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                         light.shadowMap.update(t);
79                     }
80                 }
81             }
82         }
83     }
84 
85     override void render()
86     {
87         if (group && lightGroup)
88         {
89             foreach(entity; lightGroup)
90             {
91                 Light light = cast(Light)entity;
92                 if (light)
93                 {
94                     if (light.shadowEnabled)
95                     {
96                         state.light = light;
97                         CascadedShadowMap csm = cast(CascadedShadowMap)light.shadowMap;
98                         
99                         if (light.type == LightType.Sun && csm)
100                             renderCSM(csm);
101                     }
102                 }
103             }
104         }
105     }
106 
107     void renderEntities(Shader shader)
108     {
109         foreach(entity; group)
110         if (entity.visible && entity.castShadow)
111         {
112             state.modelMatrix = entity.absoluteTransformation;
113             state.modelViewMatrix = state.viewMatrix * state.modelMatrix;
114             state.normalMatrix = state.modelViewMatrix.inverse.transposed;
115             state.shader = shader;
116             state.opacity = 1.0f;
117             state.environment = pipeline.environment;
118 
119             if (entity.material)
120                 entity.material.bind(&state);
121             else
122                 defaultMaterial.bind(&state);
123 
124             shader.bindParameters(&state);
125 
126             if (entity.drawable)
127                 entity.drawable.render(&state);
128 
129             shader.unbindParameters(&state);
130 
131             if (entity.material)
132                 entity.material.unbind(&state);
133             else
134                 defaultMaterial.unbind(&state);
135         }
136     }
137 
138     void renderCSM(CascadedShadowMap csm)
139     {
140         state.resolution = Vector2f(csm.resolution, csm.resolution);
141         state.zNear = csm.area[0].zStart;
142         state.zFar = csm.area[0].zEnd;
143 
144         state.cameraPosition = csm.area[0].position;
145 
146         glScissor(0, 0, csm.resolution, csm.resolution);
147         glViewport(0, 0, csm.resolution, csm.resolution);
148 
149         csmShader.bind();
150 
151         glPolygonOffset(3.0, 0.0);
152         glDisable(GL_CULL_FACE);
153 
154         state.viewMatrix = csm.area[0].viewMatrix;
155         state.invViewMatrix = csm.area[0].invViewMatrix;
156         state.projectionMatrix = csm.area[0].projectionMatrix;
157         state.invProjectionMatrix = csm.area[0].projectionMatrix.inverse;
158         glBindFramebuffer(GL_FRAMEBUFFER, csm.framebuffer1);
159         glClear(GL_DEPTH_BUFFER_BIT);
160         renderEntities(csmShader);
161         glBindFramebuffer(GL_FRAMEBUFFER, 0);
162 
163         state.viewMatrix = csm.area[1].viewMatrix;
164         state.invViewMatrix = csm.area[1].invViewMatrix;
165         state.projectionMatrix = csm.area[1].projectionMatrix;
166         state.invProjectionMatrix = csm.area[1].projectionMatrix.inverse;
167         glBindFramebuffer(GL_FRAMEBUFFER, csm.framebuffer2);
168         glClear(GL_DEPTH_BUFFER_BIT);
169         renderEntities(csmShader);
170         glBindFramebuffer(GL_FRAMEBUFFER, 0);
171 
172         state.viewMatrix = csm.area[2].viewMatrix;
173         state.invViewMatrix = csm.area[2].invViewMatrix;
174         state.projectionMatrix = csm.area[2].projectionMatrix;
175         state.invProjectionMatrix = csm.area[2].projectionMatrix.inverse;
176         glBindFramebuffer(GL_FRAMEBUFFER, csm.framebuffer3);
177         glClear(GL_DEPTH_BUFFER_BIT);
178         renderEntities(csmShader);
179         glBindFramebuffer(GL_FRAMEBUFFER, 0);
180 
181         glEnable(GL_CULL_FACE);
182         glPolygonOffset(0.0, 0.0);
183 
184         csmShader.unbind();
185     }
186 }