第 24 课:Normal in Non-uniform Scale
我的解:transpose 让“垂直”在被拉扯变形后的空间里仍然保持垂直,而 inverse 负责把被拉歪的比例反过来修正。
本课需 HLSL 顶点 / 纹理对象,暂以代码复盘呈现。
我的解
cbuffer Transform : register(b0) {
float4x4 modelMatrix;
float4x4 viewMatrix;
float4x4 projectionMatrix;
float iTime;
};
struct VSInput {
float3 position : Position;
float3 normal : NORMAL0;
};
struct VSOutput {
float4 position : SV_Position;
float3 normal: NORMAL0;
};
// HLSL does not provide a built-in inverse() function.
// This utility manually computes the inverse of the
// upper-left 3×3 portion of a 4×4 matrix, assuming
// the bottom row and rightmost column are identity.
float4x4 inverse4x4(float4x4 m) {
float a00 = m._11, a01 = m._12, a02 = m._13;
float a10 = m._21, a11 = m._22, a12 = m._23;
float a20 = m._31, a21 = m._32, a22 = m._33;
float det = a00 * (a11 * a22 - a12 * a21)
- a01 * (a10 * a22 - a12 * a20)
+ a02 * (a10 * a21 - a11 * a20);
float invDet = 1.0 / det;
float4x4 inv;
inv._11 = (a11 * a22 - a12 * a21) * invDet;
inv._12 = -(a01 * a22 - a02 * a21) * invDet;
inv._13 = (a01 * a12 - a02 * a11) * invDet;
inv._21 = -(a10 * a22 - a12 * a20) * invDet;
inv._22 = (a00 * a22 - a02 * a20) * invDet;
inv._23 = -(a00 * a12 - a02 * a10) * invDet;
inv._31 = (a10 * a21 - a11 * a20) * invDet;
inv._32 = -(a00 * a21 - a01 * a20) * invDet;
inv._33 = (a00 * a11 - a01 * a10) * invDet;
inv._44 = 1.0;
return inv;
}
float3x3 extractFloat3x3(float4x4 m) {
return float3x3(
m._11, m._12, m._13,
m._21, m._22, m._23,
m._31, m._32, m._33
);
}
float4x4 getModel() {
float4 r1 = float4(cos(iTime) + 2.0, 0.0, 0.0, 0.0);
float4 r2 = float4(0.0, 1.0, 0.0, 0.0);
float4 r3 = float4(0.0, 0.0, 1.0, 0.0);
float4 r4 = float4(0.0, 0.0, 0.0, 1.0);
float4x4 transform = transpose(float4x4(r1, r2, r3, r4));
return mul(modelMatrix, transform);
}
VSOutput main(VSInput input) {
VSOutput output;
float4x4 model = getModel();
float3x3 normTransform = extractFloat3x3(transpose(inverse4x4(model)));
output.normal = normalize(mul(normTransform, input.normal));
float4 localPos = mul(model, float4(input.position, 1.0));
float4 viewPos = mul(viewMatrix, localPos);
output.position = mul(projectionMatrix, viewPos);
return output;
}
复盘笔记
- transpose 让“垂直”在被拉扯变形后的空间里仍然保持垂直,而 inverse 负责把被拉歪的比例反过来修正。
- algebra能证明,拉扯变形的法向量可以通过transpose(inverse4x4(model))来修复。