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 b868f86c3..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); //=========================================================================== // @@ -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(NORMALMAP) mat3 cotangent_frame(vec3 n, vec3 p, vec2 uv) { // get edge vectors of the pixel triangle @@ -312,251 +299,6 @@ vec3 ApplyNormalMap() } #endif -//=========================================================================== -// -// Calculates the brightness of a dynamic point light -// -//=========================================================================== - -vec2 pointLightAttenuation(vec4 lightpos, float lightcolorA) -{ - 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 vec2(attenuation, 0.0); - } - else - { - vec3 lightDirection = normalize(lightpos.xyz - pixelpos.xyz); - vec3 pixelnormal = ApplyNormalMap(); - float diffuseAmount = diffuseContribution(lightDirection, pixelnormal); - -#if defined(SPECULAR) - float specularAmount = blinnSpecularContribution(diffuseAmount, lightDirection, pixelnormal, uSpecularMaterial.x, uSpecularMaterial.y); - return vec2(diffuseAmount, specularAmount) * attenuation; -#else - return vec2(attenuation * diffuseAmount, 0.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); -} - -#if defined(PBR) - -const float PI = 3.14159265359; - -float DistributionGGX(vec3 N, vec3 H, float roughness) -{ - float a = roughness * roughness; - float a2 = a * a; - float NdotH = max(dot(N, H), 0.0); - float NdotH2 = NdotH*NdotH; - - float nom = a2; - float denom = (NdotH2 * (a2 - 1.0) + 1.0); - denom = PI * denom * denom; - - return nom / denom; -} - -float GeometrySchlickGGX(float NdotV, float roughness) -{ - float r = (roughness + 1.0); - float k = (r * r) / 8.0; - - float nom = NdotV; - float denom = NdotV * (1.0 - k) + k; - - return nom / denom; -} - -float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) -{ - float NdotV = max(dot(N, V), 0.0); - float NdotL = max(dot(N, L), 0.0); - float ggx2 = GeometrySchlickGGX(NdotV, roughness); - float ggx1 = GeometrySchlickGGX(NdotL, roughness); - return ggx1 * ggx2; -} - -vec3 fresnelSchlick(float cosTheta, vec3 F0) -{ - return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); -} - -vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness) -{ - return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0); -} - -float quadraticDistanceAttenuation(vec4 lightpos) -{ - float strength = (1.0 + lightpos.w * lightpos.w * 0.25) * 0.5; - - vec3 distVec = lightpos.xyz - pixelpos.xyz; - float attenuation = strength / (1.0 + dot(distVec, distVec)); - if (attenuation <= 1.0 / 256.0) return 0.0; - - return attenuation; -} - -float shadowAttenuation(vec4 lightpos, float lightcolorA) -{ -#ifdef SUPPORTS_SHADOWMAPS - float shadowIndex = abs(lightcolorA) - 1.0; - return shadowmapAttenuation(lightpos, shadowIndex); -#else - return 1.0; -#endif -} - -vec3 applyLight(vec3 albedo, vec3 ambientLight) -{ - vec3 worldpos = pixelpos.xyz; - - albedo = pow(albedo, vec3(2.2)); // sRGB to linear - ambientLight = pow(ambientLight, vec3(2.2)); - - float metallic = texture(metallictexture, vTexCoord.st).r; - float roughness = texture(roughnesstexture, vTexCoord.st).r; - float ao = texture(aotexture, vTexCoord.st).r; - - vec3 N = ApplyNormalMap(); - vec3 V = normalize(uCameraPos.xyz - worldpos); - - vec3 F0 = mix(vec3(0.04), albedo, metallic); - - vec3 Lo = uDynLightColor.rgb; - -#if defined NUM_UBO_LIGHTS || defined SHADER_STORAGE_LIGHTS - if (uLightIndex >= 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; - } - } - } - } -#endif - - // 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)); -} - -#endif - //=========================================================================== // // Calculate light @@ -571,7 +313,7 @@ vec3 applyLight(vec3 albedo, vec3 ambientLight) // //=========================================================================== -vec4 getLightColor(vec4 material, vec4 materialSpec, float fogdist, float fogfactor) +vec4 getLightColor(vec4 material, float fogdist, float fogfactor) { vec4 color = vColor; @@ -612,63 +354,10 @@ vec4 getLightColor(vec4 material, vec4 materialSpec, float fogdist, float fogfac // color = ProcessLight(color); -#if defined(PBR) - return vec4(applyLight(material.rgb, color.rgb), color.a * vColor.a); -#else // - // apply dynamic lights (except additive) + // apply dynamic lights // - - vec4 dynlight = uDynLightColor; - vec4 specular = vec4(0.0, 0.0, 0.0, 1.0); - -#if defined NUM_UBO_LIGHTS || defined SHADER_STORAGE_LIGHTS - if (uLightIndex >= 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 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