116 lines
4.2 KiB
HLSL
116 lines
4.2 KiB
HLSL
#if !defined(SHADOW_PROJECT_VERTEX)
|
|
#define SHADOW_PROJECT_VERTEX
|
|
|
|
#define ToFloat(x) x
|
|
#define Deg2Rad(x) (x * 3.14159265359f / 180)
|
|
|
|
#define MIN_SHADOW_Y 0.000001f
|
|
|
|
struct Attributes
|
|
{
|
|
float3 vertex : POSITION;
|
|
float4 packed0 : TANGENT;
|
|
};
|
|
|
|
struct Varyings
|
|
{
|
|
float4 vertex : SV_POSITION;
|
|
float2 shadow : TEXCOORD0;
|
|
|
|
};
|
|
|
|
uniform float3 _LightPos;
|
|
uniform float4x4 _ShadowModelMatrix; // This is a custom model matrix without scaling
|
|
uniform float4x4 _ShadowModelInvMatrix;
|
|
uniform float3 _ShadowModelScale; // This is the scale
|
|
uniform float _ShadowRadius;
|
|
uniform float _ShadowContractionDistance;
|
|
uniform float _SoftShadowAngle;
|
|
|
|
float AngleFromDir(float3 dir)
|
|
{
|
|
// Assumes dir is normalized. Will return -180 to 180
|
|
float angle = acos(dir.x);
|
|
float gt180 = ceil(saturate(-dir.y)); // Greater than 180
|
|
return gt180 * -angle + (1 - gt180) * angle;
|
|
}
|
|
|
|
float3 DirFromAngle(float angle)
|
|
{
|
|
return float3(cos(angle), sin(angle), 0);
|
|
}
|
|
|
|
float2 CalculateShadowValue(float shadowType)
|
|
{
|
|
float isLeft = ToFloat(shadowType == 1);
|
|
float isRight = ToFloat(shadowType == 3);
|
|
|
|
return float2(-isLeft + isRight, isLeft + isRight);
|
|
}
|
|
|
|
|
|
float3 SoftShadowDir(float3 lightDir, float3 vertex0, float3 vertex1, float angleOp, float softShadowAngle)
|
|
{
|
|
float lightAngle = AngleFromDir(lightDir);
|
|
float edgeAngle = AngleFromDir(normalize(vertex1 - vertex0));
|
|
float softAngle = lightAngle + angleOp * softShadowAngle;
|
|
|
|
return DirFromAngle(softAngle);
|
|
}
|
|
|
|
float4 ProjectShadowVertexToWS(float2 vertex, float2 otherEndPt, float2 contractDir, float shadowType, float3 lightPos, float3 shadowModelScale, float4x4 shadowModelMatrix, float4x4 shadowModelInvMatrix, float shadowContractionDistance, float shadowRadius, float softShadowAngle)
|
|
{
|
|
float3 vertexOS0 = float3(vertex.x * shadowModelScale.x, vertex.y * shadowModelScale.y, 0);
|
|
float3 vertexOS1 = float3(otherEndPt.x * shadowModelScale.x, otherEndPt.y * shadowModelScale.y, 0); // the tangent has the adjacent point stored in zw
|
|
float3 lightPosOS = float3(mul(shadowModelInvMatrix, float4(lightPos.x, lightPos.y, lightPos.z, 1)).xy, 0); // Transform the light into local space
|
|
|
|
float3 unnormalizedLightDir0 = vertexOS0 - lightPosOS;
|
|
float3 unnormalizedLightDir1 = vertexOS1 - lightPosOS;
|
|
|
|
float3 lightDir0 = normalize(unnormalizedLightDir0);
|
|
float3 lightDir1 = normalize(unnormalizedLightDir1);
|
|
float3 avgLightDir = normalize(lightDir0 + lightDir1);
|
|
|
|
float isSoftShadow = ToFloat(shadowType >= 1);
|
|
float isHardShadow = ToFloat(shadowType == 0);
|
|
|
|
float isShadowVertex = saturate(isSoftShadow + isHardShadow);
|
|
|
|
float3 softShadowDir = SoftShadowDir(lightDir0, vertexOS0, vertexOS1, shadowType - 2, softShadowAngle);
|
|
float3 hardShadowDir = lightDir0;
|
|
|
|
float3 shadowDir = isSoftShadow * softShadowDir + isHardShadow * hardShadowDir;
|
|
|
|
float lightDistance = length(unnormalizedLightDir0);
|
|
float hardShadowLength = max(shadowRadius / dot(lightDir0, avgLightDir), lightDistance);
|
|
float softShadowLength = shadowRadius * (1 / cos(softShadowAngle));
|
|
|
|
// Tests to make sure the light is between 0-90 degrees to the normal. Will be one if it is, zero if not.
|
|
float3 shadowOffset = (isSoftShadow * softShadowLength + isHardShadow * hardShadowLength) * shadowDir;
|
|
float3 contractedVertexPos = vertexOS0 + float3(shadowContractionDistance * contractDir.xy, 0);
|
|
|
|
// If we are suppose to extrude this point, then
|
|
float3 finalVertexOS = isShadowVertex * (lightPosOS + shadowOffset) + (1 - isShadowVertex) * contractedVertexPos;
|
|
|
|
return mul(shadowModelMatrix, float4(finalVertexOS, 1));
|
|
}
|
|
|
|
|
|
Varyings ProjectShadow(Attributes v)
|
|
{
|
|
Varyings o;
|
|
|
|
float2 otherEndPt = v.packed0.zw;
|
|
float shadowType = v.packed0.x;
|
|
float2 position = v.vertex.xy;
|
|
float softShadowAngle = _SoftShadowAngle;
|
|
float2 contractDir = 0;
|
|
|
|
float4 positionWS = ProjectShadowVertexToWS(position, otherEndPt, contractDir, shadowType, _LightPos, _ShadowModelScale, _ShadowModelMatrix, _ShadowModelInvMatrix, _ShadowContractionDistance, _ShadowRadius, softShadowAngle);
|
|
o.vertex = mul(GetWorldToHClipMatrix(), positionWS);
|
|
o.shadow = CalculateShadowValue(shadowType);
|
|
return o;
|
|
}
|
|
|
|
#endif
|