277 lines
9.9 KiB
C++
277 lines
9.9 KiB
C++
#include "StoneObject.h"
|
|
|
|
#include "Utils.h"
|
|
#include <GL/gl.h>
|
|
#include <random>
|
|
#include <cmath>
|
|
#include "Renderer.h"
|
|
#include "PlanetData.h"
|
|
|
|
namespace ZL {
|
|
|
|
|
|
// --- ÊÎÍÑÒÀÍÒÛ ÏÀÐÀÌÅÒÐÎÂ (êàê âû ïðîñèëè) ---
|
|
const float StoneParams::BASE_SCALE = 17.0f; // Îáùèé ðàçìåð êàìíÿ
|
|
//const float StoneParams::BASE_SCALE = 5000.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_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;
|
|
|
|
// Âñïîìîãàòåëüíàÿ ôóíêöèÿ äëÿ ïîëó÷åíèÿ ñëó÷àéíîãî ÷èñëà â äèàïàçîíå [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 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() * StoneParams::BASE_SCALE; // Íîðìàëèçàöèÿ ê ñôåðå ðàäèóñà BASE_SCALE
|
|
|
|
// Ðàäèàëüíîå âîçìóùåíèå:
|
|
float perturbation = getRandomFloat(engine, StoneParams::MIN_PERTURBATION, StoneParams::MAX_PERTURBATION);
|
|
v = v * (1.0f + perturbation);
|
|
}
|
|
|
|
// 2. Òðàíñôîðìàöèÿ (Ìàñøòàáèðîâàíèå è Ïîâîðîò)
|
|
|
|
// Ñëó÷àéíûå ìàñøòàáû ïî îñÿì
|
|
Vector3f scaleFactors = {
|
|
getRandomFloat(engine, StoneParams::MIN_AXIS_SCALE, StoneParams::MAX_AXIS_SCALE),
|
|
getRandomFloat(engine, StoneParams::MIN_AXIS_SCALE, StoneParams::MAX_AXIS_SCALE),
|
|
getRandomFloat(engine, StoneParams::MIN_AXIS_SCALE, StoneParams::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;
|
|
}
|
|
|
|
StoneGroup CreateStoneGroupData(uint64_t globalSeed, const LodLevel& planetLodLevel) {
|
|
StoneGroup group;
|
|
|
|
// Ðåçåðâèðóåì ìåñòî ïîä âñå òðåóãîëüíèêè òåêóùåãî LOD
|
|
group.allInstances.resize(planetLodLevel.triangles.size());
|
|
|
|
for (size_t tIdx = 0; tIdx < planetLodLevel.triangles.size(); ++tIdx) {
|
|
const Triangle& tri = planetLodLevel.triangles[tIdx];
|
|
std::mt19937 engine(static_cast<unsigned int>(globalSeed));
|
|
|
|
for (int i = 0; i < StoneParams::STONES_PER_TRIANGLE; ++i) {
|
|
StoneInstance instance;
|
|
instance.seed = globalSeed;// + tIdx * 1000 + i; // Óíèêàëüíûé ñèä äëÿ êàæäîãî êàìíÿ
|
|
|
|
instance.position = GetRandomPointOnTriangle(tri, engine);
|
|
|
|
//instance.position = Vector3f(5000.0f, 5000.0f, 5000.0f);
|
|
// Ãåíåðèðóåì ñëó÷àéíûå ïàðàìåòðû îäèí ðàç
|
|
instance.scale = {
|
|
getRandomFloat(engine, 0.5f, 1.5f),
|
|
getRandomFloat(engine, 0.5f, 1.5f),
|
|
getRandomFloat(engine, 0.5f, 1.5f)
|
|
};
|
|
|
|
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();
|
|
|
|
group.allInstances[tIdx].push_back(instance);
|
|
}
|
|
}
|
|
return group;
|
|
}
|
|
|
|
void StoneGroup::inflate(const std::vector<int>& triangleIndices) {
|
|
// 1. Î÷èùàåì òåêóùèé ìåø ïåðåä çàïîëíåíèåì
|
|
mesh.PositionData.clear();
|
|
mesh.NormalData.clear();
|
|
mesh.TexCoordData.clear();
|
|
|
|
static VertexDataStruct baseStone = CreateBaseConvexPolyhedron(1337);
|
|
|
|
// 2. Íàïîëíÿåì ìåø òîëüêî äëÿ âèäèìûõ òðåóãîëüíèêîâ
|
|
for (int tIdx : triangleIndices) {
|
|
if (tIdx >= allInstances.size()) continue;
|
|
|
|
for (const auto& inst : allInstances[tIdx]) {
|
|
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];
|
|
p.v[1] *= inst.scale.v[1];
|
|
p.v[2] *= inst.scale.v[2];
|
|
|
|
mesh.PositionData.push_back(MultMatrixVector(rotMat, p) + inst.position);
|
|
mesh.NormalData.push_back(MultMatrixVector(rotMat, n));
|
|
mesh.TexCoordData.push_back(baseStone.TexCoordData[j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} // namespace ZL
|