1 /*
2 Copyright (c) 2017-2018 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.shaders.standard;
29 
30 import std.stdio;
31 import std.math;
32 
33 import dlib.core.memory;
34 import dlib.math.vector;
35 import dlib.math.matrix;
36 import dlib.math.transformation;
37 import dlib.math.interpolation;
38 import dlib.image.color;
39 
40 import dagon.core.libs;
41 import dagon.core.ownership;
42 import dagon.graphics.rc;
43 import dagon.graphics.shadow;
44 import dagon.graphics.texture;
45 import dagon.graphics.cubemap;
46 import dagon.graphics.material;
47 import dagon.graphics.shader;
48 
49 class StandardShader: Shader
50 {
51     string vs = import("Standard.vs");
52     string fs = import("Standard.fs");
53 
54     CascadedShadowMap shadowMap;
55     Matrix4x4f defaultShadowMatrix;
56 
57     this(Owner o)
58     {
59         auto myProgram = New!ShaderProgram(vs, fs, this);
60         super(myProgram, o);
61 
62         defaultShadowMatrix = Matrix4x4f.identity;
63     }
64 
65     override void bind(RenderingContext* rc)
66     {
67         auto idiffuse = "diffuse" in rc.material.inputs;
68         auto inormal = "normal" in rc.material.inputs;
69         auto iheight = "height" in rc.material.inputs;
70         auto iroughness = "roughness" in rc.material.inputs;
71         auto imetallic = "metallic" in rc.material.inputs;
72         auto ipbr = "pbr" in rc.material.inputs;
73         auto iemission = "emission" in rc.material.inputs;
74         auto ienergy = "energy" in rc.material.inputs;
75         auto itransparency = "transparency" in rc.material.inputs;
76         auto itextureScale = "textureScale" in rc.material.inputs;
77 
78         bool shadeless = rc.material.boolProp("shadeless");
79 
80         bool useShadows;
81         if (shadowMap is null)
82             useShadows = false;
83         else
84             useShadows = shadowMap.enabled && rc.material.boolProp("shadowsEnabled");
85 
86         auto iparallax = "parallax" in rc.material.inputs;
87 
88         int parallaxMethod = iparallax.asInteger;
89         if (parallaxMethod > ParallaxOcclusionMapping)
90             parallaxMethod = ParallaxOcclusionMapping;
91         if (parallaxMethod < 0)
92             parallaxMethod = 0;
93 
94         if (idiffuse.texture)
95         {
96             glActiveTexture(GL_TEXTURE0);
97             idiffuse.texture.bind();
98         }
99 
100         if (ipbr is null)
101         {
102             rc.material.setInput("pbr", 0.0f);
103             ipbr = "pbr" in rc.material.inputs;
104         }
105 
106         if (ipbr.texture is null)
107             ipbr.texture = rc.material.makeTexture(*iroughness, *imetallic, materialInput(0.0f), materialInput(0.0f));
108         glActiveTexture(GL_TEXTURE2);
109         ipbr.texture.bind();
110 
111         // Emission
112         if (iemission.texture)
113         {
114             glActiveTexture(GL_TEXTURE3);
115             iemission.texture.bind();
116 
117             setParameter("emissionTexture", 3);
118             setParameterSubroutine("emission", ShaderType.Fragment, "emissionMap");
119         }
120         else
121         {
122             setParameter("emissionVector", rc.material.emission.asVector4f);
123             setParameterSubroutine("emission", ShaderType.Fragment, "emissionValue");
124         }
125         setParameter("emissionEnergy", ienergy.asFloat);
126 
127         if (rc.environment.environmentMap)
128         {
129             glActiveTexture(GL_TEXTURE4);
130             rc.environment.environmentMap.bind();
131         }
132 
133         if (useShadows)
134         {
135             glActiveTexture(GL_TEXTURE5);
136             glBindTexture(GL_TEXTURE_2D_ARRAY, shadowMap.depthTexture);
137         }
138 
139         setParameter("modelViewMatrix", rc.modelViewMatrix);
140         setParameter("projectionMatrix", rc.projectionMatrix);
141         setParameter("normalMatrix", rc.normalMatrix);
142         setParameter("viewMatrix", rc.viewMatrix);
143         setParameter("invViewMatrix", rc.invViewMatrix);
144 
145         setParameter("prevModelViewProjMatrix", rc.prevModelViewProjMatrix);
146         setParameter("blurModelViewProjMatrix", rc.blurModelViewProjMatrix);
147         setParameter("blurMask", rc.blurMask);
148 
149         setParameter("textureScale", itextureScale.asVector2f);
150 
151         setParameter("sunDirection", rc.environment.sunDirectionEye(rc.viewMatrix));
152         setParameter("sunColor", rc.environment.sunColor);
153         setParameter("sunEnergy", rc.environment.sunEnergy);
154 
155         float transparency = 1.0f;
156         if (itransparency)
157             transparency = itransparency.asFloat;
158         setParameter("transparency", transparency);
159 
160         // Diffuse
161         if (idiffuse.texture)
162         {
163             setParameter("diffuseTexture", 0);
164             setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorTexture");
165         }
166         else
167         {
168             setParameter("diffuseVector", rc.material.diffuse.asVector4f);
169             setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorValue");
170         }
171 
172         // Normal/height
173         bool haveHeightMap = inormal.texture !is null;
174         if (haveHeightMap)
175             haveHeightMap = inormal.texture.image.channels == 4;
176 
177         if (!haveHeightMap)
178         {
179             if (inormal.texture is null)
180             {
181                 if (iheight.texture !is null) // we have height map, but no normal map
182                 {
183                     Color4f color = Color4f(0.5f, 0.5f, 1.0f, 0.0f); // default normal pointing upwards
184                     inormal.texture = rc.material.makeTexture(color, iheight.texture);
185                     haveHeightMap = true;
186                 }
187             }
188             else
189             {
190                 if (iheight.texture !is null) // we have both normal and height maps
191                 {
192                     inormal.texture = rc.material.makeTexture(inormal.texture, iheight.texture);
193                     haveHeightMap = true;
194                 }
195             }
196         }
197 
198         if (inormal.texture)
199         {
200             setParameter("normalTexture", 1);
201             setParameterSubroutine("normal", ShaderType.Fragment, "normalMap");
202 
203             glActiveTexture(GL_TEXTURE1);
204             inormal.texture.bind();
205         }
206         else
207         {
208             setParameter("normalVector", rc.material.normal.asVector3f);
209             setParameterSubroutine("normal", ShaderType.Fragment, "normalValue");
210         }
211 
212         // TODO: make these material properties
213         float parallaxScale = 0.03f;
214         float parallaxBias = -0.01f;
215         setParameter("parallaxScale", parallaxScale);
216         setParameter("parallaxBias", parallaxBias);
217 
218         if (haveHeightMap)
219         {
220             setParameterSubroutine("height", ShaderType.Fragment, "heightMap");
221         }
222         else
223         {
224             float h = 0.0f; //-parallaxBias / parallaxScale;
225             setParameter("heightScalar", h);
226             setParameterSubroutine("height", ShaderType.Fragment, "heightValue");
227             parallaxMethod = ParallaxNone;
228         }
229 
230         if (parallaxMethod == ParallaxSimple)
231             setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxSimple");
232         else if (parallaxMethod == ParallaxOcclusionMapping)
233             setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxOcclusionMapping");
234         else
235             setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxNone");
236 
237         // PBR
238         // TODO: pass solid values as uniforms, make subroutine for each mode
239         setParameter("pbrTexture", 2);
240 
241         // Environment
242         if (rc.environment.environmentMap)
243         {
244             if (cast(Cubemap)rc.environment.environmentMap)
245             {
246                 setParameter("envTextureCube", 4);
247                 setParameterSubroutine("environment", ShaderType.Fragment, "environmentCubemap");
248             }
249             else
250             {
251                 setParameter("envTexture", 4);
252                 setParameterSubroutine("environment", ShaderType.Fragment, "environmentTexture");
253             }
254         }
255         else
256         {
257             setParameter("skyZenithColor", rc.environment.skyZenithColor);
258             setParameter("skyHorizonColor", rc.environment.skyHorizonColor);
259             setParameter("groundColor", rc.environment.groundColor);
260             setParameter("skyEnergy", rc.environment.skyEnergy);
261             setParameter("groundEnergy", rc.environment.groundEnergy);
262             setParameterSubroutine("environment", ShaderType.Fragment, "environmentSky");
263         }
264         
265         setParameter("environmentBrightness", rc.environment.environmentBrightness);
266 
267         // Shadow map
268         if (useShadows)
269         {
270             setParameter("shadowMatrix1", shadowMap.area1.shadowMatrix);
271             setParameter("shadowMatrix2", shadowMap.area2.shadowMatrix);
272             setParameter("shadowMatrix3", shadowMap.area3.shadowMatrix);
273 
274             setParameter("shadowTextureSize", cast(float)shadowMap.size);
275             setParameter("shadowTextureArray", 5);
276 
277             setParameterSubroutine("shadow", ShaderType.Fragment, "shadowCSM");
278         }
279         else
280         {
281             setParameter("shadowMatrix1", defaultShadowMatrix);
282             setParameter("shadowMatrix2", defaultShadowMatrix);
283             setParameter("shadowMatrix3", defaultShadowMatrix);
284 
285             setParameterSubroutine("shadow", ShaderType.Fragment, "shadowNone");
286         }
287 
288         // BRDF
289         if (shadeless)
290             setParameterSubroutine("brdf", ShaderType.Fragment, "brdfEmission");
291         else
292             setParameterSubroutine("brdf", ShaderType.Fragment, "brdfPBR");
293 
294         glActiveTexture(GL_TEXTURE0);
295 
296         super.bind(rc);
297     }
298 
299     override void unbind(RenderingContext* rc)
300     {
301         super.unbind(rc);
302 
303         glActiveTexture(GL_TEXTURE0);
304         glBindTexture(GL_TEXTURE_2D, 0);
305 
306         glActiveTexture(GL_TEXTURE1);
307         glBindTexture(GL_TEXTURE_2D, 0);
308 
309         glActiveTexture(GL_TEXTURE2);
310         glBindTexture(GL_TEXTURE_2D, 0);
311 
312         glActiveTexture(GL_TEXTURE3);
313         glBindTexture(GL_TEXTURE_2D, 0);
314 
315         glActiveTexture(GL_TEXTURE4);
316         glBindTexture(GL_TEXTURE_2D, 0);
317         glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
318 
319         glActiveTexture(GL_TEXTURE5);
320         glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
321 
322         glActiveTexture(GL_TEXTURE6);
323         glBindTexture(GL_TEXTURE_2D, 0);
324 
325         glActiveTexture(GL_TEXTURE7);
326         glBindTexture(GL_TEXTURE_2D, 0);
327 
328         glActiveTexture(GL_TEXTURE8);
329         glBindTexture(GL_TEXTURE_2D, 0);
330 
331         glActiveTexture(GL_TEXTURE0);
332     }
333 }