在 DirectX 11 中渲染 world-space 行
Rendering a world-space line in DirectX 11
我正在 DirectX 11 中渲染样条曲线,但我遇到了一个问题,它似乎卡在屏幕上 space,我无法说服它出现在世界中 space.
样条曲线最初定义为 std::vector<DirectX::XMFLOAT3>
个控制点,它被扩展为与样条曲线上的实际点相同的矢量,称为 linePoints
。然后在这个函数中创建顶点、索引和常量缓冲区:
void Spline::createBuffers(ID3D11Device* device)
{
Vertex vertices[100];
for (int i = 0; i < 100; i++)
{
Vertex v;
v.position = linePoints.at(i);
v.colour = XMFLOAT4(0, 0, 0, 1.0);
vertices[i] = v;
}
D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(D3D11_BUFFER_DESC));
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof(Vertex) * linePoints.size();
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = 0;
D3D11_SUBRESOURCE_DATA InitData;
ZeroMemory(&InitData, sizeof(InitData));
InitData.pSysMem = vertices;
device->CreateBuffer(&bd, &InitData, &vertexBuffer);
ZeroMemory(&bd, sizeof(D3D11_BUFFER_DESC));
bd.Usage = D3D11_USAGE_DEFAULT;
bd.CPUAccessFlags = 0;
bd.ByteWidth = sizeof(WORD) * linePoints.size();
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
WORD indices[200];
int count = 0;
for (WORD i = 0; i < 100; i++)
{
indices[count] = i;
indices[count + 1] = i + 1;
count += 2;
}
ZeroMemory(&InitData, sizeof(InitData));
InitData.pSysMem = indices;
device->CreateBuffer(&bd, &InitData, &indexBuffer);
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof(LineCBuffer);
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bd.CPUAccessFlags = 0;
device->CreateBuffer(&bd, nullptr, &constBuffer);
}
绘制函数为:
void Spline::Draw(ID3D11PixelShader* pShader, ID3D11VertexShader* vShader, Camera& cam)
{
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP);
context->VSSetShader(vShader, nullptr, 0);
context->PSSetShader(pShader, nullptr, 0);
LineCBuffer lCB;
lCB.world = XMMatrixIdentity();
lCB.view = XMMatrixTranspose(cam.getView());
lCB.projection = XMMatrixTranspose(cam.getProjection());
context->UpdateSubresource(constBuffer, 0, nullptr, &lCB, 0, 0);
context->VSSetConstantBuffers(0, 1, &constBuffer);
UINT stride = sizeof(Vertex);
UINT offset = 0;
context->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
context->IASetIndexBuffer(indexBuffer, DXGI_FORMAT_R16_UINT, 0);
context->DrawIndexed(100, 0, 0);
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
}
而整个着色器文件是:
cbuffer lineCBuffer : register(b0)
{
matrix World;
matrix View;
matrix Projection;
};
struct VS_IN
{
float3 position : POSITION;
float4 colour : COLOUR;
};
struct VS_OUT
{
float4 pos : SV_POSITION;
float4 colour : COLOUR;
};
VS_OUT lineVertexShader(float3 position : POSITION, float4 colour : COLOUR)
{
VS_OUT output = (VS_OUT)0;
output.pos = mul(position, World);
output.pos = mul(output.pos, View);
output.pos = mul(output.pos, Projection);
output.pos.w = 1.0f;
output.colour = colour;
return output;
}
float4 linePixelShader(VS_OUT input) : SV_TARGET
{
return input.colour;
}
问题是线的起点(尤其是当它设置为 (0,0,0) 时)锚定到视口。如果线在 (0,0,0) 开始,它不会离开屏幕中心,即使它应该在屏幕外。
我认为你的乘法运算有问题。
VS_OUT lineVertexShader(float3 position : POSITION, float4 colour : COLOUR)
{
VS_OUT output = (VS_OUT)0;
output.pos = mul(position, World);
output.pos = mul(output.pos, View);
output.pos = mul(output.pos, Projection);
output.pos.w = 1.0f;
output.colour = colour;
return output;
}
您使用 float3 作为位置输入。位置是一个点,所以你应该使用
float4(position,1.0f)
作为 3D 中的一个点 Space。如果你的 float3 是一个向量,你创建一个
float4(position,0.0f)
因此您的顶点着色器应如下所示:
VS_OUT lineVertexShader(float3 position : POSITION, float4 colour : COLOUR)
{
VS_OUT output;
output.pos = mul(float4(position,1.0), mul(mul(World,View),Projection));
output.colour = colour;
return output;
}
还有一件事。不要将 pos.w 设置为 1! Rasterrizer 正在将透视图自动转换为 SV_POSITION 的值。然后将同质值传递给像素着色器。有时你真的想将 z 和 w 设置为 1,也许是为了你的立方体贴图在最大距离处渲染或类似的东西。但我认为这是另一个错误。
当您不需要在额外乘法中使用世界、视图和投影时,为什么不在 cpu 上预先计算它,然后将最终的 worldViewProj 矩阵推送到您的着色器?
好看
我正在 DirectX 11 中渲染样条曲线,但我遇到了一个问题,它似乎卡在屏幕上 space,我无法说服它出现在世界中 space.
样条曲线最初定义为 std::vector<DirectX::XMFLOAT3>
个控制点,它被扩展为与样条曲线上的实际点相同的矢量,称为 linePoints
。然后在这个函数中创建顶点、索引和常量缓冲区:
void Spline::createBuffers(ID3D11Device* device)
{
Vertex vertices[100];
for (int i = 0; i < 100; i++)
{
Vertex v;
v.position = linePoints.at(i);
v.colour = XMFLOAT4(0, 0, 0, 1.0);
vertices[i] = v;
}
D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(D3D11_BUFFER_DESC));
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof(Vertex) * linePoints.size();
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = 0;
D3D11_SUBRESOURCE_DATA InitData;
ZeroMemory(&InitData, sizeof(InitData));
InitData.pSysMem = vertices;
device->CreateBuffer(&bd, &InitData, &vertexBuffer);
ZeroMemory(&bd, sizeof(D3D11_BUFFER_DESC));
bd.Usage = D3D11_USAGE_DEFAULT;
bd.CPUAccessFlags = 0;
bd.ByteWidth = sizeof(WORD) * linePoints.size();
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
WORD indices[200];
int count = 0;
for (WORD i = 0; i < 100; i++)
{
indices[count] = i;
indices[count + 1] = i + 1;
count += 2;
}
ZeroMemory(&InitData, sizeof(InitData));
InitData.pSysMem = indices;
device->CreateBuffer(&bd, &InitData, &indexBuffer);
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof(LineCBuffer);
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bd.CPUAccessFlags = 0;
device->CreateBuffer(&bd, nullptr, &constBuffer);
}
绘制函数为:
void Spline::Draw(ID3D11PixelShader* pShader, ID3D11VertexShader* vShader, Camera& cam)
{
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP);
context->VSSetShader(vShader, nullptr, 0);
context->PSSetShader(pShader, nullptr, 0);
LineCBuffer lCB;
lCB.world = XMMatrixIdentity();
lCB.view = XMMatrixTranspose(cam.getView());
lCB.projection = XMMatrixTranspose(cam.getProjection());
context->UpdateSubresource(constBuffer, 0, nullptr, &lCB, 0, 0);
context->VSSetConstantBuffers(0, 1, &constBuffer);
UINT stride = sizeof(Vertex);
UINT offset = 0;
context->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
context->IASetIndexBuffer(indexBuffer, DXGI_FORMAT_R16_UINT, 0);
context->DrawIndexed(100, 0, 0);
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
}
而整个着色器文件是:
cbuffer lineCBuffer : register(b0)
{
matrix World;
matrix View;
matrix Projection;
};
struct VS_IN
{
float3 position : POSITION;
float4 colour : COLOUR;
};
struct VS_OUT
{
float4 pos : SV_POSITION;
float4 colour : COLOUR;
};
VS_OUT lineVertexShader(float3 position : POSITION, float4 colour : COLOUR)
{
VS_OUT output = (VS_OUT)0;
output.pos = mul(position, World);
output.pos = mul(output.pos, View);
output.pos = mul(output.pos, Projection);
output.pos.w = 1.0f;
output.colour = colour;
return output;
}
float4 linePixelShader(VS_OUT input) : SV_TARGET
{
return input.colour;
}
问题是线的起点(尤其是当它设置为 (0,0,0) 时)锚定到视口。如果线在 (0,0,0) 开始,它不会离开屏幕中心,即使它应该在屏幕外。
我认为你的乘法运算有问题。
VS_OUT lineVertexShader(float3 position : POSITION, float4 colour : COLOUR)
{
VS_OUT output = (VS_OUT)0;
output.pos = mul(position, World);
output.pos = mul(output.pos, View);
output.pos = mul(output.pos, Projection);
output.pos.w = 1.0f;
output.colour = colour;
return output;
}
您使用 float3 作为位置输入。位置是一个点,所以你应该使用
float4(position,1.0f)
作为 3D 中的一个点 Space。如果你的 float3 是一个向量,你创建一个
float4(position,0.0f)
因此您的顶点着色器应如下所示:
VS_OUT lineVertexShader(float3 position : POSITION, float4 colour : COLOUR)
{
VS_OUT output;
output.pos = mul(float4(position,1.0), mul(mul(World,View),Projection));
output.colour = colour;
return output;
}
还有一件事。不要将 pos.w 设置为 1! Rasterrizer 正在将透视图自动转换为 SV_POSITION 的值。然后将同质值传递给像素着色器。有时你真的想将 z 和 w 设置为 1,也许是为了你的立方体贴图在最大距离处渲染或类似的东西。但我认为这是另一个错误。
当您不需要在额外乘法中使用世界、视图和投影时,为什么不在 cpu 上预先计算它,然后将最终的 worldViewProj 矩阵推送到您的着色器?
好看