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 }