485 lines
21 KiB
C++
485 lines
21 KiB
C++
#include "PlanetData.h"
|
|
#include <iostream>
|
|
#include <numeric>
|
|
#include <cmath>
|
|
#include <algorithm>
|
|
|
|
namespace ZL {
|
|
|
|
const float PlanetData::PLANET_RADIUS = 20000.f;
|
|
const Vector3f PlanetData::PLANET_CENTER_OFFSET = Vector3f{ 0.f, 0.f, 0.0f };
|
|
|
|
// --- Êîíñòàíòû äèàïàçîíîâ (ïåðåíåñåíû èç PlanetObject.cpp) ---
|
|
static constexpr float FAR_Z_NEAR = 2000.0f;
|
|
static constexpr float FAR_Z_FAR = 200000.0f;
|
|
static constexpr float TRANSITION_FAR_START = 3000.0f;
|
|
static constexpr float MIDDLE_Z_NEAR = 500.f;
|
|
static constexpr float MIDDLE_Z_FAR = 100000.f;
|
|
static constexpr float TRANSITION_MIDDLE_START = 500.f;
|
|
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 = 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) {
|
|
return id1 < id2 ? id1 + "_" + id2 : id2 + "_" + id1;
|
|
}
|
|
|
|
// Âñïîìîãàòåëüíàÿ ôóíêöèÿ äëÿ ïðîåêöèè (ëîêàëüíàÿ)
|
|
static 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);
|
|
float distance = N.dot(AP);
|
|
return P + N * (-distance);
|
|
}
|
|
|
|
PlanetData::PlanetData()
|
|
: perlin(77777)
|
|
, colorPerlin(123123)
|
|
, currentLod(0)
|
|
{
|
|
currentLod = planetMeshLods.size() - 1; // Start with max LOD
|
|
|
|
initialVertexMap = {
|
|
{{ 0.0f, 1.0f, 0.0f}, "A"},
|
|
{{ 0.0f, -1.0f, 0.0f}, "B"},
|
|
{{ 1.0f, 0.0f, 0.0f}, "C"},
|
|
{{-1.0f, 0.0f, 0.0f}, "D"},
|
|
{{ 0.0f, 0.0f, 1.0f}, "E"},
|
|
{{ 0.0f, 0.0f, -1.0f}, "F"}
|
|
};
|
|
}
|
|
|
|
void PlanetData::init() {
|
|
for (int i = 0; i < planetMeshLods.size(); i++) {
|
|
planetMeshLods[i] = generateSphere(i, 0);
|
|
planetMeshLods[i].Scale(PLANET_RADIUS);
|
|
planetMeshLods[i].Move(PLANET_CENTER_OFFSET);
|
|
}
|
|
|
|
planetAtmosphereLod = generateSphere(5, 0);
|
|
planetAtmosphereLod.Scale(PLANET_RADIUS * 1.03);
|
|
planetAtmosphereLod.Move(PLANET_CENTER_OFFSET);
|
|
}
|
|
|
|
const LodLevel& PlanetData::getLodLevel(int level) const {
|
|
return planetMeshLods.at(level);
|
|
}
|
|
|
|
const LodLevel& PlanetData::getAtmosphereLod() const {
|
|
return planetAtmosphereLod;
|
|
}
|
|
|
|
int PlanetData::getCurrentLodIndex() const {
|
|
return currentLod;
|
|
}
|
|
|
|
int PlanetData::getMaxLodIndex() const {
|
|
return static_cast<int>(planetMeshLods.size() - 1);
|
|
}
|
|
|
|
std::pair<float, float> PlanetData::calculateZRange(float dToPlanetSurface) {
|
|
float currentZNear;
|
|
float currentZFar;
|
|
float alpha;
|
|
|
|
if (dToPlanetSurface >= TRANSITION_FAR_START) {
|
|
currentZNear = FAR_Z_NEAR;
|
|
currentZFar = FAR_Z_FAR;
|
|
}
|
|
else if (dToPlanetSurface > TRANSITION_MIDDLE_START) {
|
|
const float transitionLength = TRANSITION_FAR_START - TRANSITION_MIDDLE_START;
|
|
float normalizedDist = (dToPlanetSurface - TRANSITION_MIDDLE_START) / transitionLength;
|
|
alpha = 1.0f - normalizedDist;
|
|
currentZNear = FAR_Z_NEAR * (1.0f - alpha) + MIDDLE_Z_NEAR * alpha;
|
|
currentZFar = FAR_Z_FAR * (1.0f - alpha) + MIDDLE_Z_FAR * alpha;
|
|
}
|
|
else if (dToPlanetSurface > TRANSITION_NEAR_END) {
|
|
const float transitionLength = TRANSITION_MIDDLE_START - TRANSITION_NEAR_END;
|
|
float normalizedDist = (dToPlanetSurface - TRANSITION_NEAR_END) / transitionLength;
|
|
alpha = 1.0f - normalizedDist;
|
|
currentZNear = MIDDLE_Z_NEAR * (1.0f - alpha) + NEAR_Z_NEAR * alpha;
|
|
currentZFar = MIDDLE_Z_FAR * (1.0f - alpha) + NEAR_Z_FAR * alpha;
|
|
}
|
|
else if (dToPlanetSurface > TRANSITION_SUPER_NEAR_END) {
|
|
const float transitionLength = TRANSITION_NEAR_END - TRANSITION_SUPER_NEAR_END;
|
|
float normalizedDist = (dToPlanetSurface - TRANSITION_SUPER_NEAR_END) / transitionLength;
|
|
alpha = 1.0f - normalizedDist;
|
|
currentZNear = NEAR_Z_NEAR * (1.0f - alpha) + SUPER_NEAR_Z_NEAR * alpha;
|
|
currentZFar = NEAR_Z_FAR * (1.0f - alpha) + SUPER_NEAR_Z_FAR * alpha;
|
|
}
|
|
else {
|
|
currentZNear = SUPER_NEAR_Z_NEAR;
|
|
currentZFar = SUPER_NEAR_Z_FAR;
|
|
}
|
|
|
|
return { currentZNear, currentZFar };
|
|
}
|
|
|
|
|
|
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<int> targetTriangles = getTrianglesUnderCamera(viewerPosition);
|
|
|
|
if (targetTriangles.empty()) {
|
|
return (shipLocalPosition.length() - PLANET_RADIUS);
|
|
}
|
|
|
|
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;
|
|
|
|
return (shipLocalPosition - P_closest).length();
|
|
}
|
|
|
|
// --- Ðåàëèçàöèÿ getTrianglesUnderCamera (áûâøàÿ triangleUnderCamera) ---
|
|
// Âñïîìîãàòåëüíàÿ ðåêóðñèâíàÿ ôóíêöèÿ, ñêðûòàÿ îò ïóáëè÷íîãî API
|
|
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) {
|
|
if (pos.v[1] >= 0) {
|
|
if (pos.v[0] >= 0 && pos.v[2] >= 0) r.push_back(0);
|
|
if (pos.v[0] >= 0 && pos.v[2] <= 0) r.push_back(1);
|
|
if (pos.v[0] <= 0 && pos.v[2] <= 0) r.push_back(2);
|
|
if (pos.v[0] <= 0 && pos.v[2] >= 0) r.push_back(3);
|
|
}
|
|
if (pos.v[1] <= 0) {
|
|
if (pos.v[0] >= 0 && pos.v[2] >= 0) r.push_back(4);
|
|
if (pos.v[0] <= 0 && pos.v[2] >= 0) r.push_back(5);
|
|
if (pos.v[0] <= 0 && pos.v[2] <= 0) r.push_back(6);
|
|
if (pos.v[0] >= 0 && pos.v[2] <= 0) r.push_back(7);
|
|
}
|
|
}
|
|
else {
|
|
// Ðåêóðñèâíûé øàã
|
|
std::vector<int> r0 = recursiveTriangleSearch(lod - 1, pos, meshes);
|
|
for (int tri0 : r0) {
|
|
Vector3f a = meshes[lod - 1].vertexData.PositionData[tri0 * 3];
|
|
Vector3f b = meshes[lod - 1].vertexData.PositionData[tri0 * 3 + 1];
|
|
Vector3f c = meshes[lod - 1].vertexData.PositionData[tri0 * 3 + 2];
|
|
|
|
std::vector<int> result = PlanetData::find_sub_triangle_spherical(a, b, c, pos);
|
|
for (int trix : result) {
|
|
r.push_back(tri0 * 4 + trix);
|
|
}
|
|
}
|
|
}
|
|
return r;
|
|
}
|
|
|
|
std::vector<int> PlanetData::getTrianglesUnderCamera(const Vector3f& viewerPosition) {
|
|
// Âûçûâàåì ðåêóðñèþ ñ òåêóùèì LOD
|
|
return recursiveTriangleSearch(currentLod, viewerPosition, planetMeshLods);
|
|
}
|
|
|
|
// --- Îñòàëüíûå ìåòîäû (check_spherical_side, generateSphere è ò.ä.) ---
|
|
// (Êîïèðóéòå ðåàëèçàöèþ èç ñòàðîãî PlanetObject.cpp,
|
|
// çàìåíÿÿ îáðàùåíèÿ ê Environment::shipPosition íà àðãóìåíòû, åñëè íóæíî,
|
|
// è èñïîëüçóÿ this->planetMeshLods)
|
|
|
|
float PlanetData::check_spherical_side(const Vector3f& V1, const Vector3f& V2, const Vector3f& P, const Vector3f& V3, float epsilon) {
|
|
Vector3f N_plane = V1.cross(V2);
|
|
float sign_P = P.dot(N_plane);
|
|
float sign_V3 = V3.dot(N_plane);
|
|
return sign_P * sign_V3;
|
|
}
|
|
|
|
bool PlanetData::is_inside_spherical_triangle(const Vector3f& P, const Vector3f& V1, const Vector3f& V2, const Vector3f& V3, float epsilon) {
|
|
if (check_spherical_side(V1, V2, P, V3, epsilon) < -epsilon) return false;
|
|
if (check_spherical_side(V2, V3, P, V1, epsilon) < -epsilon) return false;
|
|
if (check_spherical_side(V3, V1, P, V2, epsilon) < -epsilon) return false;
|
|
return true;
|
|
}
|
|
|
|
std::vector<int> PlanetData::find_sub_triangle_spherical(const Vector3f& a_orig, const Vector3f& b_orig, const Vector3f& c_orig, const Vector3f& px_orig) {
|
|
const float EPSILON = 1e-6f;
|
|
std::vector<int> result;
|
|
const Vector3f a = a_orig.normalized();
|
|
const Vector3f b = b_orig.normalized();
|
|
const Vector3f c = c_orig.normalized();
|
|
const Vector3f pxx_normalized = px_orig.normalized();
|
|
const Vector3f m_ab = ((a + b) * 0.5f).normalized();
|
|
const Vector3f m_bc = ((b + c) * 0.5f).normalized();
|
|
const Vector3f m_ac = ((a + c) * 0.5f).normalized();
|
|
|
|
if (is_inside_spherical_triangle(pxx_normalized, a, m_ab, m_ac, EPSILON)) result.push_back(0);
|
|
if (is_inside_spherical_triangle(pxx_normalized, m_ab, b, m_bc, EPSILON)) result.push_back(1);
|
|
if (is_inside_spherical_triangle(pxx_normalized, m_ac, m_bc, c, EPSILON)) result.push_back(2);
|
|
if (is_inside_spherical_triangle(pxx_normalized, m_ab, m_bc, m_ac, EPSILON)) result.push_back(3);
|
|
|
|
return result;
|
|
}
|
|
|
|
// ... Ðåàëèçàöèè subdivideTriangles, calculateSurfaceNormal, trianglesToVertices, generateSphere, findNeighbors
|
|
// Ïåðåíåñèòå èõ èç PlanetObject.cpp "êàê åñòü", äîáàâèâ êëàññ PlanetData:: ïåðåä èìåíåì.
|
|
// Óáåäèòåñü, ÷òî èñïîëüçóåòå perlin è planetMeshLods èç this.
|
|
|
|
std::vector<Triangle> PlanetData::subdivideTriangles(const std::vector<Triangle>& input) {
|
|
std::vector<Triangle> output;
|
|
|
|
for (const auto& t : input) {
|
|
// Âåðøèíû è èõ ID
|
|
const Vector3f& a = t.data[0];
|
|
const Vector3f& b = t.data[1];
|
|
const Vector3f& c = t.data[2];
|
|
const VertexID& id_a = t.ids[0];
|
|
const VertexID& id_b = t.ids[1];
|
|
const VertexID& id_c = t.ids[2];
|
|
|
|
// 1. Âû÷èñëÿåì ñåðåäèíû (êîîðäèíàòû)
|
|
Vector3f m_ab = ((a + b) * 0.5f).normalized();
|
|
Vector3f m_bc = ((b + c) * 0.5f).normalized();
|
|
Vector3f m_ac = ((a + c) * 0.5f).normalized();
|
|
|
|
// 2. Âû÷èñëÿåì ID íîâûõ âåðøèí
|
|
VertexID id_mab = generateEdgeID(id_a, id_b);
|
|
VertexID id_mbc = generateEdgeID(id_b, id_c);
|
|
VertexID id_mac = generateEdgeID(id_a, id_c);
|
|
|
|
// 3. Ôîðìèðóåì 4 íîâûõ òðåóãîëüíèêà
|
|
output.emplace_back(Triangle{ {a, m_ab, m_ac}, {id_a, id_mab, id_mac} }); // 0
|
|
output.emplace_back(Triangle{ {m_ab, b, m_bc}, {id_mab, id_b, id_mbc} }); // 1
|
|
output.emplace_back(Triangle{ {m_ac, m_bc, c}, {id_mac, id_mbc, id_c} }); // 2
|
|
output.emplace_back(Triangle{ {m_ab, m_bc, m_ac}, {id_mab, id_mbc, id_mac} }); // 3
|
|
}
|
|
return output;
|
|
}
|
|
|
|
Vector3f PlanetData::calculateSurfaceNormal(Vector3f p_sphere, float noiseCoeff) {
|
|
// p_sphere - ýòî íîðìàëèçîâàííûé âåêòîð (òî÷êà íà èäåàëüíîé ñôåðå)
|
|
|
|
float theta = 0.01f; // Øàã äëÿ "ùóïàíüÿ" ñîñåäåé (epsilon)
|
|
|
|
// Íàì íóæíî íàéòè äâà âåêòîðà, êàñàòåëüíûõ ê ñôåðå â òî÷êå p_sphere.
|
|
// Äëÿ ýòîãî áåðåì ëþáîé âåêòîð (íàïðèìåð UP), äåëàåì Cross Product, ÷òîáû ïîëó÷èòü êàñàòåëüíóþ.
|
|
// Åñëè p_sphere ñîâïàäàåò ñ UP, áåðåì RIGHT.
|
|
Vector3f up = Vector3f(0.0f, 1.0f, 0.0f);
|
|
if (abs(p_sphere.dot(up)) > 0.99f) {
|
|
up = Vector3f(1.0f, 0.0f, 0.0f);
|
|
}
|
|
|
|
Vector3f tangentX = (up.cross(p_sphere)).normalized();
|
|
Vector3f tangentY = (p_sphere.cross(tangentX)).normalized();
|
|
|
|
// Òî÷êè íà èäåàëüíîé ñôåðå ñî ñìåùåíèåì
|
|
Vector3f p0_dir = p_sphere;
|
|
Vector3f p1_dir = (p_sphere + tangentX * theta).normalized();
|
|
Vector3f p2_dir = (p_sphere + tangentY * theta).normalized();
|
|
|
|
// Ðåàëüíûå òî÷êè íà èñêàæåííîé ïîâåðõíîñòè
|
|
// p = dir * height(dir)
|
|
Vector3f p0 = p0_dir * perlin.getSurfaceHeight(p0_dir, noiseCoeff);
|
|
Vector3f p1 = p1_dir * perlin.getSurfaceHeight(p1_dir, noiseCoeff);
|
|
Vector3f p2 = p2_dir * perlin.getSurfaceHeight(p2_dir, noiseCoeff);
|
|
|
|
// Âåêòîðà îò öåíòðàëüíîé òî÷êè ê ñîñåäÿì
|
|
Vector3f v1 = p1 - p0;
|
|
Vector3f v2 = p2 - p0;
|
|
|
|
// Íîðìàëü - ýòî ïåðïåíäèêóëÿð ê ýòèì äâóì âåêòîðàì
|
|
// Ïîðÿäîê (v2, v1) èëè (v1, v2) çàâèñèò îò ñèñòåìû êîîðäèíàò,
|
|
// çäåñü ïîäáèðàåì òàê, ÷òîáû íîðìàëü ñìîòðåëà íàðóæó.
|
|
return (-v2.cross(v1)).normalized();
|
|
}
|
|
|
|
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); // <-- ÐÅÇÅÐÂÈÐÓÅÌ
|
|
//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) {
|
|
for (int i = 0; i < 3; ++i) {
|
|
// Çàïîëíÿåì PositionData
|
|
result.vertexData.PositionData.push_back(t.data[i]);
|
|
|
|
// Çàïîëíÿåì 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]);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
LodLevel PlanetData::generateSphere(int subdivisions, float noiseCoeff) {
|
|
// 1. Èñõîäíûé îêòàýäð è ïðèñâîåíèå ID
|
|
std::vector<Triangle> geometry = {
|
|
{{ 0.0f, 1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, { 1.0f, 0.0f, 0.0f}}, // 0
|
|
{{ 0.0f, 1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}}, // 1
|
|
{{ 0.0f, 1.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}, {-1.0f, 0.0f, 0.0f}}, // 2
|
|
{{ 0.0f, 1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}}, // 3
|
|
{{ 0.0f, -1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}}, // 4
|
|
{{ 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, 0.0f}}, // 5
|
|
{{ 0.0f, -1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}}, // 6
|
|
{{ 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}, { 1.0f, 0.0f, 0.0f}} // 7
|
|
};
|
|
|
|
// Ïðèñâîåíèå ID èñõîäíûì âåðøèíàì
|
|
for (auto& t : geometry) {
|
|
for (int i = 0; i < 3; i++) {
|
|
// Èñïîëüçóåì map äëÿ ïîëó÷åíèÿ ID ïî ÷èñòûì êîîðäèíàòàì (íîðì. == ÷èñòûå)
|
|
t.ids[i] = initialVertexMap[t.data[i].normalized()];
|
|
}
|
|
}
|
|
|
|
// 2. ÏÐÈÌÅÍßÅÌ ØÓÌ Ê ÈÑÕÎÄÍÛÌ ÂÅÐØÈÍÀÌ
|
|
// ÂÀÆÍÎ: Ìû ïðèìåíÿåì øóì ÏÎÑËÅ íîðìàëèçàöèè, íî ïåðåä ðàçáèåíèåì.
|
|
// Åñëè âû õîòèòå, ÷òîáû øóì áûë ïðèìåíåí òîëüêî ê êîíå÷íûì âåðøèíàì,
|
|
// ïåðåìåñòèòå ýòîò áëîê ïîñëå øàãà 3. Îñòàâèì, êàê â âàøåì êîäå.
|
|
// **ÏÐÈÌÅ×ÀÍÈÅ:** Åñëè øóì ïðèìåíåí ñåé÷àñ, òî âåðøèíû íà L>0 áóäóò èìåòü
|
|
// êîîðäèíàòû (m_ab = (a_noisy + b_noisy)*0.5).
|
|
// Åñëè âû õîòèòå, ÷òîáû òîëüêî ôèíàëüíûå âåðøèíû èìåëè øóì, ïðîïóñòèòå ýòîò áëîê.
|
|
//  òåêóùåé çàäà÷å ýòî íå êðèòè÷íî, òàê êàê ìû èñïîëüçóåì ÒÎËÜÊÎ VertexID.
|
|
|
|
// 3. Ðàçáèâàåì N ðàç (â subdivideTriangles ãåíåðèðóþòñÿ ID íîâûõ âåðøèí)
|
|
for (int i = 0; i < subdivisions; i++) {
|
|
geometry = subdivideTriangles(geometry);
|
|
}
|
|
|
|
// 4. Ãåíåðèðóåì PositionData, NormalData è VertexIDs
|
|
LodLevel lodLevel = trianglesToVertices(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) {
|
|
for (int j = 0; j < 3; ++j) {
|
|
VertexID v_id = finalVertexIDs[i * 3 + j];
|
|
|
|
// Åñëè êëþ÷ óæå åñòü, ïðîñòî äîáàâëÿåì èíäåêñ
|
|
v2tMap[v_id].push_back((int)i);
|
|
}
|
|
}
|
|
lodLevel.v2tMap = v2tMap;
|
|
|
|
// 6. Ïðèìåíåíèå ôèíàëüíîãî øóìà (åñëè âû õîòåëè, ÷òîáû øóì áûë òîëüêî çäåñü)
|
|
// Çäåñü ìû äîëæíû áûëè áû ïðèìåíèòü øóì ê buffer.PositionData,
|
|
// íî â âàøåì èñõîäíîì êîäå øóì ïðèìåíÿëñÿ ðàíåå.
|
|
// Ïðåäïîëàãàåì, ÷òî øóì áóäåò ïðèìåíåí çäåñü (èíà÷å v2tMap íå áóäåò ñîîòâåòñòâîâàòü).
|
|
// ÂÎÑÑÒÀÍÎÂÈÌ ØÀÃ 2, íî äëÿ ôèíàëüíîé ãåîìåòðèè:
|
|
for (size_t i = 0; i < lodLevel.vertexData.PositionData.size(); i++) {
|
|
Vector3f dir = lodLevel.vertexData.PositionData[i].normalized();
|
|
lodLevel.vertexData.PositionData[i] = dir * perlin.getSurfaceHeight(dir, noiseCoeff);
|
|
// Îáðàòèòå âíèìàíèå: NormalData îñòàåòñÿ (dir), êàê â âàøåì êîäå
|
|
lodLevel.vertexData.NormalData[i] = dir;
|
|
}
|
|
|
|
|
|
// 7. Ãåíåðàöèÿ ColorData
|
|
lodLevel.vertexData.ColorData.reserve(geometry.size() * 3);
|
|
const Vector3f baseColor = { 0.498f, 0.416f, 0.0f };
|
|
const float colorFrequency = 5.0f;
|
|
const float colorAmplitude = 0.2f;
|
|
const Vector3f offsetR = { 0.1f, 0.2f, 0.3f };
|
|
const Vector3f offsetG = { 0.5f, 0.4f, 0.6f };
|
|
const Vector3f offsetB = { 0.9f, 0.8f, 0.7f };
|
|
|
|
|
|
for (size_t i = 0; i < geometry.size(); i++) {
|
|
for (int j = 0; j < 3; j++) {
|
|
// Èñïîëüçóåì íîðìàëèçîâàííûé âåêòîð èç PositionData (êîòîðûé ðàâåí NormalData)
|
|
Vector3f dir = lodLevel.vertexData.NormalData[i * 3 + j];
|
|
|
|
// Âû÷èñëåíèå öâåòîâîãî øóìà
|
|
float noiseR = colorPerlin.noise(
|
|
(dir.v[0] + offsetR.v[0]) * colorFrequency,
|
|
(dir.v[1] + offsetR.v[1]) * colorFrequency,
|
|
(dir.v[2] + offsetR.v[2]) * colorFrequency
|
|
);
|
|
// ... (àíàëîãè÷íî äëÿ noiseG è noiseB)
|
|
|
|
// Çäåñü ìû èñïîëüçóåì çàãëóøêè, òàê êàê íåò ïîëíîãî îïðåäåëåíèÿ PerlinNoise
|
|
float noiseG = 0.0f;
|
|
float noiseB = 0.0f;
|
|
|
|
Vector3f colorOffset = {
|
|
noiseR * colorAmplitude,
|
|
noiseG * colorAmplitude,
|
|
noiseB * colorAmplitude
|
|
};
|
|
|
|
Vector3f finalColor = baseColor + colorOffset;
|
|
// ... (îãðàíè÷åíèÿ öâåòà)
|
|
|
|
lodLevel.vertexData.ColorData.push_back(finalColor);
|
|
}
|
|
}
|
|
|
|
return lodLevel;
|
|
}
|
|
|
|
|
|
// Ïðèìåð findNeighbors:
|
|
std::vector<int> 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<int> 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<int>(neighbors.begin(), neighbors.end());
|
|
}
|
|
|
|
// ... È îñòàëüíûå ìåòîäû ãåíåðàöèè ...
|
|
|
|
} |