1 /*
2 Copyright (c) 2019-2020 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.render.shadowpass;
29 
30 import std.stdio;
31 
32 import dlib.core.memory;
33 import dlib.core.ownership;
34 import dlib.math.vector;
35 
36 import dagon.core.bindings;
37 import dagon.core.time;
38 import dagon.graphics.entity;
39 import dagon.graphics.camera;
40 import dagon.graphics.light;
41 import dagon.graphics.csm;
42 import dagon.graphics.shader;
43 import dagon.render.pipeline;
44 import dagon.render.pass;
45 import dagon.render.shaders.shadow;
46 
47 class ShadowPass: RenderPass
48 {
49     EntityGroup lightGroup;
50     ShadowShader csmShader;
51     Camera camera;
52 
53     this(RenderPipeline pipeline)
54     {
55         super(pipeline);
56         csmShader = New!ShadowShader(this);
57         state.colorMask = false;
58         state.culling = false;
59     }
60 
61     override void update(Time t)
62     {
63         super.update(t);
64 
65         if (lightGroup)
66         {
67             foreach(entity; lightGroup)
68             {
69                 Light light = cast(Light)entity;
70                 if (light && camera)
71                 {
72                     if (light.shadowEnabled)
73                     {
74                         CascadedShadowMap csm = cast(CascadedShadowMap)light.shadowMap;
75                         if (csm)
76                             csm.camera = camera;
77 
78                         // TODO: other shadow types
79 
80                         light.shadowMap.update(t);
81                     }
82                 }
83             }
84         }
85     }
86 
87     override void render()
88     {
89         if (group && lightGroup)
90         {
91             foreach(entity; lightGroup)
92             {
93                 Light light = cast(Light)entity;
94                 if (light)
95                 {
96                     if (light.shadowEnabled)
97                     {
98                         state.light = light;
99                         CascadedShadowMap csm = cast(CascadedShadowMap)light.shadowMap;
100 
101                         if (light.type == LightType.Sun && csm)
102                             renderCSM(csm);
103 
104                         // TODO: other shadow types
105                     }
106                 }
107             }
108         }
109     }
110 
111     void renderEntities(Shader shader)
112     {
113         foreach(entity; group)
114         if (entity.visible && entity.castShadow)
115         {
116             state.modelMatrix = entity.absoluteTransformation;
117             state.modelViewMatrix = state.viewMatrix * state.modelMatrix;
118             state.normalMatrix = state.modelViewMatrix.inverse.transposed;
119             state.shader = shader;
120             state.opacity = 1.0f;
121 
122             if (entity.material)
123                 entity.material.bind(&state);
124             else
125                 defaultMaterial.bind(&state);
126 
127             shader.bindParameters(&state);
128 
129             if (entity.drawable)
130                 entity.drawable.render(&state);
131 
132             shader.unbindParameters(&state);
133 
134             if (entity.material)
135                 entity.material.unbind(&state);
136             else
137                 defaultMaterial.unbind(&state);
138         }
139     }
140 
141     void renderCSM(CascadedShadowMap csm)
142     {
143         state.resolution = Vector2f(csm.resolution, csm.resolution);
144         state.zNear = csm.area[0].zStart;
145         state.zFar = csm.area[0].zEnd;
146 
147         state.cameraPosition = csm.area[0].position;
148 
149         glScissor(0, 0, csm.resolution, csm.resolution);
150         glViewport(0, 0, csm.resolution, csm.resolution);
151 
152         csmShader.bind();
153 
154         glPolygonOffset(3.0, 0.0);
155         glDisable(GL_CULL_FACE);
156 
157         state.viewMatrix = csm.area[0].viewMatrix;
158         state.invViewMatrix = csm.area[0].invViewMatrix;
159         state.projectionMatrix = csm.area[0].projectionMatrix;
160         state.invProjectionMatrix = csm.area[0].projectionMatrix.inverse;
161         glBindFramebuffer(GL_FRAMEBUFFER, csm.framebuffer1);
162         glClear(GL_DEPTH_BUFFER_BIT);
163         renderEntities(csmShader);
164         glBindFramebuffer(GL_FRAMEBUFFER, 0);
165 
166         state.viewMatrix = csm.area[1].viewMatrix;
167         state.invViewMatrix = csm.area[1].invViewMatrix;
168         state.projectionMatrix = csm.area[1].projectionMatrix;
169         state.invProjectionMatrix = csm.area[1].projectionMatrix.inverse;
170         glBindFramebuffer(GL_FRAMEBUFFER, csm.framebuffer2);
171         glClear(GL_DEPTH_BUFFER_BIT);
172         renderEntities(csmShader);
173         glBindFramebuffer(GL_FRAMEBUFFER, 0);
174 
175         state.viewMatrix = csm.area[2].viewMatrix;
176         state.invViewMatrix = csm.area[2].invViewMatrix;
177         state.projectionMatrix = csm.area[2].projectionMatrix;
178         state.invProjectionMatrix = csm.area[2].projectionMatrix.inverse;
179         glBindFramebuffer(GL_FRAMEBUFFER, csm.framebuffer3);
180         glClear(GL_DEPTH_BUFFER_BIT);
181         renderEntities(csmShader);
182         glBindFramebuffer(GL_FRAMEBUFFER, 0);
183 
184         glEnable(GL_CULL_FACE);
185         glPolygonOffset(0.0, 0.0);
186 
187         csmShader.unbind();
188     }
189 }