Определение каскадных диапазонов карты теней

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

На данный момент сцена освещения шейдера выглядит так:

"#version 420

const float DEPTH_BIAS = 0.00005;

layout(std140) uniform UnifDirLight
{
mat4 mVPMatrix[4];
mat4 mCamViewMatrix;
vec4 mSplitDistance;
vec4 mLightColor;
vec4 mLightDir;
vec4 mGamma;
vec2 mScreenSize;
} UnifDirLightPass;

layout (binding = 2) uniform sampler2D unifPositionTexture;
layout (binding = 3) uniform sampler2D unifNormalTexture;
layout (binding = 4) uniform sampler2D unifDiffuseTexture;
layout (binding = 6) uniform sampler2DArrayShadow unifShadowTexture;

out vec4 fragColor;

void main()
{
vec2 texcoord = gl_FragCoord.xy / UnifDirLightPass.mScreenSize;

vec3 worldPos = texture(unifPositionTexture, texcoord).xyz;
vec3 normal   = normalize(texture(unifNormalTexture, texcoord).xyz);
vec3 diffuse  = texture(unifDiffuseTexture, texcoord).xyz;

vec4 camPos = UnifDirLightPass.mCamViewMatrix * vec4(worldPos, 1.0);     // legit way of determining the split?

int index = 3;
if (camPos .z > UnifDirLightPass.mSplitDistance.x)
index = 0;
else if (camPos .z > UnifDirLightPass.mSplitDistance.y)
index = 1;
else if (camPos .z > UnifDirLightPass.mSplitDistance.z)
index = 2;

vec4 projCoords = UnifDirLightPass.mVPMatrix[index] * vec4(worldPos, 1.0);
projCoords.w    = projCoords.z - DEPTH_BIAS;
projCoords.z    = float(index);
float visibilty = texture(unifShadowTexture, projCoords);

float angleNormal = clamp(dot(normal, UnifDirLightPass.mLightDir.xyz), 0, 1);

fragColor = vec4(diffuse, 1.0) * visibilty * angleNormal * UnifDirLightPass.mLightColor;
}

И «mSplitDistance», каждый компонент — это центральное расстояние frustrum для этого разделения, умноженное на матрицу вида основных камер.

Vec4 camFarDistCenter;
CameraFrustrum cameraFrustrum = CalculateCameraFrustrum(nearDistArr[cascadeIndex], farDistArr[cascadeIndex], lighting.mCameraPosition, lighting.mCameraDirection, camFarDistCenter);

.....

camFarDistCenter = lighting.mCameraViewMatrix * camFarDistCenter;
splitDistances[cascadeIndex] = camFarDistCenter.z;

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

CameraFrustrum CalculateCameraFrustrum(const float minDist, const float maxDist, const Vec3& cameraPosition, const Vec3& cameraDirection, Vec4& camFarZ)
{
CameraFrustrum ret = { Vec4(-1.0f, -1.0f, 1.0f, 1.0f), Vec4(-1.0f, -1.0f, -1.0f, 1.0f), Vec4(-1.0f, 1.0f, 1.0f, 1.0f), Vec4(-1.0f, 1.0f, -1.0f, 1.0f),
Vec4(1.0f, -1.0f, 1.0f, 1.0f), Vec4(1.0f, -1.0f, -1.0f, 1.0f), Vec4(1.0f, 1.0f, 1.0f, 1.0f), Vec4(1.0f, 1.0f, -1.0f, 1.0f) };

const Vec3 forwardVec = glm::normalize(cameraDirection);
const Vec3 rightVec   = glm::normalize(glm::cross(forwardVec, Vec3(0.0f, 0.0f, 1.0f)));
const Vec3 upVec      = glm::normalize(glm::cross(rightVec, forwardVec));

const Vec3 nearCenter = cameraPosition + forwardVec * minDist;
const Vec3 farCenter  = cameraPosition + forwardVec * maxDist;

camFarZ = Vec4(farCenter, 1.0);

const float nearHeight = tan(glm::radians(70.0f) / 2.0f) * minDist;
const float nearWidth = nearHeight * 1920.0f / 1080.0f;
const float farHeight  = tan(glm::radians(70.0f) / 2.0f) * maxDist;
const float farWidth = farHeight * 1920.0f / 1080.0f;

ret[0] = Vec4(nearCenter - (upVec * nearHeight) - (rightVec * nearWidth), 1.0);
ret[1] = Vec4(nearCenter + (upVec * nearHeight) - (rightVec * nearWidth), 1.0);
ret[2] = Vec4(nearCenter + (upVec * nearHeight) + (rightVec * nearWidth), 1.0);
ret[3] = Vec4(nearCenter - (upVec * nearHeight) + (rightVec * nearWidth), 1.0);

ret[4] = Vec4(farCenter - upVec * farHeight - rightVec * farWidth, 1.0);
ret[5] = Vec4(farCenter + upVec * farHeight - rightVec * farWidth, 1.0);
ret[6] = Vec4(farCenter + upVec * farHeight + rightVec * farWidth, 1.0);
ret[7] = Vec4(farCenter - upVec * farHeight + rightVec * farWidth, 1.0);

return ret;
}

Разве это разумно делать сравнение в пространстве камеры, как я? Это потенциальная проблема?

0

Решение

    void CalculateCameraFrustrum(glm::mat4& projectionMatrix,
glm::mat4  viewMatrix,       // viewMatrix = light POV
glm::vec3  camera            // camera = eye position + eye direction
float      zNear,
float      zFar,
glm::vec4  point[4])         // point[4] = shadow map boundaries
glm::mat4 shadMvp =  projectionMatrix * (viewMatrix * glm::translate(camera));
glm::vec3 transf;
float     maxX = zNear, minX = zFar,
maxY = zNear, minY = zFar;

int i = -1;
while (++i < 4)
{
transf = shadMvp * point[i];

transf.x /= transf.w;
transf.y /= transf.w;

if(transf.x > maxX)
maxX = transf.x;
if(transf.x < minX)
minX = transf.x;
if(transf.y > maxY)
maxY = transf.y;
if(transf.y < minY)
minY = transf.y;
}

float scaleX  =  2.0f / (maxX - minX),
scaleY  =  2.0f / (maxY - minY),
offsetX = -0.5f * (maxX + minX) * scaleX,
offsetY = -0.5f * (maxY + minY) * scaleY;

shadMvp = glm::mat4(1); // Identity matrix

shadMvp[0][0] = scaleX;
shadMvp[1][1] = scaleY;
shadMvp[0][3] = offsetX;
shadMvp[1][3] = offsetY;

projectionMatrix *= shadMvp;
} // No need to calculate view frustum splitting,
// only the boundaries of the shadow maps levels are needed (glm::ortho(...)).
// :)
0

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

Других решений пока нет …

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