#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)