簡體   English   中英

從視圖和投影矩陣中獲取它們時錯誤的視錐平面

[英]Wrong frustum plane when getting them from view and proj matrix

我在用 aabb 進行視錐剔除時遇到了一些麻煩。 所有平截頭體平面似乎都是錯誤的,我不知道它是從哪里來的。

這是計算平截頭體平面的代碼。

std::vector<math::Vec4> BaseCamera::GetFrustumPlanes()
{
    //Matrix are Column Major
    math::Matrix4 mat = viewMatrix_ * projectionMatrix_;

    std::vector<math::Vec4> tempFrustumPlane(6);

    // Left Frustum Plane
    tempFrustumPlane[0] = mat.GetColumn(3) + mat.GetColumn(0);

    // Right Frustum Plane
    // Subtract first column of matrix from the fourth column
    tempFrustumPlane[1] = mat.GetColumn(3) - mat.GetColumn(0);

    // Top Frustum Plane
    tempFrustumPlane[2] = mat.GetColumn(3) - mat.GetColumn(1);

    // Bottom Frustum Plane
    tempFrustumPlane[3] = mat.GetColumn(3) + mat.GetColumn(1);

    // Near Frustum Plane
    tempFrustumPlane[4] = mat.GetColumn(3) - mat.GetColumn(2);

    // Far Frustum Plane
    // Subtract third column of matrix from the fourth column
    tempFrustumPlane[5] = mat.GetColumn(3) + mat.GetColumn(2);

    // Normalize plane normals (A, B and C (xyz))
    for(int i = 0; i < 6; i++) {
        const auto length = sqrt((tempFrustumPlane[i].x * tempFrustumPlane[i].x) + (tempFrustumPlane[i].y * tempFrustumPlane[i].y) + (tempFrustumPlane[i].z * tempFrustumPlane[i].z));
        tempFrustumPlane[i].x /= length;
        tempFrustumPlane[i].y /= length;
        tempFrustumPlane[i].z /= length;
        tempFrustumPlane[i].w /= length;
    }

    return tempFrustumPlane;
}

使用此函數計算 viewMatrix

Matrix4 Matrix4::LookAt(const Vec3 eye, const Vec3 center, const Vec3 up)
{
    const Vec3 f((center - eye).Normalize());
    const Vec3 s(Vec3::Cross(f, up).Normalize());
    const Vec3 u(Vec3::Cross(s, f));

    Matrix4 result = Identity();
    result[0][0] = s.x;
    result[1][0] = s.y;
    result[2][0] = s.z;
    result[0][1] = u.x;
    result[1][1] = u.y;
    result[2][1] = u.z;
    result[0][2] = -f.x;
    result[1][2] = -f.y;
    result[2][2] = -f.z;
    result[3][0] = -(s * eye);
    result[3][1] = -(u * eye);
    result[3][2] = (f * eye);

    return result;
}

以及使用此函數計算的視角

Matrix4 Matrix4::Perspective(
    const float fov,
    const float aspect,
    const float near,
    const float far)
{
    const float tanHalfFov = tan(fov * 0.5f);

    Matrix4 result(0);

    result[0][0] = 1.0f / (aspect * tanHalfFov);
    result[1][1] = 1.0f / tanHalfFov;
    result[2][2] = far / (near - far);
    result[2][3] = -1.0f;
    result[3][2] = -(far * near) / (far - near);

    return result;
}

最后我在這個函數中測試 aabbs 對視錐體

bool DrawSystem::CullAABB(
    const physics::AABB aabb,
    std::vector<math::Vec4> frustumPlanes)
{

    const float minX = aabb.centerPoint.x - aabb.extent.x;
    const float maxX = aabb.centerPoint.x + aabb.extent.x;

    const float minY = aabb.centerPoint.y - aabb.extent.y;
    const float maxY = aabb.centerPoint.y + aabb.extent.y;

    const float minZ = aabb.centerPoint.z - aabb.extent.z;
    const float maxZ = aabb.centerPoint.z + aabb.extent.z;

    auto& gizmoCommandBuffer = GraphicsEngine::Get().GetGizmoCommandBuffer();

    math::Vec3 center = Camera::Get().GetPosition() + Camera::Get().GetFront() * 2;

    // check box outside/inside of frustum
    for (int i = 0; i < 6; i++)
    {
        math::Vec3 dir{ frustumPlanes[i].x, frustumPlanes[i].y, frustumPlanes[i].z };
        if(i == 0) { //left
            gizmoCommandBuffer.SetColor(Color::red);
        } else if(i == 1) { //right
            gizmoCommandBuffer.SetColor(Color::yellow);
        }
        else if (i == 2) { //top
            gizmoCommandBuffer.SetColor(Color::blue);
        }
        else if (i == 3) { //bottom
            gizmoCommandBuffer.SetColor(Color::green);
        }
        else {
            gizmoCommandBuffer.SetColor(Color::grey);
        }
        for(int j = 0; j < 10; j++) {
            gizmoCommandBuffer.DrawWireSphere(center + (dir * j / 10 )* 0.1f, 0.01f);
        }

        if (frustumPlanes[i] * math::Vec4(minX, minY, minZ, 1.0f) > 0.0f) {
            continue;
        }
        if (frustumPlanes[i] * math::Vec4(maxX, minY, minZ, 1.0f) > 0.0f) {
            continue;
        }
        if (frustumPlanes[i] * math::Vec4(minX, maxY, minZ, 1.0f) > 0.0f) {
            continue;
        }
        if (frustumPlanes[i] * math::Vec4(maxX, maxY, minZ, 1.0f) > 0.0f) {
            continue;
        }
        if (frustumPlanes[i] * math::Vec4(minX, minY, maxZ, 1.0f) > 0.0f) {
            continue;
        }
        if (frustumPlanes[i] * math::Vec4(maxX, minY, maxZ, 1.0f) > 0.0f) {
            continue;
        }
        if (frustumPlanes[i] * math::Vec4(minX, maxY, maxZ, 1.0f) > 0.0f) {
            continue;
        }
        if (frustumPlanes[i] * math::Vec4(maxX, maxY, maxZ, 1.0f) > 0.0f) {
            continue;
        }
        return false;
    }
    return true;
}

在引擎中我做了一個測試。 aabbs 被繪制(在相機外面被認為是藍色,在里面被認為是紅色): 在此處輸入圖片說明

十字架似乎起作用了,但是一旦我轉動相機,十字架就錯了。

AABB 正在工作,因為它們繪制正確。

如果您需要其他任何東西,請詢問

我在這個 repos 中找到了一個有效的解決方案: https : //github.com/EQMG/Acid/blob/master/Sources/Physics/Frustum.cpp

暫無
暫無

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

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