Working on the night mode

This commit is contained in:
Vladislav Khorev committed 2026-06-04 13:27:52 +03:00
1 parent e6bfe85e2e
commit 442d3a7945
18 files changed
+1060 -2

No files matched your search

+180
View File
@@ -9,6 +9,7 @@
#include <functional>
#include <memory>
#include <cfloat>
#include <limits>
#include "GameConstants.h"
#include "Character.h"
#include "external/nlohmann/json.hpp"
@@ -878,6 +879,185 @@ namespace ZL
}
}
void Location::drawNightShadowDepthPass(const PointLight& light)
{
if (!shadowMap) return;
static constexpr float kSpotFovY = static_cast<float>(M_PI) * 0.5f; // 90°
shadowMap->updateSpotlightMatrix(light.position, light.direction, kSpotFovY, 0.1f, 20.0f);
shadowMap->bind();
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glEnable(GL_CULL_FACE);
renderer.shaderManager.PushShader("shadow_depth");
renderer.PushPerspectiveProjectionMatrix(kSpotFovY, 1.0f, 0.1f, 20.0f);
renderer.PushSpecialMatrix(shadowMap->getLightViewMatrix());
for (auto& [name, gameObj] : gameObjects) {
renderer.DrawVertexRenderStruct(gameObj.mesh);
}
for (auto& intObj : interactiveObjects) {
if (intObj.isActive && intObj.loadedObject.texture) {
renderer.PushMatrix();
renderer.TranslateMatrix(intObj.position);
renderer.DrawVertexRenderStruct(intObj.loadedObject.mesh);
renderer.PopMatrix();
}
}
if (player) player->drawShadowDepth(renderer);
for (auto& npc : npcs) npc->drawShadowDepth(renderer);
renderer.PopMatrix(); // light view
renderer.PopProjectionMatrix();
renderer.shaderManager.PopShader();
glDisable(GL_CULL_FACE);
shadowMap->unbind();
}
void Location::drawGameNight()
{
// --- Find nearest spotlight for shadow casting ---
const PointLight* shadowLight = nullptr;
if (player && !pointLights.empty()) {
float minDist = FLT_MAX;
for (const auto& pl : pointLights) {
const float d = (pl.position - player->position).norm();
if (d < minDist) { minDist = d; shadowLight = &pl; }
}
}
const bool hasShadows = (shadowMap != nullptr && shadowLight != nullptr);
if (hasShadows) {
drawNightShadowDepthPass(*shadowLight);
}
// --- Main render pass ---
glClearColor(0.01f, 0.01f, 0.05f, 1.0f);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
const std::string mainShader = hasShadows ? "night_fog_shadow" : "night_fog";
renderer.shaderManager.PushShader(mainShader);
renderer.RenderUniform1i(textureUniformName, 0);
if (hasShadows) {
renderer.RenderUniform1i("uShadowMap", 1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, shadowMap->getDepthTexture());
glActiveTexture(GL_TEXTURE0);
}
const float playerEyePos[3] = { 0.0f, 0.0f, -Environment::zoom };
renderer.RenderUniform3fv("uPlayerEyePos", playerEyePos);
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() });
cameraViewMatrix = renderer.GetCurrentModelViewMatrix();
// Transform spot lights to eye space and build uniform arrays (max 4)
static constexpr int MAX_POINT_LIGHTS = 4;
float plPosEye[MAX_POINT_LIGHTS * 3] = {};
float plDirEye[MAX_POINT_LIGHTS * 3] = {};
float plColors[MAX_POINT_LIGHTS * 3] = {};
const Eigen::Matrix3f camRot = cameraViewMatrix.block<3, 3>(0, 0);
const int lightCount = min(static_cast<int>(pointLights.size()), MAX_POINT_LIGHTS);
for (int i = 0; i < lightCount; ++i) {
const Eigen::Vector4f worldPos(pointLights[i].position.x(), pointLights[i].position.y(), pointLights[i].position.z(), 1.0f);
const Eigen::Vector4f eyePos4 = cameraViewMatrix * worldPos;
plPosEye[i * 3 + 0] = eyePos4.x();
plPosEye[i * 3 + 1] = eyePos4.y();
plPosEye[i * 3 + 2] = eyePos4.z();
const Eigen::Vector3f eyeDir = camRot * pointLights[i].direction;
plDirEye[i * 3 + 0] = eyeDir.x();
plDirEye[i * 3 + 1] = eyeDir.y();
plDirEye[i * 3 + 2] = eyeDir.z();
plColors[i * 3 + 0] = pointLights[i].color.x();
plColors[i * 3 + 1] = pointLights[i].color.y();
plColors[i * 3 + 2] = pointLights[i].color.z();
}
// Compute light-from-camera matrix for shadow lookup
Eigen::Matrix4f lightFromCamera = Eigen::Matrix4f::Identity();
if (hasShadows) {
lightFromCamera = shadowMap->getLightSpaceMatrix() * cameraViewMatrix.inverse();
renderer.RenderUniformMatrix4fv("uLightFromCamera", false, lightFromCamera.data());
// Pass first light's eye-space direction as uLightDir for shadow bias
renderer.RenderUniform3fv("uLightDir", plDirEye);
}
renderer.RenderUniform1i("uPointLightCount", lightCount);
if (lightCount > 0) {
renderer.RenderUniform3fvArray("uPointLightPos[0]", lightCount, plPosEye);
renderer.RenderUniform3fvArray("uPointLightDir[0]", lightCount, plDirEye);
renderer.RenderUniform3fvArray("uPointLightColor[0]", lightCount, plColors);
}
renderer.RenderUniform1f("uAlpha", 1.0f);
for (auto& [name, gameObj] : gameObjects) {
if (!gameObj.texture) continue;
glBindTexture(GL_TEXTURE_2D, gameObj.texture->getTexID());
renderer.DrawVertexRenderStruct(gameObj.mesh);
}
for (auto& intObj : interactiveObjects) {
if (intObj.isActive) {
intObj.draw(renderer);
}
}
renderer.RenderUniform1f("uAlpha", 1.0f);
if (player) player->prepareHitSparksForDraw(cameraViewMatrix);
for (auto& npc : npcs) npc->prepareHitSparksForDraw(cameraViewMatrix);
for (auto& tz : teleportZones) tz.prepareForDraw(cameraViewMatrix);
if (hasShadows) {
if (player) player->drawNightWithShadow(renderer, plPosEye, plDirEye, plColors, lightCount, lightFromCamera, shadowMap->getDepthTexture());
for (auto& npc : npcs) npc->drawNightWithShadow(renderer, plPosEye, plDirEye, plColors, lightCount, lightFromCamera, shadowMap->getDepthTexture());
} else {
if (player) player->drawNight(renderer, plPosEye, plDirEye, plColors, lightCount);
for (auto& npc : npcs) npc->drawNight(renderer, plPosEye, plDirEye, plColors, lightCount);
}
for (auto& tz : teleportZones) tz.draw(renderer, Environment::zoom, Environment::width, Environment::height);
if (editorMode == EditorMode::Navigation) {
editor.drawNavigation();
editor.drawPoints();
}
if (editorMode == EditorMode::InteractiveObjects) {
editor.drawInteractiveObjectBounds();
}
renderer.PopMatrix();
renderer.PopProjectionMatrix();
renderer.shaderManager.PopShader();
if (npcNameText) {
Eigen::Matrix4f proj = MakePerspectiveMatrix(1.0f / 1.5f,
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
for (auto& npc : npcs) {
if (npc) npc->drawName(*npcNameText, cameraViewMatrix, proj);
}
if (player) player->drawHealthBar(renderer, cameraViewMatrix, proj);
for (auto& npc : npcs) {
if (npc) npc->drawHealthBar(renderer, cameraViewMatrix, proj);
}
}
}
bool Location::setNavigationAreaAvailable(const std::string& areaName, bool available)
{
if (!navigation) return false;