mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
Add centralized anisotropic filtering, fog, and Blinn-Phong specular to all renderers
Anisotropic filtering now queries GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT once and applies via a single applyAnisotropicFiltering() utility, replacing hardcoded calls across all renderers. Fog (sky horizon color, 100-600 range) and Blinn-Phong specular highlights are added to WMO, M2, and character shaders for visual parity with terrain. Shadow sampling plumbing (sampler2DShadow with 3x3 PCF) is wired into all three shaders gated by uShadowEnabled, ready for a future shadow map pass.
This commit is contained in:
parent
c9adcd3d96
commit
aeccddddeb
10 changed files with 280 additions and 8 deletions
|
|
@ -77,6 +77,15 @@ public:
|
|||
|
||||
size_t getInstanceCount() const { return instances.size(); }
|
||||
|
||||
void setFog(const glm::vec3& color, float start, float end) {
|
||||
fogColor = color; fogStart = start; fogEnd = end;
|
||||
}
|
||||
|
||||
void setShadowMap(GLuint depthTex, const glm::mat4& lightSpace) {
|
||||
shadowDepthTex = depthTex; lightSpaceMatrix = lightSpace; shadowEnabled = true;
|
||||
}
|
||||
void clearShadowMap() { shadowEnabled = false; }
|
||||
|
||||
private:
|
||||
// GPU representation of M2 model
|
||||
struct M2ModelGPU {
|
||||
|
|
@ -168,6 +177,16 @@ private:
|
|||
std::unique_ptr<Shader> characterShader;
|
||||
pipeline::AssetManager* assetManager = nullptr;
|
||||
|
||||
// Fog parameters
|
||||
glm::vec3 fogColor = glm::vec3(0.5f, 0.6f, 0.7f);
|
||||
float fogStart = 400.0f;
|
||||
float fogEnd = 1200.0f;
|
||||
|
||||
// Shadow mapping
|
||||
GLuint shadowDepthTex = 0;
|
||||
glm::mat4 lightSpaceMatrix = glm::mat4(1.0f);
|
||||
bool shadowEnabled = false;
|
||||
|
||||
// Texture cache
|
||||
std::unordered_map<std::string, GLuint> textureCache;
|
||||
GLuint whiteTexture = 0;
|
||||
|
|
|
|||
|
|
@ -224,6 +224,15 @@ public:
|
|||
uint32_t getTotalTriangleCount() const;
|
||||
uint32_t getDrawCallCount() const { return lastDrawCallCount; }
|
||||
|
||||
void setFog(const glm::vec3& color, float start, float end) {
|
||||
fogColor = color; fogStart = start; fogEnd = end;
|
||||
}
|
||||
|
||||
void setShadowMap(GLuint depthTex, const glm::mat4& lightSpace) {
|
||||
shadowDepthTex = depthTex; lightSpaceMatrix = lightSpace; shadowEnabled = true;
|
||||
}
|
||||
void clearShadowMap() { shadowEnabled = false; }
|
||||
|
||||
private:
|
||||
pipeline::AssetManager* assetManager = nullptr;
|
||||
std::unique_ptr<Shader> shader;
|
||||
|
|
@ -242,6 +251,16 @@ private:
|
|||
glm::vec3 lightDir = glm::vec3(0.5f, 0.5f, 1.0f);
|
||||
glm::vec3 ambientColor = glm::vec3(0.4f, 0.4f, 0.45f);
|
||||
|
||||
// Fog parameters
|
||||
glm::vec3 fogColor = glm::vec3(0.5f, 0.6f, 0.7f);
|
||||
float fogStart = 400.0f;
|
||||
float fogEnd = 1200.0f;
|
||||
|
||||
// Shadow mapping
|
||||
GLuint shadowDepthTex = 0;
|
||||
glm::mat4 lightSpaceMatrix = glm::mat4(1.0f);
|
||||
bool shadowEnabled = false;
|
||||
|
||||
// Optional query-space culling for collision/raycast hot paths.
|
||||
bool collisionFocusEnabled = false;
|
||||
glm::vec3 collisionFocusPos = glm::vec3(0.0f);
|
||||
|
|
|
|||
|
|
@ -27,5 +27,12 @@ private:
|
|||
int height = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply anisotropic filtering to the currently bound GL_TEXTURE_2D.
|
||||
* Queries the driver maximum once and caches it. No-op if the extension
|
||||
* is not available.
|
||||
*/
|
||||
void applyAnisotropicFiltering();
|
||||
|
||||
} // namespace rendering
|
||||
} // namespace wowee
|
||||
|
|
|
|||
|
|
@ -129,6 +129,20 @@ public:
|
|||
*/
|
||||
void setFrustumCulling(bool enabled) { frustumCulling = enabled; }
|
||||
|
||||
void setFog(const glm::vec3& color, float start, float end) {
|
||||
fogColor = color; fogStart = start; fogEnd = end;
|
||||
}
|
||||
|
||||
void setShadowMap(GLuint depthTex, const glm::mat4& lightSpace) {
|
||||
shadowDepthTex = depthTex; lightSpaceMatrix = lightSpace; shadowEnabled = true;
|
||||
}
|
||||
void clearShadowMap() { shadowEnabled = false; }
|
||||
|
||||
/**
|
||||
* Render depth-only for shadow casting (reuses VAOs)
|
||||
*/
|
||||
void renderShadow(const glm::mat4& lightView, const glm::mat4& lightProj, Shader& shadowShader);
|
||||
|
||||
/**
|
||||
* Get floor height at a GL position via ray-triangle intersection
|
||||
*/
|
||||
|
|
@ -308,6 +322,16 @@ private:
|
|||
bool frustumCulling = true;
|
||||
uint32_t lastDrawCalls = 0;
|
||||
|
||||
// Fog parameters
|
||||
glm::vec3 fogColor = glm::vec3(0.5f, 0.6f, 0.7f);
|
||||
float fogStart = 400.0f;
|
||||
float fogEnd = 1200.0f;
|
||||
|
||||
// Shadow mapping
|
||||
GLuint shadowDepthTex = 0;
|
||||
glm::mat4 lightSpaceMatrix = glm::mat4(1.0f);
|
||||
bool shadowEnabled = false;
|
||||
|
||||
// Optional query-space culling for collision/raycast hot paths.
|
||||
bool collisionFocusEnabled = false;
|
||||
glm::vec3 collisionFocusPos = glm::vec3(0.0f);
|
||||
|
|
|
|||
|
|
@ -92,15 +92,46 @@ bool CharacterRenderer::initialize() {
|
|||
uniform vec3 uLightDir;
|
||||
uniform vec3 uViewPos;
|
||||
|
||||
uniform vec3 uFogColor;
|
||||
uniform float uFogStart;
|
||||
uniform float uFogEnd;
|
||||
|
||||
uniform sampler2DShadow uShadowMap;
|
||||
uniform mat4 uLightSpaceMatrix;
|
||||
uniform int uShadowEnabled;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
void main() {
|
||||
vec3 normal = normalize(Normal);
|
||||
vec3 lightDir = normalize(uLightDir);
|
||||
|
||||
// Simple diffuse lighting
|
||||
// Diffuse lighting
|
||||
float diff = max(dot(normal, lightDir), 0.0);
|
||||
vec3 diffuse = diff * vec3(1.0);
|
||||
|
||||
// Blinn-Phong specular
|
||||
vec3 viewDir = normalize(uViewPos - FragPos);
|
||||
vec3 halfDir = normalize(lightDir + viewDir);
|
||||
float spec = pow(max(dot(normal, halfDir), 0.0), 32.0);
|
||||
vec3 specular = spec * vec3(0.2);
|
||||
|
||||
// Shadow mapping
|
||||
float shadow = 1.0;
|
||||
if (uShadowEnabled != 0) {
|
||||
vec4 lsPos = uLightSpaceMatrix * vec4(FragPos, 1.0);
|
||||
vec3 proj = lsPos.xyz / lsPos.w * 0.5 + 0.5;
|
||||
if (proj.z <= 1.0 && proj.x >= 0.0 && proj.x <= 1.0 && proj.y >= 0.0 && proj.y <= 1.0) {
|
||||
float bias = max(0.005 * (1.0 - abs(dot(normal, lightDir))), 0.001);
|
||||
shadow = 0.0;
|
||||
vec2 texelSize = vec2(1.0 / 2048.0);
|
||||
for (int sx = -1; sx <= 1; sx++) {
|
||||
for (int sy = -1; sy <= 1; sy++) {
|
||||
shadow += texture(uShadowMap, vec3(proj.xy + vec2(sx, sy) * texelSize, proj.z - bias));
|
||||
}
|
||||
}
|
||||
shadow /= 9.0;
|
||||
}
|
||||
}
|
||||
|
||||
// Ambient
|
||||
vec3 ambient = vec3(0.3);
|
||||
|
|
@ -109,7 +140,13 @@ bool CharacterRenderer::initialize() {
|
|||
vec4 texColor = texture(uTexture0, TexCoord);
|
||||
|
||||
// Combine
|
||||
vec3 result = (ambient + diffuse) * texColor.rgb;
|
||||
vec3 result = (ambient + (diff * vec3(1.0) + specular) * shadow) * texColor.rgb;
|
||||
|
||||
// Fog
|
||||
float fogDist = length(uViewPos - FragPos);
|
||||
float fogFactor = clamp((uFogEnd - fogDist) / (uFogEnd - uFogStart), 0.0, 1.0);
|
||||
result = mix(uFogColor, result, fogFactor);
|
||||
|
||||
FragColor = vec4(result, texColor.a);
|
||||
}
|
||||
)";
|
||||
|
|
@ -207,6 +244,7 @@ GLuint CharacterRenderer::loadTexture(const std::string& path) {
|
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
applyAnisotropicFiltering();
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
textureCache[path] = texId;
|
||||
|
|
@ -417,6 +455,7 @@ GLuint CharacterRenderer::compositeTextures(const std::vector<std::string>& laye
|
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
applyAnisotropicFiltering();
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
core::Logger::getInstance().info("Composite texture created: ", width, "x", height, " from ", layerPaths.size(), " layers");
|
||||
|
|
@ -542,6 +581,7 @@ GLuint CharacterRenderer::compositeWithRegions(const std::string& basePath,
|
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
applyAnisotropicFiltering();
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
core::Logger::getInstance().info("compositeWithRegions: created ", width, "x", height,
|
||||
|
|
@ -978,6 +1018,20 @@ void CharacterRenderer::render(const Camera& camera, const glm::mat4& view, cons
|
|||
characterShader->setUniform("uLightDir", glm::vec3(0.0f, -1.0f, 0.3f));
|
||||
characterShader->setUniform("uViewPos", camera.getPosition());
|
||||
|
||||
// Fog
|
||||
characterShader->setUniform("uFogColor", fogColor);
|
||||
characterShader->setUniform("uFogStart", fogStart);
|
||||
characterShader->setUniform("uFogEnd", fogEnd);
|
||||
|
||||
// Shadows
|
||||
characterShader->setUniform("uShadowEnabled", shadowEnabled ? 1 : 0);
|
||||
if (shadowEnabled) {
|
||||
characterShader->setUniform("uLightSpaceMatrix", lightSpaceMatrix);
|
||||
glActiveTexture(GL_TEXTURE7);
|
||||
glBindTexture(GL_TEXTURE_2D, shadowDepthTex);
|
||||
characterShader->setUniform("uShadowMap", 7);
|
||||
}
|
||||
|
||||
for (const auto& pair : instances) {
|
||||
const auto& instance = pair.second;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "rendering/m2_renderer.hpp"
|
||||
#include "rendering/texture.hpp"
|
||||
#include "rendering/shader.hpp"
|
||||
#include "rendering/camera.hpp"
|
||||
#include "rendering/frustum.hpp"
|
||||
|
|
@ -253,11 +254,20 @@ bool M2Renderer::initialize(pipeline::AssetManager* assets) {
|
|||
|
||||
uniform vec3 uLightDir;
|
||||
uniform vec3 uAmbientColor;
|
||||
uniform vec3 uViewPos;
|
||||
uniform sampler2D uTexture;
|
||||
uniform bool uHasTexture;
|
||||
uniform bool uAlphaTest;
|
||||
uniform float uFadeAlpha;
|
||||
|
||||
uniform vec3 uFogColor;
|
||||
uniform float uFogStart;
|
||||
uniform float uFogEnd;
|
||||
|
||||
uniform sampler2DShadow uShadowMap;
|
||||
uniform mat4 uLightSpaceMatrix;
|
||||
uniform bool uShadowEnabled;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
void main() {
|
||||
|
|
@ -285,10 +295,40 @@ bool M2Renderer::initialize(pipeline::AssetManager* assets) {
|
|||
// Two-sided lighting for foliage
|
||||
float diff = max(abs(dot(normal, lightDir)), 0.3);
|
||||
|
||||
// Blinn-Phong specular
|
||||
vec3 viewDir = normalize(uViewPos - FragPos);
|
||||
vec3 halfDir = normalize(lightDir + viewDir);
|
||||
float spec = pow(max(dot(normal, halfDir), 0.0), 32.0);
|
||||
vec3 specular = spec * vec3(0.1);
|
||||
|
||||
// Shadow mapping
|
||||
float shadow = 1.0;
|
||||
if (uShadowEnabled) {
|
||||
vec4 lsPos = uLightSpaceMatrix * vec4(FragPos, 1.0);
|
||||
vec3 proj = lsPos.xyz / lsPos.w * 0.5 + 0.5;
|
||||
if (proj.z <= 1.0 && proj.x >= 0.0 && proj.x <= 1.0 && proj.y >= 0.0 && proj.y <= 1.0) {
|
||||
float bias = max(0.005 * (1.0 - abs(dot(normal, lightDir))), 0.001);
|
||||
shadow = 0.0;
|
||||
vec2 texelSize = vec2(1.0 / 2048.0);
|
||||
for (int sx = -1; sx <= 1; sx++) {
|
||||
for (int sy = -1; sy <= 1; sy++) {
|
||||
shadow += texture(uShadowMap, vec3(proj.xy + vec2(sx, sy) * texelSize, proj.z - bias));
|
||||
}
|
||||
}
|
||||
shadow /= 9.0;
|
||||
}
|
||||
}
|
||||
|
||||
vec3 ambient = uAmbientColor * texColor.rgb;
|
||||
vec3 diffuse = diff * texColor.rgb;
|
||||
|
||||
vec3 result = ambient + diffuse;
|
||||
vec3 result = ambient + (diffuse + specular) * shadow;
|
||||
|
||||
// Fog
|
||||
float fogDist = length(uViewPos - FragPos);
|
||||
float fogFactor = clamp((uFogEnd - fogDist) / (uFogEnd - uFogStart), 0.0, 1.0);
|
||||
result = mix(uFogColor, result, fogFactor);
|
||||
|
||||
FragColor = vec4(result, finalAlpha);
|
||||
}
|
||||
)";
|
||||
|
|
@ -1051,8 +1091,6 @@ void M2Renderer::update(float deltaTime) {
|
|||
}
|
||||
|
||||
void M2Renderer::render(const Camera& camera, const glm::mat4& view, const glm::mat4& projection) {
|
||||
(void)camera; // unused for now
|
||||
|
||||
if (instances.empty() || !shader) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -1080,6 +1118,17 @@ void M2Renderer::render(const Camera& camera, const glm::mat4& view, const glm::
|
|||
shader->setUniform("uProjection", projection);
|
||||
shader->setUniform("uLightDir", lightDir);
|
||||
shader->setUniform("uAmbientColor", ambientColor);
|
||||
shader->setUniform("uViewPos", camera.getPosition());
|
||||
shader->setUniform("uFogColor", fogColor);
|
||||
shader->setUniform("uFogStart", fogStart);
|
||||
shader->setUniform("uFogEnd", fogEnd);
|
||||
shader->setUniform("uShadowEnabled", shadowEnabled ? 1 : 0);
|
||||
if (shadowEnabled) {
|
||||
shader->setUniform("uLightSpaceMatrix", lightSpaceMatrix);
|
||||
glActiveTexture(GL_TEXTURE7);
|
||||
glBindTexture(GL_TEXTURE_2D, shadowDepthTex);
|
||||
shader->setUniform("uShadowMap", 7);
|
||||
}
|
||||
|
||||
lastDrawCallCount = 0;
|
||||
|
||||
|
|
@ -1389,6 +1438,7 @@ GLuint M2Renderer::loadTexture(const std::string& path) {
|
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
applyAnisotropicFiltering();
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -921,6 +921,14 @@ void Renderer::renderWorld(game::World* world) {
|
|||
lensFlare->render(*camera, sunPosition, timeOfDay);
|
||||
}
|
||||
|
||||
// Update fog across all renderers based on time of day (match sky color)
|
||||
if (skybox) {
|
||||
glm::vec3 horizonColor = skybox->getHorizonColor(timeOfDay);
|
||||
if (wmoRenderer) wmoRenderer->setFog(horizonColor, 100.0f, 600.0f);
|
||||
if (m2Renderer) m2Renderer->setFog(horizonColor, 100.0f, 600.0f);
|
||||
if (characterRenderer) characterRenderer->setFog(horizonColor, 100.0f, 600.0f);
|
||||
}
|
||||
|
||||
// Render terrain if loaded and enabled
|
||||
if (terrainEnabled && terrainLoaded && terrainRenderer && camera) {
|
||||
// Check if camera/character is underwater for fog override
|
||||
|
|
@ -951,7 +959,6 @@ void Renderer::renderWorld(game::World* world) {
|
|||
}
|
||||
|
||||
if (skybox) {
|
||||
// Update terrain fog based on time of day (match sky color)
|
||||
glm::vec3 horizonColor = skybox->getHorizonColor(timeOfDay);
|
||||
float fogColorArray[3] = {horizonColor.r, horizonColor.g, horizonColor.b};
|
||||
terrainRenderer->setFog(fogColorArray, 400.0f, 1200.0f);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "rendering/terrain_renderer.hpp"
|
||||
#include "rendering/texture.hpp"
|
||||
#include "rendering/frustum.hpp"
|
||||
#include "pipeline/asset_manager.hpp"
|
||||
#include "pipeline/blp_loader.hpp"
|
||||
|
|
@ -239,6 +240,7 @@ GLuint TerrainRenderer::loadTexture(const std::string& path) {
|
|||
|
||||
// Generate mipmaps
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
applyAnisotropicFiltering();
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ bool Texture::loadFromMemory(const unsigned char* data, int w, int h, int channe
|
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
applyAnisotropicFiltering();
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
return true;
|
||||
|
|
@ -47,5 +48,22 @@ void Texture::unbind() const {
|
|||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
void applyAnisotropicFiltering() {
|
||||
static float maxAniso = -1.0f;
|
||||
if (maxAniso < 0.0f) {
|
||||
if (GLEW_EXT_texture_filter_anisotropic) {
|
||||
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAniso);
|
||||
if (maxAniso < 1.0f) maxAniso = 1.0f;
|
||||
} else {
|
||||
maxAniso = 0.0f; // Extension not available
|
||||
}
|
||||
}
|
||||
if (maxAniso > 0.0f) {
|
||||
float desired = 16.0f;
|
||||
float clamped = (desired < maxAniso) ? desired : maxAniso;
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, clamped);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rendering
|
||||
} // namespace wowee
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "rendering/wmo_renderer.hpp"
|
||||
#include "rendering/texture.hpp"
|
||||
#include "rendering/shader.hpp"
|
||||
#include "rendering/camera.hpp"
|
||||
#include "rendering/frustum.hpp"
|
||||
|
|
@ -79,6 +80,14 @@ bool WMORenderer::initialize(pipeline::AssetManager* assets) {
|
|||
uniform bool uHasTexture;
|
||||
uniform bool uAlphaTest;
|
||||
|
||||
uniform vec3 uFogColor;
|
||||
uniform float uFogStart;
|
||||
uniform float uFogEnd;
|
||||
|
||||
uniform sampler2DShadow uShadowMap;
|
||||
uniform mat4 uLightSpaceMatrix;
|
||||
uniform bool uShadowEnabled;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
void main() {
|
||||
|
|
@ -92,6 +101,12 @@ bool WMORenderer::initialize(pipeline::AssetManager* assets) {
|
|||
// Ambient
|
||||
vec3 ambient = uAmbientColor;
|
||||
|
||||
// Blinn-Phong specular
|
||||
vec3 viewDir = normalize(uViewPos - FragPos);
|
||||
vec3 halfDir = normalize(lightDir + viewDir);
|
||||
float spec = pow(max(dot(normal, halfDir), 0.0), 32.0);
|
||||
vec3 specular = spec * vec3(0.15);
|
||||
|
||||
// Sample texture or use vertex color
|
||||
vec4 texColor;
|
||||
if (uHasTexture) {
|
||||
|
|
@ -103,8 +118,32 @@ bool WMORenderer::initialize(pipeline::AssetManager* assets) {
|
|||
texColor = vec4(VertexColor.rgb, 1.0);
|
||||
}
|
||||
|
||||
// Shadow mapping
|
||||
float shadow = 1.0;
|
||||
if (uShadowEnabled) {
|
||||
vec4 lsPos = uLightSpaceMatrix * vec4(FragPos, 1.0);
|
||||
vec3 proj = lsPos.xyz / lsPos.w * 0.5 + 0.5;
|
||||
if (proj.z <= 1.0 && proj.x >= 0.0 && proj.x <= 1.0 && proj.y >= 0.0 && proj.y <= 1.0) {
|
||||
float bias = max(0.005 * (1.0 - dot(normal, lightDir)), 0.001);
|
||||
shadow = 0.0;
|
||||
vec2 texelSize = vec2(1.0 / 2048.0);
|
||||
for (int sx = -1; sx <= 1; sx++) {
|
||||
for (int sy = -1; sy <= 1; sy++) {
|
||||
shadow += texture(uShadowMap, vec3(proj.xy + vec2(sx, sy) * texelSize, proj.z - bias));
|
||||
}
|
||||
}
|
||||
shadow /= 9.0;
|
||||
}
|
||||
}
|
||||
|
||||
// Combine lighting with texture
|
||||
vec3 result = (ambient + diffuse) * texColor.rgb;
|
||||
vec3 result = (ambient + (diffuse + specular) * shadow) * texColor.rgb;
|
||||
|
||||
// Fog
|
||||
float fogDist = length(uViewPos - FragPos);
|
||||
float fogFactor = clamp((uFogEnd - fogDist) / (uFogEnd - uFogStart), 0.0, 1.0);
|
||||
result = mix(uFogColor, result, fogFactor);
|
||||
|
||||
FragColor = vec4(result, 1.0);
|
||||
}
|
||||
)";
|
||||
|
|
@ -452,6 +491,16 @@ void WMORenderer::render(const Camera& camera, const glm::mat4& view, const glm:
|
|||
shader->setUniform("uViewPos", camera.getPosition());
|
||||
shader->setUniform("uLightDir", glm::vec3(-0.3f, -0.7f, -0.6f)); // Default sun direction
|
||||
shader->setUniform("uAmbientColor", glm::vec3(0.4f, 0.4f, 0.5f));
|
||||
shader->setUniform("uFogColor", fogColor);
|
||||
shader->setUniform("uFogStart", fogStart);
|
||||
shader->setUniform("uFogEnd", fogEnd);
|
||||
shader->setUniform("uShadowEnabled", shadowEnabled ? 1 : 0);
|
||||
if (shadowEnabled) {
|
||||
shader->setUniform("uLightSpaceMatrix", lightSpaceMatrix);
|
||||
glActiveTexture(GL_TEXTURE7);
|
||||
glBindTexture(GL_TEXTURE_2D, shadowDepthTex);
|
||||
shader->setUniform("uShadowMap", 7);
|
||||
}
|
||||
|
||||
// Enable wireframe if requested
|
||||
if (wireframeMode) {
|
||||
|
|
@ -512,6 +561,28 @@ void WMORenderer::render(const Camera& camera, const glm::mat4& view, const glm:
|
|||
glEnable(GL_CULL_FACE);
|
||||
}
|
||||
|
||||
void WMORenderer::renderShadow(const glm::mat4& lightView, const glm::mat4& lightProj, Shader& shadowShader) {
|
||||
if (instances.empty()) return;
|
||||
Frustum frustum;
|
||||
frustum.extractFromMatrix(lightProj * lightView);
|
||||
for (const auto& instance : instances) {
|
||||
auto modelIt = loadedModels.find(instance.modelId);
|
||||
if (modelIt == loadedModels.end()) continue;
|
||||
if (frustumCulling) {
|
||||
glm::vec3 instMin = instance.worldBoundsMin - glm::vec3(0.5f);
|
||||
glm::vec3 instMax = instance.worldBoundsMax + glm::vec3(0.5f);
|
||||
if (!frustum.intersectsAABB(instMin, instMax)) continue;
|
||||
}
|
||||
const ModelData& model = modelIt->second;
|
||||
shadowShader.setUniform("uModel", instance.modelMatrix);
|
||||
for (const auto& group : model.groups) {
|
||||
glBindVertexArray(group.vao);
|
||||
glDrawElements(GL_TRIANGLES, group.indexCount, GL_UNSIGNED_SHORT, 0);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t WMORenderer::getTotalTriangleCount() const {
|
||||
uint32_t total = 0;
|
||||
for (const auto& instance : instances) {
|
||||
|
|
@ -769,6 +840,7 @@ GLuint WMORenderer::loadTexture(const std::string& path) {
|
|||
|
||||
// Set texture parameters with mipmaps
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
applyAnisotropicFiltering();
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue