From 15b04249840a069486134760249e4a6b705dead5 Mon Sep 17 00:00:00 2001 From: Vsevolod Kremianskii Date: Sat, 8 May 2021 01:39:50 +0700 Subject: [PATCH] Refactor PBR shaders --- src/engine/graphics/shader/shaders.cpp | 7 +- src/engine/graphics/shader/shaders_pbr.cpp | 127 ++++++++++--------- src/engine/scene/node/modelnodescenenode.cpp | 10 +- 3 files changed, 74 insertions(+), 70 deletions(-) diff --git a/src/engine/graphics/shader/shaders.cpp b/src/engine/graphics/shader/shaders.cpp index 30996316..24cb8a78 100644 --- a/src/engine/graphics/shader/shaders.cpp +++ b/src/engine/graphics/shader/shaders.cpp @@ -40,7 +40,6 @@ extern char g_shaderBaseHeader[]; extern char g_shaderBaseModel[]; extern char g_shaderBaseBlinnPhong[]; extern char g_shaderBasePBR[]; -extern char g_shaderBasePBRIBL[]; extern char g_shaderVertexSimple[]; extern char g_shaderVertexModel[]; extern char g_shaderVertexParticle[]; @@ -97,9 +96,9 @@ void Shaders::init() { initShader(ShaderName::FragmentBlinnPhong, GL_FRAGMENT_SHADER, { g_shaderBaseHeader, g_shaderBaseModel, g_shaderBaseBlinnPhong, g_shaderFragmentBlinnPhong }); initShader(ShaderName::FragmentBlinnPhongDiffuseless, GL_FRAGMENT_SHADER, { g_shaderBaseHeader, g_shaderBaseModel, g_shaderBaseBlinnPhong, g_shaderFragmentBlinnPhongDiffuseless }); initShader(ShaderName::FragmentIrradiance, GL_FRAGMENT_SHADER, { g_shaderBaseHeader, g_shaderFragmentIrradiance }); - initShader(ShaderName::FragmentPrefilter, GL_FRAGMENT_SHADER, { g_shaderBaseHeader, g_shaderBasePBR, g_shaderBasePBRIBL, g_shaderFragmentPrefilter }); - initShader(ShaderName::FragmentBRDF, GL_FRAGMENT_SHADER, { g_shaderBaseHeader, g_shaderBasePBR, g_shaderBasePBRIBL, g_shaderFragmentBRDF }); - initShader(ShaderName::FragmentPBR, GL_FRAGMENT_SHADER, { g_shaderBaseHeader, g_shaderBasePBR, g_shaderBasePBRIBL, g_shaderBaseModel, g_shaderFragmentPBR }); + initShader(ShaderName::FragmentPrefilter, GL_FRAGMENT_SHADER, { g_shaderBaseHeader, g_shaderBasePBR, g_shaderFragmentPrefilter }); + initShader(ShaderName::FragmentBRDF, GL_FRAGMENT_SHADER, { g_shaderBaseHeader, g_shaderBasePBR, g_shaderFragmentBRDF }); + initShader(ShaderName::FragmentPBR, GL_FRAGMENT_SHADER, { g_shaderBaseHeader, g_shaderBasePBR, g_shaderBaseModel, g_shaderFragmentPBR }); initProgram(ShaderProgram::SimpleColor, { ShaderName::VertexSimple, ShaderName::FragmentColor }); initProgram(ShaderProgram::SimpleDepth, { ShaderName::VertexSimple, ShaderName::GeometryDepth, ShaderName::FragmentDepth }); diff --git a/src/engine/graphics/shader/shaders_pbr.cpp b/src/engine/graphics/shader/shaders_pbr.cpp index 152c8a37..ff6b4f46 100644 --- a/src/engine/graphics/shader/shaders_pbr.cpp +++ b/src/engine/graphics/shader/shaders_pbr.cpp @@ -61,9 +61,7 @@ float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) { vec3 fresnelSchlick(float cosTheta, vec3 F0) { return F0 + (1.0 - F0) * pow(max(1.0 - cosTheta, 0.0), 5.0); } -)END"; -char g_shaderBasePBRIBL[] = R"END( float RadicalInverse_VdC(uint bits) { bits = (bits << 16u) | (bits >> 16u); bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); @@ -241,25 +239,71 @@ void getMetallicRoughness(vec4 diffuseSample, out float metallic, out float roug void main() { vec2 uv = getUV(); - vec4 diffuseSample = texture(uDiffuse, uv); + float shadow = getShadow(); + bool opaque = isFeatureEnabled(FEATURE_ENVMAP) || isFeatureEnabled(FEATURE_BUMPMAPS); - vec3 cameraToFragment = uGeneral.cameraPosition.xyz - fragPosition; - vec3 V = normalize(cameraToFragment); + vec3 V = normalize(uGeneral.cameraPosition.xyz - fragPosition); vec3 N = getNormal(uv); vec3 R = reflect(-V, N); - vec3 albedo = isFeatureEnabled(FEATURE_HDR) ? pow(diffuseSample.rgb, vec3(GAMMA)) : diffuseSample.rgb; + vec4 diffuseSample = texture(uDiffuse, uv); + if (isFeatureEnabled(FEATURE_HDR)) { + diffuseSample.rgb = pow(diffuseSample.rgb, vec3(GAMMA)); + } + vec3 albedo = diffuseSample.rgb; float ao = 1.0; - float metallic, roughness; getMetallicRoughness(diffuseSample, metallic, roughness); vec3 objectColor; + if (isFeatureEnabled(FEATURE_LIGHTMAP)) { + vec4 lightmapSample = texture(uLightmap, fragLightmapCoords); + if (isFeatureEnabled(FEATURE_HDR)) { + lightmapSample.rgb = pow(lightmapSample.rgb, vec3(GAMMA)); + } + objectColor = (1.0 - 0.5 * shadow) * lightmapSample.rgb * albedo * ao; - if (isFeatureEnabled(FEATURE_LIGHTING)) { + if (isFeatureEnabled(FEATURE_ENVMAP)) { + vec3 R = reflect(-V, N); + vec4 envmapSample = texture(uEnvmap, R); + if (isFeatureEnabled(FEATURE_HDR)) { + envmapSample.rgb = pow(envmapSample.rgb, vec3(GAMMA)); + } + objectColor += (1.0 - diffuseSample.a) * envmapSample.rgb; + } + } else if (isFeatureEnabled(FEATURE_LIGHTING)) { vec3 F0 = vec3(0.04); F0 = mix(F0, albedo, metallic); + // Indirect lighting + + vec3 ambient = uGeneral.ambientColor.rgb * albedo * ao; + + if (isFeatureEnabled(FEATURE_PBRIBL)) { + vec3 F = fresnelSchlickRoughness(max(dot(N, V), 0.0), F0, roughness); + + vec3 kS = F; + vec3 kD = 1.0 - kS; + kD *= 1.0 - metallic; + + vec3 irradiance = texture(uIrradianceMap, N).rgb; + vec3 diffuse = irradiance * albedo; + + const float MAX_REFLECTION_LOD = 4.0; + vec3 prefilteredColor = textureLod(uPrefilterMap, R, roughness * MAX_REFLECTION_LOD).rgb; + if (isFeatureEnabled(FEATURE_HDR)) { + prefilteredColor = pow(prefilteredColor, vec3(GAMMA)); + } + vec2 brdf = texture(uBRDFLookup, vec2(max(dot(N, V), 0.0), roughness)).rg; + vec3 specular = (1.0 - diffuseSample.a) * prefilteredColor * (F * brdf.x + brdf.y); + + ambient += (kD * diffuse + specular) * ao; + } + + // END Indirect lighting + + // Direct lighting + vec3 Lo = vec3(0.0); for (int i = 0; i < uLightCount; ++i) { @@ -267,8 +311,7 @@ void main() { vec3 H = normalize(V + L); float attenuation = getLightAttenuation(i); - vec3 radiance = uLights[i].multiplier * uLights[i].color.rgb; - radiance *= attenuation; + vec3 radiance = uLights[i].multiplier * uLights[i].color.rgb * attenuation; float NDF = DistributionGGX(N, H, roughness); float G = GeometrySmith(N, V, L, roughness); @@ -287,78 +330,36 @@ void main() { Lo += (kD * albedo / PI + specular) * radiance * NdotL; } - vec3 ambient = uGeneral.ambientColor.rgb * albedo * ao; - - if (isFeatureEnabled(FEATURE_PBRIBL)) { - vec3 F = fresnelSchlickRoughness(max(dot(N, V), 0.0), F0, roughness); - - vec3 kS = F; - vec3 kD = 1.0 - kS; - kD *= 1.0 - metallic; - - vec3 irradiance = texture(uIrradianceMap, N).rgb; - vec3 diffuse = irradiance * albedo; - - const float MAX_REFLECTION_LOD = 4.0; - vec3 prefilteredColor = textureLod(uPrefilterMap, R, roughness * MAX_REFLECTION_LOD).rgb; - vec2 brdf = texture(uBRDFLookup, vec2(max(dot(N, V), 0.0), roughness)).rg; - vec3 specular = (1.0 - diffuseSample.a) * prefilteredColor * (F * brdf.x + brdf.y); - - ambient += (kD * diffuse + specular) * ao; - } - - objectColor = ambient + Lo; + // END Direct lighting + objectColor = ambient + (1.0 - shadow) * Lo; } else { - objectColor = albedo; + objectColor = albedo * ao; } - if (isFeatureEnabled(FEATURE_LIGHTMAP)) { - vec4 lightmapSample = texture(uLightmap, fragLightmapCoords); - if (isFeatureEnabled(FEATURE_HDR)) { - lightmapSample.rgb = pow(lightmapSample.rgb, vec3(GAMMA)); - } - objectColor = mix(objectColor, objectColor * lightmapSample.rgb, isFeatureEnabled(FEATURE_WATER) ? 0.2 : 1.0); - } - if (!isFeatureEnabled(FEATURE_LIGHTING) && isFeatureEnabled(FEATURE_ENVMAP)) { - vec4 envmapSample = texture(uEnvmap, R); - if (isFeatureEnabled(FEATURE_HDR)) { - envmapSample.rgb = pow(envmapSample.rgb, vec3(GAMMA)); - } - objectColor += (1.0 - diffuseSample.a) * envmapSample.rgb; - } - if (isFeatureEnabled(FEATURE_SHADOWS)) { - vec3 S = vec3(1.0) - max(vec3(0.0), vec3(getShadow()) - uGeneral.ambientColor.rgb); - objectColor *= S; - } + float objectAlpha = (opaque ? 1.0 : diffuseSample.a) * uGeneral.alpha; - float objectAlpha = uGeneral.alpha; - if (!isFeatureEnabled(FEATURE_ENVMAP) && !isFeatureEnabled(FEATURE_BUMPMAPS)) { - objectAlpha *= diffuseSample.a; - } if (isFeatureEnabled(FEATURE_WATER)) { objectColor *= uGeneral.waterAlpha; objectAlpha *= uGeneral.waterAlpha; } - if (isFeatureEnabled(FEATURE_HDR)) { - // HDR tonemapping - objectColor = vec3(1.0) - exp(-objectColor * uGeneral.exposure); - // gamma correct + objectColor = objectColor / (objectColor + vec3(1.0)); objectColor = pow(objectColor, vec3(1.0 / GAMMA)); } if (isFeatureEnabled(FEATURE_FOG)) { objectColor = applyFog(objectColor); } - vec3 brightColor = vec3(0.0); - if (isFeatureEnabled(FEATURE_SELFILLUM) && !isFeatureEnabled(FEATURE_WATER)) { - objectColor *= uGeneral.selfIllumColor.rgb; - brightColor = smoothstep(SELFILLUM_THRESHOLD, 1.0, uGeneral.selfIllumColor.rgb * diffuseSample.rgb * objectAlpha); + vec3 objectColorBright; + if (isFeatureEnabled(FEATURE_SELFILLUM)) { + objectColorBright = smoothstep(SELFILLUM_THRESHOLD, 1.0, uGeneral.selfIllumColor.rgb * diffuseSample.rgb * diffuseSample.a); + } else { + objectColorBright = vec3(0.0); } fragColor = vec4(objectColor, objectAlpha); - fragColorBright = vec4(brightColor, 1.0); + fragColorBright = vec4(objectColorBright, objectAlpha); } )END"; diff --git a/src/engine/scene/node/modelnodescenenode.cpp b/src/engine/scene/node/modelnodescenenode.cpp index 7723d3ae..95f57f26 100644 --- a/src/engine/scene/node/modelnodescenenode.cpp +++ b/src/engine/scene/node/modelnodescenenode.cpp @@ -241,9 +241,13 @@ void ModelNodeSceneNode::drawSingle(bool shadowPass) { program = ShaderProgram::SimpleDepth; } else { - program = !_textures.diffuse ? - ShaderProgram::ModelBlinnPhongDiffuseless : - (isFeatureEnabled(Feature::PBR) ? ShaderProgram::ModelPBR : ShaderProgram::ModelBlinnPhong); + if (!_textures.diffuse) { + program = ShaderProgram::ModelBlinnPhongDiffuseless; + } else if (isFeatureEnabled(Feature::PBR)) { + program = ShaderProgram::ModelPBR; + } else { + program = ShaderProgram::ModelBlinnPhong; + } if (_textures.diffuse) { uniforms.combined.featureMask |= UniformFeatureFlags::diffuse;