1 /*
2 Copyright (c) 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.game.deferredrenderer;
29 
30 import dlib.core.memory;
31 import dlib.core.ownership;
32 
33 import dagon.core.event;
34 import dagon.core.time;
35 import dagon.resource.scene;
36 import dagon.render.deferred;
37 import dagon.render.gbuffer;
38 import dagon.render.view;
39 import dagon.render.framebuffer;
40 import dagon.render.shadowpass;
41 import dagon.postproc.filterpass;
42 import dagon.postproc.shaders.denoise;
43 import dagon.game.renderer;
44 
45 class DeferredRenderer: Renderer
46 {
47     GBuffer gbuffer;
48 
49     DenoiseShader denoiseShader;
50 
51     ShadowPass passShadow;
52     DeferredClearPass passClear;
53     DeferredBackgroundPass passBackground;
54     DeferredGeometryPass passStaticGeometry;
55     DeferredDecalPass passDecals;
56     DeferredGeometryPass passDynamicGeometry;
57     DeferredOcclusionPass passOcclusion;
58     FilterPass passOcclusionDenoise;
59     DeferredEnvironmentPass passEnvironment;
60     DeferredLightPass passLight;
61     DeferredParticlesPass passParticles;
62     DeferredForwardPass passForward;
63     DeferredDebugOutputPass passDebug;
64 
65     RenderView occlusionView;
66     Framebuffer occlusionNoisyBuffer;
67     Framebuffer occlusionBuffer;
68 
69     DebugOutputMode outputMode = DebugOutputMode.Radiance;
70 
71     bool _ssaoEnabled = true;
72 
73     int ssaoSamples = 10;
74     float ssaoRadius = 0.2f;
75     float ssaoPower = 7.0f;
76     float ssaoDenoise = 1.0f;
77 
78     this(EventManager eventManager, Owner owner)
79     {
80         super(eventManager, owner);
81 
82         occlusionView = New!RenderView(0, 0, view.width / 2, view.height / 2, this);
83         occlusionNoisyBuffer = New!Framebuffer(occlusionView.width, occlusionView.height, FrameBufferFormat.R8, false, this);
84         occlusionBuffer = New!Framebuffer(occlusionView.width, occlusionView.height, FrameBufferFormat.R8, false, this);
85 
86         // HDR buffer
87         auto radianceBuffer = New!Framebuffer(eventManager.windowWidth, eventManager.windowHeight, FrameBufferFormat.RGBA16F, true, this);
88         outputBuffer = radianceBuffer;
89 
90         gbuffer = New!GBuffer(view.width, view.height, radianceBuffer, this);
91 
92         passShadow = New!ShadowPass(pipeline);
93 
94         passClear = New!DeferredClearPass(pipeline, gbuffer);
95 
96         passBackground = New!DeferredBackgroundPass(pipeline, gbuffer);
97         passBackground.view = view;
98 
99         passStaticGeometry = New!DeferredGeometryPass(pipeline, gbuffer);
100         passStaticGeometry.view = view;
101 
102         passDecals = New!DeferredDecalPass(pipeline, gbuffer);
103         passDecals.view = view;
104 
105         passDynamicGeometry = New!DeferredGeometryPass(pipeline, gbuffer);
106         passDynamicGeometry.view = view;
107 
108         passOcclusion = New!DeferredOcclusionPass(pipeline, gbuffer);
109         passOcclusion.view = occlusionView;
110         passOcclusion.outputBuffer = occlusionNoisyBuffer;
111 
112         denoiseShader = New!DenoiseShader(this);
113         passOcclusionDenoise = New!FilterPass(pipeline, denoiseShader);
114         passOcclusionDenoise.view = occlusionView;
115         passOcclusionDenoise.inputBuffer = occlusionNoisyBuffer;
116         passOcclusionDenoise.outputBuffer = occlusionBuffer;
117 
118         passEnvironment = New!DeferredEnvironmentPass(pipeline, gbuffer);
119         passEnvironment.view = view;
120         passEnvironment.outputBuffer = radianceBuffer;
121         passEnvironment.occlusionBuffer = occlusionBuffer;
122 
123         passLight = New!DeferredLightPass(pipeline, gbuffer);
124         passLight.view = view;
125         passLight.outputBuffer = radianceBuffer;
126         passLight.occlusionBuffer = occlusionBuffer;
127 
128         passForward = New!DeferredForwardPass(pipeline, gbuffer);
129         passForward.view = view;
130         passForward.outputBuffer = radianceBuffer;
131 
132         passParticles = New!DeferredParticlesPass(pipeline, gbuffer);
133         passParticles.view = view;
134         passParticles.outputBuffer = radianceBuffer;
135         passParticles.gbuffer = gbuffer;
136 
137         passDebug = New!DeferredDebugOutputPass(pipeline, gbuffer);
138         passDebug.view = view;
139         passDebug.active = false;
140         passDebug.outputBuffer = radianceBuffer;
141         passDebug.occlusionBuffer = occlusionBuffer;
142     }
143 
144     void ssaoEnabled(bool mode) @property
145     {
146         _ssaoEnabled = mode;
147         passOcclusion.active = mode;
148         passOcclusionDenoise.active = mode;
149         if (_ssaoEnabled)
150         {
151             passEnvironment.occlusionBuffer = occlusionBuffer;
152             passLight.occlusionBuffer = occlusionBuffer;
153         }
154         else
155         {
156             passEnvironment.occlusionBuffer = null;
157             passLight.occlusionBuffer = null;
158         }
159     }
160 
161     bool ssaoEnabled() @property
162     {
163         return _ssaoEnabled;
164     }
165 
166     override void scene(Scene s)
167     {
168         passShadow.group = s.spatial;
169         passShadow.lightGroup = s.lights;
170         passBackground.group = s.background;
171         passStaticGeometry.group = s.spatialOpaqueStatic;
172         passDecals.group = s.decals;
173         passDynamicGeometry.group = s.spatialOpaqueDynamic;
174         passLight.groupSunLights = s.sunLights;
175         passLight.groupAreaLights = s.areaLights;
176         passForward.group = s.spatialTransparent;
177         passParticles.group = s.spatial;
178         
179         passBackground.state.environment = s.environment;
180         passStaticGeometry.state.environment = s.environment;
181         passDecals.state.environment = s.environment;
182         passDynamicGeometry.state.environment = s.environment;
183         passEnvironment.state.environment = s.environment;
184         passLight.state.environment = s.environment;
185         passForward.state.environment = s.environment;
186         passParticles.state.environment = s.environment;
187         passDebug.state.environment = s.environment;
188     }
189 
190     override void update(Time t)
191     {
192         passShadow.camera = activeCamera;
193         passDebug.active = (outputMode != DebugOutputMode.Radiance);
194         passDebug.outputMode = outputMode;
195 
196         passOcclusion.ssaoShader.samples = ssaoSamples;
197         passOcclusion.ssaoShader.radius = ssaoRadius;
198         passOcclusion.ssaoShader.power = ssaoPower;
199         denoiseShader.factor = ssaoDenoise;
200 
201         super.update(t);
202     }
203 
204     override void setViewport(uint x, uint y, uint w, uint h)
205     {
206         super.setViewport(x, y, w, h);
207 
208         outputBuffer.resize(view.width, view.height);
209         gbuffer.resize(view.width, view.height);
210 
211         occlusionView.resize(view.width / 2, view.height / 2);
212         occlusionNoisyBuffer.resize(occlusionView.width, occlusionView.height);
213         occlusionBuffer.resize(occlusionView.width, occlusionView.height);
214     }
215 }