|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "mesh.h" |
|
|
#include "platform.h" |
|
|
|
|
|
#include <map> |
|
|
#include <fstream> |
|
|
#include <iostream> |
|
|
|
|
|
using namespace std; |
|
|
|
|
|
void Mesh::DuplicateVertex(uint32_t i) |
|
|
{ |
|
|
assert(m_positions.size() > i); |
|
|
m_positions.push_back(m_positions[i]); |
|
|
|
|
|
if (m_normals.size() > i) |
|
|
m_normals.push_back(m_normals[i]); |
|
|
|
|
|
if (m_colours.size() > i) |
|
|
m_colours.push_back(m_colours[i]); |
|
|
|
|
|
if (m_texcoords[0].size() > i) |
|
|
m_texcoords[0].push_back(m_texcoords[0][i]); |
|
|
|
|
|
if (m_texcoords[1].size() > i) |
|
|
m_texcoords[1].push_back(m_texcoords[1][i]); |
|
|
|
|
|
} |
|
|
|
|
|
void Mesh::Normalize(float s) |
|
|
{ |
|
|
Vec3 lower, upper; |
|
|
GetBounds(lower, upper); |
|
|
Vec3 edges = upper-lower; |
|
|
|
|
|
Transform(TranslationMatrix(Point3(-lower))); |
|
|
|
|
|
float maxEdge = max(edges.x, max(edges.y, edges.z)); |
|
|
Transform(ScaleMatrix(s/maxEdge)); |
|
|
} |
|
|
|
|
|
void Mesh::CalculateNormals() |
|
|
{ |
|
|
m_normals.resize(0); |
|
|
m_normals.resize(m_positions.size()); |
|
|
|
|
|
int numTris = int(GetNumFaces()); |
|
|
|
|
|
for (int i=0; i < numTris; ++i) |
|
|
{ |
|
|
int a = m_indices[i*3+0]; |
|
|
int b = m_indices[i*3+1]; |
|
|
int c = m_indices[i*3+2]; |
|
|
|
|
|
Vec3 n = Cross(m_positions[b]-m_positions[a], m_positions[c]-m_positions[a]); |
|
|
|
|
|
m_normals[a] += n; |
|
|
m_normals[b] += n; |
|
|
m_normals[c] += n; |
|
|
} |
|
|
|
|
|
int numVertices = int(GetNumVertices()); |
|
|
|
|
|
for (int i=0; i < numVertices; ++i) |
|
|
m_normals[i] = ::Normalize(m_normals[i]); |
|
|
} |
|
|
|
|
|
namespace |
|
|
{ |
|
|
|
|
|
enum PlyFormat |
|
|
{ |
|
|
eAscii, |
|
|
eBinaryBigEndian |
|
|
}; |
|
|
|
|
|
template <typename T> |
|
|
T PlyRead(ifstream& s, PlyFormat format) |
|
|
{ |
|
|
T data = eAscii; |
|
|
|
|
|
switch (format) |
|
|
{ |
|
|
case eAscii: |
|
|
{ |
|
|
s >> data; |
|
|
break; |
|
|
} |
|
|
case eBinaryBigEndian: |
|
|
{ |
|
|
char c[sizeof(T)]; |
|
|
s.read(c, sizeof(T)); |
|
|
reverse(c, c+sizeof(T)); |
|
|
data = *(T*)c; |
|
|
break; |
|
|
} |
|
|
default: |
|
|
assert(0); |
|
|
} |
|
|
|
|
|
return data; |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
Mesh* ImportMesh(const char* path) |
|
|
{ |
|
|
std::string ext = GetExtension(path); |
|
|
|
|
|
Mesh* mesh = NULL; |
|
|
|
|
|
if (ext == "ply") |
|
|
mesh = ImportMeshFromPly(path); |
|
|
else if (ext == "obj") |
|
|
mesh = ImportMeshFromObj(path); |
|
|
|
|
|
|
|
|
return mesh; |
|
|
} |
|
|
|
|
|
Mesh* ImportMeshFromBin(const char* path) |
|
|
{ |
|
|
double start = GetSeconds(); |
|
|
|
|
|
FILE* f = fopen(path, "rb"); |
|
|
|
|
|
if (f) |
|
|
{ |
|
|
int numVertices; |
|
|
int numIndices; |
|
|
|
|
|
size_t len; |
|
|
len = fread(&numVertices, sizeof(numVertices), 1, f); |
|
|
len = fread(&numIndices, sizeof(numIndices), 1, f); |
|
|
|
|
|
Mesh* m = new Mesh(); |
|
|
m->m_positions.resize(numVertices); |
|
|
m->m_normals.resize(numVertices); |
|
|
m->m_indices.resize(numIndices); |
|
|
|
|
|
len = fread(&m->m_positions[0], sizeof(Vec3)*numVertices, 1, f); |
|
|
len = fread(&m->m_normals[0], sizeof(Vec3)*numVertices, 1, f); |
|
|
len = fread(&m->m_indices[0], sizeof(int)*numIndices, 1, f); |
|
|
|
|
|
(void)len; |
|
|
|
|
|
fclose(f); |
|
|
|
|
|
double end = GetSeconds(); |
|
|
|
|
|
printf("Imported mesh %s in %f ms\n", path, (end-start)*1000.0f); |
|
|
|
|
|
return m; |
|
|
} |
|
|
|
|
|
return NULL; |
|
|
} |
|
|
|
|
|
void ExportMeshToBin(const char* path, const Mesh* m) |
|
|
{ |
|
|
FILE* f = fopen(path, "wb"); |
|
|
|
|
|
if (f) |
|
|
{ |
|
|
int numVertices = int(m->m_positions.size()); |
|
|
int numIndices = int(m->m_indices.size()); |
|
|
|
|
|
fwrite(&numVertices, sizeof(numVertices), 1, f); |
|
|
fwrite(&numIndices, sizeof(numIndices), 1, f); |
|
|
|
|
|
|
|
|
fwrite(&m->m_positions[0], sizeof(Vec3)*numVertices, 1, f); |
|
|
fwrite(&m->m_normals[0], sizeof(Vec3)*numVertices, 1, f); |
|
|
fwrite(&m->m_indices[0], sizeof(int)*numIndices, 1, f); |
|
|
|
|
|
fclose(f); |
|
|
} |
|
|
} |
|
|
|
|
|
Mesh* ImportMeshFromPly(const char* path) |
|
|
{ |
|
|
ifstream file(path, ios_base::in | ios_base::binary); |
|
|
|
|
|
if (!file) |
|
|
return NULL; |
|
|
|
|
|
|
|
|
const uint32_t kMaxLineLength = 1024; |
|
|
char buffer[kMaxLineLength]; |
|
|
|
|
|
|
|
|
|
|
|
file >> buffer; |
|
|
if (strcmp(buffer, "ply") != 0) |
|
|
return NULL; |
|
|
|
|
|
PlyFormat format = eAscii; |
|
|
|
|
|
uint32_t numFaces = 0; |
|
|
uint32_t numVertices = 0; |
|
|
|
|
|
const uint32_t kMaxProperties = 16; |
|
|
uint32_t numProperties = 0; |
|
|
float properties[kMaxProperties]; |
|
|
|
|
|
bool vertexElement = false; |
|
|
|
|
|
while (file) |
|
|
{ |
|
|
file >> buffer; |
|
|
|
|
|
if (strcmp(buffer, "element") == 0) |
|
|
{ |
|
|
file >> buffer; |
|
|
|
|
|
if (strcmp(buffer, "face") == 0) |
|
|
{ |
|
|
vertexElement = false; |
|
|
file >> numFaces; |
|
|
} |
|
|
|
|
|
else if (strcmp(buffer, "vertex") == 0) |
|
|
{ |
|
|
vertexElement = true; |
|
|
file >> numVertices; |
|
|
} |
|
|
} |
|
|
else if (strcmp(buffer, "format") == 0) |
|
|
{ |
|
|
file >> buffer; |
|
|
if (strcmp(buffer, "ascii") == 0) |
|
|
{ |
|
|
format = eAscii; |
|
|
} |
|
|
else if (strcmp(buffer, "binary_big_endian") == 0) |
|
|
{ |
|
|
format = eBinaryBigEndian; |
|
|
} |
|
|
else |
|
|
{ |
|
|
printf("Ply: unknown format\n"); |
|
|
return NULL; |
|
|
} |
|
|
} |
|
|
else if (strcmp(buffer, "property") == 0) |
|
|
{ |
|
|
if (vertexElement) |
|
|
++numProperties; |
|
|
} |
|
|
else if (strcmp(buffer, "end_header") == 0) |
|
|
{ |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
char nl; |
|
|
file.read(&nl, 1); |
|
|
|
|
|
|
|
|
#if ENABLE_VERBOSE_OUTPUT |
|
|
printf ("Loaded mesh: %s numFaces: %d numVertices: %d format: %d numProperties: %d\n", path, numFaces, numVertices, format, numProperties); |
|
|
#endif |
|
|
|
|
|
Mesh* mesh = new Mesh; |
|
|
|
|
|
mesh->m_positions.resize(numVertices); |
|
|
mesh->m_normals.resize(numVertices); |
|
|
mesh->m_colours.resize(numVertices, Colour(1.0f, 1.0f, 1.0f, 1.0f)); |
|
|
|
|
|
mesh->m_indices.reserve(numFaces*3); |
|
|
|
|
|
|
|
|
for (uint32_t v=0; v < numVertices; ++v) |
|
|
{ |
|
|
for (uint32_t i=0; i < numProperties; ++i) |
|
|
{ |
|
|
properties[i] = PlyRead<float>(file, format); |
|
|
} |
|
|
|
|
|
mesh->m_positions[v] = Point3(properties[0], properties[1], properties[2]); |
|
|
mesh->m_normals[v] = Vector3(0.0f, 0.0f, 0.0f); |
|
|
} |
|
|
|
|
|
|
|
|
for (uint32_t f=0; f < numFaces; ++f) |
|
|
{ |
|
|
uint32_t numIndices = (format == eAscii)?PlyRead<uint32_t>(file, format):PlyRead<uint8_t>(file, format); |
|
|
uint32_t indices[4]; |
|
|
|
|
|
for (uint32_t i=0; i < numIndices; ++i) |
|
|
{ |
|
|
indices[i] = PlyRead<uint32_t>(file, format); |
|
|
} |
|
|
|
|
|
switch (numIndices) |
|
|
{ |
|
|
case 3: |
|
|
mesh->m_indices.push_back(indices[0]); |
|
|
mesh->m_indices.push_back(indices[1]); |
|
|
mesh->m_indices.push_back(indices[2]); |
|
|
break; |
|
|
case 4: |
|
|
mesh->m_indices.push_back(indices[0]); |
|
|
mesh->m_indices.push_back(indices[1]); |
|
|
mesh->m_indices.push_back(indices[2]); |
|
|
|
|
|
mesh->m_indices.push_back(indices[2]); |
|
|
mesh->m_indices.push_back(indices[3]); |
|
|
mesh->m_indices.push_back(indices[0]); |
|
|
break; |
|
|
|
|
|
default: |
|
|
assert(!"invalid number of indices, only support tris and quads"); |
|
|
break; |
|
|
}; |
|
|
|
|
|
|
|
|
Point3& v0 = mesh->m_positions[indices[0]]; |
|
|
Point3& v1 = mesh->m_positions[indices[1]]; |
|
|
Point3& v2 = mesh->m_positions[indices[2]]; |
|
|
|
|
|
Vector3 n = SafeNormalize(Cross(v1-v0, v2-v0), Vector3(0.0f, 1.0f, 0.0f)); |
|
|
|
|
|
for (uint32_t i=0; i < numIndices; ++i) |
|
|
{ |
|
|
mesh->m_normals[indices[i]] += n; |
|
|
} |
|
|
} |
|
|
|
|
|
for (uint32_t i=0; i < numVertices; ++i) |
|
|
{ |
|
|
mesh->m_normals[i] = SafeNormalize(mesh->m_normals[i], Vector3(0.0f, 1.0f, 0.0f)); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return mesh; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
struct VertexKey |
|
|
{ |
|
|
VertexKey() : v(0), vt(0), vn(0) {} |
|
|
|
|
|
uint32_t v, vt, vn; |
|
|
|
|
|
bool operator == (const VertexKey& rhs) const |
|
|
{ |
|
|
return v == rhs.v && vt == rhs.vt && vn == rhs.vn; |
|
|
} |
|
|
|
|
|
bool operator < (const VertexKey& rhs) const |
|
|
{ |
|
|
if (v != rhs.v) |
|
|
return v < rhs.v; |
|
|
else if (vt != rhs.vt) |
|
|
return vt < rhs.vt; |
|
|
else |
|
|
return vn < rhs.vn; |
|
|
} |
|
|
}; |
|
|
|
|
|
Mesh* ImportMeshFromObj(const char* path) |
|
|
{ |
|
|
ifstream file(path); |
|
|
|
|
|
if (!file) |
|
|
return NULL; |
|
|
|
|
|
Mesh* m = new Mesh(); |
|
|
|
|
|
vector<Point3> positions; |
|
|
vector<Vector3> normals; |
|
|
vector<Vector2> texcoords; |
|
|
vector<Vector3> colors; |
|
|
vector<uint32_t>& indices = m->m_indices; |
|
|
|
|
|
|
|
|
typedef map<VertexKey, uint32_t> VertexMap; |
|
|
VertexMap vertexLookup; |
|
|
|
|
|
|
|
|
const uint32_t kMaxLineLength = 1024; |
|
|
char buffer[kMaxLineLength]; |
|
|
|
|
|
|
|
|
|
|
|
while (file) |
|
|
{ |
|
|
file >> buffer; |
|
|
|
|
|
if (strcmp(buffer, "vn") == 0) |
|
|
{ |
|
|
|
|
|
float x, y, z; |
|
|
file >> x >> y >> z; |
|
|
|
|
|
normals.push_back(Vector3(x, y, z)); |
|
|
} |
|
|
else if (strcmp(buffer, "vt") == 0) |
|
|
{ |
|
|
|
|
|
float u, v; |
|
|
file >> u >> v; |
|
|
|
|
|
texcoords.push_back(Vector2(u, v)); |
|
|
} |
|
|
else if (buffer[0] == 'v') |
|
|
{ |
|
|
|
|
|
float x, y, z; |
|
|
file >> x >> y >> z; |
|
|
|
|
|
positions.push_back(Point3(x, y, z)); |
|
|
} |
|
|
else if (buffer[0] == 's' || buffer[0] == 'g' || buffer[0] == 'o') |
|
|
{ |
|
|
|
|
|
char linebuf[256]; |
|
|
file.getline(linebuf, 256); |
|
|
} |
|
|
else if (strcmp(buffer, "mtllib") == 0) |
|
|
{ |
|
|
|
|
|
std::string MaterialFile; |
|
|
file >> MaterialFile; |
|
|
} |
|
|
else if (strcmp(buffer, "usemtl") == 0) |
|
|
{ |
|
|
|
|
|
std::string materialName; |
|
|
file >> materialName; |
|
|
} |
|
|
else if (buffer[0] == 'f') |
|
|
{ |
|
|
|
|
|
uint32_t faceIndices[4]; |
|
|
uint32_t faceIndexCount = 0; |
|
|
|
|
|
for (int i=0; i < 4; ++i) |
|
|
{ |
|
|
VertexKey key; |
|
|
|
|
|
file >> key.v; |
|
|
|
|
|
if (!file.eof()) |
|
|
{ |
|
|
|
|
|
if (file.fail()) |
|
|
{ |
|
|
file.clear(); |
|
|
break; |
|
|
} |
|
|
|
|
|
if (file.peek() == '/') |
|
|
{ |
|
|
file.ignore(); |
|
|
|
|
|
if (file.peek() != '/') |
|
|
{ |
|
|
file >> key.vt; |
|
|
} |
|
|
|
|
|
if (file.peek() == '/') |
|
|
{ |
|
|
file.ignore(); |
|
|
file >> key.vn; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
VertexMap::iterator iter = vertexLookup.find(key); |
|
|
|
|
|
if (iter != vertexLookup.end()) |
|
|
{ |
|
|
faceIndices[faceIndexCount++] = iter->second; |
|
|
} |
|
|
else |
|
|
{ |
|
|
|
|
|
uint32_t newIndex = uint32_t(m->m_positions.size()); |
|
|
faceIndices[faceIndexCount++] = newIndex; |
|
|
|
|
|
vertexLookup.insert(make_pair(key, newIndex)); |
|
|
|
|
|
|
|
|
assert(key.v > 0); |
|
|
|
|
|
m->m_positions.push_back(positions[key.v-1]); |
|
|
|
|
|
|
|
|
m->m_colours.push_back(Colour(1.0f, 1.0f, 1.0f)); |
|
|
|
|
|
|
|
|
if (key.vn) |
|
|
{ |
|
|
m->m_normals.push_back(normals[key.vn-1]); |
|
|
} |
|
|
|
|
|
|
|
|
if (key.vt) |
|
|
{ |
|
|
m->m_texcoords[0].push_back(texcoords[key.vt-1]); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
if (faceIndexCount == 3) |
|
|
{ |
|
|
|
|
|
indices.insert(indices.end(), faceIndices, faceIndices+3); |
|
|
} |
|
|
else if (faceIndexCount == 4) |
|
|
{ |
|
|
|
|
|
indices.insert(indices.end(), faceIndices, faceIndices+3); |
|
|
|
|
|
indices.push_back(faceIndices[2]); |
|
|
indices.push_back(faceIndices[3]); |
|
|
indices.push_back(faceIndices[0]); |
|
|
} |
|
|
else |
|
|
{ |
|
|
cout << "Face with more than 4 vertices are not supported" << endl; |
|
|
} |
|
|
|
|
|
} |
|
|
else if (buffer[0] == '#') |
|
|
{ |
|
|
|
|
|
char linebuf[256]; |
|
|
file.getline(linebuf, 256); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
m->m_normals.resize(m->m_positions.size()); |
|
|
|
|
|
const uint32_t numFaces = uint32_t(indices.size())/3; |
|
|
for (uint32_t i=0; i < numFaces; ++i) |
|
|
{ |
|
|
uint32_t a = indices[i*3+0]; |
|
|
uint32_t b = indices[i*3+1]; |
|
|
uint32_t c = indices[i*3+2]; |
|
|
|
|
|
Point3& v0 = m->m_positions[a]; |
|
|
Point3& v1 = m->m_positions[b]; |
|
|
Point3& v2 = m->m_positions[c]; |
|
|
|
|
|
Vector3 n = SafeNormalize(Cross(v1-v0, v2-v0), Vector3(0.0f, 1.0f, 0.0f)); |
|
|
|
|
|
m->m_normals[a] += n; |
|
|
m->m_normals[b] += n; |
|
|
m->m_normals[c] += n; |
|
|
} |
|
|
|
|
|
for (uint32_t i=0; i < m->m_normals.size(); ++i) |
|
|
{ |
|
|
m->m_normals[i] = SafeNormalize(m->m_normals[i], Vector3(0.0f, 1.0f, 0.0f)); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return m; |
|
|
} |
|
|
|
|
|
void ExportToObj(const char* path, const Mesh& m) |
|
|
{ |
|
|
ofstream file(path); |
|
|
|
|
|
if (!file) |
|
|
return; |
|
|
|
|
|
file << "# positions" << endl; |
|
|
|
|
|
for (uint32_t i=0; i < m.m_positions.size(); ++i) |
|
|
{ |
|
|
Point3 v = m.m_positions[i]; |
|
|
file << "v " << v.x << " " << v.y << " " << v.z << endl; |
|
|
} |
|
|
|
|
|
file << "# texcoords" << endl; |
|
|
|
|
|
for (uint32_t i=0; i < m.m_texcoords[0].size(); ++i) |
|
|
{ |
|
|
Vec2 t = m.m_texcoords[0][i]; |
|
|
file << "vt " << t.x << " " << t.y << endl; |
|
|
} |
|
|
|
|
|
file << "# normals" << endl; |
|
|
|
|
|
for (uint32_t i=0; i < m.m_normals.size(); ++i) |
|
|
{ |
|
|
Vec3 n = m.m_normals[0][i]; |
|
|
file << "vn " << n.x << " " << n.y << " " << n.z << endl; |
|
|
} |
|
|
|
|
|
file << "# faces" << endl; |
|
|
|
|
|
for (uint32_t i=0; i < m.m_indices.size()/3; ++i) |
|
|
{ |
|
|
uint32_t j = i+1; |
|
|
|
|
|
|
|
|
file << "f " << j << "/" << j << "/" << j << endl; |
|
|
} |
|
|
} |
|
|
|
|
|
void Mesh::AddMesh(const Mesh& m) |
|
|
{ |
|
|
uint32_t offset = uint32_t(m_positions.size()); |
|
|
|
|
|
|
|
|
m_positions.insert(m_positions.end(), m.m_positions.begin(), m.m_positions.end()); |
|
|
m_normals.insert(m_normals.end(), m.m_normals.begin(), m.m_normals.end()); |
|
|
m_colours.insert(m_colours.end(), m.m_colours.begin(), m.m_colours.end()); |
|
|
|
|
|
|
|
|
for (uint32_t i=0; i < m.m_indices.size(); ++i) |
|
|
{ |
|
|
m_indices.push_back(m.m_indices[i]+offset); |
|
|
} |
|
|
} |
|
|
|
|
|
void Mesh::Transform(const Matrix44& m) |
|
|
{ |
|
|
for (uint32_t i=0; i < m_positions.size(); ++i) |
|
|
{ |
|
|
m_positions[i] = m*m_positions[i]; |
|
|
m_normals[i] = m*m_normals[i]; |
|
|
} |
|
|
} |
|
|
|
|
|
void Mesh::GetBounds(Vector3& outMinExtents, Vector3& outMaxExtents) const |
|
|
{ |
|
|
Point3 minExtents(FLT_MAX); |
|
|
Point3 maxExtents(-FLT_MAX); |
|
|
|
|
|
|
|
|
for (uint32_t i=0; i < m_positions.size(); ++i) |
|
|
{ |
|
|
const Point3& a = m_positions[i]; |
|
|
|
|
|
minExtents = Min(a, minExtents); |
|
|
maxExtents = Max(a, maxExtents); |
|
|
} |
|
|
|
|
|
outMinExtents = Vector3(minExtents); |
|
|
outMaxExtents = Vector3(maxExtents); |
|
|
} |
|
|
|
|
|
Mesh* CreateTriMesh(float size, float y) |
|
|
{ |
|
|
uint32_t indices[] = { 0, 1, 2 }; |
|
|
Point3 positions[3]; |
|
|
Vector3 normals[3]; |
|
|
|
|
|
positions[0] = Point3(-size, y, size); |
|
|
positions[1] = Point3(size, y, size); |
|
|
positions[2] = Point3(size, y, -size); |
|
|
|
|
|
normals[0] = Vector3(0.0f, 1.0f, 0.0f); |
|
|
normals[1] = Vector3(0.0f, 1.0f, 0.0f); |
|
|
normals[2] = Vector3(0.0f, 1.0f, 0.0f); |
|
|
|
|
|
Mesh* m = new Mesh(); |
|
|
m->m_indices.insert(m->m_indices.begin(), indices, indices + 3); |
|
|
m->m_positions.insert(m->m_positions.begin(), positions, positions + 3); |
|
|
m->m_normals.insert(m->m_normals.begin(), normals, normals + 3); |
|
|
|
|
|
return m; |
|
|
} |
|
|
|
|
|
Mesh* CreateCubeMesh() |
|
|
{ |
|
|
const Point3 vertices[24] = |
|
|
{ |
|
|
Point3(0.5, 0.5, 0.5), |
|
|
Point3(-0.5, 0.5, 0.5), |
|
|
Point3(0.5, -0.5, 0.5), |
|
|
Point3(-0.5, -0.5, 0.5), |
|
|
Point3(0.5, 0.5, -0.5), |
|
|
Point3(-0.5, 0.5, -0.5), |
|
|
Point3(0.5, -0.5, -0.5), |
|
|
Point3(-0.5, -0.5, -0.5), |
|
|
Point3(0.5, 0.5, 0.5), |
|
|
Point3(0.5, -0.5, 0.5), |
|
|
Point3(0.5, 0.5, 0.5), |
|
|
Point3(0.5, 0.5, -0.5), |
|
|
Point3(-0.5, 0.5, 0.5), |
|
|
Point3(-0.5, 0.5, -0.5), |
|
|
Point3(0.5, -0.5, -0.5), |
|
|
Point3(0.5, 0.5, -0.5), |
|
|
Point3(-0.5, -0.5, -0.5), |
|
|
Point3(0.5, -0.5, -0.5), |
|
|
Point3(-0.5, -0.5, 0.5), |
|
|
Point3(0.5, -0.5, 0.5), |
|
|
Point3(-0.5, -0.5, -0.5), |
|
|
Point3(-0.5, -0.5, 0.5), |
|
|
Point3(-0.5, 0.5, -0.5), |
|
|
Point3(-0.5, 0.5, 0.5) |
|
|
}; |
|
|
|
|
|
const Vec3 normals[24] = |
|
|
{ |
|
|
Vec3(0.0f, 0.0f, 1.0f), |
|
|
Vec3(0.0f, 0.0f, 1.0f), |
|
|
Vec3(0.0f, 0.0f, 1.0f), |
|
|
Vec3(0.0f, 0.0f, 1.0f), |
|
|
Vec3(1.0f, 0.0f, 0.0f), |
|
|
Vec3(0.0f, 1.0f, 0.0f), |
|
|
Vec3(1.0f, 0.0f, 0.0f), |
|
|
Vec3(0.0f, 0.0f, -1.0f), |
|
|
Vec3(1.0f, 0.0f, 0.0f), |
|
|
Vec3(1.0f, 0.0f, 0.0f), |
|
|
Vec3(0.0f, 1.0f, 0.0f), |
|
|
Vec3(0.0f, 1.0f, 0.0f), |
|
|
Vec3(0.0f, 1.0f, 0.0f), |
|
|
Vec3(0.0f, 0.0f, -1.0f), |
|
|
Vec3(0.0f, 0.0f, -1.0f), |
|
|
Vec3(-0.0f, -0.0f, -1.0f), |
|
|
Vec3(0.0f, -1.0f, 0.0f), |
|
|
Vec3(0.0f, -1.0f, 0.0f), |
|
|
Vec3(0.0f, -1.0f, 0.0f), |
|
|
Vec3(-0.0f, -1.0f, -0.0f), |
|
|
Vec3(-1.0f, 0.0f, 0.0f), |
|
|
Vec3(-1.0f, 0.0f, 0.0f), |
|
|
Vec3(-1.0f, 0.0f, 0.0f), |
|
|
Vec3(-1.0f, -0.0f, -0.0f) |
|
|
}; |
|
|
|
|
|
const int indices[36] = |
|
|
{ |
|
|
0, 1, 2, |
|
|
3, 2, 1, |
|
|
8, 9, 4, |
|
|
6, 4, 9, |
|
|
10, 11, 12, |
|
|
5, 12, 11, |
|
|
7, 13, 14, |
|
|
15, 14, 13, |
|
|
16, 17, 18, |
|
|
19, 18, 17, |
|
|
20, 21, 22, |
|
|
23, 22, 21 |
|
|
}; |
|
|
|
|
|
Mesh* m = new Mesh(); |
|
|
m->m_positions.assign(vertices, vertices+24); |
|
|
m->m_normals.assign(normals, normals+24); |
|
|
m->m_indices.assign(indices, indices+36); |
|
|
|
|
|
return m; |
|
|
|
|
|
} |
|
|
|
|
|
Mesh* CreateQuadMesh(float size, float y) |
|
|
{ |
|
|
uint32_t indices[] = { 0, 1, 2, 2, 3, 0 }; |
|
|
Point3 positions[4]; |
|
|
Vector3 normals[4]; |
|
|
|
|
|
positions[0] = Point3(-size, y, size); |
|
|
positions[1] = Point3(size, y, size); |
|
|
positions[2] = Point3(size, y, -size); |
|
|
positions[3] = Point3(-size, y, -size); |
|
|
|
|
|
normals[0] = Vector3(0.0f, 1.0f, 0.0f); |
|
|
normals[1] = Vector3(0.0f, 1.0f, 0.0f); |
|
|
normals[2] = Vector3(0.0f, 1.0f, 0.0f); |
|
|
normals[3] = Vector3(0.0f, 1.0f, 0.0f); |
|
|
|
|
|
Mesh* m = new Mesh(); |
|
|
m->m_indices.insert(m->m_indices.begin(), indices, indices+6); |
|
|
m->m_positions.insert(m->m_positions.begin(), positions, positions+4); |
|
|
m->m_normals.insert(m->m_normals.begin(), normals, normals+4); |
|
|
|
|
|
return m; |
|
|
} |
|
|
|
|
|
Mesh* CreateDiscMesh(float radius, uint32_t segments) |
|
|
{ |
|
|
const uint32_t numVerts = 1 + segments; |
|
|
|
|
|
Mesh* m = new Mesh(); |
|
|
m->m_positions.resize(numVerts); |
|
|
m->m_normals.resize(numVerts, Vec3(0.0f, 1.0f, 0.0f)); |
|
|
|
|
|
m->m_positions[0] = Point3(0.0f); |
|
|
m->m_positions[1] = Point3(0.0f, 0.0f, radius); |
|
|
|
|
|
for (uint32_t i=1; i <= segments; ++i) |
|
|
{ |
|
|
uint32_t nextVert = (i+1)%numVerts; |
|
|
|
|
|
if (nextVert == 0) |
|
|
nextVert = 1; |
|
|
|
|
|
m->m_positions[nextVert] = Point3(radius*Sin((float(i)/segments)*k2Pi), 0.0f, radius*Cos((float(i)/segments)*k2Pi)); |
|
|
|
|
|
m->m_indices.push_back(0); |
|
|
m->m_indices.push_back(i); |
|
|
m->m_indices.push_back(nextVert); |
|
|
} |
|
|
|
|
|
return m; |
|
|
} |
|
|
|
|
|
Mesh* CreateTetrahedron(float ground, float height) |
|
|
{ |
|
|
Mesh* m = new Mesh(); |
|
|
|
|
|
const float dimValue = 1.0f / sqrtf(2.0f); |
|
|
const Point3 vertices[4] = |
|
|
{ |
|
|
Point3(-1.0f, ground, -dimValue), |
|
|
Point3(1.0f, ground, -dimValue), |
|
|
Point3(0.0f, ground + height, dimValue), |
|
|
Point3(0.0f, ground, dimValue) |
|
|
}; |
|
|
|
|
|
const int indices[12] = |
|
|
{ |
|
|
|
|
|
0, 2, 1, |
|
|
2, 3, 1, |
|
|
2, 0, 3, |
|
|
3, 0, 1 |
|
|
}; |
|
|
|
|
|
m->m_positions.assign(vertices, vertices+4); |
|
|
m->m_indices.assign(indices, indices+12); |
|
|
|
|
|
m->CalculateNormals(); |
|
|
|
|
|
return m; |
|
|
} |
|
|
|
|
|
|
|
|
Mesh* CreateSphere(int slices, int segments, float radius) |
|
|
{ |
|
|
float dTheta = kPi / slices; |
|
|
float dPhi = k2Pi / segments; |
|
|
|
|
|
int vertsPerRow = segments + 1; |
|
|
|
|
|
Mesh* mesh = new Mesh(); |
|
|
|
|
|
for (int i = 0; i <= slices; ++i) |
|
|
{ |
|
|
float theta = dTheta*i; |
|
|
|
|
|
for (int j = 0; j <= segments; ++j) |
|
|
{ |
|
|
float phi = dPhi*j; |
|
|
|
|
|
float x = sinf(theta)*cosf(phi); |
|
|
float y = cosf(theta); |
|
|
float z = sinf(theta)*sinf(phi); |
|
|
|
|
|
mesh->m_positions.push_back(Point3(x, y, z)*radius); |
|
|
mesh->m_normals.push_back(Vec3(x, y, z)); |
|
|
|
|
|
if (i > 0 && j > 0) |
|
|
{ |
|
|
int a = i*vertsPerRow + j; |
|
|
int b = (i - 1)*vertsPerRow + j; |
|
|
int c = (i - 1)*vertsPerRow + j - 1; |
|
|
int d = i*vertsPerRow + j - 1; |
|
|
|
|
|
|
|
|
mesh->m_indices.push_back(b); |
|
|
mesh->m_indices.push_back(a); |
|
|
mesh->m_indices.push_back(d); |
|
|
|
|
|
mesh->m_indices.push_back(b); |
|
|
mesh->m_indices.push_back(d); |
|
|
mesh->m_indices.push_back(c); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
return mesh; |
|
|
} |
|
|
|
|
|
Mesh* CreateCapsule(int slices, int segments, float radius, float halfHeight) |
|
|
{ |
|
|
float dTheta = kPi / (slices * 2); |
|
|
float dPhi = k2Pi / segments; |
|
|
|
|
|
int vertsPerRow = segments + 1; |
|
|
|
|
|
Mesh* mesh = new Mesh(); |
|
|
|
|
|
float theta = 0.0f; |
|
|
|
|
|
for (int i = 0; i <= 2 * slices + 1; ++i) |
|
|
{ |
|
|
for (int j = 0; j <= segments; ++j) |
|
|
{ |
|
|
float phi = dPhi*j; |
|
|
|
|
|
float x = sinf(theta)*cosf(phi); |
|
|
float y = cosf(theta); |
|
|
float z = sinf(theta)*sinf(phi); |
|
|
|
|
|
|
|
|
float yoffset = (i < slices) ? halfHeight : -halfHeight; |
|
|
|
|
|
mesh->m_positions.push_back(Point3(x, y, z)*radius + Vec3(0.0f, yoffset, 0.0f)); |
|
|
mesh->m_normals.push_back(Vec3(x, y, z)); |
|
|
|
|
|
if (i > 0 && j > 0) |
|
|
{ |
|
|
int a = i*vertsPerRow + j; |
|
|
int b = (i - 1)*vertsPerRow + j; |
|
|
int c = (i - 1)*vertsPerRow + j - 1; |
|
|
int d = i*vertsPerRow + j - 1; |
|
|
|
|
|
|
|
|
mesh->m_indices.push_back(b); |
|
|
mesh->m_indices.push_back(a); |
|
|
mesh->m_indices.push_back(d); |
|
|
|
|
|
mesh->m_indices.push_back(b); |
|
|
mesh->m_indices.push_back(d); |
|
|
mesh->m_indices.push_back(c); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (i != slices) |
|
|
theta += dTheta; |
|
|
} |
|
|
|
|
|
return mesh; |
|
|
} |
|
|
|