Каскадные карты теней работают не так, как ожидалось

#c #opengl #shadow-mapping

#c #opengl #отображение теней

Вопрос:

я пытаюсь реализовать каскадное отображение теней с помощью 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); 
  

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

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

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

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

это диапазоны моих разделений
ближний-> дальний
0,1 -> 30,0
0,1 -> 50,0
0,1 -> 1000,0

Ответ №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)