From b580a349997cc0f8b6c2ac4122a0732e08c649af Mon Sep 17 00:00:00 2001 From: cwj3rcb Date: Sun, 31 Aug 2025 18:00:03 -0500 Subject: [PATCH] Variable fog of war --- main.c | 75 ++++++++++++++++++++++++++++++++++++---- resources/shaders/fog.fs | 32 +++++++++++++++++ resources/shaders/fog.vs | 16 +++++++++ 3 files changed, 117 insertions(+), 6 deletions(-) create mode 100644 resources/shaders/fog.fs create mode 100644 resources/shaders/fog.vs diff --git a/main.c b/main.c index 8494bf3..74d66ac 100644 --- a/main.c +++ b/main.c @@ -252,7 +252,43 @@ int main(void) SetShaderValue(skyboxShader, GetShaderLocation(skyboxShader, "vflipped"), &vflipped, SHADER_UNIFORM_INT); SetShaderValue(skyboxShader, GetShaderLocation(skyboxShader, "doGamma"), &doGamma, SHADER_UNIFORM_INT); - // Done – now you can draw it + // Load the fog-of-war shader + Shader fog = LoadShader( + "resources/shaders/fog.vs", + "resources/shaders/fog.fs" +); + + // Grab uniform locations (cache them) + int locPlayer = GetShaderLocation(fog, "u_playerPos"); + int locRadius = GetShaderLocation(fog, "u_fogRadius"); + int locFeather = GetShaderLocation(fog, "u_fogFeather"); + int locFogColor = GetShaderLocation(fog, "u_fogColor"); + int locCutoff_fog = GetShaderLocation(fog, "u_alphaCutoff"); + + int locInner = GetShaderLocation(fog, "u_inner"); + int locOuter = GetShaderLocation(fog, "u_outer"); + int locMinShadow = GetShaderLocation(fog, "u_minShadow"); + // Optional if you added the sharpness curve in the shader + int locSharpness = GetShaderLocation(fog, "u_sharpness"); + + + // Let raylib know which matrices the shader expects + fog.locs[SHADER_LOC_MATRIX_MODEL] = GetShaderLocation(fog, "matModel"); + fog.locs[SHADER_LOC_MATRIX_VIEW] = GetShaderLocation(fog, "matView"); + fog.locs[SHADER_LOC_MATRIX_PROJECTION] = GetShaderLocation(fog, "matProjection"); + + // --- Apply shader to your ground tile model --- + mdlTile.materials[0].shader = fog; // same shader also works for opaque + // (texture0 already set on mdlTile) + + // Defaults for opaque geometry (no alpha cut) + float cutoffOpaque = 0.0f; + SetShaderValue(fog, locCutoff_fog, &cutoffOpaque, SHADER_UNIFORM_FLOAT); + + // You’ll reuse the *same* shader for trees (alpha cut). + // We won’t assign it to a Model because billboards aren’t models; + // instead we’ll render trees inside BeginShaderMode(fog) so they use it. + @@ -376,30 +412,57 @@ int main(void) { ClearBackground(BLACK); + // Fog/vignette tuning + float inner = 0.0f; // start radius (center under player) + float outer = 45.0f; // how far until full fog + float minShadow = 0.40f; // baseline darkness at the center (0 = none, 1 = pitch black) + float sharpness = 2.0f; // steeper edge (optional if shader uses it) + Vector4 fogColor = {0.0f, 0.0f, 0.0f, 1.0f}; + + SetShaderValue(fog, locPlayer, &g.player.position, SHADER_UNIFORM_VEC3); + SetShaderValue(fog, locInner, &inner, SHADER_UNIFORM_FLOAT); + SetShaderValue(fog, locOuter, &outer, SHADER_UNIFORM_FLOAT); + SetShaderValue(fog, locMinShadow, &minShadow, SHADER_UNIFORM_FLOAT); + SetShaderValue(fog, locFogColor, &fogColor, SHADER_UNIFORM_VEC4); + + // Only if you added sharpness + SetShaderValue(fog, locSharpness, &sharpness, SHADER_UNIFORM_FLOAT); + + BeginMode3D(g.player.camera); rlDisableBackfaceCulling(); rlDisableDepthMask(); - // keep it centered on the camera skybox.transform = MatrixTranslate( g.player.camera.position.x, g.player.camera.position.y, g.player.camera.position.z ); - DrawModel(skybox, (Vector3){0}, 1.0f, WHITE); - rlEnableDepthMask(); - rlEnableBackfaceCulling(); + rlEnableBackfaceCulling(); DrawLevel(mdlTile); - + + /* BeginShaderMode(shAlphaClip); { RenderTrees(&g, tree, treepos, treeSize); } EndShaderMode(); + */ + + // --- Trees use same fog shader but with alpha-cut enabled --- + float cutoffAlpha = 0.3f; + SetShaderValue(fog, locCutoff_fog, &cutoffAlpha, SHADER_UNIFORM_FLOAT); + BeginShaderMode(fog); + RenderTrees(&g, tree, treepos, treeSize); + EndShaderMode(); + + // Restore opaque cutoff for anything else you draw with that material later + SetShaderValue(fog, locCutoff_fog, &cutoffOpaque, SHADER_UNIFORM_FLOAT); + //DrawBillboard(g.player.camera, sign, bbPos, bbSize, WHITE); //This was the texture chasing you. EndMode3D(); diff --git a/resources/shaders/fog.fs b/resources/shaders/fog.fs new file mode 100644 index 0000000..44318d7 --- /dev/null +++ b/resources/shaders/fog.fs @@ -0,0 +1,32 @@ +#version 330 + +in vec3 vWorldPos; +in vec2 vTexCoord; + +uniform sampler2D texture0; +uniform vec3 u_playerPos; // player world pos +uniform float u_inner; // start of vignette (m) +uniform float u_outer; // end of vignette (m) u_outer > u_inner +uniform float u_minShadow; // baseline darkness at center [0..1], e.g. 0.15 +uniform vec4 u_fogColor; // usually vec4(0,0,0,1) +uniform float u_alphaCutoff; // for trees/billboards too + +out vec4 finalColor; + +void main() +{ + vec4 texel = texture(texture0, vTexCoord); + if (texel.a < u_alphaCutoff) discard; + + // distance on the ground plane + float distXZ = length(vWorldPos.xz - u_playerPos.xz); + + // 0 at u_inner, 1 at u_outer + float t = smoothstep(u_inner, u_outer, distXZ); + + // add baseline shadow so center is not fully bright + t = u_minShadow + (1.0 - u_minShadow) * t; + + vec3 rgb = mix(texel.rgb, u_fogColor.rgb, t); + finalColor = vec4(rgb, texel.a); +} diff --git a/resources/shaders/fog.vs b/resources/shaders/fog.vs new file mode 100644 index 0000000..2d2aeea --- /dev/null +++ b/resources/shaders/fog.vs @@ -0,0 +1,16 @@ +#version 330 +in vec3 vertexPosition; +in vec2 vertexTexCoord; + +uniform mat4 matModel, matView, matProjection; + +out vec3 vWorldPos; +out vec2 vTexCoord; + +void main() +{ + vec4 world = matModel * vec4(vertexPosition, 1.0); + vWorldPos = world.xyz; + vTexCoord = vertexTexCoord; + gl_Position = matProjection * matView * world; +}