Рендеринг мировой космической линии в DirectX 11

Я рендерил сплайн в 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), она не покинет центр экрана, даже когда она должна быть за кадром.

1

Решение

Я думаю, что вы делаете что-то не так с вашим умножением.

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-пространстве. Если ваш float3 будет вектором, вы создадите

float4(position,0.0f)

Итак, ваш Vertex Shader должен выглядеть следующим образом:

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, возможно, для вашей карты куба, отображаемой на максимальном расстоянии, или чего-то в этом роде. Но я думаю, что это еще одна ошибка здесь.

Если вам не нужно использовать мир, вид и проекцию в дополнительных умножениях, почему бы не предварительно вычислить их на процессоре, а затем просто вставить окончательную матрицу worldViewProj в ваши шейдеры?

Хорошо выглядеть

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]