1 /* 2 Copyright (c) 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.shaders.forward; 29 30 import std.stdio; 31 import std.math; 32 33 import dlib.core.memory; 34 import dlib.core.ownership; 35 import dlib.math.vector; 36 import dlib.math.matrix; 37 import dlib.math.transformation; 38 import dlib.math.interpolation; 39 import dlib.image.color; 40 import dlib.text.str; 41 42 import dagon.core.bindings; 43 import dagon.graphics.material; 44 import dagon.graphics.shader; 45 import dagon.graphics.state; 46 import dagon.graphics.cubemap; 47 import dagon.graphics.csm; 48 49 class ForwardShader: Shader 50 { 51 String vs, fs; 52 53 Matrix4x4f defaultShadowMatrix; 54 GLuint defaultShadowTexture; 55 56 this(Owner owner) 57 { 58 vs = Shader.load("data/__internal/shaders/Forward/Forward.vert.glsl"); 59 fs = Shader.load("data/__internal/shaders/Forward/Forward.frag.glsl"); 60 61 auto prog = New!ShaderProgram(vs, fs, this); 62 super(prog, owner); 63 64 defaultShadowMatrix = Matrix4x4f.identity; 65 66 glGenTextures(1, &defaultShadowTexture); 67 glActiveTexture(GL_TEXTURE0); 68 glBindTexture(GL_TEXTURE_2D_ARRAY, defaultShadowTexture); 69 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT24, 1, 1, 3, 0, GL_DEPTH_COMPONENT, GL_FLOAT, null); 70 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); 71 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); 72 glBindTexture(GL_TEXTURE_2D_ARRAY, 0); 73 } 74 75 ~this() 76 { 77 if (glIsFramebuffer(defaultShadowTexture)) 78 glDeleteFramebuffers(1, &defaultShadowTexture); 79 80 vs.free(); 81 fs.free(); 82 } 83 84 override void bindParameters(GraphicsState* state) 85 { 86 auto idiffuse = "diffuse" in state.material.inputs; 87 auto inormal = "normal" in state.material.inputs; 88 auto iheight = "height" in state.material.inputs; 89 auto ipbr = "pbr" in state.material.inputs; 90 auto iroughness = "roughness" in state.material.inputs; 91 auto imetallic = "metallic" in state.material.inputs; 92 auto ispecularity = "specularity" in state.material.inputs; 93 auto itranslucency = "translucency" in state.material.inputs; 94 auto itextureScale = "textureScale" in state.material.inputs; 95 auto iparallax = "parallax" in state.material.inputs; 96 auto iemission = "emission" in state.material.inputs; 97 auto ienergy = "energy" in state.material.inputs; 98 auto isphericalNormal = "sphericalNormal" in state.material.inputs; 99 auto ishadeless = "shadeless" in state.material.inputs; 100 101 setParameter("modelViewMatrix", state.modelViewMatrix); 102 setParameter("projectionMatrix", state.projectionMatrix); 103 setParameter("normalMatrix", state.normalMatrix); 104 setParameter("viewMatrix", state.viewMatrix); 105 setParameter("invViewMatrix", state.invViewMatrix); 106 setParameter("prevModelViewMatrix", state.prevModelViewMatrix); 107 108 setParameter("layer", cast(float)(state.layer)); 109 setParameter("opacity", state.opacity); 110 setParameter("textureScale", itextureScale.asVector2f); 111 112 setParameter("viewSize", state.resolution); 113 114 // Sun 115 Vector3f sunDirection = Vector3f(0.0f, 0.0f, 1.0f); 116 Color4f sunColor = Color4f(1.0f, 1.0f, 1.0f, 1.0f); 117 float sunEnergy = 1.0f; 118 bool sunScatteringEnabled = false; 119 float sunScatteringG = 0.0f; 120 float sunScatteringDensity = 1.0f; 121 int sunScatteringSamples = 1; 122 float sunScatteringMaxRandomStepOffset = 0.0f; 123 bool sunScatteringShadow = false; 124 bool shaded = !ishadeless.asBool; 125 if (state.material.sun) 126 { 127 auto sun = state.material.sun; 128 sunDirection = sun.directionAbsolute; 129 sunColor = sun.color; 130 sunEnergy = sun.energy; 131 sunScatteringG = 1.0f - sun.scattering; 132 sunScatteringDensity = sun.mediumDensity; 133 sunScatteringEnabled = sun.scatteringEnabled; 134 sunScatteringSamples = sun.scatteringSamples; 135 sunScatteringMaxRandomStepOffset = sun.scatteringMaxRandomStepOffset; 136 sunScatteringShadow = sun.scatteringUseShadow; 137 } 138 Vector4f sunDirHg = Vector4f(sunDirection); 139 sunDirHg.w = 0.0; 140 setParameter("sunDirection", (sunDirHg * state.viewMatrix).xyz); 141 setParameter("sunColor", sunColor); 142 setParameter("sunEnergy", sunEnergy); 143 setParameter("sunScatteringG", sunScatteringG); 144 setParameter("sunScatteringDensity", sunScatteringDensity); 145 setParameter("sunScattering", sunScatteringEnabled); 146 setParameter("sunScatteringSamples", sunScatteringSamples); 147 setParameter("sunScatteringMaxRandomStepOffset", sunScatteringMaxRandomStepOffset); 148 setParameter("sunScatteringShadow", sunScatteringShadow); 149 setParameter("shaded", shaded); 150 151 setParameter("time", state.localTime); 152 153 // Parallax mode 154 int parallaxMethod = iparallax.asInteger; 155 if (parallaxMethod > ParallaxOcclusionMapping) 156 parallaxMethod = ParallaxOcclusionMapping; 157 if (parallaxMethod < 0) 158 parallaxMethod = 0; 159 160 setParameter("sphericalNormal", cast(int)isphericalNormal.asBool); 161 162 // Diffuse 163 if (idiffuse.texture) 164 { 165 glActiveTexture(GL_TEXTURE0); 166 idiffuse.texture.bind(); 167 setParameter("diffuseTexture", cast(int)0); 168 setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorTexture"); 169 } 170 else 171 { 172 setParameter("diffuseVector", idiffuse.asVector4f); 173 setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorValue"); 174 } 175 176 // Normal/height 177 bool haveHeightMap = inormal.texture !is null; 178 if (haveHeightMap) 179 haveHeightMap = inormal.texture.image.channels == 4; 180 181 if (!haveHeightMap) 182 { 183 if (inormal.texture is null) 184 { 185 if (iheight.texture !is null) // we have height map, but no normal map 186 { 187 Color4f color = Color4f(0.5f, 0.5f, 1.0f, 0.0f); // default normal pointing upwards 188 inormal.texture = state.material.makeTexture(color, iheight.texture); 189 haveHeightMap = true; 190 } 191 else 192 { 193 Color4f color = Color4f(0.5f, 0.5f, 1.0f, 0.0f); // default normal pointing upwards 194 inormal.texture = state.material.makeTexture(color); 195 } 196 } 197 else 198 { 199 if (iheight.texture !is null) // we have both normal and height maps 200 { 201 inormal.texture = state.material.makeTexture(inormal.texture, iheight.texture); 202 haveHeightMap = true; 203 } 204 } 205 } 206 207 if (inormal.texture) 208 { 209 setParameter("normalTexture", 1); 210 setParameterSubroutine("normal", ShaderType.Fragment, "normalMap"); 211 212 glActiveTexture(GL_TEXTURE1); 213 inormal.texture.bind(); 214 } 215 else 216 { 217 setParameter("normalVector", state.material.normal.asVector3f); 218 setParameterSubroutine("normal", ShaderType.Fragment, "normalValue"); 219 } 220 221 // Height and parallax 222 // TODO: make these material properties 223 float parallaxScale = 0.03f; 224 float parallaxBias = -0.01f; 225 setParameter("parallaxScale", parallaxScale); 226 setParameter("parallaxBias", parallaxBias); 227 228 if (haveHeightMap) 229 { 230 setParameterSubroutine("height", ShaderType.Fragment, "heightMap"); 231 } 232 else 233 { 234 float h = 0.0f; //-parallaxBias / parallaxScale; 235 setParameter("heightScalar", h); 236 setParameterSubroutine("height", ShaderType.Fragment, "heightValue"); 237 parallaxMethod = ParallaxNone; 238 } 239 240 if (parallaxMethod == ParallaxSimple) 241 setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxSimple"); 242 else if (parallaxMethod == ParallaxOcclusionMapping) 243 setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxOcclusionMapping"); 244 else 245 setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxNone"); 246 247 // PBR 248 if (ipbr is null) 249 { 250 state.material.setInput("pbr", 0.0f); 251 ipbr = "pbr" in state.material.inputs; 252 } 253 if (ipbr.texture is null) 254 { 255 ipbr.texture = state.material.makeTexture(*iroughness, *imetallic, *ispecularity, *itranslucency); 256 } 257 glActiveTexture(GL_TEXTURE2); 258 ipbr.texture.bind(); 259 setParameter("pbrTexture", 2); 260 261 if (iroughness.texture is null) 262 { 263 setParameterSubroutine("roughness", ShaderType.Fragment, "roughnessValue"); 264 265 if (iroughness.type == MaterialInputType.Float) 266 setParameter("roughnessScalar", iroughness.asFloat); 267 else if (iroughness.type == MaterialInputType.Bool) 268 setParameter("roughnessScalar", cast(float)iroughness.asBool); 269 else if (iroughness.type == MaterialInputType.Integer) 270 setParameter("roughnessScalar", cast(float)iroughness.asInteger); 271 else if (iroughness.type == MaterialInputType.Vec2) 272 setParameter("roughnessScalar", iroughness.asVector2f.r); 273 else if (iroughness.type == MaterialInputType.Vec3) 274 setParameter("roughnessScalar", iroughness.asVector3f.r); 275 else if (iroughness.type == MaterialInputType.Vec4) 276 setParameter("roughnessScalar", iroughness.asVector4f.r); 277 } 278 else 279 { 280 setParameterSubroutine("roughness", ShaderType.Fragment, "roughnessMap"); 281 } 282 283 if (imetallic.texture is null) 284 { 285 setParameterSubroutine("metallic", ShaderType.Fragment, "metallicValue"); 286 287 if (imetallic.type == MaterialInputType.Float) 288 setParameter("metallicScalar", imetallic.asFloat); 289 else if (imetallic.type == MaterialInputType.Bool) 290 setParameter("metallicScalar", cast(float)imetallic.asBool); 291 else if (imetallic.type == MaterialInputType.Integer) 292 setParameter("metallicScalar", cast(float)imetallic.asInteger); 293 else if (imetallic.type == MaterialInputType.Vec2) 294 setParameter("metallicScalar", imetallic.asVector2f.r); 295 else if (imetallic.type == MaterialInputType.Vec3) 296 setParameter("metallicScalar", imetallic.asVector3f.r); 297 else if (imetallic.type == MaterialInputType.Vec4) 298 setParameter("metallicScalar", imetallic.asVector4f.r); 299 } 300 else 301 { 302 setParameterSubroutine("metallic", ShaderType.Fragment, "metallicMap"); 303 } 304 305 if (ispecularity.texture is null) 306 { 307 setParameterSubroutine("specularity", ShaderType.Fragment, "specularityValue"); 308 309 if (ispecularity.type == MaterialInputType.Float) 310 setParameter("specularityScalar", ispecularity.asFloat); 311 else if (ispecularity.type == MaterialInputType.Bool) 312 setParameter("specularityScalar", cast(float)ispecularity.asBool); 313 else if (ispecularity.type == MaterialInputType.Integer) 314 setParameter("specularityScalar", cast(float)ispecularity.asInteger); 315 else if (ispecularity.type == MaterialInputType.Vec2) 316 setParameter("specularityScalar", ispecularity.asVector2f.r); 317 else if (ispecularity.type == MaterialInputType.Vec3) 318 setParameter("specularityScalar", ispecularity.asVector3f.r); 319 else if (ispecularity.type == MaterialInputType.Vec4) 320 setParameter("specularityScalar", ispecularity.asVector4f.r); 321 } 322 else 323 { 324 setParameterSubroutine("specularity", ShaderType.Fragment, "specularityMap"); 325 } 326 327 if (itranslucency.texture is null) 328 { 329 setParameterSubroutine("translucency", ShaderType.Fragment, "translucencyValue"); 330 331 if (itranslucency.type == MaterialInputType.Float) 332 setParameter("translucencyScalar", itranslucency.asFloat); 333 else if (itranslucency.type == MaterialInputType.Bool) 334 setParameter("translucencyScalar", cast(float)itranslucency.asBool); 335 else if (itranslucency.type == MaterialInputType.Integer) 336 setParameter("translucencyScalar", cast(float)itranslucency.asInteger); 337 else if (itranslucency.type == MaterialInputType.Vec2) 338 setParameter("translucencyScalar", itranslucency.asVector2f.r); 339 else if (itranslucency.type == MaterialInputType.Vec3) 340 setParameter("translucencyScalar", itranslucency.asVector3f.r); 341 else if (itranslucency.type == MaterialInputType.Vec4) 342 setParameter("translucencyScalar", itranslucency.asVector4f.r); 343 } 344 else 345 { 346 setParameterSubroutine("translucency", ShaderType.Fragment, "translucencyMap"); 347 } 348 349 // Emission 350 if (iemission.texture) 351 { 352 glActiveTexture(GL_TEXTURE3); 353 iemission.texture.bind(); 354 setParameter("emissionTexture", cast(int)3); 355 setParameterSubroutine("emission", ShaderType.Fragment, "emissionColorTexture"); 356 } 357 else 358 { 359 setParameter("emissionVector", iemission.asVector4f); 360 setParameterSubroutine("emission", ShaderType.Fragment, "emissionColorValue"); 361 } 362 setParameter("energy", ienergy.asFloat); 363 364 // Environment 365 if (state.environment) 366 { 367 setParameter("fogColor", state.environment.fogColor); 368 setParameter("fogStart", state.environment.fogStart); 369 setParameter("fogEnd", state.environment.fogEnd); 370 setParameter("ambientEnergy", state.environment.ambientEnergy); 371 372 if (state.environment.ambientMap) 373 { 374 glActiveTexture(GL_TEXTURE4); 375 state.environment.ambientMap.bind(); 376 if (cast(Cubemap)state.environment.ambientMap) 377 { 378 setParameter("ambientTextureCube", 4); 379 setParameterSubroutine("ambient", ShaderType.Fragment, "ambientCubemap"); 380 } 381 else 382 { 383 setParameter("ambientTexture", 4); 384 setParameterSubroutine("ambient", ShaderType.Fragment, "ambientEquirectangularMap"); 385 } 386 } 387 else 388 { 389 setParameter("ambientVector", state.environment.ambientColor); 390 setParameterSubroutine("ambient", ShaderType.Fragment, "ambientColor"); 391 } 392 } 393 else 394 { 395 setParameter("fogColor", Color4f(0.5f, 0.5f, 0.5f, 1.0f)); 396 setParameter("fogStart", 0.0f); 397 setParameter("fogEnd", 1000.0f); 398 setParameter("ambientEnergy", 1.0f); 399 setParameter("ambientVector", Color4f(0.5f, 0.5f, 0.5f, 1.0f)); 400 setParameterSubroutine("ambient", ShaderType.Fragment, "ambientColor"); 401 } 402 403 // Shadow map 404 if (state.material.sun) 405 { 406 if (state.material.sun.shadowEnabled) 407 { 408 CascadedShadowMap csm = cast(CascadedShadowMap)state.material.sun.shadowMap; 409 410 glActiveTexture(GL_TEXTURE5); 411 glBindTexture(GL_TEXTURE_2D_ARRAY, csm.depthTexture); 412 setParameter("shadowTextureArray", 5); 413 setParameter("shadowResolution", cast(float)csm.resolution); 414 setParameter("shadowMatrix1", csm.area[0].shadowMatrix); 415 setParameter("shadowMatrix2", csm.area[1].shadowMatrix); 416 setParameter("shadowMatrix3", csm.area[2].shadowMatrix); 417 setParameterSubroutine("shadowMap", ShaderType.Fragment, "shadowMapCascaded"); 418 } 419 else 420 { 421 glActiveTexture(GL_TEXTURE5); 422 glBindTexture(GL_TEXTURE_2D_ARRAY, defaultShadowTexture); 423 setParameter("shadowTextureArray", 5); 424 setParameter("shadowMatrix1", defaultShadowMatrix); 425 setParameter("shadowMatrix2", defaultShadowMatrix); 426 setParameter("shadowMatrix3", defaultShadowMatrix); 427 setParameterSubroutine("shadowMap", ShaderType.Fragment, "shadowMapNone"); 428 } 429 } 430 else 431 { 432 glActiveTexture(GL_TEXTURE5); 433 glBindTexture(GL_TEXTURE_2D_ARRAY, defaultShadowTexture); 434 setParameter("shadowTextureArray", 5); 435 setParameter("shadowMatrix1", defaultShadowMatrix); 436 setParameter("shadowMatrix2", defaultShadowMatrix); 437 setParameter("shadowMatrix3", defaultShadowMatrix); 438 setParameterSubroutine("shadowMap", ShaderType.Fragment, "shadowMapNone"); 439 } 440 441 super.bindParameters(state); 442 } 443 444 override void unbindParameters(GraphicsState* state) 445 { 446 super.unbindParameters(state); 447 448 glActiveTexture(GL_TEXTURE0); 449 glBindTexture(GL_TEXTURE_2D, 0); 450 451 glActiveTexture(GL_TEXTURE1); 452 glBindTexture(GL_TEXTURE_2D, 0); 453 454 glActiveTexture(GL_TEXTURE2); 455 glBindTexture(GL_TEXTURE_2D, 0); 456 457 glActiveTexture(GL_TEXTURE3); 458 glBindTexture(GL_TEXTURE_2D, 0); 459 460 glActiveTexture(GL_TEXTURE4); 461 glBindTexture(GL_TEXTURE_2D, 0); 462 glBindTexture(GL_TEXTURE_CUBE_MAP, 0); 463 464 glActiveTexture(GL_TEXTURE5); 465 glBindTexture(GL_TEXTURE_2D, 0); 466 467 glActiveTexture(GL_TEXTURE0); 468 } 469 }