From c9178cff3a22887c19dd2da7538c52656d726044 Mon Sep 17 00:00:00 2001 From: Vladislav Khorev Date: Fri, 2 Jan 2026 21:16:44 +0300 Subject: [PATCH] Working on fog shader --- shaders/planet_land.vertex | 5 ++ shaders/planet_land_desktop.fragment | 92 ++++++++++++--------- shaders/planet_stone.vertex | 32 +++++--- shaders/planet_stone_desktop.fragment | 110 +++++++++++++++----------- src/planet/PlanetData.cpp | 72 ++++++++++++++++- src/planet/PlanetData.h | 2 + src/planet/PlanetObject.cpp | 18 +++-- 7 files changed, 232 insertions(+), 99 deletions(-) diff --git a/shaders/planet_land.vertex b/shaders/planet_land.vertex index 9715a1f..856c57b 100644 --- a/shaders/planet_land.vertex +++ b/shaders/planet_land.vertex @@ -3,6 +3,9 @@ attribute vec2 vTexCoord; attribute vec3 vNormal; attribute vec3 vTangent; // Новые атрибуты attribute vec3 vBinormal; +attribute vec3 vColor; + +varying vec3 Color; varying vec2 TexCoord; varying vec3 vViewDirTangent; @@ -29,4 +32,6 @@ void main() { vec4 viewPosition = ModelViewMatrix * vec4(vPosition.xyz, 1.0); worldPosition = vPosition; + + Color = vColor; } \ No newline at end of file diff --git a/shaders/planet_land_desktop.fragment b/shaders/planet_land_desktop.fragment index e1379c0..5d5afb6 100644 --- a/shaders/planet_land_desktop.fragment +++ b/shaders/planet_land_desktop.fragment @@ -1,12 +1,13 @@ varying vec2 TexCoord; varying vec3 vViewDirTangent; +varying vec3 Color; +varying vec3 worldPosition; uniform sampler2D Texture; uniform sampler2D BakedTexture; uniform float uHeightScale; uniform float uDistanceToPlanetSurface; uniform float uCurrentZFar; -varying vec3 worldPosition; uniform vec3 uViewPos; const vec4 FOG_COLOR = vec4(0.0, 0.5, 1.0, 1.0); // Синий туман @@ -32,46 +33,65 @@ void main() { vec4 bakedTextureColor = texture2D(BakedTexture, finalTexCoord); vec4 textureColor = texture2D(Texture, TexCoord); + vec4 textureFlavoredColor = vec4(textureColor.rgb * Color, 1.0); + if (bakedTextureColor.x < 0.01 && bakedTextureColor.y < 0.01 && bakedTextureColor.y < 0.01) { textureMixFactor = 1.0; } - vec4 finalColor = textureMixFactor*textureColor + (1 - textureMixFactor) * bakedTextureColor; + vec4 finalColor = textureMixFactor*textureFlavoredColor + (1 - textureMixFactor) * bakedTextureColor; - float fogFactor; - if (uDistanceToPlanetSurface > 1000) - { +float h = uDistanceToPlanetSurface; + + float fogStart; + float fogEnd; + + if (h >= 1000.0) { gl_FragColor = vec4(finalColor.rgb, 1.0); + } + else + { + if (h > 100.0) { + // Нормализуем высоту от 100 до 1000 (t: 0 -> 1) + float t = (h - 100.0) / 900.0; + + // На высоте 100 туман начинается со 100. + // К высоте 1000 он плавно "убегает" к границе 2500, где объект исчезает. + fogStart = mix(1500.0, 15000.0, t); + + // Держим ширину зоны тумана в пределах 400-600 единиц + float fogRange = mix(1000.0, 6000.0, t); + fogEnd = fogStart + fogRange; + } + else if (h > 40.0) { + float t = (h - 40.0) / 60.0; + + // На высоте 100 туман начинается со 100. + // К высоте 1000 он плавно "убегает" к границе 2500, где объект исчезает. + fogStart = mix(800.0, 1500.0, t); + + fogEnd = mix(1000.0, 2500.0, t); + } + else if (h > 20.0) { + float t = (h - 20.0) / 20.0; + fogStart = mix(200.0, 800.0, t); + fogEnd = mix(500.0, 1000.0, t); + } + else { + // Минимумы при h = 0: start 25, end 125 + float t = clamp(h / 20.0, 0.0, 1.0); + fogStart = mix(100.0, 200.0, t); + fogEnd = mix(250.0, 500.0, t); + } + + // Расчет фактора тумана + float fogRange = max(fogEnd - fogStart, 1.0); + float fogFactor = clamp((realDist - fogStart) / fogRange, 0.0, 1.0); + + // --- Смешивание --- + vec3 mixedColor = mix(finalColor.rgb, FOG_COLOR.rgb, fogFactor); + + gl_FragColor = vec4(mixedColor, 1.0); } - else if (uDistanceToPlanetSurface > 100) - { - float t = clamp((uDistanceToPlanetSurface - 100) / 900.0, 0.0, 1.0); // 1 upstairs, 0 downstairs - - fogFactor = clamp((realDist - 2400) / (300.0*(1 + 10*t)), 0.0, 1.0); - - gl_FragColor = mix(vec4(finalColor.rgb, 1.0), FOG_COLOR, fogFactor*(1.0 - t)); - } - else if (uDistanceToPlanetSurface > 40) - { - //From 100 to 40: - //(1000 < realDist < 1800) - - float t = clamp((uDistanceToPlanetSurface - 40) / 60.0, 0.0, 1.0); // 1 upstairs, 0 downstairs - - fogFactor = clamp((realDist - 2400) / 300.0, 0.0, 1.0); // old fog factor - - float fogFactor2 = clamp((realDist - 1000) / 800.0, 0.0, 1.0); - - gl_FragColor = mix(vec4(finalColor.rgb, 1.0), FOG_COLOR, max(fogFactor, fogFactor2*(1.0 - t))); - } - else - { - fogFactor = clamp((realDist - 1000) / (800.0), 0.0, 1.0); - - gl_FragColor = mix(vec4(finalColor.rgb, 1.0), FOG_COLOR, fogFactor); - - } - - //gl_FragColor = vec4(finalColor.rgb, 1.0); -} +} \ No newline at end of file diff --git a/shaders/planet_stone.vertex b/shaders/planet_stone.vertex index 7ee5836..55496c8 100644 --- a/shaders/planet_stone.vertex +++ b/shaders/planet_stone.vertex @@ -1,22 +1,34 @@ -// Вершинный шейдер (Vertex Shader) - attribute vec3 vPosition; attribute vec2 vTexCoord; +attribute vec3 vNormal; +attribute vec3 vTangent; +attribute vec3 vBinormal; +attribute vec3 vColor; varying vec2 TexCoord; +varying vec3 Color; +varying vec3 vViewDirTangent; varying vec3 worldPosition; - uniform mat4 ProjectionModelViewMatrix; uniform mat4 ModelViewMatrix; -void main() -{ - // Преобразование позиции в пространство вида (View Space) - vec4 viewPosition = ModelViewMatrix * vec4(vPosition.xyz, 1.0); - - gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0); - +uniform vec3 uViewPos; + +void main() { + gl_Position = ProjectionModelViewMatrix * vec4(vPosition, 1.0); TexCoord = vTexCoord; + + vec3 viewDirWorld = normalize(uViewPos - vPosition); + + // Строим матрицу перехода из атрибутов + // Так как базис ортонормирован, TBN^-1 == TBN_transpose + vViewDirTangent = vec3( + dot(viewDirWorld, vTangent), + dot(viewDirWorld, vBinormal), + dot(viewDirWorld, vNormal) + ); + vec4 viewPosition = ModelViewMatrix * vec4(vPosition.xyz, 1.0); + worldPosition = vPosition; } \ No newline at end of file diff --git a/shaders/planet_stone_desktop.fragment b/shaders/planet_stone_desktop.fragment index 51d81e0..8411b83 100644 --- a/shaders/planet_stone_desktop.fragment +++ b/shaders/planet_stone_desktop.fragment @@ -1,57 +1,77 @@ -// ---Фрагментный шейдер (Fragment Shader) +// --- Улучшенный Фрагментный шейдер varying vec2 TexCoord; - -uniform sampler2D Texture; -uniform float uDistanceToPlanetSurface; - -const vec4 FOG_COLOR = vec4(0.0, 0.5, 1.0, 1.0); // Синий туман - varying vec3 worldPosition; +uniform sampler2D Texture; +uniform float uDistanceToPlanetSurface; uniform vec3 uViewPos; +const vec4 FOG_COLOR = vec4(0.0, 0.5, 1.0, 1.0); + + void main() { + vec4 textureColor = texture2D(Texture, TexCoord); + float realDist = distance(worldPosition, uViewPos); + float h = uDistanceToPlanetSurface; - vec4 textureColor = texture2D(Texture, TexCoord); - vec3 finalColor = textureColor.rgb; - - float realDist = distance(worldPosition, uViewPos); - - float alphaFactor = clamp((2000 - realDist) / 500.0, 0.0, 1.0); + float fogStart; + float fogEnd; - float fogFactor; - if (uDistanceToPlanetSurface > 1000) - { - gl_FragColor = vec4(finalColor.rgb, 1.0); + // --- Логика AlphaFactor (строго 2000-2500) --- + // Объект полностью исчезает на 2500. + // Если fogStart на высоте 1000 равен 2500, то туман и объект исчезнут одновременно. + float alphaFactor = clamp((2000.0 - realDist) / 500.0, 0.0, 1.0); + + + // --- Логика расчета границ тумана --- + + if (h >= 1000.0) { + gl_FragColor = vec4(textureColor.rgb, alphaFactor); + } + else + { + if (h > 100.0) { + // Нормализуем высоту от 100 до 1000 (t: 0 -> 1) + float t = (h - 100.0) / 900.0; + + // На высоте 100 туман начинается со 100. + // К высоте 1000 он плавно "убегает" к границе 2500, где объект исчезает. + fogStart = mix(1500.0, 15000.0, t); + + // Держим ширину зоны тумана в пределах 400-600 единиц + float fogRange = mix(1000.0, 6000.0, t); + fogEnd = fogStart + fogRange; + } + else if (h > 40.0) { + float t = (h - 40.0) / 60.0; + + // На высоте 100 туман начинается со 100. + // К высоте 1000 он плавно "убегает" к границе 2500, где объект исчезает. + fogStart = mix(800.0, 1500.0, t); + + fogEnd = mix(1000.0, 2500.0, t); + } + else if (h > 20.0) { + float t = (h - 20.0) / 20.0; + fogStart = mix(200.0, 800.0, t); + fogEnd = mix(500.0, 1000.0, t); + } + else { + // Минимумы при h = 0: start 25, end 125 + float t = clamp(h / 20.0, 0.0, 1.0); + fogStart = mix(100.0, 200.0, t); + fogEnd = mix(250.0, 500.0, t); + } + + // Расчет фактора тумана + float fogRange = max(fogEnd - fogStart, 1.0); + float fogFactor = clamp((realDist - fogStart) / fogRange, 0.0, 1.0); + + // --- Смешивание --- + vec3 mixedColor = mix(textureColor.rgb, FOG_COLOR.rgb, fogFactor); + + gl_FragColor = vec4(mixedColor, alphaFactor); } - else if (uDistanceToPlanetSurface > 100) - { - float t = clamp((uDistanceToPlanetSurface - 100) / 900.0, 0.0, 1.0); // 1 upstairs, 0 downstairs - - fogFactor = clamp((realDist - 2400) / (300.0*(1 + 10*t)), 0.0, 1.0); - - gl_FragColor = mix(vec4(finalColor.rgb, alphaFactor), FOG_COLOR, fogFactor*(1.0 - t)); - } - else if (uDistanceToPlanetSurface > 40) - { - //From 100 to 40: - //(1000 < realDist < 1800) - - float t = clamp((uDistanceToPlanetSurface - 40) / 60.0, 0.0, 1.0); // 1 upstairs, 0 downstairs - - fogFactor = clamp((realDist - 2400) / 300.0, 0.0, 1.0); // old fog factor - - float fogFactor2 = clamp((realDist - 1000) / 800.0, 0.0, 1.0); - - gl_FragColor = mix(vec4(finalColor.rgb, alphaFactor), FOG_COLOR, max(fogFactor, fogFactor2*(1.0 - t))); - } - else - { - fogFactor = clamp((realDist - 1000) / (800.0), 0.0, 1.0); - - gl_FragColor = mix(vec4(finalColor.rgb, alphaFactor), FOG_COLOR, fogFactor); - } - //gl_FragColor = vec4(finalColor.rgb, 1.0); } \ No newline at end of file diff --git a/src/planet/PlanetData.cpp b/src/planet/PlanetData.cpp index 343d902..d84d136 100644 --- a/src/planet/PlanetData.cpp +++ b/src/planet/PlanetData.cpp @@ -6,6 +6,7 @@ namespace ZL { + const float PlanetData::PLANET_RADIUS = 20000.f; const Vector3f PlanetData::PLANET_CENTER_OFFSET = Vector3f{ 0.f, 0.f, 0.0f }; @@ -109,15 +110,32 @@ namespace ZL { currentZNear = 32; currentZFar = 10000.f; } - else + else if (dToPlanetSurface > 20) { currentZNear = 16; currentZFar = 5000.f; } + else if (dToPlanetSurface > 5) + { + currentZNear = 8; + currentZFar = 2500.f; + } + else + { + currentZNear = 4; + currentZFar = 1250.f; + } return { currentZNear, currentZFar }; } + float PlanetData::distanceToPlanetSurfaceFast(const Vector3f& viewerPosition) + { + Vector3f shipLocalPosition = viewerPosition - PLANET_CENTER_OFFSET; + + return sqrt(shipLocalPosition.squaredNorm()) - PLANET_RADIUS; + } + float PlanetData::distanceToPlanetSurface(const Vector3f& viewerPosition) { Vector3f shipLocalPosition = viewerPosition - PLANET_CENTER_OFFSET; @@ -304,12 +322,14 @@ namespace ZL { lod.vertexData.TexCoordData.clear(); lod.vertexData.TangentData.clear(); lod.vertexData.BinormalData.clear(); + lod.vertexData.ColorData.clear(); lod.vertexData.PositionData.reserve(vertexCount); lod.vertexData.NormalData.reserve(vertexCount); lod.vertexData.TexCoordData.reserve(vertexCount); lod.vertexData.TangentData.reserve(vertexCount); lod.vertexData.BinormalData.reserve(vertexCount); + lod.vertexData.ColorData.reserve(vertexCount); const std::array triangleUVs = { @@ -346,6 +366,56 @@ namespace ZL { lod.vertexData.BinormalData.push_back(y_axis); } } + + // + const Vector3f baseColor = { 0.498f, 0.416f, 0.0f }; + const float colorFrequency = 5.0f; + const float colorAmplitude = 0.2f; + const Vector3f offsetR = { 0.1f, 0.2f, 0.3f }; + const Vector3f offsetG = { 0.5f, 0.4f, 0.6f }; + const Vector3f offsetB = { 0.9f, 0.8f, 0.7f }; + + + for (const auto& t : lod.triangles) { + for (int i = 0; i < 3; i++) { + // : t.data[i] , + // PositionData buffer, . + Vector3f p_geometry = t.data[i]; + Vector3f dir = p_geometry.normalized(); + + // ( ) + float noiseR = colorPerlin.noise( + (dir.v[0] + offsetR.v[0]) * colorFrequency, + (dir.v[1] + offsetR.v[1]) * colorFrequency, + (dir.v[2] + offsetR.v[2]) * colorFrequency + ); + float noiseG = colorPerlin.noise( + (dir.v[0] + offsetG.v[0]) * colorFrequency, + (dir.v[1] + offsetG.v[1]) * colorFrequency, + (dir.v[2] + offsetG.v[2]) * colorFrequency + ); + float noiseB = colorPerlin.noise( + (dir.v[0] + offsetB.v[0]) * colorFrequency, + (dir.v[1] + offsetB.v[1]) * colorFrequency, + (dir.v[2] + offsetB.v[2]) * colorFrequency + ); + + Vector3f colorOffset = { + noiseR * colorAmplitude, + noiseG * colorAmplitude, + noiseB * colorAmplitude + }; + + Vector3f finalColor = baseColor + colorOffset; + + finalColor.v[0] = max(0.0f, min(1.0f, finalColor.v[0])); + finalColor.v[1] = max(0.0f, min(1.0f, finalColor.v[1])); + finalColor.v[2] = max(0.0f, min(1.0f, finalColor.v[2])); + + // , PositionData NormalData ! + lod.vertexData.ColorData.push_back(finalColor); + } + } } diff --git a/src/planet/PlanetData.h b/src/planet/PlanetData.h index 0a56779..73d3d5a 100644 --- a/src/planet/PlanetData.h +++ b/src/planet/PlanetData.h @@ -11,6 +11,7 @@ namespace ZL { + using VertexID = std::string; using V2TMap = std::map>; @@ -102,6 +103,7 @@ namespace ZL { // std::pair calculateZRange(float distanceToSurface); float distanceToPlanetSurface(const Vector3f& viewerPosition); + float distanceToPlanetSurfaceFast(const Vector3f& viewerPosition); // , std::vector getTrianglesUnderCameraNew(const Vector3f& viewerPosition); diff --git a/src/planet/PlanetObject.cpp b/src/planet/PlanetObject.cpp index 98f900b..92b64df 100644 --- a/src/planet/PlanetObject.cpp +++ b/src/planet/PlanetObject.cpp @@ -65,8 +65,9 @@ namespace ZL { //planetRenderStruct.data.PositionData.resize(9); planetRenderStruct.RefreshVBO(); + sandTexture = std::make_unique(CreateTextureDataFromPng("./resources/sand2.png", "")); - stoneTexture = std::make_unique(CreateTextureDataFromPng("./resources/rock.png", "")); + stoneTexture = std::make_unique(CreateTextureDataFromPng("./resources/rockdark2.png", "")); // Атмосфера planetAtmosphereRenderStruct.data = planetData.getAtmosphereLod().vertexData; @@ -271,7 +272,8 @@ namespace ZL { renderer.EnableVertexAttribArray("vBinormal"); renderer.EnableVertexAttribArray(vTexCoordName); - float dist = planetData.distanceToPlanetSurface(Environment::shipPosition); + + float dist = planetData.distanceToPlanetSurfaceFast(Environment::shipPosition); auto zRange = planetData.calculateZRange(dist); const float currentZNear = zRange.first; const float currentZFar = zRange.second; @@ -300,13 +302,14 @@ namespace ZL { // Позиция камеры (корабля) в мире renderer.RenderUniform3fv("uViewPos", &Environment::shipPosition.v[0]); - renderer.RenderUniform1f("uHeightScale", 0.03f); + renderer.RenderUniform1f("uHeightScale", 0.08f); //renderer.RenderUniform1f("uHeightScale", 0.0f); renderer.RenderUniform1f("uDistanceToPlanetSurface", dist); renderer.RenderUniform1f("uCurrentZFar", currentZFar); + glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, stoneMapFB->getTextureID()); glActiveTexture(GL_TEXTURE0); @@ -329,7 +332,6 @@ namespace ZL { } - void PlanetObject::drawStones(Renderer& renderer) { static const std::string defaultShaderName2 = "planetStone"; @@ -346,7 +348,8 @@ namespace ZL { renderer.EnableVertexAttribArray(vNormalName); renderer.EnableVertexAttribArray(vTexCoordName); - float dist = planetData.distanceToPlanetSurface(Environment::shipPosition); + + float dist = planetData.distanceToPlanetSurfaceFast(Environment::shipPosition); auto zRange = planetData.calculateZRange(dist); const float currentZNear = zRange.first; const float currentZFar = zRange.second; @@ -481,7 +484,7 @@ namespace ZL { renderer.EnableVertexAttribArray(vNormalName); - float dist = planetData.distanceToPlanetSurface(Environment::shipPosition); + float dist = planetData.distanceToPlanetSurfaceFast(Environment::shipPosition); auto zRange = planetData.calculateZRange(dist); const float currentZNear = zRange.first; const float currentZFar = zRange.second; @@ -501,6 +504,7 @@ namespace ZL { Vector3f color = { 0.0, 0.5, 1.0 }; + renderer.RenderUniform3fv("uColor", &color.v[0]); renderer.RenderUniformMatrix4fv("ModelViewMatrix", false, &viewMatrix.m[0]); @@ -525,7 +529,7 @@ namespace ZL { float PlanetObject::distanceToPlanetSurface(const Vector3f& viewerPosition) { - return planetData.distanceToPlanetSurface(viewerPosition); + return planetData.distanceToPlanetSurfaceFast(viewerPosition); }