first commit
This commit is contained in:
343
src/Asset.cpp
Normal file
343
src/Asset.cpp
Normal file
@@ -0,0 +1,343 @@
|
||||
#include "Asset.hpp"
|
||||
#include <cmath>
|
||||
#include <array>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
namespace asset {
|
||||
|
||||
Mesh make_unit_quad(float size) {
|
||||
Mesh m;
|
||||
const float h = size * 0.5f;
|
||||
m.positions = {-size, -size, 0.0f, size, -size, 0.0f,
|
||||
size, size, 0.0f, -size, size, 0.0f};
|
||||
m.uvs = {0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};
|
||||
m.indices = {0, 1, 2, 2, 3, 0};
|
||||
return m;
|
||||
}
|
||||
|
||||
Mesh make_unit_cube(float size) {
|
||||
Mesh m;
|
||||
const float h = size * 0.5f;
|
||||
|
||||
// 6 faces × 4 verts (CCW when viewed from outside)
|
||||
const float P[] = {
|
||||
// +X (right)
|
||||
h,-h,-h, h, h,-h, h, h, h, h,-h, h,
|
||||
// -X (left)
|
||||
-h,-h, h, -h, h, h, -h, h,-h, -h,-h,-h,
|
||||
// +Y (top) *** fixed winding ***
|
||||
-h, h,-h, -h, h, h, h, h, h, h, h,-h,
|
||||
// -Y (bottom) *** fixed winding ***
|
||||
-h,-h,-h, h,-h,-h, h,-h, h, -h,-h, h,
|
||||
// +Z (front)
|
||||
-h,-h, h, h,-h, h, h, h, h, -h, h, h,
|
||||
// -Z (back)
|
||||
h,-h,-h, -h,-h,-h, -h, h,-h, h, h,-h
|
||||
};
|
||||
|
||||
const float N[] = {
|
||||
// +X
|
||||
1,0,0, 1,0,0, 1,0,0, 1,0,0,
|
||||
// -X
|
||||
-1,0,0, -1,0,0, -1,0,0, -1,0,0,
|
||||
// +Y
|
||||
0,1,0, 0,1,0, 0,1,0, 0,1,0,
|
||||
// -Y
|
||||
0,-1,0, 0,-1,0, 0,-1,0, 0,-1,0,
|
||||
// +Z
|
||||
0,0,1, 0,0,1, 0,0,1, 0,0,1,
|
||||
// -Z
|
||||
0,0,-1, 0,0,-1, 0,0,-1, 0,0,-1
|
||||
};
|
||||
|
||||
// 0..1 quad per face; orientation is fine with the corrected positions
|
||||
const float UV[] = {
|
||||
0,0, 1,0, 1,1, 0,1,
|
||||
0,0, 1,0, 1,1, 0,1,
|
||||
0,0, 1,0, 1,1, 0,1,
|
||||
0,0, 1,0, 1,1, 0,1,
|
||||
0,0, 1,0, 1,1, 0,1,
|
||||
0,0, 1,0, 1,1, 0,1
|
||||
};
|
||||
|
||||
// 2 triangles per face
|
||||
const uint32_t I[] = {
|
||||
0, 1, 2, 0, 2, 3, // +X
|
||||
4, 5, 6, 4, 6, 7, // -X
|
||||
8, 9, 10, 8, 10, 11, // +Y (fixed)
|
||||
12, 13, 14, 12, 14, 15, // -Y (fixed)
|
||||
16, 17, 18, 16, 18, 19, // +Z
|
||||
20, 21, 22, 20, 22, 23 // -Z
|
||||
};
|
||||
|
||||
m.positions.assign(std::begin(P), std::end(P));
|
||||
m.normals.assign (std::begin(N), std::end(N));
|
||||
m.uvs.assign (std::begin(UV), std::end(UV));
|
||||
m.indices.assign (std::begin(I), std::end(I));
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
Mesh make_unit_ico(float size){
|
||||
Mesh m;
|
||||
|
||||
// Golden ratio
|
||||
const float phi = (1.0f + std::sqrt(5.0f)) * 0.5f;
|
||||
|
||||
// Canonical 12 vertices (right-handed)
|
||||
const std::array<glm::vec3, 12> V = {
|
||||
glm::vec3(-1, phi, 0),
|
||||
glm::vec3( 1, phi, 0),
|
||||
glm::vec3(-1, -phi, 0),
|
||||
glm::vec3( 1, -phi, 0),
|
||||
|
||||
glm::vec3( 0, -1, phi),
|
||||
glm::vec3( 0, 1, phi),
|
||||
glm::vec3( 0, -1, -phi),
|
||||
glm::vec3( 0, 1, -phi),
|
||||
|
||||
glm::vec3( phi, 0, -1),
|
||||
glm::vec3( phi, 0, 1),
|
||||
glm::vec3(-phi, 0, -1),
|
||||
glm::vec3(-phi, 0, 1)
|
||||
};
|
||||
|
||||
// Normalize to unit sphere and scale to radius = size * 0.5
|
||||
const float r = size * 0.5f;
|
||||
m.positions.reserve(12 * 3);
|
||||
m.normals .reserve(12 * 3);
|
||||
for (auto p : V) {
|
||||
glm::vec3 n = glm::normalize(p);
|
||||
glm::vec3 s = r * n;
|
||||
m.positions.insert(m.positions.end(), {s.x, s.y, s.z});
|
||||
m.normals .insert(m.normals .end(), {n.x, n.y, n.z});
|
||||
}
|
||||
|
||||
// 20 faces (CCW)
|
||||
static const uint32_t I[] = {
|
||||
0, 11, 5,
|
||||
0, 5, 1,
|
||||
0, 1, 7,
|
||||
0, 7, 10,
|
||||
0, 10, 11,
|
||||
|
||||
1, 5, 9,
|
||||
5, 11, 4,
|
||||
11, 10, 2,
|
||||
10, 7, 6,
|
||||
7, 1, 8,
|
||||
|
||||
3, 9, 4,
|
||||
3, 4, 2,
|
||||
3, 2, 6,
|
||||
3, 6, 8,
|
||||
3, 8, 9,
|
||||
|
||||
4, 9, 5,
|
||||
2, 4, 11,
|
||||
6, 2, 10,
|
||||
8, 6, 7,
|
||||
9, 8, 1
|
||||
};
|
||||
m.indices.assign(std::begin(I), std::end(I));
|
||||
|
||||
// UVs omitted (non-trivial on icosahedra)
|
||||
m.uvs.clear();
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
Mesh make_unit_ico_flat(float size) {
|
||||
Mesh m;
|
||||
m.positions.clear();
|
||||
m.normals.clear();
|
||||
m.uvs.clear();
|
||||
m.indices.clear(); // draw non-indexed (or fill 0..N-1 if you prefer)
|
||||
|
||||
// Golden ratio
|
||||
const float phi = (1.0f + std::sqrt(5.0f)) * 0.5f;
|
||||
const float r = size * 0.5f; // radius
|
||||
|
||||
// 12 canonical vertices (right-handed)
|
||||
const std::array<glm::vec3, 12> V = {
|
||||
glm::vec3(-1, phi, 0),
|
||||
glm::vec3( 1, phi, 0),
|
||||
glm::vec3(-1, -phi, 0),
|
||||
glm::vec3( 1, -phi, 0),
|
||||
|
||||
glm::vec3( 0, -1, phi),
|
||||
glm::vec3( 0, 1, phi),
|
||||
glm::vec3( 0, -1, -phi),
|
||||
glm::vec3( 0, 1, -phi),
|
||||
|
||||
glm::vec3( phi, 0, -1),
|
||||
glm::vec3( phi, 0, 1),
|
||||
glm::vec3(-phi, 0, -1),
|
||||
glm::vec3(-phi, 0, 1)
|
||||
};
|
||||
|
||||
// 20 faces (CCW)
|
||||
static const uint32_t F[20][3] = {
|
||||
{ 0,11, 5}, { 0, 5, 1}, { 0, 1, 7}, { 0, 7,10}, { 0,10,11},
|
||||
{ 1, 5, 9}, { 5,11, 4}, {11,10, 2}, {10, 7, 6}, { 7, 1, 8},
|
||||
{ 3, 9, 4}, { 3, 4, 2}, { 3, 2, 6}, { 3, 6, 8}, { 3, 8, 9},
|
||||
{ 4, 9, 5}, { 2, 4,11}, { 6, 2,10}, { 8, 6, 7}, { 9, 8, 1}
|
||||
};
|
||||
|
||||
m.positions.reserve(20 * 3 * 3);
|
||||
m.normals.reserve (20 * 3 * 3);
|
||||
|
||||
for (const auto& tri : F) {
|
||||
// Sphere positions (normalized then scaled to radius r)
|
||||
glm::vec3 p0 = glm::normalize(V[tri[0]]) * r;
|
||||
glm::vec3 p1 = glm::normalize(V[tri[1]]) * r;
|
||||
glm::vec3 p2 = glm::normalize(V[tri[2]]) * r;
|
||||
|
||||
// Flat face normal (one per triangle)
|
||||
glm::vec3 n = glm::normalize(glm::cross(p1 - p0, p2 - p0));
|
||||
|
||||
// Duplicate vertices per face so normals don't interpolate across edges
|
||||
const glm::vec3 P[3] = { p0, p1, p2 };
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
m.positions.push_back(P[i].x);
|
||||
m.positions.push_back(P[i].y);
|
||||
m.positions.push_back(P[i].z);
|
||||
|
||||
m.normals.push_back(n.x);
|
||||
m.normals.push_back(n.y);
|
||||
m.normals.push_back(n.z);
|
||||
}
|
||||
}
|
||||
|
||||
// If you prefer indexed draw, uncomment to fill 0..N-1
|
||||
// m.indices.resize(m.positions.size() / 3);
|
||||
// std::iota(m.indices.begin(), m.indices.end(), 0u);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
Mesh make_grid(int N, float extent) {
|
||||
Mesh m;
|
||||
const int V = (N+1);
|
||||
m.positions.reserve(V*V*3);
|
||||
m.uvs .reserve(V*V*2);
|
||||
const float half = extent*0.5f;
|
||||
for (int y=0; y<V; ++y){
|
||||
for (int x=0; x<V; ++x){
|
||||
float fx = float(x)/N, fy = float(y)/N;
|
||||
float X = -half + fx*extent;
|
||||
float Y = -half + fy*extent;
|
||||
m.positions.insert(m.positions.end(), {X,Y,0.0f}); // Z = 0 (we’ll displace in VS)
|
||||
m.uvs.insert(m.uvs.end(), {fx, fy}); // 0..1 for height/albedo sampling
|
||||
}
|
||||
}
|
||||
m.indices.reserve(N*N*6);
|
||||
for (int y=0; y<N; ++y){
|
||||
for (int x=0; x<N; ++x){
|
||||
uint32_t i0 = y *V + x;
|
||||
uint32_t i1 = y *V + (x+1);
|
||||
uint32_t i2 = (y+1)*V + x;
|
||||
uint32_t i3 = (y+1)*V + (x+1);
|
||||
m.indices.insert(m.indices.end(), { i0,i2,i1, i1,i2,i3 }); // CCW
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
static inline void add3(std::vector<float>& v, size_t i, const glm::vec3& a) {
|
||||
v[i+0] += a.x; v[i+1] += a.y; v[i+2] += a.z;
|
||||
}
|
||||
|
||||
Mesh make_terrain(int W, int H, float dx, float dz,
|
||||
HeightFn heightFn,
|
||||
bool genNormals,
|
||||
bool genUVs,
|
||||
float x0, float z0)
|
||||
{
|
||||
assert(W > 0 && H > 0 && dx > 0.0f && dz > 0.0f);
|
||||
|
||||
Mesh m;
|
||||
const int VX = (W + 1);
|
||||
const int VZ = (H + 1);
|
||||
const int N = VX * VZ;
|
||||
|
||||
m.positions.resize(3 * N);
|
||||
if (genNormals) m.normals.assign(3 * N, 0.0f);
|
||||
if (genUVs) m.uvs.resize(2 * N);
|
||||
|
||||
// --- Vertices (positions + uvs) ---
|
||||
for (int j = 0; j < VZ; ++j) {
|
||||
for (int i = 0; i < VX; ++i) {
|
||||
const int v = j * VX + i;
|
||||
const size_t p3 = 3 * v;
|
||||
const size_t t2 = 2 * v;
|
||||
|
||||
// Grid spans the XY plane; height goes into Z
|
||||
const float X = x0 + i * dx;
|
||||
const float Y = z0 + j * dz; // reuse dz as grid step in Y
|
||||
const float Z = heightFn ? heightFn(X, Y) : 0.0f;
|
||||
|
||||
m.positions[p3 + 0] = X; // x
|
||||
m.positions[p3 + 1] = Y; // y (planar)
|
||||
m.positions[p3 + 2] = Z; // z (height)
|
||||
|
||||
if (genUVs) {
|
||||
m.uvs[t2 + 0] = (VX > 1) ? (float)i / (float)(VX - 1) : 0.0f;
|
||||
m.uvs[t2 + 1] = (VZ > 1) ? (float)j / (float)(VZ - 1) : 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Indices (two triangles per quad), CCW in XY so normals point +Z ---
|
||||
m.indices.reserve(W * H * 6);
|
||||
for (int j = 0; j < H; ++j) {
|
||||
for (int i = 0; i < W; ++i) {
|
||||
const uint32_t i0 = (uint32_t)( j * VX + i );
|
||||
const uint32_t i1 = (uint32_t)( j * VX + i + 1);
|
||||
const uint32_t i2 = (uint32_t)((j+1) * VX + i );
|
||||
const uint32_t i3 = (uint32_t)((j+1) * VX + i + 1);
|
||||
|
||||
m.indices.push_back(i0); m.indices.push_back(i1); m.indices.push_back(i2);
|
||||
m.indices.push_back(i1); m.indices.push_back(i3); m.indices.push_back(i2);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Smoothed per-vertex normals (area-weighted) ---
|
||||
if (genNormals) {
|
||||
// Accumulate face normals
|
||||
for (size_t k = 0; k < m.indices.size(); k += 3) {
|
||||
const uint32_t ia = m.indices[k+0];
|
||||
const uint32_t ib = m.indices[k+1];
|
||||
const uint32_t ic = m.indices[k+2];
|
||||
|
||||
const glm::vec3 A{ m.positions[3*ia+0], m.positions[3*ia+1], m.positions[3*ia+2] };
|
||||
const glm::vec3 B{ m.positions[3*ib+0], m.positions[3*ib+1], m.positions[3*ib+2] };
|
||||
const glm::vec3 C{ m.positions[3*ic+0], m.positions[3*ic+1], m.positions[3*ic+2] };
|
||||
|
||||
const glm::vec3 N = glm::cross(B - A, C - A); // CCW -> +Z on flat areas
|
||||
|
||||
add3(m.normals, 3*ia, N);
|
||||
add3(m.normals, 3*ib, N);
|
||||
add3(m.normals, 3*ic, N);
|
||||
}
|
||||
|
||||
// Normalize
|
||||
for (int v = 0; v < N; ++v) {
|
||||
glm::vec3 n{ m.normals[3*v+0], m.normals[3*v+1], m.normals[3*v+2] };
|
||||
const float len = glm::length(n);
|
||||
if (len > 1e-20f) {
|
||||
n /= len;
|
||||
} else {
|
||||
n = glm::vec3(0, 0, 1); // fallback for degenerate spots
|
||||
}
|
||||
m.normals[3*v+0] = n.x;
|
||||
m.normals[3*v+1] = n.y;
|
||||
m.normals[3*v+2] = n.z;
|
||||
}
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
} // namespace asset
|
||||
Reference in New Issue
Block a user