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