From af550f56a785c09341d746d287c56a3abd65d3ce Mon Sep 17 00:00:00 2001 From: Vladislav Khorev Date: Sat, 13 Dec 2025 23:17:03 +0300 Subject: [PATCH] Cool working --- Game.cpp | 31 ++++- Game.h | 2 +- PlanetObject.cpp | 131 +++++++++++++++++++++- PlanetObject.h | 7 +- Renderer.cpp | 12 ++ Renderer.h | 2 +- shaders/defaultAtmosphere.fragment | 41 +++++++ shaders/defaultAtmosphere.vertex | 20 ++++ shaders/defaultColor_fog.vertex | 32 ++++++ shaders/defaultColor_fog_desktop.fragment | 89 +++++++++++++++ shaders/env_sky.vertex | 12 ++ shaders/env_sky_desktop.fragment | 11 ++ 12 files changed, 379 insertions(+), 11 deletions(-) create mode 100644 shaders/defaultAtmosphere.fragment create mode 100644 shaders/defaultAtmosphere.vertex create mode 100644 shaders/defaultColor_fog.vertex create mode 100644 shaders/defaultColor_fog_desktop.fragment create mode 100644 shaders/env_sky.vertex create mode 100644 shaders/env_sky_desktop.fragment diff --git a/Game.cpp b/Game.cpp index a9af59b..885ad64 100755 --- a/Game.cpp +++ b/Game.cpp @@ -152,11 +152,13 @@ namespace ZL renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_web.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_web.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("env", "./shaders/env.vertex", "./shaders/env_web.fragment", CONST_ZIP_FILE); + renderer.shaderManager.AddShaderFromFiles("defaultAtmosphere", "./shaders/defaultAtmosphere.vertex", "./shaders/defaultAtmosphere.fragment", CONST_ZIP_FILE); #else renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_desktop.fragment", CONST_ZIP_FILE); - renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_desktop.fragment", CONST_ZIP_FILE); - renderer.shaderManager.AddShaderFromFiles("env", "./shaders/env.vertex", "./shaders/env_desktop.fragment", CONST_ZIP_FILE); + renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor_fog.vertex", "./shaders/defaultColor_fog_desktop.fragment", CONST_ZIP_FILE); + renderer.shaderManager.AddShaderFromFiles("env", "./shaders/env_sky.vertex", "./shaders/env_sky_desktop.fragment", CONST_ZIP_FILE); + renderer.shaderManager.AddShaderFromFiles("defaultAtmosphere", "./shaders/defaultAtmosphere.vertex", "./shaders/defaultAtmosphere.fragment", CONST_ZIP_FILE); #endif @@ -267,16 +269,18 @@ namespace ZL } - void Game::drawCubemap() + void Game::drawCubemap(float skyPercent) { static const std::string defaultShaderName = "default"; static const std::string envShaderName = "env"; static const std::string vPositionName = "vPosition"; static const std::string vTexCoordName = "vTexCoord"; static const std::string textureUniformName = "Texture"; + static const std::string skyPercentUniformName = "skyPercent"; renderer.shaderManager.PushShader(envShaderName); renderer.RenderUniform1i(textureUniformName, 0); + renderer.RenderUniform1f(skyPercentUniformName, skyPercent); renderer.EnableVertexAttribArray(vPositionName); renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, static_cast(Environment::width) / static_cast(Environment::height), @@ -455,16 +459,31 @@ namespace ZL static const std::string vTexCoordName = "vTexCoord"; static const std::string textureUniformName = "Texture"; - glClearColor(0.0f, 0.5f, 1.0f, 1.0f); + glClearColor(0.0f, 1.0f, 0.0f, 1.0f); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glViewport(0, 0, Environment::width, Environment::height); CheckGlError(); - drawCubemap(); + float skyPercent = 0.0; + float distance = planetObject.distanceToPlanetSurface(); + if (distance > 2000.f) + { + skyPercent = 0.0f; + } + else if (distance < 1000.f) + { + skyPercent = 1.0f; + } + else + { + skyPercent = (2000.f - distance) / 1000.f; + } + + drawCubemap(skyPercent); planetObject.draw(renderer); - if (planetObject.planetIsFar(Environment::shipPosition)) + if (planetObject.planetIsFar()) { glClear(GL_DEPTH_BUFFER_BIT); } diff --git a/Game.h b/Game.h index 65bb5b6..987e3e1 100755 --- a/Game.h +++ b/Game.h @@ -32,7 +32,7 @@ namespace ZL { private: void processTickCount(); void drawScene(); - void drawCubemap(); + void drawCubemap(float skyPercent); void drawShip(); void drawBoxes(); void drawUI(); diff --git a/PlanetObject.cpp b/PlanetObject.cpp index a483d2c..a7e8bd1 100644 --- a/PlanetObject.cpp +++ b/PlanetObject.cpp @@ -154,14 +154,23 @@ namespace ZL { - bool PlanetObject::planetIsFar(const Vector3f& shipPosition) + bool PlanetObject::planetIsFar() { const Vector3f planetWorldPosition = PLANET_CENTER_OFFSET; - const float distanceToPlanetCenter = (planetWorldPosition - shipPosition).length(); + const float distanceToPlanetCenter = (planetWorldPosition - Environment::shipPosition).length(); const float distanceToPlanetSurface = distanceToPlanetCenter - PLANET_RADIUS; return distanceToPlanetSurface > 0.1*TRANSITION_MIDDLE_START; } + + float PlanetObject::distanceToPlanetSurface() + { + const Vector3f planetWorldPosition = PLANET_CENTER_OFFSET; + const float distanceToPlanetCenter = (planetWorldPosition - Environment::shipPosition).length(); + const float distanceToPlanetSurface = distanceToPlanetCenter - PLANET_RADIUS; + return distanceToPlanetSurface; + + } PlanetObject::PlanetObject() @@ -184,6 +193,18 @@ namespace ZL { sandTexture = std::make_unique(CreateTextureDataFromPng("./resources/sand.png", "")); //sandTexture = std::make_unique(CreateTextureDataFromPng("./resources/rock.png", "")); + planetAtmosphere.data = CreateRect2D({ 0.f, 0.f }, { 1.f, 1.f }, 0.f); + planetAtmosphere.data.TexCoordData.clear(); + planetAtmosphere.data.ColorData.push_back({ 0,0.5,1 }); + planetAtmosphere.data.ColorData.push_back({ 0,0.5,1 }); + planetAtmosphere.data.ColorData.push_back({ 0,0.5,1 }); + planetAtmosphere.data.ColorData.push_back({ 0,0.5,1 }); + planetAtmosphere.data.ColorData.push_back({ 0,0.5,1 }); + planetAtmosphere.data.ColorData.push_back({ 0,0.5,1 }); + planetAtmosphere.data.Scale(1000.f); + //planetAtmosphere.data.Scale(PLANET_RADIUS*1.25f); + //planetAtmosphere.data.Move(PLANET_CENTER_OFFSET); + planetAtmosphere.RefreshVBO(); } void PlanetObject::prepareDrawData() { @@ -245,6 +266,11 @@ namespace ZL { renderer.RenderUniform3fv("uLightDirection", &lightDirection_View.v[0]); renderer.RenderUniformMatrix4fv("ModelViewMatrix", false, &viewMatrix.m[0]); + float dist = distanceToPlanetSurface(); + + renderer.RenderUniform1f("uDistanceToPlanetSurface", dist); + renderer.RenderUniform1f("uCurrentZFar", currentZFar); + glBindTexture(GL_TEXTURE_2D, sandTexture->getTexID()); renderer.DrawVertexRenderStruct(planetRenderStruct); @@ -261,6 +287,107 @@ namespace ZL { renderer.shaderManager.PopShader(); CheckGlError(); + //drawAtmosphere(renderer); + } + + void PlanetObject::drawAtmosphere(Renderer& renderer) { + static const std::string defaultShaderName = "defaultAtmosphere"; + static const std::string vPositionName = "vPosition"; + static const std::string vColorName = "vColor"; + + glClear(GL_DEPTH_BUFFER_BIT); + + + renderer.shaderManager.PushShader(defaultShaderName); + renderer.EnableVertexAttribArray(vPositionName); + renderer.EnableVertexAttribArray(vColorName); + + const auto zRange = calculateZRange(Environment::shipPosition); + const float currentZNear = zRange.first; + const float currentZFar = zRange.second; + + // 2. Применяем динамическую матрицу проекции + renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, + static_cast(Environment::width) / static_cast(Environment::height), + currentZNear, currentZFar); + + renderer.PushMatrix(); + renderer.LoadIdentity(); + renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); + renderer.RotateMatrix(Environment::inverseShipMatrix); + renderer.TranslateMatrix(-Environment::shipPosition); + + Matrix4f projMatrix = renderer.GetProjectionModelViewMatrix(); + Matrix4f modelViewMatrix = renderer.GetCurrentModelViewMatrix(); + + + renderer.PopMatrix(); + renderer.PopProjectionMatrix(); + + renderer.PushProjectionMatrix((Environment::width), static_cast(Environment::height), -1, 1); + renderer.PushMatrix(); + renderer.LoadIdentity(); + + // Преобразуем центр планеты в экранные координаты + int screenX = 0; + int screenY = 0; + worldToScreenCoordinates( + PLANET_CENTER_OFFSET, + projMatrix, + Environment::width, + Environment::height, + screenX, + screenY + ); + + // Позиция центра в пикселях + Vector3f centerPos = Vector3f(static_cast(screenX), static_cast(screenY), 0.0f); + + renderer.TranslateMatrix(centerPos); + renderer.RenderUniform1f("uCenterRadius", 0.f); + renderer.RenderUniform3fv("uCenterPos", ¢erPos.v[0]); + + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE);// Аддитивное смешивание для эффекта свечения + + renderer.DrawVertexRenderStruct(planetAtmosphere); + glDisable(GL_BLEND); + renderer.PopMatrix(); + renderer.PopProjectionMatrix(); + + + /* + renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, + static_cast(Environment::width) / static_cast(Environment::height), + currentZNear, currentZFar); + + renderer.PushMatrix(); + renderer.LoadIdentity(); + renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); + renderer.RotateMatrix(Environment::inverseShipMatrix); + renderer.TranslateMatrix(-Environment::shipPosition); + + float centerRadius = PLANET_RADIUS*1.2f; + + Vector3f centerPos = PLANET_CENTER_OFFSET; + + + renderer.RenderUniform1f("uCenterRadius", centerRadius); + renderer.RenderUniform3fv("uCenterPos", ¢erPos.v[0]); + + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE);// Аддитивное смешивание для эффекта свечения + + renderer.DrawVertexRenderStruct(planetAtmosphere); + glDisable(GL_BLEND); + renderer.PopMatrix(); + renderer.PopProjectionMatrix();*/ + renderer.DisableVertexAttribArray(vColorName); + renderer.DisableVertexAttribArray(vPositionName); + renderer.shaderManager.PopShader(); + CheckGlError(); } diff --git a/PlanetObject.h b/PlanetObject.h index 0d3140c..2c67bfe 100644 --- a/PlanetObject.h +++ b/PlanetObject.h @@ -48,6 +48,9 @@ namespace ZL { VertexDataStruct planetMesh; VertexRenderStruct planetRenderStruct; + VertexRenderStruct planetAtmosphere; + + std::shared_ptr sandTexture; public: @@ -58,8 +61,10 @@ namespace ZL { void update(float deltaTimeMs); void draw(Renderer& renderer); + void drawAtmosphere(Renderer& renderer); - bool planetIsFar(const Vector3f& shipPosition); + bool planetIsFar(); + float distanceToPlanetSurface(); private: diff --git a/Renderer.cpp b/Renderer.cpp index fd10526..69a206b 100755 --- a/Renderer.cpp +++ b/Renderer.cpp @@ -727,6 +727,18 @@ namespace ZL { } + void Renderer::RenderUniform1f(const std::string& uniformName, float value) + { + auto shader = shaderManager.GetCurrentShader(); + + auto uniform = shader->uniformList.find(uniformName); + + if (uniform != shader->uniformList.end()) + { + glUniform1fv(uniform->second, 1, &value); + } + + } void Renderer::VertexAttribPointer2fv(const std::string& attribName, int stride, const char* pointer) diff --git a/Renderer.h b/Renderer.h index 39eca83..c102d77 100755 --- a/Renderer.h +++ b/Renderer.h @@ -124,7 +124,7 @@ namespace ZL { void RenderUniformMatrix4fv(const std::string& uniformName, bool transpose, const float* value); void RenderUniform1i(const std::string& uniformName, const int value); void RenderUniform3fv(const std::string& uniformName, const float* value); - + void RenderUniform1f(const std::string& uniformName, float value); void VertexAttribPointer2fv(const std::string& attribName, int stride, const char* pointer); diff --git a/shaders/defaultAtmosphere.fragment b/shaders/defaultAtmosphere.fragment new file mode 100644 index 0000000..324256f --- /dev/null +++ b/shaders/defaultAtmosphere.fragment @@ -0,0 +1,41 @@ +varying vec3 color; +varying vec3 vViewPosition; // Получаем позицию фрагмента в пространстве вида + +uniform vec3 uCenterPos; // Центр планеты/атмосферы (в пространстве вида) +uniform float uCenterRadius; // Радиус атмосферы (точка, где прозрачность = 0.5) + +// Определение зоны плавного спада alpha +const float FADE_WIDTH = 0.05; // Например, 5% от радиуса для плавного перехода + +void main() +{ + // 1. Расчет расстояния от фрагмента до центра + float distanceToCenter = length(vViewPosition - uCenterPos); + + // 2. Расчет границ для плавного перехода + // Начало спада (R) + float startRadius = uCenterRadius; + // Конец спада (R + dR) + float endRadius = uCenterRadius + FADE_WIDTH * uCenterRadius; + + // 3. Расчет коэффициента прозрачности с помощью smoothstep + // smoothstep(edge0, edge1, x) возвращает 0.0, если x < edge0, + // 1.0, если x > edge1, и плавно меняется между ними. + + // Нам нужно, чтобы alpha была 0.5 при startRadius и 0.0 при endRadius. + // Если мы используем smoothstep(start, end, distance), то получим: + // - 0.0, когда distance < start + // - 1.0, когда distance > end + // Нам нужен обратный результат (1.0 - smoothstep), чтобы 0.5 было внутри, а 0.0 - снаружи. + + // Вычисляем множитель прозрачности (от 1.0 до 0.0) + float fadeFactor = 1.0 - smoothstep(startRadius, endRadius, distanceToCenter); + + // 4. Применение нового alpha + // Если fadeFactor = 1.0 (внутри R), alpha = 0.5 * 1.0 = 0.5 + // Если fadeFactor = 0.0 (вне R+dR), alpha = 0.5 * 0.0 = 0.0 + // Если между ними - плавная интерполяция. + float finalAlpha = 0.5 * fadeFactor; + + gl_FragColor = vec4(color, 0.5); +} \ No newline at end of file diff --git a/shaders/defaultAtmosphere.vertex b/shaders/defaultAtmosphere.vertex new file mode 100644 index 0000000..629ebe8 --- /dev/null +++ b/shaders/defaultAtmosphere.vertex @@ -0,0 +1,20 @@ +attribute vec3 vPosition; +attribute vec3 vColor; + +uniform mat4 ProjectionModelViewMatrix; +uniform mat4 ModelViewMatrix; + +varying vec3 color; +varying vec3 vViewPosition; // Новая переменная: позиция вершины в пространстве вида + +void main() +{ + // Расчет позиции в пространстве отсечения (как у вас) + gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0); + + // Передача позиции в пространстве вида во фрагментный шейдер + vViewPosition = vec3(ModelViewMatrix * vec4(vPosition.xyz, 1.0)); + //vViewPosition = vPosition.xyz; + + color = vColor; +} \ No newline at end of file diff --git a/shaders/defaultColor_fog.vertex b/shaders/defaultColor_fog.vertex new file mode 100644 index 0000000..eadfe41 --- /dev/null +++ b/shaders/defaultColor_fog.vertex @@ -0,0 +1,32 @@ +// Вершинный шейдер (Vertex Shader) + +attribute vec3 vPosition; +attribute vec3 vColor; +attribute vec3 vNormal; +attribute vec2 vTexCoord; + +varying vec3 color; +varying vec3 normal; +varying vec2 TexCoord; +varying float viewZ; // <--- НОВОЕ: Z-координата в пространстве вида (View Space) + +uniform mat4 ProjectionModelViewMatrix; +uniform mat4 ModelViewMatrix; // Нужна для преобразования vPosition в View Space +uniform vec3 uLightDirection; + +void main() +{ + // Преобразование позиции в пространство вида (View Space) + vec4 viewPosition = ModelViewMatrix * vec4(vPosition.xyz, 1.0); + + // Сохраняем отрицательную Z-координату. В OpenGL Z-координата (глубина) + // в пространстве вида обычно отрицательна, но для расчета тумана + // удобнее использовать положительное значение. + viewZ = -viewPosition.z; + + gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0); + + normal = normalize((ModelViewMatrix * vec4(vNormal, 0.0)).xyz); + color = vColor; + TexCoord = vTexCoord; +} \ No newline at end of file diff --git a/shaders/defaultColor_fog_desktop.fragment b/shaders/defaultColor_fog_desktop.fragment new file mode 100644 index 0000000..cc24c23 --- /dev/null +++ b/shaders/defaultColor_fog_desktop.fragment @@ -0,0 +1,89 @@ +// ---Фрагментный шейдер (Fragment Shader) + +varying vec3 color; +varying vec3 normal; +varying vec2 TexCoord; +varying float viewZ; + +uniform sampler2D Texture; +uniform vec3 uLightDirection; +uniform float uDistanceToPlanetSurface; +uniform float uCurrentZFar; + +// Константы для тумана: +const vec4 FOG_COLOR = vec4(0.0, 0.5, 1.0, 1.0); // Синий туман + +// Параметры "Distance Fog" +const float DIST_FOG_MAX = 2000.0; +const float DIST_FOG_MIN = 1000.0; + +// Параметры "Z-Far Fog" +// Насколько близко к Zfar должен начинаться туман (например, 10% от Zfar) +const float Z_FOG_START_RATIO = 0.9; +// Какую долю от Zfar должен покрывать туман (например, 10% от Zfar) +const float Z_FOG_RANGE_RATIO = 0.1; + + +void main() +{ + // ... (1. Получаем цвет и 2. Расчет освещения) + vec4 textureColor = texture2D(Texture, TexCoord); + vec3 finalColor = textureColor.rgb * color; + + float diffuse = max(0.0, dot(normal, uLightDirection)); + float ambient = 0.2; + float lightingFactor = min(1.0, ambient + diffuse); + vec3 litColor = finalColor * lightingFactor; + + + // 3. Расчет коэффициента тумана (fogFactor) + float fogFactor = 0.0; + + // --- 3.1. Расчет коэффициента тумана на основе расстояния до поверхности (Distance Fog) --- + // Этот туман работает на больших расстояниях и постепенно исчезает, + // уступая место Z-Far Fog при приближении к планете. + + if (uDistanceToPlanetSurface >= DIST_FOG_MIN && uDistanceToPlanetSurface 0.0) { + // Нормализация Z-глубины: 0.0f при farFogStart, 1.0f при farFogStart + depthRange + farFogFactor = clamp((viewZ - farFogStart) / depthRange, 0.0, 1.0); + } + + // --- 3.3. Объединение --- + + // Когда мы далеко (fogFactor > 0.0), Distance Fog доминирует. + // Когда мы близко (fogFactor = 0.0), Z-Far Fog берет управление. + // Если оба активны, берем максимум (например, когда фрагмент далек от игрока, но игрок все еще в зоне Distance Fog). + //fogFactor = max(fogFactor, farFogFactor); + fogFactor = fogFactor * farFogFactor; + + + // 4. Смешивание цвета с туманом + gl_FragColor = mix(vec4(litColor, 1.0), FOG_COLOR, fogFactor); +} \ No newline at end of file diff --git a/shaders/env_sky.vertex b/shaders/env_sky.vertex new file mode 100644 index 0000000..5903df6 --- /dev/null +++ b/shaders/env_sky.vertex @@ -0,0 +1,12 @@ +attribute vec3 vPosition; + +uniform mat4 ProjectionModelViewMatrix; + +varying vec3 dir; + +void main(){ + vec4 realVertexPos = vec4(vPosition.xyz, 1.0); + gl_Position = ProjectionModelViewMatrix * realVertexPos; + + dir = vPosition; +} \ No newline at end of file diff --git a/shaders/env_sky_desktop.fragment b/shaders/env_sky_desktop.fragment new file mode 100644 index 0000000..c6139e3 --- /dev/null +++ b/shaders/env_sky_desktop.fragment @@ -0,0 +1,11 @@ +uniform samplerCube Texture; +uniform float skyPercent; + +varying vec3 dir; + +void main(){ + vec4 skyBoxColor = textureCube(Texture, normalize(dir)); + vec4 skyColor = vec4(0.0, 0.5, 1.0, 1.0); + gl_FragColor = skyPercent*skyColor + (1.0 - skyPercent) * skyBoxColor; + +} \ No newline at end of file