From 854a425d856096e37e1a761b3d7258920b1c2016 Mon Sep 17 00:00:00 2001 From: Vladislav Khorev Date: Mon, 15 Dec 2025 22:30:33 +0300 Subject: [PATCH] Added some rocks --- Game.cpp | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++++- Game.h | 3 + ZLMath.cpp | 10 +++ ZLMath.h | 1 + 4 files changed, 187 insertions(+), 2 deletions(-) diff --git a/Game.cpp b/Game.cpp index a343918..093f886 100755 --- a/Game.cpp +++ b/Game.cpp @@ -17,6 +17,173 @@ namespace ZL const char* CONST_ZIP_FILE = ""; #endif + // Вспомогательная функция для получения случайного числа в диапазоне [min, max] + float getRandomFloat(std::mt19937& gen, float min, float max) { + std::uniform_real_distribution<> distrib(min, max); + return static_cast(distrib(gen)); + } + + // Икосаэдр (на основе золотого сечения phi) + // Координаты могут быть вычислены заранее для константного икосаэдра. + // Здесь только объявление, чтобы показать идею. + + VertexDataStruct CreateConvexPolyhedron(uint64_t seed) { + + // --- КОНСТАНТЫ ПАРАМЕТРОВ (как вы просили) --- + const float BASE_SCALE = 3.0f; // Общий размер камня + const float MIN_AXIS_SCALE = 0.5f; // Минимальное растяжение/сжатие по оси + const float MAX_AXIS_SCALE = 1.5f; // Максимальное растяжение/сжатие по оси + const float MIN_PERTURBATION = 0.05f; // Минимальное радиальное возмущение вершины + const float MAX_PERTURBATION = 0.25f; // Максимальное радиальное возмущение вершины + // const size_t SUBDIVISION_LEVEL = 1; // Уровень подразделения (для более круглого камня, пока опустим) + + std::mt19937 engine(static_cast(seed)); + + // Золотое сечение + const float t = (1.0f + std::sqrt(5.0f)) / 2.0f; + + // 12 вершин икосаэдра + std::vector initialVertices = { + { -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 } + }; + + // 20 треугольных граней (индексы вершин) + std::vector> faces = { + // 5 треугольников вокруг вершины 0 + {0, 11, 5}, {0, 5, 1}, {0, 1, 7}, {0, 7, 10}, {0, 10, 11}, + // 5 смежных полос + {1, 5, 9}, {5, 11, 4}, {11, 10, 2}, {10, 7, 6}, {7, 1, 8}, + // 5 треугольников вокруг вершины 3 + {3, 9, 4}, {3, 4, 2}, {3, 2, 6}, {3, 6, 8}, {3, 8, 9}, + // 5 смежных полос + {4, 9, 5}, {2, 4, 11}, {6, 2, 10}, {8, 6, 7}, {9, 8, 1} + }; + + // 1. Нормализация и Возмущение (Perturbation) + for (Vector3f& v : initialVertices) { + v = v.normalized() * BASE_SCALE; // Нормализация к сфере радиуса BASE_SCALE + + // Радиальное возмущение: + float perturbation = getRandomFloat(engine, MIN_PERTURBATION, MAX_PERTURBATION); + v = v * (1.0f + perturbation); + } + + // 2. Трансформация (Масштабирование и Поворот) + + // Случайные масштабы по осям + Vector3f scaleFactors = { + getRandomFloat(engine, MIN_AXIS_SCALE, MAX_AXIS_SCALE), + getRandomFloat(engine, MIN_AXIS_SCALE, MAX_AXIS_SCALE), + getRandomFloat(engine, MIN_AXIS_SCALE, MAX_AXIS_SCALE) + }; + + // Применяем масштабирование + for (Vector3f& v : initialVertices) { + v.v[0] *= scaleFactors.v[0]; + v.v[1] *= scaleFactors.v[1]; + v.v[2] *= scaleFactors.v[2]; + } + + // Случайный поворот (например, вокруг трех осей) + 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)); + Vector4f qFinal = slerp(qx, qy, 0.5f); // Простой пример комбинирования + qFinal = slerp(qFinal, qz, 0.5f).normalized(); + Matrix3f rotationMatrix = QuatToMatrix(qFinal); + + for (Vector3f& v : initialVertices) { + v = MultMatrixVector(rotationMatrix, v); + } + + // 3. Сглаженные Нормали и Формирование Mesh + VertexDataStruct result; + // Карта для накопления нормалей по уникальным позициям вершин + // (Требует определенного оператора < для Vector3f в ZLMath.h, который у вас есть) + std::map smoothNormalsMap; + + // Предварительное заполнение карты нормалями + for (const auto& face : faces) { + Vector3f p1 = initialVertices[face[0]]; + Vector3f p2 = initialVertices[face[1]]; + Vector3f p3 = initialVertices[face[2]]; + + // Нормаль грани: (p2 - p1) x (p3 - p1) + Vector3f faceNormal = (p2 - p1).cross(p3 - p1).normalized(); + + smoothNormalsMap[p1] = smoothNormalsMap[p1] + faceNormal; + smoothNormalsMap[p2] = smoothNormalsMap[p2] + faceNormal; + smoothNormalsMap[p3] = smoothNormalsMap[p3] + faceNormal; + } + + // Нормализация накопленных нормалей + for (auto& pair : smoothNormalsMap) { + pair.second = pair.second.normalized(); + } + + + // 4. Финальное заполнение VertexDataStruct и Текстурные Координаты + for (const auto& face : faces) { + Vector3f p1 = initialVertices[face[0]]; + Vector3f p2 = initialVertices[face[1]]; + Vector3f p3 = initialVertices[face[2]]; + + // Позиции + result.PositionData.push_back(p1); + result.PositionData.push_back(p2); + result.PositionData.push_back(p3); + + // Сглаженные Нормали (из карты) + result.NormalData.push_back(smoothNormalsMap[p1]); + result.NormalData.push_back(smoothNormalsMap[p2]); + result.NormalData.push_back(smoothNormalsMap[p3]); + + // Текстурные Координаты (Планарная проекция на плоскость грани) + // p1 -> (0, 0), p2 -> (L_12, 0), p3 -> (L_13 * cos(angle), L_13 * sin(angle)) + // Где L_xy - длина вектора, angle - угол между p2-p1 и p3-p1 + + Vector3f uAxis = (p2 - p1).normalized(); + Vector3f vRaw = p3 - p1; + + // Проекция vRaw на uAxis + float uProjLen = vRaw.dot(uAxis); + + // Вектор V перпендикулярный U: vRaw - uProj + Vector3f vAxisRaw = vRaw - (uAxis * uProjLen); + + // Длина оси V + float vLen = vAxisRaw.length(); + + // Нормализованная ось V + Vector3f vAxis = vAxisRaw.normalized(); + + // Координаты (u, v) для p1, p2, p3 относительно p1 + Vector2f uv1 = { 0.0f, 0.0f }; + Vector2f uv2 = { (p2 - p1).length(), 0.0f }; // p2-p1 вдоль оси U + Vector2f uv3 = { uProjLen, vLen }; // p3-p1: u-компонента = uProjLen, v-компонента = vLen + + // Находим максимальный размер, чтобы масштабировать в [0, 1] + float maxUV = max( uv2.v[0], uv3.v[0], uv3.v[1] ); + + if (maxUV > 0.000001f) { + // Масштабируем: + result.TexCoordData.push_back(uv1); + result.TexCoordData.push_back(uv2 * (1.f/ maxUV)); + result.TexCoordData.push_back(uv3 * (1.f/ maxUV)); + } + else { + // Предотвращение деления на ноль для вырожденных граней + result.TexCoordData.push_back({ 0.0f, 0.0f }); + result.TexCoordData.push_back({ 0.0f, 0.0f }); + result.TexCoordData.push_back({ 0.0f, 0.0f }); + } + } + + return result; + } + Vector4f generateRandomQuaternion(std::mt19937& gen) { // Ðàñïðåäåëåíèå äëÿ ãåíåðàöèè ñëó÷àéíûõ êîîðäèíàò êâàòåðíèîíà @@ -197,7 +364,8 @@ namespace ZL for (int i = 0; i < boxCoordsArr.size(); i++) { - boxRenderArr[i].AssignFrom(boxBase); + //boxRenderArr[i].AssignFrom(boxBase); + boxRenderArr[i].data = CreateConvexPolyhedron(1999); boxRenderArr[i].RefreshVBO(); } @@ -268,6 +436,8 @@ namespace ZL planetObject.init(); + rockTexture = std::make_unique(CreateTextureDataFromPng("./resources/rock.png", "")); + } void Game::drawCubemap(float skyPercent) @@ -370,7 +540,8 @@ namespace ZL renderer.TranslateMatrix(boxCoordsArr[i].pos); renderer.RotateMatrix(boxCoordsArr[i].m); - glBindTexture(GL_TEXTURE_2D, boxTexture->getTexID()); + //glBindTexture(GL_TEXTURE_2D, boxTexture->getTexID()); + glBindTexture(GL_TEXTURE_2D, rockTexture->getTexID()); renderer.DrawVertexRenderStruct(boxRenderArr[i]); renderer.PopMatrix(); diff --git a/Game.h b/Game.h index 987e3e1..0b8796b 100755 --- a/Game.h +++ b/Game.h @@ -44,6 +44,9 @@ namespace ZL { size_t newTickCount; size_t lastTickCount; + std::shared_ptr rockTexture; + + std::vector boxCoordsArr; std::vector boxRenderArr; diff --git a/ZLMath.cpp b/ZLMath.cpp index a05843e..4077cd9 100644 --- a/ZLMath.cpp +++ b/ZLMath.cpp @@ -609,6 +609,16 @@ namespace ZL { return r; } + Vector2f operator*(Vector2f v, float scale) + { + Vector2f r = v; + + r.v[0] = v.v[0] * scale; + r.v[1] = v.v[1] * scale; + + return r; + } + Vector3f operator*(Vector3f v, float scale) { Vector3f r = v; diff --git a/ZLMath.h b/ZLMath.h index be5a5c1..d5c7534 100755 --- a/ZLMath.h +++ b/ZLMath.h @@ -164,6 +164,7 @@ namespace ZL { Vector4f QuatFromRotateAroundY(float angle); Vector4f QuatFromRotateAroundZ(float angle); + Vector2f operator*(Vector2f v, float scale); Vector3f operator*(Vector3f v, float scale); Vector4f operator*(Vector4f v, float scale);