【问题标题】:Draw a sphere on a billboard with world normal from a pointlist从点列表中用世界法线在广告牌上绘制一个球体
【发布时间】:2015-06-13 07:35:07
【问题描述】:

我通过 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;
}

我应该拥有比进行计算所需的信息更多的信息,但我无法完全理解要进行的计算

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

【问题讨论】:

  • 我不太明白。法线仅对每个像素有意义,而不是每个广告牌。您应该从片段着色器中获得法线 - 而不是几何体。如果您的广告牌有法线贴图,您需要传递切线空间 (google) 基向量。在广告牌空间中,正前方的法线将是 (0,0,1)。或者 (dx,dy,1) 如果您有法线贴图。对于照明,您希望将其带入世界空间。什么是世界空间取决于你。这是一个广告牌!
  • 我正在尝试在广告牌上绘制一个球体。我得到了正确的广告牌部分和球体的本地部分。像素着色器的“n”部分是广告牌局部空间中的球体,因此它不会因相机位置而异。我需要做的是从中心和法线方向计算球体世界矩阵,然后用它转换“n”,但我之前使用轴角到矩阵的尝试没有奏效,而且太重了..
  • 第一:投影球体并不明显!大多数人认为一个球体投影到一个圆上。因此到一个边界正方形。那不是真的。画出来。不要粘在球体上。从概念上讲,它是一个虚假的朋友。我没有太多的空间和耐心来输入所有内容,但谷歌搜索“切线空间”。一开始需要花点功夫才能理解,但我认为你已经足够理解了!
  • 检查球体光线投射以获得正确的球体。大多数方法也会为您提供相应的法线。

标签: 3d directx shader hlsl


【解决方案1】:

以下描述了一种适合您的情况的方法。

  1. 在广告牌空间中计算正常

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

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. 逆矩阵(Billboard -> World)

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

  1. 将矩阵应用于法线

到这里,你的世界空间法线已经完成。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-19
    • 2015-10-24
    相关资源
    最近更新 更多