lod 0 and 1
This commit is contained in:
parent
7a1961b5d1
commit
16ba536481
@ -31,7 +31,7 @@ bool Environment::tapDownHold = false;
|
||||
Vector2f Environment::tapDownStartPos = { 0, 0 };
|
||||
Vector2f Environment::tapDownCurrentPos = { 0, 0 };
|
||||
|
||||
Vector3f Environment::shipPosition = {0,0,45000.f};
|
||||
Vector3f Environment::shipPosition = {100,100,45000.f};
|
||||
|
||||
float Environment::shipVelocity = 0.f;
|
||||
|
||||
|
||||
2
Game.cpp
2
Game.cpp
@ -159,6 +159,7 @@ namespace ZL
|
||||
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);
|
||||
renderer.shaderManager.AddShaderFromFiles("defaultColor2", "./shaders/defaultColor_fog2.vertex", "./shaders/defaultColor_fog2_desktop.fragment", CONST_ZIP_FILE);
|
||||
|
||||
#endif
|
||||
|
||||
@ -509,6 +510,7 @@ namespace ZL
|
||||
|
||||
//gameObjects.updateScene(delta);
|
||||
sparkEmitter.update(static_cast<float>(delta));
|
||||
planetObject.update(static_cast<float>(delta));
|
||||
|
||||
if (Environment::tapDownHold) {
|
||||
|
||||
|
||||
220
PlanetObject.cpp
220
PlanetObject.cpp
@ -210,12 +210,18 @@ namespace ZL {
|
||||
|
||||
void PlanetObject::init() {
|
||||
|
||||
planetMesh = generateSphere(8);
|
||||
planetMeshLods[0] = generateSphere(0);
|
||||
|
||||
planetMesh.Scale(PLANET_RADIUS);
|
||||
planetMesh.Move(PLANET_CENTER_OFFSET);
|
||||
planetMeshLods[0].Scale(PLANET_RADIUS);
|
||||
planetMeshLods[0].Move(PLANET_CENTER_OFFSET);
|
||||
|
||||
planetRenderStruct.data = planetMesh;
|
||||
planetMeshLods[1] = generateSphere(1);
|
||||
|
||||
planetMeshLods[1].Scale(PLANET_RADIUS);
|
||||
planetMeshLods[1].Move(PLANET_CENTER_OFFSET);
|
||||
|
||||
|
||||
planetRenderStruct.data = planetMeshLods[1];
|
||||
planetRenderStruct.RefreshVBO();
|
||||
|
||||
sandTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/sand.png", ""));
|
||||
@ -239,6 +245,7 @@ namespace ZL {
|
||||
prepareDrawData();
|
||||
|
||||
static const std::string defaultShaderName = "defaultColor";
|
||||
static const std::string defaultShaderName2 = "defaultColor2";
|
||||
static const std::string vPositionName = "vPosition";
|
||||
static const std::string vColorName = "vColor";
|
||||
static const std::string vNormalName = "vNormal";
|
||||
@ -311,7 +318,43 @@ namespace ZL {
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
|
||||
drawAtmosphere(renderer);
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
//--------------------------
|
||||
|
||||
if (planetRenderRedStruct.data.PositionData.size() > 0)
|
||||
{
|
||||
|
||||
renderer.shaderManager.PushShader(defaultShaderName2);
|
||||
//renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
renderer.DrawVertexRenderStruct(planetRenderRedStruct);
|
||||
//glDisable(GL_BLEND);
|
||||
CheckGlError();
|
||||
|
||||
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
|
||||
}
|
||||
|
||||
//drawAtmosphere(renderer);
|
||||
}
|
||||
|
||||
void PlanetObject::drawAtmosphere(Renderer& renderer) {
|
||||
@ -371,6 +414,16 @@ namespace ZL {
|
||||
|
||||
void PlanetObject::update(float deltaTimeMs) {
|
||||
|
||||
auto lr = triangleUnderCamera(currentLod);
|
||||
planetRenderRedStruct.data.PositionData.clear();
|
||||
for (int i : lr)
|
||||
{
|
||||
planetRenderRedStruct.data.PositionData.push_back(planetMeshLods[currentLod].PositionData[i * 3]);
|
||||
planetRenderRedStruct.data.PositionData.push_back(planetMeshLods[currentLod].PositionData[i * 3+1]);
|
||||
planetRenderRedStruct.data.PositionData.push_back(planetMeshLods[currentLod].PositionData[i * 3+2]);
|
||||
}
|
||||
|
||||
planetRenderRedStruct.RefreshVBO();
|
||||
}
|
||||
|
||||
std::vector<Triangle> PlanetObject::subdivideTriangles(const std::vector<Triangle>& inputTriangles) {
|
||||
@ -578,5 +631,162 @@ namespace ZL {
|
||||
}
|
||||
|
||||
|
||||
float check_spherical_side(const Vector3f& V1, const Vector3f& V2, const Vector3f& P, const Vector3f& V3, float epsilon = 1e-6f) {
|
||||
// Нормаль к плоскости, проходящей через O, V1 и V2
|
||||
Vector3f N_plane = V1.cross(V2);
|
||||
|
||||
// Расстояние P до плоскости V1V2 (со знаком)
|
||||
float sign_P = P.dot(N_plane);
|
||||
|
||||
// Расстояние V3 до плоскости V1V2 (со знаком)
|
||||
float sign_V3 = V3.dot(N_plane);
|
||||
|
||||
// Если знаки совпадают, P находится на той же стороне, что и V3.
|
||||
// Возвращаем произведение знаков.
|
||||
return sign_P * sign_V3;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Проверяет, находится ли точка P внутри сферического треугольника (V1, V2, V3).
|
||||
* @param P Проверяемая точка (нормализованная).
|
||||
* @param V1, V2, V3 Нормализованные вершины треугольника.
|
||||
* @return true, если внутри или на границе.
|
||||
*/
|
||||
bool is_inside_spherical_triangle(const Vector3f& P, const Vector3f& V1, const Vector3f& V2, const Vector3f& V3, float epsilon) {
|
||||
// Точка P должна быть на одной стороне от всех трех граней относительно третьей вершины.
|
||||
|
||||
// 1. Проверка относительно V1V2 (эталон V3)
|
||||
if (check_spherical_side(V1, V2, P, V3, epsilon) < -epsilon) return false;
|
||||
|
||||
// 2. Проверка относительно V2V3 (эталон V1)
|
||||
if (check_spherical_side(V2, V3, P, V1, epsilon) < -epsilon) return false;
|
||||
|
||||
// 3. Проверка относительно V3V1 (эталон V2)
|
||||
if (check_spherical_side(V3, V1, P, V2, epsilon) < -epsilon) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
std::vector<int> find_sub_triangle_spherical(const Vector3f& a_orig, const Vector3f& b_orig, const Vector3f& c_orig, const Vector3f& px_orig) {
|
||||
const float EPSILON = 1e-6f;
|
||||
std::vector<int> result;
|
||||
|
||||
// 1. Нормализация всех вершин и проверяемой точки для работы на сфере (радиус 1)
|
||||
const Vector3f a = a_orig.normalized();
|
||||
const Vector3f b = b_orig.normalized();
|
||||
const Vector3f c = c_orig.normalized();
|
||||
|
||||
// Точка pxx должна быть спроецирована на сферу.
|
||||
const Vector3f pxx_normalized = px_orig.normalized();
|
||||
|
||||
// 2. Вычисляем нормализованные середины (вершины внутренних треугольников)
|
||||
const Vector3f m_ab = ((a + b) * 0.5f).normalized();
|
||||
const Vector3f m_bc = ((b + c) * 0.5f).normalized();
|
||||
const Vector3f m_ac = ((a + c) * 0.5f).normalized();
|
||||
|
||||
// 3. Определяем 4 подтреугольника
|
||||
|
||||
// Delta_0: (a, m_ab, m_ac)
|
||||
if (is_inside_spherical_triangle(pxx_normalized, a, m_ab, m_ac, EPSILON)) {
|
||||
result.push_back(0);
|
||||
}
|
||||
|
||||
// Delta_1: (m_ab, b, m_bc)
|
||||
if (is_inside_spherical_triangle(pxx_normalized, m_ab, b, m_bc, EPSILON)) {
|
||||
result.push_back(1);
|
||||
}
|
||||
|
||||
// Delta_2: (m_ac, m_bc, c)
|
||||
if (is_inside_spherical_triangle(pxx_normalized, m_ac, m_bc, c, EPSILON)) {
|
||||
result.push_back(2);
|
||||
}
|
||||
|
||||
// Delta_3: (m_ab, m_bc, m_ac) - Внутренний
|
||||
if (is_inside_spherical_triangle(pxx_normalized, m_ab, m_bc, m_ac, EPSILON)) {
|
||||
result.push_back(3);
|
||||
}
|
||||
|
||||
// Если исходный pxx точно лежит на луче из O(0,0,0) и внутри исходного треугольника,
|
||||
// то pxx_normalized гарантированно попадет в один или несколько (на границе)
|
||||
// из 4х подтреугольников.
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<int> PlanetObject::triangleUnderCamera(int lod)
|
||||
{
|
||||
std::vector<int> r;
|
||||
if (lod == 0)
|
||||
{
|
||||
if (Environment::shipPosition.v[1] >= 0)
|
||||
{
|
||||
if (Environment::shipPosition.v[0] >= 0 && Environment::shipPosition.v[2] >= 0)
|
||||
{
|
||||
r.push_back(0);
|
||||
}
|
||||
if (Environment::shipPosition.v[0] >= 0 && Environment::shipPosition.v[2] <= 0)
|
||||
{
|
||||
r.push_back(1);
|
||||
}
|
||||
if (Environment::shipPosition.v[0] <= 0 && Environment::shipPosition.v[2] <= 0)
|
||||
{
|
||||
r.push_back(2);
|
||||
}
|
||||
if (Environment::shipPosition.v[0] <= 0 && Environment::shipPosition.v[2] >= 0)
|
||||
{
|
||||
r.push_back(3);
|
||||
}
|
||||
}
|
||||
if (Environment::shipPosition.v[1] <= 0)
|
||||
{
|
||||
if (Environment::shipPosition.v[0] >= 0 && Environment::shipPosition.v[2] >= 0)
|
||||
{
|
||||
r.push_back(4);
|
||||
}
|
||||
if (Environment::shipPosition.v[0] <= 0 && Environment::shipPosition.v[2] >= 0)
|
||||
{
|
||||
r.push_back(5);
|
||||
}
|
||||
if (Environment::shipPosition.v[0] <= 0 && Environment::shipPosition.v[2] <= 0)
|
||||
{
|
||||
r.push_back(6);
|
||||
}
|
||||
if (Environment::shipPosition.v[0] >= 0 && Environment::shipPosition.v[2] <= 0)
|
||||
{
|
||||
r.push_back(7);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if (lod == 1)
|
||||
{
|
||||
std::vector<int> r0 = triangleUnderCamera(0);
|
||||
|
||||
for (int tri0 : r0)
|
||||
{
|
||||
Vector3f a = planetMeshLods[0].PositionData[tri0 * 3];
|
||||
Vector3f b = planetMeshLods[0].PositionData[tri0 * 3+1];
|
||||
Vector3f c = planetMeshLods[0].PositionData[tri0 * 3+2];
|
||||
|
||||
std::vector<int> result = find_sub_triangle_spherical(a, b, c, Environment::shipPosition);
|
||||
|
||||
if (result.size() == 0)
|
||||
{
|
||||
std::cout << "???" << std::endl;
|
||||
}
|
||||
|
||||
for (int trix : result)
|
||||
{
|
||||
r.push_back(tri0 * 4 + trix);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace ZL
|
||||
@ -45,8 +45,11 @@ namespace ZL {
|
||||
PerlinNoise perlin;
|
||||
PerlinNoise colorPerlin;
|
||||
void prepareDrawData();
|
||||
VertexDataStruct planetMesh;
|
||||
std::array< VertexDataStruct, 2> planetMeshLods;
|
||||
//VertexDataStruct planetMeshLod0;
|
||||
//VertexDataStruct planetMeshLod1;
|
||||
VertexRenderStruct planetRenderStruct;
|
||||
VertexRenderStruct planetRenderRedStruct;
|
||||
|
||||
VertexRenderStruct planetAtmosphere;
|
||||
|
||||
@ -70,10 +73,14 @@ namespace ZL {
|
||||
private:
|
||||
bool drawDataDirty = true;
|
||||
|
||||
int currentLod = 1;
|
||||
|
||||
std::vector<Triangle> subdivideTriangles(const std::vector<Triangle>& inputTriangles);
|
||||
Vector3f calculateSurfaceNormal(Vector3f p_sphere);
|
||||
VertexDataStruct trianglesToVertices(const std::vector<Triangle>& triangles);
|
||||
VertexDataStruct generateSphere(int subdivisions);
|
||||
|
||||
std::vector<int> triangleUnderCamera(int lod);
|
||||
};
|
||||
|
||||
} // namespace ZL
|
||||
6
ZLMath.h
6
ZLMath.h
@ -13,6 +13,9 @@ namespace ZL {
|
||||
|
||||
Vector4f normalized() const {
|
||||
double norm = std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]);
|
||||
if (norm <= 0.000001f) {
|
||||
return { 0,0, 0, 0};
|
||||
}
|
||||
Vector4f r;
|
||||
|
||||
r.v[0] = v[0] / norm;
|
||||
@ -43,6 +46,9 @@ namespace ZL {
|
||||
|
||||
Vector3f normalized() const {
|
||||
double norm = std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
|
||||
if (norm <= 0.000001f) {
|
||||
return { 0,0,0 };
|
||||
}
|
||||
Vector3f r;
|
||||
|
||||
r.v[0] = v[0] / norm;
|
||||
|
||||
35
shaders/defaultColor_fog2.vertex
Normal file
35
shaders/defaultColor_fog2.vertex
Normal file
@ -0,0 +1,35 @@
|
||||
// Вершинный шейдер (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)
|
||||
varying vec3 pos;
|
||||
|
||||
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;
|
||||
|
||||
pos = vPosition.xyz;
|
||||
|
||||
gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
||||
|
||||
normal = normalize((ModelViewMatrix * vec4(vNormal, 0.0)).xyz);
|
||||
color = vColor;
|
||||
TexCoord = vTexCoord;
|
||||
}
|
||||
106
shaders/defaultColor_fog2_desktop.fragment
Normal file
106
shaders/defaultColor_fog2_desktop.fragment
Normal file
@ -0,0 +1,106 @@
|
||||
// ---Фрагментный шейдер (Fragment Shader)
|
||||
|
||||
varying vec3 color;
|
||||
varying vec3 normal;
|
||||
varying vec2 TexCoord;
|
||||
varying float viewZ;
|
||||
varying vec3 pos;
|
||||
|
||||
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.f;//uCurrentZFar * 0.7;
|
||||
// Длина перехода тумана: 10% от uCurrentZFar
|
||||
float depthRange = 2000.f;//uCurrentZFar * 0.25;
|
||||
|
||||
if (abs(uDistanceToPlanetSurface) < 410.f)
|
||||
{
|
||||
farFogStart = 1800.f * abs(uDistanceToPlanetSurface-10.f) * 0.0025 + 200.f;
|
||||
depthRange = farFogStart;
|
||||
}
|
||||
if (abs(uDistanceToPlanetSurface) < 10.f)
|
||||
{
|
||||
farFogStart = 200.f;
|
||||
depthRange = 200.f;
|
||||
}
|
||||
|
||||
float farFogFactor = 0.0;
|
||||
|
||||
if (depthRange > 0.0) {
|
||||
// Нормализация Z-глубины: 0.0f при farFogStart, 1.0f при farFogStart + depthRange
|
||||
farFogFactor = clamp((abs(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. Смешивание цвета с туманом
|
||||
|
||||
//vec3 mountainColor = vec3((length(pos+vec3(0.0,0.0,45000.0))-20000.0)/100.0, 0.5,0.0);
|
||||
gl_FragColor = mix(vec4(finalColor.rgb, 0.5), FOG_COLOR, fogFactor);
|
||||
//gl_FragColor = vec4((length(pos+vec3(0.0,0.0,45000.0))-20000.0)/100.0, 0.0,0.0, 1.0);
|
||||
//gl_FragColor = vec4(fogFactor, 0.5,0.5, 1.0);
|
||||
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user