网格被切断
Mesh getting cut off
我正在使用 DirectX 11。我试图在屏幕上绘制一个立方体网格,但下半部分被切断了。如果我移动相机 up/down,下半部分仍然被切断,这使我认为这不是 viewport/rasterizer 问题,但我不确定。图片是立方体向下看然后向上看的画面。无论相机位置如何,您都可以看到立方体被切断。我认为这可能是我的投影矩阵的问题。
我在此处附上了 RenderDoc 捕获,您可以看到 VS 输入是正确的,但是当查看具有纯色阴影的 VS 输出时,同样的事情发生了。 https://drive.google.com/file/d/1sh7tj0hPYwD936BEQCL0wtH8ZzXMiEno/view?usp=sharing
这就是我计算矩阵的方式:
mat4 LookAtMatrix(float3 Position, float3 Target, float3 Up) {
float3 Forward = Normalise(Target - Position);
float3 Right = Cross(Normalise(Up), Forward);
float3 UpV = Cross(Forward, Right);
mat4 Out;
Out.v[0] = float4(Right, 0);
Out.v[1] = float4(UpV, 0);
Out.v[2] = float4(Forward, 0);
Out.v[3] = float4(Position, 1);
return Out;
}
mat4 ProjectionMatrix(f32 FOV, f32 Aspect, f32 Near, f32 Far) {
mat4 Out;
f32 YScale = 1.0f / tan((FOV * Deg2Rad) / 2.0f);
f32 XScale = YScale / Aspect;
f32 NmF = Near - Far;
Out.v[0] = float4(XScale, 0, 0, 0);
Out.v[1] = float4(0, YScale, 0, 0);
Out.v[2] = float4(0, 0, (Far + Near) / NmF, -1.0f);
Out.v[3] = float4(0, 0, 2 * Far * Near / NmF, 0);
return Out;
}
这就是我调用这些函数的方式(无论我是否使用旋转都会出现问题):
D3D11_MAPPED_SUBRESOURCE Resource;
HRESULT Result = DeviceContext->Map(ConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &Resource);
if(FAILED(Result)) FatalError("DeviceContext->Map failed");
matrix_buffer *Buffer = (matrix_buffer *)Resource.pData;
static float yR = 0.0f;
yR += 50.0f * DeltaTime;
while(yR > 360.0f) yR -= 360.0f;
while(yR < 0.0f) yR += 360.0f;
quat R = QuatFromAngles(0.0f, yR, 0.0f);
const float Speed = 100.0f;
static float3 Position = float3(0, 0, -300);
if(WDown) Position.z += Speed * DeltaTime;
if(ADown) Position.x += Speed * DeltaTime;
if(SDown) Position.z -= Speed * DeltaTime;
if(DDown) Position.x -= Speed * DeltaTime;
if(QDown) Position.y -= Speed * DeltaTime;
if(EDown) Position.y += Speed * DeltaTime;
Buffer->WorldMatrix = RotationMatrix(R, float3(0, 0, 0));
Buffer->ViewMatrix = LookAtMatrix(Position, Position+float3(0, 0, 1), float3(0, 1, 0));
Buffer->ProjectionMatrix = ProjectionMatrix(45.0f, 1366/768, 0.1f, 1000.0f);
DeviceContext->Unmap(ConstantBuffer, 0);
这是我的顶点着色器代码:
struct vertex_data {
float3 Position : POSITION;
float2 UV : TEXCOORD;
float4 Colour : COLOR;
float3 Normal : NORMAL;
};
struct pixel_data {
float4 Position : SV_POSITION;
float2 UV : TEXCOORD;
float4 Colour : COLOR;
float3 Normal : NORMAL;
};
cbuffer MatrixBuffer {
float4x4 WorldMatrix;
float4x4 ViewMatrix;
float4x4 ProjectionMatrix;
};
pixel_data VertexMain(vertex_data Input) {
pixel_data Output;
float4 V = float4(Input.Position, 1);
Output.Position = mul(V, transpose(WorldMatrix));
Output.Position = mul(Output.Position, transpose(ViewMatrix));
Output.Position = mul(Output.Position, transpose(ProjectionMatrix));
Output.UV = Input.UV;
Output.Colour = Input.Colour;
Output.Normal = Input.Normal;
return Output;
}
这是我设置视口的代码(Width/Height 是 1366/768 - window 的大小):
D3D11_VIEWPORT Viewport;
Viewport.Width = (float)Width;
Viewport.Height = (float)Height;
Viewport.MinDepth = 0.0f;
Viewport.MaxDepth = 1.0f;
Viewport.TopLeftX = 0.0f;
Viewport.TopLeftY = 0.0f;
DeviceContext->RSSetViewports(1, &Viewport);
我看到过由以下原因引起的类似问题:
转置矩阵(你使用的是行主矩阵还是列主矩阵?你需要#pragma pack_matrix吗?看起来你已经对转置做了很多事情 - 避免这样做那,因为你会犯难以推理的错误)
否则矩阵乘法顺序乱了。如果你摆动相机 up/down/left/right 或围绕它旋转模型并旋转它,它真的有效吗?确保将相机旋转与相机平移和对象旋转/平移相结合,否则您可能会错误地认为您的代码有效。如果你拉近或拉远会怎样?
我建议您在调试这些问题时首先尝试 运行 在 CPU 代码中进行着色器转换:
- 取一个简单的 model-space 坐标(例如 0,0,0)。
- 通过你的世界矩阵,检查它是否正确。
- 通过你的视图矩阵,验证它。
- 然后是你的项目矩阵。
即使是那个简单的测试也能揭示很多问题。基本上,如果您认为您的顶点着色器是错误的,幸运的是,这通常是最容易在软件中验证的着色器!如果通过,请尝试其他几个顶点,例如您的盒子的顶点。如果这在软件中成功了,那么现在您知道它在某种程度上与您将顶点数据传递给 GPU 的方式有关(例如 row-major 与 column-major)。如果没有,那么您已经构建了一个简单的 CPU-side 重现,太棒了。
(此外,我不确定您的像素着色器是什么,但要排除它并隔离顶点着色器,请考虑将像素着色器设为 return 纯白色)
我正在使用 DirectX 11。我试图在屏幕上绘制一个立方体网格,但下半部分被切断了。如果我移动相机 up/down,下半部分仍然被切断,这使我认为这不是 viewport/rasterizer 问题,但我不确定。图片是立方体向下看然后向上看的画面。无论相机位置如何,您都可以看到立方体被切断。我认为这可能是我的投影矩阵的问题。
我在此处附上了 RenderDoc 捕获,您可以看到 VS 输入是正确的,但是当查看具有纯色阴影的 VS 输出时,同样的事情发生了。 https://drive.google.com/file/d/1sh7tj0hPYwD936BEQCL0wtH8ZzXMiEno/view?usp=sharing
这就是我计算矩阵的方式:
mat4 LookAtMatrix(float3 Position, float3 Target, float3 Up) {
float3 Forward = Normalise(Target - Position);
float3 Right = Cross(Normalise(Up), Forward);
float3 UpV = Cross(Forward, Right);
mat4 Out;
Out.v[0] = float4(Right, 0);
Out.v[1] = float4(UpV, 0);
Out.v[2] = float4(Forward, 0);
Out.v[3] = float4(Position, 1);
return Out;
}
mat4 ProjectionMatrix(f32 FOV, f32 Aspect, f32 Near, f32 Far) {
mat4 Out;
f32 YScale = 1.0f / tan((FOV * Deg2Rad) / 2.0f);
f32 XScale = YScale / Aspect;
f32 NmF = Near - Far;
Out.v[0] = float4(XScale, 0, 0, 0);
Out.v[1] = float4(0, YScale, 0, 0);
Out.v[2] = float4(0, 0, (Far + Near) / NmF, -1.0f);
Out.v[3] = float4(0, 0, 2 * Far * Near / NmF, 0);
return Out;
}
这就是我调用这些函数的方式(无论我是否使用旋转都会出现问题):
D3D11_MAPPED_SUBRESOURCE Resource;
HRESULT Result = DeviceContext->Map(ConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &Resource);
if(FAILED(Result)) FatalError("DeviceContext->Map failed");
matrix_buffer *Buffer = (matrix_buffer *)Resource.pData;
static float yR = 0.0f;
yR += 50.0f * DeltaTime;
while(yR > 360.0f) yR -= 360.0f;
while(yR < 0.0f) yR += 360.0f;
quat R = QuatFromAngles(0.0f, yR, 0.0f);
const float Speed = 100.0f;
static float3 Position = float3(0, 0, -300);
if(WDown) Position.z += Speed * DeltaTime;
if(ADown) Position.x += Speed * DeltaTime;
if(SDown) Position.z -= Speed * DeltaTime;
if(DDown) Position.x -= Speed * DeltaTime;
if(QDown) Position.y -= Speed * DeltaTime;
if(EDown) Position.y += Speed * DeltaTime;
Buffer->WorldMatrix = RotationMatrix(R, float3(0, 0, 0));
Buffer->ViewMatrix = LookAtMatrix(Position, Position+float3(0, 0, 1), float3(0, 1, 0));
Buffer->ProjectionMatrix = ProjectionMatrix(45.0f, 1366/768, 0.1f, 1000.0f);
DeviceContext->Unmap(ConstantBuffer, 0);
这是我的顶点着色器代码:
struct vertex_data {
float3 Position : POSITION;
float2 UV : TEXCOORD;
float4 Colour : COLOR;
float3 Normal : NORMAL;
};
struct pixel_data {
float4 Position : SV_POSITION;
float2 UV : TEXCOORD;
float4 Colour : COLOR;
float3 Normal : NORMAL;
};
cbuffer MatrixBuffer {
float4x4 WorldMatrix;
float4x4 ViewMatrix;
float4x4 ProjectionMatrix;
};
pixel_data VertexMain(vertex_data Input) {
pixel_data Output;
float4 V = float4(Input.Position, 1);
Output.Position = mul(V, transpose(WorldMatrix));
Output.Position = mul(Output.Position, transpose(ViewMatrix));
Output.Position = mul(Output.Position, transpose(ProjectionMatrix));
Output.UV = Input.UV;
Output.Colour = Input.Colour;
Output.Normal = Input.Normal;
return Output;
}
这是我设置视口的代码(Width/Height 是 1366/768 - window 的大小):
D3D11_VIEWPORT Viewport;
Viewport.Width = (float)Width;
Viewport.Height = (float)Height;
Viewport.MinDepth = 0.0f;
Viewport.MaxDepth = 1.0f;
Viewport.TopLeftX = 0.0f;
Viewport.TopLeftY = 0.0f;
DeviceContext->RSSetViewports(1, &Viewport);
我看到过由以下原因引起的类似问题:
转置矩阵(你使用的是行主矩阵还是列主矩阵?你需要#pragma pack_matrix吗?看起来你已经对转置做了很多事情 - 避免这样做那,因为你会犯难以推理的错误)
否则矩阵乘法顺序乱了。如果你摆动相机 up/down/left/right 或围绕它旋转模型并旋转它,它真的有效吗?确保将相机旋转与相机平移和对象旋转/平移相结合,否则您可能会错误地认为您的代码有效。如果你拉近或拉远会怎样?
我建议您在调试这些问题时首先尝试 运行 在 CPU 代码中进行着色器转换:
- 取一个简单的 model-space 坐标(例如 0,0,0)。
- 通过你的世界矩阵,检查它是否正确。
- 通过你的视图矩阵,验证它。
- 然后是你的项目矩阵。
即使是那个简单的测试也能揭示很多问题。基本上,如果您认为您的顶点着色器是错误的,幸运的是,这通常是最容易在软件中验证的着色器!如果通过,请尝试其他几个顶点,例如您的盒子的顶点。如果这在软件中成功了,那么现在您知道它在某种程度上与您将顶点数据传递给 GPU 的方式有关(例如 row-major 与 column-major)。如果没有,那么您已经构建了一个简单的 CPU-side 重现,太棒了。
(此外,我不确定您的像素着色器是什么,但要排除它并隔离顶点着色器,请考虑将像素着色器设为 return 纯白色)