new topology code

This commit is contained in:
Evert Prants 2023-02-23 21:33:50 +02:00
parent 44c54b03bf
commit c1e3e2fd3d
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
8 changed files with 262 additions and 221 deletions

View File

@ -205,7 +205,7 @@ void Application::run()
// TEST CODE // TEST CODE
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
glCullFace(GL_BACK); glCullFace(GL_FRONT);
if (!m_pauseLod) if (!m_pauseLod)
pl->tick(m_camera, deltaTime); pl->tick(m_camera, deltaTime);

View File

@ -204,22 +204,23 @@ void Camera::processMouseMovement(GLfloat xoffset, GLfloat yoffset, GLboolean co
void Camera::processMouseScroll(GLfloat yoffset) void Camera::processMouseScroll(GLfloat yoffset)
{ {
if (m_zoom >= 44.0f && m_zoom <= 45.0f) // if (m_zoom >= 44.0f && m_zoom <= 45.0f)
{ // {
m_zoom -= yoffset; // m_zoom -= yoffset;
} // }
if (m_zoom <= 44.0f) // if (m_zoom <= 44.0f)
{ // {
m_zoom = 44.0f; // m_zoom = 44.0f;
} // }
if (m_zoom >= 45.0f) // if (m_zoom >= 45.0f)
{ // {
m_zoom = 45.0f; // m_zoom = 45.0f;
} // }
updateProjection(); // updateProjection();
m_movementSpeed += yoffset * 50.0f;
} }
void Camera::updateProjection(void) void Camera::updateProjection(void)

View File

@ -2,9 +2,22 @@
#include "planet/PlanetFace.h" #include "planet/PlanetFace.h"
Planet::Planet(glm::vec3 position, float radius, PlanetNoiseParams &noiseParams) : Planet::Planet(glm::vec3 position, float radius, PlanetNoiseParams &noiseParams) :
m_position(position), m_radius(radius), m_noise(noiseParams.frequency, noiseParams.amplitude, noiseParams.lacunarity, noiseParams.persistence), m_position(position), m_radius(radius), m_noise(noiseParams.frequency, noiseParams.amplitude, noiseParams.lacunarity, noiseParams.persistence)
m_ibuffers(new PlanetIndexBuffer(15))
{ {
for (unsigned int a = 0; a <= 4; a++)
{
for (unsigned int b = 0; b <= 4; b++)
{
for (unsigned int c = 0; c <= 4; c++)
{
for (unsigned int d = 0; d <= 4; d++)
{
m_ibuffers[a][b][c][d] = new PlanetIndexBuffer(16, a, b, c, d);
}
}
}
}
for (int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)
{ {
m_faces[i] = new PlanetFace(this, i); m_faces[i] = new PlanetFace(this, i);
@ -18,7 +31,21 @@ Planet::~Planet()
{ {
delete m_faces[i]; delete m_faces[i];
} }
delete m_ibuffers;
for (unsigned int a = 0; a <= 4; a++)
{
for (unsigned int b = 0; b <= 4; b++)
{
for (unsigned int c = 0; c <= 4; c++)
{
for (unsigned int d = 0; d <= 4; d++)
{
delete m_ibuffers[a][b][c][d];
m_ibuffers[a][b][c][d] = 0;
}
}
}
}
} }
void Planet::draw(Camera* camera, Shader* shader) void Planet::draw(Camera* camera, Shader* shader)
@ -60,3 +87,7 @@ glm::mat4 Planet::getTransformation()
newMat = glm::translate(newMat, m_position); newMat = glm::translate(newMat, m_position);
return newMat; return newMat;
} }
PlanetIndexBuffer* Planet::getIndexBuffer(const unsigned int detailTop, const unsigned int detailRight, const unsigned int detailBottom, const unsigned int detailLeft) {
return m_ibuffers[detailTop][detailRight][detailBottom][detailLeft];
}

View File

@ -33,14 +33,14 @@ class Planet
void draw(Camera* camera, Shader* shader); void draw(Camera* camera, Shader* shader);
inline SimplexNoise& getNoise() { return m_noise; } inline SimplexNoise& getNoise() { return m_noise; }
inline PlanetIndexBuffer* getBuffers() { return m_ibuffers; }
inline PlanetFace* getFace(const unsigned int face) { return m_faces[face]; } inline PlanetFace* getFace(const unsigned int face) { return m_faces[face]; }
PlanetIndexBuffer* getIndexBuffer(const unsigned int detailTop, const unsigned int detailRight, const unsigned int detailBottom, const unsigned int detailLeft);
glm::mat4 getTransformation(); glm::mat4 getTransformation();
private: private:
void connectFaces(); void connectFaces();
PlanetIndexBuffer* m_ibuffers; PlanetIndexBuffer* m_ibuffers[5][5][5][5];
SimplexNoise m_noise; SimplexNoise m_noise;
glm::vec3 m_position; glm::vec3 m_position;
float m_radius; float m_radius;

View File

@ -236,6 +236,12 @@ void PlanetFaceNode::updateNeighborDetailDifferences(const unsigned int side)
} }
} }
// Returns the neighbor detail (depth) difference [0,MAX_DETAIL_DIFFERENCE]
unsigned int PlanetFaceNode::getNeighborDetailDifference(const unsigned int side) const
{
return neighborDetailDifferences[side];
}
void PlanetFaceNode::tick(Camera* camera, GLfloat dtime) void PlanetFaceNode::tick(Camera* camera, GLfloat dtime)
{ {
// TODO: based on planet transform // TODO: based on planet transform
@ -259,12 +265,6 @@ void PlanetFaceNode::tick(Camera* camera, GLfloat dtime)
} }
} }
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) void PlanetFaceNode::draw(Camera* camera, Shader* shader)
{ {
// TODO: occlusion culling // TODO: occlusion culling
@ -280,49 +280,20 @@ void PlanetFaceNode::draw(Camera* camera, Shader* shader)
if (!m_generated) if (!m_generated)
return; return;
if (neighborDetailDifferences[TOP] == 1) { PlanetIndexBuffer* buffers = m_planetFace->getPlanet()->getIndexBuffer(
if (neighborDetailDifferences[RIGHT] == 1) { getNeighborDetailDifference(TOP),
setIndexBuffer(FixTR); getNeighborDetailDifference(RIGHT),
} else if (neighborDetailDifferences[LEFT] == 1) { getNeighborDetailDifference(BOTTOM),
setIndexBuffer(FixTL); getNeighborDetailDifference(LEFT)
} else { );
setIndexBuffer(FixT);
}
} else if (neighborDetailDifferences[BOTTOM] == 1) {
if (neighborDetailDifferences[RIGHT] == 1) {
setIndexBuffer(FixBR);
} else if (neighborDetailDifferences[LEFT] == 1) {
setIndexBuffer(FixBL);
} else {
setIndexBuffer(FixB);
}
} else if (neighborDetailDifferences[RIGHT] == 1) {
if (neighborDetailDifferences[BOTTOM] == 1) {
setIndexBuffer(FixBR);
} else if (neighborDetailDifferences[TOP] == 1) {
setIndexBuffer(FixTR);
} else {
setIndexBuffer(FixR);
}
} else if (neighborDetailDifferences[LEFT] == 1) {
if (neighborDetailDifferences[BOTTOM] == 1) {
setIndexBuffer(FixBL);
} else if (neighborDetailDifferences[TOP] == 1) {
setIndexBuffer(FixTL);
} else {
setIndexBuffer(FixL);
}
} else {
setIndexBuffer(Base);
}
shader->setBuffers(m_vao, m_vbo, m_ebo); shader->setBuffers(m_vao, m_vbo, buffers->getIbo());
shader->use(); shader->use();
camera->shaderViewProjection(*shader); camera->shaderViewProjection(*shader);
shader->setUniform("modelMatrix", m_planetFace->getPlanet()->getTransformation()); shader->setUniform("modelMatrix", m_planetFace->getPlanet()->getTransformation());
glDrawElements(GL_TRIANGLES, m_indices, GL_UNSIGNED_INT, nullptr); glDrawElements(GL_TRIANGLES, buffers->getVertexCount(), GL_UNSIGNED_SHORT, nullptr);
} }
void PlanetFaceNode::generate() void PlanetFaceNode::generate()
@ -405,8 +376,6 @@ void PlanetFaceNode::generate()
m_center = boundingSphereCenterF; m_center = boundingSphereCenterF;
m_radius = boundingSphereRadiusF; m_radius = boundingSphereRadiusF;
std::cout << m_radius << std::endl;
m_generated = true; m_generated = true;
} }
@ -484,7 +453,7 @@ PlanetFace::PlanetFace(Planet* planet, const unsigned int face) :
m_planet(planet), m_face(face) m_planet(planet), m_face(face)
{ {
m_normal = FACE_NORMALS[m_face]; m_normal = FACE_NORMALS[m_face];
m_lod = new PlanetFaceNode(this, 0, m_normal, face); m_lod = new PlanetFaceNode(this, 0, m_normal, 0);
} }
PlanetFace::~PlanetFace() PlanetFace::~PlanetFace()
@ -505,8 +474,9 @@ void PlanetFace::tick(Camera* camera, GLfloat dtime)
void PlanetFace::connect(const unsigned int side, PlanetFace* face) void PlanetFace::connect(const unsigned int side, PlanetFace* face)
{ {
if (m_lod && face->getLODRoot()) if (m_lod && face->getLODRoot()) {
m_lod->setNeighbor(side, face->getLODRoot()); m_lod->setNeighbor(side, face->getLODRoot());
}
} }
bool PlanetFace::hasSplitsLeft() bool PlanetFace::hasSplitsLeft()

View File

@ -6,7 +6,7 @@
#include "Shader.h" #include "Shader.h"
#include "Camera.h" #include "Camera.h"
#define RESOLUTION 15 #define RESOLUTION 17
enum Face enum Face
{ {
@ -24,12 +24,6 @@ enum Quadrant
BOTTOM_RIGHT, BOTTOM_LEFT BOTTOM_RIGHT, BOTTOM_LEFT
}; };
enum Direction
{
TOP, RIGHT,
BOTTOM, LEFT,
};
const unsigned int MAX_SPLITS_PER_UPDATE = 2; const unsigned int MAX_SPLITS_PER_UPDATE = 2;
#define MIRROR(s) (((s) + 2) % 4) #define MIRROR(s) (((s) + 2) % 4)
@ -74,8 +68,6 @@ class PlanetFaceNode
bool merge(); bool merge();
void dispose(); void dispose();
void setIndexBuffer(PlanetBufferIndex buf);
void findNeighbor(const unsigned int side); void findNeighbor(const unsigned int side);
void getNeighbor(const unsigned int side); void getNeighbor(const unsigned int side);
void updateNeighborDetailDifferences(const unsigned int side); void updateNeighborDetailDifferences(const unsigned int side);

View File

@ -1,145 +1,179 @@
#include "PlanetIndexBuffer.h" #include "PlanetIndexBuffer.h"
PlanetIndexBuffer::PlanetIndexBuffer(unsigned int resolution) : m_resolution(resolution) { PlanetIndexBuffer::PlanetIndexBuffer(
createBuffer(PlanetBufferIndex::Base); unsigned int resolution,
createBuffer(PlanetBufferIndex::FixT, false, false, true, false); const unsigned int detailTop,
createBuffer(PlanetBufferIndex::FixR, true, false, false, false); const unsigned int detailRight,
createBuffer(PlanetBufferIndex::FixB, false, true, false, false); const unsigned int detailBottom,
createBuffer(PlanetBufferIndex::FixL, false, false, false, true); const unsigned int detailLeft
createBuffer(PlanetBufferIndex::FixTL, false, false, true, true); ) : m_resolution(resolution) {
createBuffer(PlanetBufferIndex::FixTR, true, false, true, false); TriangleFanList triangleFans;
createBuffer(PlanetBufferIndex::FixBR, true, true, false, false);
createBuffer(PlanetBufferIndex::FixBL, false, true, false, true); // Build the patch body (without edges)
for (unsigned int x = 2; x < m_resolution - 1; x += 2)
{
for (unsigned int y = 2; y < m_resolution - 1; y += 2)
{
addTriangleFan(triangleFans);
addTriangleFanVertex(triangleFans, x, y);
addTriangleFanVertex(triangleFans, x + 1, y + 1);
addTriangleFanVertex(triangleFans, x, y + 1);
addTriangleFanVertex(triangleFans, x - 1, y + 1);
addTriangleFanVertex(triangleFans, x - 1, y);
addTriangleFanVertex(triangleFans, x - 1, y - 1);
addTriangleFanVertex(triangleFans, x, y - 1);
addTriangleFanVertex(triangleFans, x + 1, y - 1);
addTriangleFanVertex(triangleFans, x + 1, y);
addTriangleFanVertex(triangleFans, x + 1, y + 1);
}
}
// Build all four edges
buildEdge(triangleFans, TOP, detailLeft);
buildEdge(triangleFans, RIGHT, detailBottom);
buildEdge(triangleFans, BOTTOM, detailRight);
buildEdge(triangleFans, LEFT, detailTop);
// Count the number of triangles and reserve three vertices per triangle
int triangleCount = 0;
for (unsigned int i = 0; i < triangleFans.size(); i++)
if (triangleFans[i].size() > 2)
triangleCount += triangleFans[i].size() - 2;
m_vertexCount = 3 * triangleCount;
// Create an index array
GLushort *indexData = new GLushort[m_vertexCount];
int n = 0;
for (unsigned int i = 0; i < triangleFans.size(); i++)
{
for (unsigned int j = 2; j < triangleFans[i].size(); j++)
{
indexData[n++] = triangleFans[i][0];
indexData[n++] = triangleFans[i][j-1];
indexData[n++] = triangleFans[i][j];
}
}
// Generate the index buffer object (IBO)
glGenBuffers(1, &m_ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * m_vertexCount, indexData, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// Delete unnecessary data
triangleFans.clear();
delete[] indexData;
} }
PlanetIndexBuffer::~PlanetIndexBuffer() { PlanetIndexBuffer::~PlanetIndexBuffer() {
for (int i = 0; i < 9; i++) { glDeleteBuffers(1, &m_ibo);
if (m_buffers[i] == nullptr) continue;
glDeleteBuffers(1, &m_buffers[i]->ebo);
m_buffers[i]->indices.clear();
delete m_buffers[i];
}
} }
PIB* PlanetIndexBuffer::getBuffer(PlanetBufferIndex idx) { void PlanetIndexBuffer::rotateIndices(unsigned int &x, unsigned int &y, const unsigned int rotation)
return m_buffers[idx]; {
// Change the indices to match the given rotation
switch (rotation)
{
case TOP:
default:
return;
case RIGHT:
std::swap(x, y);
y = m_resolution - y;
return;
case BOTTOM:
x = m_resolution - x;
y = m_resolution - y;
return;
case LEFT:
std::swap(x, y);
x = m_resolution - x;
return;
}
} }
void PlanetIndexBuffer::createBuffer(PlanetBufferIndex idx, bool fanTop, bool fanRight, bool fanLeft, bool fanBottom) { // Creates and adds a triangle fan
PIB* buffer = new PIB(); void PlanetIndexBuffer::addTriangleFan(TriangleFanList &triangleFans)
// Create indices for mesh {
for (unsigned int gz = 0; gz < m_resolution - 1; gz++) triangleFans.push_back(TriangleFan());
{ }
bool slantLeft = gz % 2 == 0;
for (unsigned int gx = 0; gx < m_resolution - 1; gx++) // adds a vertex index to the most recently added triangle fan
{ void PlanetIndexBuffer::addTriangleFanVertex(TriangleFanList &triangleFans, unsigned int x, unsigned int y, const unsigned int rotation)
unsigned int topLeft = (gz * m_resolution) + gx; {
unsigned int topRight = topLeft + 1; // Rotate and use the x and y indices
unsigned int bottomLeft = ((gz + 1) * m_resolution) + gx; PlanetIndexBuffer::rotateIndices(x, y, rotation);
unsigned int bottomRight = bottomLeft + 1; triangleFans.back().push_back(index1D(x,y));
}
bool uTri1 = true;
bool uTri2 = true; void PlanetIndexBuffer::buildEdge(TriangleFanList &triangleFans, const unsigned int side, const unsigned int detail)
unsigned int tri1[3]; {
unsigned int tri2[3]; // If detail difference is 0 (default case) or too high
if (detail == 0 || detail > 4)
if (slantLeft) {
{ for (unsigned int x = 0; x < m_resolution - 1; x += 2)
tri1[0] = topLeft; {
tri1[1] = bottomLeft; addTriangleFan(triangleFans);
tri1[2] = bottomRight; addTriangleFanVertex(triangleFans, x + 1, m_resolution - 1, side);
tri2[0] = topLeft; for (int d = -1; d <= 1; d++)
tri2[1] = bottomRight; addTriangleFanVertex(triangleFans, x + 1 - d, m_resolution, side);
tri2[2] = topRight;
} if (x > 0)
else {
{ addTriangleFan(triangleFans);
tri1[0] = topLeft; addTriangleFanVertex(triangleFans, x, m_resolution, side);
tri1[1] = bottomLeft; for (int d = -1; d <= 1; d++)
tri1[2] = topRight; addTriangleFanVertex(triangleFans, x + d, m_resolution - 1, side);
tri2[0] = bottomLeft; }
tri2[1] = bottomRight; }
tri2[2] = topRight; return;
} }
if (fanTop && gz == 0) // Calculate step sizes; step = 2^detail
{ const int step = 1 << detail;
if (gx % 2 == 0) const int halfStep = step / 2;
{
tri2[0] = topLeft; unsigned int x = 0;
tri2[1] = bottomRight; for (x = 0; x < m_resolution; x += step)
tri2[2] = topRight + 1; {
} addTriangleFan(triangleFans);
else addTriangleFanVertex(triangleFans, x, m_resolution, side);
{ addTriangleFanVertex(triangleFans, x + halfStep, m_resolution - 1, side);
uTri1 = false; addTriangleFanVertex(triangleFans, x + step, m_resolution, side);
}
} if (x > 0)
{
if (fanRight && gx == m_resolution - 2) addTriangleFan(triangleFans);
{ addTriangleFanVertex(triangleFans, x, m_resolution, side);
if (gz % 2 == 0) for (int d = -halfStep; d <= halfStep; d++)
{ addTriangleFanVertex(triangleFans, x + d, m_resolution - 1, side);
tri2[0] = topRight; }
tri2[1] = bottomLeft; }
tri2[2] = bottomRight + m_resolution;
} if (step > 2)
else {
{ addTriangleFan(triangleFans);
uTri2 = false; addTriangleFanVertex(triangleFans, 0, m_resolution, side);
} for (int d = 1; d <= halfStep; d++)
} addTriangleFanVertex(triangleFans, d, m_resolution - 1, side);
if (fanBottom && gz == m_resolution - 2) addTriangleFan(triangleFans);
{ addTriangleFanVertex(triangleFans, m_resolution, m_resolution, side);
if (gx % 2 == 0) for (int d = -halfStep; d <= -1; d++)
{ addTriangleFanVertex(triangleFans, m_resolution + d, m_resolution - 1, side);
tri2[0] = bottomLeft; }
tri2[1] = bottomRight + 1; }
tri2[2] = topRight;
} GLsizei PlanetIndexBuffer::getVertexCount() const
else {
{ return m_vertexCount;
uTri1 = false; }
}
} GLuint PlanetIndexBuffer::getIbo() const
{
if (fanLeft && gx == 0) return m_ibo;
{ }
if (gz % 2 == 0)
{ unsigned int PlanetIndexBuffer::index1D(const unsigned int x, const unsigned int y) {
tri1[0] = topLeft; return ((x) + (y) * (m_resolution + 1));
tri1[1] = bottomLeft + m_resolution;
tri1[2] = bottomRight;
}
else
{
uTri1 = false;
}
}
if (uTri1)
{
buffer->indices.push_back(tri1[0]);
buffer->indices.push_back(tri1[1]);
buffer->indices.push_back(tri1[2]);
}
if (uTri2)
{
buffer->indices.push_back(tri2[0]);
buffer->indices.push_back(tri2[1]);
buffer->indices.push_back(tri2[2]);
}
slantLeft = !slantLeft;
}
}
glGenBuffers(1, &(buffer->ebo));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer->ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * buffer->indices.size(), &(buffer->indices[0]), GL_STATIC_DRAW);
m_buffers[idx] = buffer;
} }

View File

@ -3,24 +3,37 @@
#include "util/Common.h" #include "util/Common.h"
struct PIB { enum Direction
GLuint ebo; {
std::vector<uint> indices; TOP, RIGHT,
BOTTOM, LEFT,
}; };
enum PlanetBufferIndex {
Base, FixT, FixR, FixB, FixL, FixTL, FixTR, FixBR, FixBL typedef std::vector<GLushort> TriangleFan;
}; typedef std::vector<TriangleFan> TriangleFanList;
class PlanetIndexBuffer { class PlanetIndexBuffer {
public: public:
PlanetIndexBuffer(unsigned int resolution); PlanetIndexBuffer(unsigned int resolution, const unsigned int detailTop, const unsigned int detailRight, const unsigned int detailBottom, const unsigned int detailLeft);
~PlanetIndexBuffer(); ~PlanetIndexBuffer();
PIB* getBuffer(PlanetBufferIndex idx); // Instance methods
GLsizei getVertexCount() const;
GLuint getIbo() const;
private: private:
void createBuffer(PlanetBufferIndex idx, bool fanTop = false, bool fanRight = false, bool fanLeft = false, bool fanBottom = false); void rotateIndices(unsigned int &x, unsigned int &y, const unsigned int rotation);
PIB* m_buffers[9]; void addTriangleFan(TriangleFanList &triangleFans);
void addTriangleFanVertex(TriangleFanList &triangleFans, unsigned int x, unsigned int y, const unsigned int rotation = 0);
void buildEdge(TriangleFanList &triangleFans, const unsigned int side, const unsigned int detail = 0);
// Instance variables
GLsizei m_vertexCount;
GLuint m_ibo;
// TODO: move to utility
unsigned int index1D(const unsigned int x, const unsigned int y);
unsigned int m_resolution; unsigned int m_resolution;
}; };