From 0e22dbfd47bbbfcbee3b0a04031a6e43222e80b1 Mon Sep 17 00:00:00 2001 From: Vsevolod Kremianskii Date: Sat, 8 May 2021 00:05:34 +0700 Subject: [PATCH] Refactor Blinn-Phong shaders --- src/engine/graphics/shader/shaders.cpp | 9 +- src/engine/graphics/shader/shaders.h | 4 +- src/engine/graphics/shader/shaders_common.cpp | 93 ++++++---- src/engine/graphics/shader/shaders_pbr.cpp | 24 +-- src/engine/graphics/shader/shaders_phong.cpp | 162 +++++++++--------- src/engine/scene/node/modelnodescenenode.cpp | 2 +- 6 files changed, 146 insertions(+), 148 deletions(-) diff --git a/src/engine/graphics/shader/shaders.cpp b/src/engine/graphics/shader/shaders.cpp index 871437a7..30996316 100644 --- a/src/engine/graphics/shader/shaders.cpp +++ b/src/engine/graphics/shader/shaders.cpp @@ -38,6 +38,7 @@ namespace graphics { extern char g_shaderBaseHeader[]; extern char g_shaderBaseModel[]; +extern char g_shaderBaseBlinnPhong[]; extern char g_shaderBasePBR[]; extern char g_shaderBasePBRIBL[]; extern char g_shaderVertexSimple[]; @@ -56,7 +57,7 @@ extern char g_shaderFragmentGrass[]; extern char g_shaderFragmentBlur[]; extern char g_shaderFragmentPresentWorld[]; extern char g_shaderFragmentBlinnPhong[]; -extern char g_shaderFragmentBlinnPhongTextureless[]; +extern char g_shaderFragmentBlinnPhongDiffuseless[]; extern char g_shaderFragmentIrradiance[]; extern char g_shaderFragmentPrefilter[]; extern char g_shaderFragmentBRDF[]; @@ -93,8 +94,8 @@ void Shaders::init() { initShader(ShaderName::FragmentGrass, GL_FRAGMENT_SHADER, { g_shaderBaseHeader, g_shaderFragmentGrass }); initShader(ShaderName::FragmentBlur, GL_FRAGMENT_SHADER, { g_shaderBaseHeader, g_shaderFragmentBlur }); initShader(ShaderName::FragmentPresentWorld, GL_FRAGMENT_SHADER, { g_shaderBaseHeader, g_shaderFragmentPresentWorld }); - initShader(ShaderName::FragmentBlinnPhong, GL_FRAGMENT_SHADER, { g_shaderBaseHeader, g_shaderBaseModel, g_shaderFragmentBlinnPhong }); - initShader(ShaderName::FragmentBlinnPhongTextureless, GL_FRAGMENT_SHADER, { g_shaderBaseHeader, g_shaderBaseModel, g_shaderFragmentBlinnPhongTextureless }); + 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 }); @@ -110,7 +111,7 @@ void Shaders::init() { initProgram(ShaderProgram::SimplePresentWorld, { ShaderName::VertexSimple, ShaderName::FragmentPresentWorld }); initProgram(ShaderProgram::ModelColor, { ShaderName::VertexModel, ShaderName::FragmentColor }); initProgram(ShaderProgram::ModelBlinnPhong, { ShaderName::VertexModel, ShaderName::FragmentBlinnPhong }); - initProgram(ShaderProgram::ModelBlinnPhongTextureless, { ShaderName::VertexModel, ShaderName::FragmentBlinnPhongTextureless }); + initProgram(ShaderProgram::ModelBlinnPhongDiffuseless, { ShaderName::VertexModel, ShaderName::FragmentBlinnPhongDiffuseless }); initProgram(ShaderProgram::ModelPBR, { ShaderName::VertexModel, ShaderName::FragmentPBR }); initProgram(ShaderProgram::ParticleParticle, { ShaderName::VertexParticle, ShaderName::FragmentParticle }); initProgram(ShaderProgram::GrassGrass, { ShaderName::VertexGrass, ShaderName::FragmentGrass }); diff --git a/src/engine/graphics/shader/shaders.h b/src/engine/graphics/shader/shaders.h index 9d2973b0..38cb3d9e 100644 --- a/src/engine/graphics/shader/shaders.h +++ b/src/engine/graphics/shader/shaders.h @@ -46,7 +46,7 @@ enum class ShaderProgram { SimplePresentWorld, ModelColor, ModelBlinnPhong, - ModelBlinnPhongTextureless, + ModelBlinnPhongDiffuseless, ModelPBR, ParticleParticle, GrassGrass, @@ -244,7 +244,7 @@ private: // Blinn-Phong FragmentBlinnPhong, - FragmentBlinnPhongTextureless, + FragmentBlinnPhongDiffuseless, // PBR FragmentIrradiance, diff --git a/src/engine/graphics/shader/shaders_common.cpp b/src/engine/graphics/shader/shaders_common.cpp index 3d2e31a5..e07d46cf 100644 --- a/src/engine/graphics/shader/shaders_common.cpp +++ b/src/engine/graphics/shader/shaders_common.cpp @@ -202,6 +202,10 @@ in mat3 fragTanSpace; layout(location = 0) out vec4 fragColor; layout(location = 1) out vec4 fragColorBright; +vec2 getUV() { + return fragTexCoords + uGeneral.uvOffset; +} + vec2 packUV(vec2 uv, vec4 bounds) { return bounds.xy + bounds.zw * clamp(fract(uv), 0.001, 0.999); } @@ -240,62 +244,74 @@ vec3 getNormalFromBumpmap(vec2 uv) { } result = normalize(fragTanSpace * result); + return result; +} + +vec3 getNormal(vec2 uv) { + vec3 result; + + if (isFeatureEnabled(FEATURE_BUMPMAPS)) { + result = getNormalFromBumpmap(uv); + } else { + result = normalize(fragNormal); + } return result; } float getShadow() { - float shadow = 0.0; + if (!isFeatureEnabled(FEATURE_SHADOWS) || !uShadows.lightPresent) return 0.0; - if (uShadows.lightPresent) { - if (uShadows.lightPosition.w == 0.0) { - // Directional light + float result = 0.0; - vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w; - projCoords = projCoords * 0.5 + 0.5; - float closestDepth = texture(uShadowMap, projCoords.xy).r; - float currentDepth = projCoords.z; + if (uShadows.lightPosition.w == 0.0) { + // Directional light - vec2 texelSize = 1.0 / textureSize(uShadowMap, 0); - for (int x = -1; x <= 1; ++x) { - for (int y = -1; y <= 1; ++y) { - float pcfDepth = texture(uShadowMap, projCoords.xy + vec2(x, y) * texelSize).r; - shadow += currentDepth > pcfDepth ? 1.0 : 0.0; - } + vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w; + projCoords = projCoords * 0.5 + 0.5; + float closestDepth = texture(uShadowMap, projCoords.xy).r; + float currentDepth = projCoords.z; + + vec2 texelSize = 1.0 / textureSize(uShadowMap, 0); + for (int x = -1; x <= 1; ++x) { + for (int y = -1; y <= 1; ++y) { + float pcfDepth = texture(uShadowMap, projCoords.xy + vec2(x, y) * texelSize).r; + result += currentDepth > pcfDepth ? 1.0 : 0.0; } - shadow /= 9.0; + } + result /= 9.0; - if (projCoords.z > 1.0) { - shadow = 0.0; - } - } else { - // Point light + if (projCoords.z > 1.0) { + result = 0.0; + } + } else { + // Point light - vec3 fragToLight = fragPosition - uShadows.lightPosition.xyz; - float currentDepth = length(fragToLight); + vec3 fragToLight = fragPosition - uShadows.lightPosition.xyz; + float currentDepth = length(fragToLight); - float bias = 0.1; - float samples = 4.0; - float offset = 0.1; + float bias = 0.1; + float samples = 4.0; + float offset = 0.1; - for (float x = -offset; x < offset; x += offset / (samples * 0.5)) { - for (float y = -offset; y < offset; y += offset / (samples * 0.5)) { - for (float z = -offset; z < offset; z += offset / (samples * 0.5)) { - float closestDepth = texture(uCubeShadowMap, fragToLight + vec3(x, y, z)).r; - closestDepth *= SHADOW_FAR_PLANE; + for (float x = -offset; x < offset; x += offset / (samples * 0.5)) { + for (float y = -offset; y < offset; y += offset / (samples * 0.5)) { + for (float z = -offset; z < offset; z += offset / (samples * 0.5)) { + float closestDepth = texture(uCubeShadowMap, fragToLight + vec3(x, y, z)).r; + closestDepth *= SHADOW_FAR_PLANE; - if (currentDepth - bias > closestDepth) { - shadow += 1.0; - } + if (currentDepth - bias > closestDepth) { + result += 1.0; } } } - - shadow /= samples * samples * samples; } + + result /= samples * samples * samples; } - return uShadows.strength * shadow; + result *= uShadows.strength; + return result; } float getLightAttenuation(int light) { @@ -308,9 +324,10 @@ float getLightAttenuation(int light) { return D / (D + r); } -vec3 applyFog(vec3 rgb, float distance) { +vec3 applyFog(vec3 objectColor) { + float distance = length(uGeneral.cameraPosition.xyz - fragPosition); float fogAmount = clamp(distance - uGeneral.fogNear, 0.0, uGeneral.fogFar - uGeneral.fogNear) / (uGeneral.fogFar - uGeneral.fogNear); - return mix(rgb, uGeneral.fogColor.rgb, fogAmount); + return mix(objectColor, uGeneral.fogColor.rgb, fogAmount); } )END"; diff --git a/src/engine/graphics/shader/shaders_pbr.cpp b/src/engine/graphics/shader/shaders_pbr.cpp index 4d93dffb..152c8a37 100644 --- a/src/engine/graphics/shader/shaders_pbr.cpp +++ b/src/engine/graphics/shader/shaders_pbr.cpp @@ -229,7 +229,7 @@ uniform sampler2D uBRDFLookup; uniform samplerCube uIrradianceMap; uniform samplerCube uPrefilterMap; -void determineMetallicRoughness(vec4 diffuseSample, out float metallic, out float roughness) { +void getMetallicRoughness(vec4 diffuseSample, out float metallic, out float roughness) { if (isFeatureEnabled(FEATURE_CUSTOMMAT) || !isFeatureEnabled(FEATURE_ENVMAP)) { metallic = uMaterial.metallic; roughness = uMaterial.roughness; @@ -240,31 +240,19 @@ void determineMetallicRoughness(vec4 diffuseSample, out float metallic, out floa } void main() { - vec2 texCoords = fragTexCoords + uGeneral.uvOffset; - - vec4 diffuseSample; - if (isFeatureEnabled(FEATURE_DIFFUSE)) { - diffuseSample = texture(uDiffuse, texCoords); - } else { - diffuseSample = vec4(vec3(0.5), 1.0); - } - - vec3 N; - if (isFeatureEnabled(FEATURE_BUMPMAPS)) { - N = getNormalFromBumpmap(texCoords); - } else { - N = normalize(fragNormal); - } + vec2 uv = getUV(); + vec4 diffuseSample = texture(uDiffuse, uv); vec3 cameraToFragment = uGeneral.cameraPosition.xyz - fragPosition; vec3 V = normalize(cameraToFragment); + vec3 N = getNormal(uv); vec3 R = reflect(-V, N); vec3 albedo = isFeatureEnabled(FEATURE_HDR) ? pow(diffuseSample.rgb, vec3(GAMMA)) : diffuseSample.rgb; float ao = 1.0; float metallic, roughness; - determineMetallicRoughness(diffuseSample, metallic, roughness); + getMetallicRoughness(diffuseSample, metallic, roughness); vec3 objectColor; @@ -360,7 +348,7 @@ void main() { objectColor = pow(objectColor, vec3(1.0 / GAMMA)); } if (isFeatureEnabled(FEATURE_FOG)) { - objectColor = applyFog(objectColor, length(cameraToFragment)); + objectColor = applyFog(objectColor); } vec3 brightColor = vec3(0.0); diff --git a/src/engine/graphics/shader/shaders_phong.cpp b/src/engine/graphics/shader/shaders_phong.cpp index 9408e1e2..4a3b0cf8 100644 --- a/src/engine/graphics/shader/shaders_phong.cpp +++ b/src/engine/graphics/shader/shaders_phong.cpp @@ -25,118 +25,110 @@ namespace reone { namespace graphics { +char g_shaderBaseBlinnPhong[] = R"END( +vec3 getLightingIndirect(vec3 N) { + return uGeneral.ambientColor.rgb * uMaterial.ambient.rgb; +} + +vec3 getLightingDirect(vec3 N) { + vec3 result = vec3(0.0); + vec3 V = normalize(uGeneral.cameraPosition.xyz - fragPosition); + + for (int i = 0; i < uLightCount; ++i) { + vec3 L = normalize(uLights[i].position.xyz - fragPosition); + vec3 H = normalize(V + L); + + vec3 diff = uMaterial.diffuse.rgb * max(dot(L, N), 0.0); + vec3 diffuse = uLights[i].multiplier * uLights[i].color.rgb * diff; + + float spec = uMaterial.specular * pow(max(dot(N, H), 0.0), uMaterial.shininess); + vec3 specular = uLights[i].multiplier * uLights[i].color.rgb * spec; + + float attenuation = getLightAttenuation(i); + diffuse *= attenuation; + specular *= attenuation; + + result += diffuse + specular; + } + + return result; +} +)END"; + char g_shaderFragmentBlinnPhong[] = R"END( void main() { - vec2 texCoords = fragTexCoords + uGeneral.uvOffset; - vec4 diffuseSample = texture(uDiffuse, texCoords); - vec3 cameraToFragment = uGeneral.cameraPosition.xyz - fragPosition; - vec3 V = normalize(cameraToFragment); - - vec3 N; - if (isFeatureEnabled(FEATURE_BUMPMAPS)) { - N = getNormalFromBumpmap(texCoords); - } else { - N = normalize(fragNormal); - } - - vec3 objectColor; - - if (isFeatureEnabled(FEATURE_LIGHTING)) { - objectColor = uGeneral.ambientColor.rgb * uMaterial.ambient.rgb * diffuseSample.rgb; - - for (int i = 0; i < uLightCount; ++i) { - vec3 L = normalize(uLights[i].position.xyz - fragPosition); - vec3 H = normalize(V + L); - - float diff = max(dot(L, N), 0.0); - vec3 diffuse = uLights[i].multiplier * uLights[i].color.rgb * diff * uMaterial.diffuse.rgb * diffuseSample.rgb; - - float spec = pow(max(dot(N, H), 0.0), uMaterial.shininess); - vec3 specular = uLights[i].multiplier * uLights[i].color.rgb * spec * vec3(uMaterial.specular); - - float attenuation = getLightAttenuation(i); - diffuse *= attenuation; - specular *= attenuation; - - objectColor += diffuse + specular; - } - - objectColor = min(objectColor, diffuseSample.rgb); - - } else { - objectColor = diffuseSample.rgb; - } + vec2 uv = getUV(); + vec3 N = getNormal(uv); + float shadow = getShadow(); + vec4 diffuseSample = texture(uDiffuse, uv); + bool opaque = isFeatureEnabled(FEATURE_ENVMAP) || isFeatureEnabled(FEATURE_BUMPMAPS); + vec3 lighting; if (isFeatureEnabled(FEATURE_LIGHTMAP)) { vec4 lightmapSample = texture(uLightmap, fragLightmapCoords); - objectColor = mix(objectColor, objectColor * lightmapSample.rgb, isFeatureEnabled(FEATURE_WATER) ? 0.2 : 1.0); + lighting = (1.0 - 0.5 * shadow) * lightmapSample.rgb; + if (isFeatureEnabled(FEATURE_WATER)) { + lighting *= 0.2; + } + } else if (isFeatureEnabled(FEATURE_LIGHTING)) { + vec3 indirect = getLightingIndirect(N); + vec3 direct = getLightingDirect(N); + lighting = min(vec3(1.0), indirect + (1.0 - shadow) * direct); + } else { + lighting = vec3(1.0); } + + vec3 objectColor = lighting * uGeneral.color.rgb * diffuseSample.rgb; + float objectAlpha = (opaque ? 1.0 : diffuseSample.a) * uGeneral.alpha; + if (isFeatureEnabled(FEATURE_ENVMAP)) { + vec3 V = normalize(uGeneral.cameraPosition.xyz - fragPosition); vec3 R = reflect(-V, N); vec4 envmapSample = texture(uEnvmap, R); 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; - } - if (isFeatureEnabled(FEATURE_FOG)) { - objectColor = applyFog(objectColor, length(cameraToFragment)); - } - - 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_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"; -char g_shaderFragmentBlinnPhongTextureless[] = R"END( +char g_shaderFragmentBlinnPhongDiffuseless[] = R"END( void main() { - vec3 indirect = uGeneral.ambientColor.rgb * uMaterial.ambient.rgb; - vec3 direct = vec3(0.0); + vec3 N = normalize(fragNormal); + float shadow = getShadow(); - if (isFeatureEnabled(FEATURE_LIGHTING)) { - vec3 V = normalize(uGeneral.cameraPosition.xyz - fragPosition); - vec3 N = normalize(fragNormal); - - for (int i = 0; i < uLightCount; ++i) { - vec3 L = normalize(uLights[i].position.xyz - fragPosition); - vec3 H = normalize(V + L); - - vec3 diff = uMaterial.diffuse.rgb * max(dot(L, N), 0.0); - vec3 diffuse = uLights[i].multiplier * uLights[i].color.rgb * diff; - - float spec = uMaterial.specular * pow(max(dot(N, H), 0.0), uMaterial.shininess); - vec3 specular = uLights[i].multiplier * uLights[i].color.rgb * spec; - - float attenuation = getLightAttenuation(i); - diffuse *= attenuation; - specular *= attenuation; - - direct += diffuse + specular; - } - } else if (isFeatureEnabled(FEATURE_LIGHTMAP)) { - indirect *= texture(uLightmap, fragLightmapCoords).rgb; + vec3 lighting; + if (isFeatureEnabled(FEATURE_LIGHTMAP)) { + vec4 lightmapSample = texture(uLightmap, fragLightmapCoords); + lighting = (1.0 - 0.5 * shadow) * lightmapSample.rgb; + } else if (isFeatureEnabled(FEATURE_LIGHTING)) { + vec3 indirect = getLightingIndirect(N); + vec3 direct = getLightingDirect(N); + lighting = min(vec3(1.0), indirect + (1.0 - shadow) * direct); + } else { + lighting = vec3(1.0); } - vec3 objectColor = indirect + direct; + vec3 objectColor = lighting * uGeneral.color.rgb; + float objectAlpha = uGeneral.alpha; - fragColor = vec4(objectColor, uGeneral.alpha); - fragColorBright = vec4(0.0); + fragColor = vec4(objectColor, objectAlpha); + fragColorBright = vec4(vec3(0.0), objectAlpha); } )END"; diff --git a/src/engine/scene/node/modelnodescenenode.cpp b/src/engine/scene/node/modelnodescenenode.cpp index 076fbce4..7723d3ae 100644 --- a/src/engine/scene/node/modelnodescenenode.cpp +++ b/src/engine/scene/node/modelnodescenenode.cpp @@ -242,7 +242,7 @@ void ModelNodeSceneNode::drawSingle(bool shadowPass) { } else { program = !_textures.diffuse ? - ShaderProgram::ModelBlinnPhongTextureless : + ShaderProgram::ModelBlinnPhongDiffuseless : (isFeatureEnabled(Feature::PBR) ? ShaderProgram::ModelPBR : ShaderProgram::ModelBlinnPhong); if (_textures.diffuse) {