add material sphere preview, add ssr, improve shadow
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
// -----------------------------
|
||||
// -----------------------------
|
||||
// -- Based on Hazel PBR shader --
|
||||
// -----------------------------
|
||||
// Note: this shader is still very much in progress. There are likely many bugs and future additions that will go in.
|
||||
@ -22,8 +22,6 @@ uniform mat4 u_ViewProjectionMatrix;
|
||||
uniform mat4 u_ViewMatrix;
|
||||
uniform mat4 u_Transform;
|
||||
|
||||
uniform mat4 u_LightSpaceMatrix;
|
||||
|
||||
out VertexOutput
|
||||
{
|
||||
vec3 WorldPosition;
|
||||
@ -33,7 +31,7 @@ out VertexOutput
|
||||
mat3 WorldTransform;
|
||||
vec3 Binormal;
|
||||
vec3 ViewPosition;
|
||||
vec4 FragPosLightSpace;
|
||||
float ViewZ;
|
||||
} vs_Output;
|
||||
|
||||
void main()
|
||||
@ -45,9 +43,8 @@ void main()
|
||||
vs_Output.WorldTransform = mat3(u_Transform);
|
||||
vs_Output.Binormal = a_Binormal;
|
||||
|
||||
vs_Output.FragPosLightSpace = u_LightSpaceMatrix * u_Transform * vec4(a_Position, 1.0);
|
||||
|
||||
vs_Output.ViewPosition = vec3(u_ViewMatrix * vec4(vs_Output.WorldPosition, 1.0));
|
||||
vs_Output.ViewZ = vs_Output.ViewPosition.z;
|
||||
|
||||
gl_Position = u_ViewProjectionMatrix * u_Transform * vec4(a_Position, 1.0);
|
||||
}
|
||||
@ -62,7 +59,8 @@ const int LightCount = 1;
|
||||
const vec3 Fdielectric = vec3(0.04);
|
||||
|
||||
layout(location = 0) out vec4 color;
|
||||
layout(location = 1) out vec4 o_BloomColor;
|
||||
layout(location = 1) out vec4 o_MaterialInfo;
|
||||
layout(location = 2) out vec4 o_BloomColor;
|
||||
|
||||
struct DirectionalLight {
|
||||
vec3 Direction;
|
||||
@ -100,7 +98,7 @@ in VertexOutput
|
||||
mat3 WorldTransform;
|
||||
vec3 Binormal;
|
||||
vec3 ViewPosition;
|
||||
vec4 FragPosLightSpace;
|
||||
float ViewZ;
|
||||
} vs_Input;
|
||||
|
||||
uniform DirectionalLight u_DirectionalLights;
|
||||
@ -143,7 +141,15 @@ uniform float u_MetalnessTexToggle;
|
||||
uniform float u_RoughnessTexToggle;
|
||||
|
||||
// shadow
|
||||
uniform sampler2D u_ShadowMap;
|
||||
const int CSM_CASCADE_COUNT = 4;
|
||||
uniform sampler2D u_ShadowMap[4];
|
||||
uniform mat4 u_LightSpaceMatrix0;
|
||||
uniform mat4 u_LightSpaceMatrix1;
|
||||
uniform mat4 u_LightSpaceMatrix2;
|
||||
uniform mat4 u_LightSpaceMatrix3;
|
||||
uniform vec4 u_CascadeSplits;
|
||||
uniform float u_ShadowFar;
|
||||
uniform float u_ShadowNear;
|
||||
uniform float u_ShadowBias;
|
||||
uniform float u_ShadowSoftness;
|
||||
uniform float u_ShadowIntensity;
|
||||
@ -338,7 +344,7 @@ vec3 IBL(vec3 F0, vec3 Lr)
|
||||
u_EnvRadianceTex,
|
||||
RotateVectorAboutY(u_EnvMapRotation, Lr),
|
||||
m_Params.Roughness * u_EnvRadianceTexLevels
|
||||
).rgb;
|
||||
).rgb;
|
||||
|
||||
vec2 specularBRDF = texture(u_BRDFLUTTexture, vec2(m_Params.NdotV, 1.0 - m_Params.Roughness)).rg;
|
||||
vec3 specularIBL = specularIrradiance * (F * specularBRDF.x + specularBRDF.y);
|
||||
@ -347,23 +353,54 @@ vec3 IBL(vec3 F0, vec3 Lr)
|
||||
}
|
||||
|
||||
// shadow
|
||||
float calculateShadow(vec4 fragPosLightSpace, vec3 normal, vec3 lightDir)
|
||||
int selectCascade(float viewZ)
|
||||
{
|
||||
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
||||
projCoords = projCoords * 0.5 + 0.5;
|
||||
float depth = -viewZ;
|
||||
float linearDepth = (depth - u_ShadowNear) / (u_ShadowFar - u_ShadowNear);
|
||||
if (linearDepth < u_CascadeSplits.x) return 0;
|
||||
if (linearDepth < u_CascadeSplits.y) return 1;
|
||||
if (linearDepth < u_CascadeSplits.z) return 2;
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (projCoords.z > 1.0 || projCoords.x < 0.0 || projCoords.x > 1.0 ||
|
||||
projCoords.y < 0.0 || projCoords.y > 1.0)
|
||||
return 0.0;
|
||||
mat4 getLightSpaceMatrix(int cascade)
|
||||
{
|
||||
if (cascade == 0) return u_LightSpaceMatrix0;
|
||||
else if (cascade == 1) return u_LightSpaceMatrix1;
|
||||
else if (cascade == 2) return u_LightSpaceMatrix2;
|
||||
else return u_LightSpaceMatrix3;
|
||||
}
|
||||
|
||||
float closestDepth = texture(u_ShadowMap, projCoords.xy).r;
|
||||
float currentDepth = projCoords.z;
|
||||
float getCascadeSplit(int cascade)
|
||||
{
|
||||
if (cascade == 0) return u_CascadeSplits.x;
|
||||
else if (cascade == 1) return u_CascadeSplits.y;
|
||||
else if (cascade == 2) return u_CascadeSplits.z;
|
||||
else return u_CascadeSplits.w;
|
||||
}
|
||||
|
||||
float bias = max(u_ShadowBias * (1.0 - dot(normal, lightDir)), u_ShadowBias * 0.1);
|
||||
float sampleShadow(int cascade, vec2 uv, float compareDepth, float bias)
|
||||
{
|
||||
float depth;
|
||||
if (cascade == 0) depth = texture(u_ShadowMap[0], uv).r;
|
||||
else if (cascade == 1) depth = texture(u_ShadowMap[1], uv).r;
|
||||
else if (cascade == 2) depth = texture(u_ShadowMap[2], uv).r;
|
||||
else depth = texture(u_ShadowMap[3], uv).r;
|
||||
return (compareDepth - bias) > depth ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
vec2 getTexelSize(int cascade)
|
||||
{
|
||||
if (cascade == 0) return 1.0 / vec2(textureSize(u_ShadowMap[0], 0));
|
||||
else if (cascade == 1) return 1.0 / vec2(textureSize(u_ShadowMap[1], 0));
|
||||
else if (cascade == 2) return 1.0 / vec2(textureSize(u_ShadowMap[2], 0));
|
||||
else return 1.0 / vec2(textureSize(u_ShadowMap[3], 0));
|
||||
}
|
||||
|
||||
float pcfShadow(int cascade, vec3 projCoords, float bias)
|
||||
{
|
||||
vec2 texelSize = getTexelSize(cascade);
|
||||
int pcfRange = clamp(int(u_ShadowSoftness), 0, 3);
|
||||
|
||||
vec2 texelSize = 1.0 / textureSize(u_ShadowMap, 0);
|
||||
float shadow = 0.0;
|
||||
int samples = 0;
|
||||
|
||||
@ -372,34 +409,57 @@ float calculateShadow(vec4 fragPosLightSpace, vec3 normal, vec3 lightDir)
|
||||
for (int y = -pcfRange; y <= pcfRange; ++y)
|
||||
{
|
||||
vec2 offset = vec2(x, y) * texelSize;
|
||||
float pcfDepth = texture(u_ShadowMap, projCoords.xy + offset).r;
|
||||
shadow += (currentDepth - bias) > pcfDepth ? 1.0 : 0.0;
|
||||
shadow += sampleShadow(cascade, projCoords.xy + offset, projCoords.z, bias);
|
||||
samples++;
|
||||
}
|
||||
}
|
||||
shadow /= float(samples);
|
||||
return shadow * u_ShadowIntensity;
|
||||
return shadow / float(samples);
|
||||
}
|
||||
|
||||
|
||||
float ComputeShadow(vec4 fragPosLightSpace, float NdotL)
|
||||
float calculateCSMShadow(vec3 worldPos, vec3 normal, vec3 lightDir, float viewZ)
|
||||
{
|
||||
if (u_ShadowEnabled == 0) return 1.0;
|
||||
int cascade = selectCascade(viewZ);
|
||||
|
||||
vec4 fragPosLightSpace = getLightSpaceMatrix(cascade) * vec4(worldPos, 1.0);
|
||||
|
||||
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
||||
projCoords = projCoords * 0.5 + 0.5;
|
||||
|
||||
if (projCoords.x < 0.0 || projCoords.x > 1.0 ||
|
||||
projCoords.y < 0.0 || projCoords.y > 1.0 ||
|
||||
projCoords.z > 1.0) return 1.0;
|
||||
if (projCoords.z > 1.0 || projCoords.x < 0.0 || projCoords.x > 1.0 ||
|
||||
projCoords.y < 0.0 || projCoords.y > 1.0)
|
||||
return 0.0;
|
||||
|
||||
float closestDepth = texture(u_ShadowMap, projCoords.xy).r;
|
||||
float currentDepth = projCoords.z;
|
||||
float bias = max(u_ShadowBias * (1.0 - dot(normal, lightDir)), u_ShadowBias * 0.1);
|
||||
float shadow = pcfShadow(cascade, projCoords, bias);
|
||||
|
||||
float bias = max(u_ShadowBias * (1.0 - NdotL), u_ShadowBias * 0.5);
|
||||
float cascadeEdge = 0.0;
|
||||
if (cascade < CSM_CASCADE_COUNT - 1)
|
||||
{
|
||||
float depth = -viewZ;
|
||||
float linearDepth = (depth - u_ShadowNear) / (u_ShadowFar - u_ShadowNear);
|
||||
float splitDist = getCascadeSplit(cascade);
|
||||
float prevSplit = (cascade > 0) ? getCascadeSplit(cascade - 1) : 0.0;
|
||||
float blendStart = splitDist - (splitDist - prevSplit) * 0.1;
|
||||
if (linearDepth > blendStart)
|
||||
{
|
||||
cascadeEdge = (linearDepth - blendStart) / (splitDist - blendStart);
|
||||
|
||||
float shadow = (currentDepth - bias) > closestDepth ? 1.0 : 0.0;
|
||||
return mix(1.0, 1.0 - u_ShadowIntensity, shadow);
|
||||
int nextCascade = cascade + 1;
|
||||
vec4 fragPosNext = getLightSpaceMatrix(nextCascade) * vec4(worldPos, 1.0);
|
||||
|
||||
vec3 projCoordsNext = fragPosNext.xyz / fragPosNext.w;
|
||||
projCoordsNext = projCoordsNext * 0.5 + 0.5;
|
||||
|
||||
if (!(projCoordsNext.z > 1.0 || projCoordsNext.x < 0.0 || projCoordsNext.x > 1.0 ||
|
||||
projCoordsNext.y < 0.0 || projCoordsNext.y > 1.0))
|
||||
{
|
||||
float nextShadow = pcfShadow(nextCascade, projCoordsNext, bias);
|
||||
shadow = mix(shadow, nextShadow, cascadeEdge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return shadow * u_ShadowIntensity;
|
||||
}
|
||||
|
||||
|
||||
@ -428,7 +488,7 @@ void main()
|
||||
// Shadow
|
||||
float shadowFactor = 1.0;
|
||||
if (u_ShadowEnabled > 0.5) {
|
||||
float shadow = calculateShadow(vs_Input.FragPosLightSpace, m_Params.Normal, u_DirectionalLights.Direction);
|
||||
float shadow = calculateCSMShadow(vs_Input.WorldPosition, m_Params.Normal, u_DirectionalLights.Direction, vs_Input.ViewZ);
|
||||
shadowFactor = 1.0 - shadow;
|
||||
}
|
||||
|
||||
@ -459,4 +519,6 @@ void main()
|
||||
// Bloom
|
||||
float brightness = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
|
||||
o_BloomColor = brightness > u_BloomThreshold ? color : vec4(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
o_MaterialInfo = vec4(m_Params.Metalness, m_Params.Roughness, 0.0, 1.0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user