Finally somehow planet is done
This commit is contained in:
parent
592e008914
commit
2b40c13c9d
@ -32,6 +32,11 @@ void main() {
|
|||||||
vec4 bakedTextureColor = texture2D(BakedTexture, finalTexCoord);
|
vec4 bakedTextureColor = texture2D(BakedTexture, finalTexCoord);
|
||||||
vec4 textureColor = texture2D(Texture, TexCoord);
|
vec4 textureColor = texture2D(Texture, TexCoord);
|
||||||
|
|
||||||
|
if (bakedTextureColor.x < 0.01 && bakedTextureColor.y < 0.01 && bakedTextureColor.y < 0.01)
|
||||||
|
{
|
||||||
|
textureMixFactor = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
vec4 finalColor = textureMixFactor*textureColor + (1 - textureMixFactor) * bakedTextureColor;
|
vec4 finalColor = textureMixFactor*textureColor + (1 - textureMixFactor) * bakedTextureColor;
|
||||||
|
|
||||||
float fogFactor;
|
float fogFactor;
|
||||||
@ -65,6 +70,8 @@ void main() {
|
|||||||
fogFactor = clamp((realDist - 1000) / (800.0), 0.0, 1.0);
|
fogFactor = clamp((realDist - 1000) / (800.0), 0.0, 1.0);
|
||||||
|
|
||||||
gl_FragColor = mix(vec4(finalColor.rgb, 1.0), FOG_COLOR, fogFactor);
|
gl_FragColor = mix(vec4(finalColor.rgb, 1.0), FOG_COLOR, fogFactor);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//gl_FragColor = vec4(finalColor.rgb, 1.0);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,6 @@ attribute vec3 vPosition;
|
|||||||
attribute vec2 vTexCoord;
|
attribute vec2 vTexCoord;
|
||||||
|
|
||||||
varying vec2 TexCoord;
|
varying vec2 TexCoord;
|
||||||
varying float viewZ;
|
|
||||||
varying vec3 pos;
|
|
||||||
varying vec3 worldPosition;
|
varying vec3 worldPosition;
|
||||||
|
|
||||||
|
|
||||||
@ -17,13 +15,6 @@ void main()
|
|||||||
// Преобразование позиции в пространство вида (View Space)
|
// Преобразование позиции в пространство вида (View Space)
|
||||||
vec4 viewPosition = ModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
vec4 viewPosition = ModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
||||||
|
|
||||||
// Сохраняем отрицательную Z-координату. В OpenGL Z-координата (глубина)
|
|
||||||
// в пространстве вида обычно отрицательна, но для расчета тумана
|
|
||||||
// удобнее использовать положительное значение.
|
|
||||||
viewZ = -viewPosition.z;
|
|
||||||
|
|
||||||
pos = vPosition.xyz;
|
|
||||||
|
|
||||||
gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
||||||
|
|
||||||
TexCoord = vTexCoord;
|
TexCoord = vTexCoord;
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
// ---Фрагментный шейдер (Fragment Shader)
|
// ---Фрагментный шейдер (Fragment Shader)
|
||||||
|
|
||||||
varying vec2 TexCoord;
|
varying vec2 TexCoord;
|
||||||
varying float viewZ;
|
|
||||||
varying vec3 pos;
|
|
||||||
|
|
||||||
uniform sampler2D Texture;
|
uniform sampler2D Texture;
|
||||||
uniform float uDistanceToPlanetSurface;
|
uniform float uDistanceToPlanetSurface;
|
||||||
@ -55,5 +53,5 @@ void main()
|
|||||||
|
|
||||||
gl_FragColor = mix(vec4(finalColor.rgb, alphaFactor), FOG_COLOR, fogFactor);
|
gl_FragColor = mix(vec4(finalColor.rgb, alphaFactor), FOG_COLOR, fogFactor);
|
||||||
}
|
}
|
||||||
|
//gl_FragColor = vec4(finalColor.rgb, 1.0);
|
||||||
}
|
}
|
||||||
@ -44,17 +44,12 @@ namespace ZL {
|
|||||||
|
|
||||||
void PlanetData::init() {
|
void PlanetData::init() {
|
||||||
for (int i = 0; i < planetMeshLods.size(); i++) {
|
for (int i = 0; i < planetMeshLods.size(); i++) {
|
||||||
planetMeshLods[i] = generateSphere(i, 0.025f);
|
//planetMeshLods[i] = generateSphere(i, 0.01f);
|
||||||
|
planetMeshLods[i] = generateSphere(i, 0.f);
|
||||||
planetMeshLods[i].Scale(PLANET_RADIUS);
|
planetMeshLods[i].Scale(PLANET_RADIUS);
|
||||||
planetMeshLods[i].Move(PLANET_CENTER_OFFSET);
|
planetMeshLods[i].Move(PLANET_CENTER_OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < planetMeshLodsNoDist.size(); i++) {
|
|
||||||
planetMeshLodsNoDist[i] = generateSphere(i, 0);
|
|
||||||
planetMeshLodsNoDist[i].Scale(PLANET_RADIUS);
|
|
||||||
planetMeshLodsNoDist[i].Move(PLANET_CENTER_OFFSET);
|
|
||||||
}
|
|
||||||
|
|
||||||
planetAtmosphereLod = generateSphere(5, 0);
|
planetAtmosphereLod = generateSphere(5, 0);
|
||||||
planetAtmosphereLod.Scale(PLANET_RADIUS * 1.03);
|
planetAtmosphereLod.Scale(PLANET_RADIUS * 1.03);
|
||||||
planetAtmosphereLod.Move(PLANET_CENTER_OFFSET);
|
planetAtmosphereLod.Move(PLANET_CENTER_OFFSET);
|
||||||
@ -64,9 +59,6 @@ namespace ZL {
|
|||||||
return planetMeshLods.at(level);
|
return planetMeshLods.at(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
const LodLevel& PlanetData::getLodLevelNoDist(int level) const {
|
|
||||||
return planetMeshLodsNoDist.at(level);
|
|
||||||
}
|
|
||||||
|
|
||||||
const LodLevel& PlanetData::getAtmosphereLod() const {
|
const LodLevel& PlanetData::getAtmosphereLod() const {
|
||||||
return planetAtmosphereLod;
|
return planetAtmosphereLod;
|
||||||
@ -145,7 +137,7 @@ namespace ZL {
|
|||||||
|
|
||||||
// Âðåìåííîå ðåøåíèå: ïîëíàÿ êîïèÿ ëîãèêè ïîèñêà òðåóãîëüíèêà
|
// Âðåìåííîå ðåøåíèå: ïîëíàÿ êîïèÿ ëîãèêè ïîèñêà òðåóãîëüíèêà
|
||||||
// Íî íàì íóæåí äîñòóï ê ìåòîäó.
|
// Íî íàì íóæåí äîñòóï ê ìåòîäó.
|
||||||
std::vector<int> targetTriangles = getTrianglesUnderCamera(viewerPosition);
|
std::vector<int> targetTriangles = getTrianglesUnderCameraNew(viewerPosition);
|
||||||
|
|
||||||
if (targetTriangles.empty()) {
|
if (targetTriangles.empty()) {
|
||||||
return (shipLocalPosition.length() - PLANET_RADIUS);
|
return (shipLocalPosition.length() - PLANET_RADIUS);
|
||||||
@ -202,85 +194,50 @@ namespace ZL {
|
|||||||
return lowestDistance;
|
return lowestDistance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
std::vector<int> PlanetData::getTrianglesUnderCameraNew(const Vector3f& viewerPosition) {
|
||||||
|
const LodLevel& finalLod = planetMeshLods[currentLod]; // Ðàáîòàåì ñ òåêóùèì àêòèâíûì LOD
|
||||||
|
Vector3f targetDir = (viewerPosition - PLANET_CENTER_OFFSET).normalized();
|
||||||
|
|
||||||
// --- Ðåàëèçàöèÿ getTrianglesUnderCamera (áûâøàÿ triangleUnderCamera) ---
|
int bestTriangle = -1;
|
||||||
// Âñïîìîãàòåëüíàÿ ðåêóðñèâíàÿ ôóíêöèÿ, ñêðûòàÿ îò ïóáëè÷íîãî API
|
float maxDot = -1.0f;
|
||||||
static std::vector<int> recursiveTriangleSearch(int lod, const Vector3f& pos, const std::array<LodLevel, MAX_LOD_LEVELS>& meshes) {
|
|
||||||
std::vector<int> r;
|
// Øàã 1: Áûñòðûé ïîèñê áëèæàéøåãî òðåóãîëüíèêà ïî "öåíòðîèäó"
|
||||||
// Ëîãèêà óðîâíÿ 0 (áàçîâûé îêòàýäð)
|
// ×òîáû íå ïðîâåðÿòü âñå, ìîæíî ïðîâåðÿòü êàæäûé N-é èëè èñïîëüçîâàòü
|
||||||
if (lod == 0) {
|
// ïðåäâàðèòåëüíî âû÷èñëåííûå öåíòðû äëÿ LOD0, ÷òîáû ñóçèòü êðóã.
|
||||||
if (pos.v[1] >= 0) {
|
// Íî äëÿ íàäåæíîñòè ïðîéäåìñÿ ïî ìàññèâó (äëÿ 5-6 ïîäðàçäåëåíèé ýòî áûñòðî)
|
||||||
if (pos.v[0] >= 0 && pos.v[2] >= 0) r.push_back(0);
|
for (int i = 0; i < (int)finalLod.triangles.size(); ++i) {
|
||||||
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);
|
Vector3f triDir = (finalLod.triangles[i].data[0] +
|
||||||
if (pos.v[0] <= 0 && pos.v[2] >= 0) r.push_back(3);
|
finalLod.triangles[i].data[1] +
|
||||||
}
|
finalLod.triangles[i].data[2]).normalized();
|
||||||
if (pos.v[1] <= 0) {
|
|
||||||
if (pos.v[0] >= 0 && pos.v[2] >= 0) r.push_back(4);
|
float dot = targetDir.dot(triDir);
|
||||||
if (pos.v[0] <= 0 && pos.v[2] >= 0) r.push_back(5);
|
if (dot > maxDot) {
|
||||||
if (pos.v[0] <= 0 && pos.v[2] <= 0) r.push_back(6);
|
maxDot = dot;
|
||||||
if (pos.v[0] >= 0 && pos.v[2] <= 0) r.push_back(7);
|
bestTriangle = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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);
|
if (bestTriangle == -1) return {};
|
||||||
for (int trix : result) {
|
|
||||||
r.push_back(tri0 * 4 + trix);
|
// Øàã 2: Ñîáèðàåì "ïÿòíî" âîêðóã íàéäåííîãî òðåóãîëüíèêà
|
||||||
}
|
// Èñïîëüçóåì óæå èìåþùèéñÿ ó òåáÿ ìåòîä findNeighbors
|
||||||
|
std::set<int> resultSet;
|
||||||
|
resultSet.insert(bestTriangle);
|
||||||
|
|
||||||
|
// Äîáàâëÿåì ïåðâûé êðóã ñîñåäåé
|
||||||
|
std::vector<int> neighbors = findNeighbors(bestTriangle, currentLod);
|
||||||
|
for (int n : neighbors) {
|
||||||
|
resultSet.insert(n);
|
||||||
|
|
||||||
|
// Îïöèîíàëüíî: Äîáàâëÿåì âòîðîé êðóã ñîñåäåé äëÿ çàïàñà (ïðèõâàòûâàåì áîëüøå)
|
||||||
|
std::vector<int> secondCircle = findNeighbors(n, currentLod);
|
||||||
|
for (int nn : secondCircle) {
|
||||||
|
resultSet.insert(nn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return std::vector<int>(resultSet.begin(), resultSet.end());
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Triangle> PlanetData::subdivideTriangles(const std::vector<Triangle>& input, float noiseCoeff) {
|
std::vector<Triangle> PlanetData::subdivideTriangles(const std::vector<Triangle>& input, float noiseCoeff) {
|
||||||
@ -300,9 +257,13 @@ namespace ZL {
|
|||||||
Vector3f m_bc = ((b + c) * 0.5f).normalized();
|
Vector3f m_bc = ((b + c) * 0.5f).normalized();
|
||||||
Vector3f m_ac = ((a + c) * 0.5f).normalized();
|
Vector3f m_ac = ((a + c) * 0.5f).normalized();
|
||||||
|
|
||||||
Vector3f pm_ab = m_ab * perlin.getSurfaceHeight(m_ab, noiseCoeff);
|
//Vector3f pm_ab = m_ab * perlin.getSurfaceHeight(m_ab, noiseCoeff);
|
||||||
Vector3f pm_bc = m_bc * perlin.getSurfaceHeight(m_bc, noiseCoeff);
|
//Vector3f pm_bc = m_bc * perlin.getSurfaceHeight(m_bc, noiseCoeff);
|
||||||
Vector3f pm_ac = m_ac * perlin.getSurfaceHeight(m_ac, noiseCoeff);
|
//Vector3f pm_ac = m_ac * perlin.getSurfaceHeight(m_ac, noiseCoeff);
|
||||||
|
|
||||||
|
Vector3f pm_ab = m_ab;
|
||||||
|
Vector3f pm_bc = m_bc;
|
||||||
|
Vector3f pm_ac = m_ac;
|
||||||
|
|
||||||
// 2. Âû÷èñëÿåì ID íîâûõ âåðøèí
|
// 2. Âû÷èñëÿåì ID íîâûõ âåðøèí
|
||||||
VertexID id_mab = generateEdgeID(id_a, id_b);
|
VertexID id_mab = generateEdgeID(id_a, id_b);
|
||||||
@ -318,25 +279,46 @@ namespace ZL {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
LodLevel PlanetData::trianglesToVertices(const std::vector<Triangle>& geometry) {
|
LodLevel PlanetData::createLodLevel(const std::vector<Triangle>& geometry) {
|
||||||
LodLevel result;
|
LodLevel result;
|
||||||
result.triangles = geometry;
|
result.triangles = geometry;
|
||||||
|
|
||||||
size_t vertexCount = geometry.size() * 3;
|
size_t vertexCount = geometry.size() * 3;
|
||||||
result.vertexData.PositionData.reserve(vertexCount);
|
|
||||||
result.vertexData.NormalData.reserve(vertexCount);
|
|
||||||
result.vertexData.TexCoordData.reserve(vertexCount);
|
|
||||||
result.vertexData.TangentData.reserve(vertexCount); // Äîáàâëÿåì ðåçåðâ
|
|
||||||
result.vertexData.BinormalData.reserve(vertexCount);
|
|
||||||
result.VertexIDs.reserve(vertexCount);
|
result.VertexIDs.reserve(vertexCount);
|
||||||
|
|
||||||
|
for (const auto& t : geometry) {
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
result.VertexIDs.push_back(t.ids[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlanetData::recalculateMeshAttributes(LodLevel& lod)
|
||||||
|
{
|
||||||
|
size_t vertexCount = lod.triangles.size() * 3;
|
||||||
|
|
||||||
|
lod.vertexData.PositionData.clear();
|
||||||
|
lod.vertexData.NormalData.clear();
|
||||||
|
lod.vertexData.TexCoordData.clear();
|
||||||
|
lod.vertexData.TangentData.clear();
|
||||||
|
lod.vertexData.BinormalData.clear();
|
||||||
|
|
||||||
|
lod.vertexData.PositionData.reserve(vertexCount);
|
||||||
|
lod.vertexData.NormalData.reserve(vertexCount);
|
||||||
|
lod.vertexData.TexCoordData.reserve(vertexCount);
|
||||||
|
lod.vertexData.TangentData.reserve(vertexCount);
|
||||||
|
lod.vertexData.BinormalData.reserve(vertexCount);
|
||||||
|
|
||||||
|
|
||||||
const std::array<Vector2f, 3> triangleUVs = {
|
const std::array<Vector2f, 3> triangleUVs = {
|
||||||
Vector2f(0.5f, 1.0f),
|
Vector2f(0.5f, 1.0f),
|
||||||
Vector2f(0.0f, 0.0f),
|
Vector2f(0.0f, 0.0f),
|
||||||
Vector2f(1.0f, 0.0f)
|
Vector2f(1.0f, 0.0f)
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const auto& t : geometry) {
|
for (const auto& t : lod.triangles) {
|
||||||
// --- Âû÷èñëÿåì ëîêàëüíûé áàçèñ òðåóãîëüíèêà (êàê â GetRotationForTriangle) ---
|
// --- Âû÷èñëÿåì ëîêàëüíûé áàçèñ òðåóãîëüíèêà (êàê â GetRotationForTriangle) ---
|
||||||
Vector3f vA = t.data[0];
|
Vector3f vA = t.data[0];
|
||||||
Vector3f vB = t.data[1];
|
Vector3f vB = t.data[1];
|
||||||
@ -357,18 +339,13 @@ namespace ZL {
|
|||||||
Vector3f y_axis = z_axis.cross(x_axis).normalized(); // Íàïðàâëåíèå V
|
Vector3f y_axis = z_axis.cross(x_axis).normalized(); // Íàïðàâëåíèå V
|
||||||
|
|
||||||
for (int i = 0; i < 3; ++i) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
result.vertexData.PositionData.push_back(t.data[i]);
|
lod.vertexData.PositionData.push_back(t.data[i]);
|
||||||
result.vertexData.NormalData.push_back(z_axis); // Ïëîñêàÿ íîðìàëü ãðàíè äëÿ Parallax
|
lod.vertexData.NormalData.push_back(z_axis);
|
||||||
result.vertexData.TexCoordData.push_back(triangleUVs[i]);
|
lod.vertexData.TexCoordData.push_back(triangleUVs[i]);
|
||||||
|
lod.vertexData.TangentData.push_back(x_axis);
|
||||||
// Çàïèñûâàåì âû÷èñëåííûé áàçèñ â êàæäóþ âåðøèíó òðåóãîëüíèêà
|
lod.vertexData.BinormalData.push_back(y_axis);
|
||||||
result.vertexData.TangentData.push_back(x_axis);
|
|
||||||
result.vertexData.BinormalData.push_back(y_axis);
|
|
||||||
|
|
||||||
result.VertexIDs.push_back(t.ids[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -400,7 +377,7 @@ namespace ZL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 4. Ãåíåðèðóåì PositionData, NormalData è VertexIDs
|
// 4. Ãåíåðèðóåì PositionData, NormalData è VertexIDs
|
||||||
LodLevel lodLevel = trianglesToVertices(geometry);
|
LodLevel lodLevel = createLodLevel(geometry);
|
||||||
|
|
||||||
// 5. Ñîçäàíèå V2T-Map íà îñíîâå VertexIDs (ÒÎÏÎËÎÃÈ×ÅÑÊÈÉ ÊËÞ×)
|
// 5. Ñîçäàíèå V2T-Map íà îñíîâå VertexIDs (ÒÎÏÎËÎÃÈ×ÅÑÊÈÉ ÊËÞ×)
|
||||||
V2TMap v2tMap;
|
V2TMap v2tMap;
|
||||||
@ -417,55 +394,26 @@ namespace ZL {
|
|||||||
}
|
}
|
||||||
lodLevel.v2tMap = v2tMap;
|
lodLevel.v2tMap = v2tMap;
|
||||||
|
|
||||||
// 6. Ïðèìåíåíèå ôèíàëüíîãî øóìà (åñëè âû õîòåëè, ÷òîáû øóì áûë òîëüêî çäåñü)
|
applySphericalLaplacianSmoothing(lodLevel, 5, 0.5f);
|
||||||
// Çäåñü ìû äîëæíû áûëè áû ïðèìåíèòü øóì ê 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Ïðèìåíåíèå øóìà ÷åðåç óíèêàëüíûå ID ïîñëå ñãëàæèâàíèÿ
|
||||||
// 7. Ãåíåðàöèÿ ColorData
|
std::map<VertexID, Vector3f> displacedPositions;
|
||||||
lodLevel.vertexData.ColorData.reserve(geometry.size() * 3);
|
for (const auto& tri : lodLevel.triangles) {
|
||||||
const Vector3f baseColor = { 0.498f, 0.416f, 0.0f };
|
for (int i = 0; i < 3; ++i) {
|
||||||
const float colorFrequency = 5.0f;
|
if (displacedPositions.find(tri.ids[i]) == displacedPositions.end()) {
|
||||||
const float colorAmplitude = 0.2f;
|
Vector3f dir = tri.data[i].normalized();
|
||||||
const Vector3f offsetR = { 0.1f, 0.2f, 0.3f };
|
displacedPositions[tri.ids[i]] = dir * perlin.getSurfaceHeight(dir, noiseCoeff);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Îáíîâëÿåì òðåóãîëüíèêè ôèíàëüíûìè ïîçèöèÿìè
|
||||||
|
for (auto& tri : lodLevel.triangles) {
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
tri.data[i] = displacedPositions[tri.ids[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
recalculateMeshAttributes(lodLevel);
|
||||||
|
|
||||||
return lodLevel;
|
return lodLevel;
|
||||||
}
|
}
|
||||||
@ -490,4 +438,56 @@ namespace ZL {
|
|||||||
}
|
}
|
||||||
return std::vector<int>(neighbors.begin(), neighbors.end());
|
return std::vector<int>(neighbors.begin(), neighbors.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PlanetData::applySphericalLaplacianSmoothing(LodLevel& lod, int iterations, float relaxationFactor) {
|
||||||
|
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. Öåíòðîèä ñîñåäåé
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Îáíîâëÿåì êîîðäèíàòû ïðÿìî â îáúåêòàõ Triangle
|
||||||
|
for (auto& tri : lod.triangles) {
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
tri.data[i] = newPositions[tri.ids[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -17,13 +17,17 @@ namespace ZL {
|
|||||||
VertexID generateEdgeID(const VertexID& id1, const VertexID& id2);
|
VertexID generateEdgeID(const VertexID& id1, const VertexID& id2);
|
||||||
|
|
||||||
constexpr static int MAX_LOD_LEVELS = 6;
|
constexpr static int MAX_LOD_LEVELS = 6;
|
||||||
//constexpr static int MAX_LOD_LEVELS = 3;
|
//constexpr static int MAX_LOD_LEVELS = 2;
|
||||||
|
|
||||||
struct Triangle
|
struct Triangle
|
||||||
{
|
{
|
||||||
std::array<Vector3f, 3> data;
|
std::array<Vector3f, 3> data;
|
||||||
std::array<VertexID, 3> ids;
|
std::array<VertexID, 3> ids;
|
||||||
|
|
||||||
|
Triangle()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
Triangle(Vector3f p1, Vector3f p2, Vector3f p3)
|
Triangle(Vector3f p1, Vector3f p2, Vector3f p3)
|
||||||
: data{ p1, p2, p3 }
|
: data{ p1, p2, p3 }
|
||||||
{
|
{
|
||||||
@ -73,7 +77,6 @@ namespace ZL {
|
|||||||
PerlinNoise colorPerlin;
|
PerlinNoise colorPerlin;
|
||||||
|
|
||||||
std::array<LodLevel, MAX_LOD_LEVELS> planetMeshLods;
|
std::array<LodLevel, MAX_LOD_LEVELS> planetMeshLods;
|
||||||
std::array<LodLevel, MAX_LOD_LEVELS> planetMeshLodsNoDist;
|
|
||||||
LodLevel planetAtmosphereLod;
|
LodLevel planetAtmosphereLod;
|
||||||
|
|
||||||
int currentLod; // Ëîãè÷åñêèé òåêóùèé óðîâåíü äåòàëèçàöèè
|
int currentLod; // Ëîãè÷åñêèé òåêóùèé óðîâåíü äåòàëèçàöèè
|
||||||
@ -82,13 +85,9 @@ namespace ZL {
|
|||||||
|
|
||||||
// Âíóòðåííèå ìåòîäû ãåíåðàöèè
|
// Âíóòðåííèå ìåòîäû ãåíåðàöèè
|
||||||
std::vector<Triangle> subdivideTriangles(const std::vector<Triangle>& inputTriangles, float noiseCoeff);
|
std::vector<Triangle> subdivideTriangles(const std::vector<Triangle>& inputTriangles, float noiseCoeff);
|
||||||
LodLevel trianglesToVertices(const std::vector<Triangle>& triangles);
|
LodLevel createLodLevel(const std::vector<Triangle>& triangles);
|
||||||
|
void recalculateMeshAttributes(LodLevel& lod);
|
||||||
LodLevel generateSphere(int subdivisions, float noiseCoeff);
|
LodLevel generateSphere(int subdivisions, float noiseCoeff);
|
||||||
|
|
||||||
// Âñïîìîãàòåëüíûå ìåòîäû ìàòåìàòèêè
|
|
||||||
static float check_spherical_side(const Vector3f& V1, const Vector3f& V2, const Vector3f& P, const Vector3f& V3, float epsilon = 1e-6f);
|
|
||||||
static bool is_inside_spherical_triangle(const Vector3f& P, const Vector3f& V1, const Vector3f& V2, const Vector3f& V3, float epsilon);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PlanetData();
|
PlanetData();
|
||||||
|
|
||||||
@ -96,7 +95,6 @@ namespace ZL {
|
|||||||
|
|
||||||
// Ìåòîäû äîñòóïà ê äàííûì (äëÿ ðåíäåðåðà)
|
// Ìåòîäû äîñòóïà ê äàííûì (äëÿ ðåíäåðåðà)
|
||||||
const LodLevel& getLodLevel(int level) const;
|
const LodLevel& getLodLevel(int level) const;
|
||||||
const LodLevel& getLodLevelNoDist(int level) const;
|
|
||||||
const LodLevel& getAtmosphereLod() const;
|
const LodLevel& getAtmosphereLod() const;
|
||||||
int getCurrentLodIndex() const;
|
int getCurrentLodIndex() const;
|
||||||
int getMaxLodIndex() const;
|
int getMaxLodIndex() const;
|
||||||
@ -106,12 +104,10 @@ namespace ZL {
|
|||||||
float distanceToPlanetSurface(const Vector3f& viewerPosition);
|
float distanceToPlanetSurface(const Vector3f& viewerPosition);
|
||||||
|
|
||||||
// Âîçâðàùàåò èíäåêñû òðåóãîëüíèêîâ, âèäèìûõ êàìåðîé
|
// Âîçâðàùàåò èíäåêñû òðåóãîëüíèêîâ, âèäèìûõ êàìåðîé
|
||||||
std::vector<int> getTrianglesUnderCamera(const Vector3f& viewerPosition);
|
std::vector<int> getTrianglesUnderCameraNew(const Vector3f& viewerPosition);
|
||||||
|
|
||||||
std::vector<int> findNeighbors(int index, int lod);
|
std::vector<int> findNeighbors(int index, int lod);
|
||||||
|
|
||||||
static std::vector<int> find_sub_triangle_spherical(const Vector3f& a_orig, const Vector3f& b_orig, const Vector3f& c_orig, const Vector3f& px_orig);
|
void applySphericalLaplacianSmoothing(LodLevel& lod, int iterations, float relaxationFactor);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ZL
|
} // namespace ZL
|
||||||
@ -7,19 +7,13 @@
|
|||||||
|
|
||||||
namespace ZL {
|
namespace ZL {
|
||||||
|
|
||||||
|
|
||||||
Matrix3f GetRotationForTriangle(const Triangle& tri) {
|
Matrix3f GetRotationForTriangle(const Triangle& tri) {
|
||||||
// Для треугольника №0:
|
|
||||||
// tri.data[0] = {0, 20000, 0} (A)
|
|
||||||
// tri.data[1] = {0, 0, 20000} (B)
|
|
||||||
// tri.data[2] = {20000, 0, 0} (C)
|
|
||||||
|
|
||||||
Vector3f vA = tri.data[0];
|
Vector3f vA = tri.data[0];
|
||||||
Vector3f vB = tri.data[1];
|
Vector3f vB = tri.data[1];
|
||||||
Vector3f vC = tri.data[2];
|
Vector3f vC = tri.data[2];
|
||||||
|
|
||||||
// 1. Вычисляем ось X (горизонталь).
|
// 1. Вычисляем ось X (горизонталь).
|
||||||
// Нам нужна грань BC: от (0, 0, 20000) до (20000, 0, 0)
|
|
||||||
Vector3f x_axis = (vC - vB).normalized();
|
Vector3f x_axis = (vC - vB).normalized();
|
||||||
|
|
||||||
|
|
||||||
@ -67,28 +61,24 @@ namespace ZL {
|
|||||||
// Берем максимальный LOD для начальной отрисовки
|
// Берем максимальный LOD для начальной отрисовки
|
||||||
int lodIndex = planetData.getMaxLodIndex();
|
int lodIndex = planetData.getMaxLodIndex();
|
||||||
planetRenderStruct.data = planetData.getLodLevel(lodIndex).vertexData;
|
planetRenderStruct.data = planetData.getLodLevel(lodIndex).vertexData;
|
||||||
|
|
||||||
|
//planetRenderStruct.data.PositionData.resize(9);
|
||||||
planetRenderStruct.RefreshVBO();
|
planetRenderStruct.RefreshVBO();
|
||||||
|
|
||||||
planetRenderStructCut.data = planetData.getLodLevelNoDist(lodIndex).vertexData;
|
|
||||||
|
|
||||||
planetRenderStructCut.data.PositionData.resize(3);
|
|
||||||
|
|
||||||
planetRenderStructCut.RefreshVBO();
|
|
||||||
//sandTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/sand2.png", ""));
|
|
||||||
sandTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/sand2.png", ""));
|
sandTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/sand2.png", ""));
|
||||||
stoneTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/rock.png", ""));
|
stoneTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/rock.png", ""));
|
||||||
|
|
||||||
// Атмосфера
|
// Атмосфера
|
||||||
planetAtmosphereRenderStruct.data = planetData.getAtmosphereLod().vertexData;
|
planetAtmosphereRenderStruct.data = planetData.getAtmosphereLod().vertexData;
|
||||||
planetAtmosphereRenderStruct.RefreshVBO();
|
if (planetAtmosphereRenderStruct.data.PositionData.size() > 0)
|
||||||
|
{
|
||||||
|
planetAtmosphereRenderStruct.RefreshVBO();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
planetStones = CreateStoneGroupData(778, planetData.getLodLevel(lodIndex));
|
planetStones = CreateStoneGroupData(778, planetData.getLodLevel(lodIndex));
|
||||||
planetStones.inflate({ 0/*,1,2,3,4,5,6,7*/ });
|
|
||||||
planetStonesToBakeRenderStruct.AssignFrom(planetStones.mesh);
|
|
||||||
planetStonesToBakeRenderStruct.RefreshVBO();
|
|
||||||
|
|
||||||
|
|
||||||
|
stonesToRender = planetStones.inflate(planetStones.allInstances.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlanetObject::prepareDrawData() {
|
void PlanetObject::prepareDrawData() {
|
||||||
@ -99,33 +89,14 @@ namespace ZL {
|
|||||||
|
|
||||||
void PlanetObject::update(float deltaTimeMs) {
|
void PlanetObject::update(float deltaTimeMs) {
|
||||||
// 1. Получаем базовые треугольники под камерой
|
// 1. Получаем базовые треугольники под камерой
|
||||||
auto lr = planetData.getTrianglesUnderCamera(Environment::shipPosition);
|
auto lr = planetData.getTrianglesUnderCameraNew(Environment::shipPosition);
|
||||||
int currentLod = planetData.getCurrentLodIndex();
|
int currentLod = planetData.getCurrentLodIndex();
|
||||||
|
|
||||||
|
|
||||||
// Временный вектор для сбора новых индексов
|
// Временный вектор для сбора новых индексов
|
||||||
std::vector<int> newIndices;
|
std::vector<int> newIndices;
|
||||||
std::set<int> used;
|
|
||||||
|
|
||||||
// Рекурсивно (или итеративно, как у тебя) собираем индексы видимых зон
|
newIndices = lr;
|
||||||
for (int i : lr) {
|
|
||||||
if (used.insert(i).second) newIndices.push_back(i);
|
|
||||||
|
|
||||||
auto neighbors = planetData.findNeighbors(i, currentLod);
|
|
||||||
for (int n : neighbors) {
|
|
||||||
if (used.insert(n).second) newIndices.push_back(n);
|
|
||||||
|
|
||||||
auto neighbors2 = planetData.findNeighbors(n, currentLod);
|
|
||||||
for (int n2 : neighbors2) {
|
|
||||||
if (used.insert(n2).second) newIndices.push_back(n2);
|
|
||||||
|
|
||||||
auto neighbors3 = planetData.findNeighbors(n, currentLod);
|
|
||||||
|
|
||||||
for (int n3 : neighbors3) {
|
|
||||||
if (used.insert(n3).second) newIndices.push_back(n3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Сортируем новый список, чтобы порядок не влиял на сравнение
|
// 2. Сортируем новый список, чтобы порядок не влиял на сравнение
|
||||||
std::sort(newIndices.begin(), newIndices.end());
|
std::sort(newIndices.begin(), newIndices.end());
|
||||||
@ -134,7 +105,7 @@ namespace ZL {
|
|||||||
if (newIndices != triangleIndicesToDraw) {
|
if (newIndices != triangleIndicesToDraw) {
|
||||||
// Обновляем список индексов (используем move для эффективности)
|
// Обновляем список индексов (используем move для эффективности)
|
||||||
triangleIndicesToDraw = std::move(newIndices);
|
triangleIndicesToDraw = std::move(newIndices);
|
||||||
|
/*
|
||||||
// --- ОБНОВЛЯЕМ ЖЕЛТУЮ ЗОНУ (только когда изменился состав треугольников) ---
|
// --- ОБНОВЛЯЕМ ЖЕЛТУЮ ЗОНУ (только когда изменился состав треугольников) ---
|
||||||
const auto& fullMesh = planetData.getLodLevel(currentLod).vertexData;
|
const auto& fullMesh = planetData.getLodLevel(currentLod).vertexData;
|
||||||
planetRenderYellowStruct.data.PositionData.clear();
|
planetRenderYellowStruct.data.PositionData.clear();
|
||||||
@ -150,15 +121,7 @@ namespace ZL {
|
|||||||
if (planetRenderYellowStruct.data.PositionData.size() > 0)
|
if (planetRenderYellowStruct.data.PositionData.size() > 0)
|
||||||
{
|
{
|
||||||
planetRenderYellowStruct.RefreshVBO();
|
planetRenderYellowStruct.RefreshVBO();
|
||||||
}
|
}*/
|
||||||
|
|
||||||
// --- ОБНОВЛЯЕМ КАМНИ (через новую структуру StoneGroup) ---
|
|
||||||
if (triangleIndicesToDraw.size() > 0)
|
|
||||||
{
|
|
||||||
planetStones.inflate(triangleIndicesToDraw);
|
|
||||||
// Используем AssignFrom, он внутри сам вызывает RefreshVBO
|
|
||||||
planetStonesRenderStruct.AssignFrom(planetStones.mesh);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -166,7 +129,7 @@ namespace ZL {
|
|||||||
|
|
||||||
void PlanetObject::bakeStoneTexture(Renderer& renderer) {
|
void PlanetObject::bakeStoneTexture(Renderer& renderer) {
|
||||||
glViewport(0, 0, 512, 512);
|
glViewport(0, 0, 512, 512);
|
||||||
glClearColor(224 / 255.f, 201 / 255.f, 167 / 255.f, 1.0f);
|
glClearColor(0,0,0, 1.0f);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
|
||||||
@ -188,7 +151,7 @@ namespace ZL {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Triangle tr = planetData.getLodLevelNoDist(planetData.getCurrentLodIndex()).triangles[0];
|
Triangle tr = planetData.getLodLevel(planetData.getCurrentLodIndex()).triangles[0];
|
||||||
|
|
||||||
// 1. Получаем матрицу вращения (оси в столбцах)
|
// 1. Получаем матрицу вращения (оси в столбцах)
|
||||||
Matrix3f mr = GetRotationForTriangle(tr);
|
Matrix3f mr = GetRotationForTriangle(tr);
|
||||||
@ -213,8 +176,8 @@ namespace ZL {
|
|||||||
float centerX = (minX + maxX) * 0.5f;
|
float centerX = (minX + maxX) * 0.5f;
|
||||||
float centerY = (minY + maxY) * 0.5f;
|
float centerY = (minY + maxY) * 0.5f;
|
||||||
|
|
||||||
width = width * 0.995;
|
//width = width * 0.995;
|
||||||
height = height * 0.995;
|
//height = height * 0.995;
|
||||||
|
|
||||||
renderer.PushProjectionMatrix(
|
renderer.PushProjectionMatrix(
|
||||||
centerX - width*0.5, centerX + width * 0.5,
|
centerX - width*0.5, centerX + width * 0.5,
|
||||||
@ -239,19 +202,14 @@ namespace ZL {
|
|||||||
|
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_2D, sandTexture->getTexID());
|
|
||||||
renderer.PushMatrix();
|
|
||||||
|
|
||||||
renderer.DrawVertexRenderStruct(planetRenderStructCut);
|
|
||||||
renderer.PopMatrix();
|
|
||||||
|
|
||||||
glEnable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
glCullFace(GL_BACK); // Отсекаем задние грани
|
glCullFace(GL_BACK); // Отсекаем задние грани
|
||||||
if (planetStonesToBakeRenderStruct.data.PositionData.size() > 0)
|
if (stonesToRender[0].data.PositionData.size() > 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, stoneTexture->getTexID());
|
glBindTexture(GL_TEXTURE_2D, stoneTexture->getTexID());
|
||||||
renderer.DrawVertexRenderStruct(planetStonesToBakeRenderStruct);
|
renderer.DrawVertexRenderStruct(stonesToRender[0]);
|
||||||
CheckGlError();
|
CheckGlError();
|
||||||
}
|
}
|
||||||
glDisable(GL_CULL_FACE); // Не забываем выключить, чтобы не сломать остальной рендер
|
glDisable(GL_CULL_FACE); // Не забываем выключить, чтобы не сломать остальной рендер
|
||||||
@ -342,8 +300,8 @@ namespace ZL {
|
|||||||
// Позиция камеры (корабля) в мире
|
// Позиция камеры (корабля) в мире
|
||||||
renderer.RenderUniform3fv("uViewPos", &Environment::shipPosition.v[0]);
|
renderer.RenderUniform3fv("uViewPos", &Environment::shipPosition.v[0]);
|
||||||
|
|
||||||
//renderer.RenderUniform1f("uHeightScale", 0.03f);
|
renderer.RenderUniform1f("uHeightScale", 0.03f);
|
||||||
renderer.RenderUniform1f("uHeightScale", 0.0f);
|
//renderer.RenderUniform1f("uHeightScale", 0.0f);
|
||||||
|
|
||||||
renderer.RenderUniform1f("uDistanceToPlanetSurface", dist);
|
renderer.RenderUniform1f("uDistanceToPlanetSurface", dist);
|
||||||
renderer.RenderUniform1f("uCurrentZFar", currentZFar);
|
renderer.RenderUniform1f("uCurrentZFar", currentZFar);
|
||||||
@ -371,6 +329,7 @@ namespace ZL {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PlanetObject::drawStones(Renderer& renderer)
|
void PlanetObject::drawStones(Renderer& renderer)
|
||||||
{
|
{
|
||||||
static const std::string defaultShaderName2 = "planetStone";
|
static const std::string defaultShaderName2 = "planetStone";
|
||||||
@ -412,13 +371,16 @@ namespace ZL {
|
|||||||
glCullFace(GL_BACK);
|
glCullFace(GL_BACK);
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, stoneTexture->getTexID());
|
||||||
|
|
||||||
if (planetStonesRenderStruct.data.PositionData.size() > 0)
|
for (int i : triangleIndicesToDraw)
|
||||||
{
|
{
|
||||||
glBindTexture(GL_TEXTURE_2D, stoneTexture->getTexID());
|
if (stonesToRender[i].data.PositionData.size() > 0)
|
||||||
renderer.DrawVertexRenderStruct(planetStonesRenderStruct);
|
{
|
||||||
CheckGlError();
|
renderer.DrawVertexRenderStruct(stonesToRender[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
CheckGlError();
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
glDisable(GL_CULL_FACE);
|
glDisable(GL_CULL_FACE);
|
||||||
|
|
||||||
@ -436,6 +398,7 @@ namespace ZL {
|
|||||||
|
|
||||||
void PlanetObject::drawYellowZone(Renderer& renderer)
|
void PlanetObject::drawYellowZone(Renderer& renderer)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
|
||||||
static const std::string defaultShaderName = "planetLand";
|
static const std::string defaultShaderName = "planetLand";
|
||||||
static const std::string vPositionName = "vPosition";
|
static const std::string vPositionName = "vPosition";
|
||||||
@ -503,7 +466,7 @@ namespace ZL {
|
|||||||
renderer.shaderManager.PopShader();
|
renderer.shaderManager.PopShader();
|
||||||
CheckGlError();
|
CheckGlError();
|
||||||
|
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlanetObject::drawAtmosphere(Renderer& renderer) {
|
void PlanetObject::drawAtmosphere(Renderer& renderer) {
|
||||||
|
|||||||
@ -27,12 +27,10 @@ namespace ZL {
|
|||||||
|
|
||||||
// Данные только для рендеринга (OpenGL specific)
|
// Данные только для рендеринга (OpenGL specific)
|
||||||
VertexRenderStruct planetRenderStruct;
|
VertexRenderStruct planetRenderStruct;
|
||||||
VertexRenderStruct planetRenderStructCut;
|
|
||||||
VertexRenderStruct planetRenderYellowStruct;
|
VertexRenderStruct planetRenderYellowStruct;
|
||||||
VertexRenderStruct planetAtmosphereRenderStruct;
|
VertexRenderStruct planetAtmosphereRenderStruct;
|
||||||
VertexRenderStruct planetStonesRenderStruct;
|
|
||||||
VertexRenderStruct planetStonesToBakeRenderStruct;
|
|
||||||
StoneGroup planetStones;
|
StoneGroup planetStones;
|
||||||
|
std::vector<VertexRenderStruct> stonesToRender;
|
||||||
|
|
||||||
std::vector<int> triangleIndicesToDraw;
|
std::vector<int> triangleIndicesToDraw;
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
#include "StoneObject.h"
|
#include "StoneObject.h"
|
||||||
|
|
||||||
#include "utils/Utils.h"
|
#include "utils/Utils.h"
|
||||||
#include <GL/gl.h>
|
#include <GL/gl.h>
|
||||||
@ -10,39 +10,40 @@
|
|||||||
namespace ZL {
|
namespace ZL {
|
||||||
|
|
||||||
|
|
||||||
// --- КОНСТАНТЫ ПАРАМЕТРОВ (как вы просили) ---
|
|
||||||
const float StoneParams::BASE_SCALE = 17.0f; // Общий размер камня
|
const float StoneParams::BASE_SCALE = 15.0f; // Общий размер камня
|
||||||
//const float StoneParams::BASE_SCALE = 5000.0f; // Общий размер камня
|
/*const float StoneParams::BASE_SCALE = 150.0f; // Общий размер камня
|
||||||
//const float StoneParams::MIN_AXIS_SCALE = 1.0f; // Минимальное растяжение/сжатие по оси
|
const float StoneParams::MIN_AXIS_SCALE = 1.0f; // Минимальное растяжение/сжатие по оси
|
||||||
//const float StoneParams::MAX_AXIS_SCALE = 1.0f; // Максимальное растяжение/сжатие по оси
|
const float StoneParams::MAX_AXIS_SCALE = 1.0f; // Максимальное растяжение/сжатие по оси
|
||||||
//const float StoneParams::MIN_PERTURBATION = 0.0f; // Минимальное радиальное возмущение вершины
|
const float StoneParams::MIN_PERTURBATION = 0.0f; // Минимальное радиальное возмущение вершины
|
||||||
//const float StoneParams::MAX_PERTURBATION = 0.0f; // Максимальное радиальное возмущение вершины
|
const float StoneParams::MAX_PERTURBATION = 0.0f;*/ // Максимальное радиальное возмущение вершины
|
||||||
const float StoneParams::MIN_AXIS_SCALE = 0.5f; // Минимальное растяжение/сжатие по оси
|
const float StoneParams::MIN_AXIS_SCALE = 0.5f; // Минимальное растяжение/сжатие по оси
|
||||||
const float StoneParams::MAX_AXIS_SCALE = 1.5f; // Максимальное растяжение/сжатие по оси
|
const float StoneParams::MAX_AXIS_SCALE = 1.5f; // Максимальное растяжение/сжатие по оси
|
||||||
const float StoneParams::MIN_PERTURBATION = 0.05f; // Минимальное радиальное возмущение вершины
|
const float StoneParams::MIN_PERTURBATION = 0.05f; // Минимальное радиальное возмущение вершины
|
||||||
const float StoneParams::MAX_PERTURBATION = 0.25f; // Максимальное радиальное возмущение вершины
|
const float StoneParams::MAX_PERTURBATION = 0.25f; // Максимальное радиальное возмущение вершины
|
||||||
|
|
||||||
const int StoneParams::STONES_PER_TRIANGLE = 100;
|
const int StoneParams::STONES_PER_TRIANGLE = 100;
|
||||||
|
|
||||||
// Вспомогательная функция для получения случайного числа в диапазоне [min, max]
|
// Вспомогательная функция для получения случайного числа в диапазоне [min, max]
|
||||||
float getRandomFloat(std::mt19937& gen, float min, float max) {
|
float getRandomFloat(std::mt19937& gen, float min, float max) {
|
||||||
std::uniform_real_distribution<> distrib(min, max);
|
std::uniform_real_distribution<> distrib(min, max);
|
||||||
return static_cast<float>(distrib(gen));
|
return static_cast<float>(distrib(gen));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Вспомогательная функция для генерации случайной точки на треугольнике
|
// Вспомогательная функция для генерации случайной точки на треугольнике
|
||||||
// Использует барицентрические координаты
|
// Использует барицентрические координаты
|
||||||
Vector3f GetRandomPointOnTriangle(const Triangle& t, std::mt19937& engine) {
|
Vector3f GetRandomPointOnTriangle(const Triangle& t, std::mt19937& engine) {
|
||||||
std::uniform_real_distribution<> distrib(0.0f, 1.0f);
|
std::uniform_real_distribution<> distrib(0.0f, 1.0f);
|
||||||
|
|
||||||
float r1 = getRandomFloat(engine, 0.0f, 1.0f);
|
float r1 = getRandomFloat(engine, 0.0f, 1.0f);
|
||||||
float r2 = getRandomFloat(engine, 0.0f, 1.0f);
|
float r2 = getRandomFloat(engine, 0.0f, 1.0f);
|
||||||
|
|
||||||
// Преобразование r1, r2 для получения равномерного распределения
|
// Преобразование r1, r2 для получения равномерного распределения
|
||||||
float a = 1.0f - std::sqrt(r1);
|
float a = 1.0f - std::sqrt(r1);
|
||||||
float b = std::sqrt(r1) * r2;
|
float b = std::sqrt(r1) * r2;
|
||||||
float c = 1.0f - a - b; // c = sqrt(r1) * (1 - r2)
|
float c = 1.0f - a - b; // c = sqrt(r1) * (1 - r2)
|
||||||
|
|
||||||
// Барицентрические координаты
|
// Барицентрические координаты
|
||||||
// P = a*p1 + b*p2 + c*p3
|
// P = a*p1 + b*p2 + c*p3
|
||||||
Vector3f p1_term = t.data[0] * a;
|
Vector3f p1_term = t.data[0] * a;
|
||||||
Vector3f p2_term = t.data[1] * b;
|
Vector3f p2_term = t.data[1] * b;
|
||||||
@ -52,68 +53,68 @@ namespace ZL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Икосаэдр (на основе золотого сечения phi)
|
// Икосаэдр (на основе золотого сечения phi)
|
||||||
// Координаты могут быть вычислены заранее для константного икосаэдра.
|
// Координаты могут быть вычислены заранее для константного икосаэдра.
|
||||||
// Здесь только объявление, чтобы показать идею.
|
// Здесь только объявление, чтобы показать идею.
|
||||||
|
|
||||||
VertexDataStruct CreateBaseConvexPolyhedron(uint64_t seed) {
|
VertexDataStruct CreateBaseConvexPolyhedron(uint64_t seed) {
|
||||||
|
|
||||||
// const size_t SUBDIVISION_LEVEL = 1; // Уровень подразделения (для более круглого камня, пока опустим)
|
// const size_t SUBDIVISION_LEVEL = 1; // Уровень подразделения (для более круглого камня, пока опустим)
|
||||||
|
|
||||||
std::mt19937 engine(static_cast<unsigned int>(seed));
|
std::mt19937 engine(static_cast<unsigned int>(seed));
|
||||||
|
|
||||||
// Золотое сечение
|
// Золотое сечение
|
||||||
const float t = (1.0f + std::sqrt(5.0f)) / 2.0f;
|
const float t = (1.0f + std::sqrt(5.0f)) / 2.0f;
|
||||||
|
|
||||||
// 12 вершин икосаэдра
|
// 12 вершин икосаэдра
|
||||||
std::vector<Vector3f> initialVertices = {
|
std::vector<Vector3f> initialVertices = {
|
||||||
{ -1, t, 0 }, { 1, t, 0 }, { -1, -t, 0 }, { 1, -t, 0 },
|
{ -1, t, 0 }, { 1, t, 0 }, { -1, -t, 0 }, { 1, -t, 0 },
|
||||||
{ 0, -1, t }, { 0, 1, t }, { 0, -1, -t }, { 0, 1, -t },
|
{ 0, -1, t }, { 0, 1, t }, { 0, -1, -t }, { 0, 1, -t },
|
||||||
{ t, 0, -1 }, { t, 0, 1 }, { -t, 0, -1 }, { -t, 0, 1 }
|
{ t, 0, -1 }, { t, 0, 1 }, { -t, 0, -1 }, { -t, 0, 1 }
|
||||||
};
|
};
|
||||||
|
|
||||||
// 20 треугольных граней (индексы вершин)
|
// 20 треугольных граней (индексы вершин)
|
||||||
std::vector<std::array<int, 3>> faces = {
|
std::vector<std::array<int, 3>> faces = {
|
||||||
// 5 треугольников вокруг вершины 0
|
// 5 треугольников вокруг вершины 0
|
||||||
{0, 11, 5}, {0, 5, 1}, {0, 1, 7}, {0, 7, 10}, {0, 10, 11},
|
{0, 11, 5}, {0, 5, 1}, {0, 1, 7}, {0, 7, 10}, {0, 10, 11},
|
||||||
// 5 смежных полос
|
// 5 смежных полос
|
||||||
{1, 5, 9}, {5, 11, 4}, {11, 10, 2}, {10, 7, 6}, {7, 1, 8},
|
{1, 5, 9}, {5, 11, 4}, {11, 10, 2}, {10, 7, 6}, {7, 1, 8},
|
||||||
// 5 треугольников вокруг вершины 3
|
// 5 треугольников вокруг вершины 3
|
||||||
{3, 9, 4}, {3, 4, 2}, {3, 2, 6}, {3, 6, 8}, {3, 8, 9},
|
{3, 9, 4}, {3, 4, 2}, {3, 2, 6}, {3, 6, 8}, {3, 8, 9},
|
||||||
// 5 смежных полос
|
// 5 смежных полос
|
||||||
{4, 9, 5}, {2, 4, 11}, {6, 2, 10}, {8, 6, 7}, {9, 8, 1}
|
{4, 9, 5}, {2, 4, 11}, {6, 2, 10}, {8, 6, 7}, {9, 8, 1}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 1. Нормализация и Возмущение (Perturbation)
|
// 1. Нормализация и Возмущение (Perturbation)
|
||||||
for (Vector3f& v : initialVertices) {
|
for (Vector3f& v : initialVertices) {
|
||||||
v = v.normalized() * StoneParams::BASE_SCALE; // Нормализация к сфере радиуса BASE_SCALE
|
v = v.normalized() * StoneParams::BASE_SCALE; // Нормализация к сфере радиуса BASE_SCALE
|
||||||
|
|
||||||
// Радиальное возмущение:
|
// Радиальное возмущение:
|
||||||
float perturbation = getRandomFloat(engine, StoneParams::MIN_PERTURBATION, StoneParams::MAX_PERTURBATION);
|
float perturbation = getRandomFloat(engine, StoneParams::MIN_PERTURBATION, StoneParams::MAX_PERTURBATION);
|
||||||
v = v * (1.0f + perturbation);
|
v = v * (1.0f + perturbation);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Трансформация (Масштабирование и Поворот)
|
// 2. Трансформация (Масштабирование и Поворот)
|
||||||
|
|
||||||
// Случайные масштабы по осям
|
// Случайные масштабы по осям
|
||||||
Vector3f scaleFactors = {
|
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),
|
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) {
|
for (Vector3f& v : initialVertices) {
|
||||||
v.v[0] *= scaleFactors.v[0];
|
v.v[0] *= scaleFactors.v[0];
|
||||||
v.v[1] *= scaleFactors.v[1];
|
v.v[1] *= scaleFactors.v[1];
|
||||||
v.v[2] *= scaleFactors.v[2];
|
v.v[2] *= scaleFactors.v[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Случайный поворот (например, вокруг трех осей)
|
// Случайный поворот (например, вокруг трех осей)
|
||||||
Vector4f qx = QuatFromRotateAroundX(getRandomFloat(engine, 0.0f, 360.0f));
|
Vector4f qx = QuatFromRotateAroundX(getRandomFloat(engine, 0.0f, 360.0f));
|
||||||
Vector4f qy = QuatFromRotateAroundY(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 qz = QuatFromRotateAroundZ(getRandomFloat(engine, 0.0f, 360.0f));
|
||||||
Vector4f qFinal = slerp(qx, qy, 0.5f); // Простой пример комбинирования
|
Vector4f qFinal = slerp(qx, qy, 0.5f); // Простой пример комбинирования
|
||||||
qFinal = slerp(qFinal, qz, 0.5f).normalized();
|
qFinal = slerp(qFinal, qz, 0.5f).normalized();
|
||||||
Matrix3f rotationMatrix = QuatToMatrix(qFinal);
|
Matrix3f rotationMatrix = QuatToMatrix(qFinal);
|
||||||
|
|
||||||
@ -121,19 +122,19 @@ namespace ZL {
|
|||||||
v = MultMatrixVector(rotationMatrix, v);
|
v = MultMatrixVector(rotationMatrix, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Сглаженные Нормали и Формирование Mesh
|
// 3. Сглаженные Нормали и Формирование Mesh
|
||||||
VertexDataStruct result;
|
VertexDataStruct result;
|
||||||
// Карта для накопления нормалей по уникальным позициям вершин
|
// Карта для накопления нормалей по уникальным позициям вершин
|
||||||
// (Требует определенного оператора < для Vector3f в ZLMath.h, который у вас есть)
|
// (Требует определенного оператора < для Vector3f в ZLMath.h, который у вас есть)
|
||||||
std::map<Vector3f, Vector3f> smoothNormalsMap;
|
std::map<Vector3f, Vector3f> smoothNormalsMap;
|
||||||
|
|
||||||
// Предварительное заполнение карты нормалями
|
// Предварительное заполнение карты нормалями
|
||||||
for (const auto& face : faces) {
|
for (const auto& face : faces) {
|
||||||
Vector3f p1 = initialVertices[face[0]];
|
Vector3f p1 = initialVertices[face[0]];
|
||||||
Vector3f p2 = initialVertices[face[1]];
|
Vector3f p2 = initialVertices[face[1]];
|
||||||
Vector3f p3 = initialVertices[face[2]];
|
Vector3f p3 = initialVertices[face[2]];
|
||||||
|
|
||||||
// Нормаль грани: (p2 - p1) x (p3 - p1)
|
// Нормаль грани: (p2 - p1) x (p3 - p1)
|
||||||
Vector3f faceNormal = (p2 - p1).cross(p3 - p1).normalized();
|
Vector3f faceNormal = (p2 - p1).cross(p3 - p1).normalized();
|
||||||
|
|
||||||
smoothNormalsMap[p1] = smoothNormalsMap[p1] + faceNormal;
|
smoothNormalsMap[p1] = smoothNormalsMap[p1] + faceNormal;
|
||||||
@ -141,63 +142,63 @@ namespace ZL {
|
|||||||
smoothNormalsMap[p3] = smoothNormalsMap[p3] + faceNormal;
|
smoothNormalsMap[p3] = smoothNormalsMap[p3] + faceNormal;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Нормализация накопленных нормалей
|
// Нормализация накопленных нормалей
|
||||||
for (auto& pair : smoothNormalsMap) {
|
for (auto& pair : smoothNormalsMap) {
|
||||||
pair.second = pair.second.normalized();
|
pair.second = pair.second.normalized();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 4. Финальное заполнение VertexDataStruct и Текстурные Координаты
|
// 4. Финальное заполнение VertexDataStruct и Текстурные Координаты
|
||||||
for (const auto& face : faces) {
|
for (const auto& face : faces) {
|
||||||
Vector3f p1 = initialVertices[face[0]];
|
Vector3f p1 = initialVertices[face[0]];
|
||||||
Vector3f p2 = initialVertices[face[1]];
|
Vector3f p2 = initialVertices[face[1]];
|
||||||
Vector3f p3 = initialVertices[face[2]];
|
Vector3f p3 = initialVertices[face[2]];
|
||||||
|
|
||||||
// Позиции
|
// Позиции
|
||||||
result.PositionData.push_back(p1);
|
result.PositionData.push_back(p1);
|
||||||
result.PositionData.push_back(p2);
|
result.PositionData.push_back(p2);
|
||||||
result.PositionData.push_back(p3);
|
result.PositionData.push_back(p3);
|
||||||
|
|
||||||
// Сглаженные Нормали (из карты)
|
// Сглаженные Нормали (из карты)
|
||||||
result.NormalData.push_back(smoothNormalsMap[p1]);
|
result.NormalData.push_back(smoothNormalsMap[p1]);
|
||||||
result.NormalData.push_back(smoothNormalsMap[p2]);
|
result.NormalData.push_back(smoothNormalsMap[p2]);
|
||||||
result.NormalData.push_back(smoothNormalsMap[p3]);
|
result.NormalData.push_back(smoothNormalsMap[p3]);
|
||||||
|
|
||||||
// Текстурные Координаты (Планарная проекция на плоскость грани)
|
// Текстурные Координаты (Планарная проекция на плоскость грани)
|
||||||
// p1 -> (0, 0), p2 -> (L_12, 0), p3 -> (L_13 * cos(angle), L_13 * sin(angle))
|
// p1 -> (0, 0), p2 -> (L_12, 0), p3 -> (L_13 * cos(angle), L_13 * sin(angle))
|
||||||
// Где L_xy - длина вектора, angle - угол между p2-p1 и p3-p1
|
// Где L_xy - длина вектора, angle - угол между p2-p1 и p3-p1
|
||||||
|
|
||||||
Vector3f uAxis = (p2 - p1).normalized();
|
Vector3f uAxis = (p2 - p1).normalized();
|
||||||
Vector3f vRaw = p3 - p1;
|
Vector3f vRaw = p3 - p1;
|
||||||
|
|
||||||
// Проекция vRaw на uAxis
|
// Проекция vRaw на uAxis
|
||||||
float uProjLen = vRaw.dot(uAxis);
|
float uProjLen = vRaw.dot(uAxis);
|
||||||
|
|
||||||
// Вектор V перпендикулярный U: vRaw - uProj
|
// Вектор V перпендикулярный U: vRaw - uProj
|
||||||
Vector3f vAxisRaw = vRaw - (uAxis * uProjLen);
|
Vector3f vAxisRaw = vRaw - (uAxis * uProjLen);
|
||||||
|
|
||||||
// Длина оси V
|
// Длина оси V
|
||||||
float vLen = vAxisRaw.length();
|
float vLen = vAxisRaw.length();
|
||||||
|
|
||||||
// Нормализованная ось V
|
// Нормализованная ось V
|
||||||
Vector3f vAxis = vAxisRaw.normalized();
|
Vector3f vAxis = vAxisRaw.normalized();
|
||||||
|
|
||||||
// Координаты (u, v) для p1, p2, p3 относительно p1
|
// Координаты (u, v) для p1, p2, p3 относительно p1
|
||||||
Vector2f uv1 = { 0.0f, 0.0f };
|
Vector2f uv1 = { 0.0f, 0.0f };
|
||||||
Vector2f uv2 = { (p2 - p1).length(), 0.0f }; // p2-p1 вдоль оси U
|
Vector2f uv2 = { (p2 - p1).length(), 0.0f }; // p2-p1 вдоль оси U
|
||||||
Vector2f uv3 = { uProjLen, vLen }; // p3-p1: u-компонента = uProjLen, v-компонента = vLen
|
Vector2f uv3 = { uProjLen, vLen }; // p3-p1: u-компонента = uProjLen, v-компонента = vLen
|
||||||
|
|
||||||
// Находим максимальный размер, чтобы масштабировать в [0, 1]
|
// Находим максимальный размер, чтобы масштабировать в [0, 1]
|
||||||
float maxUV = max(uv2.v[0], max(uv3.v[0], uv3.v[1]));
|
float maxUV = max(uv2.v[0], max(uv3.v[0], uv3.v[1]));
|
||||||
|
|
||||||
if (maxUV > 0.000001f) {
|
if (maxUV > 0.000001f) {
|
||||||
// Масштабируем:
|
// Масштабируем:
|
||||||
result.TexCoordData.push_back(uv1);
|
result.TexCoordData.push_back(uv1);
|
||||||
result.TexCoordData.push_back(uv2 * (1.f / maxUV));
|
result.TexCoordData.push_back(uv2 * (1.f / maxUV));
|
||||||
result.TexCoordData.push_back(uv3 * (1.f / maxUV));
|
result.TexCoordData.push_back(uv3 * (1.f / maxUV));
|
||||||
}
|
}
|
||||||
else {
|
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 });
|
result.TexCoordData.push_back({ 0.0f, 0.0f });
|
||||||
result.TexCoordData.push_back({ 0.0f, 0.0f });
|
result.TexCoordData.push_back({ 0.0f, 0.0f });
|
||||||
@ -207,10 +208,36 @@ namespace ZL {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Triangle createLocalTriangle(const Triangle& sampleTri)
|
||||||
|
{
|
||||||
|
// Находим центр в 3D
|
||||||
|
Vector3f center = (sampleTri.data[0] + sampleTri.data[1] + sampleTri.data[2]) * (1.0f / 3.0f);
|
||||||
|
|
||||||
|
// Строим базис самого треугольника
|
||||||
|
// vY направляем на 0-ю вершину (как в вашем Special расчете)
|
||||||
|
Vector3f vY = (sampleTri.data[0] - center).normalized();
|
||||||
|
// Временный X для расчета нормали
|
||||||
|
Vector3f vX_temp = (sampleTri.data[1] - sampleTri.data[2]).normalized();
|
||||||
|
// Чистая нормаль
|
||||||
|
Vector3f vZ = vX_temp.cross(vY).normalized();
|
||||||
|
// Чистый X, перпендикулярный Y и Z
|
||||||
|
Vector3f vX = vY.cross(vZ).normalized();
|
||||||
|
|
||||||
|
// Переводим 3D точки в этот 2D базис (Z зануляется сам собой)
|
||||||
|
auto toLocal = [&](const Vector3f& p) {
|
||||||
|
Vector3f d = p - center;
|
||||||
|
return Vector3f{ d.dot(vX), d.dot(vY), 0.0f };
|
||||||
|
};
|
||||||
|
|
||||||
|
Triangle local;
|
||||||
|
local.data[0] = toLocal(sampleTri.data[0]);
|
||||||
|
local.data[1] = toLocal(sampleTri.data[1]);
|
||||||
|
local.data[2] = toLocal(sampleTri.data[2]);
|
||||||
|
return local;
|
||||||
|
}
|
||||||
|
|
||||||
StoneGroup CreateStoneGroupData(uint64_t globalSeed, const LodLevel& planetLodLevel) {
|
StoneGroup CreateStoneGroupData(uint64_t globalSeed, const LodLevel& planetLodLevel) {
|
||||||
StoneGroup group;
|
StoneGroup group;
|
||||||
|
|
||||||
// Резервируем место под все треугольники текущего LOD
|
|
||||||
group.allInstances.resize(planetLodLevel.triangles.size());
|
group.allInstances.resize(planetLodLevel.triangles.size());
|
||||||
|
|
||||||
for (size_t tIdx = 0; tIdx < planetLodLevel.triangles.size(); ++tIdx) {
|
for (size_t tIdx = 0; tIdx < planetLodLevel.triangles.size(); ++tIdx) {
|
||||||
@ -219,18 +246,21 @@ namespace ZL {
|
|||||||
|
|
||||||
for (int i = 0; i < StoneParams::STONES_PER_TRIANGLE; ++i) {
|
for (int i = 0; i < StoneParams::STONES_PER_TRIANGLE; ++i) {
|
||||||
StoneInstance instance;
|
StoneInstance instance;
|
||||||
instance.seed = globalSeed;// + tIdx * 1000 + i; // Уникальный сид для каждого камня
|
instance.seed = globalSeed;// + tIdx * 1000 + i;
|
||||||
|
|
||||||
instance.position = GetRandomPointOnTriangle(tri, engine);
|
instance.position = GetRandomPointOnTriangle(tri, engine);
|
||||||
|
|
||||||
//instance.position = Vector3f(5000.0f, 5000.0f, 5000.0f);
|
|
||||||
// Генерируем случайные параметры один раз
|
|
||||||
instance.scale = {
|
instance.scale = {
|
||||||
getRandomFloat(engine, 0.5f, 1.5f),
|
getRandomFloat(engine, 0.5f, 1.5f),
|
||||||
getRandomFloat(engine, 0.5f, 1.5f),
|
getRandomFloat(engine, 0.5f, 1.5f),
|
||||||
getRandomFloat(engine, 0.5f, 1.5f)
|
getRandomFloat(engine, 0.5f, 1.5f)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//!!! Hack - to fix it! -- Vladislav Khorev
|
||||||
|
if (tIdx == 0)
|
||||||
|
{
|
||||||
|
instance.scale = instance.scale * 0.6f;
|
||||||
|
}
|
||||||
|
|
||||||
Vector4f qx = QuatFromRotateAroundX(getRandomFloat(engine, 0.0f, 360.0f));
|
Vector4f qx = QuatFromRotateAroundX(getRandomFloat(engine, 0.0f, 360.0f));
|
||||||
Vector4f qy = QuatFromRotateAroundY(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 qz = QuatFromRotateAroundZ(getRandomFloat(engine, 0.0f, 360.0f));
|
||||||
@ -242,18 +272,15 @@ namespace ZL {
|
|||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StoneGroup::inflate(const std::vector<int>& triangleIndices) {
|
std::vector<VertexRenderStruct> StoneGroup::inflate(int count)
|
||||||
// 1. Очищаем текущий меш перед заполнением
|
{
|
||||||
mesh.PositionData.clear();
|
|
||||||
mesh.NormalData.clear();
|
|
||||||
mesh.TexCoordData.clear();
|
|
||||||
|
|
||||||
static VertexDataStruct baseStone = CreateBaseConvexPolyhedron(1337);
|
static VertexDataStruct baseStone = CreateBaseConvexPolyhedron(1337);
|
||||||
|
|
||||||
// 2. Наполняем меш только для видимых треугольников
|
std::vector<VertexRenderStruct> result;
|
||||||
for (int tIdx : triangleIndices) {
|
result.resize(count);
|
||||||
if (tIdx >= allInstances.size()) continue;
|
|
||||||
|
|
||||||
|
for (int tIdx = 0; tIdx < count; tIdx++)
|
||||||
|
{
|
||||||
for (const auto& inst : allInstances[tIdx]) {
|
for (const auto& inst : allInstances[tIdx]) {
|
||||||
Matrix3f rotMat = QuatToMatrix(inst.rotation);
|
Matrix3f rotMat = QuatToMatrix(inst.rotation);
|
||||||
|
|
||||||
@ -261,16 +288,21 @@ namespace ZL {
|
|||||||
Vector3f p = baseStone.PositionData[j];
|
Vector3f p = baseStone.PositionData[j];
|
||||||
Vector3f n = baseStone.NormalData[j];
|
Vector3f n = baseStone.NormalData[j];
|
||||||
|
|
||||||
// Масштаб -> Поворот -> Смещение
|
|
||||||
p.v[0] *= inst.scale.v[0];
|
p.v[0] *= inst.scale.v[0];
|
||||||
p.v[1] *= inst.scale.v[1];
|
p.v[1] *= inst.scale.v[1];
|
||||||
p.v[2] *= inst.scale.v[2];
|
p.v[2] *= inst.scale.v[2];
|
||||||
|
|
||||||
mesh.PositionData.push_back(MultMatrixVector(rotMat, p) + inst.position);
|
result[tIdx].data.PositionData.push_back(MultMatrixVector(rotMat, p) + inst.position);
|
||||||
mesh.NormalData.push_back(MultMatrixVector(rotMat, n));
|
result[tIdx].data.NormalData.push_back(MultMatrixVector(rotMat, n));
|
||||||
mesh.TexCoordData.push_back(baseStone.TexCoordData[j]);
|
result[tIdx].data.TexCoordData.push_back(baseStone.TexCoordData[j]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result[tIdx].RefreshVBO();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ZL
|
} // namespace ZL
|
||||||
|
|||||||
@ -27,15 +27,15 @@ namespace ZL {
|
|||||||
// mesh.PositionData и прочие будут заполняться в inflate()
|
// mesh.PositionData и прочие будут заполняться в inflate()
|
||||||
VertexDataStruct mesh;
|
VertexDataStruct mesh;
|
||||||
|
|
||||||
// Âíåøíèé âåêòîð — èíäåêñ òðåóãîëüíèêà ïëàíåòû,
|
|
||||||
// âíóòðåííèé — ñïèñîê êàìíåé íà ýòîì òðåóãîëüíèêå
|
|
||||||
std::vector<std::vector<StoneInstance>> allInstances;
|
std::vector<std::vector<StoneInstance>> allInstances;
|
||||||
|
|
||||||
// Очищает старую геометрию и генерирует новую для указанных индексов
|
// Очищает старую геометрию и генерирует новую для указанных индексов
|
||||||
void inflate(const std::vector<int>& triangleIndices);
|
std::vector<VertexRenderStruct> inflate(int count);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Теперь возвращает заготовку со всеми параметрами, но без тяжелого меша
|
// Теперь возвращает заготовку со всеми параметрами, но без тяжелого меша
|
||||||
StoneGroup CreateStoneGroupData(uint64_t globalSeed, const LodLevel& planetLodLevel);
|
StoneGroup CreateStoneGroupData(uint64_t globalSeed, const LodLevel& lodLevel);
|
||||||
|
|
||||||
|
Triangle createLocalTriangle(const Triangle& sampleTri);
|
||||||
|
|
||||||
} // namespace ZL
|
} // namespace ZL
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user