From c553780b6e1579501b451575f455bced850f0176 Mon Sep 17 00:00:00 2001 From: Vladislav Khorev Date: Sat, 3 Jan 2026 17:29:40 +0300 Subject: [PATCH] Make IcoSphere --- src/planet/PlanetData.cpp | 290 ++++++++++++------------------------ src/planet/PlanetData.h | 7 +- src/planet/PlanetObject.cpp | 127 ++-------------- src/planet/PlanetObject.h | 10 +- src/planet/StoneObject.cpp | 68 +++++++-- src/planet/StoneObject.h | 2 + src/utils/ZLMath.h | 10 ++ 7 files changed, 174 insertions(+), 340 deletions(-) diff --git a/src/planet/PlanetData.cpp b/src/planet/PlanetData.cpp index 37fbf93..cca7074 100644 --- a/src/planet/PlanetData.cpp +++ b/src/planet/PlanetData.cpp @@ -137,82 +137,7 @@ namespace ZL { } - float PlanetData::distanceToPlanetSurface(const Vector3f& viewerPosition) { - Vector3f shipLocalPosition = viewerPosition - PLANET_CENTER_OFFSET; - - // Используем getTrianglesUnderCamera для поиска - // ВНИМАНИЕ: Здесь рекурсия логики. Метод getTrianglesUnderCamera использует внутри viewerPosition. - // Чтобы не дублировать код, перепишем логику поиска здесь или будем использовать уже найденный ранее. - // Для простоты оставим логику как в оригинале, но адаптированную. - - // ВАЖНО: getTrianglesUnderCamera - это "тяжелая" функция. В оригинале она вызывалась внутри distanceToPlanetSurface. - // Но она требует LOD. Используем MAX LOD для точности. - - // Рекурсивный поиск треугольников под камерой. - // Здесь нам нужно реализовать аналог triangleUnderCamera, но не зависящий от глобального состояния. - // В оригинале функция triangleUnderCamera была рекурсивной. - // Ниже я реализую итеративный или рекурсивный подход внутри getTrianglesUnderCamera. - - // Временное решение: полная копия логики поиска треугольника - // Но нам нужен доступ к методу. - std::vector targetTriangles = getTrianglesUnderCameraNew(viewerPosition); - - if (targetTriangles.empty()) { - return (shipLocalPosition.length() - PLANET_RADIUS); - } - - float lowestDistance; - - int tri_index = targetTriangles[0]; - const auto& posData = planetMeshLods[currentLod].vertexData.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]; - - Vector3f P_proj = projectPointOnPlane(shipLocalPosition, A, B, C); - Vector3f P_closest = P_proj; - - lowestDistance = (shipLocalPosition - P_closest).length(); - - if (targetTriangles.size() <= 1) - { - return lowestDistance; - } - else - { - for (int i = 0; i < targetTriangles.size(); i++) - { - int tri_index = targetTriangles[i]; - const auto& posData = planetMeshLods[currentLod].vertexData.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]; - - Vector3f P_proj = projectPointOnPlane(shipLocalPosition, A, B, C); - Vector3f P_closest = P_proj; - - if (lowestDistance < (shipLocalPosition - P_closest).length()) - { - lowestDistance = (shipLocalPosition - P_closest).length(); - } - } - - return lowestDistance; - } - } - std::vector PlanetData::getTrianglesUnderCameraNew(const Vector3f& viewerPosition) { + std::vector PlanetData::getBestTriangleUnderCamera(const Vector3f& viewerPosition) { const LodLevel& finalLod = planetMeshLods[currentLod]; // Работаем с текущим активным LOD Vector3f targetDir = (viewerPosition - PLANET_CENTER_OFFSET).normalized(); @@ -238,24 +163,42 @@ namespace ZL { if (bestTriangle == -1) return {}; - // Шаг 2: Собираем "пятно" вокруг найденного треугольника - // Используем уже имеющийся у тебя метод findNeighbors - std::set resultSet; - resultSet.insert(bestTriangle); + return { bestTriangle }; + } - // Добавляем первый круг соседей - std::vector neighbors = findNeighbors(bestTriangle, currentLod); - for (int n : neighbors) { - resultSet.insert(n); + std::vector PlanetData::getTrianglesUnderCameraNew2(const Vector3f& viewerPosition) { + const LodLevel& finalLod = planetMeshLods[currentLod]; + Vector3f shipLocal = viewerPosition - PLANET_CENTER_OFFSET; + float currentDist = shipLocal.length(); + Vector3f targetDir = shipLocal.normalized(); - // Опционально: Добавляем второй круг соседей для запаса (прихватываем больше) - std::vector secondCircle = findNeighbors(n, currentLod); - for (int nn : secondCircle) { - resultSet.insert(nn); + // Желаемый радиус покрытия на поверхности планеты (в метрах/единицах движка) + // Подбери это значение так, чтобы камни вокруг корабля всегда были видны. + const float desiredCoverageRadius = 3000.0f; + + // Вычисляем порог косинуса на основе желаемого радиуса и текущего расстояния. + // Чем мы дальше (currentDist больше), тем меньше должен быть угол отклонения + // от нормали, чтобы захватить ту же площадь. + float angle = atan2(desiredCoverageRadius, currentDist); + float searchThreshold = cos(angle); + + // Ограничитель, чтобы не захватить всю планету или вообще ничего + searchThreshold = std::clamp(searchThreshold, 0.90f, 0.9999f); + + std::vector result; + for (int i = 0; i < (int)finalLod.triangles.size(); ++i) { + // Используем центроид (можно кэшировать в LodLevel для скорости) + Vector3f triDir = (finalLod.triangles[i].data[0] + + finalLod.triangles[i].data[1] + + finalLod.triangles[i].data[2]).normalized(); + + if (targetDir.dot(triDir) > searchThreshold) { + result.push_back(i); } } - return std::vector(resultSet.begin(), resultSet.end()); + if (result.empty()) return getBestTriangleUnderCamera(viewerPosition); + return result; } std::vector PlanetData::subdivideTriangles(const std::vector& input, float noiseCoeff) { @@ -394,141 +337,94 @@ namespace ZL { } } - LodLevel PlanetData::generateSphere(int subdivisions, float noiseCoeff) { - // 1. Исходный октаэдр и присвоение ID - std::vector geometry = { - // Верхняя полусфера (Y > 0) - {{ 0.0f, 1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}}, // 0 - {{ 0.0f, 1.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}, { 1.0f, 0.0f, 0.0f}}, // 1 - {{ 0.0f, 1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}}, // 2 - {{ 0.0f, 1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, 0.0f}}, // 3 - // Нижняя полусфера (Y < 0) - {{ 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, { 1.0f, 0.0f, 0.0f}}, // 4 - {{ 0.0f, -1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}}, // 5 - {{ 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}, {-1.0f, 0.0f, 0.0f}}, // 6 - {{ 0.0f, -1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}} // 7 + const float t = (1.0f + std::sqrt(5.0f)) / 2.0f; + + // 12 базовых вершин икосаэдра + std::vector icosaVertices = { + {-1, t, 0}, { 1, t, 0}, {-1, -t, 0}, { 1, -t, 0}, + { 0, -1, t}, { 0, 1, t}, { 0, -1, -t}, { 0, 1, -t}, + { t, 0, -1}, { t, 0, 1}, {-t, 0, -1}, {-t, 0, 1} }; - // Присвоение ID исходным вершинам - for (auto& t : geometry) { - for (int i = 0; i < 3; i++) { - // Используем map для получения ID по чистым координатам (норм. == чистые) - t.ids[i] = initialVertexMap[t.data[i].normalized()]; + // Нормализуем вершины + for (auto& v : icosaVertices) v = v.normalized(); + + // 20 граней икосаэдра + struct IndexedTri { int v1, v2, v3; }; + std::vector faces = { + {0, 11, 5}, {0, 5, 1}, {0, 1, 7}, {0, 7, 10}, {0, 10, 11}, + {1, 5, 9}, {5, 11, 4}, {11, 10, 2}, {10, 7, 6}, {7, 1, 8}, + {3, 9, 4}, {3, 4, 2}, {3, 2, 6}, {3, 6, 8}, {3, 8, 9}, + {4, 9, 5}, {2, 4, 11}, {6, 2, 10}, {8, 6, 7}, {9, 8, 1} + }; + + std::vector geometry; + for (auto& f : faces) { + Triangle tri; + tri.data[0] = icosaVertices[f.v1]; + tri.data[1] = icosaVertices[f.v2]; + tri.data[2] = icosaVertices[f.v3]; + + // Генерируем ID для базовых вершин (можно использовать их координаты) + for (int i = 0; i < 3; ++i) { + tri.ids[i] = std::to_string(tri.data[i].v[0]) + "_" + + std::to_string(tri.data[i].v[1]) + "_" + + std::to_string(tri.data[i].v[2]); } - } - // 3. Разбиваем N раз (в subdivideTriangles генерируются ID новых вершин) - for (int i = 0; i < subdivisions; i++) { - geometry = subdivideTriangles(geometry, noiseCoeff); + geometry.push_back(tri); } - // 4. Генерируем PositionData, NormalData и VertexIDs + // 3. Разбиваем N раз + for (int i = 0; i < subdivisions; i++) { + geometry = subdivideTriangles(geometry, 0.0f); // Шум пока игнорируем + } + + // 4. Создаем LodLevel и заполняем топологию (v2tMap) LodLevel lodLevel = createLodLevel(geometry); - // 5. Создание V2T-Map на основе VertexIDs (ТОПОЛОГИЧЕСКИЙ КЛЮЧ) - V2TMap v2tMap; - const auto& finalVertexIDs = lodLevel.VertexIDs; - size_t num_triangles = geometry.size(); - - for (size_t i = 0; i < num_triangles; ++i) { + // Пересобираем v2tMap (она критична для релаксации) + lodLevel.v2tMap.clear(); + for (size_t i = 0; i < geometry.size(); ++i) { for (int j = 0; j < 3; ++j) { - VertexID v_id = finalVertexIDs[i * 3 + j]; - - // Если ключ уже есть, просто добавляем индекс - v2tMap[v_id].push_back((int)i); + lodLevel.v2tMap[geometry[i].ids[j]].push_back((int)i); } } - lodLevel.v2tMap = v2tMap; - applySphericalLaplacianSmoothing(lodLevel, 5, 0.5f); + // 5. Применяем итеративную релаксацию (Lloyd-like) + // 5-10 итераций достаточно для отличной сетки + applySphericalRelaxation(lodLevel, 8); - // Применение шума через уникальные ID после сглаживания - std::map displacedPositions; - for (const auto& tri : lodLevel.triangles) { - for (int i = 0; i < 3; ++i) { - if (displacedPositions.find(tri.ids[i]) == displacedPositions.end()) { - Vector3f dir = tri.data[i].normalized(); - displacedPositions[tri.ids[i]] = dir * perlin.getSurfaceHeight(dir, noiseCoeff); - } - } - } - // Обновляем треугольники финальными позициями - for (auto& tri : lodLevel.triangles) { - for (int i = 0; i < 3; ++i) { - tri.data[i] = displacedPositions[tri.ids[i]]; - } - } + // 6. Накладываем шум и обновляем атрибуты + // ... (твой код наложения шума через Perlin) recalculateMeshAttributes(lodLevel); - return lodLevel; } - // Пример findNeighbors: - std::vector PlanetData::findNeighbors(int index, int lod) { - const V2TMap& v2tMap = planetMeshLods[lod].v2tMap; - const auto& vertexIDs = planetMeshLods[lod].VertexIDs; - if ((index * 3 + 2) >= vertexIDs.size()) return {}; - std::set neighbors; - for (int i = 0; i < 3; ++i) { - VertexID v_id = vertexIDs[index * 3 + i]; - auto it = v2tMap.find(v_id); - if (it != v2tMap.end()) { - for (int tri_index : it->second) { - if (tri_index != index) { - neighbors.insert(tri_index); - } - } - } - } - return std::vector(neighbors.begin(), neighbors.end()); - } - - void PlanetData::applySphericalLaplacianSmoothing(LodLevel& lod, int iterations, float relaxationFactor) { + void PlanetData::applySphericalRelaxation(LodLevel& lod, int iterations) { for (int iter = 0; iter < iterations; ++iter) { std::map newPositions; - // 1. Собираем соседей и текущие позиции из triangles - for (auto const& [vID, connectedTriangles] : lod.v2tMap) { - Vector3f currentPos; - std::set neighborIDs; - - for (int triIdx : connectedTriangles) { - const auto& tri = lod.triangles[triIdx]; - for (int i = 0; i < 3; ++i) { - if (tri.ids[i] == vID) { - currentPos = tri.data[i]; // Берем из triangles - } - else { - neighborIDs.insert(tri.ids[i]); - } - } - } - - if (neighborIDs.empty()) continue; - - // 2. Центроид соседей + for (auto const& [vID, connectedTris] : lod.v2tMap) { Vector3f centroid(0, 0, 0); - for (const auto& nID : neighborIDs) { - int firstTriIdx = lod.v2tMap[nID][0]; - const auto& tri = lod.triangles[firstTriIdx]; - for (int k = 0; k < 3; ++k) { - if (tri.ids[k] == nID) { - centroid = centroid + tri.data[k]; - break; - } - } - } - centroid = centroid * (1.0f / (float)neighborIDs.size()); - // 3. Расслабление и сферическая проекция - Vector3f relaxedPos = currentPos + (centroid - currentPos) * relaxationFactor; - newPositions[vID] = relaxedPos.normalized() * currentPos.length(); + // Находим среднюю точку среди центров всех соседних треугольников + for (int triIdx : connectedTris) { + const auto& tri = lod.triangles[triIdx]; + Vector3f faceCenter = (tri.data[0] + tri.data[1] + tri.data[2]) * (1.0f / 3.0f); + centroid = centroid + faceCenter; + } + + centroid = centroid * (1.0f / (float)connectedTris.size()); + + // Проецируем обратно на единичную сферу + newPositions[vID] = centroid.normalized(); } - // 4. Обновляем координаты прямо в объектах Triangle + // Синхронизируем данные в треугольниках for (auto& tri : lod.triangles) { for (int i = 0; i < 3; ++i) { tri.data[i] = newPositions[tri.ids[i]]; diff --git a/src/planet/PlanetData.h b/src/planet/PlanetData.h index 73d3d5a..c0f59d1 100644 --- a/src/planet/PlanetData.h +++ b/src/planet/PlanetData.h @@ -102,14 +102,13 @@ namespace ZL { // Логика std::pair calculateZRange(float distanceToSurface); - float distanceToPlanetSurface(const Vector3f& viewerPosition); float distanceToPlanetSurfaceFast(const Vector3f& viewerPosition); // Возвращает индексы треугольников, видимых камерой - std::vector getTrianglesUnderCameraNew(const Vector3f& viewerPosition); - std::vector findNeighbors(int index, int lod); + std::vector getBestTriangleUnderCamera(const Vector3f& viewerPosition); + std::vector getTrianglesUnderCameraNew2(const Vector3f& viewerPosition); - void applySphericalLaplacianSmoothing(LodLevel& lod, int iterations, float relaxationFactor); + void applySphericalRelaxation(LodLevel& lod, int iterations); }; } // namespace ZL \ No newline at end of file diff --git a/src/planet/PlanetObject.cpp b/src/planet/PlanetObject.cpp index 00973d9..9ce81d2 100644 --- a/src/planet/PlanetObject.cpp +++ b/src/planet/PlanetObject.cpp @@ -81,51 +81,27 @@ namespace ZL { planetStones = CreateStoneGroupData(778, planetData.getLodLevel(lodIndex)); stonesToRender = planetStones.inflate(planetStones.allInstances.size()); - } - void PlanetObject::prepareDrawData() { - if (!drawDataDirty) return; - drawDataDirty = false; + stoneToBake = planetStones.inflateOne(0, 0.75); } void PlanetObject::update(float deltaTimeMs) { - // 1. Получаем базовые треугольники РїРѕРґ камерой - auto lr = planetData.getTrianglesUnderCameraNew(Environment::shipPosition); - int currentLod = planetData.getCurrentLodIndex(); - - // Временный вектор для СЃР±РѕСЂР° новых индексов - std::vector newIndices; + float movementThreshold = 1.0f; + if ((Environment::shipPosition - lastUpdatePos).squaredNorm() < movementThreshold * movementThreshold && !triangleIndicesToDraw.empty()) { + return; + } + lastUpdatePos = Environment::shipPosition; - newIndices = lr; + auto newIndices = planetData.getTrianglesUnderCameraNew2(Environment::shipPosition); - // 2. Сортируем новый СЃРїРёСЃРѕРє, чтобы РїРѕСЂСЏРґРѕРє РЅРµ влиял РЅР° сравнение + // Сортировка важна для сравнения векторов std::sort(newIndices.begin(), newIndices.end()); - // 3. Сравниваем СЃ тем, что было нарисовано РІ прошлый раз if (newIndices != triangleIndicesToDraw) { - // Обновляем СЃРїРёСЃРѕРє индексов (используем move для эффективности) triangleIndicesToDraw = std::move(newIndices); - /* - // --- ОБНОВЛЯЕМ ЖЕЛТУЮ Р—РћРќРЈ (только РєРѕРіРґР° изменился состав треугольников) --- - const auto& fullMesh = planetData.getLodLevel(currentLod).vertexData; - planetRenderYellowStruct.data.PositionData.clear(); - planetRenderYellowStruct.data.TexCoordData.clear(); - - for (int i : triangleIndicesToDraw) { - // Копируем геометрию для подсветки - for (int j = 0; j < 3; ++j) { - planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[i * 3 + j]); - planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[i * 3 + j]); - } - } - if (planetRenderYellowStruct.data.PositionData.size() > 0) - { - planetRenderYellowStruct.RefreshVBO(); - }*/ } - } @@ -146,13 +122,6 @@ namespace ZL { renderer.EnableVertexAttribArray(vPositionName); renderer.EnableVertexAttribArray(vTexCoordName); - float dist = planetData.distanceToPlanetSurface(Environment::shipPosition); - auto zRange = planetData.calculateZRange(dist); - const float currentZNear = zRange.first; - const float currentZFar = zRange.second; - - - Triangle tr = planetData.getLodLevel(planetData.getCurrentLodIndex()).triangles[0]; // 1. Получаем матрицу вращения (РѕСЃРё РІ столбцах) @@ -207,11 +176,11 @@ namespace ZL { glEnable(GL_CULL_FACE); glCullFace(GL_BACK); // Отсекаем задние грани - if (stonesToRender[0].data.PositionData.size() > 0) + if (stoneToBake.data.PositionData.size() > 0) { glBindTexture(GL_TEXTURE_2D, stoneTexture->getTexID()); - renderer.DrawVertexRenderStruct(stonesToRender[0]); + renderer.DrawVertexRenderStruct(stoneToBake); CheckGlError(); } glDisable(GL_CULL_FACE); // РќРµ забываем выключить, чтобы РЅРµ сломать остальной рендер @@ -225,8 +194,6 @@ namespace ZL { void PlanetObject::draw(Renderer& renderer) { - - prepareDrawData(); { if (stoneMapFB == nullptr) @@ -248,7 +215,6 @@ namespace ZL { drawPlanet(renderer); - //drawYellowZone(renderer); drawStones(renderer); drawAtmosphere(renderer); @@ -400,79 +366,6 @@ namespace ZL { glClear(GL_DEPTH_BUFFER_BIT); } - void PlanetObject::drawYellowZone(Renderer& renderer) - { - /* - - static const std::string defaultShaderName = "planetLand"; - static const std::string vPositionName = "vPosition"; - static const std::string vColorName = "vColor"; - static const std::string vNormalName = "vNormal"; - static const std::string vTexCoordName = "vTexCoord"; - static const std::string textureUniformName = "Texture"; - - float dist = planetData.distanceToPlanetSurface(Environment::shipPosition); - auto zRange = planetData.calculateZRange(dist); - const float currentZNear = zRange.first; - const float currentZFar = zRange.second; - - - glClear(GL_DEPTH_BUFFER_BIT); - if (planetRenderYellowStruct.data.PositionData.size() > 0) - { - - renderer.shaderManager.PushShader(defaultShaderName); - renderer.RenderUniform1i(textureUniformName, 0); - renderer.EnableVertexAttribArray(vPositionName); - renderer.EnableVertexAttribArray(vColorName); - renderer.EnableVertexAttribArray(vNormalName); - renderer.EnableVertexAttribArray("vTangent"); - renderer.EnableVertexAttribArray("vBinormal"); - renderer.EnableVertexAttribArray(vTexCoordName); - - // 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); - - - - renderer.RenderUniform1f("uDistanceToPlanetSurface", dist); - renderer.RenderUniform1f("uCurrentZFar", currentZFar); - - renderer.RenderUniform3fv("uViewPos", &Environment::shipPosition.v[0]); - - Vector3f color2 = { 1.0, 1.0, 0.0 }; - - glBindTexture(GL_TEXTURE_2D, sandTexture->getTexID()); - - renderer.RenderUniform3fv("uColor", &color2.v[0]); - renderer.DrawVertexRenderStruct(planetRenderYellowStruct); - //glDisable(GL_BLEND); - CheckGlError(); - - - renderer.PopMatrix(); - renderer.PopProjectionMatrix(); - renderer.DisableVertexAttribArray(vTexCoordName); - renderer.DisableVertexAttribArray(vNormalName); - renderer.DisableVertexAttribArray("vTangent"); - renderer.DisableVertexAttribArray("vBinormal"); - renderer.DisableVertexAttribArray(vColorName); - renderer.DisableVertexAttribArray(vPositionName); - renderer.shaderManager.PopShader(); - CheckGlError(); - - }*/ - } - void PlanetObject::drawAtmosphere(Renderer& renderer) { static const std::string defaultShaderName = "defaultAtmosphere"; static const std::string vPositionName = "vPosition"; diff --git a/src/planet/PlanetObject.h b/src/planet/PlanetObject.h index f30fa3d..a36b20d 100644 --- a/src/planet/PlanetObject.h +++ b/src/planet/PlanetObject.h @@ -22,26 +22,24 @@ namespace ZL { class PlanetObject { public: - // Агрегация: логика Рё данные теперь здесь PlanetData planetData; // Данные только для рендеринга (OpenGL specific) VertexRenderStruct planetRenderStruct; - VertexRenderStruct planetRenderYellowStruct; VertexRenderStruct planetAtmosphereRenderStruct; StoneGroup planetStones; std::vector stonesToRender; + VertexRenderStruct stoneToBake; std::vector triangleIndicesToDraw; std::shared_ptr sandTexture; std::shared_ptr stoneTexture; - bool drawDataDirty = true; - void prepareDrawData(); - std::unique_ptr stoneMapFB; + Vector3f lastUpdatePos; + public: PlanetObject(); @@ -51,10 +49,8 @@ namespace ZL { void draw(Renderer& renderer); void drawStones(Renderer& renderer); void drawPlanet(Renderer& renderer); - void drawYellowZone(Renderer& renderer); void drawAtmosphere(Renderer& renderer); - float distanceToPlanetSurface(const Vector3f& viewerPosition); }; diff --git a/src/planet/StoneObject.cpp b/src/planet/StoneObject.cpp index a0cb5b5..4efcad5 100644 --- a/src/planet/StoneObject.cpp +++ b/src/planet/StoneObject.cpp @@ -12,17 +12,16 @@ namespace ZL { const float StoneParams::BASE_SCALE = 15.0f; // Общий размер камня - /*const float StoneParams::BASE_SCALE = 150.0f; // Общий размер камня const float StoneParams::MIN_AXIS_SCALE = 1.0f; // Минимальное растяжение/сжатие РїРѕ РѕСЃРё const float StoneParams::MAX_AXIS_SCALE = 1.0f; // Максимальное растяжение/сжатие РїРѕ РѕСЃРё const float StoneParams::MIN_PERTURBATION = 0.0f; // Минимальное радиальное возмущение вершины - const float StoneParams::MAX_PERTURBATION = 0.0f;*/ // Максимальное радиальное возмущение вершины - const float StoneParams::MIN_AXIS_SCALE = 0.5f; // Минимальное растяжение/сжатие РїРѕ РѕСЃРё + const float StoneParams::MAX_PERTURBATION = 0.0f; // Максимальное радиальное возмущение вершины + /*const float StoneParams::MIN_AXIS_SCALE = 0.5f; // Минимальное растяжение/сжатие РїРѕ РѕСЃРё const float StoneParams::MAX_AXIS_SCALE = 1.5f; // Максимальное растяжение/сжатие РїРѕ РѕСЃРё const float StoneParams::MIN_PERTURBATION = 0.05f; // Минимальное радиальное возмущение вершины const float StoneParams::MAX_PERTURBATION = 0.25f; // Максимальное радиальное возмущение вершины - - const int StoneParams::STONES_PER_TRIANGLE = 100; + */ + const int StoneParams::STONES_PER_TRIANGLE = 40; // Вспомогательная функция для получения случайного числа РІ диапазоне [min, max] float getRandomFloat(std::mt19937& gen, float min, float max) { @@ -110,6 +109,7 @@ namespace ZL { v.v[2] *= scaleFactors.v[2]; } + /* // Случайный РїРѕРІРѕСЂРѕС‚ (например, РІРѕРєСЂСѓРі трех осей) Vector4f qx = QuatFromRotateAroundX(getRandomFloat(engine, 0.0f, 360.0f)); Vector4f qy = QuatFromRotateAroundY(getRandomFloat(engine, 0.0f, 360.0f)); @@ -120,7 +120,7 @@ namespace ZL { for (Vector3f& v : initialVertices) { v = MultMatrixVector(rotationMatrix, v); - } + }*/ // 3. Сглаженные Нормали Рё Формирование Mesh VertexDataStruct result; @@ -249,23 +249,28 @@ namespace ZL { instance.seed = globalSeed;// + tIdx * 1000 + i; instance.position = GetRandomPointOnTriangle(tri, engine); + float SCALE_MIN = 0.75f; + float SCALE_MAX = 2.5f; + instance.scale = { - getRandomFloat(engine, 0.5f, 1.5f), - getRandomFloat(engine, 0.5f, 1.5f), - getRandomFloat(engine, 0.5f, 1.5f) + getRandomFloat(engine, SCALE_MIN, SCALE_MAX), + getRandomFloat(engine, SCALE_MIN, SCALE_MAX), + getRandomFloat(engine, SCALE_MIN, SCALE_MAX) }; - //!!! Hack - to fix it! -- Vladislav Khorev + /* if (tIdx == 0) { - instance.scale = instance.scale * 0.6f; - } + instance.scale = instance.scale * 0.7f; + }*/ + /* Vector4f qx = QuatFromRotateAroundX(getRandomFloat(engine, 0.0f, 360.0f)); Vector4f qy = QuatFromRotateAroundY(getRandomFloat(engine, 0.0f, 360.0f)); Vector4f qz = QuatFromRotateAroundZ(getRandomFloat(engine, 0.0f, 360.0f)); instance.rotation = slerp(slerp(qx, qy, 0.5f), qz, 0.5f).normalized(); - + */ + instance.rotation = Vector4f(0.f, 0.f, 0.f, 1.f); group.allInstances[tIdx].push_back(instance); } } @@ -274,13 +279,15 @@ namespace ZL { std::vector StoneGroup::inflate(int count) { - static VertexDataStruct baseStone = CreateBaseConvexPolyhedron(1337); + //static VertexDataStruct baseStone = CreateBaseConvexPolyhedron(1337); std::vector result; result.resize(count); for (int tIdx = 0; tIdx < count; tIdx++) { + result[tIdx] = inflateOne(tIdx, 1.0f); + /* for (const auto& inst : allInstances[tIdx]) { Matrix3f rotMat = QuatToMatrix(inst.rotation); @@ -299,10 +306,41 @@ namespace ZL { } result[tIdx].RefreshVBO(); - } + }*/ } return result; } + VertexRenderStruct StoneGroup::inflateOne(int index, float scaleModifier) + { + static VertexDataStruct baseStone = CreateBaseConvexPolyhedron(1337); + + VertexRenderStruct result; + + + for (const auto& inst : allInstances[index]) { + Matrix3f rotMat = QuatToMatrix(inst.rotation); + + for (size_t j = 0; j < baseStone.PositionData.size(); ++j) { + Vector3f p = baseStone.PositionData[j]; + Vector3f n = baseStone.NormalData[j]; + + p.v[0] *= inst.scale.v[0] * scaleModifier; + p.v[1] *= inst.scale.v[1] * scaleModifier; + p.v[2] *= inst.scale.v[2] * scaleModifier; + + result.data.PositionData.push_back(MultMatrixVector(rotMat, p) + inst.position); + result.data.NormalData.push_back(MultMatrixVector(rotMat, n)); + result.data.TexCoordData.push_back(baseStone.TexCoordData[j]); + + } + + result.RefreshVBO(); + } + + + return result; + } + } // namespace ZL diff --git a/src/planet/StoneObject.h b/src/planet/StoneObject.h index f2d301d..de244e1 100644 --- a/src/planet/StoneObject.h +++ b/src/planet/StoneObject.h @@ -31,6 +31,8 @@ namespace ZL { // Очищает старую геометрию и генерирует новую для указанных индексов std::vector inflate(int count); + + VertexRenderStruct inflateOne(int index, float scaleModifier); }; // Теперь возвращает заготовку со всеми параметрами, но без тяжелого меша diff --git a/src/utils/ZLMath.h b/src/utils/ZLMath.h index b065087..303ca48 100644 --- a/src/utils/ZLMath.h +++ b/src/utils/ZLMath.h @@ -9,6 +9,16 @@ namespace ZL { struct Vector4f { + Vector4f() + { + + } + + Vector4f(float x, float y, float z, float t) + : v{ x,y,z,t } + { + } + std::array v = { 0.f, 0.f, 0.f, 0.f }; Vector4f normalized() const {