c++ 在DirectX 11中渲染世界空间线

b4lqfgs4  于 2023-05-08  发布在  其他
关注(0)|答案(1)|浏览(179)

我在DirectX 11中渲染样条线,但我遇到了一个问题,它似乎被卡在屏幕空间中,我不能说服它在世界空间中。

样条曲线最初定义为控制点的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),它将不会离开屏幕的中心,即使它应该在屏幕外。

ny6fqffe

ny6fqffe1#

我想你的乘法运算出了问题。

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;
}

使用float 3作为位置输入。位置是Point,所以应该使用

float4(position,1.0f)

作为3D空间中的点。如果你的float 3是一个向量,你创建一个

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;
}

还有一件事不要将位置w设置为1!光栅化器自动对SV_POSITION值进行透视分割。然后将同质值传递到像素着色器。有时你真的想设置z和w为1,也许你的立方体贴图渲染在最大距离。但我认为这是另一个错误。
当你不需要在额外的乘法中使用世界、视图和投影时,为什么不在CPU上预先计算它,然后将最终的worldViewProj矩阵推送到你的着色器?
祝你好运

相关问题