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.materials.sky;
29 
30 import std.stdio;
31 import std.math;
32 import std.conv;
33 
34 import dlib.core.memory;
35 import dlib.math.vector;
36 import dlib.math.matrix;
37 import dlib.image.color;
38 
39 import derelict.opengl;
40 
41 import dagon.core.ownership;
42 import dagon.graphics.rc;
43 import dagon.graphics.material;
44 import dagon.graphics.materials.generic;
45 
46 /*
47  * Backend for skydome material. 
48  */
49 
50 class SkyBackend: GLSLMaterialBackend
51 {    
52     private string vsText = "
53         #version 330 core
54         
55         layout (location = 0) in vec3 va_Vertex;
56         layout (location = 1) in vec3 va_Normal;
57         
58         uniform mat4 modelViewMatrix;
59         uniform mat4 normalMatrix;
60         uniform mat4 projectionMatrix;
61         uniform mat4 invViewMatrix;
62         
63         uniform mat4 prevModelViewProjMatrix;
64         uniform mat4 blurModelViewProjMatrix;
65         
66         out vec3 eyePosition;
67         
68         out vec3 worldNormal;
69         
70         out vec4 blurPosition;
71         out vec4 prevPosition;
72     
73         void main()
74         {
75             vec4 pos = modelViewMatrix * vec4(va_Vertex, 1.0);
76             eyePosition = pos.xyz;
77         
78             worldNormal = va_Normal;
79             
80             blurPosition = blurModelViewProjMatrix * vec4(va_Vertex, 1.0);
81             prevPosition = prevModelViewProjMatrix * vec4(va_Vertex, 1.0);
82             
83             gl_Position = projectionMatrix * modelViewMatrix * vec4(va_Vertex, 1.0);
84         }
85     ";
86     
87     private string fsText = "
88         #version 330 core
89         
90         #define EPSILON 0.000001
91         #define PI 3.14159265
92         const float PI2 = PI * 2.0;
93         
94         uniform vec3 sunDirection;
95         uniform vec3 skyZenithColor;
96         uniform vec3 skyHorizonColor;
97         uniform vec3 sunColor;
98         
99         in vec3 eyePosition;
100         in vec3 worldNormal;
101         
102         in vec4 blurPosition;
103         in vec4 prevPosition;
104         
105         layout(location = 0) out vec4 frag_color;
106         layout(location = 1) out vec4 frag_velocity;
107         layout(location = 2) out vec4 frag_luma;
108         layout(location = 3) out vec4 frag_position;
109         
110         uniform vec3 groundColor;
111         uniform float skyEnergy;
112         uniform float groundEnergy;
113         uniform float sunEnergy;
114         
115         uniform sampler2D environmentMap;
116         uniform bool useEnvironmentMap;
117         
118         vec2 envMapEquirect(vec3 dir)
119         {
120             float phi = acos(dir.y);
121             float theta = atan(dir.x, dir.z) + PI;
122             return vec2(theta / PI2, phi / PI);
123         }
124         
125         vec3 toLinear(vec3 v)
126         {
127             return pow(v, vec3(2.2));
128         }
129         
130         float luminance(vec3 color)
131         {
132             return (
133                 color.x * 0.27 +
134                 color.y * 0.67 +
135                 color.z * 0.06
136             );
137         }
138 
139         void main()
140         {
141             vec3 normalWorldN = normalize(worldNormal);
142             vec3 env;
143             
144             vec2 posScreen = (blurPosition.xy / blurPosition.w) * 0.5 + 0.5;
145             vec2 prevPosScreen = (prevPosition.xy / prevPosition.w) * 0.5 + 0.5;
146             vec2 screenVelocity = posScreen - prevPosScreen;
147 
148             if (useEnvironmentMap)
149             {
150                 env = texture(environmentMap, envMapEquirect(-normalWorldN)).rgb;
151             }
152             else
153             {                
154                 float horizonOrZenith = pow(clamp(dot(-normalWorldN, vec3(0, 1, 0)), 0.0, 1.0), 0.5);
155                 float groundOrSky = pow(clamp(dot(-normalWorldN, vec3(0, -1, 0)), 0.0, 1.0), 0.4);
156                 
157                 env = mix(mix(skyHorizonColor * skyEnergy, groundColor * groundEnergy, groundOrSky), skyZenithColor * skyEnergy, horizonOrZenith);
158                 float sun = clamp(dot(-normalWorldN, sunDirection), 0.0, 1.0);
159                 sun = min(float(sun > 0.999) + pow(sun, 96.0) * 0.2, 1.0);
160                 env += sunColor * sun * sunEnergy;
161             }
162             
163             frag_color = vec4(env, 1.0);
164             frag_velocity = vec4(screenVelocity, 0.0, 1.0);
165             frag_luma = vec4(luminance(env));
166             frag_position = vec4(eyePosition, 0.0);
167         }
168     ";
169     
170     override string vertexShaderSrc() {return vsText;}
171     override string fragmentShaderSrc() {return fsText;}
172 
173     GLint modelViewMatrixLoc;
174     GLint projectionMatrixLoc;
175     GLint normalMatrixLoc;
176     
177     GLint prevModelViewProjMatrixLoc;
178     GLint blurModelViewProjMatrixLoc;
179     
180     GLint locInvViewMatrix;
181     GLint locSunDirection;
182     GLint locSkyZenithColor;
183     GLint locSkyHorizonColor;
184     GLint locSkyEnergy;
185     GLint locSunColor;
186     GLint locSunEnergy;
187     GLint locGroundColor;
188     GLint locGroundEnergy;
189     
190     GLint environmentMapLoc;
191     GLint useEnvironmentMapLoc;
192     
193     bool useEnvironmentMap = true;
194     
195     this(Owner o)
196     {
197         super(o);
198         
199         modelViewMatrixLoc = glGetUniformLocation(shaderProgram, "modelViewMatrix");
200         projectionMatrixLoc = glGetUniformLocation(shaderProgram, "projectionMatrix");
201         normalMatrixLoc = glGetUniformLocation(shaderProgram, "normalMatrix");
202         
203         prevModelViewProjMatrixLoc = glGetUniformLocation(shaderProgram, "prevModelViewProjMatrix");
204         blurModelViewProjMatrixLoc = glGetUniformLocation(shaderProgram, "blurModelViewProjMatrix");
205             
206         locInvViewMatrix = glGetUniformLocation(shaderProgram, "invViewMatrix");
207         locSunDirection = glGetUniformLocation(shaderProgram, "sunDirection");
208         locSkyZenithColor = glGetUniformLocation(shaderProgram, "skyZenithColor");
209         locSkyHorizonColor = glGetUniformLocation(shaderProgram, "skyHorizonColor");
210         locSkyEnergy = glGetUniformLocation(shaderProgram, "skyEnergy");
211         locSunColor = glGetUniformLocation(shaderProgram, "sunColor");
212         locSunEnergy = glGetUniformLocation(shaderProgram, "sunEnergy");
213         locGroundColor = glGetUniformLocation(shaderProgram, "groundColor");
214         locGroundEnergy = glGetUniformLocation(shaderProgram, "groundEnergy");
215         
216         environmentMapLoc = glGetUniformLocation(shaderProgram, "environmentMap");
217         useEnvironmentMapLoc = glGetUniformLocation(shaderProgram, "useEnvironmentMap");
218     }
219     
220     override void bind(GenericMaterial mat, RenderingContext* rc)
221     {    
222         glUseProgram(shaderProgram);
223         
224         // Matrices
225         glUniformMatrix4fv(modelViewMatrixLoc, 1, GL_FALSE, rc.modelViewMatrix.arrayof.ptr);
226         glUniformMatrix4fv(projectionMatrixLoc, 1, GL_FALSE, rc.projectionMatrix.arrayof.ptr);
227         glUniformMatrix4fv(normalMatrixLoc, 1, GL_FALSE, rc.normalMatrix.arrayof.ptr);
228         glUniformMatrix4fv(locInvViewMatrix, 1, GL_FALSE, rc.invViewMatrix.arrayof.ptr);
229         
230         glUniformMatrix4fv(prevModelViewProjMatrixLoc, 1, GL_FALSE, rc.prevModelViewProjMatrix.arrayof.ptr);
231         glUniformMatrix4fv(blurModelViewProjMatrixLoc, 1, GL_FALSE, rc.blurModelViewProjMatrix.arrayof.ptr);
232         
233         // Environment
234         Vector3f sunVector = Vector4f(rc.environment.sunDirection);
235         glUniform3fv(locSunDirection, 1, sunVector.arrayof.ptr);
236         Vector3f sunColor = rc.environment.sunColor;
237         glUniform3fv(locSunColor, 1, sunColor.arrayof.ptr);
238         glUniform1f(locSunEnergy, rc.environment.sunEnergy);
239         glUniform3fv(locSkyZenithColor, 1, rc.environment.skyZenithColor.arrayof.ptr);
240         glUniform3fv(locSkyHorizonColor, 1, rc.environment.skyHorizonColor.arrayof.ptr);
241         glUniform1f(locSkyEnergy, rc.environment.skyEnergy);
242         glUniform3fv(locGroundColor, 1, rc.environment.groundColor.arrayof.ptr);
243         glUniform1f(locGroundEnergy, rc.environment.groundEnergy);
244         
245         // Texture 4 - environment map
246         bool useEnvmap = false;
247         if (rc.environment)
248         {
249             if (rc.environment.environmentMap)
250                 useEnvmap = useEnvironmentMap;
251         }
252         
253         if (useEnvmap)
254         {
255             glActiveTexture(GL_TEXTURE4);
256             rc.environment.environmentMap.bind();
257             glUniform1i(useEnvironmentMapLoc, 1);
258         }
259         else
260         {
261             glUniform1i(useEnvironmentMapLoc, 0);
262         }
263         glUniform1i(environmentMapLoc, 4);
264     }
265     
266     override void unbind(GenericMaterial mat, RenderingContext* rc)
267     {
268         bool useEnvmap = false;
269         if (rc.environment)
270         {
271             if (rc.environment.environmentMap)
272                 useEnvmap = true;
273         }
274         
275         if (useEnvmap)
276         {
277             glActiveTexture(GL_TEXTURE4);
278             rc.environment.environmentMap.unbind();
279         }
280         
281         glUseProgram(0);
282     }
283 }