从点列表中使用世界法线在广告牌上绘制一个球体

Draw a sphere on a billboard with world normal from a pointlist

我通过 StructuredBuffer 传递中心世界位置在广告牌上绘制球体,并使用几何着色器构建面向相机的广告牌。球体绘制正确,我可以计算出 UV。现在我想点亮它,但我不知道如何计算世界坐标中的法线...

代码如下所示:

StructuredBuffer<float3> bufferPositions;

VS_OUTPUT VS_Main(uint vertexId : SV_VertexId)
{
    VS_OUTPUT res = (VS_OUTPUT)0;

    res.position = float4(bufferPositions[vertexId], 1);
    res.vertexId = vertexId;

    return res;
}

[maxvertexcount(4)]
void GS_Main(point VS_OUTPUT input[1], inout TriangleStream<VS_OUTPUT> OutputStream)
{
    float halfWidth = SIZE / 2.0f;

    float3 objToCam = normalize(input[0].position.xyz - fCameraPos);
    float3 upVector = float3(0.0f, 1.0f, 0.0f);
    float3 rightVector = normalize(cross(objToCam, upVector));

    rightVector = rightVector * halfWidth;
    upVector = normalize(cross(rightVector, objToCam)) * halfWidth;

    float3 vert[4];

    vert[0] = input[0].position.xyz - rightVector - upVector; // Get bottom left vertex
    vert[1] = input[0].position.xyz + rightVector - upVector; // Get bottom right vertex
    vert[2] = input[0].position.xyz - rightVector + upVector; // Get top left vertex
    vert[3] = input[0].position.xyz + rightVector + upVector; // Get top right vertex

    float2 texCoord[4];
    texCoord[0] = float2(-1, -1);
    texCoord[1] = float2(1, -1);
    texCoord[2] = float2(-1, 1);
    texCoord[3] = float2(1, 1);

    VS_OUTPUT outputVert;
    for(int i = 0; i < 4; i++)
    {
        outputVert.position = mul(float4(vert[i], 1.0f), fViewProj);
        outputVert.wpos = vert[i];
        outputVert.normal = objToCam;
        outputVert.texcoord0 = texCoord[i];
        outputVert.vertexId = input[0].vertexId;

        OutputStream.Append(outputVert);
    }   
}

PS_OUTPUT PS_Main(VS_OUTPUT input)
{
    PS_OUTPUT res = (PS_OUTPUT)0;

    float3 n = float3(input.texcoord0.x, input.texcoord0.y, 0);
    float r2 = dot(n.xy, n.xy);

    // if the texel is not inside the sphere
    if(r2 > 1.0f)
      discard;

    n.z = sqrt(1 - r2);

    // calculate UV mapping
    float u = 0.5 + atan2(n.z, n.x) / (2.0 * PI);
    float v = 0.5 - asin(n.y) / PI;   

    // how to calculate normal in world space ?

    return res;
}

我应该掌握比计算所需更多的信息,但我无法全神贯注地进行计算

更新:我试图从平面向量创建一个轴法线并创建一个旋转矩阵,我将其应用于局部法线 n 但没有成功

下面描述了一种方法,应该适合您的情况。

  1. 在广告牌中计算法线 space

例如,您可以在此处使用纹理坐标

float3 normal = float3(Tex.x*2-1, 0, Tex.y*2-1);
normal.y = sqrt(normal.x*normal.x+normal.y*normal.y)
  1. 创建一个正交变换矩阵(世界 -> 广告牌)

此矩阵由广告牌的三个标准化基本向量(左、法线、上)组成,您必须将它们传递给像素着色器。

  1. 反转矩阵(广告牌 -> 世界)

由于矩阵是正交矩阵,逆矩阵只是转置,结果将广告牌坐标转换为世界坐标。

  1. 将矩阵应用于法线

开始吧,你的世界space正常结束了。