3D レンダラーで影を安定させようとしています。CSMを使用しています。
これが私が手に入れたコードで、安定化を試みていません。ただし、ワールド空間での投影のサイズは少なくとも一定である必要があります。
void SkyLight::update() {
// direction is the direction that the light is facing
vec3 tangent = sq::make_tangent(direction);
for (int i = 0; i < 4; i++) {
// .first is the far plane, .second is a struct of 8 vec3 making a world space camera frustum
const std::pair<float, sq::Frustum>& csm = camera->csmArr[i];
// calculates the bounding box centre of the frustum
vec3 frusCentre = sq::calc_frusCentre(csm.second);
mat4 viewMat = glm::lookAt(frusCentre-direction, frusCentre, tangent);
mat4 projMat = glm::ortho(-csm.first, csm.first, -csm.first, csm.first, -csm.first, csm.first);
matArr[i] = projMat * viewMat;
}
}
それはうまくいきます。しかし、影はちらつき、狂ったように泳いでいます。したがって、どこでも推奨されているように見えますが、説明されていないように見えるように、テクセルサイズの増分にスナップしようとすることで、安定化を試みます。
void SkyLight::update() {
vec3 tangent = sq::make_tangent(direction);
for (int i = 0; i < 4; i++) {
const std::pair<float, sq::Frustum>& csm = camera->csmArr[i];
vec3 frusCentre = sq::calc_frusCentre(csm.second);
double qStep = csm.first / 1024.0; // shadow texture size
frusCentre.x = std::round(frusCentre.x / qStep) * qStep;
frusCentre.y = std::round(frusCentre.y / qStep) * qStep;
frusCentre.z = std::round(frusCentre.z / qStep) * qStep;
mat4 viewMat = glm::lookAt(frusCentre-direction, frusCentre, tangent);
mat4 projMat = glm::ortho(-csm.first, csm.first, -csm.first, csm.first, -csm.first, csm.first);
matArr[i] = projMat * viewMat;
}
}
これは、パターンに気付かないほど速くバウンスするのではなく、影がゆっくりと泳ぐという点で違いを生みます。しかし、それはたまたまのことであり、正しいものにまったくスナップしていないこと、または正しいものにスナップしていないことは確かです。