Neighbours finding well
This commit is contained in:
parent
16ba536481
commit
a91d7c04e8
323
PlanetObject.cpp
323
PlanetObject.cpp
@ -43,6 +43,12 @@ namespace ZL {
|
|||||||
// Дистанция, где ЗАВЕРШАЕТСЯ переход MIDDLE -> NEAR
|
// Дистанция, где ЗАВЕРШАЕТСЯ переход MIDDLE -> NEAR
|
||||||
static constexpr float TRANSITION_SUPER_NEAR_END = 10.f;
|
static constexpr float TRANSITION_SUPER_NEAR_END = 10.f;
|
||||||
|
|
||||||
|
|
||||||
|
VertexID generateEdgeID(const VertexID& id1, const VertexID& id2) {
|
||||||
|
// Канонический вид для ребра V1-V2: (min(ID1, ID2) + "_" + max(ID1, ID2))
|
||||||
|
return id1 < id2 ? id1 + "_" + id2 : id2 + "_" + id1;
|
||||||
|
}
|
||||||
|
|
||||||
std::pair<float, float> calculateZRange(const Vector3f& shipPosition) {
|
std::pair<float, float> calculateZRange(const Vector3f& shipPosition) {
|
||||||
|
|
||||||
// 1. Вычисление расстояния до поверхности планеты
|
// 1. Вычисление расстояния до поверхности планеты
|
||||||
@ -210,28 +216,24 @@ namespace ZL {
|
|||||||
|
|
||||||
void PlanetObject::init() {
|
void PlanetObject::init() {
|
||||||
|
|
||||||
planetMeshLods[0] = generateSphere(0);
|
for (int i = 0; i < planetMeshLods.size(); i++) {
|
||||||
|
planetMeshLods[i] = generateSphere(i);
|
||||||
|
planetMeshLods[i].vertexData.Scale(PLANET_RADIUS);
|
||||||
|
planetMeshLods[i].vertexData.Move(PLANET_CENTER_OFFSET);
|
||||||
|
}
|
||||||
|
|
||||||
planetMeshLods[0].Scale(PLANET_RADIUS);
|
planetRenderStruct.data = planetMeshLods[currentLod].vertexData;
|
||||||
planetMeshLods[0].Move(PLANET_CENTER_OFFSET);
|
|
||||||
|
|
||||||
planetMeshLods[1] = generateSphere(1);
|
|
||||||
|
|
||||||
planetMeshLods[1].Scale(PLANET_RADIUS);
|
|
||||||
planetMeshLods[1].Move(PLANET_CENTER_OFFSET);
|
|
||||||
|
|
||||||
|
|
||||||
planetRenderStruct.data = planetMeshLods[1];
|
|
||||||
planetRenderStruct.RefreshVBO();
|
planetRenderStruct.RefreshVBO();
|
||||||
|
|
||||||
sandTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/sand.png", ""));
|
sandTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/sand.png", ""));
|
||||||
//sandTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/rock.png", ""));
|
//sandTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/rock.png", ""));
|
||||||
|
|
||||||
planetAtmosphere.data = generateSphere(5);
|
/*
|
||||||
|
planetAtmosphere.data = generateSphereOld(5);
|
||||||
planetAtmosphere.data.Scale(PLANET_RADIUS*1.03);
|
planetAtmosphere.data.Scale(PLANET_RADIUS*1.03);
|
||||||
planetAtmosphere.data.Move(PLANET_CENTER_OFFSET);
|
planetAtmosphere.data.Move(PLANET_CENTER_OFFSET);
|
||||||
|
|
||||||
planetAtmosphere.RefreshVBO();
|
planetAtmosphere.RefreshVBO();*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlanetObject::prepareDrawData() {
|
void PlanetObject::prepareDrawData() {
|
||||||
@ -341,7 +343,13 @@ namespace ZL {
|
|||||||
renderer.RotateMatrix(Environment::inverseShipMatrix);
|
renderer.RotateMatrix(Environment::inverseShipMatrix);
|
||||||
renderer.TranslateMatrix(-Environment::shipPosition);
|
renderer.TranslateMatrix(-Environment::shipPosition);
|
||||||
|
|
||||||
|
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);
|
renderer.DrawVertexRenderStruct(planetRenderRedStruct);
|
||||||
|
|
||||||
|
renderer.RenderUniform3fv("uColor", &color2.v[0]);
|
||||||
|
renderer.DrawVertexRenderStruct(planetRenderYellowStruct);
|
||||||
//glDisable(GL_BLEND);
|
//glDisable(GL_BLEND);
|
||||||
CheckGlError();
|
CheckGlError();
|
||||||
|
|
||||||
@ -416,47 +424,69 @@ namespace ZL {
|
|||||||
|
|
||||||
auto lr = triangleUnderCamera(currentLod);
|
auto lr = triangleUnderCamera(currentLod);
|
||||||
planetRenderRedStruct.data.PositionData.clear();
|
planetRenderRedStruct.data.PositionData.clear();
|
||||||
|
planetRenderYellowStruct.data.PositionData.clear();
|
||||||
|
|
||||||
|
std::set<int> usedYellow;
|
||||||
|
|
||||||
for (int i : lr)
|
for (int i : lr)
|
||||||
{
|
{
|
||||||
planetRenderRedStruct.data.PositionData.push_back(planetMeshLods[currentLod].PositionData[i * 3]);
|
planetRenderRedStruct.data.PositionData.push_back(planetMeshLods[currentLod].vertexData.PositionData[i * 3]);
|
||||||
planetRenderRedStruct.data.PositionData.push_back(planetMeshLods[currentLod].PositionData[i * 3+1]);
|
planetRenderRedStruct.data.PositionData.push_back(planetMeshLods[currentLod].vertexData.PositionData[i * 3 + 1]);
|
||||||
planetRenderRedStruct.data.PositionData.push_back(planetMeshLods[currentLod].PositionData[i * 3+2]);
|
planetRenderRedStruct.data.PositionData.push_back(planetMeshLods[currentLod].vertexData.PositionData[i * 3 + 2]);
|
||||||
|
|
||||||
|
usedYellow.insert(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
planetRenderRedStruct.RefreshVBO();
|
planetRenderRedStruct.RefreshVBO();
|
||||||
|
|
||||||
|
for (int i : lr)
|
||||||
|
{
|
||||||
|
auto neighbors = findNeighbors(i, currentLod);
|
||||||
|
for (int n : neighbors)
|
||||||
|
{
|
||||||
|
if (usedYellow.count(n) == 0)
|
||||||
|
{
|
||||||
|
usedYellow.insert(n);
|
||||||
|
planetRenderYellowStruct.data.PositionData.push_back(planetMeshLods[currentLod].vertexData.PositionData[n * 3]);
|
||||||
|
planetRenderYellowStruct.data.PositionData.push_back(planetMeshLods[currentLod].vertexData.PositionData[n * 3 + 1]);
|
||||||
|
planetRenderYellowStruct.data.PositionData.push_back(planetMeshLods[currentLod].vertexData.PositionData[n * 3 + 2]);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
planetRenderYellowStruct.RefreshVBO();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Triangle> PlanetObject::subdivideTriangles(const std::vector<Triangle>& inputTriangles) {
|
std::vector<Triangle> PlanetObject::subdivideTriangles(const std::vector<Triangle>& input) {
|
||||||
std::vector<Triangle> output;
|
std::vector<Triangle> output;
|
||||||
output.reserve(inputTriangles.size() * 4);
|
|
||||||
|
|
||||||
for (const auto& t : inputTriangles) {
|
for (const auto& t : input) {
|
||||||
Vector3f a = t.data[0];
|
// Вершины и их ID
|
||||||
Vector3f b = t.data[1];
|
const Vector3f& a = t.data[0];
|
||||||
Vector3f c = t.data[2];
|
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. Вычисляем "сырые" середины
|
// 1. Вычисляем середины (координаты)
|
||||||
Vector3f m_ab = (a + b) * 0.5f;
|
Vector3f m_ab = ((a + b) * 0.5f).normalized();
|
||||||
Vector3f m_bc = (b + c) * 0.5f;
|
Vector3f m_bc = ((b + c) * 0.5f).normalized();
|
||||||
Vector3f m_ac = (a + c) * 0.5f;
|
Vector3f m_ac = ((a + c) * 0.5f).normalized();
|
||||||
|
|
||||||
// 2. Нормализуем их (получаем идеальную сферу радиуса 1)
|
// 2. Вычисляем ID новых вершин
|
||||||
m_ab = m_ab.normalized();
|
VertexID id_mab = generateEdgeID(id_a, id_b);
|
||||||
m_bc = m_bc.normalized();
|
VertexID id_mbc = generateEdgeID(id_b, id_c);
|
||||||
m_ac = m_ac.normalized();
|
VertexID id_mac = generateEdgeID(id_a, id_c);
|
||||||
|
|
||||||
// 3. ПРИМЕНЯЕМ ШУМ: Смещаем точку по радиусу
|
// 3. Формируем 4 новых треугольника
|
||||||
m_ab = m_ab * perlin.getSurfaceHeight(m_ab);
|
output.emplace_back(Triangle{ {a, m_ab, m_ac}, {id_a, id_mab, id_mac} }); // 0
|
||||||
m_bc = m_bc * perlin.getSurfaceHeight(m_bc);
|
output.emplace_back(Triangle{ {m_ab, b, m_bc}, {id_mab, id_b, id_mbc} }); // 1
|
||||||
m_ac = m_ac * perlin.getSurfaceHeight(m_ac);
|
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
|
||||||
// 4. Формируем новые треугольники
|
|
||||||
output.emplace_back(a, m_ab, m_ac);
|
|
||||||
output.emplace_back(m_ab, b, m_bc);
|
|
||||||
output.emplace_back(m_ac, m_bc, c);
|
|
||||||
output.emplace_back(m_ab, m_bc, m_ac);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -497,87 +527,97 @@ namespace ZL {
|
|||||||
return (-v2.cross(v1)).normalized();
|
return (-v2.cross(v1)).normalized();
|
||||||
}
|
}
|
||||||
|
|
||||||
VertexDataStruct PlanetObject::trianglesToVertices(const std::vector<Triangle>& triangles) {
|
LodLevel PlanetObject::trianglesToVertices(const std::vector<Triangle>& geometry) {
|
||||||
VertexDataStruct buffer;
|
LodLevel result;
|
||||||
buffer.PositionData.reserve(triangles.size() * 3);
|
|
||||||
buffer.NormalData.reserve(triangles.size() * 3);
|
|
||||||
buffer.TexCoordData.reserve(triangles.size() * 3); // <-- РЕЗЕРВИРУЕМ
|
|
||||||
//buffer.TexCoord3Data.reserve(triangles.size() * 3); // <-- РЕЗЕРВИРУЕМ
|
|
||||||
|
|
||||||
// Стандартные UV-координаты для покрытия одного треугольника
|
result.vertexData.PositionData.reserve(geometry.size() * 3);
|
||||||
// Покрывает текстурой всю грань.
|
result.vertexData.NormalData.reserve(geometry.size() * 3);
|
||||||
const std::array<Vector2f, 3> triangleUVs = {
|
result.VertexIDs.reserve(geometry.size() * 3); // Заполняем ID здесь
|
||||||
Vector2f(0.0f, 0.0f),
|
|
||||||
Vector2f(1.0f, 0.0f),
|
|
||||||
Vector2f(0.0f, 1.0f)
|
|
||||||
};
|
|
||||||
/*
|
|
||||||
const std::array<Vector3f, 3> barycentricCoords = {
|
|
||||||
Vector3f(1.0f, 0.0f, 0.0f), // Вершина 1
|
|
||||||
Vector3f(0.0f, 1.0f, 0.0f), // Вершина 2
|
|
||||||
Vector3f(0.0f, 0.0f, 1.0f) // Вершина 3
|
|
||||||
};*/
|
|
||||||
|
|
||||||
for (const auto& t : triangles) {
|
for (const auto& t : geometry) {
|
||||||
// Проходим по всем 3 вершинам треугольника
|
for (int i = 0; i < 3; ++i) {
|
||||||
for (int i = 0; i < 3; i++) {
|
// Заполняем PositionData
|
||||||
// p_geometry - это уже точка на поверхности (с шумом)
|
result.vertexData.PositionData.push_back(t.data[i]);
|
||||||
Vector3f p_geometry = t.data[i];
|
|
||||||
|
|
||||||
// Нам нужно восстановить направление от центра к этой точке,
|
// Заполняем NormalData (нормаль = нормализованная позиция на сфере)
|
||||||
// чтобы передать его в функцию расчета нормали.
|
result.vertexData.NormalData.push_back(t.data[i].normalized());
|
||||||
// Так как (0,0,0) - центр, то normalize(p) даст нам направление.
|
|
||||||
Vector3f p_dir = p_geometry.normalized();
|
|
||||||
|
|
||||||
// Считаем аналитическую нормаль для этой конкретной точки
|
|
||||||
Vector3f normal = calculateSurfaceNormal(p_dir);
|
|
||||||
|
|
||||||
buffer.PositionData.push_back({ p_geometry });
|
|
||||||
buffer.NormalData.push_back({ normal });
|
|
||||||
//buffer.TexCoord3Data.push_back(barycentricCoords[i]);
|
|
||||||
buffer.TexCoordData.push_back(triangleUVs[i]);
|
|
||||||
|
|
||||||
|
// Заполняем VertexIDs
|
||||||
|
result.VertexIDs.push_back(t.ids[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return buffer;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VertexDataStruct PlanetObject::generateSphere(int subdivisions) {
|
LodLevel PlanetObject::generateSphere(int subdivisions) {
|
||||||
// 1. Исходный октаэдр
|
// 1. Исходный октаэдр и присвоение ID
|
||||||
std::vector<Triangle> geometry = {
|
std::vector<Triangle> geometry = {
|
||||||
Triangle{{ 0.0f, 1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, { 1.0f, 0.0f, 0.0f}}, // Top-Front-Right
|
{{ 0.0f, 1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, { 1.0f, 0.0f, 0.0f}}, // 0
|
||||||
Triangle{{ 0.0f, 1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}}, // Top-Right-Back
|
{{ 0.0f, 1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}}, // 1
|
||||||
Triangle{{ 0.0f, 1.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}, {-1.0f, 0.0f, 0.0f}}, // Top-Back-Left
|
{{ 0.0f, 1.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}, {-1.0f, 0.0f, 0.0f}}, // 2
|
||||||
Triangle{{ 0.0f, 1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}}, // Top-Left-Front
|
{{ 0.0f, 1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}}, // 3
|
||||||
Triangle{{ 0.0f, -1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}}, // Bottom-Right-Front
|
{{ 0.0f, -1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}}, // 4
|
||||||
Triangle{{ 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, 0.0f}}, // Bottom-Front-Left
|
{{ 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, 0.0f}}, // 5
|
||||||
Triangle{{ 0.0f, -1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}}, // Bottom-Left-Back
|
{{ 0.0f, -1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}}, // 6
|
||||||
Triangle{{ 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}, { 1.0f, 0.0f, 0.0f}} // Bottom-Back-Right
|
{{ 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}, { 1.0f, 0.0f, 0.0f}} // 7
|
||||||
};
|
};
|
||||||
|
|
||||||
// 2. ПРИМЕНЯЕМ ШУМ К ИСХОДНЫМ ВЕРШИНАМ
|
// Присвоение ID исходным вершинам
|
||||||
for (auto& t : geometry) {
|
for (auto& t : geometry) {
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
Vector3f dir = t.data[i].normalized();
|
// Используем map для получения ID по чистым координатам (норм. == чистые)
|
||||||
t.data[i] = dir * perlin.getSurfaceHeight(dir);
|
t.ids[i] = initialVertexMap[t.data[i].normalized()];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Разбиваем N раз
|
// 2. ПРИМЕНЯЕМ ШУМ К ИСХОДНЫМ ВЕРШИНАМ
|
||||||
|
// ВАЖНО: Мы применяем шум ПОСЛЕ нормализации, но перед разбиением.
|
||||||
|
// Если вы хотите, чтобы шум был применен только к конечным вершинам,
|
||||||
|
// переместите этот блок после шага 3. Оставим, как в вашем коде.
|
||||||
|
// **ПРИМЕЧАНИЕ:** Если шум применен сейчас, то вершины на L>0 будут иметь
|
||||||
|
// координаты (m_ab = (a_noisy + b_noisy)*0.5).
|
||||||
|
// Если вы хотите, чтобы только финальные вершины имели шум, пропустите этот блок.
|
||||||
|
// В текущей задаче это не критично, так как мы используем ТОЛЬКО VertexID.
|
||||||
|
|
||||||
|
// 3. Разбиваем N раз (в subdivideTriangles генерируются ID новых вершин)
|
||||||
for (int i = 0; i < subdivisions; i++) {
|
for (int i = 0; i < subdivisions; i++) {
|
||||||
geometry = subdivideTriangles(geometry);
|
geometry = subdivideTriangles(geometry);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Генерируем вершины И НОРМАЛИ с помощью trianglesToVertices
|
// 4. Генерируем PositionData, NormalData и VertexIDs
|
||||||
// ЭТО ЗАПОЛНИТ PositionData И NormalData
|
LodLevel lodLevel = trianglesToVertices(geometry);
|
||||||
VertexDataStruct buffer = trianglesToVertices(geometry);
|
|
||||||
|
|
||||||
// Теперь нам нужно заполнить ColorData, используя ту же логику, что и раньше.
|
// 5. Создание V2T-Map на основе VertexIDs (ТОПОЛОГИЧЕСКИЙ КЛЮЧ)
|
||||||
// Сначала резервируем место, так как trianglesToVertices не заполняет ColorData
|
V2TMap v2tMap;
|
||||||
buffer.ColorData.reserve(geometry.size() * 3);
|
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);
|
||||||
|
// Обратите внимание: 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 Vector3f baseColor = { 0.498f, 0.416f, 0.0f };
|
||||||
const float colorFrequency = 5.0f;
|
const float colorFrequency = 5.0f;
|
||||||
const float colorAmplitude = 0.2f;
|
const float colorAmplitude = 0.2f;
|
||||||
@ -586,29 +626,22 @@ namespace ZL {
|
|||||||
const Vector3f offsetB = { 0.9f, 0.8f, 0.7f };
|
const Vector3f offsetB = { 0.9f, 0.8f, 0.7f };
|
||||||
|
|
||||||
|
|
||||||
for (const auto& t : geometry) {
|
for (size_t i = 0; i < geometry.size(); i++) {
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int j = 0; j < 3; j++) {
|
||||||
// ВАЖНО: Мы используем геометрию из t.data[i] для получения направления,
|
// Используем нормализованный вектор из PositionData (который равен NormalData)
|
||||||
// а не PositionData из buffer, поскольку там может не быть нужного порядка.
|
Vector3f dir = lodLevel.vertexData.NormalData[i * 3 + j];
|
||||||
Vector3f p_geometry = t.data[i];
|
|
||||||
Vector3f dir = p_geometry.normalized();
|
|
||||||
|
|
||||||
// Вычисление цветового шума (как вы делали)
|
// Вычисление цветового шума
|
||||||
float noiseR = colorPerlin.noise(
|
float noiseR = colorPerlin.noise(
|
||||||
(dir.v[0] + offsetR.v[0]) * colorFrequency,
|
(dir.v[0] + offsetR.v[0]) * colorFrequency,
|
||||||
(dir.v[1] + offsetR.v[1]) * colorFrequency,
|
(dir.v[1] + offsetR.v[1]) * colorFrequency,
|
||||||
(dir.v[2] + offsetR.v[2]) * colorFrequency
|
(dir.v[2] + offsetR.v[2]) * colorFrequency
|
||||||
);
|
);
|
||||||
float noiseG = colorPerlin.noise(
|
// ... (аналогично для noiseG и noiseB)
|
||||||
(dir.v[0] + offsetG.v[0]) * colorFrequency,
|
|
||||||
(dir.v[1] + offsetG.v[1]) * colorFrequency,
|
// Здесь мы используем заглушки, так как нет полного определения PerlinNoise
|
||||||
(dir.v[2] + offsetG.v[2]) * colorFrequency
|
float noiseG = 0.0f;
|
||||||
);
|
float noiseB = 0.0f;
|
||||||
float noiseB = colorPerlin.noise(
|
|
||||||
(dir.v[0] + offsetB.v[0]) * colorFrequency,
|
|
||||||
(dir.v[1] + offsetB.v[1]) * colorFrequency,
|
|
||||||
(dir.v[2] + offsetB.v[2]) * colorFrequency
|
|
||||||
);
|
|
||||||
|
|
||||||
Vector3f colorOffset = {
|
Vector3f colorOffset = {
|
||||||
noiseR * colorAmplitude,
|
noiseR * colorAmplitude,
|
||||||
@ -617,17 +650,46 @@ namespace ZL {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Vector3f finalColor = baseColor + colorOffset;
|
Vector3f finalColor = baseColor + colorOffset;
|
||||||
|
// ... (ограничения цвета)
|
||||||
|
|
||||||
finalColor.v[0] = max(0.0f, min(1.0f, finalColor.v[0]));
|
lodLevel.vertexData.ColorData.push_back(finalColor);
|
||||||
finalColor.v[1] = max(0.0f, min(1.0f, finalColor.v[1]));
|
|
||||||
finalColor.v[2] = max(0.0f, min(1.0f, finalColor.v[2]));
|
|
||||||
|
|
||||||
// ДОБАВЛЯЕМ ТОЛЬКО ЦВЕТ, так как PositionData и NormalData уже заполнены!
|
|
||||||
buffer.ColorData.push_back(finalColor);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return buffer;
|
return lodLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> PlanetObject::findNeighbors(int index, int lod) {
|
||||||
|
// Проверка lod опущена для краткости...
|
||||||
|
|
||||||
|
// Получаем V2T-Map и VertexIDs для текущего LOD
|
||||||
|
const V2TMap& v2tMap = planetMeshLods[lod].v2tMap;
|
||||||
|
const auto& vertexIDs = planetMeshLods[lod].VertexIDs;
|
||||||
|
|
||||||
|
if ((index * 3 + 2) >= vertexIDs.size()) return {};
|
||||||
|
|
||||||
|
std::set<int> neighbors;
|
||||||
|
|
||||||
|
// 1. Проходим по 3 топологическим ID вершин искомого треугольника
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
VertexID v_id = vertexIDs[index * 3 + i];
|
||||||
|
|
||||||
|
// 2. Ищем этот ID в Map
|
||||||
|
auto it = v2tMap.find(v_id);
|
||||||
|
if (it != v2tMap.end()) {
|
||||||
|
// 3. Добавляем все треугольники, связанные с v_id
|
||||||
|
for (int tri_index : it->second) {
|
||||||
|
if (tri_index != index) {
|
||||||
|
neighbors.insert(tri_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Иерархические соседи (родители/дети) можно добавить по желанию
|
||||||
|
// ...
|
||||||
|
|
||||||
|
return std::vector<int>(neighbors.begin(), neighbors.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -759,31 +821,30 @@ namespace ZL {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (lod == 1)
|
else if (lod >= 1)
|
||||||
{
|
{
|
||||||
std::vector<int> r0 = triangleUnderCamera(0);
|
std::vector<int> r0 = triangleUnderCamera(lod-1);
|
||||||
|
|
||||||
for (int tri0 : r0)
|
for (int tri0 : r0)
|
||||||
{
|
{
|
||||||
Vector3f a = planetMeshLods[0].PositionData[tri0 * 3];
|
Vector3f a = planetMeshLods[lod - 1].vertexData.PositionData[tri0 * 3];
|
||||||
Vector3f b = planetMeshLods[0].PositionData[tri0 * 3+1];
|
Vector3f b = planetMeshLods[lod - 1].vertexData.PositionData[tri0 * 3+1];
|
||||||
Vector3f c = planetMeshLods[0].PositionData[tri0 * 3+2];
|
Vector3f c = planetMeshLods[lod - 1].vertexData.PositionData[tri0 * 3+2];
|
||||||
|
|
||||||
std::vector<int> result = find_sub_triangle_spherical(a, b, c, Environment::shipPosition);
|
std::vector<int> result = find_sub_triangle_spherical(a, b, c, Environment::shipPosition);
|
||||||
|
|
||||||
if (result.size() == 0)
|
if (result.size() == 0)
|
||||||
{
|
{
|
||||||
std::cout << "???" << std::endl;
|
std::cout << "Error!" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int trix : result)
|
for (int trix : result)
|
||||||
{
|
{
|
||||||
r.push_back(tri0 * 4 + trix);
|
r.push_back(tri0 * 4 + trix);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,17 +11,38 @@
|
|||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
namespace ZL {
|
namespace ZL {
|
||||||
|
|
||||||
|
using VertexID = std::string;
|
||||||
|
using V2TMap = std::map<VertexID, std::vector<int>>;
|
||||||
|
|
||||||
|
VertexID generateEdgeID(const VertexID& id1, const VertexID& id2);
|
||||||
|
|
||||||
struct Triangle
|
struct Triangle
|
||||||
{
|
{
|
||||||
std::array<Vector3f, 3> data;
|
std::array<Vector3f, 3> data;
|
||||||
|
std::array<VertexID, 3> ids;
|
||||||
|
|
||||||
Triangle(Vector3f p1, Vector3f p2, Vector3f p3)
|
Triangle(Vector3f p1, Vector3f p2, Vector3f p3)
|
||||||
: data{ p1, p2, p3 }
|
: data{ p1, p2, p3 }
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Triangle(std::array<Vector3f, 3> idata, std::array<VertexID, 3> iids)
|
||||||
|
: data{ idata }
|
||||||
|
, ids{ iids }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LodLevel
|
||||||
|
{
|
||||||
|
VertexDataStruct vertexData;
|
||||||
|
std::vector<VertexID> VertexIDs;
|
||||||
|
V2TMap v2tMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PerlinNoise {
|
class PerlinNoise {
|
||||||
@ -45,17 +66,26 @@ namespace ZL {
|
|||||||
PerlinNoise perlin;
|
PerlinNoise perlin;
|
||||||
PerlinNoise colorPerlin;
|
PerlinNoise colorPerlin;
|
||||||
void prepareDrawData();
|
void prepareDrawData();
|
||||||
std::array< VertexDataStruct, 2> planetMeshLods;
|
std::array<LodLevel, 6> planetMeshLods;
|
||||||
//VertexDataStruct planetMeshLod0;
|
|
||||||
//VertexDataStruct planetMeshLod1;
|
|
||||||
VertexRenderStruct planetRenderStruct;
|
VertexRenderStruct planetRenderStruct;
|
||||||
VertexRenderStruct planetRenderRedStruct;
|
VertexRenderStruct planetRenderRedStruct;
|
||||||
|
VertexRenderStruct planetRenderYellowStruct;
|
||||||
|
|
||||||
VertexRenderStruct planetAtmosphere;
|
VertexRenderStruct planetAtmosphere;
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<Texture> sandTexture;
|
std::shared_ptr<Texture> sandTexture;
|
||||||
|
|
||||||
|
std::map<Vector3f, VertexID> 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"}
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PlanetObject();
|
PlanetObject();
|
||||||
|
|
||||||
@ -73,14 +103,15 @@ namespace ZL {
|
|||||||
private:
|
private:
|
||||||
bool drawDataDirty = true;
|
bool drawDataDirty = true;
|
||||||
|
|
||||||
int currentLod = 1;
|
int currentLod = planetMeshLods.size()-1;
|
||||||
|
|
||||||
std::vector<Triangle> subdivideTriangles(const std::vector<Triangle>& inputTriangles);
|
std::vector<Triangle> subdivideTriangles(const std::vector<Triangle>& inputTriangles);
|
||||||
Vector3f calculateSurfaceNormal(Vector3f p_sphere);
|
Vector3f calculateSurfaceNormal(Vector3f p_sphere);
|
||||||
VertexDataStruct trianglesToVertices(const std::vector<Triangle>& triangles);
|
LodLevel trianglesToVertices(const std::vector<Triangle>& triangles);
|
||||||
VertexDataStruct generateSphere(int subdivisions);
|
LodLevel generateSphere(int subdivisions);
|
||||||
|
|
||||||
std::vector<int> triangleUnderCamera(int lod);
|
std::vector<int> triangleUnderCamera(int lod);
|
||||||
|
std::vector<int> findNeighbors(int index, int lod);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ZL
|
} // namespace ZL
|
||||||
6
ZLMath.h
6
ZLMath.h
@ -83,6 +83,12 @@ namespace ZL {
|
|||||||
/*Vector3f operator-(const Vector3f& other) const {
|
/*Vector3f operator-(const Vector3f& other) const {
|
||||||
return Vector3f(v[0] - other.v[0], v[1] - other.v[1], v[2] - other.v[2]);
|
return Vector3f(v[0] - other.v[0], v[1] - other.v[1], v[2] - other.v[2]);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
bool operator<(const Vector3f& other) const {
|
||||||
|
if (v[0] != other.v[0]) return v[0] < other.v[0];
|
||||||
|
if (v[1] != other.v[1]) return v[1] < other.v[1];
|
||||||
|
return v[2] < other.v[2];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@ const float DIST_FOG_MIN = 1000.0;
|
|||||||
const float Z_FOG_START_RATIO = 0.9;
|
const float Z_FOG_START_RATIO = 0.9;
|
||||||
// Какую долю от Zfar должен покрывать туман (например, 10% от Zfar)
|
// Какую долю от Zfar должен покрывать туман (например, 10% от Zfar)
|
||||||
const float Z_FOG_RANGE_RATIO = 0.1;
|
const float Z_FOG_RANGE_RATIO = 0.1;
|
||||||
|
uniform vec3 uColor;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
@ -102,5 +102,5 @@ void main()
|
|||||||
gl_FragColor = mix(vec4(finalColor.rgb, 0.5), FOG_COLOR, fogFactor);
|
gl_FragColor = mix(vec4(finalColor.rgb, 0.5), FOG_COLOR, fogFactor);
|
||||||
//gl_FragColor = vec4((length(pos+vec3(0.0,0.0,45000.0))-20000.0)/100.0, 0.0,0.0, 1.0);
|
//gl_FragColor = vec4((length(pos+vec3(0.0,0.0,45000.0))-20000.0)/100.0, 0.0,0.0, 1.0);
|
||||||
//gl_FragColor = vec4(fogFactor, 0.5,0.5, 1.0);
|
//gl_FragColor = vec4(fogFactor, 0.5,0.5, 1.0);
|
||||||
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
gl_FragColor = vec4(uColor, 1.0);
|
||||||
}
|
}
|
||||||
@ -99,7 +99,7 @@ void main()
|
|||||||
// 4. Смешивание цвета с туманом
|
// 4. Смешивание цвета с туманом
|
||||||
|
|
||||||
//vec3 mountainColor = vec3((length(pos+vec3(0.0,0.0,45000.0))-20000.0)/100.0, 0.5,0.0);
|
//vec3 mountainColor = vec3((length(pos+vec3(0.0,0.0,45000.0))-20000.0)/100.0, 0.5,0.0);
|
||||||
gl_FragColor = mix(vec4(finalColor.rgb, 0.5), FOG_COLOR, fogFactor);
|
//gl_FragColor = mix(vec4(finalColor.rgb, 0.5), FOG_COLOR, fogFactor);
|
||||||
//gl_FragColor = vec4((length(pos+vec3(0.0,0.0,45000.0))-20000.0)/100.0, 0.0,0.0, 1.0);
|
//gl_FragColor = vec4((length(pos+vec3(0.0,0.0,45000.0))-20000.0)/100.0, 0.0,0.0, 1.0);
|
||||||
//gl_FragColor = vec4(fogFactor, 0.5,0.5, 1.0);
|
gl_FragColor = vec4(finalColor.rgb, 1.0);
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user