[英]C++ and DirectX: Calculate tangent to mesh with arbitrary normals
我有一個帶有任意法線的網格,我使用標准方法計算了它們來計算切線..
void calcTangent(uint32_t idx1, uint32_t idx2, uint32_t idx3)
{
vertex v1 = _vertex[idx1];
vertex v2 = _vertex[idx2];
vertex v3 = _vertex[idx3];
float du1 = v3.Text.x - v1.Text.x;
float dv1 = v3.Text.y - v1.Text.y;
float du2 = v2.Text.x - v1.Text.x;
float dv2 = v2.Text.y - v1.Text.y;
float tx1 = v3.Pos.x - v1.Pos.x;
float ty1 = v3.Pos.y - v1.Pos.z;
float tz1 = v3.Pos.z - v1.Pos.z;
float tx2 = v2.Pos.x - v1.Pos.x;
float ty2 = v2.Pos.y - v1.Pos.z;
float tz2 = v2.Pos.z - v1.Pos.z;
float r = 1.0f / (du1 * dv2 - dv1 * du2);
float e1x = (dv2 * tx1 - dv1 * tx2) * r;
float e1y = (dv2 * ty1 - dv1 * ty2) * r;
float e1z = (dv2 * tz1 - dv1 * tz2) * r;
//Binormals
float e2x = (du1 * tx2 - du2 * tx1) * r;
float e2y = (du1 * ty2 - du2 * ty1) * r;
float e2z = (du1 * tz2 - du2 * tz1) * r;
XMFLOAT3 ot1 = Math::gramSchmidthF({ v1.Norm.x, v1.Norm.y, v1.Norm.z }, { e1x, e1y, e1z });
XMFLOAT3 ot2 = Math::gramSchmidthF({ v2.Norm.x, v2.Norm.y, v2.Norm.z }, { e1x, e1y, e1z });
XMFLOAT3 ot3 = Math::gramSchmidthF({ v3.Norm.x, v3.Norm.y, v3.Norm.z }, { e1x, e1y, e1z });
_vertex[idx1].Tangent = ot1;
_vertex[idx2].Tangent = ot2;
_vertex[idx3].Tangent = ot3;
}
bitangent 不會傳遞給着色器,而是在 PS.. 頂點着色器和像素着色器中計算。
struct VS_INPUT
{
float4 Position : POSITION;
float3 Normal : NORMAL;
float2 Texture : TEXCOORD;
float3 Tangent : TANGENT;
};
struct PS_INPUT
{
float4 Position : SV_POSITION;
float3 Normal : NORMAL;
float3 Tangent : TANGENT;
float3 Binormal : BINORMAL;
float2 Texture : TEXCOORD0;
float3 ViewDirection : TEXCOORD1;
};
PS_INPUT vertex_shader(VS_INPUT input)
{
PS_INPUT output = (PS_INPUT)0;
input.Position.w = 1.0f;
//transformations
output.Position = mul(input.Position, World);
output.Position = mul(output.Position, View);
output.Position = mul(output.Position, Projection);
//
output.Normal = normalize(mul(float4(input.Normal, 0), World).xyz);
output.Texture = input.Texture;
float3 worldPosition = mul(input.Position, World).xyz;
output.ViewDirection = normalize(CAMERA_POSITION - worldPosition);
//add the tangent and binormal
output.Tangent = normalize(mul(float4(input.Tangent, 0), World).xyz);
output.Binormal = normalize(cross(output.Normal, output.Tangent));
return output;
}
float4 ps(PS_INPUT input) : SV_Target
{
float4 OUT = (float4)0;
//texture normal
float3 sampledNormal = (2 * normalMapTexture.Sample(normalMapSampler, input.Texture).xyz) - 1.0; // Map normal from [0..1] to [-1..1]
//creating matrix
// Tangent
// Binormal
// Normal
float3x3 tbn = float3x3(input.Tangent, input.Binormal, input.Normal);
//convert tangent space to world space
sampledNormal = mul(sampledNormal, tbn); // Transform normal from normal map to world space
float3 viewDirection = normalize(input.ViewDirection);
//texture color
float4 color = colorTexture.Sample(samLinear, input.Texture); //getting the color from texture without normals..
//ambient color
float3 ambient = getVectorColorContribution(AMBIENT_COLOR, color.rgb); //mult AMBIENT_COLOR(.rgb) * AMBIENT_COLOR Intensity (.a) * color
float3 diffuse = (float3)0;
float3 specular = (float3)0;
float3 lightDirection = normalize(-LIGHT_DIR.xyz);
float n_dot_l = dot(sampledNormal, lightDirection);
//calculating the diffuse value
diffuse = saturate(n_dot_l) * LIGHT_COLOR.rgb * LIGHT_COLOR.a;
}
//changing the return types will change the result to basic or specular..
OUT.rgb = diffuse * color;
OUT.a = 1.0f;
return OUT;
}
經過大量挖掘,在 DirectXMesh 中有一個 function 來計算切線權(ComputeTangentFrame)它將結果保存在XMFLOAT4 tangent[3]
數組中,效果很好,所以我的問題是計算切線。 希望它對其他人有幫助.. 使用它的小例子:
uint32_t idx[3];
idx[0] = 0;
idx[1] = 1;
idx[2] = 2;
XMFLOAT3 pos[3];
pos[0] = Pos1;
pos[1] = Pos2;
pos[2] = Pos3;
XMFLOAT3 normals[3];
normals[0] = Normal1;
normals[1] = Normal2;
normals[2] = Normal3;
XMFLOAT2 t[3];
t[0] = TextureCoord1;
t[1] = TextureCoord2;
t[2] = TextureCoord3;
XMFLOAT4 tangent[3];
ComputeTangentFrame(idx,1, pos, normals,t,3, tangent);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.