From 44c54b03bfc8dc429666e4b6493562a3ae052d82 Mon Sep 17 00:00:00 2001 From: Evert Prants Date: Sat, 1 Oct 2022 12:00:55 +0300 Subject: [PATCH] random --- .vscode/settings.json | 6 + data/shaders/chunk.frag | 2 +- src/Application.cpp | 2 +- src/geometry/sphere/Sphere.cpp | 595 +++++++++++++++++++++++++++++++++ src/geometry/sphere/Sphere.h | 99 ++++++ src/planet/PlanetFace.cpp | 111 +++--- src/planet/PlanetFace.h | 7 +- 7 files changed, 772 insertions(+), 50 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 src/geometry/sphere/Sphere.cpp create mode 100644 src/geometry/sphere/Sphere.h diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..d04c0f4 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", + "files.associations": { + "*.def": "cpp" + } +} diff --git a/data/shaders/chunk.frag b/data/shaders/chunk.frag index 91ef902..af7c4a8 100644 --- a/data/shaders/chunk.frag +++ b/data/shaders/chunk.frag @@ -3,5 +3,5 @@ in vec3 testo; void main(void) { - gl_FragColor = vec4(testo.xyz, 1.0f); + gl_FragColor = vec4((testo.x / 2) + 0.5, (testo.y / 2) + 0.5, (testo.z / 2) + 0.5, 1.0f); } diff --git a/src/Application.cpp b/src/Application.cpp index b4566d0..628e559 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -197,7 +197,7 @@ void Application::run() handleEvents(); // Clear color buffer - glClearColor(0.39f, 0.58f, 0.93f, 1.f); + glClearColor(0.0f, 0.0f, 0.0f, 1.f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); deltaTime = ((m_now - m_last) / (double)SDL_GetPerformanceFrequency()); diff --git a/src/geometry/sphere/Sphere.cpp b/src/geometry/sphere/Sphere.cpp new file mode 100644 index 0000000..4a32a72 --- /dev/null +++ b/src/geometry/sphere/Sphere.cpp @@ -0,0 +1,595 @@ +/////////////////////////////////////////////////////////////////////////////// +// Sphere.cpp +// ========== +// Sphere for OpenGL with (radius, sectors, stacks) +// The min number of sectors is 3 and the min number of stacks are 2. +// +// AUTHOR: Song Ho Ahn (song.ahn@gmail.com) +// CREATED: 2017-11-01 +// UPDATED: 2020-05-20 +/////////////////////////////////////////////////////////////////////////////// + +#ifdef _WIN32 +#include // include windows.h to avoid thousands of compile errors even though this class is not depending on Windows +#endif + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#include +#include +#include +#include "Sphere.h" + + + +// constants ////////////////////////////////////////////////////////////////// +const int MIN_SECTOR_COUNT = 3; +const int MIN_STACK_COUNT = 2; + + + +/////////////////////////////////////////////////////////////////////////////// +// ctor +/////////////////////////////////////////////////////////////////////////////// +Sphere::Sphere(float radius, int sectors, int stacks, bool smooth) : interleavedStride(32) +{ + set(radius, sectors, stacks, smooth); +} + + + +/////////////////////////////////////////////////////////////////////////////// +// setters +/////////////////////////////////////////////////////////////////////////////// +void Sphere::set(float radius, int sectors, int stacks, bool smooth) +{ + this->radius = radius; + this->sectorCount = sectors; + if(sectors < MIN_SECTOR_COUNT) + this->sectorCount = MIN_SECTOR_COUNT; + this->stackCount = stacks; + if(sectors < MIN_STACK_COUNT) + this->sectorCount = MIN_STACK_COUNT; + this->smooth = smooth; + + if(smooth) + buildVerticesSmooth(); + else + buildVerticesFlat(); +} + +void Sphere::setRadius(float radius) +{ + if(radius != this->radius) + set(radius, sectorCount, stackCount, smooth); +} + +void Sphere::setSectorCount(int sectors) +{ + if(sectors != this->sectorCount) + set(radius, sectors, stackCount, smooth); +} + +void Sphere::setStackCount(int stacks) +{ + if(stacks != this->stackCount) + set(radius, sectorCount, stacks, smooth); +} + +void Sphere::setSmooth(bool smooth) +{ + if(this->smooth == smooth) + return; + + this->smooth = smooth; + if(smooth) + buildVerticesSmooth(); + else + buildVerticesFlat(); +} + + + +/////////////////////////////////////////////////////////////////////////////// +// print itself +/////////////////////////////////////////////////////////////////////////////// +void Sphere::printSelf() const +{ + std::cout << "===== Sphere =====\n" + << " Radius: " << radius << "\n" + << " Sector Count: " << sectorCount << "\n" + << " Stack Count: " << stackCount << "\n" + << "Smooth Shading: " << (smooth ? "true" : "false") << "\n" + << "Triangle Count: " << getTriangleCount() << "\n" + << " Index Count: " << getIndexCount() << "\n" + << " Vertex Count: " << getVertexCount() << "\n" + << " Normal Count: " << getNormalCount() << "\n" + << "TexCoord Count: " << getTexCoordCount() << std::endl; +} + + + +/////////////////////////////////////////////////////////////////////////////// +// draw a sphere in VertexArray mode +// OpenGL RC must be set before calling it +/////////////////////////////////////////////////////////////////////////////// +void Sphere::draw() const +{ + // interleaved array + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glVertexPointer(3, GL_FLOAT, interleavedStride, &interleavedVertices[0]); + glNormalPointer(GL_FLOAT, interleavedStride, &interleavedVertices[3]); + glTexCoordPointer(2, GL_FLOAT, interleavedStride, &interleavedVertices[6]); + + glDrawElements(GL_TRIANGLES, (unsigned int)indices.size(), GL_UNSIGNED_INT, indices.data()); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); +} + + + +/////////////////////////////////////////////////////////////////////////////// +// draw lines only +// the caller must set the line width before call this +/////////////////////////////////////////////////////////////////////////////// +void Sphere::drawLines(const float lineColor[4]) const +{ + // set line colour + glColor4fv(lineColor); + glMaterialfv(GL_FRONT, GL_DIFFUSE, lineColor); + + // draw lines with VA + glDisable(GL_LIGHTING); + glDisable(GL_TEXTURE_2D); + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, vertices.data()); + + glDrawElements(GL_LINES, (unsigned int)lineIndices.size(), GL_UNSIGNED_INT, lineIndices.data()); + + glDisableClientState(GL_VERTEX_ARRAY); + glEnable(GL_LIGHTING); + glEnable(GL_TEXTURE_2D); +} + + + +/////////////////////////////////////////////////////////////////////////////// +// draw a sphere surfaces and lines on top of it +// the caller must set the line width before call this +/////////////////////////////////////////////////////////////////////////////// +void Sphere::drawWithLines(const float lineColor[4]) const +{ + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(1.0, 1.0f); // move polygon backward + this->draw(); + glDisable(GL_POLYGON_OFFSET_FILL); + + // draw lines with VA + drawLines(lineColor); +} + + + +/*@@ FIXME: when the radius = 0 +/////////////////////////////////////////////////////////////////////////////// +// update vertex positions only +/////////////////////////////////////////////////////////////////////////////// +void Sphere::updateRadius() +{ + float scale = sqrtf(radius * radius / (vertices[0] * vertices[0] + vertices[1] * vertices[1] + vertices[2] * vertices[2])); + + std::size_t i, j; + std::size_t count = vertices.size(); + for(i = 0, j = 0; i < count; i += 3, j += 8) + { + vertices[i] *= scale; + vertices[i+1] *= scale; + vertices[i+2] *= scale; + + // for interleaved array + interleavedVertices[j] *= scale; + interleavedVertices[j+1] *= scale; + interleavedVertices[j+2] *= scale; + } +} +*/ + + + +/////////////////////////////////////////////////////////////////////////////// +// dealloc vectors +/////////////////////////////////////////////////////////////////////////////// +void Sphere::clearArrays() +{ + std::vector().swap(vertices); + std::vector().swap(normals); + std::vector().swap(texCoords); + std::vector().swap(indices); + std::vector().swap(lineIndices); +} + + + +/////////////////////////////////////////////////////////////////////////////// +// build vertices of sphere with smooth shading using parametric equation +// x = r * cos(u) * cos(v) +// y = r * cos(u) * sin(v) +// z = r * sin(u) +// where u: stack(latitude) angle (-90 <= u <= 90) +// v: sector(longitude) angle (0 <= v <= 360) +/////////////////////////////////////////////////////////////////////////////// +void Sphere::buildVerticesSmooth() +{ + const float PI = acos(-1); + + // clear memory of prev arrays + clearArrays(); + + float x, y, z, xy; // vertex position + float nx, ny, nz, lengthInv = 1.0f / radius; // normal + float s, t; // texCoord + + float sectorStep = 2 * PI / sectorCount; + float stackStep = PI / stackCount; + float sectorAngle, stackAngle; + + for(int i = 0; i <= stackCount; ++i) + { + stackAngle = PI / 2 - i * stackStep; // starting from pi/2 to -pi/2 + xy = radius * cosf(stackAngle); // r * cos(u) + z = radius * sinf(stackAngle); // r * sin(u) + + // add (sectorCount+1) vertices per stack + // the first and last vertices have same position and normal, but different tex coords + for(int j = 0; j <= sectorCount; ++j) + { + sectorAngle = j * sectorStep; // starting from 0 to 2pi + + // vertex position + x = xy * cosf(sectorAngle); // r * cos(u) * cos(v) + y = xy * sinf(sectorAngle); // r * cos(u) * sin(v) + addVertex(x, y, z); + + // normalized vertex normal + nx = x * lengthInv; + ny = y * lengthInv; + nz = z * lengthInv; + addNormal(nx, ny, nz); + + // vertex tex coord between [0, 1] + s = (float)j / sectorCount; + t = (float)i / stackCount; + addTexCoord(s, t); + } + } + + // indices + // k1--k1+1 + // | / | + // | / | + // k2--k2+1 + unsigned int k1, k2; + for(int i = 0; i < stackCount; ++i) + { + k1 = i * (sectorCount + 1); // beginning of current stack + k2 = k1 + sectorCount + 1; // beginning of next stack + + for(int j = 0; j < sectorCount; ++j, ++k1, ++k2) + { + // 2 triangles per sector excluding 1st and last stacks + if(i != 0) + { + addIndices(k1, k2, k1+1); // k1---k2---k1+1 + } + + if(i != (stackCount-1)) + { + addIndices(k1+1, k2, k2+1); // k1+1---k2---k2+1 + } + + // vertical lines for all stacks + lineIndices.push_back(k1); + lineIndices.push_back(k2); + if(i != 0) // horizontal lines except 1st stack + { + lineIndices.push_back(k1); + lineIndices.push_back(k1 + 1); + } + } + } + + // generate interleaved vertex array as well + buildInterleavedVertices(); +} + + + +/////////////////////////////////////////////////////////////////////////////// +// generate vertices with flat shading +// each triangle is independent (no shared vertices) +/////////////////////////////////////////////////////////////////////////////// +void Sphere::buildVerticesFlat() +{ + const float PI = acos(-1); + + // tmp vertex definition (x,y,z,s,t) + struct Vertex + { + float x, y, z, s, t; + }; + std::vector tmpVertices; + + float sectorStep = 2 * PI / sectorCount; + float stackStep = PI / stackCount; + float sectorAngle, stackAngle; + + // compute all vertices first, each vertex contains (x,y,z,s,t) except normal + for(int i = 0; i <= stackCount; ++i) + { + stackAngle = PI / 2 - i * stackStep; // starting from pi/2 to -pi/2 + float xy = radius * cosf(stackAngle); // r * cos(u) + float z = radius * sinf(stackAngle); // r * sin(u) + + // add (sectorCount+1) vertices per stack + // the first and last vertices have same position and normal, but different tex coords + for(int j = 0; j <= sectorCount; ++j) + { + sectorAngle = j * sectorStep; // starting from 0 to 2pi + + Vertex vertex; + vertex.x = xy * cosf(sectorAngle); // x = r * cos(u) * cos(v) + vertex.y = xy * sinf(sectorAngle); // y = r * cos(u) * sin(v) + vertex.z = z; // z = r * sin(u) + vertex.s = (float)j/sectorCount; // s + vertex.t = (float)i/stackCount; // t + tmpVertices.push_back(vertex); + } + } + + // clear memory of prev arrays + clearArrays(); + + Vertex v1, v2, v3, v4; // 4 vertex positions and tex coords + std::vector n; // 1 face normal + + int i, j, k, vi1, vi2; + int index = 0; // index for vertex + for(i = 0; i < stackCount; ++i) + { + vi1 = i * (sectorCount + 1); // index of tmpVertices + vi2 = (i + 1) * (sectorCount + 1); + + for(j = 0; j < sectorCount; ++j, ++vi1, ++vi2) + { + // get 4 vertices per sector + // v1--v3 + // | | + // v2--v4 + v1 = tmpVertices[vi1]; + v2 = tmpVertices[vi2]; + v3 = tmpVertices[vi1 + 1]; + v4 = tmpVertices[vi2 + 1]; + + // if 1st stack and last stack, store only 1 triangle per sector + // otherwise, store 2 triangles (quad) per sector + if(i == 0) // a triangle for first stack ========================== + { + // put a triangle + addVertex(v1.x, v1.y, v1.z); + addVertex(v2.x, v2.y, v2.z); + addVertex(v4.x, v4.y, v4.z); + + // put tex coords of triangle + addTexCoord(v1.s, v1.t); + addTexCoord(v2.s, v2.t); + addTexCoord(v4.s, v4.t); + + // put normal + n = computeFaceNormal(v1.x,v1.y,v1.z, v2.x,v2.y,v2.z, v4.x,v4.y,v4.z); + for(k = 0; k < 3; ++k) // same normals for 3 vertices + { + addNormal(n[0], n[1], n[2]); + } + + // put indices of 1 triangle + addIndices(index, index+1, index+2); + + // indices for line (first stack requires only vertical line) + lineIndices.push_back(index); + lineIndices.push_back(index+1); + + index += 3; // for next + } + else if(i == (stackCount-1)) // a triangle for last stack ========= + { + // put a triangle + addVertex(v1.x, v1.y, v1.z); + addVertex(v2.x, v2.y, v2.z); + addVertex(v3.x, v3.y, v3.z); + + // put tex coords of triangle + addTexCoord(v1.s, v1.t); + addTexCoord(v2.s, v2.t); + addTexCoord(v3.s, v3.t); + + // put normal + n = computeFaceNormal(v1.x,v1.y,v1.z, v2.x,v2.y,v2.z, v3.x,v3.y,v3.z); + for(k = 0; k < 3; ++k) // same normals for 3 vertices + { + addNormal(n[0], n[1], n[2]); + } + + // put indices of 1 triangle + addIndices(index, index+1, index+2); + + // indices for lines (last stack requires both vert/hori lines) + lineIndices.push_back(index); + lineIndices.push_back(index+1); + lineIndices.push_back(index); + lineIndices.push_back(index+2); + + index += 3; // for next + } + else // 2 triangles for others ==================================== + { + // put quad vertices: v1-v2-v3-v4 + addVertex(v1.x, v1.y, v1.z); + addVertex(v2.x, v2.y, v2.z); + addVertex(v3.x, v3.y, v3.z); + addVertex(v4.x, v4.y, v4.z); + + // put tex coords of quad + addTexCoord(v1.s, v1.t); + addTexCoord(v2.s, v2.t); + addTexCoord(v3.s, v3.t); + addTexCoord(v4.s, v4.t); + + // put normal + n = computeFaceNormal(v1.x,v1.y,v1.z, v2.x,v2.y,v2.z, v3.x,v3.y,v3.z); + for(k = 0; k < 4; ++k) // same normals for 4 vertices + { + addNormal(n[0], n[1], n[2]); + } + + // put indices of quad (2 triangles) + addIndices(index, index+1, index+2); + addIndices(index+2, index+1, index+3); + + // indices for lines + lineIndices.push_back(index); + lineIndices.push_back(index+1); + lineIndices.push_back(index); + lineIndices.push_back(index+2); + + index += 4; // for next + } + } + } + + // generate interleaved vertex array as well + buildInterleavedVertices(); +} + + + +/////////////////////////////////////////////////////////////////////////////// +// generate interleaved vertices: V/N/T +// stride must be 32 bytes +/////////////////////////////////////////////////////////////////////////////// +void Sphere::buildInterleavedVertices() +{ + std::vector().swap(interleavedVertices); + + std::size_t i, j; + std::size_t count = vertices.size(); + for(i = 0, j = 0; i < count; i += 3, j += 2) + { + interleavedVertices.push_back(vertices[i]); + interleavedVertices.push_back(vertices[i+1]); + interleavedVertices.push_back(vertices[i+2]); + + interleavedVertices.push_back(normals[i]); + interleavedVertices.push_back(normals[i+1]); + interleavedVertices.push_back(normals[i+2]); + + interleavedVertices.push_back(texCoords[j]); + interleavedVertices.push_back(texCoords[j+1]); + } +} + + + +/////////////////////////////////////////////////////////////////////////////// +// add single vertex to array +/////////////////////////////////////////////////////////////////////////////// +void Sphere::addVertex(float x, float y, float z) +{ + vertices.push_back(x); + vertices.push_back(y); + vertices.push_back(z); +} + + + +/////////////////////////////////////////////////////////////////////////////// +// add single normal to array +/////////////////////////////////////////////////////////////////////////////// +void Sphere::addNormal(float nx, float ny, float nz) +{ + normals.push_back(nx); + normals.push_back(ny); + normals.push_back(nz); +} + + + +/////////////////////////////////////////////////////////////////////////////// +// add single texture coord to array +/////////////////////////////////////////////////////////////////////////////// +void Sphere::addTexCoord(float s, float t) +{ + texCoords.push_back(s); + texCoords.push_back(t); +} + + + +/////////////////////////////////////////////////////////////////////////////// +// add 3 indices to array +/////////////////////////////////////////////////////////////////////////////// +void Sphere::addIndices(unsigned int i1, unsigned int i2, unsigned int i3) +{ + indices.push_back(i1); + indices.push_back(i2); + indices.push_back(i3); +} + + + +/////////////////////////////////////////////////////////////////////////////// +// return face normal of a triangle v1-v2-v3 +// if a triangle has no surface (normal length = 0), then return a zero vector +/////////////////////////////////////////////////////////////////////////////// +std::vector Sphere::computeFaceNormal(float x1, float y1, float z1, // v1 + float x2, float y2, float z2, // v2 + float x3, float y3, float z3) // v3 +{ + const float EPSILON = 0.000001f; + + std::vector normal(3, 0.0f); // default return value (0,0,0) + float nx, ny, nz; + + // find 2 edge vectors: v1-v2, v1-v3 + float ex1 = x2 - x1; + float ey1 = y2 - y1; + float ez1 = z2 - z1; + float ex2 = x3 - x1; + float ey2 = y3 - y1; + float ez2 = z3 - z1; + + // cross product: e1 x e2 + nx = ey1 * ez2 - ez1 * ey2; + ny = ez1 * ex2 - ex1 * ez2; + nz = ex1 * ey2 - ey1 * ex2; + + // normalize only if the length is > 0 + float length = sqrtf(nx * nx + ny * ny + nz * nz); + if(length > EPSILON) + { + // normalize + float lengthInv = 1.0f / length; + normal[0] = nx * lengthInv; + normal[1] = ny * lengthInv; + normal[2] = nz * lengthInv; + } + + return normal; +} diff --git a/src/geometry/sphere/Sphere.h b/src/geometry/sphere/Sphere.h new file mode 100644 index 0000000..a8b2b2d --- /dev/null +++ b/src/geometry/sphere/Sphere.h @@ -0,0 +1,99 @@ +/////////////////////////////////////////////////////////////////////////////// +// Sphere.h +// ======== +// Sphere for OpenGL with (radius, sectors, stacks) +// The min number of sectors is 3 and The min number of stacks are 2. +// +// AUTHOR: Song Ho Ahn (song.ahn@gmail.com) +// CREATED: 2017-11-01 +// UPDATED: 2020-05-20 +/////////////////////////////////////////////////////////////////////////////// + +#ifndef GEOMETRY_SPHERE_H +#define GEOMETRY_SPHERE_H + +#include + +class Sphere +{ +public: + // ctor/dtor + Sphere(float radius=1.0f, int sectorCount=36, int stackCount=18, bool smooth=true); + ~Sphere() {} + + // getters/setters + float getRadius() const { return radius; } + int getSectorCount() const { return sectorCount; } + int getStackCount() const { return stackCount; } + void set(float radius, int sectorCount, int stackCount, bool smooth=true); + void setRadius(float radius); + void setSectorCount(int sectorCount); + void setStackCount(int stackCount); + void setSmooth(bool smooth); + + // for vertex data + unsigned int getVertexCount() const { return (unsigned int)vertices.size() / 3; } + unsigned int getNormalCount() const { return (unsigned int)normals.size() / 3; } + unsigned int getTexCoordCount() const { return (unsigned int)texCoords.size() / 2; } + unsigned int getIndexCount() const { return (unsigned int)indices.size(); } + unsigned int getLineIndexCount() const { return (unsigned int)lineIndices.size(); } + unsigned int getTriangleCount() const { return getIndexCount() / 3; } + unsigned int getVertexSize() const { return (unsigned int)vertices.size() * sizeof(float); } + unsigned int getNormalSize() const { return (unsigned int)normals.size() * sizeof(float); } + unsigned int getTexCoordSize() const { return (unsigned int)texCoords.size() * sizeof(float); } + unsigned int getIndexSize() const { return (unsigned int)indices.size() * sizeof(unsigned int); } + unsigned int getLineIndexSize() const { return (unsigned int)lineIndices.size() * sizeof(unsigned int); } + const float* getVertices() const { return vertices.data(); } + const float* getNormals() const { return normals.data(); } + const float* getTexCoords() const { return texCoords.data(); } + const unsigned int* getIndices() const { return indices.data(); } + const unsigned int* getLineIndices() const { return lineIndices.data(); } + + // for interleaved vertices: V/N/T + unsigned int getInterleavedVertexCount() const { return getVertexCount(); } // # of vertices + unsigned int getInterleavedVertexSize() const { return (unsigned int)interleavedVertices.size() * sizeof(float); } // # of bytes + int getInterleavedStride() const { return interleavedStride; } // should be 32 bytes + const float* getInterleavedVertices() const { return interleavedVertices.data(); } + + // draw in VertexArray mode + void draw() const; // draw surface + void drawLines(const float lineColor[4]) const; // draw lines only + void drawWithLines(const float lineColor[4]) const; // draw surface and lines + + // debug + void printSelf() const; + +protected: + +private: + // member functions + void buildVerticesSmooth(); + void buildVerticesFlat(); + void buildInterleavedVertices(); + void clearArrays(); + void addVertex(float x, float y, float z); + void addNormal(float x, float y, float z); + void addTexCoord(float s, float t); + void addIndices(unsigned int i1, unsigned int i2, unsigned int i3); + std::vector computeFaceNormal(float x1, float y1, float z1, + float x2, float y2, float z2, + float x3, float y3, float z3); + + // memeber vars + float radius; + int sectorCount; // longitude, # of slices + int stackCount; // latitude, # of stacks + bool smooth; + std::vector vertices; + std::vector normals; + std::vector texCoords; + std::vector indices; + std::vector lineIndices; + + // interleaved + std::vector interleavedVertices; + int interleavedStride; // # of bytes to hop to the next vertex (should be 32 bytes) + +}; + +#endif diff --git a/src/planet/PlanetFace.cpp b/src/planet/PlanetFace.cpp index 84860a9..7cd815f 100644 --- a/src/planet/PlanetFace.cpp +++ b/src/planet/PlanetFace.cpp @@ -18,9 +18,9 @@ const glm::vec3 FACE_NORMALS[6] = { glm::vec3(0.0f, -1.0f, 0.0f) }; -PlanetFaceNode::PlanetFaceNode(Planet* planet, PlanetFace* face, glm::vec3 position, const unsigned int index, const unsigned int level) : - m_planet(planet), m_planetFace(face), m_pos(position), m_index(index), m_level(level), m_generated(false), - m_dirty(true), m_leaf(true), m_parent(0), m_children(), m_neighbors(), neighborDetailDifferences() +PlanetFaceNode::PlanetFaceNode(PlanetFace* face, PlanetFaceNode* parent, glm::vec3 position, const unsigned int index) : + m_planetFace(face), m_pos(position), m_index(index), m_level(parent ? parent->m_level + 1 : 0), m_generated(false), + m_dirty(true), m_leaf(true), m_parent(parent), m_children(), m_neighbors(), neighborDetailDifferences() { glm::vec3 normal = face->getNormal(); @@ -239,13 +239,12 @@ void PlanetFaceNode::updateNeighborDetailDifferences(const unsigned int side) void PlanetFaceNode::tick(Camera* camera, GLfloat dtime) { // TODO: based on planet transform - float camToOrigin = glm::distance(camera->getPosition(), (m_planet->getPosition() + m_center)); - float divisionLevel = (float)pow(2, m_level); - float splitDistance = m_planet->getRadius() / divisionLevel; - if (camToOrigin < splitDistance * 2.0 && m_leaf) { + float camToOrigin = glm::distance(camera->getPosition(), (m_planetFace->getPlanet()->getPosition() + m_center)); + + if (camToOrigin < m_radius * 2.0 && m_leaf) { this->subdivide(); return; - } else if (camToOrigin > splitDistance * 2.0 && !m_leaf) { + } else if (camToOrigin > m_radius * 2.0 && !m_leaf) { this->merge(); return; } @@ -258,6 +257,28 @@ void PlanetFaceNode::tick(Camera* camera, GLfloat dtime) } return; } +} + +void PlanetFaceNode::setIndexBuffer(PlanetBufferIndex buf) { + PIB* indx = m_planetFace->getPlanet()->getBuffers()->getBuffer(buf); + m_ebo = indx->ebo; + m_indices = indx->indices.size(); +} + +void PlanetFaceNode::draw(Camera* camera, Shader* shader) +{ + // TODO: occlusion culling + if (!m_leaf) + { + for (int i = 0; i < 4; i++) + { + m_children[i]->draw(camera, shader); + } + return; + } + + if (!m_generated) + return; if (neighborDetailDifferences[TOP] == 1) { if (neighborDetailDifferences[RIGHT] == 1) { @@ -294,34 +315,12 @@ void PlanetFaceNode::tick(Camera* camera, GLfloat dtime) } else { setIndexBuffer(Base); } -} - -void PlanetFaceNode::setIndexBuffer(PlanetBufferIndex buf) { - PIB* indx = m_planet->getBuffers()->getBuffer(buf); - m_ebo = indx->ebo; - m_indices = indx->indices.size(); -} - -void PlanetFaceNode::draw(Camera* camera, Shader* shader) -{ - // TODO: occlusion culling - if (!m_leaf) - { - for (int i = 0; i < 4; i++) - { - m_children[i]->draw(camera, shader); - } - return; - } - - if (!m_generated) - return; shader->setBuffers(m_vao, m_vbo, m_ebo); shader->use(); camera->shaderViewProjection(*shader); - shader->setUniform("modelMatrix", m_planet->getTransformation()); + shader->setUniform("modelMatrix", m_planetFace->getPlanet()->getTransformation()); glDrawElements(GL_TRIANGLES, m_indices, GL_UNSIGNED_INT, nullptr); } @@ -334,7 +333,7 @@ void PlanetFaceNode::generate() std::vector vertices; float divisionLevel = (float)pow(2.0, m_level); - float radius = m_planet->getRadius(); + float radius = m_planetFace->getPlanet()->getRadius(); for (int i = 0; i < RESOLUTION; i++) { for (int j = 0; j < RESOLUTION; j++) @@ -364,7 +363,7 @@ void PlanetFaceNode::generate() ); // Get noise height and multiply by radius - float height = m_planet->getNoise().fractal(8, point.x, point.y, point.z) * 20.0f; + float height = m_planetFace->getPlanet()->getNoise().fractal(8, point.x, point.y, point.z) * 20.0f; glm::vec3 pos = -(height + radius) * point; // Add vertex @@ -384,13 +383,36 @@ void PlanetFaceNode::generate() glBindBuffer(GL_ARRAY_BUFFER, m_vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * vertices.size(), &(vertices[0]), GL_STATIC_DRAW); + glm::vec3 boundingSphereCenterF = glm::vec3(0.0, 0.0, 0.0); + float boundingSphereRadiusF = 0.0; + int patchVerticesTotal = RESOLUTION * RESOLUTION; + + // Calculate mean position and use as bounding sphere center + for (int i = 0; i < patchVerticesTotal; i++) + { + boundingSphereCenterF += vertices[i].position; + } + boundingSphereCenterF /= (float)patchVerticesTotal; + + // Find the largest distance from the center to a vertex + for (int i = 0; i < patchVerticesTotal; i++) + { + glm::vec3 length = (vertices[i].position - boundingSphereCenterF); + boundingSphereRadiusF = std::max(boundingSphereRadiusF, glm::dot(length, length)); + } + boundingSphereRadiusF = std::sqrt(boundingSphereRadiusF); + + m_center = boundingSphereCenterF; + m_radius = boundingSphereRadiusF; + + std::cout << m_radius << std::endl; + m_generated = true; - setIndexBuffer(PlanetBufferIndex::Base); } bool PlanetFaceNode::subdivide() { - if (m_level == 8 || !m_planetFace->hasSplitsLeft() || !m_leaf) + if (m_level == 10 || !m_planetFace->hasSplitsLeft() || !m_leaf) return false; int lv = m_level + 1; @@ -399,14 +421,10 @@ bool PlanetFaceNode::subdivide() glm::vec3 stepLeft = m_left * (1.0f / (float)pow(2, lv)); glm::vec3 stepForward = m_forward * (1.0f / (float)pow(2, lv)); - m_children[TOP_LEFT] = new PlanetFaceNode(m_planet, m_planetFace, m_pos + stepForward - stepLeft, TOP_LEFT, lv); - m_children[TOP_RIGHT] = new PlanetFaceNode(m_planet, m_planetFace, m_pos - stepForward - stepLeft, TOP_RIGHT, lv); - m_children[BOTTOM_RIGHT] = new PlanetFaceNode(m_planet, m_planetFace, m_pos - stepForward + stepLeft, BOTTOM_RIGHT, lv); - m_children[BOTTOM_LEFT] = new PlanetFaceNode(m_planet, m_planetFace, m_pos + stepForward + stepLeft, BOTTOM_LEFT, lv); - - // Connect parent - for (int i = 0; i < 4; i++) - m_children[i]->m_parent = this; + m_children[TOP_LEFT] = new PlanetFaceNode(m_planetFace, this, m_pos + stepForward - stepLeft, TOP_LEFT); + m_children[TOP_RIGHT] = new PlanetFaceNode(m_planetFace, this, m_pos - stepForward - stepLeft, TOP_RIGHT); + m_children[BOTTOM_RIGHT] = new PlanetFaceNode(m_planetFace, this, m_pos - stepForward + stepLeft, BOTTOM_RIGHT); + m_children[BOTTOM_LEFT] = new PlanetFaceNode(m_planetFace, this, m_pos + stepForward + stepLeft, BOTTOM_LEFT); // Connect the children m_children[TOP_LEFT]->setNeighbor(RIGHT, m_children[TOP_RIGHT]); @@ -457,11 +475,16 @@ bool PlanetFaceNode::isLeaf() return m_leaf; } +glm::vec3 PlanetFaceNode::getAbsolutePosition() +{ + return m_planetFace->getPlanet()->getPosition() + m_pos; +} + PlanetFace::PlanetFace(Planet* planet, const unsigned int face) : m_planet(planet), m_face(face) { m_normal = FACE_NORMALS[m_face]; - m_lod = new PlanetFaceNode(planet, this, m_normal, face, 0); + m_lod = new PlanetFaceNode(this, 0, m_normal, face); } PlanetFace::~PlanetFace() diff --git a/src/planet/PlanetFace.h b/src/planet/PlanetFace.h index d636bf9..f31b06d 100644 --- a/src/planet/PlanetFace.h +++ b/src/planet/PlanetFace.h @@ -49,7 +49,7 @@ class PlanetFace; class PlanetFaceNode { public: - PlanetFaceNode(Planet* planet, PlanetFace* face, glm::vec3 position, const unsigned int index, const unsigned int level); + PlanetFaceNode(PlanetFace* face, PlanetFaceNode* parent, glm::vec3 position, const unsigned int index); ~PlanetFaceNode(); void tick(Camera* camera, GLfloat dtime); @@ -57,10 +57,9 @@ class PlanetFaceNode bool isLeaf(); - inline Planet* getPlanet() const { return m_planet; } inline PlanetFace* getPlanetFace() const { return m_planetFace; } - inline glm::vec3 getAbsolutePosition() const { return m_planet->getPosition() + m_pos; } + glm::vec3 getAbsolutePosition(); inline PlanetFaceNode* getNeighborAt(Direction dir) const { return m_neighbors[dir]; } inline PlanetFaceNode* getChildAt(Quadrant quad) const { return m_children[quad]; } @@ -82,7 +81,6 @@ class PlanetFaceNode void updateNeighborDetailDifferences(const unsigned int side); unsigned int mirrorQuadrant(const unsigned int side, const unsigned int quadrant) const; - Planet* m_planet; PlanetFace* m_planetFace; PlanetFaceNode* m_parent; @@ -104,6 +102,7 @@ class PlanetFaceNode glm::vec3 m_center; glm::vec3 m_left; glm::vec3 m_forward; + float m_radius; }; class PlanetFace