1 /* 2 Copyright (c) 2018-2019 Timur Gafarov 3 4 Boost Software License - Version 1.0 - August 17th, 2003 5 Permission is hereby granted, free of charge, to any person or organization 6 obtaining a copy of the software and accompanying documentation covered by 7 this license (the "Software") to use, reproduce, display, distribute, 8 execute, and transmit the Software, and to prepare derivative works of the 9 Software, and to permit third-parties to whom the Software is furnished to 10 do so, all subject to the following: 11 12 The copyright notices in the Software and this entire statement, including 13 the above license grant, this restriction and the following disclaimer, 14 must be included in all copies of the Software, in whole or in part, and 15 all derivative works of the Software, unless such copies or derivative 16 works are solely in the form of machine-executable object code generated by 17 a source language processor. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 DEALINGS IN THE SOFTWARE. 26 */ 27 28 module dagon.graphics.renderer; 29 30 import std.stdio; 31 import std.math; 32 import std.algorithm; 33 import std.traits; 34 35 import dlib.core.memory; 36 import dlib.container.array; 37 import dlib.math.vector; 38 import dlib.math.matrix; 39 import dlib.math.transformation; 40 41 import dagon.core.libs; 42 import dagon.core.ownership; 43 import dagon.core.event; 44 import dagon.graphics.gbuffer; 45 import dagon.graphics.framebuffer; 46 import dagon.graphics.deferred; 47 import dagon.graphics.shadow; 48 import dagon.graphics.view; 49 import dagon.graphics.rc; 50 import dagon.graphics.postproc; 51 import dagon.graphics.texture; 52 import dagon.graphics.cubemap; 53 import dagon.graphics.cubemaprendertarget; 54 import dagon.graphics.terrain; 55 import dagon.resource.scene; 56 57 import dagon.graphics.filters.fxaa; 58 import dagon.graphics.filters.lens; 59 import dagon.graphics.filters.hdrprepass; 60 import dagon.graphics.filters.hdr; 61 import dagon.graphics.filters.brightpass; 62 import dagon.graphics.filters.blur; 63 import dagon.graphics.filters.finalizer; 64 65 import dagon.graphics.shader; 66 import dagon.logics.entity; 67 68 class Renderer: Owner 69 { 70 Scene scene; 71 EventManager eventManager; 72 73 GBuffer gbuffer; 74 Framebuffer sceneFramebuffer; 75 76 DeferredEnvironmentPass deferredEnvPass; 77 DeferredLightPass deferredLightPass; 78 79 DynamicArray!PostFilter postFilters; 80 81 PostFilterHDR hdrFilter; 82 83 Framebuffer hdrPrepassFramebuffer; 84 PostFilterHDRPrepass hdrPrepassFilter; 85 86 Framebuffer hblurredFramebuffer; 87 Framebuffer vblurredFramebuffer; 88 89 PostFilterBrightPass brightPass; 90 PostFilterBlur hblur; 91 PostFilterBlur vblur; 92 93 PostFilterFXAA fxaaFilter; 94 PostFilterLensDistortion lensFilter; 95 96 PostFilterFinalizer finalizerFilter; 97 98 SSAOSettings ssao; 99 HDRSettings hdr; 100 MotionBlurSettings motionBlur; 101 GlowSettings glow; 102 LUTSettings lut; 103 VignetteSettings vignette; 104 AASettings antiAliasing; 105 LensSettings lensDistortion; 106 107 RenderingContext rc3d; 108 RenderingContext rc2d; 109 110 GLuint decalFbo; 111 112 this(Scene scene, Owner o) 113 { 114 super(o); 115 116 this.scene = scene; 117 this.eventManager = scene.eventManager; 118 119 gbuffer = New!GBuffer(eventManager.windowWidth, eventManager.windowHeight, this); 120 sceneFramebuffer = New!Framebuffer(gbuffer, eventManager.windowWidth, eventManager.windowHeight, true, true, this); 121 122 deferredEnvPass = New!DeferredEnvironmentPass(gbuffer, this); 123 deferredLightPass = New!DeferredLightPass(gbuffer, this); 124 125 ssao.renderer = this; 126 hdr.renderer = this; 127 motionBlur.renderer = this; 128 glow.renderer = this; 129 glow.radius = 7; 130 lut.renderer = this; 131 vignette.renderer = this; 132 antiAliasing.renderer = this; 133 lensDistortion.renderer = this; 134 135 hblurredFramebuffer = New!Framebuffer(gbuffer, eventManager.windowWidth / 2, eventManager.windowHeight / 2, true, false, this); 136 vblurredFramebuffer = New!Framebuffer(gbuffer, eventManager.windowWidth / 2, eventManager.windowHeight / 2, true, false, this); 137 138 brightPass = New!PostFilterBrightPass(sceneFramebuffer, vblurredFramebuffer, this); 139 hblur = New!PostFilterBlur(true, vblurredFramebuffer, hblurredFramebuffer, this); 140 vblur = New!PostFilterBlur(false, hblurredFramebuffer, vblurredFramebuffer, this); 141 142 hdrPrepassFramebuffer = New!Framebuffer(gbuffer, eventManager.windowWidth, eventManager.windowHeight, true, false, this); 143 hdrPrepassFilter = New!PostFilterHDRPrepass(sceneFramebuffer, hdrPrepassFramebuffer, this); 144 hdrPrepassFilter.blurredTexture = vblurredFramebuffer.currentColorTexture; 145 postFilters.append(hdrPrepassFilter); 146 147 hdrFilter = New!PostFilterHDR(hdrPrepassFramebuffer, null, this); 148 hdrFilter.velocityTexture = gbuffer.velocityTexture; 149 postFilters.append(hdrFilter); 150 151 fxaaFilter = New!PostFilterFXAA(null, null, this); 152 postFilters.append(fxaaFilter); 153 fxaaFilter.enabled = false; 154 155 lensFilter = New!PostFilterLensDistortion(null, null, this); 156 postFilters.append(lensFilter); 157 lensFilter.enabled = false; 158 159 finalizerFilter = New!PostFilterFinalizer(null, null, this); 160 161 rc3d.initPerspective(eventManager, scene.environment, 60.0f, 0.1f, 1000.0f); 162 rc2d.initOrtho(eventManager, scene.environment, 0.0f, 100.0f); 163 164 glGenFramebuffers(1, &decalFbo); 165 glBindFramebuffer(GL_FRAMEBUFFER, decalFbo); 166 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gbuffer.colorTexture, 0); 167 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, gbuffer.rmsTexture, 0); 168 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, gbuffer.normalTexture, 0); 169 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, gbuffer.emissionTexture, 0); 170 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, gbuffer.depthTexture, 0); 171 172 GLenum[4] bufs = [GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3]; 173 glDrawBuffers(4, bufs.ptr); 174 175 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 176 if (status != GL_FRAMEBUFFER_COMPLETE) 177 writeln(status); 178 179 glBindFramebuffer(GL_FRAMEBUFFER, 0); 180 } 181 182 ~this() 183 { 184 postFilters.free(); 185 186 glBindFramebuffer(GL_FRAMEBUFFER, 0); 187 glDeleteFramebuffers(1, &decalFbo); 188 } 189 190 PostFilter addFilter(PostFilter f) 191 { 192 postFilters.append(f); 193 return f; 194 } 195 196 void renderToCubemap(Vector3f position, Cubemap cubemap) 197 { 198 if (scene.environment.environmentMap is cubemap) 199 { 200 writeln("Warning: feedback loop detected in renderToCubemap"); 201 return; 202 } 203 204 CubemapRenderTarget rt = New!CubemapRenderTarget(cubemap.width, null); 205 renderToCubemap(position, cubemap, rt); 206 Delete(rt); 207 } 208 209 void renderToCubemap(Vector3f position, Cubemap cubemap, CubemapRenderTarget rt) 210 { 211 if (scene.environment.environmentMap is cubemap) 212 { 213 writeln("Warning: feedback loop detected in renderToCubemap"); 214 return; 215 } 216 217 scene.fixedStepUpdate(false); 218 219 RenderingContext rcCubemap; 220 rcCubemap.init(eventManager, scene.environment); 221 rcCubemap.projectionMatrix = perspectiveMatrix(90.0f, 1.0f, 0.001f, 1000.0f); 222 223 foreach(face; EnumMembers!CubeFace) 224 { 225 rt.prepareRC(face, position, &rcCubemap); 226 rt.setCubemapFace(cubemap, face); 227 //TODO: simplified shadow rendering (lower resolution, only one cascade, render only once per cubemap) 228 scene.lightManager.updateShadows(position, Vector3f(0.0f, 0.0f, 1.0f), &rcCubemap, scene.fixedTimeStep); 229 renderPreStep(rt.gbuffer, &rcCubemap); 230 renderToTarget(rt, rt.gbuffer, &rcCubemap); 231 } 232 233 cubemap.invalidateMipmap(); 234 } 235 236 void render() 237 { 238 RenderingContext rcLocal = rc3d; 239 RenderingContext *rc = &rcLocal; 240 241 renderPreStep(gbuffer, rc); 242 renderToTarget(sceneFramebuffer, gbuffer, rc); 243 sceneFramebuffer.swapColorTextureAttachments(); 244 245 if (hdrFilter.autoExposure) 246 { 247 sceneFramebuffer.genLuminanceMipmaps(); 248 float lum = sceneFramebuffer.averageLuminance(); 249 250 if (!isNaN(lum)) 251 { 252 float newExposure = hdrFilter.keyValue * (1.0f / clamp(lum, hdrFilter.minLuminance, hdrFilter.maxLuminance)); 253 254 float exposureDelta = newExposure - hdrFilter.exposure; 255 hdrFilter.exposure += exposureDelta * hdrFilter.adaptationSpeed * eventManager.deltaTime; 256 } 257 } 258 259 if (hdrPrepassFilter.glowEnabled) 260 { 261 renderBlur(glow.radius); 262 } 263 264 RenderingContext rcTmp; 265 Framebuffer nextInput = sceneFramebuffer; 266 267 hdrPrepassFilter.perspectiveMatrix = rc.projectionMatrix; 268 269 foreach(i, f; postFilters.data) 270 if (f.enabled) 271 { 272 if (f.outputBuffer is null) 273 f.outputBuffer = New!Framebuffer(gbuffer, eventManager.windowWidth, eventManager.windowHeight, false, false, this); 274 275 if (f.inputBuffer is null) 276 f.inputBuffer = nextInput; 277 278 nextInput = f.outputBuffer; 279 280 f.outputBuffer.bind(); 281 rcTmp.initOrtho(eventManager, scene.environment, f.outputBuffer.width, f.outputBuffer.height, 0.0f, 100.0f); 282 prepareViewport(f.outputBuffer); 283 f.render(&rcTmp); 284 f.outputBuffer.unbind(); 285 } 286 287 prepareViewport(); 288 finalizerFilter.inputBuffer = nextInput; 289 finalizerFilter.render(&rc2d); 290 291 renderEntities2D(scene, &rc2d); 292 } 293 294 void renderPreStep(GBuffer gbuf, RenderingContext *rc) 295 { 296 scene.lightManager.renderShadows(scene, rc); 297 gbuf.clear(); 298 gbuf.renderTerrains(scene, rc); 299 gbuf.renderStatic(scene, rc); 300 301 glBindFramebuffer(GL_FRAMEBUFFER, decalFbo); 302 glDisable(GL_DEPTH_TEST); 303 //glCullFace(GL_FRONT); 304 foreach(e; scene.decals) 305 e.render(rc); 306 //glCullFace(GL_BACK); 307 glEnable(GL_DEPTH_TEST); 308 glBindFramebuffer(GL_FRAMEBUFFER, 0); 309 310 gbuf.renderDynamic(scene, rc); 311 } 312 313 void renderToTarget(RenderTarget rt, GBuffer gbuf, RenderingContext *rc) 314 { 315 rt.bind(); 316 317 RenderingContext rcDeferred; 318 rcDeferred.initOrtho(eventManager, scene.environment, gbuf.width, gbuf.height, 0.0f, 100.0f); 319 prepareViewport(rt); 320 rt.clear(scene.environment.backgroundColor); 321 322 glBindFramebuffer(GL_READ_FRAMEBUFFER, gbuf.fbo); 323 glBlitFramebuffer(0, 0, gbuf.width, gbuf.height, 0, 0, gbuf.width, gbuf.height, GL_DEPTH_BUFFER_BIT, GL_NEAREST); 324 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); 325 326 deferredEnvPass.gbuffer = gbuf; 327 deferredLightPass.gbuffer = gbuf; 328 329 renderBackgroundEntities3D(scene, rc); 330 deferredEnvPass.render(&rcDeferred, rc); 331 deferredLightPass.render(scene, &rcDeferred, rc); 332 renderTransparentEntities3D(scene, rc); 333 scene.particleSystem.render(rc); 334 335 rt.unbind(); 336 } 337 338 void renderBackgroundEntities3D(Scene scene, RenderingContext* rc) 339 { 340 glEnable(GL_DEPTH_TEST); 341 foreach(e; scene.entities3Dflat) 342 if (e.layer <= 0 && !entityIsTerrain(e)) 343 e.render(rc); 344 } 345 346 void renderOpaqueEntities3D(Scene scene, RenderingContext* rc) 347 { 348 glEnable(GL_DEPTH_TEST); 349 RenderingContext rcLocal = *rc; 350 rcLocal.ignoreTransparentEntities = true; 351 foreach(e; scene.entities3Dflat) 352 if (!entityIsTerrain(e)) 353 { 354 if (e.layer > 0) 355 e.render(&rcLocal); 356 } 357 } 358 359 void renderStaticOpaqueEntities3D(Scene scene, RenderingContext* rc) 360 { 361 glEnable(GL_DEPTH_TEST); 362 RenderingContext rcLocal = *rc; 363 rcLocal.ignoreTransparentEntities = true; 364 foreach(e; scene.entities3DStatic) 365 if (!entityIsTerrain(e)) 366 { 367 if (e.layer > 0) 368 e.render(&rcLocal); 369 } 370 } 371 372 void renderDynamicOpaqueEntities3D(Scene scene, RenderingContext* rc) 373 { 374 glEnable(GL_DEPTH_TEST); 375 RenderingContext rcLocal = *rc; 376 rcLocal.ignoreTransparentEntities = true; 377 foreach(e; scene.entities3DDynamic) 378 if (!entityIsTerrain(e)) 379 { 380 if (e.layer > 0) 381 e.render(&rcLocal); 382 } 383 } 384 385 void renderTransparentEntities3D(Scene scene, RenderingContext* rc) 386 { 387 glEnable(GL_DEPTH_TEST); 388 RenderingContext rcLocal = *rc; 389 rcLocal.ignoreOpaqueEntities = true; 390 foreach(e; scene.entities3Dflat) 391 if (!entityIsTerrain(e)) 392 { 393 if (e.layer > 0) 394 e.render(&rcLocal); 395 } 396 } 397 398 void renderEntities3D(Scene scene, RenderingContext* rc) 399 { 400 glEnable(GL_DEPTH_TEST); 401 foreach(e; scene.entities3Dflat) 402 if (!entityIsTerrain(e)) 403 e.render(rc); 404 } 405 406 void renderEntities2D(Scene scene, RenderingContext* rc) 407 { 408 glDisable(GL_DEPTH_TEST); 409 foreach(e; scene.entities2Dflat) 410 if (!entityIsTerrain(e)) 411 e.render(rc); 412 } 413 414 void prepareViewport(RenderTarget rt = null) 415 { 416 glEnable(GL_SCISSOR_TEST); 417 if (rt) 418 { 419 glScissor(0, 0, rt.width, rt.height); 420 glViewport(0, 0, rt.width, rt.height); 421 } 422 else 423 { 424 glScissor(0, 0, eventManager.windowWidth, eventManager.windowHeight); 425 glViewport(0, 0, eventManager.windowWidth, eventManager.windowHeight); 426 } 427 glClearColor( 428 scene.environment.backgroundColor.r, 429 scene.environment.backgroundColor.g, 430 scene.environment.backgroundColor.b, 0.0f); 431 } 432 433 void renderBlur(uint iterations) 434 { 435 RenderingContext rcTmp; 436 437 brightPass.outputBuffer.bind(); 438 rcTmp.initOrtho(eventManager, scene.environment, brightPass.outputBuffer.width, brightPass.outputBuffer.height, 0.0f, 100.0f); 439 prepareViewport(brightPass.outputBuffer); 440 brightPass.render(&rcTmp); 441 brightPass.outputBuffer.unbind(); 442 443 foreach(i; 1..iterations+1) 444 { 445 hblur.outputBuffer.bind(); 446 rcTmp.initOrtho(eventManager, scene.environment, hblur.outputBuffer.width, hblur.outputBuffer.height, 0.0f, 100.0f); 447 prepareViewport(hblur.outputBuffer); 448 hblur.radius = i; 449 hblur.render(&rcTmp); 450 hblur.outputBuffer.unbind(); 451 452 vblur.outputBuffer.bind(); 453 rcTmp.initOrtho(eventManager, scene.environment, vblur.outputBuffer.width, vblur.outputBuffer.height, 0.0f, 100.0f); 454 prepareViewport(vblur.outputBuffer); 455 vblur.radius = i; 456 vblur.render(&rcTmp); 457 vblur.outputBuffer.unbind(); 458 459 hblur.inputBuffer = vblur.outputBuffer; 460 } 461 462 hblur.inputBuffer = brightPass.outputBuffer; //sceneFramebuffer; 463 } 464 } 465 466 struct SSAOSettings 467 { 468 Renderer renderer; 469 void enabled(bool mode) @property { renderer.deferredEnvPass.shader.enableSSAO = mode; } 470 bool enabled() @property { return renderer.deferredEnvPass.shader.enableSSAO; } 471 void samples(int s) @property { renderer.deferredEnvPass.shader.ssaoSamples = s; } 472 int samples() @property { return renderer.deferredEnvPass.shader.ssaoSamples; } 473 void radius(float r) @property { renderer.deferredEnvPass.shader.ssaoRadius = r; } 474 float radius() @property { return renderer.deferredEnvPass.shader.ssaoRadius; } 475 void power(float p) @property { renderer.deferredEnvPass.shader.ssaoPower = p; } 476 float power() @property { return renderer.deferredEnvPass.shader.ssaoPower; } 477 } 478 479 struct HDRSettings 480 { 481 Renderer renderer; 482 void tonemapper(Tonemapper f) @property { renderer.hdrFilter.tonemapFunction = f; } 483 Tonemapper tonemapper() @property { return renderer.hdrFilter.tonemapFunction; } 484 void exposure(float ex) @property { renderer.hdrFilter.exposure = ex; } 485 float exposure() @property { return renderer.hdrFilter.exposure; } 486 void autoExposure(bool mode) @property { renderer.hdrFilter.autoExposure = mode; } 487 bool autoExposure() @property { return renderer.hdrFilter.autoExposure; } 488 void minLuminance(float l) @property { renderer.hdrFilter.minLuminance = l; } 489 float minLuminance() @property { return renderer.hdrFilter.minLuminance; } 490 void maxLuminance(float l) @property { renderer.hdrFilter.maxLuminance = l; } 491 float maxLuminance() @property { return renderer.hdrFilter.maxLuminance; } 492 void keyValue(float k) @property { renderer.hdrFilter.keyValue = k; } 493 float keyValue() @property { return renderer.hdrFilter.keyValue; } 494 void adaptationSpeed(float s) @property { renderer.hdrFilter.adaptationSpeed = s; } 495 float adaptationSpeed() @property { return renderer.hdrFilter.adaptationSpeed; } 496 void linearity(float l) @property { renderer.hdrFilter.parametricTonemapperLinearity = l; } 497 float linearity() @property { return renderer.hdrFilter.parametricTonemapperLinearity; } 498 } 499 500 struct GlowSettings 501 { 502 Renderer renderer; 503 uint radius; 504 void enabled(bool mode) @property 505 { 506 renderer.hblur.enabled = mode; 507 renderer.vblur.enabled = mode; 508 renderer.hdrPrepassFilter.glowEnabled = mode; 509 } 510 bool enabled() @property { return renderer.hdrPrepassFilter.glowEnabled; } 511 void brightness(float b) @property { renderer.hdrPrepassFilter.glowBrightness = b; } 512 float brightness() @property { return renderer.hdrPrepassFilter.glowBrightness; } 513 514 void luminanceThreshold(float t) @property { renderer.brightPass.luminanceThreshold = t; } 515 float luminanceThreshold() @property { return renderer.brightPass.luminanceThreshold; } 516 } 517 518 struct MotionBlurSettings 519 { 520 Renderer renderer; 521 void enabled(bool mode) @property { renderer.hdrFilter.mblurEnabled = mode; } 522 bool enabled() @property { return renderer.hdrFilter.mblurEnabled; } 523 void samples(uint s) @property { renderer.hdrFilter.motionBlurSamples = s; } 524 uint samples() @property { return renderer.hdrFilter.motionBlurSamples; } 525 void shutterSpeed(float s) @property 526 { 527 renderer.hdrFilter.shutterSpeed = s; 528 renderer.hdrFilter.shutterFps = 1.0 / s; 529 } 530 float shutterSpeed() @property { return renderer.hdrFilter.shutterSpeed; } 531 } 532 533 struct LUTSettings 534 { 535 Renderer renderer; 536 void texture(Texture tex) @property { renderer.hdrFilter.colorTable = tex; } 537 Texture texture() @property { return renderer.hdrFilter.colorTable; } 538 } 539 540 struct VignetteSettings 541 { 542 Renderer renderer; 543 void texture(Texture tex) @property { renderer.hdrFilter.vignette = tex; } 544 Texture texture() @property { return renderer.hdrFilter.vignette; } 545 } 546 547 struct AASettings 548 { 549 Renderer renderer; 550 void enabled(bool mode) @property { renderer.fxaaFilter.enabled = mode; } 551 bool enabled() @property { return renderer.fxaaFilter.enabled; } 552 } 553 554 struct LensSettings 555 { 556 Renderer renderer; 557 void enabled(bool mode) @property { renderer.lensFilter.enabled = mode; } 558 bool enabled() @property { return renderer.lensFilter.enabled; } 559 void scale(float s) @property { renderer.lensFilter.scale = s; } 560 float scale() @property { return renderer.lensFilter.scale; } 561 void dispersion(float d) @property { renderer.lensFilter.dispersion = d; } 562 float dispersion() @property { return renderer.lensFilter.dispersion; } 563 }