从点列表中使用世界法线在广告牌上绘制一个球体
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 但没有成功
下面描述了一种方法,应该适合您的情况。
- 在广告牌中计算法线 space
例如,您可以在此处使用纹理坐标
float3 normal = float3(Tex.x*2-1, 0, Tex.y*2-1);
normal.y = sqrt(normal.x*normal.x+normal.y*normal.y)
- 创建一个正交变换矩阵(世界 -> 广告牌)
此矩阵由广告牌的三个标准化基本向量(左、法线、上)组成,您必须将它们传递给像素着色器。
- 反转矩阵(广告牌 -> 世界)
由于矩阵是正交矩阵,逆矩阵只是转置,结果将广告牌坐标转换为世界坐标。
- 将矩阵应用于法线
开始吧,你的世界space正常结束了。
我通过 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 但没有成功
下面描述了一种方法,应该适合您的情况。
- 在广告牌中计算法线 space
例如,您可以在此处使用纹理坐标
float3 normal = float3(Tex.x*2-1, 0, Tex.y*2-1);
normal.y = sqrt(normal.x*normal.x+normal.y*normal.y)
- 创建一个正交变换矩阵(世界 -> 广告牌)
此矩阵由广告牌的三个标准化基本向量(左、法线、上)组成,您必须将它们传递给像素着色器。
- 反转矩阵(广告牌 -> 世界)
由于矩阵是正交矩阵,逆矩阵只是转置,结果将广告牌坐标转换为世界坐标。
- 将矩阵应用于法线
开始吧,你的世界space正常结束了。