Working on stones
This commit is contained in:
parent
854a425d85
commit
e690d0f8e2
@ -444,6 +444,8 @@ add_executable(space-game001
|
||||
PlanetData.h
|
||||
Perlin.cpp
|
||||
Perlin.h
|
||||
StoneObject.cpp
|
||||
StoneObject.h
|
||||
)
|
||||
|
||||
# Установка проекта по умолчанию для Visual Studio
|
||||
|
||||
207
Game.cpp
207
Game.cpp
@ -6,6 +6,7 @@
|
||||
#include <iostream>
|
||||
#include "TextureManager.h"
|
||||
#include "TextModel.h"
|
||||
#include "StoneObject.h"
|
||||
#include <random>
|
||||
#include <cmath>
|
||||
|
||||
@ -17,180 +18,13 @@ 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<float>(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<unsigned int>(seed));
|
||||
|
||||
// Золотое сечение
|
||||
const float t = (1.0f + std::sqrt(5.0f)) / 2.0f;
|
||||
|
||||
// 12 вершин икосаэдра
|
||||
std::vector<Vector3f> 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<std::array<int, 3>> 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<Vector3f, Vector3f> 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)
|
||||
{
|
||||
// Ðàñïðåäåëåíèå äëÿ ãåíåðàöèè ñëó÷àéíûõ êîîðäèíàò êâàòåðíèîíà
|
||||
|
||||
std::normal_distribution<> distrib(0.0, 1.0);
|
||||
|
||||
// Ãåíåðèðóåì ÷åòûðå ñëó÷àéíûõ ÷èñëà èç íîðìàëüíîãî ðàñïðåäåëåíèÿ N(0, 1).
|
||||
// Íîðìàëèçàöèÿ ýòîãî âåêòîðà äàåò ðàâíîìåðíîå ðàñïðåäåëåíèå ïî 4D-ñôåðå (ò.å. êâàòåðíèîí åäèíè÷íîé äëèíû).
|
||||
Vector4f randomQuat = {
|
||||
(float)distrib(gen),
|
||||
(float)distrib(gen),
|
||||
@ -202,25 +36,18 @@ namespace ZL
|
||||
}
|
||||
|
||||
|
||||
// --- Îñíîâíàÿ ôóíêöèÿ ãåíåðàöèè ---
|
||||
std::vector<BoxCoords> generateRandomBoxCoords(int N)
|
||||
{
|
||||
// Êîíñòàíòû
|
||||
const float MIN_DISTANCE = 3.0f;
|
||||
const float MIN_DISTANCE_SQUARED = MIN_DISTANCE * MIN_DISTANCE; // Ðàáîòàåì ñ êâàäðàòîì ðàññòîÿíèÿ
|
||||
const float MIN_DISTANCE_SQUARED = MIN_DISTANCE * MIN_DISTANCE;
|
||||
const float MIN_COORD = -100.0f;
|
||||
const float MAX_COORD = 100.0f;
|
||||
const int MAX_ATTEMPTS = 1000; // Îãðàíè÷åíèå íà êîëè÷åñòâî ïîïûòîê, ÷òîáû èçáåæàòü áåñêîíå÷íîãî öèêëà
|
||||
|
||||
const int MAX_ATTEMPTS = 1000;
|
||||
std::vector<BoxCoords> boxCoordsArr;
|
||||
boxCoordsArr.reserve(N); // Ðåçåðâèðóåì ïàìÿòü
|
||||
|
||||
// 1. Èíèöèàëèçàöèÿ ãåíåðàòîðà ïñåâäîñëó÷àéíûõ ÷èñåë
|
||||
// Èñïîëüçóåì Mersenne Twister (mt19937) êàê âûñîêîêà÷åñòâåííûé ãåíåðàòîð
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
|
||||
// 2. Îïðåäåëåíèå ðàâíîìåðíîãî ðàñïðåäåëåíèÿ äëÿ êîîðäèíàò [MIN_COORD, MAX_COORD]
|
||||
std::uniform_real_distribution<> distrib(MIN_COORD, MAX_COORD);
|
||||
|
||||
int generatedCount = 0;
|
||||
@ -230,51 +57,41 @@ namespace ZL
|
||||
bool accepted = false;
|
||||
int attempts = 0;
|
||||
|
||||
// Ïîïûòêà íàéòè ïîäõîäÿùèå êîîðäèíàòû
|
||||
while (!accepted && attempts < MAX_ATTEMPTS)
|
||||
{
|
||||
// Ãåíåðèðóåì íîâûå ñëó÷àéíûå êîîðäèíàòû
|
||||
Vector3f newPos(
|
||||
(float)distrib(gen),
|
||||
(float)distrib(gen),
|
||||
(float)distrib(gen)
|
||||
);
|
||||
|
||||
// Ïðîâåðêà ðàññòîÿíèÿ äî âñåõ óæå ñóùåñòâóþùèõ îáúåêòîâ
|
||||
accepted = true; // Ïðåäïîëàãàåì, ÷òî ïîäõîäèò, ïîêà íå äîêàçàíî îáðàòíîå
|
||||
accepted = true;
|
||||
for (const auto& existingBox : boxCoordsArr)
|
||||
{
|
||||
// Ðàñ÷åò âåêòîðà ðàçíîñòè
|
||||
|
||||
Vector3f diff = newPos - existingBox.pos;
|
||||
|
||||
// Ðàñ÷åò êâàäðàòà ðàññòîÿíèÿ
|
||||
float distanceSquared = diff.squaredNorm();
|
||||
|
||||
// Åñëè êâàäðàò ðàññòîÿíèÿ ìåíüøå êâàäðàòà ìèíèìàëüíîãî ðàññòîÿíèÿ
|
||||
if (distanceSquared < MIN_DISTANCE_SQUARED)
|
||||
{
|
||||
accepted = false; // Îòêëîíÿåì, ñëèøêîì áëèçêî
|
||||
break; // Íåò ñìûñëà ïðîâåðÿòü äàëüøå, åñëè îäíî íàðóøåíèå íàéäåíî
|
||||
accepted = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (accepted)
|
||||
{
|
||||
// 2. Ãåíåðèðóåì ñëó÷àéíûé êâàòåðíèîí
|
||||
Vector4f randomQuat = generateRandomQuaternion(gen);
|
||||
|
||||
// 3. Ïðåîáðàçóåì åãî â ìàòðèöó âðàùåíèÿ
|
||||
Matrix3f randomMatrix = QuatToMatrix(randomQuat);
|
||||
|
||||
// 4. Äîáàâëÿåì îáúåêò ñ íîâîé ñëó÷àéíîé ìàòðèöåé
|
||||
boxCoordsArr.emplace_back(BoxCoords{ newPos, randomMatrix });
|
||||
generatedCount++;
|
||||
}
|
||||
attempts++;
|
||||
}
|
||||
|
||||
// Åñëè ïðåâûøåíî ìàêñèìàëüíîå êîëè÷åñòâî ïîïûòîê, âûõîäèì èç öèêëà,
|
||||
// ÷òîáû èçáåæàòü çàâèñàíèÿ, åñëè N ñëèøêîì âåëèêî èëè äèàïàçîí ñëèøêîì ìàë.
|
||||
if (!accepted) {
|
||||
std::cerr << "Ïðåäóïðåæäåíèå: Íå óäàëîñü ñãåíåðèðîâàòü " << N << " îáúåêòîâ. Ñãåíåðèðîâàíî: " << generatedCount << std::endl;
|
||||
break;
|
||||
@ -345,11 +162,11 @@ namespace ZL
|
||||
cubemap.RefreshVBO();
|
||||
|
||||
//Load texture
|
||||
spaceshipTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/DefaultMaterial_BaseColor.png", CONST_ZIP_FILE));
|
||||
spaceshipBase = LoadFromTextFile02("./resources/spaceship005.txt", CONST_ZIP_FILE);
|
||||
spaceshipTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/DefaultMaterial_BaseColor_shine.png", CONST_ZIP_FILE));
|
||||
spaceshipBase = LoadFromTextFile02("./resources/spaceship006.txt", CONST_ZIP_FILE);
|
||||
spaceshipBase.RotateByMatrix(QuatToMatrix(QuatFromRotateAroundY(M_PI / 2.0)));
|
||||
//spaceshipBase.Move(Vector3f{ -0.52998, -13, 0 });
|
||||
spaceshipBase.Move(Vector3f{ -0.52998, -10, 10 });
|
||||
//spaceshipBase.Move(Vector3f{ -0.52998, -10, 10 });
|
||||
|
||||
spaceship.AssignFrom(spaceshipBase);
|
||||
spaceship.RefreshVBO();
|
||||
@ -365,7 +182,7 @@ namespace ZL
|
||||
for (int i = 0; i < boxCoordsArr.size(); i++)
|
||||
{
|
||||
//boxRenderArr[i].AssignFrom(boxBase);
|
||||
boxRenderArr[i].data = CreateConvexPolyhedron(1999);
|
||||
boxRenderArr[i].data = CreateBaseConvexPolyhedron(1999);
|
||||
boxRenderArr[i].RefreshVBO();
|
||||
}
|
||||
|
||||
|
||||
@ -19,8 +19,8 @@ namespace ZL {
|
||||
static constexpr float NEAR_Z_NEAR = 100.0f;
|
||||
static constexpr float NEAR_Z_FAR = 20000.0f;
|
||||
static constexpr float TRANSITION_NEAR_END = 100.f;
|
||||
static constexpr float SUPER_NEAR_Z_NEAR = 30.0f;
|
||||
static constexpr float SUPER_NEAR_Z_FAR = 6000.0f;
|
||||
static constexpr float SUPER_NEAR_Z_NEAR = 5.0f;
|
||||
static constexpr float SUPER_NEAR_Z_FAR = 5000.0f;
|
||||
static constexpr float TRANSITION_SUPER_NEAR_END = 30.f;
|
||||
|
||||
VertexID generateEdgeID(const VertexID& id1, const VertexID& id2) {
|
||||
@ -56,14 +56,14 @@ namespace ZL {
|
||||
|
||||
void PlanetData::init() {
|
||||
for (int i = 0; i < planetMeshLods.size(); i++) {
|
||||
planetMeshLods[i] = generateSphere(i, 0.02f);
|
||||
planetMeshLods[i].vertexData.Scale(PLANET_RADIUS);
|
||||
planetMeshLods[i].vertexData.Move(PLANET_CENTER_OFFSET);
|
||||
planetMeshLods[i] = generateSphere(i, 0);
|
||||
planetMeshLods[i].Scale(PLANET_RADIUS);
|
||||
planetMeshLods[i].Move(PLANET_CENTER_OFFSET);
|
||||
}
|
||||
|
||||
planetAtmosphereLod = generateSphere(5, 0);
|
||||
planetAtmosphereLod.vertexData.Scale(PLANET_RADIUS * 1.03);
|
||||
planetAtmosphereLod.vertexData.Move(PLANET_CENTER_OFFSET);
|
||||
planetAtmosphereLod.Scale(PLANET_RADIUS * 1.03);
|
||||
planetAtmosphereLod.Move(PLANET_CENTER_OFFSET);
|
||||
}
|
||||
|
||||
const LodLevel& PlanetData::getLodLevel(int level) const {
|
||||
@ -165,7 +165,7 @@ namespace ZL {
|
||||
|
||||
// --- Ðåàëèçàöèÿ getTrianglesUnderCamera (áûâøàÿ triangleUnderCamera) ---
|
||||
// Âñïîìîãàòåëüíàÿ ðåêóðñèâíàÿ ôóíêöèÿ, ñêðûòàÿ îò ïóáëè÷íîãî API
|
||||
static std::vector<int> recursiveTriangleSearch(int lod, const Vector3f& pos, const std::array<LodLevel, 6>& meshes) {
|
||||
static std::vector<int> recursiveTriangleSearch(int lod, const Vector3f& pos, const std::array<LodLevel, MAX_LOD_LEVELS>& meshes) {
|
||||
std::vector<int> r;
|
||||
// Ëîãèêà óðîâíÿ 0 (áàçîâûé îêòàýäð)
|
||||
if (lod == 0) {
|
||||
@ -317,6 +317,8 @@ namespace ZL {
|
||||
LodLevel PlanetData::trianglesToVertices(const std::vector<Triangle>& geometry) {
|
||||
LodLevel result;
|
||||
|
||||
result.triangles = geometry;
|
||||
|
||||
result.vertexData.PositionData.reserve(geometry.size() * 3);
|
||||
result.vertexData.NormalData.reserve(geometry.size() * 3);
|
||||
result.vertexData.TexCoordData.reserve(geometry.size() * 3); // <-- ÐÅÇÅÐÂÈÐÓÅÌ
|
||||
@ -384,7 +386,7 @@ namespace ZL {
|
||||
}
|
||||
|
||||
// 4. Ãåíåðèðóåì PositionData, NormalData è VertexIDs
|
||||
LodLevel lodLevel = trianglesToVertices(geometry);
|
||||
LodLevel lodLevel = trianglesToVertices(geometry);
|
||||
|
||||
// 5. Ñîçäàíèå V2T-Map íà îñíîâå VertexIDs (ÒÎÏÎËÎÃÈ×ÅÑÊÈÉ ÊËÞ×)
|
||||
V2TMap v2tMap;
|
||||
|
||||
24
PlanetData.h
24
PlanetData.h
@ -16,6 +16,8 @@ namespace ZL {
|
||||
|
||||
VertexID generateEdgeID(const VertexID& id1, const VertexID& id2);
|
||||
|
||||
constexpr static int MAX_LOD_LEVELS = 6;
|
||||
|
||||
struct Triangle
|
||||
{
|
||||
std::array<Vector3f, 3> data;
|
||||
@ -35,9 +37,29 @@ namespace ZL {
|
||||
|
||||
struct LodLevel
|
||||
{
|
||||
std::vector<Triangle> triangles;
|
||||
VertexDataStruct vertexData;
|
||||
std::vector<VertexID> VertexIDs;
|
||||
V2TMap v2tMap;
|
||||
|
||||
void Scale(float s)
|
||||
{
|
||||
vertexData.Scale(s);
|
||||
for (auto& t : triangles) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
t.data[i] = t.data[i] * s;
|
||||
}
|
||||
}
|
||||
}
|
||||
void Move(Vector3f pos)
|
||||
{
|
||||
vertexData.Move(pos);
|
||||
for (auto& t : triangles) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
t.data[i] = t.data[i] + pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class PlanetData {
|
||||
@ -49,7 +71,7 @@ namespace ZL {
|
||||
PerlinNoise perlin;
|
||||
PerlinNoise colorPerlin;
|
||||
|
||||
std::array<LodLevel, 6> planetMeshLods;
|
||||
std::array<LodLevel, MAX_LOD_LEVELS> planetMeshLods;
|
||||
LodLevel planetAtmosphereLod;
|
||||
|
||||
int currentLod; // Ëîãè÷åñêèé òåêóùèé óðîâåíü äåòàëèçàöèè
|
||||
|
||||
140
PlanetObject.cpp
140
PlanetObject.cpp
@ -3,6 +3,7 @@
|
||||
#include <cmath>
|
||||
#include "OpenGlExtensions.h"
|
||||
#include "Environment.h"
|
||||
#include "StoneObject.h"
|
||||
|
||||
namespace ZL {
|
||||
|
||||
@ -22,7 +23,8 @@ namespace ZL {
|
||||
planetRenderStruct.data = planetData.getLodLevel(lodIndex).vertexData;
|
||||
planetRenderStruct.RefreshVBO();
|
||||
|
||||
sandTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/sand.png", ""));
|
||||
sandTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/sand2.png", ""));
|
||||
stoneTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/rock.png", ""));
|
||||
|
||||
// Атмосфера
|
||||
planetAtmosphereRenderStruct.data = planetData.getAtmosphereLod().vertexData;
|
||||
@ -40,33 +42,29 @@ namespace ZL {
|
||||
int currentLod = planetData.getCurrentLodIndex();
|
||||
const auto& fullMesh = planetData.getLodLevel(currentLod).vertexData;
|
||||
|
||||
planetRenderRedStruct.data.PositionData.clear();
|
||||
planetRenderRedStruct.data.TexCoordData.clear();
|
||||
// ... очистка остальных буферов ...
|
||||
|
||||
planetRenderYellowStruct.data.PositionData.clear();
|
||||
planetRenderYellowStruct.data.TexCoordData.clear();
|
||||
|
||||
triangleIndicesToDraw.clear();
|
||||
std::set<int> usedYellow;
|
||||
|
||||
// Заполняем красный (текущий треугольник под камерой)
|
||||
for (int i : lr) {
|
||||
planetRenderRedStruct.data.PositionData.push_back(fullMesh.PositionData[i * 3]);
|
||||
planetRenderRedStruct.data.PositionData.push_back(fullMesh.PositionData[i * 3 + 1]);
|
||||
planetRenderRedStruct.data.PositionData.push_back(fullMesh.PositionData[i * 3 + 2]);
|
||||
planetRenderRedStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[i * 3]);
|
||||
planetRenderRedStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[i * 3 + 1]);
|
||||
planetRenderRedStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[i * 3 + 2]);
|
||||
planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[i * 3]);
|
||||
planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[i * 3 + 1]);
|
||||
planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[i * 3 + 2]);
|
||||
planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[i * 3]);
|
||||
planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[i * 3 + 1]);
|
||||
planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[i * 3 + 2]);
|
||||
usedYellow.insert(i);
|
||||
triangleIndicesToDraw.push_back(i);
|
||||
}
|
||||
planetRenderRedStruct.RefreshVBO();
|
||||
|
||||
// Заполняем желтый (соседи)
|
||||
for (int i : lr) {
|
||||
auto neighbors = planetData.findNeighbors(i, currentLod);
|
||||
for (int n : neighbors) {
|
||||
if (usedYellow.count(n) == 0) {
|
||||
usedYellow.insert(n);
|
||||
triangleIndicesToDraw.push_back(n);
|
||||
planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[n * 3]);
|
||||
planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[n * 3 + 1]);
|
||||
planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[n * 3 + 2]);
|
||||
@ -74,9 +72,26 @@ namespace ZL {
|
||||
planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[n * 3 + 1]);
|
||||
planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[n * 3 + 2]);
|
||||
}
|
||||
auto neighbors2 = planetData.findNeighbors(n, currentLod);
|
||||
|
||||
for (int n2 : neighbors2) {
|
||||
if (usedYellow.count(n2) == 0) {
|
||||
usedYellow.insert(n2);
|
||||
triangleIndicesToDraw.push_back(n2);
|
||||
planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[n2 * 3]);
|
||||
planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[n2 * 3 + 1]);
|
||||
planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[n2 * 3 + 2]);
|
||||
planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[n2 * 3]);
|
||||
planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[n2 * 3 + 1]);
|
||||
planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[n2 * 3 + 2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
planetRenderYellowStruct.RefreshVBO();
|
||||
|
||||
planetStonesRenderStruct.data = CreateConvexPolyhedron(777, planetData.getLodLevel(5), triangleIndicesToDraw);
|
||||
planetStonesRenderStruct.RefreshVBO();
|
||||
}
|
||||
|
||||
|
||||
@ -88,7 +103,8 @@ namespace ZL {
|
||||
//--------------------------
|
||||
|
||||
drawPlanet(renderer);
|
||||
drawYellowZone(renderer);
|
||||
//drawYellowZone(renderer);
|
||||
drawStones(renderer);
|
||||
|
||||
drawAtmosphere(renderer);
|
||||
}
|
||||
@ -167,11 +183,96 @@ namespace ZL {
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
|
||||
|
||||
}
|
||||
|
||||
void PlanetObject::drawStones(Renderer& renderer)
|
||||
{
|
||||
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";
|
||||
static const std::string vTexCoordName = "vTexCoord";
|
||||
//static const std::string vTexCoord3Name = "vTexCoord3";
|
||||
static const std::string textureUniformName = "Texture";
|
||||
|
||||
renderer.shaderManager.PushShader(defaultShaderName2);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vColorName);
|
||||
renderer.EnableVertexAttribArray(vNormalName);
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
//renderer.EnableVertexAttribArray(vTexCoord3Name);
|
||||
|
||||
float dist = planetData.distanceToPlanetSurface(Environment::shipPosition);
|
||||
auto zRange = planetData.calculateZRange(dist);
|
||||
const float currentZNear = zRange.first;
|
||||
const float currentZFar = zRange.second;
|
||||
|
||||
// 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);
|
||||
|
||||
const Matrix4f viewMatrix = renderer.GetCurrentModelViewMatrix();
|
||||
|
||||
|
||||
Vector3f lightDir_World = Vector3f(1.0f, 0.0f, -1.0f).normalized();
|
||||
// В OpenGL/шейдерах удобнее работать с вектором, указывающим ОТ источника к поверхности.
|
||||
Vector3f lightDirection_World = -lightDir_World; // Вектор, направленный от источника
|
||||
Vector3f lightDirection_View;
|
||||
|
||||
lightDirection_View.v[0] = viewMatrix.m[0] * lightDirection_World.v[0] + viewMatrix.m[4] * lightDirection_World.v[1] + viewMatrix.m[8] * lightDirection_World.v[2];
|
||||
lightDirection_View.v[1] = viewMatrix.m[1] * lightDirection_World.v[0] + viewMatrix.m[5] * lightDirection_World.v[1] + viewMatrix.m[9] * lightDirection_World.v[2];
|
||||
lightDirection_View.v[2] = viewMatrix.m[2] * lightDirection_World.v[0] + viewMatrix.m[6] * lightDirection_World.v[1] + viewMatrix.m[10] * lightDirection_World.v[2];
|
||||
lightDirection_View = lightDirection_View.normalized(); // Нормализуем на всякий случай
|
||||
|
||||
// Установка uniform-переменной
|
||||
// Предполагается, что RenderUniform3fv определена в Renderer.h
|
||||
renderer.RenderUniform3fv("uLightDirection", &lightDirection_View.v[0]);
|
||||
renderer.RenderUniformMatrix4fv("ModelViewMatrix", false, &viewMatrix.m[0]);
|
||||
|
||||
renderer.RenderUniform1f("uDistanceToPlanetSurface", dist);
|
||||
renderer.RenderUniform1f("uCurrentZFar", currentZFar);
|
||||
Vector3f color2 = { 1.0, 1.0, 1.0 };
|
||||
|
||||
renderer.RenderUniform3fv("uColor", &color2.v[0]);
|
||||
|
||||
//glEnable(GL_BLEND);
|
||||
//glBlendFunc(GL_SRC_ALPHA, GL_ONE);// Аддитивное смешивание для эффекта свечения
|
||||
|
||||
if (planetStonesRenderStruct.data.PositionData.size() > 0)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, stoneTexture->getTexID());
|
||||
renderer.DrawVertexRenderStruct(planetStonesRenderStruct);
|
||||
//glDisable(GL_BLEND);
|
||||
CheckGlError();
|
||||
}
|
||||
|
||||
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
//renderer.DisableVertexAttribArray(vTexCoord3Name);
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
renderer.DisableVertexAttribArray(vNormalName);
|
||||
renderer.DisableVertexAttribArray(vColorName);
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void PlanetObject::drawYellowZone(Renderer& renderer)
|
||||
{
|
||||
|
||||
static const std::string defaultShaderName = "defaultColor";
|
||||
static const std::string defaultShaderName2 = "defaultColor2";
|
||||
static const std::string vPositionName = "vPosition";
|
||||
@ -186,7 +287,9 @@ namespace ZL {
|
||||
const float currentZNear = zRange.first;
|
||||
const float currentZFar = zRange.second;
|
||||
|
||||
if (planetRenderRedStruct.data.PositionData.size() > 0)
|
||||
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
if (planetRenderYellowStruct.data.PositionData.size() > 0)
|
||||
{
|
||||
|
||||
renderer.shaderManager.PushShader(defaultShaderName2);
|
||||
@ -212,12 +315,7 @@ namespace ZL {
|
||||
renderer.RenderUniform1f("uDistanceToPlanetSurface", dist);
|
||||
renderer.RenderUniform1f("uCurrentZFar", currentZFar);
|
||||
|
||||
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]);
|
||||
renderer.DrawVertexRenderStruct(planetRenderRedStruct);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, sandTexture->getTexID());
|
||||
|
||||
|
||||
@ -25,11 +25,14 @@ namespace ZL {
|
||||
|
||||
// Данные только для рендеринга (OpenGL specific)
|
||||
VertexRenderStruct planetRenderStruct;
|
||||
VertexRenderStruct planetRenderRedStruct;
|
||||
VertexRenderStruct planetRenderYellowStruct;
|
||||
VertexRenderStruct planetAtmosphereRenderStruct;
|
||||
VertexRenderStruct planetStonesRenderStruct;
|
||||
|
||||
std::vector<int> triangleIndicesToDraw;
|
||||
|
||||
std::shared_ptr<Texture> sandTexture;
|
||||
std::shared_ptr<Texture> stoneTexture;
|
||||
|
||||
bool drawDataDirty = true;
|
||||
void prepareDrawData();
|
||||
@ -40,10 +43,12 @@ namespace ZL {
|
||||
void init();
|
||||
void update(float deltaTimeMs);
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
307
StoneObject.cpp
Normal file
307
StoneObject.cpp
Normal file
@ -0,0 +1,307 @@
|
||||
#include "StoneObject.h"
|
||||
|
||||
#include "Utils.h"
|
||||
#include <GL/gl.h>
|
||||
#include <random>
|
||||
#include <cmath>
|
||||
#include "Renderer.h"
|
||||
#include "PlanetData.h"
|
||||
|
||||
namespace ZL {
|
||||
|
||||
// Âñïîìîãàòåëüíàÿ ôóíêöèÿ äëÿ ïîëó÷åíèÿ ñëó÷àéíîãî ÷èñëà â äèàïàçîíå [min, max]
|
||||
float getRandomFloat(std::mt19937& gen, float min, float max) {
|
||||
std::uniform_real_distribution<> distrib(min, max);
|
||||
return static_cast<float>(distrib(gen));
|
||||
}
|
||||
|
||||
// Âñïîìîãàòåëüíàÿ ôóíêöèÿ äëÿ ãåíåðàöèè ñëó÷àéíîé òî÷êè íà òðåóãîëüíèêå
|
||||
// Èñïîëüçóåò áàðèöåíòðè÷åñêèå êîîðäèíàòû
|
||||
Vector3f GetRandomPointOnTriangle(const Triangle& t, std::mt19937& engine) {
|
||||
std::uniform_real_distribution<> distrib(0.0f, 1.0f);
|
||||
|
||||
float r1 = getRandomFloat(engine, 0.0f, 1.0f);
|
||||
float r2 = getRandomFloat(engine, 0.0f, 1.0f);
|
||||
|
||||
// Ïðåîáðàçîâàíèå r1, r2 äëÿ ïîëó÷åíèÿ ðàâíîìåðíîãî ðàñïðåäåëåíèÿ
|
||||
float a = 1.0f - std::sqrt(r1);
|
||||
float b = std::sqrt(r1) * r2;
|
||||
float c = 1.0f - a - b; // c = sqrt(r1) * (1 - r2)
|
||||
|
||||
// Áàðèöåíòðè÷åñêèå êîîðäèíàòû
|
||||
// P = a*p1 + b*p2 + c*p3
|
||||
Vector3f p1_term = t.data[0] * a;
|
||||
Vector3f p2_term = t.data[1] * b;
|
||||
Vector3f p3_term = t.data[2] * c;
|
||||
|
||||
return p1_term + p2_term + p3_term;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Èêîñàýäð (íà îñíîâå çîëîòîãî ñå÷åíèÿ phi)
|
||||
// Êîîðäèíàòû ìîãóò áûòü âû÷èñëåíû çàðàíåå äëÿ êîíñòàíòíîãî èêîñàýäðà.
|
||||
// Çäåñü òîëüêî îáúÿâëåíèå, ÷òîáû ïîêàçàòü èäåþ.
|
||||
|
||||
VertexDataStruct CreateBaseConvexPolyhedron(uint64_t seed) {
|
||||
|
||||
// --- ÊÎÍÑÒÀÍÒÛ ÏÀÐÀÌÅÒÐÎÂ (êàê âû ïðîñèëè) ---
|
||||
//const float BASE_SCALE = 3.0f; // Îáùèé ðàçìåð êàìíÿ
|
||||
const float BASE_SCALE = 20.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<unsigned int>(seed));
|
||||
|
||||
// Çîëîòîå ñå÷åíèå
|
||||
const float t = (1.0f + std::sqrt(5.0f)) / 2.0f;
|
||||
|
||||
// 12 âåðøèí èêîñàýäðà
|
||||
std::vector<Vector3f> 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<std::array<int, 3>> 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<Vector3f, Vector3f> 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], max(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;
|
||||
}
|
||||
|
||||
VertexDataStruct CreateConvexPolyhedron(uint64_t seed, const LodLevel& planetLodLevel, const std::vector<int>& triangleIndices) {
|
||||
|
||||
VertexDataStruct finalMesh;
|
||||
const int STONES_PER_TRIANGLE = 100;
|
||||
|
||||
// Êîíñòàíòû òðàíñôîðìàöèè (íóæíû çäåñü, ÷òîáû êàæäûé êàìåíü áûë óíèêàëüíûì)
|
||||
const float MIN_AXIS_SCALE = 0.5f;
|
||||
const float MAX_AXIS_SCALE = 1.5f;
|
||||
|
||||
// 1. Ñîçäàåì ÁÀÇÎÂÛÉ ÌÅØ ÎÄÈÍ ÐÀÇ, ÷òîáû íå ïîâòîðÿòü ñëîæíóþ ãåíåðàöèþ
|
||||
// Èñïîëüçóåì îòäåëüíûé seed äëÿ áàçîâîé ôîðìû, ÷òîáû îíà áûëà óíèêàëüíîé,
|
||||
// íî îñòàâàëàñü îäèíàêîâîé ïðè ðàçíûõ seed äëÿ ðàçìåùåíèÿ.
|
||||
uint64_t baseSeed = 1337; // Êîíñòàíòíûé seed äëÿ ôîðìû êàìíÿ
|
||||
VertexDataStruct baseStone = CreateBaseConvexPolyhedron(baseSeed);
|
||||
|
||||
// 2. Èòåðèðóåìñÿ ïî çàäàííûì òðåóãîëüíèêàì
|
||||
for (int triangleIndex : triangleIndices) {
|
||||
|
||||
std::mt19937 engine(static_cast<unsigned int>(seed));
|
||||
|
||||
|
||||
if (triangleIndex >= planetLodLevel.triangles.size()) {
|
||||
// Îáðàáîòêà îøèáêè
|
||||
continue;
|
||||
}
|
||||
|
||||
const Triangle& currentTriangle = planetLodLevel.triangles[triangleIndex];
|
||||
|
||||
// 3. Ãåíåðèðóåì 100 êàìíåé íà êàæäîì òðåóãîëüíèêå
|
||||
for (int i = 0; i < STONES_PER_TRIANGLE; i++) {
|
||||
|
||||
// --- 3.1. Ãåíåðèðóåì ñëó÷àéíîå ìåñòîïîëîæåíèå íà òðåóãîëüíèêå ---
|
||||
Vector3f stoneCenter = GetRandomPointOnTriangle(currentTriangle, engine);
|
||||
|
||||
// --- 3.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)
|
||||
};
|
||||
|
||||
// Ñëó÷àéíûé ïîâîðîò (íàïðèìåð, âîêðóã îñè íîðìàëè ê ïîâåðõíîñòè)
|
||||
// Äëÿ ðåàëèñòè÷íîñòè, êàìåíü äîëæåí ëåæàòü íà ïîâåðõíîñòè.
|
||||
// Âåêòîð 'ââåðõ' äëÿ êàìíÿ äîëæåí áûòü âûðîâíåí ïî íîðìàëè òðåóãîëüíèêà.
|
||||
|
||||
// 1. Ñîçäàåì âðàùåíèå âîêðóã íîðìàëè òðåóãîëüíèêà (currentTriangle.normal)
|
||||
float angle = getRandomFloat(engine, 0.0f, 360.0f);
|
||||
// (Äëÿ ïðîñòîòû çäåñü èñïîëüçóåòñÿ Matrix4f::Identity, íî âàì íóæíî ðåàëèçîâàòü
|
||||
// QuaternionFromAxisAngle äëÿ êîððåêòíîãî âðàùåíèÿ âîêðóã çàäàííîé îñè Normal)
|
||||
|
||||
// --- ÏÐÎÑÒÎÅ ÐÅØÅÍÈÅ: Ñëó÷àéíûé ïîâîðîò âîêðóã òðåõ îñåé ---
|
||||
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);
|
||||
|
||||
|
||||
// --- 3.3. Òðàíñôîðìèðóåì è Ñìåùàåì âåðøèíû áàçîâîãî ìåøà ---
|
||||
|
||||
// Êîïèðóåì äàííûå äëÿ òåêóùåãî êàìíÿ
|
||||
VertexDataStruct currentStone = baseStone;
|
||||
|
||||
// Ïðèìåíÿåì ìàñøòàáèðîâàíèå, ïîâîðîò, è ñìåùåíèå ê êàæäîé âåðøèíå
|
||||
for (size_t j = 0; j < currentStone.PositionData.size(); j++) {
|
||||
Vector3f& pos = currentStone.PositionData[j];
|
||||
Vector3f& norm = currentStone.NormalData[j];
|
||||
|
||||
// 1. Ìàñøòàáèðîâàíèå
|
||||
pos.v[0] *= scaleFactors.v[0];
|
||||
pos.v[1] *= scaleFactors.v[1];
|
||||
pos.v[2] *= scaleFactors.v[2];
|
||||
|
||||
// 2. Ïîâîðîò
|
||||
pos = MultMatrixVector(rotationMatrix, pos);
|
||||
norm = MultMatrixVector(rotationMatrix, norm);
|
||||
|
||||
// 3. Ñìåùåíèå (Translation)
|
||||
pos = pos + stoneCenter;
|
||||
}
|
||||
|
||||
// --- 3.4. Îáúåäèíÿåì ìåøè ---
|
||||
finalMesh.PositionData.insert(finalMesh.PositionData.end(),
|
||||
currentStone.PositionData.begin(),
|
||||
currentStone.PositionData.end());
|
||||
|
||||
finalMesh.NormalData.insert(finalMesh.NormalData.end(),
|
||||
currentStone.NormalData.begin(),
|
||||
currentStone.NormalData.end());
|
||||
|
||||
finalMesh.TexCoordData.insert(finalMesh.TexCoordData.end(),
|
||||
currentStone.TexCoordData.begin(),
|
||||
currentStone.TexCoordData.end());
|
||||
|
||||
// ... àíàëîãè÷íî äëÿ äðóãèõ äàííûõ (Tangent, Binormal, Color)
|
||||
}
|
||||
}
|
||||
|
||||
return finalMesh;
|
||||
}
|
||||
} // namespace ZL
|
||||
11
StoneObject.h
Normal file
11
StoneObject.h
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include "ZLMath.h"
|
||||
#include "Renderer.h"
|
||||
#include "PlanetData.h"
|
||||
|
||||
namespace ZL {
|
||||
|
||||
VertexDataStruct CreateBaseConvexPolyhedron(uint64_t seed);
|
||||
VertexDataStruct CreateConvexPolyhedron(uint64_t seed, const LodLevel& planetLodLevel, const std::vector<int>& triangleIndices);
|
||||
|
||||
} // namespace ZL
|
||||
BIN
resources/DefaultMaterial_BaseColor.png
(Stored with Git LFS)
BIN
resources/DefaultMaterial_BaseColor.png
(Stored with Git LFS)
Binary file not shown.
BIN
resources/DefaultMaterial_BaseColor_shine.png
(Stored with Git LFS)
Normal file
BIN
resources/DefaultMaterial_BaseColor_shine.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/sand2.png
(Stored with Git LFS)
Normal file
BIN
resources/sand2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
11574
resources/spaceship006.txt
Normal file
11574
resources/spaceship006.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -30,7 +30,8 @@ void main()
|
||||
{
|
||||
// ... (1. Получаем цвет и 2. Расчет освещения)
|
||||
vec4 textureColor = texture2D(Texture, TexCoord);
|
||||
vec3 finalColor = textureColor.rgb * color;
|
||||
//vec3 finalColor = textureColor.rgb * color;
|
||||
vec3 finalColor = textureColor.rgb;
|
||||
|
||||
float diffuse = max(0.0, dot(normal, uLightDirection));
|
||||
float ambient = 0.2;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user