Xna 360 FOV深度缓冲区(按拓扑和2D阴影)

Xna 360 FOV深度缓冲区(按拓扑和2D阴影),xna,monogame,Xna,Monogame,在上一个问题中,我要求提供2D阴影的矩阵解决方案,其中最近的投射者的深度由周围的灯光找到。看来不可能像我想象的那样制作出这样的矩阵。所以我发现另一种方法仍然没有预期的效果但是非常接近,这就是问题所在。首先,让我解释拓扑和行为: 我已经定义了一个背景矩形,其顶点位于XY平面0,0,1,0,1,1,0,1 灯光位置为0.5,0.5,可通过鼠标移动 在同一XY平面上单击鼠标可以添加新的矩形,作为阴影投射器,同时作为阴影接收器。 这是视频 因此,要从灯光位置计算圆周围的深度缓冲区,我需要: 对于多边形线

在上一个问题中,我要求提供2D阴影的矩阵解决方案,其中最近的投射者的深度由周围的灯光找到。看来不可能像我想象的那样制作出这样的矩阵。所以我发现另一种方法仍然没有预期的效果但是非常接近,这就是问题所在。首先,让我解释拓扑和行为:

我已经定义了一个背景矩形,其顶点位于XY平面0,0,1,0,1,1,0,1 灯光位置为0.5,0.5,可通过鼠标移动 在同一XY平面上单击鼠标可以添加新的矩形,作为阴影投射器,同时作为阴影接收器。 这是视频 因此,要从灯光位置计算圆周围的深度缓冲区,我需要:


对于多边形线的每个顶点,VS通过atan2函数计算从灯光位置的角度,并将顶点的输出位置设置为-1最后我找到了一个解决方案:这是视频

下面是用注释制作阴影的VS

VertexShaderOutputMakeShadow MakeShadowVS1(VertexShaderInput input)
{
    // lenght of the line (x1y1-x2y2)
    float d1 = distance(input.Position.xy, input.Position.zw);
    // lenght of perpendicular from LightPos to the line
    float d2 = abs(((LightPos.y - input.Position.y) * (input.Position.z - input.Position.x) - (LightPos.x - input.Position.x) * (input.Position.w - input.Position.y)) / d1);
    float2 v = input.Position.xy - input.Position.zw; // vector of the line
    float2 v1 = input.Position.xy - LightPos; // vector from light to x1y1
    float2 v2 = input.Position.zw - LightPos; // vector from light to x2y2

    float sa = v.x * v1.y - v1.x * v.y; // classify position of light and vector to x1y1 which we calculate to current vertex (left < 0 > right)

    float2 perpendicular = normalize(float2(-v.y, v.x)) * sign(sa); // sign is to flip perpendicular vector if light is not at right
    float perpendicularAngle = atan2(-perpendicular.y, perpendicular.x); // angle of perpendecular

    float angle1 = atan2(-v1.y, v1.x), angle2 = atan2(-v2.y, v2.x); // angles for both line points
    /*
        Here is the tricky part
        Since rasterizer will render left-half circle points as shortest line, like 3/4PI to (-3/4PI) it will overwrite whole depth buffer
        i render only part of it which and to oposite direction, so during the second pass the another part of it will be rendered with different condition,
        but all other lines will be clipped:
        if (abs(angle1 - angle2) > 3.1415926535)
        {
            if (angle1 > 0)
            {
            angle1 = angle1 - 2 * 3.1415926535;
            }
        }
        else
        {
            angle1 = -100;
        }
    */
    if (abs(angle1 - angle2) > 3.1415926535)
    {
        if (angle1 < 0)
        {
            angle1 = 2 * 3.1415926535 + angle1;
        }
    }
    float angleBetweenPerpendicularAndPoint = angle1 - perpendicularAngle; // angle to be interpolated
    VertexShaderOutputMakeShadow output;
    output.PosW = float4(angleBetweenPerpendicularAndPoint, d2, 0, 0); // feed to interpolator
    output.Position = float4(angle1 / 3.1415926535, 0, length(v1), 1.0); // generate X and Z of the transformed vertex, so its between -1 <= X <= 1, and 0 <= Z <= 1
    return output;
}
VS/PS使用的阴影仍然相同

float MakeShadowPS(VertexShaderOutputMakeShadow input) : COLOR0
{
    float2 v = input.PosW - LightPos;
    return length(v);
}
struct VertexShaderOutputUseShadow
{
    float4 Position : SV_POSITION;
    float2 PosW : TEXCOORD0;
    float4 Color : COLOR0;
};
VertexShaderOutputUseShadow UseShadowVS(VertexShaderInput input)
{
    VertexShaderOutputUseShadow output;
    float4 p = float4(input.Position.xy, 0, 1);
    output.Position = mul(p, World);
    output.Color = input.Color;
    output.PosW = input.Position.xy;
    return output;
}
float4 UseShadowPS(VertexShaderOutputUseShadow input) : COLOR0
{
    float2 v = input.PosW - LightPos;
    float angle = atan2(-v.y, v.x);
    float2 UV = float2((angle / 3.1415926535 + 1) / 2, 0.5);
    float shadowD = tex2D(shadowSampler, UV);
    float d = length(v);
    return input.Color * (1 - (d > shadowD ? 1 : d));
}
VertexShaderOutputMakeShadow MakeShadowVS1(VertexShaderInput input)
{
    VertexShaderOutputMakeShadow output;
    float2 v1 = input.Position.xy - LightPos, v2 = input.Position.zw - LightPos;
    float angle1 = atan2(-v1.y, v1.x), angle2 = atan2(-v2.y, v2.x);
    if (abs(angle1 - angle2) > 3.1415926535)
    {
        if (angle1 < 0)
        {
            angle1 = 2 * 3.1415926535 + angle1;
        }
    }
    output.Position = float4(angle1 / 3.1415926535, 0, length(v1), 1.0);
    output.PosW = input.Position.xy;
    return output;
}
if (abs(angle1 - angle2) > 3.1415926535)
{
    if (angle1 > 0)
    {
        angle1 = angle1 - 2 * 3.1415926535;
    }
}
else
{
    angle1 = -100;
}
float MakeShadowPS(VertexShaderOutputMakeShadow input) : COLOR0
{
    return (LightPos.y - input.PosW.y) / sin(input.PosW.z);
}
VertexShaderOutputMakeShadow MakeShadowVS1(VertexShaderInput input)
{
    // lenght of the line (x1y1-x2y2)
    float d1 = distance(input.Position.xy, input.Position.zw);
    // lenght of perpendicular from LightPos to the line
    float d2 = abs(((LightPos.y - input.Position.y) * (input.Position.z - input.Position.x) - (LightPos.x - input.Position.x) * (input.Position.w - input.Position.y)) / d1);
    float2 v = input.Position.xy - input.Position.zw; // vector of the line
    float2 v1 = input.Position.xy - LightPos; // vector from light to x1y1
    float2 v2 = input.Position.zw - LightPos; // vector from light to x2y2

    float sa = v.x * v1.y - v1.x * v.y; // classify position of light and vector to x1y1 which we calculate to current vertex (left < 0 > right)

    float2 perpendicular = normalize(float2(-v.y, v.x)) * sign(sa); // sign is to flip perpendicular vector if light is not at right
    float perpendicularAngle = atan2(-perpendicular.y, perpendicular.x); // angle of perpendecular

    float angle1 = atan2(-v1.y, v1.x), angle2 = atan2(-v2.y, v2.x); // angles for both line points
    /*
        Here is the tricky part
        Since rasterizer will render left-half circle points as shortest line, like 3/4PI to (-3/4PI) it will overwrite whole depth buffer
        i render only part of it which and to oposite direction, so during the second pass the another part of it will be rendered with different condition,
        but all other lines will be clipped:
        if (abs(angle1 - angle2) > 3.1415926535)
        {
            if (angle1 > 0)
            {
            angle1 = angle1 - 2 * 3.1415926535;
            }
        }
        else
        {
            angle1 = -100;
        }
    */
    if (abs(angle1 - angle2) > 3.1415926535)
    {
        if (angle1 < 0)
        {
            angle1 = 2 * 3.1415926535 + angle1;
        }
    }
    float angleBetweenPerpendicularAndPoint = angle1 - perpendicularAngle; // angle to be interpolated
    VertexShaderOutputMakeShadow output;
    output.PosW = float4(angleBetweenPerpendicularAndPoint, d2, 0, 0); // feed to interpolator
    output.Position = float4(angle1 / 3.1415926535, 0, length(v1), 1.0); // generate X and Z of the transformed vertex, so its between -1 <= X <= 1, and 0 <= Z <= 1
    return output;
}
float MakeShadowPS(VertexShaderOutputMakeShadow input) : COLOR0
{
    // input.PosW.y is always the distance from light to the rendered line
    // but input.PosW.x interpolated from angle1 to angle2
    return input.PosW.y / cos(input.PosW.x);
}