189 lines
4.8 KiB
C++
189 lines
4.8 KiB
C++
#ifndef EXAMPLE_MESH_H_
|
|
#define EXAMPLE_MESH_H_
|
|
|
|
#include <vector>
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <limits>
|
|
|
|
namespace example {
|
|
|
|
|
|
template<typename T>
|
|
inline void lerp(T dst[3], const T v0[3], const T v1[3], const T v2[3], float u, float v) {
|
|
dst[0] = (static_cast<T>(1.0) - u - v) * v0[0] + u * v1[0] + v * v2[0];
|
|
dst[1] = (static_cast<T>(1.0) - u - v) * v0[1] + u * v1[1] + v * v2[1];
|
|
dst[2] = (static_cast<T>(1.0) - u - v) * v0[2] + u * v1[2] + v * v2[2];
|
|
}
|
|
|
|
template <typename T>
|
|
inline T vlength(const T v[3]) {
|
|
const T d = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
|
|
if (std::fabs(d) > std::numeric_limits<T>::epsilon()) {
|
|
return std::sqrt(d);
|
|
} else {
|
|
return static_cast<T>(0.0);
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
inline void vnormalize(T dst[3], const T v[3]) {
|
|
dst[0] = v[0];
|
|
dst[1] = v[1];
|
|
dst[2] = v[2];
|
|
const T len = vlength(v);
|
|
if (std::fabs(len) > std::numeric_limits<T>::epsilon()) {
|
|
const T inv_len = static_cast<T>(1.0) / len;
|
|
dst[0] *= inv_len;
|
|
dst[1] *= inv_len;
|
|
dst[2] *= inv_len;
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
inline void vcross(T dst[3], const T a[3], const T b[3]) {
|
|
dst[0] = a[1] * b[2] - a[2] * b[1];
|
|
dst[1] = a[2] * b[0] - a[0] * b[2];
|
|
dst[2] = a[0] * b[1] - a[1] * b[0];
|
|
}
|
|
|
|
template <typename T>
|
|
inline void vsub(T dst[3], const T a[3], const T b[3]) {
|
|
dst[0] = a[0] - b[0];
|
|
dst[1] = a[1] - b[1];
|
|
dst[2] = a[2] - b[2];
|
|
}
|
|
|
|
template<typename T>
|
|
inline void calculate_normal(T Nn[3], const T v0[3], const T v1[3], const T v2[3]) {
|
|
T v10[3];
|
|
T v20[3];
|
|
|
|
vsub(v10, v1, v0);
|
|
vsub(v20, v2, v0);
|
|
|
|
T N[3];
|
|
vcross(N, v20, v10);
|
|
vnormalize(Nn, N);
|
|
}
|
|
|
|
template<typename T>
|
|
class Mesh {
|
|
public:
|
|
explicit Mesh(const size_t vertex_stride) :
|
|
stride(vertex_stride) {
|
|
}
|
|
|
|
std::string name;
|
|
|
|
std::vector<T> vertices; /// stride * num_vertices
|
|
std::vector<T> facevarying_normals; /// [xyz] * 3(triangle) * num_faces
|
|
std::vector<T> facevarying_tangents; /// [xyz] * 3(triangle) * num_faces
|
|
std::vector<T> facevarying_binormals; /// [xyz] * 3(triangle) * num_faces
|
|
std::vector<T> facevarying_uvs; /// [xy] * 3(triangle) * num_faces
|
|
std::vector<T>
|
|
facevarying_vertex_colors; /// [xyz] * 3(triangle) * num_faces
|
|
std::vector<unsigned int> faces; /// triangle x num_faces
|
|
std::vector<unsigned int> material_ids; /// index x num_faces
|
|
|
|
T pivot_xform[4][4];
|
|
size_t stride; /// stride for vertex data.
|
|
|
|
// --- Required methods in Scene::Traversal. ---
|
|
|
|
///
|
|
/// Get the geometric normal and the shading normal at `face_idx' th face.
|
|
///
|
|
void GetNormal(T Ng[3], T Ns[3], const unsigned int face_idx, const T u, const T v) const {
|
|
// Compute geometric normal.
|
|
unsigned int f0, f1, f2;
|
|
T v0[3], v1[3], v2[3];
|
|
|
|
f0 = faces[3 * face_idx + 0];
|
|
f1 = faces[3 * face_idx + 1];
|
|
f2 = faces[3 * face_idx + 2];
|
|
|
|
v0[0] = vertices[3 * f0 + 0];
|
|
v0[1] = vertices[3 * f0 + 1];
|
|
v0[2] = vertices[3 * f0 + 2];
|
|
|
|
v1[0] = vertices[3 * f1 + 0];
|
|
v1[1] = vertices[3 * f1 + 1];
|
|
v1[2] = vertices[3 * f1 + 2];
|
|
|
|
v2[0] = vertices[3 * f2 + 0];
|
|
v2[1] = vertices[3 * f2 + 1];
|
|
v2[2] = vertices[3 * f2 + 2];
|
|
|
|
calculate_normal(Ng, v0, v1, v2);
|
|
|
|
if (facevarying_normals.size() > 0) {
|
|
|
|
T n0[3], n1[3], n2[3];
|
|
|
|
n0[0] = facevarying_normals[9 * face_idx + 0];
|
|
n0[1] = facevarying_normals[9 * face_idx + 1];
|
|
n0[2] = facevarying_normals[9 * face_idx + 2];
|
|
|
|
n1[0] = facevarying_normals[9 * face_idx + 3];
|
|
n1[1] = facevarying_normals[9 * face_idx + 4];
|
|
n1[2] = facevarying_normals[9 * face_idx + 5];
|
|
|
|
n2[0] = facevarying_normals[9 * face_idx + 6];
|
|
n2[1] = facevarying_normals[9 * face_idx + 7];
|
|
n2[2] = facevarying_normals[9 * face_idx + 8];
|
|
|
|
lerp(Ns, n0, n1, n2, u, v);
|
|
|
|
} else {
|
|
|
|
// Use geometric normal.
|
|
Ns[0] = Ng[0];
|
|
Ns[1] = Ng[1];
|
|
Ns[2] = Ng[2];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// --- end of required methods in Scene::Traversal. ---
|
|
|
|
///
|
|
/// Get texture coordinate at `face_idx' th face.
|
|
///
|
|
void GetTexCoord(T tcoord[3], const unsigned int face_idx, const T u, const T v) {
|
|
|
|
if (facevarying_uvs.size() > 0) {
|
|
|
|
T t0[3], t1[3], t2[3];
|
|
|
|
t0[0] = facevarying_uvs[6 * face_idx + 0];
|
|
t0[1] = facevarying_uvs[6 * face_idx + 1];
|
|
t0[2] = static_cast<T>(0.0);
|
|
|
|
t1[0] = facevarying_uvs[6 * face_idx + 2];
|
|
t1[1] = facevarying_uvs[6 * face_idx + 3];
|
|
t1[2] = static_cast<T>(0.0);
|
|
|
|
t2[0] = facevarying_uvs[6 * face_idx + 4];
|
|
t2[1] = facevarying_uvs[6 * face_idx + 5];
|
|
t2[2] = static_cast<T>(0.0);
|
|
|
|
lerp(tcoord, t0, t1, t2, u, v);
|
|
|
|
} else {
|
|
|
|
tcoord[0] = static_cast<T>(0.0);
|
|
tcoord[1] = static_cast<T>(0.0);
|
|
tcoord[2] = static_cast<T>(0.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // namespace example
|
|
|
|
#endif // EXAMPLE_MESH_H_
|