В настоящее время я создаю простой движок DirectX, чтобы освежить некоторые свои знания в области графического программирования, но в настоящее время я, к сожалению, на некоторое время застрял. Я пытаюсь визуализировать простой треугольник с помощью движущейся камеры (пока только перевод), но треугольник, кажется, искажается всякий раз, когда я перемещаю камеру. То же самое происходит всякий раз, когда я перемещаю треугольник, но тогда искажение, конечно, происходит в противоположном направлении.
Вот как треугольник выглядит без движения камеры:
Вот как это выглядит, когда я перемещаю камеру вправо:
А вот как это выглядит, когда я поднимаю камеру:
Первой моей мыслью было, что матрица WorldViewProjection как-то отключена, но я не вижу в этом никакой проблемы.
void Renderer::CreateViewProjectionMatrix()
{
using namespace DirectX;
// Create world matrix
const XMMATRIX translation = XMMatrixTranslation(0.f, 0.f, 0.f);
const XMMATRIX rotation = XMMatrixRotationRollPitchYaw(0.f, 0.f, 0.f); // In radians
const XMMATRIX scale = XMMatrixScaling(1.f, 1.f, 1.f);
const XMMATRIX worldMatrix = scale * rotation * translation;
XMStoreFloat4x4(&m_VertexConstantBuffer.worldMatrix, worldMatrix);
// Create view matrix
const XMFLOAT3 cameraForward{ 0.f, 0.f, 1.f };
const XMFLOAT3 cameraUp{ 0.f, 1.f, 0.f };
const XMVECTOR worldPos = XMLoadFloat3(&m_CameraPos);
const XMVECTOR worldForward = XMLoadFloat3(&cameraForward);
const XMVECTOR worldUp = XMLoadFloat3(&cameraUp);
const XMMATRIX viewMatrix = XMMatrixLookToLH(worldPos, worldForward, worldUp);
// Create projection matrix
const float aspectRatioX = static_cast<float>(m_BackBufferDescription.Width) / m_BackBufferDescription.Height;
const float FOV{ 45.f };
const float nearZ{ 0.1f };
const float farZ{ 100.f };
const XMMATRIX projectionMatrix = XMMatrixPerspectiveFovLH(XMConvertToRadians(FOV), aspectRatioX, nearZ, farZ);
// Store WVP matrix
const XMMATRIX WVPMatrix = worldMatrix * viewMatrix * projectionMatrix;
XMStoreFloat4x4(&m_VertexConstantBuffer.worldViewProjection, WVPMatrix);
}
Вот как создается треугольник, если он вам понадобится:
HRESULT Renderer::CreateTriangle()
{
// Create triangle geometry
const BaseVertexInput triangleVertices[] =
{
{ DirectX::XMFLOAT3{ -0.5f,-0.5f, 0.0f }, DirectX::XMFLOAT3{}, DirectX::XMFLOAT2{} },
{ DirectX::XMFLOAT3{ 0.5f,-0.5f, 0.0f }, DirectX::XMFLOAT3{}, DirectX::XMFLOAT2{} },
{ DirectX::XMFLOAT3{ 0.0f, 0.3f, 0.0f }, DirectX::XMFLOAT3{}, DirectX::XMFLOAT2{} }
};
// Create vertexBuffer
const CD3D11_BUFFER_DESC vertexDescription{ sizeof(triangleVertices), D3D11_BIND_VERTEX_BUFFER};
D3D11_SUBRESOURCE_DATA vertexData;
ZeroMemory(&vertexData, sizeof(D3D11_SUBRESOURCE_DATA)); // Stops writes being compiled away if it isn't being read immeadiatly
vertexData.pSysMem = triangleVertices; // Initialization data
vertexData.SysMemPitch = 0; // Distance from beginning line of texture to the next line (only for 2D & 3D texture)
vertexData.SysMemSlicePitch = 0; // Distance from beginning of one depth level to the next (only for 3D texture)
HRESULT result = m_pDevice->CreateBuffer
(
&vertexDescription,
&vertexData,
m_pVertexBuffer.GetAddressOf()
);
if (FAILED(result))
{
Logger::Log(L"ERROR - Failed to create a vertexBuffer");
return result;
}
// Create indexBuffer
const unsigned short triangleIndices[]
{
0,2,1
};
m_IndexCount = ARRAYSIZE(triangleIndices);
const CD3D11_BUFFER_DESC indexDescription{ sizeof(triangleIndices), D3D11_BIND_INDEX_BUFFER };
D3D11_SUBRESOURCE_DATA indexData;
ZeroMemory(&indexData, sizeof(D3D11_SUBRESOURCE_DATA));
indexData.pSysMem = triangleIndices;
indexData.SysMemPitch = 0;
indexData.SysMemSlicePitch = 0;
result = m_pDevice->CreateBuffer
(
&indexDescription,
&indexData,
m_pIndexBuffer.GetAddressOf()
);
if (FAILED(result))
{
Logger::Log(L"ERROR - Failed to create an indexBuffer");
return result;
}
// Creation success
m_SuccesfullCreation = true;
return result;
}
Я изучил: матрицу WVP, мой вершинный шейдер, создание буфера вершин,...
Я пытался сделать транспонирование(RightHandMatrix(...)) из руководства Microsoft, но тогда вообще не вижу никакого треугольника.
Кроме того, я больше понятия не имею, где искать. Обязательно спросите, могу ли я/нужно предоставить еще код.
Обновлено:
Вот мой полный вершинный шейдер:
cbuffer CB_World : register(b0) // Register for GPU access (b. for constant buffers)
{
matrix g_WorldViewProjection; // World to projection space
matrix g_World; // World space
};
struct VS_INPUT
{
float3 position : POSITION;
float3 normal : NORMAL;
float2 uv : TEXCOORD0;
};
struct VS_OUTPUT
{
float4 position : SV_POSITION; // System value
float3 normal : NORMAL;
float2 uv : TEXCOORD0;
};
VS_OUTPUT VSMain(VS_INPUT input)
{
VS_OUTPUT output;
output.position = mul(float4(input.position, 1.0), g_WorldViewProjection);
output.normal = normalize(mul(input.normal, (float3x3) g_World));
output.uv = input.uv;
return output;
}
Гитхаб: https://github.com/RenzoDepoortere/DistortedRender_AidProject
@MaicoDeBlasio Я обновил пост, добавив код вершинного шейдера.
Было бы лучше с полностью простым проектом воспроизведения. Дьявол прячется в деталях
Вершинный шейдер выглядит нормально (за исключением того, что вам пока не нужно нормализовать нормаль... вы должны сделать это в пиксельном шейдере после интерполяции растеризатором). Не могу придумать, что это может быть, за исключением того, что, возможно, вам придется транспонировать матрицы перед привязкой к буферам (хотя вы упомянули, что уже пробовали это).
@SimonMourier, ты хочешь, чтобы я отправил весь проект? или просто начать сначала?
@MaicoDeBlasio, блин, в любом случае спасибо за попытку. Я попробую транспонировать матрицу еще раз, а в противном случае я могу попытаться переделать части рендеринга.
Вы можете опубликовать это где-нибудь в Интернете (github, что угодно).
@SimonMourier добавил к посту ссылку на GitHub
Код в вопросе не соответствует коду в проекте. Здесь вы используете XMMatrixLookToLH
находясь в проекте XMMatrixLookAtLH
. Для меня результат выглядит так, как будто он был создан с помощью кода с использованием XMMatrixLookAtLH
. Также прочтите о минимально воспроизводимом примере.
@user7860670 user7860670 Извините, вы правы. Между публикацией вопроса и публикацией ссылки на GitHub были внесены некоторые незначительные изменения (в основном просто удаление комментариев, изменение имен переменных с «куба» на «треугольник», а «большим» изменением является функция XMMatrixLookAtLH
/XMMatrixLookToLH
). Я обновил код, чтобы более точно представить то, что у меня было на момент публикации вопроса. Кроме того, что касается минимально воспроизводимого примера, я не уверен, насколько еще я смогу сэкономить на проекте, поскольку на самом деле есть только основная функция и средство рендеринга + inputManager для удобства отладки.
Кроме того, замена XMMatrixLookAtLH
на XMMatrixLookToLH
дает тот же результат.
изменение XMMatrixLookAtLH на XMMatrixLookToLH воспроизводит тот же результат" - сейчас в это утверждение сложно поверить. Они по-разному относятся ко второму аргументу. Передача 0.f, 0.f, 1.f
в качестве второго аргумента в XMMatrixLookToLH
означает, что при изменении положения камеры (передается как первый аргумент) направление обзора будет сохраняться параллельно оси Z. Передача 0.f, 0.f, 1.f
в качестве второго аргумента в XMMatrixLookAtLH
означает, что при изменении положения камеры (снова передается в качестве первого аргумента) направление обзора будет изменено на 0.f, 0.f, 1.f
(то есть камера будет повернута).
@user7860670 user7860670 Я не совсем удачно это сформулировал. Я имел в виду, что получил те же результаты, используя XMMatrixLookToLH
с cameraForward в качестве второго аргумента и XMMatrixLookAtLH
с cameraPosition + cameraForward в качестве второго аргумента. Я предполагал, что вы уже ознакомились с проектом.
Я загрузил и собрал проект, проблема, похоже, представляет собой комбинацию двух:
XMMatrixLookAtLH
вместо XMMatrixLookToLH
. Они по-разному относятся ко второму аргументу. Передача 0.f, 0.f, 1.f
в качестве второго аргумента XMMatrixLookToLH означает, что при изменении положения камеры (передается как первый аргумент) направление обзора будет сохраняться параллельно оси Z. Передача 0.f, 0.f, 1.f в качестве второго аргумента в XMMatrixLookAtLH означает, что при изменении положения камеры (снова передается в качестве первого аргумента) направление обзора будет изменено на точку 0.f, 0.f, 1.f. (камера будет повернута).const XMMATRIX WVPMatrix = XMMatrixTranspose(worldMatrix * viewMatrix * projectionMatrix);
Результат с XMMatrixLookToLH
после того, как камера немного сдвинута вправо:
Результат с XMMatrixLookAtLH
после того, как камера немного сдвинута вправо, что также приводит к тому, что она продолжает смотреть в одну и ту же точку 0.f, 0.f, 1.f
:
Ого, такую мелочь, которую я пропустил 😭. Но спасибо большое, я это очень ценю. Никогда бы не подумал, что мне понадобится транспонирование в самом конце.
@RenzoDP Вам также следует прочитать Зачем нам нужно использовать «транспонирование» преобразованной матрицы?
Хорошо, это имеет смысл, тогда мне, вероятно, тоже следует перенести свою матрицу мира. Спасибо!
Код C++ выглядит нормально, но вам нужно будет опубликовать код вершинного шейдера, потому что это похоже на проблему преобразования вершин.