add material sphere preview, add ssr, improve shadow
This commit is contained in:
BIN
Editor/assets/editor/model.png
Normal file
BIN
Editor/assets/editor/model.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
BIN
Editor/assets/editor/texture.png
Normal file
BIN
Editor/assets/editor/texture.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
@ -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.
|
||||
@ -28,8 +28,6 @@ uniform mat4 u_ViewProjectionMatrix;
|
||||
uniform mat4 u_ViewMatrix;
|
||||
uniform mat4 u_Transform;
|
||||
|
||||
uniform mat4 u_LightSpaceMatrix;
|
||||
|
||||
out VertexOutput
|
||||
{
|
||||
vec3 WorldPosition;
|
||||
@ -39,7 +37,7 @@ out VertexOutput
|
||||
mat3 WorldTransform;
|
||||
vec3 Binormal;
|
||||
vec3 ViewPosition;
|
||||
vec4 FragPosLightSpace;
|
||||
float ViewZ;
|
||||
} vs_Output;
|
||||
|
||||
void main()
|
||||
@ -58,9 +56,8 @@ void main()
|
||||
vs_Output.WorldTransform = mat3(u_Transform);
|
||||
vs_Output.Binormal = a_Binormal;
|
||||
|
||||
vs_Output.FragPosLightSpace = u_LightSpaceMatrix * u_Transform * localPosition;
|
||||
|
||||
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);
|
||||
gl_Position = u_ViewProjectionMatrix * u_Transform * localPosition;
|
||||
@ -76,7 +73,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;
|
||||
@ -113,7 +111,7 @@ in VertexOutput
|
||||
mat3 WorldTransform;
|
||||
vec3 Binormal;
|
||||
vec3 ViewPosition;
|
||||
vec4 FragPosLightSpace;
|
||||
float ViewZ;
|
||||
} vs_Input;
|
||||
|
||||
|
||||
@ -156,7 +154,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;
|
||||
@ -362,23 +368,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;
|
||||
|
||||
@ -387,34 +424,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;
|
||||
}
|
||||
|
||||
|
||||
@ -442,7 +502,7 @@ void main()
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -471,4 +531,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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
207
Editor/assets/shaders/SSR.glsl
Normal file
207
Editor/assets/shaders/SSR.glsl
Normal file
@ -0,0 +1,207 @@
|
||||
#type vertex
|
||||
#version 430
|
||||
|
||||
layout(location = 0) in vec3 a_Position;
|
||||
layout(location = 1) in vec2 a_TexCoord;
|
||||
|
||||
out vec2 v_TexCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 position = vec4(a_Position.xy, 0.0, 1.0);
|
||||
v_TexCoord = a_TexCoord;
|
||||
gl_Position = position;
|
||||
}
|
||||
|
||||
#type fragment
|
||||
#version 430
|
||||
|
||||
layout(location = 0) out vec4 o_Color;
|
||||
|
||||
in vec2 v_TexCoord;
|
||||
|
||||
uniform sampler2D u_ColorTexture;
|
||||
uniform sampler2D u_DepthTexture;
|
||||
uniform sampler2D u_MaterialInfoTexture;
|
||||
|
||||
uniform mat4 u_Projection;
|
||||
uniform mat4 u_InvProjection;
|
||||
|
||||
uniform vec2 u_ScreenSize;
|
||||
uniform float u_CameraNear;
|
||||
uniform float u_CameraFar;
|
||||
|
||||
uniform int u_Steps = 64;
|
||||
uniform float u_Thickness = 0.5;
|
||||
uniform float u_MaxDistance = 30.0;
|
||||
uniform float u_Intensity = 1.0;
|
||||
|
||||
float LinearizeDepth(float depth)
|
||||
{
|
||||
float z = depth * 2.0 - 1.0;
|
||||
return (2.0 * u_CameraNear * u_CameraFar) / (u_CameraFar + u_CameraNear - z * (u_CameraFar - u_CameraNear));
|
||||
}
|
||||
|
||||
vec3 ReconstructViewPos(vec2 tc, float depth)
|
||||
{
|
||||
float z = depth * 2.0 - 1.0;
|
||||
vec4 clipPos = vec4(tc * 2.0 - 1.0, z, 1.0);
|
||||
vec4 viewPos4 = u_InvProjection * clipPos;
|
||||
return viewPos4.xyz / viewPos4.w;
|
||||
}
|
||||
|
||||
vec3 ReconstructNormalFromDepth(vec2 tc, float depth)
|
||||
{
|
||||
vec2 texelSize = 1.0 / u_ScreenSize;
|
||||
|
||||
vec2 tcL = tc - vec2(texelSize.x, 0.0);
|
||||
vec2 tcR = tc + vec2(texelSize.x, 0.0);
|
||||
vec2 tcB = tc - vec2(0.0, texelSize.y);
|
||||
vec2 tcT = tc + vec2(0.0, texelSize.y);
|
||||
|
||||
float depthL = texture(u_DepthTexture, tcL).r;
|
||||
float depthR = texture(u_DepthTexture, tcR).r;
|
||||
float depthB = texture(u_DepthTexture, tcB).r;
|
||||
float depthT = texture(u_DepthTexture, tcT).r;
|
||||
|
||||
vec3 pL = ReconstructViewPos(tcL, depthL);
|
||||
vec3 pR = ReconstructViewPos(tcR, depthR);
|
||||
vec3 pB = ReconstructViewPos(tcB, depthB);
|
||||
vec3 pT = ReconstructViewPos(tcT, depthT);
|
||||
|
||||
vec3 dx = pR - pL;
|
||||
vec3 dy = pT - pB;
|
||||
|
||||
return normalize(cross(dx, dy));
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
float depth = texture(u_DepthTexture, v_TexCoord).r;
|
||||
|
||||
if (depth >= 1.0)
|
||||
{
|
||||
o_Color = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 matInfo = texture(u_MaterialInfoTexture, v_TexCoord);
|
||||
float metalness = matInfo.r;
|
||||
float roughness = matInfo.g;
|
||||
|
||||
if (roughness > 0.9)
|
||||
{
|
||||
o_Color = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec3 viewPos = ReconstructViewPos(v_TexCoord, depth);
|
||||
vec3 normal = ReconstructNormalFromDepth(v_TexCoord, depth);
|
||||
|
||||
vec3 viewDir = normalize(-viewPos);
|
||||
float NdotV = max(dot(normal, viewDir), 0.0);
|
||||
|
||||
vec3 reflectDir = reflect(-viewDir, normal);
|
||||
|
||||
if (dot(reflectDir, normal) < 0.0)
|
||||
{
|
||||
o_Color = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec3 rayOrigin = viewPos + normal * 0.02;
|
||||
vec3 rayEnd = rayOrigin + reflectDir * u_MaxDistance;
|
||||
|
||||
vec4 p0 = u_Projection * vec4(rayOrigin, 1.0);
|
||||
vec4 p1 = u_Projection * vec4(rayEnd, 1.0);
|
||||
|
||||
float k0 = 1.0 / p0.w;
|
||||
float k1 = 1.0 / p1.w;
|
||||
|
||||
p0.xyz *= k0;
|
||||
p1.xyz *= k1;
|
||||
|
||||
vec3 v0 = rayOrigin * k0;
|
||||
vec3 v1 = rayEnd * k1;
|
||||
|
||||
vec2 s0 = p0.xy * 0.5 + 0.5;
|
||||
vec2 s1 = p1.xy * 0.5 + 0.5;
|
||||
|
||||
vec2 sDelta = s1 - s0;
|
||||
float screenDist = length(sDelta * u_ScreenSize);
|
||||
|
||||
if (screenDist < 1.0)
|
||||
{
|
||||
o_Color = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
float divisions = min(screenDist, float(u_Steps));
|
||||
vec3 dV = (v1 - v0) / divisions;
|
||||
float dK = (k1 - k0) / divisions;
|
||||
vec2 dS = sDelta / divisions;
|
||||
|
||||
vec3 curV = v0;
|
||||
float curK = k0;
|
||||
vec2 curS = s0;
|
||||
|
||||
vec2 hitUV = vec2(0.0);
|
||||
bool found = false;
|
||||
|
||||
for (int i = 0; i < int(divisions); i++)
|
||||
{
|
||||
curV += dV;
|
||||
curK += dK;
|
||||
curS += dS;
|
||||
|
||||
if (curS.x < 0.0 || curS.x > 1.0 || curS.y < 0.0 || curS.y > 1.0)
|
||||
break;
|
||||
|
||||
float sampleDepth = texture(u_DepthTexture, curS).r;
|
||||
float surfDepth = LinearizeDepth(sampleDepth);
|
||||
float rayDepth = -curV.z / curK;
|
||||
|
||||
float depthDiff = rayDepth - surfDepth;
|
||||
|
||||
if (depthDiff > 0.0 && depthDiff < u_Thickness)
|
||||
{
|
||||
hitUV = curS;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
o_Color = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec3 hitNormal = ReconstructNormalFromDepth(hitUV, texture(u_DepthTexture, hitUV).r);
|
||||
if (dot(hitNormal, -reflectDir) < 0.0)
|
||||
{
|
||||
o_Color = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec3 reflectColor = texture(u_ColorTexture, hitUV).rgb;
|
||||
|
||||
float dist = distance(viewPos, ReconstructViewPos(hitUV, texture(u_DepthTexture, hitUV).r));
|
||||
float fadeFactor = 1.0 - smoothstep(u_MaxDistance * 0.5, u_MaxDistance, dist);
|
||||
|
||||
float edgeFade = 1.0;
|
||||
edgeFade *= smoothstep(0.0, 0.15, hitUV.x);
|
||||
edgeFade *= smoothstep(0.0, 0.15, hitUV.y);
|
||||
edgeFade *= smoothstep(0.0, 0.15, 1.0 - hitUV.x);
|
||||
edgeFade *= smoothstep(0.0, 0.15, 1.0 - hitUV.y);
|
||||
|
||||
vec3 F0 = mix(vec3(0.04), reflectColor, metalness);
|
||||
vec3 Fresnel = F0 + (1.0 - F0) * pow(1.0 - NdotV, 5.0);
|
||||
|
||||
float roughnessFade = 1.0 - roughness * roughness;
|
||||
|
||||
vec3 ssrContrib = reflectColor * Fresnel * fadeFactor * edgeFade * roughnessFade * u_Intensity;
|
||||
float ssrAlpha = length(Fresnel) * fadeFactor * edgeFade * roughnessFade;
|
||||
|
||||
o_Color = vec4(ssrContrib, ssrAlpha);
|
||||
}
|
||||
85
Editor/assets/shaders/SSRBlur.glsl
Normal file
85
Editor/assets/shaders/SSRBlur.glsl
Normal file
@ -0,0 +1,85 @@
|
||||
#type vertex
|
||||
#version 430
|
||||
|
||||
layout(location = 0) in vec3 a_Position;
|
||||
layout(location = 1) in vec2 a_TexCoord;
|
||||
|
||||
out vec2 v_TexCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 position = vec4(a_Position.xy, 0.0, 1.0);
|
||||
v_TexCoord = a_TexCoord;
|
||||
gl_Position = position;
|
||||
}
|
||||
|
||||
#type fragment
|
||||
#version 430
|
||||
|
||||
layout(location = 0) out vec4 o_Color;
|
||||
|
||||
in vec2 v_TexCoord;
|
||||
|
||||
uniform sampler2D u_SSRTexture;
|
||||
uniform sampler2D u_DepthTexture;
|
||||
uniform sampler2D u_MaterialInfoTexture;
|
||||
|
||||
uniform vec2 u_ScreenSize;
|
||||
uniform float u_BlurRadius = 4.0;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 texelSize = 1.0 / u_ScreenSize;
|
||||
|
||||
vec4 center = texture(u_SSRTexture, v_TexCoord);
|
||||
if (center.a <= 0.001)
|
||||
{
|
||||
o_Color = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
float roughness = texture(u_MaterialInfoTexture, v_TexCoord).g;
|
||||
float effectiveBlurRadius = max(u_BlurRadius * roughness * roughness, 1.0);
|
||||
|
||||
float centerDepth = texture(u_DepthTexture, v_TexCoord).r;
|
||||
vec3 result = vec3(0.0);
|
||||
float totalWeight = 0.0;
|
||||
|
||||
const int kRadius = 6;
|
||||
float sigma = effectiveBlurRadius * 0.5;
|
||||
|
||||
for (int x = -kRadius; x <= kRadius; x++)
|
||||
{
|
||||
for (int y = -kRadius; y <= kRadius; y++)
|
||||
{
|
||||
vec2 offset = vec2(float(x), float(y)) * texelSize * effectiveBlurRadius / float(kRadius);
|
||||
vec2 sampleUV = v_TexCoord + offset;
|
||||
|
||||
if (sampleUV.x < 0.0 || sampleUV.x > 1.0 || sampleUV.y < 0.0 || sampleUV.y > 1.0)
|
||||
continue;
|
||||
|
||||
float sampleDepth = texture(u_DepthTexture, sampleUV).r;
|
||||
float depthDiff = abs(centerDepth - sampleDepth);
|
||||
|
||||
float depthWeight = exp(-depthDiff * 200.0);
|
||||
|
||||
float spatialWeight = exp(-(float(x * x + y * y)) / (2.0 * sigma * sigma));
|
||||
|
||||
vec4 sampleColor = texture(u_SSRTexture, sampleUV);
|
||||
|
||||
float alphaWeight = sampleColor.a > 0.01 ? 1.0 : 0.0;
|
||||
|
||||
float weight = spatialWeight * depthWeight * alphaWeight;
|
||||
|
||||
result += sampleColor.rgb * weight;
|
||||
totalWeight += weight;
|
||||
}
|
||||
}
|
||||
|
||||
if (totalWeight > 0.0)
|
||||
result /= totalWeight;
|
||||
else
|
||||
result = center.rgb;
|
||||
|
||||
o_Color = vec4(result, center.a);
|
||||
}
|
||||
@ -49,6 +49,9 @@ uniform int u_TextureSamples;
|
||||
uniform bool u_EnableBloom;
|
||||
uniform float u_BloomThreshold;
|
||||
|
||||
uniform bool u_EnableSSR;
|
||||
uniform sampler2D u_SSRTexture;
|
||||
|
||||
const float uFar = 1.0;
|
||||
|
||||
vec4 SampleTexture(sampler2D tex, vec2 texCoord)
|
||||
@ -94,6 +97,12 @@ void main()
|
||||
color += bloomColor;
|
||||
}
|
||||
|
||||
if (u_EnableSSR)
|
||||
{
|
||||
vec4 ssrSample = texture(u_SSRTexture, v_TexCoord);
|
||||
color += ssrSample.rgb * ssrSample.a;
|
||||
}
|
||||
|
||||
|
||||
float exposure = 1.0f;
|
||||
if(u_EnableAutoExposure)
|
||||
|
||||
Reference in New Issue
Block a user