Make IcoSphere

This commit is contained in:
Vladislav Khorev 2026-01-03 17:29:40 +03:00
parent 570c96a628
commit c553780b6e
7 changed files with 174 additions and 340 deletions

View File

@ -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<int> 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<int> PlanetData::getTrianglesUnderCameraNew(const Vector3f& viewerPosition) {
std::vector<int> 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<int> resultSet;
resultSet.insert(bestTriangle);
return { bestTriangle };
}
// Äîáàâëÿåì ïåðâûé êðóã ñîñåäåé
std::vector<int> neighbors = findNeighbors(bestTriangle, currentLod);
for (int n : neighbors) {
resultSet.insert(n);
std::vector<int> 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<int> 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<int> 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<int>(resultSet.begin(), resultSet.end());
if (result.empty()) return getBestTriangleUnderCamera(viewerPosition);
return result;
}
std::vector<Triangle> PlanetData::subdivideTriangles(const std::vector<Triangle>& input, float noiseCoeff) {
@ -394,141 +337,94 @@ namespace ZL {
}
}
LodLevel PlanetData::generateSphere(int subdivisions, float noiseCoeff) {
// 1. Èñõîäíûé îêòàýäð è ïðèñâîåíèå ID
std::vector<Triangle> 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<Vector3f> 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<IndexedTri> 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<Triangle> 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<VertexID, Vector3f> 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<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());
}
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<VertexID, Vector3f> newPositions;
// 1. Ñîáèðàåì ñîñåäåé è òåêóùèå ïîçèöèè èç triangles
for (auto const& [vID, connectedTriangles] : lod.v2tMap) {
Vector3f currentPos;
std::set<VertexID> 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]];

View File

@ -102,14 +102,13 @@ namespace ZL {
// Ëîãèêà
std::pair<float, float> calculateZRange(float distanceToSurface);
float distanceToPlanetSurface(const Vector3f& viewerPosition);
float distanceToPlanetSurfaceFast(const Vector3f& viewerPosition);
// Âîçâðàùàåò èíäåêñû òðåóãîëüíèêîâ, âèäèìûõ êàìåðîé
std::vector<int> getTrianglesUnderCameraNew(const Vector3f& viewerPosition);
std::vector<int> findNeighbors(int index, int lod);
std::vector<int> getBestTriangleUnderCamera(const Vector3f& viewerPosition);
std::vector<int> getTrianglesUnderCameraNew2(const Vector3f& viewerPosition);
void applySphericalLaplacianSmoothing(LodLevel& lod, int iterations, float relaxationFactor);
void applySphericalRelaxation(LodLevel& lod, int iterations);
};
} // namespace ZL

View File

@ -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();
float movementThreshold = 1.0f;
if ((Environment::shipPosition - lastUpdatePos).squaredNorm() < movementThreshold * movementThreshold && !triangleIndicesToDraw.empty()) {
return;
}
lastUpdatePos = Environment::shipPosition;
// Временный вектор для сбора новых индексов
std::vector<int> newIndices;
auto newIndices = planetData.getTrianglesUnderCameraNew2(Environment::shipPosition);
newIndices = lr;
// 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); // Не забываем выключить, чтобы не сломать остальной рендер
@ -226,8 +195,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<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);
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";

View File

@ -22,26 +22,24 @@ namespace ZL {
class PlanetObject {
public:
// Агрегация: логика и данные теперь здесь
PlanetData planetData;
// Данные только для рендеринга (OpenGL specific)
VertexRenderStruct planetRenderStruct;
VertexRenderStruct planetRenderYellowStruct;
VertexRenderStruct planetAtmosphereRenderStruct;
StoneGroup planetStones;
std::vector<VertexRenderStruct> stonesToRender;
VertexRenderStruct stoneToBake;
std::vector<int> triangleIndicesToDraw;
std::shared_ptr<Texture> sandTexture;
std::shared_ptr<Texture> stoneTexture;
bool drawDataDirty = true;
void prepareDrawData();
std::unique_ptr<FrameBuffer> 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);
};

View File

@ -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<VertexRenderStruct> StoneGroup::inflate(int count)
{
static VertexDataStruct baseStone = CreateBaseConvexPolyhedron(1337);
//static VertexDataStruct baseStone = CreateBaseConvexPolyhedron(1337);
std::vector<VertexRenderStruct> 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

View File

@ -31,6 +31,8 @@ namespace ZL {
// Очищает старую геометрию и генерирует новую для указанных индексов
std::vector<VertexRenderStruct> inflate(int count);
VertexRenderStruct inflateOne(int index, float scaleModifier);
};
// Теперь возвращает заготовку со всеми параметрами, но без тяжелого меша

View File

@ -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<float, 4> v = { 0.f, 0.f, 0.f, 0.f };
Vector4f normalized() const {