This commit is contained in:
Vladislav Khorev 2025-12-14 18:39:45 +03:00
parent a91d7c04e8
commit 57ff27b0f6
3 changed files with 100 additions and 20 deletions

View File

@ -49,31 +49,29 @@ namespace ZL {
return id1 < id2 ? id1 + "_" + id2 : id2 + "_" + id1;
}
std::pair<float, float> calculateZRange(const Vector3f& shipPosition) {
std::pair<float, float> 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<int> 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<Vector2f, 3> 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]);

View File

@ -109,6 +109,7 @@ namespace ZL {
Vector3f calculateSurfaceNormal(Vector3f p_sphere);
LodLevel trianglesToVertices(const std::vector<Triangle>& triangles);
LodLevel generateSphere(int subdivisions);
std::pair<float, float> calculateZRange(const Vector3f& shipPosition);
std::vector<int> triangleUnderCamera(int lod);
std::vector<int> findNeighbors(int index, int lod);

View File

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