Каскадные карты теней не работают должным образом

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

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

1- рядом
2- далеко
3 - углы (углы усеченной пирамиды данного раскола в мировом пространстве)
4- карта глубины (2D-текстура с размерами 1024 * 1024)

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

float width = float(mRenderer->GetGame()->GetWidth()); 
float height = float(mRenderer->GetGame()->GetHeight()); 
mProjMatrix = glm::perspective(glm::radians(90.0f), (float)width / (float)height, mNear, mFar); 
mViewMatrix = mRenderer->GetView();

glm::mat4 viewProj = mProjMatrix * mViewMatrix; 

glm::vec3 frustumCorners[8] =
{
    glm::vec3(-1.0f, 1.0f, -1.0f),
    glm::vec3(1.0f, 1.0f, -1.0f),
    glm::vec3(1.0f, -1.0f, -1.0f),
    glm::vec3(-1.0f, -1.0f, -1.0f),
    glm::vec3(-1.0f, 1.0f, 1.0f),
    glm::vec3(1.0f, 1.0f, 1.0f),
    glm::vec3(1.0f, -1.0f, 1.0f),
    glm::vec3(-1.0f, -1.0f, 1.0f),
};

for (int i = 0; i < 8; ++i) 
{
    glm::vec4 inversePoint = glm::inverse(viewProj) * glm::vec4(frustumCorners[i], 1.0f);
    mCorners[i] = glm::vec3(inversePoint / inversePoint.w); 
}

for (int i = 0; i < 8; ++i) 
{
    mFrustumCenter += mCorners[i]; 
}

mFrustumCenter /= 8.0f;

после того, как у меня будет центр усеченной вершины этого конкретного разделения, мне нужно выяснить матрицу просмотра света, которую я буду использовать для рендеринга сцены (между ближним и дальним участком разделения ), и я делаю это следующим образом.
mRenderer- ›GetLightDirection () = {0.0f, 20.0f, -1.0f}

glm::vec3 lightDir = glm::normalize(mRenderer->GetLightDirection()); 
glm::vec3 lightPos = mFrustumCenter + lightDir; 

mLightView = glm::lookAt(lightPos, mFrustumCenter , glm::vec3(0.0f, 1.0f, 0.0f));

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

for (int i = 0; i < 8; ++i) 
{
    mCorners[i] = glm::vec3(mLightView * glm::vec4(mCorners[i], 1.0f)); 
}


float minX = std::numeric_limits<float>::max(); 
float maxX = std::numeric_limits<float>::min(); 
float minY = std::numeric_limits<float>::max(); 
float maxY = std::numeric_limits<float>::min(); 
float minZ = std::numeric_limits<float>::max();
float maxZ = std::numeric_limits<float>::min();

for (int i = 0; i < 8; ++i) 
{
    minX = std::min(minX, mCorners[i].x);
    maxX = std::max(maxX, mCorners[i].x);
    minY = std::min(minY, mCorners[i].y);
    maxY = std::max(maxY, mCorners[i].y);
    minZ = std::min(minZ, mCorners[i].z);
    maxZ = std::max(maxZ, mCorners[i].z);
}

mLightProj = glm::ortho(minX, maxX, minY, maxY, minZ, maxZ); 

когда я запускаю свою программу, моя тень работает правильно

введите описание изображения здесь

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

введите описание изображения здесь

это диапазоны моих разбиений
near- ›far
0,1 -› 30,0
0,1 - ›50,0
0,1 -› 1000,0


person Mohamed Hashem    schedule 21.08.2020    source источник


Ответы (1)


ну, я понял, я неправильно разместил свет, поэтому этот фрагмент

glm::vec3 lightDir = glm::normalize(mRenderer->GetLightDirection()); 
glm::vec3 lightPos = mFrustumCenter + lightDir; 

mLightView = glm::lookAt(lightPos, mFrustumCenter , glm::vec3(0.0f, 1.0f, 0.0f));

должно быть

glm::vec3 lightDir = glm::normalize(mRenderer->GetLightDirection()); 
glm::vec3 lightPos = mFrustumCenter + lightDir * (mFar - mNear); 
mLightView = glm::lookAt(lightPos, mFrustumCenter , glm::vec3(0.0f, 1.0f, 0.0f));

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

а также этот фрагмент

float minX = std::numeric_limits<float>::max(); 
float maxX = std::numeric_limits<float>::min(); 
float minY = std::numeric_limits<float>::max(); 
float maxY = std::numeric_limits<float>::min(); 
float minZ = std::numeric_limits<float>::max();
float maxZ = std::numeric_limits<float>::min();

for (int i = 0; i < 8; ++i) 
{
    minX = std::min(minX, mCorners[i].x);
    maxX = std::max(maxX, mCorners[i].x);
    minY = std::min(minY, mCorners[i].y);
    maxY = std::max(maxY, mCorners[i].y);
    minZ = std::min(minZ, mCorners[i].z);
    maxZ = std::max(maxZ, mCorners[i].z);
}

mLightProj = glm::ortho(minX, maxX, minY, maxY, minZ, maxZ);

должно быть

float minX = std::numeric_limits<float>::max(); 
float maxX = std::numeric_limits<float>::min(); 
float minY = std::numeric_limits<float>::max(); 
float maxY = std::numeric_limits<float>::min(); 
float minZ = std::numeric_limits<float>::max();
float maxZ = std::numeric_limits<float>::min();

for (int i = 0; i < 8; ++i) 
{
    minX = std::min(minX, mCorners[i].x);
    maxX = std::max(maxX, mCorners[i].x);
    minY = std::min(minY, mCorners[i].y);
    maxY = std::max(maxY, mCorners[i].y);
    minZ = std::min(minZ, mCorners[i].z);
    maxZ = std::max(maxZ, mCorners[i].z);
}

mLightProj = glm::ortho(minX, maxX, minY, maxY, near, maxZ - minZ);

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

person Mohamed Hashem    schedule 22.08.2020