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 }