From eb39e88682e2ef297096d22c9930d1fb2cb76103 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 19 Feb 2018 02:01:33 +0100 Subject: [PATCH 1/2] - clean up the main.fp light handling code so that a single ApplyDynLights function applies all dynamic light --- wadsrc/static/shaders/glsl/main.fp | 375 ++++++++++++++++------------- 1 file changed, 210 insertions(+), 165 deletions(-) diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index b868f86c3..a6c02654d 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -221,39 +221,26 @@ float shadowmapAttenuation(vec4 lightpos, float shadowIndex) #endif } -#endif - -//=========================================================================== -// -// Standard lambertian diffuse light calculation -// -//=========================================================================== - -float diffuseContribution(vec3 lightDirection, vec3 normal) +float shadowAttenuation(vec4 lightpos, float lightcolorA) { - return max(dot(normal, lightDirection), 0.0f); + float shadowIndex = abs(lightcolorA) - 1.0; + return shadowmapAttenuation(lightpos, shadowIndex); } -//=========================================================================== -// -// Blinn specular light calculation -// -//=========================================================================== +#else -float blinnSpecularContribution(float diffuseContribution, vec3 lightDirection, vec3 faceNormal, float glossiness, float specularLevel) +float shadowAttenuation(vec4 lightpos, float lightcolorA) { - if (diffuseContribution > 0.0f) - { - vec3 viewDir = normalize(uCameraPos.xyz - pixelpos.xyz); - vec3 halfDir = normalize(lightDirection + viewDir); - float specAngle = max(dot(halfDir, faceNormal), 0.0f); - float phExp = glossiness * 4.0f; - return specularLevel * pow(specAngle, phExp); - } - else - { - return 0.0f; - } + return 1.0; +} + +#endif + +float spotLightAttenuation(vec4 lightpos, vec3 spotdir, float lightCosInnerAngle, float lightCosOuterAngle) +{ + vec3 lightDirection = normalize(lightpos.xyz - pixelpos.xyz); + float cosDir = dot(lightDirection, spotdir); + return smoothstep(lightCosOuterAngle, lightCosInnerAngle, cosDir); } //=========================================================================== @@ -262,7 +249,7 @@ float blinnSpecularContribution(float diffuseContribution, vec3 lightDirection, // //=========================================================================== -#if defined(SPECULAR) || defined(PBR) +#if defined(SPECULAR) || defined(PBR) // To do: create define for when normal map is present mat3 cotangent_frame(vec3 n, vec3 p, vec2 uv) { // get edge vectors of the pixel triangle @@ -313,46 +300,118 @@ vec3 ApplyNormalMap() #endif //=========================================================================== +// Dynamic light material modes begin // -// Calculates the brightness of a dynamic point light -// +// To do: move each of the following #if blocks needs to its own file //=========================================================================== -vec2 pointLightAttenuation(vec4 lightpos, float lightcolorA) +#if !defined(NUM_UBO_LIGHTS) && !defined(SHADER_STORAGE_LIGHTS) // Legacy light mode (no lights[] array) + +vec3 ApplyDynLights(vec3 material, vec3 color) { - float attenuation = max(lightpos.w - distance(pixelpos.xyz, lightpos.xyz),0.0) / lightpos.w; - if (attenuation == 0.0) return vec2(0.0); -#ifdef SUPPORTS_SHADOWMAPS - float shadowIndex = abs(lightcolorA) - 1.0; - attenuation *= shadowmapAttenuation(lightpos, shadowIndex); -#endif - if (lightcolorA >= 0.0) // Sign bit is the attenuated light flag + return material * clamp(color + desaturate(uDynLightColor).rgb, 0.0, 1.4); +} + +#elif defined(SPECULAR) // Specular light mode + +vec2 lightAttenuation(int i, vec3 normal, vec3 viewdir, float lightcolorA) +{ + vec4 lightpos = lights[i]; + vec4 lightspot1 = lights[i+2]; + vec4 lightspot2 = lights[i+3]; + + float lightdistance = distance(lightpos.xyz, pixelpos.xyz); + if (lightpos.w < lightdistance) + return vec2(0.0); // Early out lights touching surface but not this fragment + + float attenuation = clamp((lightpos.w - lightdistance) / lightpos.w, 0.0, 1.0); + + if (lightspot1.w == 1.0) + attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); + + vec3 lightdir = normalize(lightpos.xyz - pixelpos.xyz); + + if (lightcolorA < 0.0) // Sign bit is the attenuated light flag + attenuation *= clamp(dot(normal, lightdir), 0.0, 1.0); + + if (attenuation > 0.0) // Skip shadow map test if possible + attenuation *= shadowAttenuation(lightpos, lightcolorA); + + if (attenuation <= 0.0) + return vec2(0.0); + + float glossiness = uSpecularMaterial.x; + float specularLevel = uSpecularMaterial.y; + + vec3 halfdir = normalize(viewdir + lightdir); + float specAngle = clamp(dot(halfdir, normal), 0.0f, 1.0f); + float phExp = glossiness * 4.0f; + return vec2(attenuation, attenuation * specularLevel * pow(specAngle, phExp)); +} + +vec3 ApplyDynLights(vec3 material, vec3 color) +{ + if (uLightIndex >= 0) { - return vec2(attenuation, 0.0); + vec4 dynlight = uDynLightColor; + vec4 specular = vec4(0.0, 0.0, 0.0, 1.0); + + vec3 normal = ApplyNormalMap(); + vec3 viewdir = normalize(uCameraPos.xyz - pixelpos.xyz); + + ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); + + if (lightRange.z > lightRange.x) + { + // modulated lights + for(int i=lightRange.x; i lightRange.z) + { + vec4 addlight = vec4(0.0,0.0,0.0,0.0); + + // additive lights + for(int i=lightRange.z; i= 0) { ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); @@ -458,7 +506,7 @@ vec3 applyLight(vec3 albedo, vec3 ambientLight) vec3 L = normalize(lightpos.xyz - worldpos); vec3 H = normalize(V + L); - float attenuation = quadraticDistanceAttenuation(lightpos) * shadowAttenuation(lightpos, lightcolor.a); + float attenuation = quadraticDistanceAttenuation(lightpos); if (lightspot1.w == 1.0) attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); if (lightcolor.a < 0.0) @@ -498,7 +546,7 @@ vec3 applyLight(vec3 albedo, vec3 ambientLight) vec3 L = normalize(lightpos.xyz - worldpos); vec3 H = normalize(V + L); - float attenuation = quadraticDistanceAttenuation(lightpos) * shadowAttenuation(lightpos, lightcolor.a); + float attenuation = quadraticDistanceAttenuation(lightpos); if (lightspot1.w == 1.0) attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); if (lightcolor.a < 0.0) @@ -527,7 +575,6 @@ vec3 applyLight(vec3 albedo, vec3 ambientLight) } } } -#endif // Pretend we sampled the sector light level from an irradiance map @@ -555,8 +602,94 @@ vec3 applyLight(vec3 albedo, vec3 ambientLight) return pow(color, vec3(1.0 / 2.2)); } +#else // Normal dynlight mode + +vec3 lightContribution(int i, vec3 normal) +{ + vec4 lightpos = lights[i]; + vec4 lightcolor = lights[i+1]; + vec4 lightspot1 = lights[i+2]; + vec4 lightspot2 = lights[i+3]; + + float lightdistance = distance(lightpos.xyz, pixelpos.xyz); + if (lightpos.w < lightdistance) + return vec3(0.0); // Early out lights touching surface but not this fragment + + float attenuation = clamp((lightpos.w - lightdistance) / lightpos.w, 0.0, 1.0); + + if (lightspot1.w == 1.0) + attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); + + if (lightcolor.a < 0.0) // Sign bit is the attenuated light flag + { + vec3 lightdir = normalize(lightpos.xyz - pixelpos.xyz); + attenuation *= clamp(dot(normal, lightdir), 0.0, 1.0); + } + + if (attenuation > 0.0) // Skip shadow map test if possible + { + attenuation *= shadowAttenuation(lightpos, lightcolor.a); + return lightcolor.rgb * attenuation; + } + else + { + return vec3(0.0); + } +} + +vec3 ApplyDynLights(vec3 material, vec3 color) +{ + if (uLightIndex >= 0) + { + vec4 dynlight = uDynLightColor; + vec3 normal = ApplyNormalMap(); + + ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); + + if (lightRange.z > lightRange.x) + { + // modulated lights + for(int i=lightRange.x; i lightRange.z) + { + vec4 addlight = vec4(0.0,0.0,0.0,0.0); + + // additive lights + for(int i=lightRange.z; i= 0) - { - ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); - if (lightRange.z > lightRange.x) - { - // - // modulated lights - // - for(int i=lightRange.x; i= 0) - { - ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); - if (lightRange.w > lightRange.z) - { - vec4 addlight = vec4(0.0,0.0,0.0,0.0); - - // - // additive lights - these can be done after the alpha test. - // - for(int i=lightRange.z; i Date: Tue, 20 Feb 2018 00:13:05 +0100 Subject: [PATCH 2/2] - move material light modes to their own subshader lumps --- src/gl/shaders/gl_shader.cpp | 68 +-- src/gl/shaders/gl_shader.h | 4 +- wadsrc/static/shaders/glsl/main.fp | 397 +----------------- .../static/shaders/glsl/material_nolight.fp | 5 + wadsrc/static/shaders/glsl/material_normal.fp | 80 ++++ wadsrc/static/shaders/glsl/material_pbr.fp | 189 +++++++++ .../static/shaders/glsl/material_specular.fp | 97 +++++ 7 files changed, 415 insertions(+), 425 deletions(-) create mode 100644 wadsrc/static/shaders/glsl/material_nolight.fp create mode 100644 wadsrc/static/shaders/glsl/material_normal.fp create mode 100644 wadsrc/static/shaders/glsl/material_pbr.fp create mode 100644 wadsrc/static/shaders/glsl/material_specular.fp diff --git a/src/gl/shaders/gl_shader.cpp b/src/gl/shaders/gl_shader.cpp index 05ddaa234..141ee333a 100644 --- a/src/gl/shaders/gl_shader.cpp +++ b/src/gl/shaders/gl_shader.cpp @@ -134,7 +134,7 @@ static FString RemoveLegacyUserUniforms(FString code) return code; } -bool FShader::Load(const char * name, const char * vert_prog_lump, const char * frag_prog_lump, const char * proc_prog_lump, const char * defines) +bool FShader::Load(const char * name, const char * vert_prog_lump, const char * frag_prog_lump, const char * proc_prog_lump, const char * light_fragprog, const char * defines) { static char buffer[10000]; FString error; @@ -346,6 +346,14 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * } } + if (light_fragprog) + { + int pp_lump = Wads.CheckNumForFullName(light_fragprog); + if (pp_lump == -1) I_Error("Unable to load '%s'", light_fragprog); + FMemLump pp_data = Wads.ReadLump(pp_lump); + fp_comb << pp_data.GetString().GetChars() << "\n"; + } + if (gl.flags & RFL_NO_CLIP_PLANES) { // On ATI's GL3 drivers we have to disable gl_ClipDistance because it's hopelessly broken. @@ -514,7 +522,7 @@ bool FShader::Bind() // //========================================================================== -FShader *FShaderCollection::Compile (const char *ShaderName, const char *ShaderPath, const char *shaderdefines, bool usediscard, EPassType passType) +FShader *FShaderCollection::Compile (const char *ShaderName, const char *ShaderPath, const char *LightModePath, const char *shaderdefines, bool usediscard, EPassType passType) { FString defines; defines += shaderdefines; @@ -527,7 +535,7 @@ FShader *FShaderCollection::Compile (const char *ShaderName, const char *ShaderP try { shader = new FShader(ShaderName); - if (!shader->Load(ShaderName, "shaders/glsl/main.vp", "shaders/glsl/main.fp", ShaderPath, defines.GetChars())) + if (!shader->Load(ShaderName, "shaders/glsl/main.vp", "shaders/glsl/main.fp", ShaderPath, LightModePath, defines.GetChars())) { I_FatalError("Unable to load shader %s\n", ShaderName); } @@ -564,30 +572,31 @@ struct FDefaultShader { const char * ShaderName; const char * gettexelfunc; + const char * lightfunc; const char * Defines; }; // Note: the MaterialShaderIndex enum in gl_shader.h needs to be updated whenever this array is modified. static const FDefaultShader defaultshaders[]= { - {"Default", "shaders/glsl/func_normal.fp", ""}, - {"Warp 1", "shaders/glsl/func_warp1.fp", ""}, - {"Warp 2", "shaders/glsl/func_warp2.fp", ""}, - {"Brightmap","shaders/glsl/func_brightmap.fp", ""}, - {"Specular","shaders/glsl/func_normal.fp", "#define SPECULAR\n"}, - {"SpecularBrightmap","shaders/glsl/func_brightmap.fp", "#define SPECULAR\n"}, - {"PBR","shaders/glsl/func_normal.fp", "#define PBR\n"}, - {"PBRBrightmap","shaders/glsl/func_brightmap.fp", "#define PBR\n"}, - {"No Texture", "shaders/glsl/func_notexture.fp", ""}, - {"Basic Fuzz", "shaders/glsl/fuzz_standard.fp", ""}, - {"Smooth Fuzz", "shaders/glsl/fuzz_smooth.fp", ""}, - {"Swirly Fuzz", "shaders/glsl/fuzz_swirly.fp", ""}, - {"Translucent Fuzz", "shaders/glsl/fuzz_smoothtranslucent.fp", ""}, - {"Jagged Fuzz", "shaders/glsl/fuzz_jagged.fp", ""}, - {"Noise Fuzz", "shaders/glsl/fuzz_noise.fp", ""}, - {"Smooth Noise Fuzz", "shaders/glsl/fuzz_smoothnoise.fp", ""}, - {"Software Fuzz", "shaders/glsl/fuzz_software.fp", ""}, - {NULL,NULL,NULL} + {"Default", "shaders/glsl/func_normal.fp", "shaders/glsl/material_normal.fp", ""}, + {"Warp 1", "shaders/glsl/func_warp1.fp", "shaders/glsl/material_normal.fp", ""}, + {"Warp 2", "shaders/glsl/func_warp2.fp", "shaders/glsl/material_normal.fp", ""}, + {"Brightmap","shaders/glsl/func_brightmap.fp", "shaders/glsl/material_normal.fp", ""}, + {"Specular", "shaders/glsl/func_normal.fp", "shaders/glsl/material_specular.fp", "#define SPECULAR\n#define NORMALMAP\n"}, + {"SpecularBrightmap", "shaders/glsl/func_brightmap.fp", "shaders/glsl/material_specular.fp", "#define SPECULAR\n#define NORMALMAP\n"}, + {"PBR","shaders/glsl/func_normal.fp", "shaders/glsl/material_pbr.fp", "#define PBR\n#define NORMALMAP\n"}, + {"PBRBrightmap","shaders/glsl/func_brightmap.fp", "shaders/glsl/material_pbr.fp", "#define PBR\n#define NORMALMAP\n"}, + {"No Texture", "shaders/glsl/func_notexture.fp", "shaders/glsl/material_normal.fp", ""}, + {"Basic Fuzz", "shaders/glsl/fuzz_standard.fp", "shaders/glsl/material_normal.fp", ""}, + {"Smooth Fuzz", "shaders/glsl/fuzz_smooth.fp", "shaders/glsl/material_normal.fp", ""}, + {"Swirly Fuzz", "shaders/glsl/fuzz_swirly.fp", "shaders/glsl/material_normal.fp", ""}, + {"Translucent Fuzz", "shaders/glsl/fuzz_smoothtranslucent.fp", "shaders/glsl/material_normal.fp", ""}, + {"Jagged Fuzz", "shaders/glsl/fuzz_jagged.fp", "shaders/glsl/material_normal.fp", ""}, + {"Noise Fuzz", "shaders/glsl/fuzz_noise.fp", "shaders/glsl/material_normal.fp", ""}, + {"Smooth Noise Fuzz", "shaders/glsl/fuzz_smoothnoise.fp", "shaders/glsl/material_normal.fp", ""}, + {"Software Fuzz", "shaders/glsl/fuzz_software.fp", "shaders/glsl/material_normal.fp", ""}, + {nullptr,nullptr,nullptr,nullptr} }; static TArray usershaders; @@ -598,15 +607,16 @@ struct FEffectShader const char *vp; const char *fp1; const char *fp2; + const char *fp3; const char *defines; }; static const FEffectShader effectshaders[]= { - { "fogboundary", "shaders/glsl/main.vp", "shaders/glsl/fogboundary.fp", NULL, "#define NO_ALPHATEST\n" }, - { "spheremap", "shaders/glsl/main.vp", "shaders/glsl/main.fp", "shaders/glsl/func_normal.fp", "#define SPHEREMAP\n#define NO_ALPHATEST\n" }, - { "burn", "shaders/glsl/main.vp", "shaders/glsl/burn.fp", NULL, "#define SIMPLE\n#define NO_ALPHATEST\n" }, - { "stencil", "shaders/glsl/main.vp", "shaders/glsl/stencil.fp", NULL, "#define SIMPLE\n#define NO_ALPHATEST\n" }, + { "fogboundary", "shaders/glsl/main.vp", "shaders/glsl/fogboundary.fp", nullptr, nullptr, "#define NO_ALPHATEST\n" }, + { "spheremap", "shaders/glsl/main.vp", "shaders/glsl/main.fp", "shaders/glsl/func_normal.fp", "shaders/glsl/material_normal.fp", "#define SPHEREMAP\n#define NO_ALPHATEST\n" }, + { "burn", "shaders/glsl/main.vp", "shaders/glsl/burn.fp", nullptr, nullptr, "#define SIMPLE\n#define NO_ALPHATEST\n" }, + { "stencil", "shaders/glsl/main.vp", "shaders/glsl/stencil.fp", nullptr, nullptr, "#define SIMPLE\n#define NO_ALPHATEST\n" }, }; FShaderManager::FShaderManager() @@ -726,11 +736,11 @@ void FShaderCollection::CompileShaders(EPassType passType) for(int i=0;defaultshaders[i].ShaderName != NULL;i++) { - FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, defaultshaders[i].Defines, true, passType); + FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, true, passType); mMaterialShaders.Push(shc); if (i < SHADER_NoTexture) { - FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, defaultshaders[i].Defines, false, passType); + FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, false, passType); mMaterialShadersNAT.Push(shc); } } @@ -740,7 +750,7 @@ void FShaderCollection::CompileShaders(EPassType passType) FString name = ExtractFileBase(usershaders[i]); FName sfn = name; - FShader *shc = Compile(sfn, usershaders[i], "", true, passType); + FShader *shc = Compile(sfn, usershaders[i], "shaders/glsl/material_normal.fp", "", true, passType); mMaterialShaders.Push(shc); } @@ -748,7 +758,7 @@ void FShaderCollection::CompileShaders(EPassType passType) { FShader *eff = new FShader(effectshaders[i].ShaderName); if (!eff->Load(effectshaders[i].ShaderName, effectshaders[i].vp, effectshaders[i].fp1, - effectshaders[i].fp2, effectshaders[i].defines)) + effectshaders[i].fp2, effectshaders[i].fp3, effectshaders[i].defines)) { delete eff; } diff --git a/src/gl/shaders/gl_shader.h b/src/gl/shaders/gl_shader.h index 8041f4880..8b119aec9 100644 --- a/src/gl/shaders/gl_shader.h +++ b/src/gl/shaders/gl_shader.h @@ -317,7 +317,7 @@ public: ~FShader(); - bool Load(const char * name, const char * vert_prog_lump, const char * fragprog, const char * fragprog2, const char *defines); + bool Load(const char * name, const char * vert_prog_lump, const char * fragprog, const char * fragprog2, const char * light_fragprog, const char *defines); void SetColormapColor(float r, float g, float b, float r1, float g1, float b1); void SetGlowParams(float *topcolors, float topheight, float *bottomcolors, float bottomheight); @@ -367,7 +367,7 @@ class FShaderCollection public: FShaderCollection(EPassType passType); ~FShaderCollection(); - FShader *Compile(const char *ShaderName, const char *ShaderPath, const char *shaderdefines, bool usediscard, EPassType passType); + FShader *Compile(const char *ShaderName, const char *ShaderPath, const char *LightModePath, const char *shaderdefines, bool usediscard, EPassType passType); int Find(const char *mame); FShader *BindEffect(int effect); void ApplyMatrices(VSMatrix *proj, VSMatrix *view); diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index a6c02654d..444a9811f 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -15,7 +15,7 @@ out vec4 FragNormal; vec4 Process(vec4 color); vec4 ProcessTexel(); vec4 ProcessLight(vec4 color); - +vec3 ProcessMaterial(vec3 material, vec3 color); //=========================================================================== // @@ -249,7 +249,7 @@ float spotLightAttenuation(vec4 lightpos, vec3 spotdir, float lightCosInnerAngle // //=========================================================================== -#if defined(SPECULAR) || defined(PBR) // To do: create define for when normal map is present +#if defined(NORMALMAP) mat3 cotangent_frame(vec3 n, vec3 p, vec2 uv) { // get edge vectors of the pixel triangle @@ -299,397 +299,6 @@ vec3 ApplyNormalMap() } #endif -//=========================================================================== -// Dynamic light material modes begin -// -// To do: move each of the following #if blocks needs to its own file -//=========================================================================== - -#if !defined(NUM_UBO_LIGHTS) && !defined(SHADER_STORAGE_LIGHTS) // Legacy light mode (no lights[] array) - -vec3 ApplyDynLights(vec3 material, vec3 color) -{ - return material * clamp(color + desaturate(uDynLightColor).rgb, 0.0, 1.4); -} - -#elif defined(SPECULAR) // Specular light mode - -vec2 lightAttenuation(int i, vec3 normal, vec3 viewdir, float lightcolorA) -{ - vec4 lightpos = lights[i]; - vec4 lightspot1 = lights[i+2]; - vec4 lightspot2 = lights[i+3]; - - float lightdistance = distance(lightpos.xyz, pixelpos.xyz); - if (lightpos.w < lightdistance) - return vec2(0.0); // Early out lights touching surface but not this fragment - - float attenuation = clamp((lightpos.w - lightdistance) / lightpos.w, 0.0, 1.0); - - if (lightspot1.w == 1.0) - attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); - - vec3 lightdir = normalize(lightpos.xyz - pixelpos.xyz); - - if (lightcolorA < 0.0) // Sign bit is the attenuated light flag - attenuation *= clamp(dot(normal, lightdir), 0.0, 1.0); - - if (attenuation > 0.0) // Skip shadow map test if possible - attenuation *= shadowAttenuation(lightpos, lightcolorA); - - if (attenuation <= 0.0) - return vec2(0.0); - - float glossiness = uSpecularMaterial.x; - float specularLevel = uSpecularMaterial.y; - - vec3 halfdir = normalize(viewdir + lightdir); - float specAngle = clamp(dot(halfdir, normal), 0.0f, 1.0f); - float phExp = glossiness * 4.0f; - return vec2(attenuation, attenuation * specularLevel * pow(specAngle, phExp)); -} - -vec3 ApplyDynLights(vec3 material, vec3 color) -{ - if (uLightIndex >= 0) - { - vec4 dynlight = uDynLightColor; - vec4 specular = vec4(0.0, 0.0, 0.0, 1.0); - - vec3 normal = ApplyNormalMap(); - vec3 viewdir = normalize(uCameraPos.xyz - pixelpos.xyz); - - ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); - - if (lightRange.z > lightRange.x) - { - // modulated lights - for(int i=lightRange.x; i lightRange.z) - { - vec4 addlight = vec4(0.0,0.0,0.0,0.0); - - // additive lights - for(int i=lightRange.z; i= 0) - { - ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); - if (lightRange.z > lightRange.x) - { - // - // modulated lights - // - for(int i=lightRange.x; i 0.0) - { - attenuation *= shadowAttenuation(lightpos, lightcolor.a); - - vec3 radiance = lightcolor.rgb * attenuation; - - // cook-torrance brdf - float NDF = DistributionGGX(N, H, roughness); - float G = GeometrySmith(N, V, L, roughness); - vec3 F = fresnelSchlick(clamp(dot(H, V), 0.0, 1.0), F0); - - vec3 kS = F; - vec3 kD = (vec3(1.0) - kS) * (1.0 - metallic); - - vec3 nominator = NDF * G * F; - float denominator = 4.0 * clamp(dot(N, V), 0.0, 1.0) * clamp(dot(N, L), 0.0, 1.0); - vec3 specular = nominator / max(denominator, 0.001); - - Lo += (kD * albedo / PI + specular) * radiance; - } - } - // - // subtractive lights - // - for(int i=lightRange.y; i 0.0) - { - attenuation *= shadowAttenuation(lightpos, lightcolor.a); - - vec3 radiance = lightcolor.rgb * attenuation; - - // cook-torrance brdf - float NDF = DistributionGGX(N, H, roughness); - float G = GeometrySmith(N, V, L, roughness); - vec3 F = fresnelSchlick(clamp(dot(H, V), 0.0, 1.0), F0); - - vec3 kS = F; - vec3 kD = (vec3(1.0) - kS) * (1.0 - metallic); - - vec3 nominator = NDF * G * F; - float denominator = 4.0 * clamp(dot(N, V), 0.0, 1.0) * clamp(dot(N, L), 0.0, 1.0); - vec3 specular = nominator / max(denominator, 0.001); - - Lo -= (kD * albedo / PI + specular) * radiance; - } - } - } - } - - // Pretend we sampled the sector light level from an irradiance map - - vec3 F = fresnelSchlickRoughness(clamp(dot(N, V), 0.0, 1.0), F0, roughness); - - vec3 kS = F; - vec3 kD = 1.0 - kS; - - vec3 irradiance = ambientLight; // texture(irradianceMap, N).rgb - vec3 diffuse = irradiance * albedo; - - //kD *= 1.0 - metallic; - //const float MAX_REFLECTION_LOD = 4.0; - //vec3 prefilteredColor = textureLod(prefilterMap, R, roughness * MAX_REFLECTION_LOD).rgb; - //vec2 envBRDF = texture(brdfLUT, vec2(clamp(dot(N, V), 0.0, 1.0), roughness)).rg; - //vec3 specular = prefilteredColor * (F * envBRDF.x + envBRDF.y); - - //vec3 ambient = (kD * diffuse + specular) * ao; - vec3 ambient = (kD * diffuse) * ao; - - vec3 color = ambient + Lo; - - // Tonemap (reinhard) and apply sRGB gamma - //color = color / (color + vec3(1.0)); - return pow(color, vec3(1.0 / 2.2)); -} - -#else // Normal dynlight mode - -vec3 lightContribution(int i, vec3 normal) -{ - vec4 lightpos = lights[i]; - vec4 lightcolor = lights[i+1]; - vec4 lightspot1 = lights[i+2]; - vec4 lightspot2 = lights[i+3]; - - float lightdistance = distance(lightpos.xyz, pixelpos.xyz); - if (lightpos.w < lightdistance) - return vec3(0.0); // Early out lights touching surface but not this fragment - - float attenuation = clamp((lightpos.w - lightdistance) / lightpos.w, 0.0, 1.0); - - if (lightspot1.w == 1.0) - attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); - - if (lightcolor.a < 0.0) // Sign bit is the attenuated light flag - { - vec3 lightdir = normalize(lightpos.xyz - pixelpos.xyz); - attenuation *= clamp(dot(normal, lightdir), 0.0, 1.0); - } - - if (attenuation > 0.0) // Skip shadow map test if possible - { - attenuation *= shadowAttenuation(lightpos, lightcolor.a); - return lightcolor.rgb * attenuation; - } - else - { - return vec3(0.0); - } -} - -vec3 ApplyDynLights(vec3 material, vec3 color) -{ - if (uLightIndex >= 0) - { - vec4 dynlight = uDynLightColor; - vec3 normal = ApplyNormalMap(); - - ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); - - if (lightRange.z > lightRange.x) - { - // modulated lights - for(int i=lightRange.x; i lightRange.z) - { - vec4 addlight = vec4(0.0,0.0,0.0,0.0); - - // additive lights - for(int i=lightRange.z; i 0.0) // Skip shadow map test if possible + { + attenuation *= shadowAttenuation(lightpos, lightcolor.a); + return lightcolor.rgb * attenuation; + } + else + { + return vec3(0.0); + } +} + +vec3 ProcessMaterial(vec3 material, vec3 color) +{ + if (uLightIndex >= 0) + { + vec4 dynlight = uDynLightColor; + vec3 normal = ApplyNormalMap(); + + ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); + + if (lightRange.z > lightRange.x) + { + // modulated lights + for(int i=lightRange.x; i lightRange.z) + { + vec4 addlight = vec4(0.0,0.0,0.0,0.0); + + // additive lights + for(int i=lightRange.z; i= 0) + { + ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); + if (lightRange.z > lightRange.x) + { + // + // modulated lights + // + for(int i=lightRange.x; i 0.0) + { + attenuation *= shadowAttenuation(lightpos, lightcolor.a); + + vec3 radiance = lightcolor.rgb * attenuation; + + // cook-torrance brdf + float NDF = DistributionGGX(N, H, roughness); + float G = GeometrySmith(N, V, L, roughness); + vec3 F = fresnelSchlick(clamp(dot(H, V), 0.0, 1.0), F0); + + vec3 kS = F; + vec3 kD = (vec3(1.0) - kS) * (1.0 - metallic); + + vec3 nominator = NDF * G * F; + float denominator = 4.0 * clamp(dot(N, V), 0.0, 1.0) * clamp(dot(N, L), 0.0, 1.0); + vec3 specular = nominator / max(denominator, 0.001); + + Lo += (kD * albedo / PI + specular) * radiance; + } + } + // + // subtractive lights + // + for(int i=lightRange.y; i 0.0) + { + attenuation *= shadowAttenuation(lightpos, lightcolor.a); + + vec3 radiance = lightcolor.rgb * attenuation; + + // cook-torrance brdf + float NDF = DistributionGGX(N, H, roughness); + float G = GeometrySmith(N, V, L, roughness); + vec3 F = fresnelSchlick(clamp(dot(H, V), 0.0, 1.0), F0); + + vec3 kS = F; + vec3 kD = (vec3(1.0) - kS) * (1.0 - metallic); + + vec3 nominator = NDF * G * F; + float denominator = 4.0 * clamp(dot(N, V), 0.0, 1.0) * clamp(dot(N, L), 0.0, 1.0); + vec3 specular = nominator / max(denominator, 0.001); + + Lo -= (kD * albedo / PI + specular) * radiance; + } + } + } + } + + // Pretend we sampled the sector light level from an irradiance map + + vec3 F = fresnelSchlickRoughness(clamp(dot(N, V), 0.0, 1.0), F0, roughness); + + vec3 kS = F; + vec3 kD = 1.0 - kS; + + vec3 irradiance = ambientLight; // texture(irradianceMap, N).rgb + vec3 diffuse = irradiance * albedo; + + //kD *= 1.0 - metallic; + //const float MAX_REFLECTION_LOD = 4.0; + //vec3 prefilteredColor = textureLod(prefilterMap, R, roughness * MAX_REFLECTION_LOD).rgb; + //vec2 envBRDF = texture(brdfLUT, vec2(clamp(dot(N, V), 0.0, 1.0), roughness)).rg; + //vec3 specular = prefilteredColor * (F * envBRDF.x + envBRDF.y); + + //vec3 ambient = (kD * diffuse + specular) * ao; + vec3 ambient = (kD * diffuse) * ao; + + vec3 color = ambient + Lo; + + // Tonemap (reinhard) and apply sRGB gamma + //color = color / (color + vec3(1.0)); + return pow(color, vec3(1.0 / 2.2)); +} diff --git a/wadsrc/static/shaders/glsl/material_specular.fp b/wadsrc/static/shaders/glsl/material_specular.fp new file mode 100644 index 000000000..ab61d6cf9 --- /dev/null +++ b/wadsrc/static/shaders/glsl/material_specular.fp @@ -0,0 +1,97 @@ + +vec2 lightAttenuation(int i, vec3 normal, vec3 viewdir, float lightcolorA) +{ + vec4 lightpos = lights[i]; + vec4 lightspot1 = lights[i+2]; + vec4 lightspot2 = lights[i+3]; + + float lightdistance = distance(lightpos.xyz, pixelpos.xyz); + if (lightpos.w < lightdistance) + return vec2(0.0); // Early out lights touching surface but not this fragment + + float attenuation = clamp((lightpos.w - lightdistance) / lightpos.w, 0.0, 1.0); + + if (lightspot1.w == 1.0) + attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); + + vec3 lightdir = normalize(lightpos.xyz - pixelpos.xyz); + + if (lightcolorA < 0.0) // Sign bit is the attenuated light flag + attenuation *= clamp(dot(normal, lightdir), 0.0, 1.0); + + if (attenuation > 0.0) // Skip shadow map test if possible + attenuation *= shadowAttenuation(lightpos, lightcolorA); + + if (attenuation <= 0.0) + return vec2(0.0); + + float glossiness = uSpecularMaterial.x; + float specularLevel = uSpecularMaterial.y; + + vec3 halfdir = normalize(viewdir + lightdir); + float specAngle = clamp(dot(halfdir, normal), 0.0f, 1.0f); + float phExp = glossiness * 4.0f; + return vec2(attenuation, attenuation * specularLevel * pow(specAngle, phExp)); +} + +vec3 ProcessMaterial(vec3 material, vec3 color) +{ + if (uLightIndex >= 0) + { + vec4 dynlight = uDynLightColor; + vec4 specular = vec4(0.0, 0.0, 0.0, 1.0); + + vec3 normal = ApplyNormalMap(); + vec3 viewdir = normalize(uCameraPos.xyz - pixelpos.xyz); + + ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); + + if (lightRange.z > lightRange.x) + { + // modulated lights + for(int i=lightRange.x; i lightRange.z) + { + vec4 addlight = vec4(0.0,0.0,0.0,0.0); + + // additive lights + for(int i=lightRange.z; i