【问题标题】:Cascaded Shadow Map shimmering级联阴影贴图闪烁
【发布时间】:2016-02-03 14:26:18
【问题描述】:

我目前正在尝试了解级联阴影贴图的工作原理,因此我一直在尝试让一个阴影贴图适合视锥体而不会闪烁。我使用 1 到 10000 的近/远平面进行相机投影,这就是我计算光线正交矩阵的方式:

GLfloat far = -INFINITY;
GLfloat near = INFINITY;

//Multiply all the world space frustum corners with the view matrix of the light
Frustum cameraFrustum = CameraMan.getActiveCamera()->mFrustum;
lightViewMatrix = glm::lookAt((cameraFrustum.frustumCenter - glm::vec3(-0.447213620f, -0.89442790f, 0.0f)), cameraFrustum.frustumCenter, glm::vec3(0.0f, 0.0f, 1.0f));

glm::vec3 arr[8];
for (unsigned int i = 0; i < 8; ++i)
    arr[i] = glm::vec3(lightViewMatrix * glm::vec4(cameraFrustum.frustumCorners[i], 1.0f));

glm::vec3 minO = glm::vec3(INFINITY, INFINITY, INFINITY);
glm::vec3 maxO = glm::vec3(-INFINITY, -INFINITY, -INFINITY);

for (auto& vec : arr)
{
    minO = glm::min(minO, vec);
    maxO = glm::max(maxO, vec);
}

far = maxO.z;
near = minO.z;

//Get the longest diagonal of the frustum, this along with texel sized increments is used to keep the shadows from shimmering
//far top right - near bottom left
glm::vec3 longestDiagonal = cameraFrustum.frustumCorners[0] - cameraFrustum.frustumCorners[6];
GLfloat lengthOfDiagonal = glm::length(longestDiagonal);
longestDiagonal = glm::vec3(lengthOfDiagonal);

glm::vec3 borderOffset = (longestDiagonal - (maxO - minO)) * glm::vec3(0.5f, 0.5f, 0.5f);

borderOffset *= glm::vec3(1.0f, 1.0f, 0.0f);

maxO += borderOffset;
minO -= borderOffset;

GLfloat worldUnitsPerTexel = lengthOfDiagonal / 1024.0f;
glm::vec3 vWorldUnitsPerTexel = glm::vec3(worldUnitsPerTexel, worldUnitsPerTexel, 0.0f);
minO /= vWorldUnitsPerTexel;
minO = glm::floor(minO);
minO *= vWorldUnitsPerTexel;

maxO /= vWorldUnitsPerTexel;
maxO = glm::floor(maxO);
maxO *= vWorldUnitsPerTexel; 

lightOrthoMatrix = glm::ortho(minO.x, maxO.x, minO.y, maxO.y, near, far);

使用最长的对角线来抵消截锥体似乎是有效的,因为阴影贴图在环顾四周时似乎没有缩小/缩放,但是使用https://msdn.microsoft.com/en-us/library/windows/desktop/ee416324(v=vs.85).aspx 描述的纹理大小增量没有任何效果。我正在使用一个相当大的场景进行测试,这导致我的阴影贴图分辨率较低,但我想在继续拆分视锥体之前获得一个适合视锥体的稳定阴影。很难从图像中分辨出来,但微软提出的解决方案并没有降低闪烁效果:

【问题讨论】:

  • “闪闪发光”是什么意思?
  • youtube.com/watch?v=PxbGUOC_UeA这个视频解释了它,我的场景看起来像视频的第一部分,而我的微软提出的解决方案应该稳定它

标签: c++ opengl shadow cascade glm-math


【解决方案1】:

最终使用了这个解决方案:

//Calculate the viewMatrix from the frustum center and light direction
Frustum cameraFrustum = CameraMan.getActiveCamera()->mFrustum;
glm::vec3 lightDirection = glm::normalize(glm::vec3(-0.447213620f, -0.89442790f, 0.0f));
lightViewMatrix = glm::lookAt((cameraFrustum.frustumCenter - lightDirection), cameraFrustum.frustumCenter, glm::vec3(0.0f, 1.0f, 0.0f));

//Get the longest radius in world space
GLfloat radius = glm::length(cameraFrustum.frustumCenter - cameraFrustum.frustumCorners[6]);
for (unsigned int i = 0; i < 8; ++i)
{
    GLfloat distance = glm::length(cameraFrustum.frustumCorners[i] - cameraFrustum.frustumCenter);
    radius = glm::max(radius, distance);

}
radius = std::ceil(radius);

//Create the AABB from the radius
glm::vec3 maxOrtho = cameraFrustum.frustumCenter + glm::vec3(radius);
glm::vec3 minOrtho = cameraFrustum.frustumCenter - glm::vec3(radius);

//Get the AABB in light view space
maxOrtho = glm::vec3(lightViewMatrix*glm::vec4(maxOrtho, 1.0f));
minOrtho = glm::vec3(lightViewMatrix*glm::vec4(minOrtho, 1.0f));

//Just checking when debugging to make sure the AABB is the same size
GLfloat lengthofTemp = glm::length(maxOrtho - minOrtho);

//Store the far and near planes
far = maxOrtho.z;
near = minOrtho.z;

lightOrthoMatrix = glm::ortho(minOrtho.x, maxOrtho.x, minOrtho.y, maxOrtho.y, near, far);

//For more accurate near and far planes, clip the scenes AABB with the orthographic frustum
//calculateNearAndFar();

// Create the rounding matrix, by projecting the world-space origin and determining
// the fractional offset in texel space
glm::mat4 shadowMatrix = lightOrthoMatrix * lightViewMatrix;
glm::vec4 shadowOrigin = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);
shadowOrigin = shadowMatrix * shadowOrigin;
GLfloat storedW = shadowOrigin.w;
shadowOrigin = shadowOrigin * 4096.0f / 2.0f;

glm::vec4 roundedOrigin = glm::round(shadowOrigin);
glm::vec4 roundOffset = roundedOrigin - shadowOrigin;
roundOffset = roundOffset *  2.0f / 4096.0f;
roundOffset.z = 0.0f;
roundOffset.w = 0.0f;

glm::mat4 shadowProj = lightOrthoMatrix;
shadowProj[3] += roundOffset;
lightOrthoMatrix = shadowProj;

我在http://www.gamedev.net/topic/650743-improving-cascade-shadow/ 找到了这个,我基本上改用边界球体,然后像该示例一样构造舍入矩阵。像魅力一样工作

【讨论】:

  • 感谢您分享解决方案!你为什么切换到边界球?避免8个梯级转角被改造?对吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-21
  • 2018-04-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多