Fixing lights and shadows

This commit is contained in:
Vladislav Khorev committed 2026-06-15 21:25:54 +03:00
1 parent 9f4d60036d
commit bba493ee7c
18 files changed
+308 -126

No files matched your search

+53 -10
View File
@@ -903,7 +903,13 @@ void Character::drawGpuSkinningWithShadow(Renderer& renderer, const Eigen::Matri
// ==================== Night pass with point lights ====================
void Character::drawNight(Renderer& renderer, const float* pointLightPosEye, const float* pointLightDirEye, const float* pointLightColors, int pointLightCount, const float* ambientColor, const float* fogColor) {
void Character::drawNight(Renderer& renderer,
const float* pointLightPosEye, const float* pointLightDirEye,
const float* pointLightColors, int pointLightCount,
const float* pointLightWorldXZ, const float* pointLightLimitXZ,
const Eigen::Matrix4f& cameraViewInverse,
const float* ambientColor, const float* fogColor)
{
if (!enabled) return;
if (hitSparkEmitter.isConfigured() && hitSparkEmitter.getActiveParticleCount() > 0) {
hitSparkEmitter.draw(renderer, 1.0f, Environment::width, Environment::height, false);
@@ -915,13 +921,19 @@ void Character::drawNight(Renderer& renderer, const float* pointLightPosEye, con
//if (!isPlayer && hp <= 0) return;
if (useGpuSkinning) {
drawNightGpuSkinning(renderer, pointLightPosEye, pointLightDirEye, pointLightColors, pointLightCount, ambientColor, fogColor);
drawNightGpuSkinning(renderer, pointLightPosEye, pointLightDirEye, pointLightColors, pointLightCount,
pointLightWorldXZ, pointLightLimitXZ, cameraViewInverse, ambientColor, fogColor);
} else {
drawNightCpu(renderer, pointLightPosEye, pointLightDirEye, pointLightColors, pointLightCount, ambientColor, fogColor);
drawNightCpu(renderer, pointLightPosEye, pointLightDirEye, pointLightColors, pointLightCount,
pointLightWorldXZ, pointLightLimitXZ, cameraViewInverse, ambientColor, fogColor);
}
}
void Character::drawNightGpuSkinning(Renderer& renderer, const float* plPosEye, const float* plDirEye, const float* plColors, int plCount, const float* ambientColor, const float* fogColor) {
void Character::drawNightGpuSkinning(Renderer& renderer,
const float* plPosEye, const float* plDirEye, const float* plColors, int plCount,
const float* plWorldXZ, const float* plLimitXZ, const Eigen::Matrix4f& cameraViewInverse,
const float* ambientColor, const float* fogColor)
{
AnimationState drawState = resolveActiveState();
auto it = animations.find(drawState);
if (it == animations.end()) return;
@@ -942,7 +954,10 @@ void Character::drawNightGpuSkinning(Renderer& renderer, const float* plPosEye,
renderer.RenderUniform3fvArray("uPointLightPos[0]", plCount, plPosEye);
renderer.RenderUniform3fvArray("uPointLightDir[0]", plCount, plDirEye);
renderer.RenderUniform3fvArray("uPointLightColor[0]", plCount, plColors);
renderer.RenderUniform2fvArray("uPointLightWorldXZ[0]", plCount, plWorldXZ);
renderer.RenderUniform2fvArray("uPointLightLimitXZ[0]", plCount, plLimitXZ);
}
renderer.RenderUniformMatrix4fv("uViewInverse", false, cameraViewInverse.data());
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
@@ -979,6 +994,8 @@ void Character::drawNightGpuSkinning(Renderer& renderer, const float* plPosEye,
renderer.RenderUniform3fvArray("uPointLightPos[0]", plCount, plPosEye);
renderer.RenderUniform3fvArray("uPointLightDir[0]", plCount, plDirEye);
renderer.RenderUniform3fvArray("uPointLightColor[0]", plCount, plColors);
renderer.RenderUniform2fvArray("uPointLightWorldXZ[0]", plCount, plWorldXZ);
renderer.RenderUniform2fvArray("uPointLightLimitXZ[0]", plCount, plLimitXZ);
}
drawAttachedWeapon(renderer);
renderer.shaderManager.PopShader();
@@ -987,7 +1004,11 @@ void Character::drawNightGpuSkinning(Renderer& renderer, const float* plPosEye,
renderer.shaderManager.PopShader();
}
void Character::drawNightCpu(Renderer& renderer, const float* plPosEye, const float* plDirEye, const float* plColors, int plCount, const float* ambientColor, const float* fogColor) {
void Character::drawNightCpu(Renderer& renderer,
const float* plPosEye, const float* plDirEye, const float* plColors, int plCount,
const float* plWorldXZ, const float* plLimitXZ, const Eigen::Matrix4f& cameraViewInverse,
const float* ambientColor, const float* fogColor)
{
AnimationState drawState = resolveActiveState();
auto it = animations.find(drawState);
if (it == animations.end()) return;
@@ -1005,6 +1026,8 @@ void Character::drawNightCpu(Renderer& renderer, const float* plPosEye, const fl
renderer.RenderUniform3fvArray("uPointLightPos[0]", plCount, plPosEye);
renderer.RenderUniform3fvArray("uPointLightDir[0]", plCount, plDirEye);
renderer.RenderUniform3fvArray("uPointLightColor[0]", plCount, plColors);
renderer.RenderUniform2fvArray("uPointLightWorldXZ[0]", plCount, plWorldXZ);
renderer.RenderUniform2fvArray("uPointLightLimitXZ[0]", plCount, plLimitXZ);
}
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
@@ -1042,7 +1065,10 @@ void Character::drawNightCpu(Renderer& renderer, const float* plPosEye, const fl
void Character::drawNightWithShadow(Renderer& renderer,
const float* plPosEye, const float* plDirEye, const float* plColors, int plCount,
const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const float* ambientColor, const float* fogColor)
const float* plWorldXZ, const float* plLimitXZ,
const Eigen::Matrix4f& cameraViewInverse,
const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex,
const float* ambientColor, const float* fogColor)
{
if (!enabled) return;
if (hitSparkEmitter.isConfigured() && hitSparkEmitter.getActiveParticleCount() > 0) {
@@ -1053,15 +1079,22 @@ void Character::drawNightWithShadow(Renderer& renderer,
//if (!isPlayer && hp <= 0) return;
if (useGpuSkinning) {
drawNightGpuSkinningWithShadow(renderer, plPosEye, plDirEye, plColors, plCount, lightFromCamera, shadowMapTex, ambientColor, fogColor);
drawNightGpuSkinningWithShadow(renderer, plPosEye, plDirEye, plColors, plCount,
plWorldXZ, plLimitXZ, cameraViewInverse,
lightFromCamera, shadowMapTex, ambientColor, fogColor);
} else {
drawNightCpuWithShadow(renderer, plPosEye, plDirEye, plColors, plCount, lightFromCamera, shadowMapTex, ambientColor, fogColor);
drawNightCpuWithShadow(renderer, plPosEye, plDirEye, plColors, plCount,
plWorldXZ, plLimitXZ, cameraViewInverse,
lightFromCamera, shadowMapTex, ambientColor, fogColor);
}
}
void Character::drawNightGpuSkinningWithShadow(Renderer& renderer,
const float* plPosEye, const float* plDirEye, const float* plColors, int plCount,
const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const float* ambientColor, const float* fogColor)
const float* plWorldXZ, const float* plLimitXZ,
const Eigen::Matrix4f& cameraViewInverse,
const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex,
const float* ambientColor, const float* fogColor)
{
AnimationState drawState = resolveActiveState();
auto it = animations.find(drawState);
@@ -1088,6 +1121,9 @@ void Character::drawNightGpuSkinningWithShadow(Renderer& renderer,
renderer.RenderUniform3fvArray("uPointLightDir[0]", plCount, plDirEye);
renderer.RenderUniform3fvArray("uPointLightColor[0]", plCount, plColors);
}
renderer.RenderUniform2fvArray("uPointLightWorldXZ[0]", plCount, plWorldXZ);
renderer.RenderUniform2fvArray("uPointLightLimitXZ[0]", plCount, plLimitXZ);
renderer.RenderUniformMatrix4fv("uViewInverse", false, cameraViewInverse.data());
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, shadowMapTex);
@@ -1133,6 +1169,8 @@ void Character::drawNightGpuSkinningWithShadow(Renderer& renderer,
renderer.RenderUniform3fvArray("uPointLightDir[0]", plCount, plDirEye);
renderer.RenderUniform3fvArray("uPointLightColor[0]", plCount, plColors);
}
renderer.RenderUniform2fvArray("uPointLightWorldXZ[0]", plCount, plWorldXZ);
renderer.RenderUniform2fvArray("uPointLightLimitXZ[0]", plCount, plLimitXZ);
drawAttachedWeapon(renderer);
renderer.shaderManager.PopShader();
@@ -1142,7 +1180,10 @@ void Character::drawNightGpuSkinningWithShadow(Renderer& renderer,
void Character::drawNightCpuWithShadow(Renderer& renderer,
const float* plPosEye, const float* plDirEye, const float* plColors, int plCount,
const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const float* ambientColor, const float* fogColor)
const float* plWorldXZ, const float* plLimitXZ,
const Eigen::Matrix4f& cameraViewInverse,
const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex,
const float* ambientColor, const float* fogColor)
{
AnimationState drawState = resolveActiveState();
auto it = animations.find(drawState);
@@ -1166,6 +1207,8 @@ void Character::drawNightCpuWithShadow(Renderer& renderer,
renderer.RenderUniform3fvArray("uPointLightDir[0]", plCount, plDirEye);
renderer.RenderUniform3fvArray("uPointLightColor[0]", plCount, plColors);
}
renderer.RenderUniform2fvArray("uPointLightWorldXZ[0]", plCount, plWorldXZ);
renderer.RenderUniform2fvArray("uPointLightLimitXZ[0]", plCount, plLimitXZ);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, shadowMapTex);
+20 -4
View File
@@ -51,10 +51,18 @@ public:
void draw(Renderer& renderer);
void drawShadowDepth(Renderer& renderer);
void drawWithShadow(Renderer& renderer, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera);
void drawNight(Renderer& renderer, const float* pointLightPosEye, const float* pointLightDirEye, const float* pointLightColors, int pointLightCount, const float* ambientColor, const float* fogColor);
void drawNight(Renderer& renderer,
const float* pointLightPosEye, const float* pointLightDirEye,
const float* pointLightColors, int pointLightCount,
const float* pointLightWorldXZ, const float* pointLightLimitXZ,
const Eigen::Matrix4f& cameraViewInverse,
const float* ambientColor, const float* fogColor);
void drawNightWithShadow(Renderer& renderer,
const float* plPosEye, const float* plDirEye, const float* plColors, int plCount,
const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const float* ambientColor, const float* fogColor);
const float* plWorldXZ, const float* plLimitXZ,
const Eigen::Matrix4f& cameraViewInverse,
const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex,
const float* ambientColor, const float* fogColor);
// Character-to-character collision (XZ-plane). Used by Location to keep
// player/NPCs from walking through each other.
@@ -217,14 +225,22 @@ private:
void drawGpuSkinningWithShadow(Renderer& renderer, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera);
void drawCpuWithShadow(Renderer& renderer, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera);
// Night: draw with spot-light shaders
void drawNightGpuSkinning(Renderer& renderer, const float* plPosEye, const float* plDirEye, const float* plColors, int plCount, const float* ambientColor, const float* fogColor);
void drawNightCpu(Renderer& renderer, const float* plPosEye, const float* plDirEye, const float* plColors, int plCount, const float* ambientColor, const float* fogColor);
void drawNightGpuSkinning(Renderer& renderer,
const float* plPosEye, const float* plDirEye, const float* plColors, int plCount,
const float* plWorldXZ, const float* plLimitXZ, const Eigen::Matrix4f& cameraViewInverse,
const float* ambientColor, const float* fogColor);
void drawNightCpu(Renderer& renderer,
const float* plPosEye, const float* plDirEye, const float* plColors, int plCount,
const float* plWorldXZ, const float* plLimitXZ, const Eigen::Matrix4f& cameraViewInverse,
const float* ambientColor, const float* fogColor);
// Night: draw with spot-light + shadow shaders
void drawNightGpuSkinningWithShadow(Renderer& renderer,
const float* plPosEye, const float* plDirEye, const float* plColors, int plCount,
const float* plWorldXZ, const float* plLimitXZ, const Eigen::Matrix4f& cameraViewInverse,
const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const float* ambientColor, const float* fogColor);
void drawNightCpuWithShadow(Renderer& renderer,
const float* plPosEye, const float* plDirEye, const float* plColors, int plCount,
const float* plWorldXZ, const float* plLimitXZ, const Eigen::Matrix4f& cameraViewInverse,
const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const float* ambientColor, const float* fogColor);
};
+1
View File
@@ -14,6 +14,7 @@
#include <android/log.h>
#endif
#ifdef EMSCRIPTEN
#include <emscripten.h>
#endif
+38 -9
View File
@@ -318,6 +318,10 @@ namespace ZL
pl.id = item.value("id", "");
pl.autoLight = item.value("autoLight", false);
pl.autoLightDistance = item.value("autoLightDistance", -1.0f);
pl.limitX = item.value("limitX", 99999.f);
pl.limitY = item.value("limitY", 99999.f);
pl.autoLightLimitX = item.value("autoLightLimitX", -1.0f);
pl.autoLightLimitY = item.value("autoLightLimitY", -1.0f);
pl.position = Eigen::Vector3f(
item.value("positionX", 0.0f),
item.value("positionY", 0.0f),
@@ -1005,10 +1009,18 @@ namespace ZL
for (int i = 0; i < static_cast<int>(pointLights.size()); ++i) {
const PointLight& pl = pointLights[i];
bool active = !pl.autoLight;
if (!active && i == nearestLightIdx) {
// autoLight: also check distance threshold if set
const float dist = player ? (pl.position - player->position).norm() : 0.0f;
active = (pl.autoLightDistance <= 0.0f || dist <= pl.autoLightDistance);
if (!active && player) {
if (pl.autoLightLimitX > 0.0f && pl.autoLightLimitY > 0.0f) {
// Rectangular activation zone — independent of nearest-light heuristic
const float dx = std::abs(player->position.x() - pl.position.x());
const float dz = std::abs(player->position.z() - pl.position.z());
active = (dx <= pl.autoLightLimitX && dz <= pl.autoLightLimitY);
} else {
// Legacy: only the nearest autoLight activates, with optional distance cap
const float dist = (pl.position - player->position).norm();
active = (i == nearestLightIdx) &&
(pl.autoLightDistance <= 0.0f || dist <= pl.autoLightDistance);
}
}
if (active) {
activeLightIndices.push_back(i);
@@ -1079,6 +1091,8 @@ namespace ZL
float plPosEye[MAX_POINT_LIGHTS * 3] = {};
float plDirEye[MAX_POINT_LIGHTS * 3] = {};
float plColors[MAX_POINT_LIGHTS * 3] = {};
float plWorldXZ[MAX_POINT_LIGHTS * 2] = {};
float plLimitXZ[MAX_POINT_LIGHTS * 2] = {};
const Eigen::Matrix3f camRot = cameraViewMatrix.block<3, 3>(0, 0);
const int lightCount = static_cast<int>(activeLightIndices.size());
for (int j = 0; j < lightCount; ++j) {
@@ -1095,12 +1109,19 @@ namespace ZL
plColors[j * 3 + 0] = pl.color.x();
plColors[j * 3 + 1] = pl.color.y();
plColors[j * 3 + 2] = pl.color.z();
plWorldXZ[j * 2 + 0] = pl.position.x();
plWorldXZ[j * 2 + 1] = pl.position.z();
plLimitXZ[j * 2 + 0] = pl.limitX;
plLimitXZ[j * 2 + 1] = pl.limitY;
}
// Compute camera view inverse (needed for shadow lookup and skinning world-pos recovery)
const Eigen::Matrix4f cameraViewInverse = cameraViewMatrix.inverse();
// Compute light-from-camera matrix for shadow lookup
Eigen::Matrix4f lightFromCamera = Eigen::Matrix4f::Identity();
if (hasShadows) {
lightFromCamera = shadowMap->getLightSpaceMatrix() * cameraViewMatrix.inverse();
lightFromCamera = shadowMap->getLightSpaceMatrix() * cameraViewInverse;
renderer.RenderUniformMatrix4fv("uLightFromCamera", false, lightFromCamera.data());
// Pass first active light's eye-space direction as uLightDir for shadow bias
renderer.RenderUniform3fv("uLightDir", plDirEye);
@@ -1111,6 +1132,8 @@ namespace ZL
renderer.RenderUniform3fvArray("uPointLightPos[0]", lightCount, plPosEye);
renderer.RenderUniform3fvArray("uPointLightDir[0]", lightCount, plDirEye);
renderer.RenderUniform3fvArray("uPointLightColor[0]", lightCount, plColors);
renderer.RenderUniform2fvArray("uPointLightWorldXZ[0]", lightCount, plWorldXZ);
renderer.RenderUniform2fvArray("uPointLightLimitXZ[0]", lightCount, plLimitXZ);
}
renderer.RenderUniform1f("uAlpha", 1.0f);
@@ -1132,11 +1155,17 @@ namespace ZL
for (auto& tz : teleportZones) tz.prepareForDraw(cameraViewMatrix);
if (hasShadows) {
if (player) player->drawNightWithShadow(renderer, plPosEye, plDirEye, plColors, lightCount, lightFromCamera, shadowMap->getDepthTexture(), ambientColor, fogColor);
for (auto& npc : npcs) npc->drawNightWithShadow(renderer, plPosEye, plDirEye, plColors, lightCount, lightFromCamera, shadowMap->getDepthTexture(), ambientColor, fogColor);
if (player) player->drawNightWithShadow(renderer, plPosEye, plDirEye, plColors, lightCount,
plWorldXZ, plLimitXZ, cameraViewInverse,
lightFromCamera, shadowMap->getDepthTexture(), ambientColor, fogColor);
for (auto& npc : npcs) npc->drawNightWithShadow(renderer, plPosEye, plDirEye, plColors, lightCount,
plWorldXZ, plLimitXZ, cameraViewInverse,
lightFromCamera, shadowMap->getDepthTexture(), ambientColor, fogColor);
} else {
if (player) player->drawNight(renderer, plPosEye, plDirEye, plColors, lightCount, ambientColor, fogColor);
for (auto& npc : npcs) npc->drawNight(renderer, plPosEye, plDirEye, plColors, lightCount, ambientColor, fogColor);
if (player) player->drawNight(renderer, plPosEye, plDirEye, plColors, lightCount,
plWorldXZ, plLimitXZ, cameraViewInverse, ambientColor, fogColor);
for (auto& npc : npcs) npc->drawNight(renderer, plPosEye, plDirEye, plColors, lightCount,
plWorldXZ, plLimitXZ, cameraViewInverse, ambientColor, fogColor);
}
for (auto& tz : teleportZones) tz.draw(renderer, Environment::zoom, Environment::width, Environment::height);
+5
View File
@@ -28,6 +28,11 @@ namespace ZL
Eigen::Vector3f color; // RGB, values > 1.0 increase intensity
bool autoLight = false; // if true, only activates when nearest light to player
float autoLightDistance = -1.0f; // max distance for autoLight activation; <=0 means unlimited
// Rectangular limits — keep light confined to a room-sized AABB centred on the light
float limitX = 99999.f; // shader fragment limit: half-width in world X
float limitY = 99999.f; // shader fragment limit: half-width in world Z
float autoLightLimitX = -1.0f; // activation rect half-width X; <0 = use legacy nearest-light logic
float autoLightLimitY = -1.0f; // activation rect half-width Z
};
struct TriggerZone
+20
View File
@@ -813,6 +813,26 @@ namespace ZL {
}
}
void Renderer::RenderUniform2fv(const std::string& uniformName, const float* value)
{
auto shader = shaderManager.GetCurrentShader();
auto uniform = shader->uniformList.find(uniformName);
if (uniform != shader->uniformList.end())
{
glUniform2fv(uniform->second, 1, value);
}
}
void Renderer::RenderUniform2fvArray(const std::string& uniformName, int count, const float* value)
{
auto shader = shaderManager.GetCurrentShader();
auto uniform = shader->uniformList.find(uniformName);
if (uniform != shader->uniformList.end())
{
glUniform2fv(uniform->second, count, value);
}
}
void Renderer::RenderUniform3fv(const std::string& uniformName, const float* value)
{
auto shader = shaderManager.GetCurrentShader();
+2
View File
@@ -134,6 +134,8 @@ namespace ZL {
void RenderUniformMatrix4fv(const std::string& uniformName, bool transpose, const float* value);
void RenderUniformMatrix4fvArray(const std::string& uniformName, int count, bool transpose, const float* value);
void RenderUniform1i(const std::string& uniformName, const int value);
void RenderUniform2fv(const std::string& uniformName, const float* value);
void RenderUniform2fvArray(const std::string& uniformName, int count, const float* value);
void RenderUniform3fv(const std::string& uniformName, const float* value);
void RenderUniform3fvArray(const std::string& uniformName, int count, const float* value);
void RenderUniform4fv(const std::string& uniformName, const float* value);