C — преобразование лучей с помощью DirectX11

#c #directx #raycasting

#c #directx #преобразование лучей

Вопрос:

У меня много проблем с вычислениями преобразования лучей, и я не могу понять, в чем проблема. Я использую математическую библиотеку DirectX для создания векторов и тому подобного.

Вот мой код на данный момент:

 auto normalizedDeviceCoords = glm::vec2((float(a_frontend->GetMousePos().x) / float(a_frontend->GetWidth())) * 2.f - 1.f, 
                                        -((float(a_frontend->GetMousePos().y) / float(a_frontend->GetHeight())) * 2.f - 1.f));
auto mouseOrigin = DirectX::XMVectorSet(normalizedDeviceCoords.x, normalizedDeviceCoords.y, 0.0f, 1.0f);
auto mouseEnd = DirectX::XMVectorSet(normalizedDeviceCoords.x, normalizedDeviceCoords.y, 1.0f, 1.0f);

auto viewproj = DirectX::XMMatrixMultiply(a_frontend->GetViewMatrix(), a_frontend->GetProjMatrix());
auto determinant = DirectX::XMMatrixDeterminant(a_camera.ViewProj());
auto inverseviewproj = DirectX::XMMatrixInverse(amp;determinant, a_camera.ViewProj());
auto rayOrigin = DirectX::XMVector4Transform(mouseOrigin, inverseviewproj);
auto rayEnd = DirectX::XMVector4Transform(mouseEnd, inverseviewproj);
auto raySubtraction = DirectX::XMVectorSubtract(rayEnd, rayOrigin);
auto rayDirection = DirectX::XMVector3Normalize(raySubtraction);

auto planeNormal = DirectX::XMVectorSet(0.f, 1.f, 0.f, 0.f);
auto pointOnPlane = DirectX::XMVectorSet(0.f, -0.1f, 0.f, 0.f);

DirectX::XMFLOAT3 denominator;
DirectX::XMStoreFloat3(amp;denominator, DirectX::XMVector3Dot(planeNormal, rayDirection));
if (fabs(denominator.x) <= 0.0001f)
{
    return;
}

auto pointMinusRay = DirectX::XMVectorSubtract(pointOnPlane, rayOrigin);

DirectX::XMFLOAT3 t;
auto almostT = DirectX::XMVector3Dot(pointMinusRay, planeNormal);
DirectX::XMStoreFloat3(amp;t, DirectX::XMVectorScale(almostT, 1.f / denominator.x));

if (t.x < 0)
{
    return;
}

auto rayDirectionLength = DirectX::XMVector3Length(rayDirection);
auto rayPoint = DirectX::XMVectorAdd(rayOrigin, DirectX::XMVectorScale(rayDirection, t.x));
 

Я проверил, что нормализованные координаты устройства верны, длина направления луча также равна единице, а направление луча кажется правильным (трудно определить только по числам).

Любая информация будет полезна. Я уже просмотрел здесь некоторую информацию о переполнении стека, а также на других форумах и ничего не добился.

Комментарии:

1. Забыл упомянуть, что точка луча, которая находится на плоскости, верна только по оси y (это -0.1, что правильно). Позиции x и z неверны, когда должно быть 5, но это 0,1.

2. Вы пробовали DirectXCollision.h функции для этих тестов? Кроме того, рассмотрите using namespace DirectX; в своем .cpp файле.

3. Я проверю этот заголовок, посмотрю, нет ли там каких-либо полезных функций, спасибо, Чак. И я бы, однако, следовал предыдущему стилю программирования программистов, пытаясь сделать код плавным.

4. Может ли проблема заключаться в том, что mouseOrigin должна быть фиксированная точка, а не скользить вокруг, с фиксированным смещением от mouseEnd ? Потому что то, как это выглядит сейчас, raySubtraction просто становится постоянным вектором, независимо от того, куда движется мышь, поэтому rayDirection никогда не меняется. Кажется, никто умнее не отвечает, поэтому я просто высказываю свое предположение.

5. Возможно, я заметил, что то же самое происходит, когда направление луча остается постоянным независимо от того, перемещалась ли мышь. Я проверю это и посмотрю, что произойдет, спасибо.

Ответ №1:

Мой товарищ по команде смог решить эту проблему. Он только что начал использовать математическую функцию DirectX Vector3Unproject. Это приведет к получению координат мыши и преобразованию их в мировые координаты, используя как начало координат, так и конец (таким образом, беря координаты мыши с z, равным 0, а затем 1). Затем вычитаем их друг из друга, чтобы получить вектор, который указывает куда-то в мире. Затем мы смогли взять это направление и преобразовать его в соответствии с текущим положением y камеры, деленным на отрицательное значение y вектора направления. Вот весь код, который у нас есть сейчас:

 DirectX::XMVECTOR mouseNear = DirectX::XMVectorSet((float)a_mousePos.x, (float)a_mousePos.y, 0.0f, 0.0f);
DirectX::XMVECTOR mouseFar = DirectX::XMVectorSet((float)a_mousePos.x, (float)a_mousePos.y, 1.0f, 0.0f);
DirectX::XMVECTOR unprojectedNear = DirectX::XMVector3Unproject(mouseNear, 0, 0, a_width, a_height, a_nearZ, a_farZ,
                                                                a_projection, a_view, DirectX::XMMatrixIdentity());
DirectX::XMVECTOR unprojectedFar = DirectX::XMVector3Unproject(mouseFar, 0, 0, a_width, a_height, a_nearZ, a_farZ,
                                                                a_projection, a_view, DirectX::XMMatrixIdentity());
DirectX::XMVECTOR result = DirectX::XMVector3Normalize(DirectX::XMVectorSubtract(unprojectedFar, unprojectedNear));
DirectX::XMFLOAT3 direction;
DirectX::XMStoreFloat3(amp;direction, result);
return direction;

//Get the distance to the ground.
DirectX::XMFLOAT3 cameraPosition = a_camera.GetPosition();

//Get the point on the ground.
cameraPosition.x  = direction.x * (cameraPosition.y / -direction.y);
cameraPosition.z  = direction.z * (cameraPosition.y / -direction.y);
 

Надеюсь, это может оказаться полезным для кого-то в будущем.