Вычисление матрицы проекционного вида для картографирования теней направленного света

Чтобы вычислить матрицу проекционного вида для направленного света, я беру вершины усеченного контура моей активной камеры, умножаю их на вращение моего направленного света и использую эти повернутые вершины, чтобы вычислить протяженность матрицы ортографической проекции для моего направленного света. свет.
Затем я создаю матрицу вида, используя центр ограничительной рамки моего источника света в качестве положения глаза, направление света для вектора вперед, а затем ось Y в качестве вектора вверх.

Я вычисляю вершины усеченной камеры, умножая 8 углов поля на 2 как размер и центрируя в начале координат.

Все работает нормально, и матрица вида проекции светового потока верна, но с этим методом я столкнулся с большой проблемой.

Допустим, моя камера направлена ​​вперед (0, 0, -1), расположена в исходной точке и имеет значение zNear, равное 1, и значение zFar, равное 100. В карту теней отображаются только объекты, видимые из области моей камеры, поэтому каждый объект который имеет позицию Z между -1 и -100.

Проблема в том, что если мой свет имеет направление, которое заставляет свет исходить из-за камеры, и это объект, например, с позицией Z 10 (так за камерой, но все еще перед светом) и достаточно высокий чтобы возможно отбрасывать тень на сцену, видимую из моей камеры, этот объект не отображается на карте теней, потому что он не включен в мою область света, что приводит к ошибке, не отбрасывающей тень.

Чтобы решить эту проблему, я подумывал об использовании ограничивающей рамки сцены для вычисления матрицы проецирования света, но делать это было бы бесполезно, поскольку изображение, отображаемое в карту теней, было настолько большим, что были бы видны многочисленные артефакты (угри тени). и т.д …), поэтому я пропустил это решение.

Как я мог преодолеть эту проблему?


я прочел эта почта в разделе «Расчет точной проекции», чтобы создать матрицу моего проекционного вида, и, для ясности, это мой код:

Frustum* cameraFrustum = activeCamera->GetFrustum();

Vertex3f direction = GetDirection();                                        // z axis
Vertex3f perpVec1 = (direction ^ Vertex3f(0.0f, 0.0f, 1.0f)).Normalized();  // y axis
Vertex3f perpVec2 = (direction ^ perpVec1).Normalized();                    // x axis

Matrix rotationMatrix;
rotationMatrix.m[0] = perpVec2.x;   rotationMatrix.m[1] = perpVec1.x;   rotationMatrix.m[2] =   direction.x;
rotationMatrix.m[4] = perpVec2.y;   rotationMatrix.m[5] = perpVec1.y;   rotationMatrix.m[6] =   direction.y;
rotationMatrix.m[8] = perpVec2.z;   rotationMatrix.m[9] = perpVec1.z;   rotationMatrix.m[10] =  direction.z;

Vertex3f frustumVertices[8];
cameraFrustum->GetFrustumVertices(frustumVertices);

for (AInt i = 0; i < 8; i++)
frustumVertices[i] = rotationMatrix * frustumVertices[i];

Vertex3f minV = frustumVertices[0], maxV = frustumVertices[0];
for (AInt i = 1; i < 8; i++)
{
minV.x = min(minV.x, frustumVertices[i].x);
minV.y = min(minV.y, frustumVertices[i].y);
minV.z = min(minV.z, frustumVertices[i].z);
maxV.x = max(maxV.x, frustumVertices[i].x);
maxV.y = max(maxV.y, frustumVertices[i].y);
maxV.z = max(maxV.z, frustumVertices[i].z);
}

Vertex3f extends = maxV - minV;
extends *= 0.5f;

Matrix viewMatrix = Matrix::MakeLookAt(cameraFrustum->GetBoundingBoxCenter(), direction, perpVec1);
Matrix projectionMatrix = Matrix::MakeOrtho(-extends.x, extends.x, -extends.y, extends.y, -extends.z, extends.z);
Matrix projectionViewMatrix = projectionMatrix * viewMatrix;

SceneObject::SetMatrix("ViewMatrix", viewMatrix);
SceneObject::SetMatrix("ProjectionMatrix", projectionMatrix);
SceneObject::SetMatrix("ProjectionViewMatrix", projectionViewMatrix);

И вот как я вычисляю усеченную фигуру и ее ограничивающую рамку:

Matrix inverseProjectionViewMatrix = projectionViewMatrix.Inversed();

Vertex3f points[8];

_frustumVertices[0] = inverseProjectionViewMatrix * Vertex3f(-1.0f,  1.0f, -1.0f);  // near top-left
_frustumVertices[1] = inverseProjectionViewMatrix * Vertex3f( 1.0f,  1.0f, -1.0f);  // near top-right
_frustumVertices[2] = inverseProjectionViewMatrix * Vertex3f(-1.0f, -1.0f, -1.0f);  // near bottom-left
_frustumVertices[3] = inverseProjectionViewMatrix * Vertex3f( 1.0f, -1.0f, -1.0f);  // near bottom-right
_frustumVertices[4] = inverseProjectionViewMatrix * Vertex3f(-1.0f,  1.0f,  1.0f);  // far top-left
_frustumVertices[5] = inverseProjectionViewMatrix * Vertex3f( 1.0f,  1.0f,  1.0f);  // far top-right
_frustumVertices[6] = inverseProjectionViewMatrix * Vertex3f(-1.0f, -1.0f,  1.0f);  // far bottom-left
_frustumVertices[7] = inverseProjectionViewMatrix * Vertex3f( 1.0f, -1.0f,  1.0f);  // far bottom-right

_boundingBoxMin = _frustumVertices[0];
_boundingBoxMax = _frustumVertices[0];

for (AInt i = 1; i < 8; i++)
{
_boundingBoxMin.x = min(_boundingBoxMin.x, _frustumVertices[i].x);
_boundingBoxMin.y = min(_boundingBoxMin.y, _frustumVertices[i].y);
_boundingBoxMin.z = min(_boundingBoxMin.z, _frustumVertices[i].z);

_boundingBoxMax.x = max(_boundingBoxMax.x, _frustumVertices[i].x);
_boundingBoxMax.y = max(_boundingBoxMax.y, _frustumVertices[i].y);
_boundingBoxMax.z = max(_boundingBoxMax.z, _frustumVertices[i].z);
}

_boundingBoxCenter = Vertex3f((_boundingBoxMin.x + _boundingBoxMax.x) / 2.0f, (_boundingBoxMin.y + _boundingBoxMax.y) / 2.0f, (_boundingBoxMin.z + _boundingBoxMax.z) / 2.0f);

1

Решение

Задача ещё не решена.

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


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