random
This commit is contained in:
parent
9a9ebf1a9b
commit
44c54b03bf
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
|
||||
"files.associations": {
|
||||
"*.def": "cpp"
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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 <windows.h> // include windows.h to avoid thousands of compile errors even though this class is not depending on Windows
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <OpenGL/gl.h>
|
||||
#else
|
||||
#include <GL/gl.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <cmath>
|
||||
#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<float>().swap(vertices);
|
||||
std::vector<float>().swap(normals);
|
||||
std::vector<float>().swap(texCoords);
|
||||
std::vector<unsigned int>().swap(indices);
|
||||
std::vector<unsigned int>().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<Vertex> 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<float> 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<float>().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<float> 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<float> 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;
|
||||
}
|
|
@ -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 <vector>
|
||||
|
||||
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<float> 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<float> vertices;
|
||||
std::vector<float> normals;
|
||||
std::vector<float> texCoords;
|
||||
std::vector<unsigned int> indices;
|
||||
std::vector<unsigned int> lineIndices;
|
||||
|
||||
// interleaved
|
||||
std::vector<float> interleavedVertices;
|
||||
int interleavedStride; // # of bytes to hop to the next vertex (should be 32 bytes)
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -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<Vertex> 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()
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue