Cool working

This commit is contained in:
Vladislav Khorev 2025-12-13 23:17:03 +03:00
parent 27fb7a448c
commit af550f56a7
12 changed files with 379 additions and 11 deletions

View File

@ -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<float>(Environment::width) / static_cast<float>(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);
}

2
Game.h
View File

@ -32,7 +32,7 @@ namespace ZL {
private:
void processTickCount();
void drawScene();
void drawCubemap();
void drawCubemap(float skyPercent);
void drawShip();
void drawBoxes();
void drawUI();

View File

@ -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<Texture>(CreateTextureDataFromPng("./resources/sand.png", ""));
//sandTexture = std::make_unique<Texture>(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<float>(Environment::width) / static_cast<float>(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<float>(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<float>(screenX), static_cast<float>(screenY), 0.0f);
renderer.TranslateMatrix(centerPos);
renderer.RenderUniform1f("uCenterRadius", 0.f);
renderer.RenderUniform3fv("uCenterPos", &centerPos.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<float>(Environment::width) / static_cast<float>(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", &centerPos.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();
}

View File

@ -48,6 +48,9 @@ namespace ZL {
VertexDataStruct planetMesh;
VertexRenderStruct planetRenderStruct;
VertexRenderStruct planetAtmosphere;
std::shared_ptr<Texture> 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:

View File

@ -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)

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 <DIST_FOG_MAX) {
// Нормализация: 0.0f при DIST_FOG_MAX, 1.0f при DIST_FOG_MIN
float distRange = DIST_FOG_MAX - DIST_FOG_MIN;
float distNormalized = clamp((uDistanceToPlanetSurface - DIST_FOG_MIN) / distRange, 0.0, 1.0);
// alpha = 0.0 (Далеко) ... 1.0 (Близко к 1000.f)
fogFactor = 1.0 - distNormalized;
}
if (uDistanceToPlanetSurface < DIST_FOG_MIN)
{
fogFactor = 1.0;
}
// Если uDistanceToPlanetSurface < 1000.0f, то fogFactor = 0.0f (пока не пересчитан ниже),
// что позволяет Z-Far Fog взять контроль.
// --- 3.2. Расчет коэффициента тумана на основе Z-глубины (Z-Far Fog) ---
// Этот туман работает всегда, но его эффект усиливается при уменьшении uCurrentZFar,
// гарантируя, что все, что подходит к границе uCurrentZFar, будет скрыто.
// Точка начала тумана: 90% от uCurrentZFar
float farFogStart = 2000.0;
// Длина перехода тумана: 10% от uCurrentZFar
float depthRange = 2500.0;
float farFogFactor = 0.0;
if (depthRange > 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);
}

12
shaders/env_sky.vertex Normal file
View File

@ -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;
}

View File

@ -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;
}