Я делаю программу для проверки пересечения сферы и усечённости и могу определить видимость сферы. Я извлекаю плоскости отсечения фрустума в пространство камеры и проверяю на пересечение. Он отлично работает для всех самолетов, кроме дальнего, и я не могу понять, почему. Я продолжаю тянуть камеру назад, но моя программа все еще утверждает, что сфера видна, несмотря на то, что она была обрезана давно. Если я зайду достаточно далеко, это в конечном итоге определит, что его не видно, но это какое-то расстояние после выхода из усеченного конуса.
Я использую единичную сферу в начале координат для теста. Я использую библиотеку математики OpenGL (GLM) для векторных и матричных структур данных и для ее встроенных математических функций. Вот мой код для функции видимости:
void visibilityTest(const struct MVP *mvp) {
static bool visLastTime = true;
bool visThisTime;
const glm::vec4 modelCenter_worldSpace = glm::vec4(0,0,0,1); //at origin
const int negRadius = -1; //unit sphere
//Get cam space model center
glm::vec4 modelCenter_cameraSpace = mvp->view * mvp->model * modelCenter_worldSpace;
//---------Get Frustum Planes--------
//extract projection matrix row vectors
//NOTE: since glm stores their mats in column-major order, we extract columns
glm::vec4 rowVec[4];
for(int i = 0; i < 4; i++) {
rowVec[i] = glm::vec4( mvp->projection[0][i], mvp->projection[1][i], mvp->projection[2][i], mvp->projection[3][i] );
}
//determine frustum clipping planes (in camera space)
glm::vec4 plane[6];
//NOTE: recall that indices start at zero. So M4 + M3 will be rowVec[3] + rowVec[2]
plane[0] = rowVec[3] + rowVec[2]; //near
plane[1] = rowVec[3] - rowVec[2]; //far
plane[2] = rowVec[3] + rowVec[0]; //left
plane[3] = rowVec[3] - rowVec[0]; //right
plane[4] = rowVec[3] + rowVec[1]; //bottom
plane[5] = rowVec[3] - rowVec[1]; //top
//extend view frustum by 1 all directions; near/far along local z, left/right among local x, bottom/top along local y
// -Ax' -By' -Cz' + D = D'
plane[0][3] -= plane[0][2]; // <x',y',z'> = <0,0,1>
plane[1][3] += plane[1][2]; // <0,0,-1>
plane[2][3] += plane[2][0]; // <-1,0,0>
plane[3][3] -= plane[3][0]; // <1,0,0>
plane[4][3] += plane[4][1]; // <0,-1,0>
plane[5][3] -= plane[5][1]; // <0,1,0>
//----------Determine Frustum-Sphere intersection--------
//if any of the dot products between model center and frustum plane is less than -r, then the object falls outside the view frustum
visThisTime = true;
for(int i = 0; i < 6; i++) {
if( glm::dot(plane[i], modelCenter_cameraSpace) < static_cast<float>(negRadius) ) {
visThisTime = false;
}
}
if(visThisTime != visLastTime) {
printf("Sphere is %s visible\n", (visThisTime) ? "" : "NOT " );
visLastTime = visThisTime;
}
}
Кажется, что многоугольники правильно обрезаются дальней плоскостью, поэтому кажется, что проекционная матрица настроена правильно, но из-за вычислений создается впечатление, что плоскость слишком далеко. Возможно, я не правильно вычисляю что-то или у меня есть фундаментальное недопонимание необходимых расчетов?
Расчеты, которые конкретно относятся к дальней плоскости отсечения:
plane[1] = rowVec[3] - rowVec[2]; //far
а также
plane[1][3] += plane[1][2]; // <0,0,-1>
Я устанавливаю плоскость, равную 4-й строке (или в данном случае столбцу) матрицы проекции — 3-й строке матрицы проекции. Затем я расширяю дальнюю плоскость еще на одну единицу (из-за радиуса сферы, равного единице; D ‘= D — C (-1))
Я много раз просматривал этот код и не понимаю, почему он не должен работать. Любая помощь приветствуется.
РЕДАКТИРОВАТЬ:
Я не могу ответить на свой вопрос, так как у меня нет представителя, поэтому я опубликую его здесь.
Проблема заключалась в том, что я не нормализовал уравнения плоскости. Похоже, что это не имело большого значения для какой-либо из плоскостей зажима, кроме далекой, поэтому я даже не учел это (но это не сделало его менее неправильным). После нормализации все работает нормально.
Задача ещё не решена.
Других решений пока нет …