簡體   English   中英

Direct3D11:在 3D 場景中渲染 2D:當相機改變位置時,如何使 2D 對象不在視口上移動?

[英]Direct3D11: Rendering 2D in 3D scene: how to make 2D objects not move on Viewport when camera changes position?

帶有問題示例的圖像: http : //imgur.com/gallery/vmMyk

嗨,我需要一些幫助來使用 3D 相機在 3D 場景中渲染 2D 對象。 我想我設法用 LH 世界坐標解決了 2D 坐標。 但是,只有當相機位於[0.0f, 0.0f, 0.0f]坐標時,我渲染的 2D 對象才位於正確的位置。 在所有其他位置,場景中 2D 對象的位置都是畸形的。 我認為我的矩陣搞砸了,但不知道該往哪里看。 我很感激好主意,如果您有什么遺漏,請發表評論,我會編輯主要帖子為您提供更多信息。

我正在使用簡單的 3D 顏色 HLSL(VS 和 PS 版本:4.0)着色器,並為更大的三角形使用 alpha 混合:

cbuffer ConstantBuffer : register( b0 )
{
    matrix World;
    matrix View;
    matrix Projection;
}
struct VS_INPUT
{
    float4 Pos : POSITION;
    float4 Color : COLOR;
};
struct PS_INPUT
{
    float4 Pos : SV_POSITION;
    float4 Color : COLOR;
};

PS_INPUT VS ( VS_INPUT input )
{
    PS_INPUT output = (PS_INPUT)0;

    input.Pos.w = 1.0f;

    output.Pos = mul ( input.Pos, World );
    output.Pos = mul ( output.Pos, View );
    output.Pos = mul ( output.Pos, Projection );
    output.Color = input.Color;

    return output;
}

float4 PS ( PS_INPUT input ) : SV_Target
{
    return input.Color;
}

那是我的頂點數據結構:

  struct Vertex
  {
    DirectX::XMFLOAT3 position;
    DirectX::XMFLOAT4 color;

    Vertex() {};

    Vertex(DirectX::XMFLOAT3 aPosition, DirectX::XMFLOAT4 aColor) 
      : position(aPosition)
      , color(aColor) 
    {};
  };

渲染對象調用:

bool PrimitiveMesh::Draw()
{
  unsigned int stride = sizeof(Vertex);
  unsigned int offset = 0;

  D3DSystem::GetD3DDeviceContext()->IASetVertexBuffers(0, 1, &iVertexBuffer, &stride, &offset);
  D3DSystem::GetD3DDeviceContext()->IASetIndexBuffer(iIndexBuffer, DXGI_FORMAT_R32_UINT, 0);
  D3DSystem::GetD3DDeviceContext()->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

  return true;
}

帶初始化的繪制調用:

    static PrimitiveMesh* mesh;
    if (mesh == 0)
    {
      std::vector<PrimitiveMesh::Vertex> vertices;
      mesh = new PrimitiveMesh();

      DirectX::XMFLOAT4 color = { 186 / 256.0f, 186 / 256.0f, 186 / 256.0f, 0.8f };
      vertices.push_back({ DirectX::XMFLOAT3(0.0f, 0.0f, 0.0f), color });
      vertices.push_back({ DirectX::XMFLOAT3(0.0f, 600.0f, 0.0f), color });
      vertices.push_back({ DirectX::XMFLOAT3(800.0f, 600.0f, 0.0f), color });

      mesh->SetVerticesAndIndices(vertices);
    }
    // Getting clean matrices here:
    D3D::Matrices(world, view, projection, ortho);
    iGI->TurnZBufferOff();
    iGI->TurnOnAlphaBlending();
    mesh->Draw();
    XMMATRIX view2D = Camera::View2D();

    iColorShader->Render(iGI->GetContext(), 3, &world, &view2D, &ortho);
    iGI->TurnZBufferOn();

這些是我對相機的 2D 計算:

  up = DirectX::XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
  lookAt = DirectX::XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f);
  rotationMatrix = DirectX::XMMatrixRotationRollPitchYaw(0.0f, 0.0f, 0.0f); // (pitch, yaw, roll);

  up = DirectX::XMVector3TransformCoord(up, rotationMatrix);
  lookAt = DirectX::XMVector3TransformCoord(lookAt, rotationMatrix) + position;
  view2D = DirectX::XMMatrixLookAtLH(position, lookAt, up);

我將不勝感激任何幫助。 親切的問候。

使用着色器,您不必使用矩陣,您可以靈活地簡化問題。

假設您使用以像素為單位的坐標渲染 2d 對象,唯一的要求是將它們縮放回標准化投影空間。

頂點着色器可以這么短:

cbuffer ConstantBuffer : register( b0 ) {
    float2 rcpDim; // 1 / renderTargetSize
}
PS_INPUT VS ( VS_INPUT input ) {
    PS_INPUT output;

    output.Pos.xy = input.Pos.xy * rcpDim * 2; // from pixel to [0..2]
    output.Pos.xy -= 1; // to [-1..1]
    output.Pos.y *= -1; // because top left in texture space is bottom left in projective space
    output.Pos.zw = float2(0,1);
    output.Color = input.Color;
    return output;
}

您當然可以使用原始着色器構建一組獲得相同結果的矩陣,只需將 World 和 View 設置為 identity 並將投影設置為使用XMMatrixOrthographicOffCenterLH(0,width,0,height,0,1)的正交投影。 但是當您開始進行 3D 編程時,您很快就必須學會處理多個着色器,因此請將其作為練習。

嗯,我解決了我的問題。 出於某種奇怪的原因,DirectXMath 生成了錯誤的 XMMATRIX。 我的XMMatrixOrtographicLH()對於好的參數是完全不正確的。 我用 Ortohraphic 矩陣的經典定義解決了我的問題, 在這篇文章中找到(圖 10 中的定義)

auto orthoMatrix = DirectX::XMMatrixIdentity();
orthoMatrix.r[0].m128_f32[0] = 2.0f / Engine::VideoSettings::Current()->WindowWidth();
orthoMatrix.r[1].m128_f32[1] = 2.0f / Engine::VideoSettings::Current()->WindowHeight();
orthoMatrix.r[2].m128_f32[2] = -(2.0f / (screenDepth - screenNear));
orthoMatrix.r[2].m128_f32[3] = -(screenDepth + screenNear) / (screenDepth - screenNear);

galop1n 提供了一個很好的解決方案,但在我的系統上

cbuffer ConstantBuffer : register( b0 ) { float2 rcpDim; // 1 / renderTargetSize }

需要是 16 的倍數才能像這樣制作:

struct VS_CONSTANT_BUFFER
{
    DirectX::XMFLOAT2 rcpDim;
    DirectX::XMFLOAT2 rcpDim2;
};

// Supply the vertex shader constant data.
VS_CONSTANT_BUFFER VsConstData;
VsConstData.rcpDim = { 2.0f / w,2.0f / h};

// Fill in a buffer description.
D3D11_BUFFER_DESC cbDesc;
ZeroMemory(&cbDesc, sizeof(cbDesc));
cbDesc.ByteWidth = sizeof(VS_CONSTANT_BUFFER);
cbDesc.Usage = D3D11_USAGE_DYNAMIC;
cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
cbDesc.MiscFlags = 0;
cbDesc.StructureByteStride = 0;

// Fill in the subresource data.
D3D11_SUBRESOURCE_DATA InitData;
ZeroMemory(&InitData, sizeof(InitData));
InitData.pSysMem = &VsConstData;
InitData.SysMemPitch = 0;
InitData.SysMemSlicePitch = 0;

// Create the buffer.
HRESULT hr = pDevice->CreateBuffer(&cbDesc, &InitData,
    &pConstantBuffer11);

或對齊

__declspec(align(16))
struct VS_CONSTANT_BUFFER
{
    DirectX::XMFLOAT2 rcpDim;
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM