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

+180 -2
View File
@@ -250,7 +250,25 @@ namespace ZL
npcs.push_back(std::move(npc02));
std::cout << "Load resurces step 12" << std::endl;
// Shadow mapping shaders
#ifdef EMSCRIPTEN
renderer.shaderManager.AddShaderFromFiles("shadow_depth", "resources/shaders/shadow_depth.vertex", "resources/shaders/shadow_depth_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("shadow_depth_skinning", "resources/shaders/shadow_depth_skinning.vertex", "resources/shaders/shadow_depth_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("default_shadow", "resources/shaders/default_shadow.vertex", "resources/shaders/default_shadow_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("skinning_shadow", "resources/shaders/skinning_shadow.vertex", "resources/shaders/default_shadow_web.fragment", CONST_ZIP_FILE);
#else
renderer.shaderManager.AddShaderFromFiles("shadow_depth", "resources/shaders/shadow_depth.vertex", "resources/shaders/shadow_depth_desktop.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("shadow_depth_skinning", "resources/shaders/shadow_depth_skinning.vertex", "resources/shaders/shadow_depth_desktop.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("default_shadow", "resources/shaders/default_shadow.vertex", "resources/shaders/default_shadow_desktop.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("skinning_shadow", "resources/shaders/skinning_shadow.vertex", "resources/shaders/default_shadow_desktop.fragment", CONST_ZIP_FILE);
#endif
// Create shadow map (2048x2048, ortho size 40, near 0.1, far 100)
shadowMap = std::make_unique<ShadowMap>(2048, 40.0f, 0.1f, 100.0f);
shadowMap->setLightDirection(Eigen::Vector3f(-0.5f, -1.0f, -0.3f));
std::cout << "Shadow map initialized" << std::endl;
loadingCompleted = true;
dialogueSystem.init(renderer, CONST_ZIP_FILE);
@@ -455,6 +473,161 @@ namespace ZL
}
void Game::drawShadowDepthPass()
{
if (!shadowMap) return;
const Eigen::Vector3f& sceneCenter = player ? player->position : Eigen::Vector3f::Zero();
shadowMap->updateLightSpaceMatrix(sceneCenter);
shadowMap->bind();
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
// Use front-face culling during depth pass to reduce shadow acne on lit faces
//glCullFace(GL_FRONT);
glEnable(GL_CULL_FACE);
renderer.shaderManager.PushShader("shadow_depth");
// Set up light's orthographic projection
const Eigen::Matrix4f& lightProj = shadowMap->getLightProjectionMatrix();
const Eigen::Matrix4f& lightView = shadowMap->getLightViewMatrix();
// Push the light's projection matrix via the 6-param ortho overload won't
// match our pre-computed matrix. Instead, use the raw stack approach:
// push a dummy projection then overwrite via PushSpecialMatrix-style.
// Simpler: push ortho then push the light view as modelview.
renderer.PushProjectionMatrix(
-40.0f, 40.0f,
-40.0f, 40.0f,
0.1f, 100.0f);
const Eigen::Vector3f& lightDir = shadowMap->getLightDirection();
Eigen::Vector3f lightPos = sceneCenter - lightDir * 50.0f;
Eigen::Vector3f up(0.0f, 1.0f, 0.0f);
if (std::abs(lightDir.dot(up)) > 0.99f) {
up = Eigen::Vector3f(0.0f, 0.0f, 1.0f);
}
// Build the light view matrix and push it
renderer.PushSpecialMatrix(lightView);
// Draw static geometry
renderer.DrawVertexRenderStruct(roomMesh);
for (auto& [name, gameObj] : gameObjects) {
renderer.DrawVertexRenderStruct(gameObj.mesh);
}
for (auto& intObj : interactiveObjects) {
if (intObj.isActive && intObj.texture) {
renderer.PushMatrix();
renderer.TranslateMatrix(intObj.position);
renderer.DrawVertexRenderStruct(intObj.mesh);
renderer.PopMatrix();
}
}
// Draw characters (they handle their own skinning shader switch internally)
if (player) player->drawShadowDepth(renderer);
for (auto& npc : npcs) npc->drawShadowDepth(renderer);
renderer.PopMatrix(); // light view
renderer.PopProjectionMatrix();
renderer.shaderManager.PopShader();
//glCullFace(GL_BACK);
glDisable(GL_CULL_FACE);
shadowMap->unbind();
}
void Game::drawGameWithShadows()
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
#ifdef DEBUG_LIGHT
// Debug mode: render from the light's point of view using the plain
// textured shader so we can see what the shadow map "sees".
renderer.shaderManager.PushShader(defaultShaderName);
renderer.RenderUniform1i(textureUniformName, 0);
renderer.PushProjectionMatrix(
-40.0f, 40.0f,
-40.0f, 40.0f,
0.1f, 1000.0f);
renderer.PushSpecialMatrix(shadowMap->getLightViewMatrix());
#else
static const std::string shadowShaderName = "default_shadow";
renderer.shaderManager.PushShader(shadowShaderName);
renderer.RenderUniform1i(textureUniformName, 0);
renderer.RenderUniform1i("uShadowMap", 1);
// Bind shadow map texture to unit 1
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, shadowMap->getDepthTexture());
glActiveTexture(GL_TEXTURE0);
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
renderer.PushMatrix();
renderer.LoadIdentity();
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraInclination, Eigen::Vector3f::UnitX())).toRotationMatrix());
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraAzimuth, Eigen::Vector3f::UnitY())).toRotationMatrix());
const Eigen::Vector3f& camTarget = player ? player->position : Eigen::Vector3f::Zero();
renderer.TranslateMatrix({ -camTarget.x(), -camTarget.y(), -camTarget.z() });
// Capture the camera view matrix and compute uLightFromCamera
cameraViewMatrix = renderer.GetCurrentModelViewMatrix();
Eigen::Matrix4f cameraViewInverse = cameraViewMatrix.inverse();
Eigen::Matrix4f lightFromCamera = shadowMap->getLightSpaceMatrix() * cameraViewInverse;
renderer.RenderUniformMatrix4fv("uLightFromCamera", false, lightFromCamera.data());
// Light direction in camera space for diffuse lighting
Eigen::Vector3f lightDirCamera = cameraViewMatrix.block<3,3>(0,0) * shadowMap->getLightDirection();
renderer.RenderUniform3fv("uLightDir", lightDirCamera.data());
#endif
glBindTexture(GL_TEXTURE_2D, roomTexture->getTexID());
renderer.DrawVertexRenderStruct(roomMesh);
for (auto& [name, gameObj] : gameObjects) {
glBindTexture(GL_TEXTURE_2D, gameObj.texture->getTexID());
renderer.DrawVertexRenderStruct(gameObj.mesh);
}
for (auto& intObj : interactiveObjects) {
if (intObj.isActive) {
intObj.draw(renderer);
}
}
#ifdef DEBUG_LIGHT
// In debug-light mode characters use the plain shaders (draw normally
// but from the light's viewpoint — projection/view already on stack).
if (player) player->draw(renderer);
for (auto& npc : npcs) npc->draw(renderer);
#else
// Characters use their own shadow-aware shaders
if (player) player->drawWithShadow(renderer, lightFromCamera, shadowMap->getDepthTexture(), lightDirCamera);
for (auto& npc : npcs) npc->drawWithShadow(renderer, lightFromCamera, shadowMap->getDepthTexture(), lightDirCamera);
#endif
renderer.PopMatrix();
renderer.PopProjectionMatrix();
renderer.shaderManager.PopShader();
}
void Game::drawScene() {
glViewport(0, 0, Environment::width, Environment::height);
if (!loadingCompleted) {
@@ -462,7 +635,12 @@ namespace ZL
}
else
{
drawGame();
if (shadowMap) {
drawShadowDepthPass();
drawGameWithShadows();
} else {
drawGame();
}
drawUI();
}
CheckGlError();