Added shadow maps

This commit is contained in:
Vladislav Khorev committed 2026-04-15 19:54:21 +03:00
1 parent a47306533e
commit d8795ec076
15 files changed
+880 -6

No files matched your search

+124
View File
@@ -0,0 +1,124 @@
#include "ShadowMap.h"
#include "Environment.h"
#include <iostream>
#include <cmath>
namespace ZL {
// Build a look-at view matrix (column-major, same convention as the engine).
static Eigen::Matrix4f lookAt(const Eigen::Vector3f& eye,
const Eigen::Vector3f& center,
const Eigen::Vector3f& up) {
Eigen::Vector3f f = (center - eye).normalized();
Eigen::Vector3f s = f.cross(up).normalized();
Eigen::Vector3f u = s.cross(f);
Eigen::Matrix4f m = Eigen::Matrix4f::Identity();
m(0, 0) = s.x(); m(0, 1) = s.y(); m(0, 2) = s.z();
m(1, 0) = u.x(); m(1, 1) = u.y(); m(1, 2) = u.z();
m(2, 0) = -f.x(); m(2, 1) = -f.y(); m(2, 2) = -f.z();
m(0, 3) = -s.dot(eye);
m(1, 3) = -u.dot(eye);
m(2, 3) = f.dot(eye);
return m;
}
// Build an orthographic projection matrix that matches the engine's
// MakeOrthoMatrix(xmin, xmax, ymin, ymax, zNear, zFar) exactly.
static Eigen::Matrix4f ortho(float left, float right,
float bottom, float top,
float zNear, float zFar) {
float width = right - left;
float height = top - bottom;
float depthRange = zFar - zNear;
Eigen::Matrix4f m = Eigen::Matrix4f::Zero();
m(0, 0) = 2.0f / width;
m(1, 1) = 2.0f / height;
m(2, 2) = -1.0f / depthRange;
m(0, 3) = -(right + left) / width;
m(1, 3) = -(top + bottom) / height;
m(2, 3) = zNear / depthRange;
m(3, 3) = 1.0f;
return m;
}
ShadowMap::ShadowMap(int res, float orthoSz, float zNear, float zFar)
: resolution(res)
, orthoSize(orthoSz)
, nearPlane(zNear)
, farPlane(zFar)
, lightDirection(Eigen::Vector3f(-0.5f, -1.0f, -0.3f).normalized())
, lightViewMatrix(Eigen::Matrix4f::Identity())
, lightProjectionMatrix(Eigen::Matrix4f::Identity())
, lightSpaceMatrix(Eigen::Matrix4f::Identity())
{
glGenFramebuffers(1, &fbo);
glGenTextures(1, &depthTexture);
glBindTexture(GL_TEXTURE_2D, depthTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,
resolution, resolution, 0,
GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_TEXTURE_2D, depthTexture, 0);
// No color buffer for this FBO — depth only.
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
std::cerr << "Error: Shadow map framebuffer is not complete!" << std::endl;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
ShadowMap::~ShadowMap() {
if (fbo) glDeleteFramebuffers(1, &fbo);
if (depthTexture) glDeleteTextures(1, &depthTexture);
}
void ShadowMap::setLightDirection(const Eigen::Vector3f& dir) {
lightDirection = dir.normalized();
}
void ShadowMap::updateLightSpaceMatrix(const Eigen::Vector3f& sceneCenter) {
// Place the light "camera" looking at the scene center from the light direction.
Eigen::Vector3f lightPos = sceneCenter - lightDirection * (farPlane * 0.5f);
// Choose an up vector that isn't parallel to the light direction.
Eigen::Vector3f up(0.0f, 1.0f, 0.0f);
if (std::abs(lightDirection.dot(up)) > 0.99f) {
up = Eigen::Vector3f(0.0f, 0.0f, 1.0f);
}
lightViewMatrix = lookAt(lightPos, sceneCenter, up);
lightProjectionMatrix = ortho(
-orthoSize, orthoSize,
-orthoSize, orthoSize,
nearPlane, farPlane);
lightSpaceMatrix = lightProjectionMatrix * lightViewMatrix;
}
void ShadowMap::bind() {
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glViewport(0, 0, resolution, resolution);
glClear(GL_DEPTH_BUFFER_BIT);
}
void ShadowMap::unbind() {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, Environment::width, Environment::height);
}
} // namespace ZL
+44
View File
@@ -0,0 +1,44 @@
#pragma once
#include "render/OpenGlExtensions.h"
#include <Eigen/Dense>
namespace ZL {
class ShadowMap {
private:
GLuint fbo = 0;
GLuint depthTexture = 0;
int resolution;
Eigen::Vector3f lightDirection;
Eigen::Matrix4f lightViewMatrix;
Eigen::Matrix4f lightProjectionMatrix;
Eigen::Matrix4f lightSpaceMatrix;
float orthoSize;
float nearPlane;
float farPlane;
public:
ShadowMap(int resolution = 2048, float orthoSize = 40.0f,
float zNear = 0.1f, float zFar = 100.0f);
~ShadowMap();
ShadowMap(const ShadowMap&) = delete;
ShadowMap& operator=(const ShadowMap&) = delete;
void setLightDirection(const Eigen::Vector3f& dir);
void updateLightSpaceMatrix(const Eigen::Vector3f& sceneCenter);
void bind();
void unbind();
GLuint getDepthTexture() const { return depthTexture; }
int getResolution() const { return resolution; }
const Eigen::Matrix4f& getLightSpaceMatrix() const { return lightSpaceMatrix; }
const Eigen::Matrix4f& getLightViewMatrix() const { return lightViewMatrix; }
const Eigen::Matrix4f& getLightProjectionMatrix() const { return lightProjectionMatrix; }
const Eigen::Vector3f& getLightDirection() const { return lightDirection; }
};
} // namespace ZL