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 }