From 57ff27b0f6305ee237f94499aaa71d33e2a7ccc6 Mon Sep 17 00:00:00 2001 From: Vladislav Khorev Date: Sun, 14 Dec 2025 18:39:45 +0300 Subject: [PATCH] working --- PlanetObject.cpp | 117 +++++++++++++++++---- PlanetObject.h | 1 + shaders/defaultColor_fog2_desktop.fragment | 2 +- 3 files changed, 100 insertions(+), 20 deletions(-) diff --git a/PlanetObject.cpp b/PlanetObject.cpp index f5af864..1c6eab5 100644 --- a/PlanetObject.cpp +++ b/PlanetObject.cpp @@ -49,31 +49,29 @@ namespace ZL { return id1 < id2 ? id1 + "_" + id2 : id2 + "_" + id1; } - std::pair calculateZRange(const Vector3f& shipPosition) { + std::pair PlanetObject::calculateZRange(const Vector3f& shipPosition) { // 1. Вычисление расстояния до поверхности планеты - const Vector3f planetWorldPosition = PLANET_CENTER_OFFSET; - const float distanceToPlanetCenter = (planetWorldPosition - shipPosition).length(); - const float distanceToPlanetSurface = distanceToPlanetCenter - PLANET_RADIUS; - std::cout << "distanceToPlanetSurface " << distanceToPlanetSurface << std::endl; + const float dToPlanetSurface = distanceToPlanetSurface(); + std::cout << "distanceToPlanetSurface " << dToPlanetSurface << std::endl; float currentZNear; float currentZFar; float alpha; // Коэффициент интерполяции для текущего сегмента // Диапазон I: Далеко (FAR) -> Средне (MIDDLE) - if (distanceToPlanetSurface >= TRANSITION_FAR_START) { + if (dToPlanetSurface >= TRANSITION_FAR_START) { // Полностью дальний диапазон currentZNear = FAR_Z_NEAR; currentZFar = FAR_Z_FAR; } - else if (distanceToPlanetSurface > TRANSITION_MIDDLE_START) { + else if (dToPlanetSurface > TRANSITION_MIDDLE_START) { // Плавный переход от FAR к MIDDLE const float transitionLength = TRANSITION_FAR_START - TRANSITION_MIDDLE_START; // Нормализация расстояния, 0 при TRANSITION_FAR_START (Далеко), 1 при TRANSITION_MIDDLE_START (Близко) - float normalizedDist = (distanceToPlanetSurface - TRANSITION_MIDDLE_START) / transitionLength; + float normalizedDist = (dToPlanetSurface - TRANSITION_MIDDLE_START) / transitionLength; alpha = 1.0f - normalizedDist; // alpha = 0 (Далеко) ... 1 (Близко) // Интерполяция: FAR * (1-alpha) + MIDDLE * alpha @@ -82,12 +80,12 @@ namespace ZL { // Диапазон II: Средне (MIDDLE) -> Близко (NEAR) } - else if (distanceToPlanetSurface > TRANSITION_NEAR_END) { + else if (dToPlanetSurface > TRANSITION_NEAR_END) { // Плавный переход от MIDDLE к NEAR const float transitionLength = TRANSITION_MIDDLE_START - TRANSITION_NEAR_END; // Нормализация расстояния, 0 при TRANSITION_MIDDLE_START (Далеко), 1 при TRANSITION_NEAR_END (Близко) - float normalizedDist = (distanceToPlanetSurface - TRANSITION_NEAR_END) / transitionLength; + float normalizedDist = (dToPlanetSurface - TRANSITION_NEAR_END) / transitionLength; alpha = 1.0f - normalizedDist; // alpha = 0 (Далеко) ... 1 (Близко) // Интерполяция: MIDDLE * (1-alpha) + NEAR * alpha @@ -95,12 +93,12 @@ namespace ZL { currentZFar = MIDDLE_Z_FAR * (1.0f - alpha) + NEAR_Z_FAR * alpha; } - else if (distanceToPlanetSurface > TRANSITION_SUPER_NEAR_END) { + else if (dToPlanetSurface > TRANSITION_SUPER_NEAR_END) { // Плавный переход от MIDDLE к NEAR const float transitionLength = TRANSITION_NEAR_END - TRANSITION_SUPER_NEAR_END; // Нормализация расстояния, 0 при TRANSITION_MIDDLE_START (Далеко), 1 при TRANSITION_NEAR_END (Близко) - float normalizedDist = (distanceToPlanetSurface - TRANSITION_SUPER_NEAR_END) / transitionLength; + float normalizedDist = (dToPlanetSurface - TRANSITION_SUPER_NEAR_END) / transitionLength; alpha = 1.0f - normalizedDist; // alpha = 0 (Далеко) ... 1 (Близко) // Интерполяция: MIDDLE * (1-alpha) + NEAR * alpha @@ -109,7 +107,7 @@ namespace ZL { } else { - // Полностью ближний диапазон (distanceToPlanetSurface <= TRANSITION_NEAR_END) + // Полностью ближний диапазон (distancdToPlanetSurfaceeToPlanetSurface <= TRANSITION_NEAR_END) currentZNear = SUPER_NEAR_Z_NEAR; currentZFar = SUPER_NEAR_Z_FAR; } @@ -180,8 +178,8 @@ namespace ZL { // Масштабируем: хотим отклонение от 1.0 до 1.1 // Значит амплитуда = 0.1 - float height = 1.0f; // * 0.2 даст вариацию высоты - //float height = 1.0f - (noiseValue * 0.01f); // * 0.2 даст вариацию высоты + //float height = 1.0f; // * 0.2 даст вариацию высоты + float height = 1.0f - (noiseValue * 0.02f); // * 0.2 даст вариацию высоты return height; } @@ -197,13 +195,81 @@ namespace ZL { return distanceToPlanetSurface > 0.1*TRANSITION_MIDDLE_START; } + /** + * @brief Находит ближайшую точку на плоскости, содержащей треугольник (A, B, C). + * Это проекция точки P на плоскость. + * @return Точка на плоскости (но не обязательно внутри треугольника). + */ + Vector3f projectPointOnPlane(const Vector3f& P, const Vector3f& A, const Vector3f& B, const Vector3f& C) { + Vector3f AB = B + A * (-1.0f); + Vector3f AC = C + A * (-1.0f); + Vector3f N = AB.cross(AC).normalized(); // Нормаль к плоскости треугольника + Vector3f AP = P + A * (-1.0f); + + // Расстояние (со знаком) от P до плоскости: d = N . AP + float distance = N.dot(AP); + + // Проекция: P_proj = P - d * N + Vector3f P_proj = P + N * (-distance); + return P_proj; + } + float PlanetObject::distanceToPlanetSurface() { + // 1. Смещение позиции корабля в локальные координаты планеты const Vector3f planetWorldPosition = PLANET_CENTER_OFFSET; - const float distanceToPlanetCenter = (planetWorldPosition - Environment::shipPosition).length(); - const float distanceToPlanetSurface = distanceToPlanetCenter - PLANET_RADIUS; - return distanceToPlanetSurface; + Vector3f shipLocalPosition = Environment::shipPosition - planetWorldPosition; + // 2. Находим индекс треугольника, над которым находится корабль + // Используем максимальный LOD для наивысшей точности + std::vector targetTriangles = triangleUnderCamera(currentLod); + + if (targetTriangles.empty()) { + // Если не удалось найти треугольник (например, ошибка в triangleUnderCamera + // или корабль очень далеко от сетки), возвращаем старую оценку. + return (shipLocalPosition.length() - PLANET_RADIUS); + } + + // Берем первый найденный треугольник (в пограничных случаях будет выбрана одна сторона) + int tri_index = targetTriangles[0]; + + // 3. Извлекаем вершины + const auto& posData = planetMeshLods[currentLod].vertexData.PositionData; + + // Индексы в плоском массиве PositionData + size_t data_index = tri_index * 3; + if (data_index + 2 >= posData.size()) { + // Ошибка данных + return (shipLocalPosition.length() - PLANET_RADIUS); + } + + const Vector3f& A = posData[data_index]; + const Vector3f& B = posData[data_index + 1]; + const Vector3f& C = posData[data_index + 2]; + + // 4. Находим ближайшую точку на плоскости треугольника + Vector3f P_proj = projectPointOnPlane(shipLocalPosition, A, B, C); + + // 5. Проверяем, находится ли P_proj внутри треугольника (используя барицентрические координаты) + + // ВАЖНОЕ УПРОЩЕНИЕ: В контексте геосферы, если корабль находится "над" треугольником + // (что гарантируется triangleUnderCamera), ближайшая точка на плоскости (P_proj) + // почти всегда будет лежать внутри треугольника A, B, C. + // Если P_ship находится очень далеко от поверхности (что обычно так), + // P_proj почти точно совпадет с P_closest. + + // Для высокой точности, нам бы понадобилась полная функция closestPointOnTriangle, + // но для оценки расстояния в LOD-системах, где P_ship находится далеко от граней, + // P_closest = P_proj — это приемлемая аппроксимация. + + // P_closest = closestPointOnTriangle(shipLocalPosition, A, B, C); + Vector3f P_closest = P_proj; // Используем аппроксимацию P_proj + + // 6. Вычисляем точное расстояние + // Расстояние = |shipLocalPosition - P_closest| + float exactDistance = (shipLocalPosition - P_closest).length(); + + return exactDistance; } @@ -328,7 +394,7 @@ namespace ZL { { renderer.shaderManager.PushShader(defaultShaderName2); - //renderer.RenderUniform1i(textureUniformName, 0); + renderer.RenderUniform1i(textureUniformName, 0); renderer.EnableVertexAttribArray(vPositionName); @@ -343,6 +409,8 @@ namespace ZL { renderer.RotateMatrix(Environment::inverseShipMatrix); renderer.TranslateMatrix(-Environment::shipPosition); + glBindTexture(GL_TEXTURE_2D, sandTexture->getTexID()); + Vector3f color1 = { 1.0, 0.0, 0.0 }; Vector3f color2 = { 1.0, 1.0, 0.0 }; renderer.RenderUniform3fv("uColor", &color1.v[0]); @@ -532,6 +600,16 @@ namespace ZL { result.vertexData.PositionData.reserve(geometry.size() * 3); result.vertexData.NormalData.reserve(geometry.size() * 3); + result.vertexData.TexCoordData.reserve(geometry.size() * 3); // <-- РЕЗЕРВИРУЕМ + //buffer.TexCoord3Data.reserve(triangles.size() * 3); // <-- РЕЗЕРВИРУЕМ + + // Стандартные UV-координаты для покрытия одного треугольника + // Покрывает текстурой всю грань. + const std::array triangleUVs = { + Vector2f(0.0f, 0.0f), + Vector2f(1.0f, 0.0f), + Vector2f(0.0f, 1.0f) + }; result.VertexIDs.reserve(geometry.size() * 3); // Заполняем ID здесь for (const auto& t : geometry) { @@ -541,6 +619,7 @@ namespace ZL { // Заполняем NormalData (нормаль = нормализованная позиция на сфере) result.vertexData.NormalData.push_back(t.data[i].normalized()); + result.vertexData.TexCoordData.push_back(triangleUVs[i]); // Заполняем VertexIDs result.VertexIDs.push_back(t.ids[i]); diff --git a/PlanetObject.h b/PlanetObject.h index 7c4ecdc..8951429 100644 --- a/PlanetObject.h +++ b/PlanetObject.h @@ -109,6 +109,7 @@ namespace ZL { Vector3f calculateSurfaceNormal(Vector3f p_sphere); LodLevel trianglesToVertices(const std::vector& triangles); LodLevel generateSphere(int subdivisions); + std::pair calculateZRange(const Vector3f& shipPosition); std::vector triangleUnderCamera(int lod); std::vector findNeighbors(int index, int lod); diff --git a/shaders/defaultColor_fog2_desktop.fragment b/shaders/defaultColor_fog2_desktop.fragment index bdf64bc..915d8de 100644 --- a/shaders/defaultColor_fog2_desktop.fragment +++ b/shaders/defaultColor_fog2_desktop.fragment @@ -102,5 +102,5 @@ void main() 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(uColor, 1.0); + gl_FragColor = vec4(uColor*textureColor.rgb, 1.0); } \ No newline at end of file