mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-03 08:03:50 +00:00
Stabilize foliage shadows and smooth motion transitions
- keep shadow projection center fixed while moving to remove per-frame projection churn flicker - replace delayed post-move catch-up with immediate stop transition and idle smoothing - rework foliage shadow caster motion to use blended phase-shifted UV samples for continuous position transitions - reduce high-frequency foliage threshold popping by removing threshold warping path - sharpen terrain receive filtering with tuned 5-tap PCF weights/offset for more detailed shadows - raise shadow map resolution to 1536 and keep light-space texel snapping for stable sampling - set shadows enabled by default and lower global shadow strength from 0.65 to 0.62 - keep foliage animation speed consistent between moving and idle at 80%
This commit is contained in:
parent
1003b25ff4
commit
7717ab8d6b
8 changed files with 111 additions and 54 deletions
|
|
@ -52,8 +52,16 @@ float calcShadow() {
|
||||||
vec3 norm = normalize(Normal);
|
vec3 norm = normalize(Normal);
|
||||||
vec3 lightDir = normalize(-uLightDir);
|
vec3 lightDir = normalize(-uLightDir);
|
||||||
float bias = max(0.005 * (1.0 - dot(norm, lightDir)), 0.001);
|
float bias = max(0.005 * (1.0 - dot(norm, lightDir)), 0.001);
|
||||||
// Single hardware PCF tap — GL_LINEAR + compare mode gives 2×2 bilinear PCF for free
|
// 5-tap PCF tuned for slightly sharper detail while keeping stability.
|
||||||
float shadow = texture(uShadowMap, vec3(proj.xy, proj.z - bias));
|
vec2 texel = vec2(1.0 / 1536.0);
|
||||||
|
float ref = proj.z - bias;
|
||||||
|
vec2 off = texel * 0.7;
|
||||||
|
float shadow = 0.0;
|
||||||
|
shadow += texture(uShadowMap, vec3(proj.xy, ref)) * 0.55;
|
||||||
|
shadow += texture(uShadowMap, vec3(proj.xy + vec2(off.x, 0.0), ref)) * 0.1125;
|
||||||
|
shadow += texture(uShadowMap, vec3(proj.xy - vec2(off.x, 0.0), ref)) * 0.1125;
|
||||||
|
shadow += texture(uShadowMap, vec3(proj.xy + vec2(0.0, off.y), ref)) * 0.1125;
|
||||||
|
shadow += texture(uShadowMap, vec3(proj.xy - vec2(0.0, off.y), ref)) * 0.1125;
|
||||||
return mix(1.0, shadow, coverageFade);
|
return mix(1.0, shadow, coverageFade);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ struct M2ModelGPU {
|
||||||
bool isSmoke = false; // True for smoke models (UV scroll animation)
|
bool isSmoke = false; // True for smoke models (UV scroll animation)
|
||||||
bool isSpellEffect = false; // True for spell effect models (skip particle dampeners)
|
bool isSpellEffect = false; // True for spell effect models (skip particle dampeners)
|
||||||
bool disableAnimation = false; // Keep foliage/tree doodads visually stable
|
bool disableAnimation = false; // Keep foliage/tree doodads visually stable
|
||||||
|
bool shadowWindFoliage = false; // Apply wind sway in shadow pass for foliage/tree cards
|
||||||
bool hasTextureAnimation = false; // True if any batch has UV animation
|
bool hasTextureAnimation = false; // True if any batch has UV animation
|
||||||
|
|
||||||
// Particle emitter data (kept from M2Model)
|
// Particle emitter data (kept from M2Model)
|
||||||
|
|
|
||||||
|
|
@ -235,15 +235,15 @@ private:
|
||||||
void shutdownPostProcess();
|
void shutdownPostProcess();
|
||||||
|
|
||||||
// Shadow mapping
|
// Shadow mapping
|
||||||
static constexpr int SHADOW_MAP_SIZE = 1024;
|
static constexpr int SHADOW_MAP_SIZE = 1536;
|
||||||
uint32_t shadowFBO = 0;
|
uint32_t shadowFBO = 0;
|
||||||
uint32_t shadowDepthTex = 0;
|
uint32_t shadowDepthTex = 0;
|
||||||
uint32_t shadowShaderProgram = 0;
|
uint32_t shadowShaderProgram = 0;
|
||||||
glm::mat4 lightSpaceMatrix = glm::mat4(1.0f);
|
glm::mat4 lightSpaceMatrix = glm::mat4(1.0f);
|
||||||
glm::vec3 shadowCenter = glm::vec3(0.0f);
|
glm::vec3 shadowCenter = glm::vec3(0.0f);
|
||||||
bool shadowCenterInitialized = false;
|
bool shadowCenterInitialized = false;
|
||||||
bool shadowsEnabled = false;
|
bool shadowsEnabled = true;
|
||||||
int shadowFrameCounter_ = 0; // throttle: only re-render depth map every 2 frames
|
int shadowPostMoveFrames_ = 0; // transition marker for movement->idle shadow recenter
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void setShadowsEnabled(bool enabled) { shadowsEnabled = enabled; }
|
void setShadowsEnabled(bool enabled) { shadowsEnabled = enabled; }
|
||||||
|
|
|
||||||
|
|
@ -1415,7 +1415,7 @@ void CharacterRenderer::render(const Camera& camera, const glm::mat4& view, cons
|
||||||
|
|
||||||
// Shadows
|
// Shadows
|
||||||
characterShader->setUniform("uShadowEnabled", shadowEnabled ? 1 : 0);
|
characterShader->setUniform("uShadowEnabled", shadowEnabled ? 1 : 0);
|
||||||
characterShader->setUniform("uShadowStrength", 0.65f);
|
characterShader->setUniform("uShadowStrength", 0.62f);
|
||||||
characterShader->setUniform("uTexture0", 0);
|
characterShader->setUniform("uTexture0", 0);
|
||||||
characterShader->setUniform("uAlphaTest", 0);
|
characterShader->setUniform("uAlphaTest", 0);
|
||||||
characterShader->setUniform("uColorKeyBlack", 0);
|
characterShader->setUniform("uColorKeyBlack", 0);
|
||||||
|
|
|
||||||
|
|
@ -1050,6 +1050,7 @@ bool M2Renderer::loadModel(const pipeline::M2Model& model, uint32_t modelId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gpuModel.disableAnimation = foliageOrTreeLike || chestName;
|
gpuModel.disableAnimation = foliageOrTreeLike || chestName;
|
||||||
|
gpuModel.shadowWindFoliage = foliageOrTreeLike;
|
||||||
gpuModel.isGroundDetail = groundDetailModel;
|
gpuModel.isGroundDetail = groundDetailModel;
|
||||||
if (groundDetailModel) {
|
if (groundDetailModel) {
|
||||||
// Ground clutter (grass/pebbles/detail cards) should never block camera/movement.
|
// Ground clutter (grass/pebbles/detail cards) should never block camera/movement.
|
||||||
|
|
@ -1871,7 +1872,7 @@ void M2Renderer::render(const Camera& camera, const glm::mat4& view, const glm::
|
||||||
shader->setUniform("uFogEnd", fogEnd);
|
shader->setUniform("uFogEnd", fogEnd);
|
||||||
bool useShadows = shadowEnabled;
|
bool useShadows = shadowEnabled;
|
||||||
shader->setUniform("uShadowEnabled", useShadows ? 1 : 0);
|
shader->setUniform("uShadowEnabled", useShadows ? 1 : 0);
|
||||||
shader->setUniform("uShadowStrength", 0.65f);
|
shader->setUniform("uShadowStrength", 0.62f);
|
||||||
if (useShadows) {
|
if (useShadows) {
|
||||||
shader->setUniform("uLightSpaceMatrix", lightSpaceMatrix);
|
shader->setUniform("uLightSpaceMatrix", lightSpaceMatrix);
|
||||||
glActiveTexture(GL_TEXTURE7);
|
glActiveTexture(GL_TEXTURE7);
|
||||||
|
|
@ -2357,14 +2358,14 @@ void M2Renderer::renderShadow(GLuint shadowShaderProgram, const glm::vec3& shado
|
||||||
GLint useTexLoc = glGetUniformLocation(shadowShaderProgram, "uUseTexture");
|
GLint useTexLoc = glGetUniformLocation(shadowShaderProgram, "uUseTexture");
|
||||||
GLint texLoc = glGetUniformLocation(shadowShaderProgram, "uTexture");
|
GLint texLoc = glGetUniformLocation(shadowShaderProgram, "uTexture");
|
||||||
GLint alphaTestLoc = glGetUniformLocation(shadowShaderProgram, "uAlphaTest");
|
GLint alphaTestLoc = glGetUniformLocation(shadowShaderProgram, "uAlphaTest");
|
||||||
GLint opacityLoc = glGetUniformLocation(shadowShaderProgram, "uShadowOpacity");
|
GLint foliageSwayLoc = glGetUniformLocation(shadowShaderProgram, "uFoliageSway");
|
||||||
if (modelLoc < 0) {
|
if (modelLoc < 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useTexLoc >= 0) glUniform1i(useTexLoc, 0);
|
if (useTexLoc >= 0) glUniform1i(useTexLoc, 0);
|
||||||
if (alphaTestLoc >= 0) glUniform1i(alphaTestLoc, 0);
|
if (alphaTestLoc >= 0) glUniform1i(alphaTestLoc, 0);
|
||||||
if (opacityLoc >= 0) glUniform1f(opacityLoc, 1.0f);
|
if (foliageSwayLoc >= 0) glUniform1i(foliageSwayLoc, 0);
|
||||||
if (texLoc >= 0) glUniform1i(texLoc, 0);
|
if (texLoc >= 0) glUniform1i(texLoc, 0);
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
|
@ -2388,13 +2389,11 @@ void M2Renderer::renderShadow(GLuint shadowShaderProgram, const glm::vec3& shado
|
||||||
if (batch.indexCount == 0) continue;
|
if (batch.indexCount == 0) continue;
|
||||||
bool useTexture = (batch.texture != 0);
|
bool useTexture = (batch.texture != 0);
|
||||||
bool alphaCutout = batch.hasAlpha;
|
bool alphaCutout = batch.hasAlpha;
|
||||||
|
bool foliageSway = model.shadowWindFoliage && alphaCutout;
|
||||||
// Foliage/leaf cutout batches cast softer shadows than opaque trunk geometry.
|
|
||||||
float shadowOpacity = alphaCutout ? 0.55f : 1.0f;
|
|
||||||
|
|
||||||
if (useTexLoc >= 0) glUniform1i(useTexLoc, useTexture ? 1 : 0);
|
if (useTexLoc >= 0) glUniform1i(useTexLoc, useTexture ? 1 : 0);
|
||||||
if (alphaTestLoc >= 0) glUniform1i(alphaTestLoc, alphaCutout ? 1 : 0);
|
if (alphaTestLoc >= 0) glUniform1i(alphaTestLoc, alphaCutout ? 1 : 0);
|
||||||
if (opacityLoc >= 0) glUniform1f(opacityLoc, shadowOpacity);
|
if (foliageSwayLoc >= 0) glUniform1i(foliageSwayLoc, foliageSway ? 1 : 0);
|
||||||
if (useTexture) {
|
if (useTexture) {
|
||||||
glBindTexture(GL_TEXTURE_2D, batch.texture);
|
glBindTexture(GL_TEXTURE_2D, batch.texture);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2661,11 +2661,9 @@ void Renderer::renderWorld(game::World* world, game::GameHandler* gameHandler) {
|
||||||
lastWMORenderMs = 0.0;
|
lastWMORenderMs = 0.0;
|
||||||
lastM2RenderMs = 0.0;
|
lastM2RenderMs = 0.0;
|
||||||
|
|
||||||
// Shadow pass (before main scene) — throttled to every 2 frames (depth buffer persists)
|
// Shadow pass (before main scene) — update every frame to avoid temporal popping.
|
||||||
if (shadowsEnabled && shadowFBO && shadowShaderProgram && terrainLoaded) {
|
if (shadowsEnabled && shadowFBO && shadowShaderProgram && terrainLoaded) {
|
||||||
if (shadowFrameCounter_++ % 2 == 0) {
|
|
||||||
renderShadowPass();
|
renderShadowPass();
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Clear shadow maps when disabled
|
// Clear shadow maps when disabled
|
||||||
if (terrainRenderer) terrainRenderer->clearShadowMap();
|
if (terrainRenderer) terrainRenderer->clearShadowMap();
|
||||||
|
|
@ -3495,6 +3493,7 @@ uint32_t Renderer::compileShadowShader() {
|
||||||
uniform bool uUseBones;
|
uniform bool uUseBones;
|
||||||
uniform mat4 uBones[200];
|
uniform mat4 uBones[200];
|
||||||
out vec2 vTexCoord;
|
out vec2 vTexCoord;
|
||||||
|
out vec3 vWorldPos;
|
||||||
void main() {
|
void main() {
|
||||||
vec3 pos = aPos;
|
vec3 pos = aPos;
|
||||||
if (uUseBones) {
|
if (uUseBones) {
|
||||||
|
|
@ -3506,36 +3505,46 @@ uint32_t Renderer::compileShadowShader() {
|
||||||
pos = vec3(boneTransform * vec4(aPos, 1.0));
|
pos = vec3(boneTransform * vec4(aPos, 1.0));
|
||||||
}
|
}
|
||||||
vTexCoord = aTexCoord;
|
vTexCoord = aTexCoord;
|
||||||
gl_Position = uLightSpaceMatrix * uModel * vec4(pos, 1.0);
|
vec4 worldPos = uModel * vec4(pos, 1.0);
|
||||||
|
vWorldPos = worldPos.xyz;
|
||||||
|
gl_Position = uLightSpaceMatrix * worldPos;
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
const char* fragSrc = R"(
|
const char* fragSrc = R"(
|
||||||
#version 330 core
|
#version 330 core
|
||||||
in vec2 vTexCoord;
|
in vec2 vTexCoord;
|
||||||
|
in vec3 vWorldPos;
|
||||||
uniform bool uUseTexture;
|
uniform bool uUseTexture;
|
||||||
uniform sampler2D uTexture;
|
uniform sampler2D uTexture;
|
||||||
uniform bool uAlphaTest;
|
uniform bool uAlphaTest;
|
||||||
uniform float uShadowOpacity;
|
uniform bool uFoliageSway;
|
||||||
|
uniform float uWindTime;
|
||||||
float hash12(vec2 p) {
|
uniform float uFoliageMotionDamp;
|
||||||
vec3 p3 = fract(vec3(p.xyx) * 0.1031);
|
|
||||||
p3 += dot(p3, p3.yzx + 33.33);
|
|
||||||
return fract((p3.x + p3.y) * p3.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
float opacity = clamp(uShadowOpacity, 0.0, 1.0);
|
|
||||||
if (uUseTexture) {
|
if (uUseTexture) {
|
||||||
vec4 tex = texture(uTexture, vTexCoord);
|
vec2 uv = vTexCoord;
|
||||||
if (uAlphaTest && tex.a < 0.5) discard;
|
vec2 uv2 = vTexCoord;
|
||||||
opacity *= tex.a;
|
if (uFoliageSway && uAlphaTest) {
|
||||||
}
|
// Slow, coherent wind-driven sway for foliage shadow cutouts.
|
||||||
|
float gust = sin(uWindTime * 0.32 + vWorldPos.x * 0.05 + vWorldPos.y * 0.04);
|
||||||
|
float flutter = sin(uWindTime * 0.55 + vWorldPos.y * 0.09 + vWorldPos.z * 0.18);
|
||||||
|
float damp = clamp(uFoliageMotionDamp, 0.2, 1.0);
|
||||||
|
uv += vec2(gust * 0.0040 * damp, flutter * 0.0022 * damp);
|
||||||
|
|
||||||
// Stochastic alpha for soft/translucent shadow casters (foliage).
|
// Second, phase-shifted sample gives smooth position-to-position
|
||||||
// Use UV-space hash so pattern stays stable with camera movement.
|
// transitions (less on/off popping during motion).
|
||||||
if (opacity < 0.999) {
|
float gust2 = sin(uWindTime * 0.32 + 1.57 + vWorldPos.x * 0.05 + vWorldPos.y * 0.04);
|
||||||
float d = hash12(floor(vTexCoord * 4096.0));
|
float flutter2 = sin(uWindTime * 0.55 + 2.17 + vWorldPos.y * 0.09 + vWorldPos.z * 0.18);
|
||||||
if (d > opacity) discard;
|
uv2 += vec2(gust2 * 0.0040 * damp, flutter2 * 0.0022 * damp);
|
||||||
|
}
|
||||||
|
// Force base mip for alpha-cutout casters to avoid temporal
|
||||||
|
// shadow holes from mip-level transitions on thin foliage cards.
|
||||||
|
vec4 tex = textureLod(uTexture, uv, 0.0);
|
||||||
|
vec4 tex2 = textureLod(uTexture, uv2, 0.0);
|
||||||
|
float alphaCut = 0.5;
|
||||||
|
float alphaVal = (tex.a + tex2.a) * 0.5;
|
||||||
|
if (uAlphaTest && alphaVal < alphaCut) discard;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
|
@ -3590,29 +3599,52 @@ glm::mat4 Renderer::computeLightSpaceMatrix() {
|
||||||
constexpr float kShadowNearPlane = 1.0f;
|
constexpr float kShadowNearPlane = 1.0f;
|
||||||
constexpr float kShadowFarPlane = 600.0f;
|
constexpr float kShadowFarPlane = 600.0f;
|
||||||
|
|
||||||
// Sun direction matching WMO light dir
|
// Fixed sun direction matching current world lighting setup.
|
||||||
glm::vec3 sunDir = glm::normalize(glm::vec3(-0.3f, -0.7f, -0.6f));
|
glm::vec3 sunDir = glm::normalize(glm::vec3(-0.3f, -0.7f, -0.6f));
|
||||||
|
|
||||||
// Keep a stable shadow focus center and only recentre occasionally.
|
// Keep a stable shadow focus center and move it smoothly toward the player
|
||||||
|
// to avoid visible shadow "state jumps" during movement.
|
||||||
glm::vec3 desiredCenter = characterPosition;
|
glm::vec3 desiredCenter = characterPosition;
|
||||||
if (!shadowCenterInitialized) {
|
if (!shadowCenterInitialized) {
|
||||||
shadowCenter = desiredCenter;
|
shadowCenter = desiredCenter;
|
||||||
shadowCenterInitialized = true;
|
shadowCenterInitialized = true;
|
||||||
} else {
|
} else {
|
||||||
constexpr float recenterThreshold = 30.0f; // world units
|
const bool movingNow = cameraController && cameraController->isMoving();
|
||||||
if (std::abs(desiredCenter.x - shadowCenter.x) > recenterThreshold ||
|
if (movingNow) {
|
||||||
std::abs(desiredCenter.y - shadowCenter.y) > recenterThreshold) {
|
// Hold projection center fixed while moving to eliminate
|
||||||
shadowCenter.x = desiredCenter.x;
|
// frame-to-frame surface flicker from projection churn.
|
||||||
shadowCenter.y = desiredCenter.y;
|
shadowPostMoveFrames_ = 1; // transition marker: was moving last frame
|
||||||
|
} else {
|
||||||
|
if (shadowPostMoveFrames_ == 1) {
|
||||||
|
// First frame after movement: snap once so there's no delayed catch-up.
|
||||||
|
shadowCenter = desiredCenter;
|
||||||
|
} else {
|
||||||
|
// Normal idle smoothing.
|
||||||
|
constexpr float kCenterLerp = 0.12f;
|
||||||
|
constexpr float kMaxHorizontalStep = 1.5f;
|
||||||
|
constexpr float kMaxVerticalStep = 0.6f;
|
||||||
|
|
||||||
|
glm::vec2 deltaXY(desiredCenter.x - shadowCenter.x, desiredCenter.y - shadowCenter.y);
|
||||||
|
float distXY = glm::length(deltaXY);
|
||||||
|
if (distXY > 0.001f) {
|
||||||
|
float step = std::min(distXY * kCenterLerp, kMaxHorizontalStep);
|
||||||
|
glm::vec2 move = (deltaXY / distXY) * step;
|
||||||
|
shadowCenter.x += move.x;
|
||||||
|
shadowCenter.y += move.y;
|
||||||
}
|
}
|
||||||
// Avoid vertical jitter from tiny terrain/camera height changes.
|
|
||||||
if (std::abs(desiredCenter.z - shadowCenter.z) > 4.0f) {
|
float deltaZ = desiredCenter.z - shadowCenter.z;
|
||||||
shadowCenter.z = desiredCenter.z;
|
if (std::abs(deltaZ) > 0.001f) {
|
||||||
|
float stepZ = std::clamp(deltaZ * kCenterLerp, -kMaxVerticalStep, kMaxVerticalStep);
|
||||||
|
shadowCenter.z += stepZ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shadowPostMoveFrames_ = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
glm::vec3 center = shadowCenter;
|
glm::vec3 center = shadowCenter;
|
||||||
|
|
||||||
// Texel snapping: round center to shadow texel boundaries to prevent shimmer
|
// Snap to shadow texel grid to keep projection stable while moving.
|
||||||
float halfExtent = kShadowHalfExtent;
|
float halfExtent = kShadowHalfExtent;
|
||||||
float texelWorld = (2.0f * halfExtent) / static_cast<float>(SHADOW_MAP_SIZE);
|
float texelWorld = (2.0f * halfExtent) / static_cast<float>(SHADOW_MAP_SIZE);
|
||||||
|
|
||||||
|
|
@ -3624,16 +3656,15 @@ glm::mat4 Renderer::computeLightSpaceMatrix() {
|
||||||
}
|
}
|
||||||
glm::mat4 lightView = glm::lookAt(center - sunDir * kShadowLightDistance, center, up);
|
glm::mat4 lightView = glm::lookAt(center - sunDir * kShadowLightDistance, center, up);
|
||||||
|
|
||||||
// Snap center in light space to texel grid
|
// Stable texel snapping in light space removes movement shimmer.
|
||||||
glm::vec4 centerLS = lightView * glm::vec4(center, 1.0f);
|
glm::vec4 centerLS = lightView * glm::vec4(center, 1.0f);
|
||||||
centerLS.x = std::round(centerLS.x / texelWorld) * texelWorld;
|
centerLS.x = std::round(centerLS.x / texelWorld) * texelWorld;
|
||||||
centerLS.y = std::round(centerLS.y / texelWorld) * texelWorld;
|
centerLS.y = std::round(centerLS.y / texelWorld) * texelWorld;
|
||||||
glm::vec4 snappedCenter = glm::inverse(lightView) * centerLS;
|
glm::vec4 snappedCenter = glm::inverse(lightView) * centerLS;
|
||||||
center = glm::vec3(snappedCenter);
|
center = glm::vec3(snappedCenter);
|
||||||
shadowCenter = center;
|
shadowCenter = center;
|
||||||
|
|
||||||
// Rebuild with snapped center
|
|
||||||
lightView = glm::lookAt(center - sunDir * kShadowLightDistance, center, up);
|
lightView = glm::lookAt(center - sunDir * kShadowLightDistance, center, up);
|
||||||
|
|
||||||
glm::mat4 lightProj = glm::ortho(-halfExtent, halfExtent, -halfExtent, halfExtent,
|
glm::mat4 lightProj = glm::ortho(-halfExtent, halfExtent, -halfExtent, halfExtent,
|
||||||
kShadowNearPlane, kShadowFarPlane);
|
kShadowNearPlane, kShadowFarPlane);
|
||||||
|
|
||||||
|
|
@ -3667,13 +3698,31 @@ void Renderer::renderShadowPass() {
|
||||||
GLint useTexLoc = glGetUniformLocation(shadowShaderProgram, "uUseTexture");
|
GLint useTexLoc = glGetUniformLocation(shadowShaderProgram, "uUseTexture");
|
||||||
GLint texLoc = glGetUniformLocation(shadowShaderProgram, "uTexture");
|
GLint texLoc = glGetUniformLocation(shadowShaderProgram, "uTexture");
|
||||||
GLint alphaTestLoc = glGetUniformLocation(shadowShaderProgram, "uAlphaTest");
|
GLint alphaTestLoc = glGetUniformLocation(shadowShaderProgram, "uAlphaTest");
|
||||||
GLint opacityLoc = glGetUniformLocation(shadowShaderProgram, "uShadowOpacity");
|
|
||||||
GLint useBonesLoc = glGetUniformLocation(shadowShaderProgram, "uUseBones");
|
GLint useBonesLoc = glGetUniformLocation(shadowShaderProgram, "uUseBones");
|
||||||
|
GLint foliageSwayLoc = glGetUniformLocation(shadowShaderProgram, "uFoliageSway");
|
||||||
|
GLint windTimeLoc = glGetUniformLocation(shadowShaderProgram, "uWindTime");
|
||||||
|
GLint foliageDampLoc = glGetUniformLocation(shadowShaderProgram, "uFoliageMotionDamp");
|
||||||
if (useTexLoc >= 0) glUniform1i(useTexLoc, 0);
|
if (useTexLoc >= 0) glUniform1i(useTexLoc, 0);
|
||||||
if (alphaTestLoc >= 0) glUniform1i(alphaTestLoc, 0);
|
if (alphaTestLoc >= 0) glUniform1i(alphaTestLoc, 0);
|
||||||
if (opacityLoc >= 0) glUniform1f(opacityLoc, 1.0f);
|
|
||||||
if (useBonesLoc >= 0) glUniform1i(useBonesLoc, 0);
|
if (useBonesLoc >= 0) glUniform1i(useBonesLoc, 0);
|
||||||
if (texLoc >= 0) glUniform1i(texLoc, 0);
|
if (texLoc >= 0) glUniform1i(texLoc, 0);
|
||||||
|
if (foliageSwayLoc >= 0) glUniform1i(foliageSwayLoc, 0);
|
||||||
|
if (foliageDampLoc >= 0) glUniform1f(foliageDampLoc, 1.0f);
|
||||||
|
if (windTimeLoc >= 0) {
|
||||||
|
const auto now = std::chrono::steady_clock::now();
|
||||||
|
static auto prev = now;
|
||||||
|
static float windPhaseSec = 0.0f;
|
||||||
|
float dt = std::chrono::duration<float>(now - prev).count();
|
||||||
|
prev = now;
|
||||||
|
dt = std::clamp(dt, 0.0f, 0.1f);
|
||||||
|
// Match moving and idle foliage evolution speed at 80% of original.
|
||||||
|
float phaseRate = 0.8f;
|
||||||
|
windPhaseSec += dt * phaseRate;
|
||||||
|
glUniform1f(windTimeLoc, windPhaseSec);
|
||||||
|
if (foliageDampLoc >= 0) {
|
||||||
|
glUniform1f(foliageDampLoc, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Render terrain into shadow map (only chunks within shadow frustum)
|
// Render terrain into shadow map (only chunks within shadow frustum)
|
||||||
if (terrainRenderer) {
|
if (terrainRenderer) {
|
||||||
|
|
|
||||||
|
|
@ -457,7 +457,7 @@ void TerrainRenderer::render(const Camera& camera) {
|
||||||
|
|
||||||
// Shadow map
|
// Shadow map
|
||||||
shader->setUniform("uShadowEnabled", shadowEnabled ? 1 : 0);
|
shader->setUniform("uShadowEnabled", shadowEnabled ? 1 : 0);
|
||||||
shader->setUniform("uShadowStrength", 0.65f);
|
shader->setUniform("uShadowStrength", 0.62f);
|
||||||
if (shadowEnabled) {
|
if (shadowEnabled) {
|
||||||
shader->setUniform("uLightSpaceMatrix", lightSpaceMatrix);
|
shader->setUniform("uLightSpaceMatrix", lightSpaceMatrix);
|
||||||
glActiveTexture(GL_TEXTURE7);
|
glActiveTexture(GL_TEXTURE7);
|
||||||
|
|
|
||||||
|
|
@ -1038,7 +1038,7 @@ void WMORenderer::render(const Camera& camera, const glm::mat4& view, const glm:
|
||||||
shader->setUniform("uFogStart", fogStart);
|
shader->setUniform("uFogStart", fogStart);
|
||||||
shader->setUniform("uFogEnd", fogEnd);
|
shader->setUniform("uFogEnd", fogEnd);
|
||||||
shader->setUniform("uShadowEnabled", shadowEnabled ? 1 : 0);
|
shader->setUniform("uShadowEnabled", shadowEnabled ? 1 : 0);
|
||||||
shader->setUniform("uShadowStrength", 0.65f);
|
shader->setUniform("uShadowStrength", 0.62f);
|
||||||
if (shadowEnabled) {
|
if (shadowEnabled) {
|
||||||
shader->setUniform("uLightSpaceMatrix", lightSpaceMatrix);
|
shader->setUniform("uLightSpaceMatrix", lightSpaceMatrix);
|
||||||
glActiveTexture(GL_TEXTURE7);
|
glActiveTexture(GL_TEXTURE7);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue