mirror of
https://git.mirrors.martin98.com/https://github.com/syoyo/tinygltf.git
synced 2025-08-13 20:45:58 +08:00
Remove old nanort/nanosg code. Keep the gltf-loader class on hand
Signed-off by: Arthur Brainville (Ybalrid) <ybalrid@ybalrid.info>
This commit is contained in:
parent
c7ae1a3e76
commit
fb7ebb955e
@ -1,33 +0,0 @@
|
|||||||
# Raytrace example
|
|
||||||
|
|
||||||
Simple raytracing example with OpenGL preview
|
|
||||||
|
|
||||||
## Status
|
|
||||||
|
|
||||||
Not working yet. Still in work in progress.
|
|
||||||
|
|
||||||
## Build
|
|
||||||
|
|
||||||
### Linux or macOS
|
|
||||||
|
|
||||||
```
|
|
||||||
$ premake5 gmake
|
|
||||||
$ make
|
|
||||||
```
|
|
||||||
|
|
||||||
### Windows
|
|
||||||
|
|
||||||
```
|
|
||||||
$ premake5 vs2015
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Third party libraries and its icenses.
|
|
||||||
|
|
||||||
* picojson : BSD license.
|
|
||||||
* bt3gui : zlib license.
|
|
||||||
* glew : BSD/MIT license.
|
|
||||||
* tinyobjloader : MIT license.
|
|
||||||
* glm : The Happy Bunny License (Modified MIT License). Copyright (c) 2005 - 2017 G-Truc Creation
|
|
||||||
* ImGui : The MIT License (MIT). Copyright (c) 2014-2015 Omar Cornut and ImGui contributors
|
|
||||||
* ImGuizmo : The MIT License (MIT). Copyright (c) 2016 Cedric Guillemet
|
|
@ -1,9 +0,0 @@
|
|||||||
{ "gltf_filename" : "../../models/Cube/Cube.gltf",
|
|
||||||
"scene_scale" : 1.0,
|
|
||||||
"width" : 512,
|
|
||||||
"height" : 512,
|
|
||||||
"eye" : [0, 2.5, 15],
|
|
||||||
"up" : [0, 1, 0],
|
|
||||||
"look_at" : [0, 0, 0],
|
|
||||||
"dummy" : 0
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,69 +0,0 @@
|
|||||||
#ifndef EXAMPLE_MATERIAL_H_
|
|
||||||
#define EXAMPLE_MATERIAL_H_
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
namespace example {
|
|
||||||
|
|
||||||
// TODO(syoyo): Support PBR material.
|
|
||||||
|
|
||||||
struct Material {
|
|
||||||
// float ambient[3];
|
|
||||||
float diffuse[3];
|
|
||||||
float specular[3];
|
|
||||||
// float reflection[3];
|
|
||||||
// float refraction[3];
|
|
||||||
int id;
|
|
||||||
int diffuse_texid;
|
|
||||||
int specular_texid;
|
|
||||||
// int reflection_texid;
|
|
||||||
// int transparency_texid;
|
|
||||||
// int bump_texid;
|
|
||||||
// int normal_texid; // normal map
|
|
||||||
// int alpha_texid; // alpha map
|
|
||||||
|
|
||||||
Material() {
|
|
||||||
// ambient[0] = 0.0;
|
|
||||||
// ambient[1] = 0.0;
|
|
||||||
// ambient[2] = 0.0;
|
|
||||||
diffuse[0] = 0.5;
|
|
||||||
diffuse[1] = 0.5;
|
|
||||||
diffuse[2] = 0.5;
|
|
||||||
specular[0] = 0.5;
|
|
||||||
specular[1] = 0.5;
|
|
||||||
specular[2] = 0.5;
|
|
||||||
// reflection[0] = 0.0;
|
|
||||||
// reflection[1] = 0.0;
|
|
||||||
// reflection[2] = 0.0;
|
|
||||||
// refraction[0] = 0.0;
|
|
||||||
// refraction[1] = 0.0;
|
|
||||||
// refraction[2] = 0.0;
|
|
||||||
id = -1;
|
|
||||||
diffuse_texid = -1;
|
|
||||||
specular_texid = -1;
|
|
||||||
// reflection_texid = -1;
|
|
||||||
// transparency_texid = -1;
|
|
||||||
// bump_texid = -1;
|
|
||||||
// normal_texid = -1;
|
|
||||||
// alpha_texid = -1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Texture {
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
int components;
|
|
||||||
unsigned char* image;
|
|
||||||
|
|
||||||
Texture() {
|
|
||||||
width = -1;
|
|
||||||
height = -1;
|
|
||||||
components = -1;
|
|
||||||
image = NULL;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace example
|
|
||||||
|
|
||||||
|
|
||||||
#endif // EXAMPLE_MATERIAL_H_
|
|
@ -1,216 +0,0 @@
|
|||||||
#include <cstdio>
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
#include "matrix.h"
|
|
||||||
|
|
||||||
//using namespace mallie;
|
|
||||||
|
|
||||||
static inline float vdot(float a[3], float b[3]) {
|
|
||||||
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void vcross(float c[3], float a[3], float b[3]) {
|
|
||||||
c[0] = a[1] * b[2] - a[2] * b[1];
|
|
||||||
c[1] = a[2] * b[0] - a[0] * b[2];
|
|
||||||
c[2] = a[0] * b[1] - a[1] * b[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline float vlength(float v[3]) {
|
|
||||||
float len2 = vdot(v, v);
|
|
||||||
if (std::abs(len2) > 1.0e-30) {
|
|
||||||
return sqrt(len2);
|
|
||||||
}
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vnormalize(float v[3]) {
|
|
||||||
float len = vlength(v);
|
|
||||||
if (std::abs(len) > 1.0e-30) {
|
|
||||||
float inv_len = 1.0f / len;
|
|
||||||
v[0] *= inv_len;
|
|
||||||
v[1] *= inv_len;
|
|
||||||
v[2] *= inv_len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Matrix::Print(float m[4][4]) {
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
printf("m[%d] = %f, %f, %f, %f\n", i, m[i][0], m[i][1], m[i][2], m[i][3]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Matrix::LookAt(float m[4][4], float eye[3], float lookat[3],
|
|
||||||
float up[3]) {
|
|
||||||
|
|
||||||
float u[3], v[3];
|
|
||||||
float look[3];
|
|
||||||
look[0] = lookat[0] - eye[0];
|
|
||||||
look[1] = lookat[1] - eye[1];
|
|
||||||
look[2] = lookat[2] - eye[2];
|
|
||||||
vnormalize(look);
|
|
||||||
|
|
||||||
vcross(u, look, up);
|
|
||||||
vnormalize(u);
|
|
||||||
|
|
||||||
vcross(v, u, look);
|
|
||||||
vnormalize(v);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
m[0][0] = u[0];
|
|
||||||
m[0][1] = v[0];
|
|
||||||
m[0][2] = -look[0];
|
|
||||||
m[0][3] = 0.0;
|
|
||||||
|
|
||||||
m[1][0] = u[1];
|
|
||||||
m[1][1] = v[1];
|
|
||||||
m[1][2] = -look[1];
|
|
||||||
m[1][3] = 0.0;
|
|
||||||
|
|
||||||
m[2][0] = u[2];
|
|
||||||
m[2][1] = v[2];
|
|
||||||
m[2][2] = -look[2];
|
|
||||||
m[2][3] = 0.0;
|
|
||||||
|
|
||||||
m[3][0] = eye[0];
|
|
||||||
m[3][1] = eye[1];
|
|
||||||
m[3][2] = eye[2];
|
|
||||||
m[3][3] = 1.0;
|
|
||||||
#else
|
|
||||||
m[0][0] = u[0];
|
|
||||||
m[1][0] = v[0];
|
|
||||||
m[2][0] = -look[0];
|
|
||||||
m[3][0] = eye[0];
|
|
||||||
|
|
||||||
m[0][1] = u[1];
|
|
||||||
m[1][1] = v[1];
|
|
||||||
m[2][1] = -look[1];
|
|
||||||
m[3][1] = eye[1];
|
|
||||||
|
|
||||||
m[0][2] = u[2];
|
|
||||||
m[1][2] = v[2];
|
|
||||||
m[2][2] = -look[2];
|
|
||||||
m[3][2] = eye[2];
|
|
||||||
|
|
||||||
m[0][3] = 0.0;
|
|
||||||
m[1][3] = 0.0;
|
|
||||||
m[2][3] = 0.0;
|
|
||||||
m[3][3] = 1.0;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Matrix::Inverse(float m[4][4]) {
|
|
||||||
/*
|
|
||||||
* codes from intel web
|
|
||||||
* cramer's rule version
|
|
||||||
*/
|
|
||||||
int i, j;
|
|
||||||
float tmp[12]; /* tmp array for pairs */
|
|
||||||
float tsrc[16]; /* array of transpose source matrix */
|
|
||||||
float det; /* determinant */
|
|
||||||
|
|
||||||
/* transpose matrix */
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
tsrc[i] = m[i][0];
|
|
||||||
tsrc[i + 4] = m[i][1];
|
|
||||||
tsrc[i + 8] = m[i][2];
|
|
||||||
tsrc[i + 12] = m[i][3];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* calculate pair for first 8 elements(cofactors) */
|
|
||||||
tmp[0] = tsrc[10] * tsrc[15];
|
|
||||||
tmp[1] = tsrc[11] * tsrc[14];
|
|
||||||
tmp[2] = tsrc[9] * tsrc[15];
|
|
||||||
tmp[3] = tsrc[11] * tsrc[13];
|
|
||||||
tmp[4] = tsrc[9] * tsrc[14];
|
|
||||||
tmp[5] = tsrc[10] * tsrc[13];
|
|
||||||
tmp[6] = tsrc[8] * tsrc[15];
|
|
||||||
tmp[7] = tsrc[11] * tsrc[12];
|
|
||||||
tmp[8] = tsrc[8] * tsrc[14];
|
|
||||||
tmp[9] = tsrc[10] * tsrc[12];
|
|
||||||
tmp[10] = tsrc[8] * tsrc[13];
|
|
||||||
tmp[11] = tsrc[9] * tsrc[12];
|
|
||||||
|
|
||||||
/* calculate first 8 elements(cofactors) */
|
|
||||||
m[0][0] = tmp[0] * tsrc[5] + tmp[3] * tsrc[6] + tmp[4] * tsrc[7];
|
|
||||||
m[0][0] -= tmp[1] * tsrc[5] + tmp[2] * tsrc[6] + tmp[5] * tsrc[7];
|
|
||||||
m[0][1] = tmp[1] * tsrc[4] + tmp[6] * tsrc[6] + tmp[9] * tsrc[7];
|
|
||||||
m[0][1] -= tmp[0] * tsrc[4] + tmp[7] * tsrc[6] + tmp[8] * tsrc[7];
|
|
||||||
m[0][2] = tmp[2] * tsrc[4] + tmp[7] * tsrc[5] + tmp[10] * tsrc[7];
|
|
||||||
m[0][2] -= tmp[3] * tsrc[4] + tmp[6] * tsrc[5] + tmp[11] * tsrc[7];
|
|
||||||
m[0][3] = tmp[5] * tsrc[4] + tmp[8] * tsrc[5] + tmp[11] * tsrc[6];
|
|
||||||
m[0][3] -= tmp[4] * tsrc[4] + tmp[9] * tsrc[5] + tmp[10] * tsrc[6];
|
|
||||||
m[1][0] = tmp[1] * tsrc[1] + tmp[2] * tsrc[2] + tmp[5] * tsrc[3];
|
|
||||||
m[1][0] -= tmp[0] * tsrc[1] + tmp[3] * tsrc[2] + tmp[4] * tsrc[3];
|
|
||||||
m[1][1] = tmp[0] * tsrc[0] + tmp[7] * tsrc[2] + tmp[8] * tsrc[3];
|
|
||||||
m[1][1] -= tmp[1] * tsrc[0] + tmp[6] * tsrc[2] + tmp[9] * tsrc[3];
|
|
||||||
m[1][2] = tmp[3] * tsrc[0] + tmp[6] * tsrc[1] + tmp[11] * tsrc[3];
|
|
||||||
m[1][2] -= tmp[2] * tsrc[0] + tmp[7] * tsrc[1] + tmp[10] * tsrc[3];
|
|
||||||
m[1][3] = tmp[4] * tsrc[0] + tmp[9] * tsrc[1] + tmp[10] * tsrc[2];
|
|
||||||
m[1][3] -= tmp[5] * tsrc[0] + tmp[8] * tsrc[1] + tmp[11] * tsrc[2];
|
|
||||||
|
|
||||||
/* calculate pairs for second 8 elements(cofactors) */
|
|
||||||
tmp[0] = tsrc[2] * tsrc[7];
|
|
||||||
tmp[1] = tsrc[3] * tsrc[6];
|
|
||||||
tmp[2] = tsrc[1] * tsrc[7];
|
|
||||||
tmp[3] = tsrc[3] * tsrc[5];
|
|
||||||
tmp[4] = tsrc[1] * tsrc[6];
|
|
||||||
tmp[5] = tsrc[2] * tsrc[5];
|
|
||||||
tmp[6] = tsrc[0] * tsrc[7];
|
|
||||||
tmp[7] = tsrc[3] * tsrc[4];
|
|
||||||
tmp[8] = tsrc[0] * tsrc[6];
|
|
||||||
tmp[9] = tsrc[2] * tsrc[4];
|
|
||||||
tmp[10] = tsrc[0] * tsrc[5];
|
|
||||||
tmp[11] = tsrc[1] * tsrc[4];
|
|
||||||
|
|
||||||
/* calculate second 8 elements(cofactors) */
|
|
||||||
m[2][0] = tmp[0] * tsrc[13] + tmp[3] * tsrc[14] + tmp[4] * tsrc[15];
|
|
||||||
m[2][0] -= tmp[1] * tsrc[13] + tmp[2] * tsrc[14] + tmp[5] * tsrc[15];
|
|
||||||
m[2][1] = tmp[1] * tsrc[12] + tmp[6] * tsrc[14] + tmp[9] * tsrc[15];
|
|
||||||
m[2][1] -= tmp[0] * tsrc[12] + tmp[7] * tsrc[14] + tmp[8] * tsrc[15];
|
|
||||||
m[2][2] = tmp[2] * tsrc[12] + tmp[7] * tsrc[13] + tmp[10] * tsrc[15];
|
|
||||||
m[2][2] -= tmp[3] * tsrc[12] + tmp[6] * tsrc[13] + tmp[11] * tsrc[15];
|
|
||||||
m[2][3] = tmp[5] * tsrc[12] + tmp[8] * tsrc[13] + tmp[11] * tsrc[14];
|
|
||||||
m[2][3] -= tmp[4] * tsrc[12] + tmp[9] * tsrc[13] + tmp[10] * tsrc[14];
|
|
||||||
m[3][0] = tmp[2] * tsrc[10] + tmp[5] * tsrc[11] + tmp[1] * tsrc[9];
|
|
||||||
m[3][0] -= tmp[4] * tsrc[11] + tmp[0] * tsrc[9] + tmp[3] * tsrc[10];
|
|
||||||
m[3][1] = tmp[8] * tsrc[11] + tmp[0] * tsrc[8] + tmp[7] * tsrc[10];
|
|
||||||
m[3][1] -= tmp[6] * tsrc[10] + tmp[9] * tsrc[11] + tmp[1] * tsrc[8];
|
|
||||||
m[3][2] = tmp[6] * tsrc[9] + tmp[11] * tsrc[11] + tmp[3] * tsrc[8];
|
|
||||||
m[3][2] -= tmp[10] * tsrc[11] + tmp[2] * tsrc[8] + tmp[7] * tsrc[9];
|
|
||||||
m[3][3] = tmp[10] * tsrc[10] + tmp[4] * tsrc[8] + tmp[9] * tsrc[9];
|
|
||||||
m[3][3] -= tmp[8] * tsrc[9] + tmp[11] * tsrc[0] + tmp[5] * tsrc[8];
|
|
||||||
|
|
||||||
/* calculate determinant */
|
|
||||||
det = tsrc[0] * m[0][0] + tsrc[1] * m[0][1] + tsrc[2] * m[0][2] +
|
|
||||||
tsrc[3] * m[0][3];
|
|
||||||
|
|
||||||
/* calculate matrix inverse */
|
|
||||||
det = 1.0f / det;
|
|
||||||
|
|
||||||
for (j = 0; j < 4; j++) {
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
m[j][i] *= det;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Matrix::Mult(float dst[4][4], float m0[4][4], float m1[4][4]) {
|
|
||||||
for (int i = 0; i < 4; ++i) {
|
|
||||||
for (int j = 0; j < 4; ++j) {
|
|
||||||
dst[i][j] = 0;
|
|
||||||
for (int k = 0; k < 4; ++k) {
|
|
||||||
dst[i][j] += m0[k][j] * m1[i][k];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Matrix::MultV(float dst[3], float m[4][4], float v[3]) {
|
|
||||||
// printf("v = %f, %f, %f\n", v[0], v[1], v[2]);
|
|
||||||
dst[0] = m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2] + m[3][0];
|
|
||||||
dst[1] = m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2] + m[3][1];
|
|
||||||
dst[2] = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2];
|
|
||||||
// printf("m = %f, %f, %f\n", m[3][0], m[3][1], m[3][2]);
|
|
||||||
// printf("dst = %f, %f, %f\n", dst[0], dst[1], dst[2]);
|
|
||||||
}
|
|
@ -1,182 +0,0 @@
|
|||||||
#ifndef EXAMPLE_MESH_H_
|
|
||||||
#define EXAMPLE_MESH_H_
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
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:
|
|
||||||
std::string name;
|
|
||||||
|
|
||||||
std::vector<T> vertices; /// [xyz] * 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];
|
|
||||||
|
|
||||||
// --- 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_
|
|
File diff suppressed because it is too large
Load Diff
@ -1,900 +0,0 @@
|
|||||||
/*
|
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2017 Light Transport Entertainment, Inc.
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef NANOSG_H_
|
|
||||||
#define NANOSG_H_
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#ifndef NOMINMAX
|
|
||||||
#define NOMINMAX
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <limits>
|
|
||||||
#include <vector>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "nanort.h"
|
|
||||||
|
|
||||||
namespace nanosg {
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
class PrimitiveInterface;
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
class PrimitiveInterface{
|
|
||||||
public:
|
|
||||||
void print(){ static_cast<T &>(this)->print(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
class SpherePrimitive : PrimitiveInterface<SpherePrimitive> {
|
|
||||||
public:
|
|
||||||
void print(){ std::cout << "Sphere" << std::endl; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// 4x4 matrix
|
|
||||||
template <typename T> class Matrix {
|
|
||||||
public:
|
|
||||||
Matrix();
|
|
||||||
~Matrix();
|
|
||||||
|
|
||||||
static void Print(T m[4][4]) {
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
printf("m[%d] = %f, %f, %f, %f\n", i, m[i][0], m[i][1], m[i][2], m[i][3]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Identity(T m[4][4]) {
|
|
||||||
m[0][0] = static_cast<T>(1);
|
|
||||||
m[0][1] = static_cast<T>(0);
|
|
||||||
m[0][2] = static_cast<T>(0);
|
|
||||||
m[0][3] = static_cast<T>(0);
|
|
||||||
m[1][0] = static_cast<T>(0);
|
|
||||||
m[1][1] = static_cast<T>(1);
|
|
||||||
m[1][2] = static_cast<T>(0);
|
|
||||||
m[1][3] = static_cast<T>(0);
|
|
||||||
m[2][0] = static_cast<T>(0);
|
|
||||||
m[2][1] = static_cast<T>(0);
|
|
||||||
m[2][2] = static_cast<T>(1);
|
|
||||||
m[2][3] = static_cast<T>(0);
|
|
||||||
m[3][0] = static_cast<T>(0);
|
|
||||||
m[3][1] = static_cast<T>(0);
|
|
||||||
m[3][2] = static_cast<T>(0);
|
|
||||||
m[3][3] = static_cast<T>(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Copy(T dst[4][4], const T src[4][4]) {
|
|
||||||
memcpy(dst, src, sizeof(T) * 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Inverse(T m[4][4]) {
|
|
||||||
/*
|
|
||||||
* codes from intel web
|
|
||||||
* cramer's rule version
|
|
||||||
*/
|
|
||||||
int i, j;
|
|
||||||
T tmp[12]; /* tmp array for pairs */
|
|
||||||
T tsrc[16]; /* array of transpose source matrix */
|
|
||||||
T det; /* determinant */
|
|
||||||
|
|
||||||
/* transpose matrix */
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
tsrc[i] = m[i][0];
|
|
||||||
tsrc[i + 4] = m[i][1];
|
|
||||||
tsrc[i + 8] = m[i][2];
|
|
||||||
tsrc[i + 12] = m[i][3];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* calculate pair for first 8 elements(cofactors) */
|
|
||||||
tmp[0] = tsrc[10] * tsrc[15];
|
|
||||||
tmp[1] = tsrc[11] * tsrc[14];
|
|
||||||
tmp[2] = tsrc[9] * tsrc[15];
|
|
||||||
tmp[3] = tsrc[11] * tsrc[13];
|
|
||||||
tmp[4] = tsrc[9] * tsrc[14];
|
|
||||||
tmp[5] = tsrc[10] * tsrc[13];
|
|
||||||
tmp[6] = tsrc[8] * tsrc[15];
|
|
||||||
tmp[7] = tsrc[11] * tsrc[12];
|
|
||||||
tmp[8] = tsrc[8] * tsrc[14];
|
|
||||||
tmp[9] = tsrc[10] * tsrc[12];
|
|
||||||
tmp[10] = tsrc[8] * tsrc[13];
|
|
||||||
tmp[11] = tsrc[9] * tsrc[12];
|
|
||||||
|
|
||||||
/* calculate first 8 elements(cofactors) */
|
|
||||||
m[0][0] = tmp[0] * tsrc[5] + tmp[3] * tsrc[6] + tmp[4] * tsrc[7];
|
|
||||||
m[0][0] -= tmp[1] * tsrc[5] + tmp[2] * tsrc[6] + tmp[5] * tsrc[7];
|
|
||||||
m[0][1] = tmp[1] * tsrc[4] + tmp[6] * tsrc[6] + tmp[9] * tsrc[7];
|
|
||||||
m[0][1] -= tmp[0] * tsrc[4] + tmp[7] * tsrc[6] + tmp[8] * tsrc[7];
|
|
||||||
m[0][2] = tmp[2] * tsrc[4] + tmp[7] * tsrc[5] + tmp[10] * tsrc[7];
|
|
||||||
m[0][2] -= tmp[3] * tsrc[4] + tmp[6] * tsrc[5] + tmp[11] * tsrc[7];
|
|
||||||
m[0][3] = tmp[5] * tsrc[4] + tmp[8] * tsrc[5] + tmp[11] * tsrc[6];
|
|
||||||
m[0][3] -= tmp[4] * tsrc[4] + tmp[9] * tsrc[5] + tmp[10] * tsrc[6];
|
|
||||||
m[1][0] = tmp[1] * tsrc[1] + tmp[2] * tsrc[2] + tmp[5] * tsrc[3];
|
|
||||||
m[1][0] -= tmp[0] * tsrc[1] + tmp[3] * tsrc[2] + tmp[4] * tsrc[3];
|
|
||||||
m[1][1] = tmp[0] * tsrc[0] + tmp[7] * tsrc[2] + tmp[8] * tsrc[3];
|
|
||||||
m[1][1] -= tmp[1] * tsrc[0] + tmp[6] * tsrc[2] + tmp[9] * tsrc[3];
|
|
||||||
m[1][2] = tmp[3] * tsrc[0] + tmp[6] * tsrc[1] + tmp[11] * tsrc[3];
|
|
||||||
m[1][2] -= tmp[2] * tsrc[0] + tmp[7] * tsrc[1] + tmp[10] * tsrc[3];
|
|
||||||
m[1][3] = tmp[4] * tsrc[0] + tmp[9] * tsrc[1] + tmp[10] * tsrc[2];
|
|
||||||
m[1][3] -= tmp[5] * tsrc[0] + tmp[8] * tsrc[1] + tmp[11] * tsrc[2];
|
|
||||||
|
|
||||||
/* calculate pairs for second 8 elements(cofactors) */
|
|
||||||
tmp[0] = tsrc[2] * tsrc[7];
|
|
||||||
tmp[1] = tsrc[3] * tsrc[6];
|
|
||||||
tmp[2] = tsrc[1] * tsrc[7];
|
|
||||||
tmp[3] = tsrc[3] * tsrc[5];
|
|
||||||
tmp[4] = tsrc[1] * tsrc[6];
|
|
||||||
tmp[5] = tsrc[2] * tsrc[5];
|
|
||||||
tmp[6] = tsrc[0] * tsrc[7];
|
|
||||||
tmp[7] = tsrc[3] * tsrc[4];
|
|
||||||
tmp[8] = tsrc[0] * tsrc[6];
|
|
||||||
tmp[9] = tsrc[2] * tsrc[4];
|
|
||||||
tmp[10] = tsrc[0] * tsrc[5];
|
|
||||||
tmp[11] = tsrc[1] * tsrc[4];
|
|
||||||
|
|
||||||
/* calculate second 8 elements(cofactors) */
|
|
||||||
m[2][0] = tmp[0] * tsrc[13] + tmp[3] * tsrc[14] + tmp[4] * tsrc[15];
|
|
||||||
m[2][0] -= tmp[1] * tsrc[13] + tmp[2] * tsrc[14] + tmp[5] * tsrc[15];
|
|
||||||
m[2][1] = tmp[1] * tsrc[12] + tmp[6] * tsrc[14] + tmp[9] * tsrc[15];
|
|
||||||
m[2][1] -= tmp[0] * tsrc[12] + tmp[7] * tsrc[14] + tmp[8] * tsrc[15];
|
|
||||||
m[2][2] = tmp[2] * tsrc[12] + tmp[7] * tsrc[13] + tmp[10] * tsrc[15];
|
|
||||||
m[2][2] -= tmp[3] * tsrc[12] + tmp[6] * tsrc[13] + tmp[11] * tsrc[15];
|
|
||||||
m[2][3] = tmp[5] * tsrc[12] + tmp[8] * tsrc[13] + tmp[11] * tsrc[14];
|
|
||||||
m[2][3] -= tmp[4] * tsrc[12] + tmp[9] * tsrc[13] + tmp[10] * tsrc[14];
|
|
||||||
m[3][0] = tmp[2] * tsrc[10] + tmp[5] * tsrc[11] + tmp[1] * tsrc[9];
|
|
||||||
m[3][0] -= tmp[4] * tsrc[11] + tmp[0] * tsrc[9] + tmp[3] * tsrc[10];
|
|
||||||
m[3][1] = tmp[8] * tsrc[11] + tmp[0] * tsrc[8] + tmp[7] * tsrc[10];
|
|
||||||
m[3][1] -= tmp[6] * tsrc[10] + tmp[9] * tsrc[11] + tmp[1] * tsrc[8];
|
|
||||||
m[3][2] = tmp[6] * tsrc[9] + tmp[11] * tsrc[11] + tmp[3] * tsrc[8];
|
|
||||||
m[3][2] -= tmp[10] * tsrc[11] + tmp[2] * tsrc[8] + tmp[7] * tsrc[9];
|
|
||||||
m[3][3] = tmp[10] * tsrc[10] + tmp[4] * tsrc[8] + tmp[9] * tsrc[9];
|
|
||||||
m[3][3] -= tmp[8] * tsrc[9] + tmp[11] * tsrc[0] + tmp[5] * tsrc[8];
|
|
||||||
|
|
||||||
/* calculate determinant */
|
|
||||||
det = tsrc[0] * m[0][0] + tsrc[1] * m[0][1] + tsrc[2] * m[0][2] +
|
|
||||||
tsrc[3] * m[0][3];
|
|
||||||
|
|
||||||
/* calculate matrix inverse */
|
|
||||||
det = static_cast<T>(1.0) / det;
|
|
||||||
|
|
||||||
for (j = 0; j < 4; j++) {
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
m[j][i] *= det;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Transpose(T m[4][4]) {
|
|
||||||
T t[4][4];
|
|
||||||
|
|
||||||
// Transpose
|
|
||||||
for (int j = 0; j < 4; j++) {
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
t[j][i] = m[i][j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy
|
|
||||||
for (int j = 0; j < 4; j++) {
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
m[j][i] = t[j][i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Mult(T dst[4][4], const T m0[4][4], const T m1[4][4]) {
|
|
||||||
for (int i = 0; i < 4; ++i) {
|
|
||||||
for (int j = 0; j < 4; ++j) {
|
|
||||||
dst[i][j] = 0;
|
|
||||||
for (int k = 0; k < 4; ++k) {
|
|
||||||
dst[i][j] += m0[k][j] * m1[i][k];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void MultV(T dst[3], const T m[4][4], const T v[3]) {
|
|
||||||
T tmp[3];
|
|
||||||
tmp[0] = m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2] + m[3][0];
|
|
||||||
tmp[1] = m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2] + m[3][1];
|
|
||||||
tmp[2] = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2];
|
|
||||||
dst[0] = tmp[0];
|
|
||||||
dst[1] = tmp[1];
|
|
||||||
dst[2] = tmp[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void MultV(nanort::real3<T> &dst, const T m[4][4], const T v[3]) {
|
|
||||||
T tmp[3];
|
|
||||||
tmp[0] = m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2] + m[3][0];
|
|
||||||
tmp[1] = m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2] + m[3][1];
|
|
||||||
tmp[2] = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2];
|
|
||||||
dst[0] = tmp[0];
|
|
||||||
dst[1] = tmp[1];
|
|
||||||
dst[2] = tmp[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
//typedef Matrix<float> Matrixf;
|
|
||||||
//typedef Matrix<double> Matrixd;
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static void XformBoundingBox(T xbmin[3], // out
|
|
||||||
T xbmax[3], // out
|
|
||||||
T bmin[3], T bmax[3],
|
|
||||||
T m[4][4]) {
|
|
||||||
|
|
||||||
// create bounding vertex from (bmin, bmax)
|
|
||||||
T b[8][3];
|
|
||||||
|
|
||||||
b[0][0] = bmin[0];
|
|
||||||
b[0][1] = bmin[1];
|
|
||||||
b[0][2] = bmin[2];
|
|
||||||
b[1][0] = bmax[0];
|
|
||||||
b[1][1] = bmin[1];
|
|
||||||
b[1][2] = bmin[2];
|
|
||||||
b[2][0] = bmin[0];
|
|
||||||
b[2][1] = bmax[1];
|
|
||||||
b[2][2] = bmin[2];
|
|
||||||
b[3][0] = bmax[0];
|
|
||||||
b[3][1] = bmax[1];
|
|
||||||
b[3][2] = bmin[2];
|
|
||||||
|
|
||||||
b[4][0] = bmin[0];
|
|
||||||
b[4][1] = bmin[1];
|
|
||||||
b[4][2] = bmax[2];
|
|
||||||
b[5][0] = bmax[0];
|
|
||||||
b[5][1] = bmin[1];
|
|
||||||
b[5][2] = bmax[2];
|
|
||||||
b[6][0] = bmin[0];
|
|
||||||
b[6][1] = bmax[1];
|
|
||||||
b[6][2] = bmax[2];
|
|
||||||
b[7][0] = bmax[0];
|
|
||||||
b[7][1] = bmax[1];
|
|
||||||
b[7][2] = bmax[2];
|
|
||||||
|
|
||||||
T xb[8][3];
|
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
Matrix<T>::MultV(xb[i], m, b[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
xbmin[0] = xb[0][0];
|
|
||||||
xbmin[1] = xb[0][1];
|
|
||||||
xbmin[2] = xb[0][2];
|
|
||||||
xbmax[0] = xb[0][0];
|
|
||||||
xbmax[1] = xb[0][1];
|
|
||||||
xbmax[2] = xb[0][2];
|
|
||||||
|
|
||||||
for (int i = 1; i < 8; i++) {
|
|
||||||
|
|
||||||
xbmin[0] = std::min(xb[i][0], xbmin[0]);
|
|
||||||
xbmin[1] = std::min(xb[i][1], xbmin[1]);
|
|
||||||
xbmin[2] = std::min(xb[i][2], xbmin[2]);
|
|
||||||
|
|
||||||
xbmax[0] = std::max(xb[i][0], xbmax[0]);
|
|
||||||
xbmax[1] = std::max(xb[i][1], xbmax[1]);
|
|
||||||
xbmax[2] = std::max(xb[i][2], xbmax[2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct Intersection
|
|
||||||
{
|
|
||||||
// required fields.
|
|
||||||
T t; // hit distance
|
|
||||||
unsigned int prim_id; // primitive ID of the hit
|
|
||||||
float u;
|
|
||||||
float v;
|
|
||||||
|
|
||||||
unsigned int node_id; // node ID of the hit.
|
|
||||||
nanort::real3<T> P; // intersection point
|
|
||||||
nanort::real3<T> Ns; // shading normal
|
|
||||||
nanort::real3<T> Ng; // geometric normal
|
|
||||||
};
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Renderable node
|
|
||||||
///
|
|
||||||
template<typename T, class M>
|
|
||||||
class Node
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef Node<T, M> type;
|
|
||||||
|
|
||||||
explicit Node(const M *mesh)
|
|
||||||
: mesh_(mesh)
|
|
||||||
{
|
|
||||||
xbmin_[0] = xbmin_[1] = xbmin_[2] = std::numeric_limits<T>::max();
|
|
||||||
xbmax_[0] = xbmax_[1] = xbmax_[2] = -std::numeric_limits<T>::max();
|
|
||||||
|
|
||||||
lbmin_[0] = lbmin_[1] = lbmin_[2] = std::numeric_limits<T>::max();
|
|
||||||
lbmax_[0] = lbmax_[1] = lbmax_[2] = -std::numeric_limits<T>::max();
|
|
||||||
|
|
||||||
Matrix<T>::Identity(local_xform_);
|
|
||||||
Matrix<T>::Identity(xform_);
|
|
||||||
Matrix<T>::Identity(inv_xform_);
|
|
||||||
Matrix<T>::Identity(inv_xform33_); inv_xform33_[3][3] = static_cast<T>(0.0);
|
|
||||||
Matrix<T>::Identity(inv_transpose_xform33_); inv_transpose_xform33_[3][3] = static_cast<T>(0.0);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
~Node() {}
|
|
||||||
|
|
||||||
void Copy(const type &rhs) {
|
|
||||||
Matrix<T>::Copy(local_xform_, rhs.local_xform_);
|
|
||||||
Matrix<T>::Copy(xform_, rhs.xform_);
|
|
||||||
Matrix<T>::Copy(inv_xform_, rhs.inv_xform_);
|
|
||||||
Matrix<T>::Copy(inv_xform33_, rhs.inv_xform33_);
|
|
||||||
Matrix<T>::Copy(inv_transpose_xform33_, rhs.inv_transpose_xform33_);
|
|
||||||
|
|
||||||
lbmin_[0] = rhs.lbmin_[0];
|
|
||||||
lbmin_[1] = rhs.lbmin_[1];
|
|
||||||
lbmin_[2] = rhs.lbmin_[2];
|
|
||||||
|
|
||||||
lbmax_[0] = rhs.lbmax_[0];
|
|
||||||
lbmax_[1] = rhs.lbmax_[1];
|
|
||||||
lbmax_[2] = rhs.lbmax_[2];
|
|
||||||
|
|
||||||
xbmin_[0] = rhs.xbmin_[0];
|
|
||||||
xbmin_[1] = rhs.xbmin_[1];
|
|
||||||
xbmin_[2] = rhs.xbmin_[2];
|
|
||||||
|
|
||||||
xbmax_[0] = rhs.xbmax_[0];
|
|
||||||
xbmax_[1] = rhs.xbmax_[1];
|
|
||||||
xbmax_[2] = rhs.xbmax_[2];
|
|
||||||
|
|
||||||
mesh_ = rhs.mesh_;
|
|
||||||
name_ = rhs.name_;
|
|
||||||
|
|
||||||
children_ = rhs.children_;
|
|
||||||
}
|
|
||||||
|
|
||||||
Node(const type &rhs) {
|
|
||||||
Copy(rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
const type &operator=(const type &rhs) {
|
|
||||||
Copy(rhs);
|
|
||||||
return (*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetName(const std::string &name) {
|
|
||||||
name_ = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string &GetName() const {
|
|
||||||
return name_;
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Add child node.
|
|
||||||
///
|
|
||||||
void AddChild(const type &child) {
|
|
||||||
children_.push_back(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Get chidren
|
|
||||||
///
|
|
||||||
const std::vector<type> &GetChildren() const {
|
|
||||||
return children_;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<type> &GetChildren() {
|
|
||||||
return children_;
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Update internal state.
|
|
||||||
///
|
|
||||||
void Update(const T parent_xform[4][4]) {
|
|
||||||
|
|
||||||
if (!accel_.IsValid() && mesh_ && (mesh_->vertices.size() > 3) && (mesh_->faces.size() >= 3)) {
|
|
||||||
|
|
||||||
// Assume mesh is composed of triangle faces only.
|
|
||||||
nanort::TriangleMesh<float> triangle_mesh(mesh_->vertices.data(), mesh_->faces.data(), sizeof(float) * 3);
|
|
||||||
nanort::TriangleSAHPred<float> triangle_pred(mesh_->vertices.data(), mesh_->faces.data(), sizeof(float) * 3);
|
|
||||||
|
|
||||||
bool ret = accel_.Build(int(mesh_->faces.size()) / 3, triangle_mesh, triangle_pred);
|
|
||||||
|
|
||||||
// Update local bbox.
|
|
||||||
if (ret) {
|
|
||||||
accel_.BoundingBox(lbmin_, lbmax_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// xform = parent_xform x local_xform
|
|
||||||
Matrix<T>::Mult(xform_, parent_xform, local_xform_);
|
|
||||||
|
|
||||||
// Compute the bounding box in world coordinate.
|
|
||||||
XformBoundingBox(xbmin_, xbmax_, lbmin_, lbmax_, xform_);
|
|
||||||
|
|
||||||
// Inverse(xform)
|
|
||||||
Matrix<T>::Copy(inv_xform_, xform_);
|
|
||||||
Matrix<T>::Inverse(inv_xform_);
|
|
||||||
|
|
||||||
// Clear translation, then inverse(xform)
|
|
||||||
Matrix<T>::Copy(inv_xform33_, xform_);
|
|
||||||
inv_xform33_[3][0] = static_cast<T>(0.0);
|
|
||||||
inv_xform33_[3][1] = static_cast<T>(0.0);
|
|
||||||
inv_xform33_[3][2] = static_cast<T>(0.0);
|
|
||||||
Matrix<T>::Inverse(inv_xform33_);
|
|
||||||
|
|
||||||
// Inverse transpose of xform33
|
|
||||||
Matrix<T>::Copy(inv_transpose_xform33_, inv_xform33_);
|
|
||||||
Matrix<T>::Transpose(inv_transpose_xform33_);
|
|
||||||
|
|
||||||
// Update children nodes
|
|
||||||
for (size_t i = 0; i < children_.size(); i++) {
|
|
||||||
children_[i].Update(xform_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Set local transformation.
|
|
||||||
///
|
|
||||||
void SetLocalXform(const T xform[4][4]) {
|
|
||||||
memcpy(local_xform_, xform, sizeof(float) * 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
const T *GetLocalXformPtr() const {
|
|
||||||
return &local_xform_[0][0];
|
|
||||||
}
|
|
||||||
|
|
||||||
const T *GetXformPtr() const {
|
|
||||||
return &xform_[0][0];
|
|
||||||
}
|
|
||||||
|
|
||||||
const M *GetMesh() const {
|
|
||||||
return mesh_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const nanort::BVHAccel<T> &GetAccel() const {
|
|
||||||
return accel_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void GetWorldBoundingBox(T bmin[3], T bmax[3]) const {
|
|
||||||
bmin[0] = xbmin_[0];
|
|
||||||
bmin[1] = xbmin_[1];
|
|
||||||
bmin[2] = xbmin_[2];
|
|
||||||
|
|
||||||
bmax[0] = xbmax_[0];
|
|
||||||
bmax[1] = xbmax_[1];
|
|
||||||
bmax[2] = xbmax_[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void GetLocalBoundingBox(T bmin[3], T bmax[3]) const {
|
|
||||||
bmin[0] = lbmin_[0];
|
|
||||||
bmin[1] = lbmin_[1];
|
|
||||||
bmin[2] = lbmin_[2];
|
|
||||||
|
|
||||||
bmax[0] = lbmax_[0];
|
|
||||||
bmax[1] = lbmax_[1];
|
|
||||||
bmax[2] = lbmax_[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
T local_xform_[4][4]; // Node's local transformation matrix.
|
|
||||||
T xform_[4][4]; // Parent xform x local_xform.
|
|
||||||
T inv_xform_[4][4]; // inverse(xform). world -> local
|
|
||||||
T inv_xform33_[4][4]; // inverse(xform0 with upper-left 3x3 elemets only(for transforming direction vector)
|
|
||||||
T inv_transpose_xform33_[4][4]; // inverse(transpose(xform)) with upper-left 3x3 elements only(for transforming normal vector)
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
// bounding box(local space)
|
|
||||||
T lbmin_[3];
|
|
||||||
T lbmax_[3];
|
|
||||||
|
|
||||||
// bounding box after xform(world space)
|
|
||||||
T xbmin_[3];
|
|
||||||
T xbmax_[3];
|
|
||||||
|
|
||||||
nanort::BVHAccel<T> accel_;
|
|
||||||
|
|
||||||
std::string name_;
|
|
||||||
|
|
||||||
const M *mesh_;
|
|
||||||
|
|
||||||
std::vector<type> children_;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// -------------------------------------------------
|
|
||||||
|
|
||||||
// Predefined SAH predicator for cube.
|
|
||||||
template<typename T, class M>
|
|
||||||
class NodeBBoxPred {
|
|
||||||
public:
|
|
||||||
NodeBBoxPred(const std::vector<Node<T, M> >* nodes) : axis_(0), pos_(0.0f), nodes_(nodes) {}
|
|
||||||
|
|
||||||
void Set(int axis, float pos) const {
|
|
||||||
axis_ = axis;
|
|
||||||
pos_ = pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator()(unsigned int i) const {
|
|
||||||
int axis = axis_;
|
|
||||||
float pos = pos_;
|
|
||||||
|
|
||||||
T bmin[3], bmax[3];
|
|
||||||
|
|
||||||
(*nodes_)[i].GetWorldBoundingBox(bmin, bmax);
|
|
||||||
|
|
||||||
T center = bmax[axis] - bmin[axis];
|
|
||||||
|
|
||||||
return (center < pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
mutable int axis_;
|
|
||||||
mutable float pos_;
|
|
||||||
const std::vector<Node<T, M> > *nodes_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T, class M>
|
|
||||||
class NodeBBoxGeometry {
|
|
||||||
public:
|
|
||||||
NodeBBoxGeometry(const std::vector<Node<T, M> >* nodes)
|
|
||||||
: nodes_(nodes) {}
|
|
||||||
|
|
||||||
/// Compute bounding box for `prim_index`th cube.
|
|
||||||
/// This function is called for each primitive in BVH build.
|
|
||||||
void BoundingBox(nanort::real3<T>* bmin, nanort::real3<T>* bmax, unsigned int prim_index) const {
|
|
||||||
T a[3], b[3];
|
|
||||||
(*nodes_)[prim_index].GetWorldBoundingBox(a, b);
|
|
||||||
(*bmin)[0] = a[0];
|
|
||||||
(*bmin)[1] = a[1];
|
|
||||||
(*bmin)[2] = a[2];
|
|
||||||
(*bmax)[0] = b[0];
|
|
||||||
(*bmax)[1] = b[1];
|
|
||||||
(*bmax)[2] = b[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<Node<T, M> >* nodes_;
|
|
||||||
mutable nanort::real3<T> ray_org_;
|
|
||||||
mutable nanort::real3<T> ray_dir_;
|
|
||||||
mutable nanort::BVHTraceOptions trace_options_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class NodeBBoxIntersection {
|
|
||||||
public:
|
|
||||||
NodeBBoxIntersection() {}
|
|
||||||
|
|
||||||
float normal[3];
|
|
||||||
|
|
||||||
// Required member variables.
|
|
||||||
float t;
|
|
||||||
unsigned int prim_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T, class M>
|
|
||||||
class NodeBBoxIntersector {
|
|
||||||
public:
|
|
||||||
NodeBBoxIntersector(const std::vector<Node<T, M> >* nodes)
|
|
||||||
: nodes_(nodes) {}
|
|
||||||
|
|
||||||
bool Intersect(float* out_t_min, float *out_t_max, unsigned int prim_index) const {
|
|
||||||
|
|
||||||
T bmin[3], bmax[3];
|
|
||||||
|
|
||||||
(*nodes_)[prim_index].GetWorldBoundingBox(bmin, bmax);
|
|
||||||
|
|
||||||
float tmin, tmax;
|
|
||||||
|
|
||||||
const float min_x = ray_dir_sign_[0] ? bmax[0] : bmin[0];
|
|
||||||
const float min_y = ray_dir_sign_[1] ? bmax[1] : bmin[1];
|
|
||||||
const float min_z = ray_dir_sign_[2] ? bmax[2] : bmin[2];
|
|
||||||
const float max_x = ray_dir_sign_[0] ? bmin[0] : bmax[0];
|
|
||||||
const float max_y = ray_dir_sign_[1] ? bmin[1] : bmax[1];
|
|
||||||
const float max_z = ray_dir_sign_[2] ? bmin[2] : bmax[2];
|
|
||||||
|
|
||||||
// X
|
|
||||||
const float tmin_x = (min_x - ray_org_[0]) * ray_inv_dir_[0];
|
|
||||||
const float tmax_x = (max_x - ray_org_[0]) * ray_inv_dir_[0];
|
|
||||||
|
|
||||||
// Y
|
|
||||||
const float tmin_y = (min_y - ray_org_[1]) * ray_inv_dir_[1];
|
|
||||||
const float tmax_y = (max_y - ray_org_[1]) * ray_inv_dir_[1];
|
|
||||||
|
|
||||||
// Z
|
|
||||||
const float tmin_z = (min_z - ray_org_[2]) * ray_inv_dir_[2];
|
|
||||||
const float tmax_z = (max_z - ray_org_[2]) * ray_inv_dir_[2];
|
|
||||||
|
|
||||||
tmin = nanort::safemax(tmin_z, nanort::safemax(tmin_y, tmin_x));
|
|
||||||
tmax = nanort::safemin(tmax_z, nanort::safemin(tmax_y, tmax_x));
|
|
||||||
|
|
||||||
if (tmin <= tmax) {
|
|
||||||
(*out_t_min) = tmin;
|
|
||||||
(*out_t_max) = tmax;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Prepare BVH traversal(e.g. compute inverse ray direction)
|
|
||||||
/// This function is called only once in BVH traversal.
|
|
||||||
void PrepareTraversal(const nanort::Ray<float>& ray) const {
|
|
||||||
ray_org_[0] = ray.org[0];
|
|
||||||
ray_org_[1] = ray.org[1];
|
|
||||||
ray_org_[2] = ray.org[2];
|
|
||||||
|
|
||||||
ray_dir_[0] = ray.dir[0];
|
|
||||||
ray_dir_[1] = ray.dir[1];
|
|
||||||
ray_dir_[2] = ray.dir[2];
|
|
||||||
|
|
||||||
// FIXME(syoyo): Consider zero div case.
|
|
||||||
ray_inv_dir_[0] = static_cast<T>(1.0) / ray.dir[0];
|
|
||||||
ray_inv_dir_[1] = static_cast<T>(1.0) / ray.dir[1];
|
|
||||||
ray_inv_dir_[2] = static_cast<T>(1.0) / ray.dir[2];
|
|
||||||
|
|
||||||
ray_dir_sign_[0] = ray.dir[0] < static_cast<T>(0.0) ? static_cast<T>(1) : static_cast<T>(0);
|
|
||||||
ray_dir_sign_[1] = ray.dir[1] < static_cast<T>(0.0) ? static_cast<T>(1) : static_cast<T>(0);
|
|
||||||
ray_dir_sign_[2] = ray.dir[2] < static_cast<T>(0.0) ? static_cast<T>(1) : static_cast<T>(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<Node<T, M> >* nodes_;
|
|
||||||
mutable nanort::real3<T> ray_org_;
|
|
||||||
mutable nanort::real3<T> ray_dir_;
|
|
||||||
mutable nanort::real3<T> ray_inv_dir_;
|
|
||||||
mutable int ray_dir_sign_[3];
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T, class M>
|
|
||||||
class Scene
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Scene() {
|
|
||||||
bmin_[0] = bmin_[1] = bmin_[2] = std::numeric_limits<T>::max();
|
|
||||||
bmax_[0] = bmax_[1] = bmax_[2] = -std::numeric_limits<T>::max();
|
|
||||||
}
|
|
||||||
|
|
||||||
~Scene() {};
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Add intersectable node to the scene.
|
|
||||||
///
|
|
||||||
bool AddNode(const Node<T, M> &node) {
|
|
||||||
nodes_.push_back(node);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<Node<T, M> > &GetNodes() const {
|
|
||||||
return nodes_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FindNode(const std::string &name, Node<T, M> **found_node) {
|
|
||||||
if (!found_node) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name.empty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simple exhaustive search.
|
|
||||||
for (size_t i = 0; i < nodes_.size(); i++) {
|
|
||||||
if (FindNodeRecursive(name, &(nodes_[i]), found_node)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Commit the scene. Must be called before tracing rays into the scene.
|
|
||||||
///
|
|
||||||
bool Commit() {
|
|
||||||
|
|
||||||
// Update nodes.
|
|
||||||
for (size_t i = 0; i < nodes_.size(); i++) {
|
|
||||||
T ident[4][4];
|
|
||||||
Matrix<T>::Identity(ident);
|
|
||||||
|
|
||||||
nodes_[i].Update(ident);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build toplevel BVH.
|
|
||||||
NodeBBoxGeometry<T, M> geom(&nodes_);
|
|
||||||
NodeBBoxPred<T, M> pred(&nodes_);
|
|
||||||
|
|
||||||
// FIXME(LTE): Limit one leaf contains one node bbox primitive. This would work, but would be inefficient.
|
|
||||||
// e.g. will miss some node when constructed BVH depth is larger than the value of BVHBuildOptions.
|
|
||||||
// Implement more better and efficient BVH build and traverse for Toplevel BVH.
|
|
||||||
nanort::BVHBuildOptions<T> build_options;
|
|
||||||
build_options.min_leaf_primitives = 1;
|
|
||||||
|
|
||||||
bool ret = toplevel_accel_.Build(static_cast<unsigned int>(nodes_.size()), geom, pred, build_options);
|
|
||||||
|
|
||||||
nanort::BVHBuildStatistics stats = toplevel_accel_.GetStatistics();
|
|
||||||
|
|
||||||
//toplevel_accel_.Debug();
|
|
||||||
|
|
||||||
if (ret) {
|
|
||||||
toplevel_accel_.BoundingBox(bmin_, bmax_);
|
|
||||||
} else {
|
|
||||||
// Set invalid bbox value.
|
|
||||||
bmin_[0] = std::numeric_limits<T>::max();
|
|
||||||
bmin_[1] = std::numeric_limits<T>::max();
|
|
||||||
bmin_[2] = std::numeric_limits<T>::max();
|
|
||||||
|
|
||||||
bmax_[0] = -std::numeric_limits<T>::max();
|
|
||||||
bmax_[1] = -std::numeric_limits<T>::max();
|
|
||||||
bmax_[2] = -std::numeric_limits<T>::max();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Get the scene bounding box.
|
|
||||||
///
|
|
||||||
void GetBoundingBox(T bmin[3], T bmax[3]) const {
|
|
||||||
bmin[0] = bmin_[0];
|
|
||||||
bmin[1] = bmin_[1];
|
|
||||||
bmin[2] = bmin_[2];
|
|
||||||
|
|
||||||
bmax[0] = bmax_[0];
|
|
||||||
bmax[1] = bmax_[1];
|
|
||||||
bmax[2] = bmax_[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Trace the ray into the scene.
|
|
||||||
/// First find the intersection of nodes' bounding box using toplevel BVH.
|
|
||||||
/// Then, trace into the hit node to find the intersection of the primitive.
|
|
||||||
///
|
|
||||||
template<class H>
|
|
||||||
bool Traverse(nanort::Ray<T> &ray, H *isect, const bool cull_back_face = false) const {
|
|
||||||
|
|
||||||
if (!toplevel_accel_.IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int kMaxIntersections = 64;
|
|
||||||
|
|
||||||
bool has_hit = false;
|
|
||||||
|
|
||||||
NodeBBoxIntersector<T, M> isector(&nodes_);
|
|
||||||
nanort::StackVector<nanort::NodeHit<T>, 128> node_hits;
|
|
||||||
bool may_hit = toplevel_accel_.ListNodeIntersections(ray, kMaxIntersections, isector, &node_hits);
|
|
||||||
|
|
||||||
if (may_hit) {
|
|
||||||
|
|
||||||
T t_max = std::numeric_limits<T>::max();
|
|
||||||
T t_nearest = t_max;
|
|
||||||
|
|
||||||
nanort::BVHTraceOptions trace_options;
|
|
||||||
trace_options.cull_back_face = cull_back_face;
|
|
||||||
|
|
||||||
// Find actual intersection point.
|
|
||||||
for (size_t i = 0; i < node_hits->size(); i++) {
|
|
||||||
|
|
||||||
// Early cull test.
|
|
||||||
if (t_nearest < node_hits[i].t_min) {
|
|
||||||
//printf("near: %f, t_min: %f, t_max: %f\n", t_nearest, node_hits[i].t_min, node_hits[i].t_max);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(node_hits[i].node_id < nodes_.size());
|
|
||||||
const Node<T, M> &node = nodes_[node_hits[i].node_id];
|
|
||||||
|
|
||||||
// Transform ray into node's local space
|
|
||||||
// TODO(LTE): Set ray tmin and tmax
|
|
||||||
nanort::Ray<T> local_ray;
|
|
||||||
Matrix<T>::MultV(local_ray.org, node.inv_xform_, ray.org);
|
|
||||||
Matrix<T>::MultV(local_ray.dir, node.inv_xform33_, ray.dir);
|
|
||||||
|
|
||||||
nanort::TriangleIntersector<T, H> triangle_intersector(node.GetMesh()->vertices.data(), node.GetMesh()->faces.data(), sizeof(T) * 3);
|
|
||||||
H local_isect;
|
|
||||||
|
|
||||||
bool hit = node.GetAccel().Traverse(local_ray, triangle_intersector, &local_isect);
|
|
||||||
|
|
||||||
if (hit) {
|
|
||||||
// Calulcate hit distance in world coordiante.
|
|
||||||
T local_P[3];
|
|
||||||
local_P[0] = local_ray.org[0] + local_isect.t * local_ray.dir[0];
|
|
||||||
local_P[1] = local_ray.org[1] + local_isect.t * local_ray.dir[1];
|
|
||||||
local_P[2] = local_ray.org[2] + local_isect.t * local_ray.dir[2];
|
|
||||||
|
|
||||||
T world_P[3];
|
|
||||||
Matrix<T>::MultV(world_P, node.xform_, local_P);
|
|
||||||
|
|
||||||
nanort::real3<T> po;
|
|
||||||
po[0] = world_P[0] - ray.org[0];
|
|
||||||
po[1] = world_P[1] - ray.org[1];
|
|
||||||
po[2] = world_P[2] - ray.org[2];
|
|
||||||
|
|
||||||
float t_world = vlength(po);
|
|
||||||
|
|
||||||
if (t_world < t_nearest) {
|
|
||||||
t_nearest = t_world;
|
|
||||||
has_hit = true;
|
|
||||||
//(*isect) = local_isect;
|
|
||||||
isect->node_id = node_hits[i].node_id;
|
|
||||||
isect->prim_id = local_isect.prim_id;
|
|
||||||
isect->u = local_isect.u;
|
|
||||||
isect->v = local_isect.v;
|
|
||||||
|
|
||||||
// TODO(LTE): Implement
|
|
||||||
T Ng[3], Ns[3]; // geometric normal, shading normal.
|
|
||||||
|
|
||||||
node.GetMesh()->GetNormal(Ng, Ns, isect->prim_id, isect->u, isect->v);
|
|
||||||
|
|
||||||
// Convert position and normal into world coordinate.
|
|
||||||
isect->t = t_world;
|
|
||||||
Matrix<T>::MultV(isect->P, node.xform_, local_P);
|
|
||||||
Matrix<T>::MultV(isect->Ng, node.inv_transpose_xform33_,
|
|
||||||
Ng);
|
|
||||||
Matrix<T>::MultV(isect->Ns, node.inv_transpose_xform33_,
|
|
||||||
Ns);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return has_hit;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Find a node by name.
|
|
||||||
///
|
|
||||||
bool FindNodeRecursive(const std::string &name, Node<T, M> *root, Node<T, M> **found_node) {
|
|
||||||
|
|
||||||
if (root->GetName().compare(name) == 0) {
|
|
||||||
(*found_node) = root;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simple exhaustive search.
|
|
||||||
for (size_t i = 0; i < root->GetChildren().size(); i++) {
|
|
||||||
if (FindNodeRecursive(name, &(root->GetChildren()[i]), found_node)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scene bounding box.
|
|
||||||
// Valid after calling `Commit()`.
|
|
||||||
T bmin_[3];
|
|
||||||
T bmax_[3];
|
|
||||||
|
|
||||||
// Toplevel BVH accel.
|
|
||||||
nanort::BVHAccel<T> toplevel_accel_;
|
|
||||||
std::vector<Node<T, M> > nodes_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace nanosg
|
|
||||||
|
|
||||||
#endif // NANOSG_H_
|
|
@ -1,109 +0,0 @@
|
|||||||
newoption {
|
|
||||||
trigger = "asan",
|
|
||||||
description = "Enable Address Sanitizer(gcc5+ ang clang only)"
|
|
||||||
}
|
|
||||||
|
|
||||||
sources = {
|
|
||||||
"main.cc",
|
|
||||||
"render.cc",
|
|
||||||
"render-config.cc",
|
|
||||||
"gltf-loader.cc",
|
|
||||||
"matrix.cc",
|
|
||||||
"../common/trackball.cc",
|
|
||||||
"../common/imgui/imgui.cpp",
|
|
||||||
"../common/imgui/imgui_draw.cpp",
|
|
||||||
"../common/imgui/imgui_impl_btgui.cpp",
|
|
||||||
"../common/imgui/ImGuizmo.cpp",
|
|
||||||
}
|
|
||||||
|
|
||||||
solution "RaytraceSolution"
|
|
||||||
configurations { "Release", "Debug" }
|
|
||||||
|
|
||||||
if os.is("Windows") then
|
|
||||||
platforms { "x64", "x32" }
|
|
||||||
else
|
|
||||||
platforms { "native", "x64", "x32" }
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- RootDir for OpenGLWindow
|
|
||||||
projectRootDir = os.getcwd() .. "/../common/"
|
|
||||||
dofile ("../common/findOpenGLGlewGlut.lua")
|
|
||||||
initOpenGL()
|
|
||||||
initGlew()
|
|
||||||
|
|
||||||
-- Use c++11
|
|
||||||
flags { "c++11" }
|
|
||||||
|
|
||||||
-- A project defines one build target
|
|
||||||
project "viwewer"
|
|
||||||
kind "ConsoleApp"
|
|
||||||
language "C++"
|
|
||||||
files { sources }
|
|
||||||
|
|
||||||
includedirs { "./", "../../" }
|
|
||||||
includedirs { "../common" }
|
|
||||||
includedirs { "../common/imgui" }
|
|
||||||
includedirs { "../common/glm" }
|
|
||||||
--includedirs { "../common/nativefiledialog/src/include" }
|
|
||||||
|
|
||||||
if _OPTIONS['asan'] then
|
|
||||||
buildoptions { "-fsanitize=address" }
|
|
||||||
linkoptions { "-fsanitize=address" }
|
|
||||||
end
|
|
||||||
|
|
||||||
if os.is("Windows") then
|
|
||||||
flags { "FatalCompileWarnings" }
|
|
||||||
warnings "Extra" -- /W4
|
|
||||||
|
|
||||||
defines { "NOMINMAX" }
|
|
||||||
defines { "USE_NATIVEFILEDIALOG" }
|
|
||||||
buildoptions { "/W4" } -- raise compile error level.
|
|
||||||
files{
|
|
||||||
"../common/OpenGLWindow/Win32OpenGLWindow.cpp",
|
|
||||||
"../common/OpenGLWindow/Win32OpenGLWindow.h",
|
|
||||||
"../common/OpenGLWindow/Win32Window.cpp",
|
|
||||||
"../common/OpenGLWindow/Win32Window.h",
|
|
||||||
}
|
|
||||||
includedirs { "./../common/nativefiledialog/src/include" }
|
|
||||||
files { "../common/nativefiledialog/src/nfd_common.c",
|
|
||||||
"../common/nativefiledialog/src/nfd_win.cpp" }
|
|
||||||
end
|
|
||||||
if os.is("Linux") then
|
|
||||||
files {
|
|
||||||
"../common/OpenGLWindow/X11OpenGLWindow.cpp",
|
|
||||||
"../common/OpenGLWindow/X11OpenGLWindows.h"
|
|
||||||
}
|
|
||||||
links {"X11", "pthread", "dl"}
|
|
||||||
if _OPTIONS["with-gtk3nfd"] then
|
|
||||||
defines { "USE_NATIVEFILEDIALOG" }
|
|
||||||
includedirs { "./../common/nativefiledialog/src/include" }
|
|
||||||
files { "../common/nativefiledialog/src/nfd_gtk.c",
|
|
||||||
"../common/nativefiledialog/src/nfd_common.c"
|
|
||||||
}
|
|
||||||
buildoptions { "`pkg-config --cflags gtk+-3.0`" }
|
|
||||||
linkoptions { "`pkg-config --libs gtk+-3.0`" }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if os.is("MacOSX") then
|
|
||||||
defines { "USE_NATIVEFILEDIALOG" }
|
|
||||||
links {"Cocoa.framework"}
|
|
||||||
files {
|
|
||||||
"../common/OpenGLWindow/MacOpenGLWindow.h",
|
|
||||||
"../common/OpenGLWindow/MacOpenGLWindow.mm",
|
|
||||||
}
|
|
||||||
includedirs { "./../common/nativefiledialog/src/include" }
|
|
||||||
files { "../common/nativefiledialog/src/nfd_cocoa.m",
|
|
||||||
"../common/nativefiledialog/src/nfd_common.c" }
|
|
||||||
end
|
|
||||||
|
|
||||||
configuration "Debug"
|
|
||||||
defines { "DEBUG" } -- -DDEBUG
|
|
||||||
symbols "On"
|
|
||||||
targetname "view_debug"
|
|
||||||
|
|
||||||
configuration "Release"
|
|
||||||
-- defines { "NDEBUG" } -- -NDEBUG
|
|
||||||
symbols "On"
|
|
||||||
optimize "On"
|
|
||||||
targetname "view"
|
|
@ -1,110 +0,0 @@
|
|||||||
#include "render-config.h"
|
|
||||||
|
|
||||||
#include "picojson.h"
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <istream>
|
|
||||||
|
|
||||||
namespace example {
|
|
||||||
|
|
||||||
bool LoadRenderConfig(example::RenderConfig* config, const char* filename) {
|
|
||||||
std::ifstream is(filename);
|
|
||||||
if (is.fail()) {
|
|
||||||
std::cerr << "Cannot open " << filename << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::istream_iterator<char> input(is);
|
|
||||||
std::string err;
|
|
||||||
picojson::value v;
|
|
||||||
input = picojson::parse(v, input, std::istream_iterator<char>(), &err);
|
|
||||||
if (!err.empty()) {
|
|
||||||
std::cerr << err << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!v.is<picojson::object>()) {
|
|
||||||
std::cerr << "Not a JSON object" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
picojson::object o = v.get<picojson::object>();
|
|
||||||
|
|
||||||
if (o.find("gltf_filename") != o.end()) {
|
|
||||||
if (o["gltf_filename"].is<std::string>()) {
|
|
||||||
config->gltf_filename = o["gltf_filename"].get<std::string>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
config->scene_scale = 1.0f;
|
|
||||||
if (o.find("scene_scale") != o.end()) {
|
|
||||||
if (o["scene_scale"].is<double>()) {
|
|
||||||
config->scene_scale = static_cast<float>(o["scene_scale"].get<double>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
config->eye[0] = 0.0f;
|
|
||||||
config->eye[1] = 0.0f;
|
|
||||||
config->eye[2] = 5.0f;
|
|
||||||
if (o.find("eye") != o.end()) {
|
|
||||||
if (o["eye"].is<picojson::array>()) {
|
|
||||||
picojson::array arr = o["eye"].get<picojson::array>();
|
|
||||||
if (arr.size() == 3) {
|
|
||||||
config->eye[0] = static_cast<float>(arr[0].get<double>());
|
|
||||||
config->eye[1] = static_cast<float>(arr[1].get<double>());
|
|
||||||
config->eye[2] = static_cast<float>(arr[2].get<double>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
config->up[0] = 0.0f;
|
|
||||||
config->up[1] = 1.0f;
|
|
||||||
config->up[2] = 0.0f;
|
|
||||||
if (o.find("up") != o.end()) {
|
|
||||||
if (o["up"].is<picojson::array>()) {
|
|
||||||
picojson::array arr = o["up"].get<picojson::array>();
|
|
||||||
if (arr.size() == 3) {
|
|
||||||
config->up[0] = static_cast<float>(arr[0].get<double>());
|
|
||||||
config->up[1] = static_cast<float>(arr[1].get<double>());
|
|
||||||
config->up[2] = static_cast<float>(arr[2].get<double>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
config->look_at[0] = 0.0f;
|
|
||||||
config->look_at[1] = 0.0f;
|
|
||||||
config->look_at[2] = 0.0f;
|
|
||||||
if (o.find("look_at") != o.end()) {
|
|
||||||
if (o["look_at"].is<picojson::array>()) {
|
|
||||||
picojson::array arr = o["look_at"].get<picojson::array>();
|
|
||||||
if (arr.size() == 3) {
|
|
||||||
config->look_at[0] = static_cast<float>(arr[0].get<double>());
|
|
||||||
config->look_at[1] = static_cast<float>(arr[1].get<double>());
|
|
||||||
config->look_at[2] = static_cast<float>(arr[2].get<double>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
config->fov = 45.0f;
|
|
||||||
if (o.find("fov") != o.end()) {
|
|
||||||
if (o["fov"].is<double>()) {
|
|
||||||
config->fov = static_cast<float>(o["fov"].get<double>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
config->width = 512;
|
|
||||||
if (o.find("width") != o.end()) {
|
|
||||||
if (o["width"].is<double>()) {
|
|
||||||
config->width = static_cast<int>(o["width"].get<double>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
config->height = 512;
|
|
||||||
if (o.find("height") != o.end()) {
|
|
||||||
if (o["height"].is<double>()) {
|
|
||||||
config->height = static_cast<int>(o["height"].get<double>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
#ifndef RENDER_CONFIG_H
|
|
||||||
#define RENDER_CONFIG_H
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace example {
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
// framebuffer
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
|
|
||||||
// camera
|
|
||||||
float eye[3];
|
|
||||||
float up[3];
|
|
||||||
float look_at[3];
|
|
||||||
float fov; // vertical fov in degree.
|
|
||||||
|
|
||||||
// render pass
|
|
||||||
int pass;
|
|
||||||
int max_passes;
|
|
||||||
|
|
||||||
// For debugging. Array size = width * height * 4.
|
|
||||||
float *normalImage;
|
|
||||||
float *positionImage;
|
|
||||||
float *depthImage;
|
|
||||||
float *texcoordImage;
|
|
||||||
float *varycoordImage;
|
|
||||||
|
|
||||||
// Scene input info
|
|
||||||
std::string gltf_filename;
|
|
||||||
float scene_scale;
|
|
||||||
|
|
||||||
} RenderConfig;
|
|
||||||
|
|
||||||
/// Loads config from JSON file.
|
|
||||||
bool LoadRenderConfig(example::RenderConfig *config, const char *filename);
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
#endif // RENDER_CONFIG_H
|
|
@ -1,512 +0,0 @@
|
|||||||
/*
|
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2015 - 2016 Light Transport Entertainment, Inc.
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#pragma warning(disable : 4018)
|
|
||||||
#pragma warning(disable : 4244)
|
|
||||||
#pragma warning(disable : 4189)
|
|
||||||
#pragma warning(disable : 4996)
|
|
||||||
#pragma warning(disable : 4267)
|
|
||||||
#pragma warning(disable : 4477)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "render.h"
|
|
||||||
|
|
||||||
#include <chrono> // C++11
|
|
||||||
#include <sstream>
|
|
||||||
#include <thread> // C++11
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "nanort.h"
|
|
||||||
#include "matrix.h"
|
|
||||||
#include "material.h"
|
|
||||||
#include "mesh.h"
|
|
||||||
|
|
||||||
|
|
||||||
#include "trackball.h"
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
#undef min
|
|
||||||
#undef max
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace example {
|
|
||||||
|
|
||||||
// PCG32 code / (c) 2014 M.E. O'Neill / pcg-random.org
|
|
||||||
// Licensed under Apache License 2.0 (NO WARRANTY, etc. see website)
|
|
||||||
// http://www.pcg-random.org/
|
|
||||||
typedef struct {
|
|
||||||
unsigned long long state;
|
|
||||||
unsigned long long inc; // not used?
|
|
||||||
} pcg32_state_t;
|
|
||||||
|
|
||||||
#define PCG32_INITIALIZER \
|
|
||||||
{ 0x853c49e6748fea9bULL, 0xda3e39cb94b95bdbULL }
|
|
||||||
|
|
||||||
float pcg32_random(pcg32_state_t* rng) {
|
|
||||||
unsigned long long oldstate = rng->state;
|
|
||||||
rng->state = oldstate * 6364136223846793005ULL + rng->inc;
|
|
||||||
unsigned int xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
|
|
||||||
unsigned int rot = oldstate >> 59u;
|
|
||||||
unsigned int ret = (xorshifted >> rot) | (xorshifted << ((-static_cast<int>(rot)) & 31));
|
|
||||||
|
|
||||||
return (float)((double)ret / (double)4294967296.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pcg32_srandom(pcg32_state_t* rng, uint64_t initstate, uint64_t initseq) {
|
|
||||||
rng->state = 0U;
|
|
||||||
rng->inc = (initseq << 1U) | 1U;
|
|
||||||
pcg32_random(rng);
|
|
||||||
rng->state += initstate;
|
|
||||||
pcg32_random(rng);
|
|
||||||
}
|
|
||||||
|
|
||||||
const float kPI = 3.141592f;
|
|
||||||
|
|
||||||
typedef nanort::real3<float> float3;
|
|
||||||
|
|
||||||
inline float3 Lerp3(float3 v0, float3 v1, float3 v2, float u, float v) {
|
|
||||||
return (1.0f - u - v) * v0 + u * v1 + v * v2;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void CalcNormal(float3& N, float3 v0, float3 v1, float3 v2) {
|
|
||||||
float3 v10 = v1 - v0;
|
|
||||||
float3 v20 = v2 - v0;
|
|
||||||
|
|
||||||
N = vcross(v20, v10);
|
|
||||||
N = vnormalize(N);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuildCameraFrame(float3* origin, float3* corner, float3* u, float3* v,
|
|
||||||
float quat[4], float eye[3], float lookat[3], float up[3],
|
|
||||||
float fov, int width, int height) {
|
|
||||||
float e[4][4];
|
|
||||||
|
|
||||||
Matrix::LookAt(e, eye, lookat, up);
|
|
||||||
|
|
||||||
float r[4][4];
|
|
||||||
build_rotmatrix(r, quat);
|
|
||||||
|
|
||||||
float3 lo;
|
|
||||||
lo[0] = lookat[0] - eye[0];
|
|
||||||
lo[1] = lookat[1] - eye[1];
|
|
||||||
lo[2] = lookat[2] - eye[2];
|
|
||||||
float dist = vlength(lo);
|
|
||||||
|
|
||||||
float dir[3];
|
|
||||||
dir[0] = 0.0;
|
|
||||||
dir[1] = 0.0;
|
|
||||||
dir[2] = dist;
|
|
||||||
|
|
||||||
Matrix::Inverse(r);
|
|
||||||
|
|
||||||
float rr[4][4];
|
|
||||||
float re[4][4];
|
|
||||||
float zero[3] = {0.0f, 0.0f, 0.0f};
|
|
||||||
float localUp[3] = {0.0f, 1.0f, 0.0f};
|
|
||||||
Matrix::LookAt(re, dir, zero, localUp);
|
|
||||||
|
|
||||||
// translate
|
|
||||||
re[3][0] += eye[0]; // 0.0; //lo[0];
|
|
||||||
re[3][1] += eye[1]; // 0.0; //lo[1];
|
|
||||||
re[3][2] += (eye[2] - dist);
|
|
||||||
|
|
||||||
// rot -> trans
|
|
||||||
Matrix::Mult(rr, r, re);
|
|
||||||
|
|
||||||
float m[4][4];
|
|
||||||
for (int j = 0; j < 4; j++) {
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
m[j][i] = rr[j][i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float vzero[3] = {0.0f, 0.0f, 0.0f};
|
|
||||||
float eye1[3];
|
|
||||||
Matrix::MultV(eye1, m, vzero);
|
|
||||||
|
|
||||||
float lookat1d[3];
|
|
||||||
dir[2] = -dir[2];
|
|
||||||
Matrix::MultV(lookat1d, m, dir);
|
|
||||||
float3 lookat1(lookat1d[0], lookat1d[1], lookat1d[2]);
|
|
||||||
|
|
||||||
float up1d[3];
|
|
||||||
Matrix::MultV(up1d, m, up);
|
|
||||||
|
|
||||||
float3 up1(up1d[0], up1d[1], up1d[2]);
|
|
||||||
|
|
||||||
// absolute -> relative
|
|
||||||
up1[0] -= eye1[0];
|
|
||||||
up1[1] -= eye1[1];
|
|
||||||
up1[2] -= eye1[2];
|
|
||||||
// printf("up1(after) = %f, %f, %f\n", up1[0], up1[1], up1[2]);
|
|
||||||
|
|
||||||
// Use original up vector
|
|
||||||
// up1[0] = up[0];
|
|
||||||
// up1[1] = up[1];
|
|
||||||
// up1[2] = up[2];
|
|
||||||
|
|
||||||
{
|
|
||||||
float flen =
|
|
||||||
(0.5f * (float)height / tanf(0.5f * (float)(fov * kPI / 180.0f)));
|
|
||||||
float3 look1;
|
|
||||||
look1[0] = lookat1[0] - eye1[0];
|
|
||||||
look1[1] = lookat1[1] - eye1[1];
|
|
||||||
look1[2] = lookat1[2] - eye1[2];
|
|
||||||
// vcross(u, up1, look1);
|
|
||||||
// flip
|
|
||||||
(*u) = nanort::vcross(look1, up1);
|
|
||||||
(*u) = vnormalize((*u));
|
|
||||||
|
|
||||||
(*v) = vcross(look1, (*u));
|
|
||||||
(*v) = vnormalize((*v));
|
|
||||||
|
|
||||||
look1 = vnormalize(look1);
|
|
||||||
look1[0] = flen * look1[0] + eye1[0];
|
|
||||||
look1[1] = flen * look1[1] + eye1[1];
|
|
||||||
look1[2] = flen * look1[2] + eye1[2];
|
|
||||||
(*corner)[0] = look1[0] - 0.5f * (width * (*u)[0] + height * (*v)[0]);
|
|
||||||
(*corner)[1] = look1[1] - 0.5f * (width * (*u)[1] + height * (*v)[1]);
|
|
||||||
(*corner)[2] = look1[2] - 0.5f * (width * (*u)[2] + height * (*v)[2]);
|
|
||||||
|
|
||||||
(*origin)[0] = eye1[0];
|
|
||||||
(*origin)[1] = eye1[1];
|
|
||||||
(*origin)[2] = eye1[2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nanort::Ray<float> GenerateRay(const float3& origin, const float3& corner,
|
|
||||||
const float3& du, const float3& dv, float u,
|
|
||||||
float v) {
|
|
||||||
float3 dir;
|
|
||||||
|
|
||||||
dir[0] = (corner[0] + u * du[0] + v * dv[0]) - origin[0];
|
|
||||||
dir[1] = (corner[1] + u * du[1] + v * dv[1]) - origin[1];
|
|
||||||
dir[2] = (corner[2] + u * du[2] + v * dv[2]) - origin[2];
|
|
||||||
dir = vnormalize(dir);
|
|
||||||
|
|
||||||
float3 org;
|
|
||||||
|
|
||||||
nanort::Ray<float> ray;
|
|
||||||
ray.org[0] = origin[0];
|
|
||||||
ray.org[1] = origin[1];
|
|
||||||
ray.org[2] = origin[2];
|
|
||||||
ray.dir[0] = dir[0];
|
|
||||||
|
|
||||||
return ray;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FetchTexture(const Texture &texture, float u, float v, float* col) {
|
|
||||||
int tx = u * texture.width;
|
|
||||||
int ty = (1.0f - v) * texture.height;
|
|
||||||
int idx_offset = (ty * texture.width + tx) * texture.components;
|
|
||||||
col[0] = texture.image[idx_offset + 0] / 255.f;
|
|
||||||
col[1] = texture.image[idx_offset + 1] / 255.f;
|
|
||||||
col[2] = texture.image[idx_offset + 2] / 255.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Renderer::Render(float* rgba, float* aux_rgba, int* sample_counts,
|
|
||||||
float quat[4],
|
|
||||||
const nanosg::Scene<float, example::Mesh<float>> &scene,
|
|
||||||
const example::Asset &asset,
|
|
||||||
const RenderConfig& config,
|
|
||||||
std::atomic<bool>& cancelFlag) {
|
|
||||||
//if (!gAccel.IsValid()) {
|
|
||||||
// return false;
|
|
||||||
//}
|
|
||||||
|
|
||||||
int width = config.width;
|
|
||||||
int height = config.height;
|
|
||||||
|
|
||||||
// camera
|
|
||||||
float eye[3] = {config.eye[0], config.eye[1], config.eye[2]};
|
|
||||||
float look_at[3] = {config.look_at[0], config.look_at[1], config.look_at[2]};
|
|
||||||
float up[3] = {config.up[0], config.up[1], config.up[2]};
|
|
||||||
float fov = config.fov;
|
|
||||||
float3 origin, corner, u, v;
|
|
||||||
BuildCameraFrame(&origin, &corner, &u, &v, quat, eye, look_at, up, fov, width,
|
|
||||||
height);
|
|
||||||
|
|
||||||
auto kCancelFlagCheckMilliSeconds = 300;
|
|
||||||
|
|
||||||
std::vector<std::thread> workers;
|
|
||||||
std::atomic<int> i(0);
|
|
||||||
|
|
||||||
uint32_t num_threads = std::max(1U, std::thread::hardware_concurrency());
|
|
||||||
|
|
||||||
auto startT = std::chrono::system_clock::now();
|
|
||||||
|
|
||||||
// Initialize RNG.
|
|
||||||
|
|
||||||
for (auto t = 0; t < num_threads; t++) {
|
|
||||||
workers.emplace_back(std::thread([&, t]() {
|
|
||||||
pcg32_state_t rng;
|
|
||||||
pcg32_srandom(&rng, config.pass,
|
|
||||||
t); // seed = combination of render pass + thread no.
|
|
||||||
|
|
||||||
int y = 0;
|
|
||||||
while ((y = i++) < config.height) {
|
|
||||||
auto currT = std::chrono::system_clock::now();
|
|
||||||
|
|
||||||
std::chrono::duration<double, std::milli> ms = currT - startT;
|
|
||||||
// Check cancel flag
|
|
||||||
if (ms.count() > kCancelFlagCheckMilliSeconds) {
|
|
||||||
if (cancelFlag) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw dash line to aux buffer for progress.
|
|
||||||
// for (int x = 0; x < config.width; x++) {
|
|
||||||
// float c = (x / 8) % 2;
|
|
||||||
// aux_rgba[4*(y*config.width+x)+0] = c;
|
|
||||||
// aux_rgba[4*(y*config.width+x)+1] = c;
|
|
||||||
// aux_rgba[4*(y*config.width+x)+2] = c;
|
|
||||||
// aux_rgba[4*(y*config.width+x)+3] = 0.0f;
|
|
||||||
//}
|
|
||||||
|
|
||||||
for (int x = 0; x < config.width; x++) {
|
|
||||||
nanort::Ray<float> ray;
|
|
||||||
ray.org[0] = origin[0];
|
|
||||||
ray.org[1] = origin[1];
|
|
||||||
ray.org[2] = origin[2];
|
|
||||||
|
|
||||||
float u0 = pcg32_random(&rng);
|
|
||||||
float u1 = pcg32_random(&rng);
|
|
||||||
|
|
||||||
float3 dir;
|
|
||||||
dir = corner + (float(x) + u0) * u +
|
|
||||||
(float(config.height - y - 1) + u1) * v;
|
|
||||||
dir = vnormalize(dir);
|
|
||||||
ray.dir[0] = dir[0];
|
|
||||||
ray.dir[1] = dir[1];
|
|
||||||
ray.dir[2] = dir[2];
|
|
||||||
|
|
||||||
float kFar = 1.0e+30f;
|
|
||||||
ray.min_t = 0.0f;
|
|
||||||
ray.max_t = kFar;
|
|
||||||
|
|
||||||
|
|
||||||
nanosg::Intersection<float> isect;
|
|
||||||
bool hit = scene.Traverse(ray, &isect, /* cull_back_face */false);
|
|
||||||
|
|
||||||
if (hit) {
|
|
||||||
|
|
||||||
const std::vector<Material> &materials = asset.materials;
|
|
||||||
const std::vector<Texture> &textures = asset.textures;
|
|
||||||
const Mesh<float> &mesh = asset.meshes[isect.node_id];
|
|
||||||
|
|
||||||
float3 p;
|
|
||||||
p[0] =
|
|
||||||
ray.org[0] + isect.t * ray.dir[0];
|
|
||||||
p[1] =
|
|
||||||
ray.org[1] + isect.t * ray.dir[1];
|
|
||||||
p[2] =
|
|
||||||
ray.org[2] + isect.t * ray.dir[2];
|
|
||||||
|
|
||||||
config.positionImage[4 * (y * config.width + x) + 0] = p.x();
|
|
||||||
config.positionImage[4 * (y * config.width + x) + 1] = p.y();
|
|
||||||
config.positionImage[4 * (y * config.width + x) + 2] = p.z();
|
|
||||||
config.positionImage[4 * (y * config.width + x) + 3] = 1.0f;
|
|
||||||
|
|
||||||
config.varycoordImage[4 * (y * config.width + x) + 0] =
|
|
||||||
isect.u;
|
|
||||||
config.varycoordImage[4 * (y * config.width + x) + 1] =
|
|
||||||
isect.v;
|
|
||||||
config.varycoordImage[4 * (y * config.width + x) + 2] = 0.0f;
|
|
||||||
config.varycoordImage[4 * (y * config.width + x) + 3] = 1.0f;
|
|
||||||
|
|
||||||
unsigned int prim_id = isect.prim_id;
|
|
||||||
|
|
||||||
float3 N;
|
|
||||||
if (mesh.facevarying_normals.size() > 0) {
|
|
||||||
float3 n0, n1, n2;
|
|
||||||
n0[0] = mesh.facevarying_normals[9 * prim_id + 0];
|
|
||||||
n0[1] = mesh.facevarying_normals[9 * prim_id + 1];
|
|
||||||
n0[2] = mesh.facevarying_normals[9 * prim_id + 2];
|
|
||||||
n1[0] = mesh.facevarying_normals[9 * prim_id + 3];
|
|
||||||
n1[1] = mesh.facevarying_normals[9 * prim_id + 4];
|
|
||||||
n1[2] = mesh.facevarying_normals[9 * prim_id + 5];
|
|
||||||
n2[0] = mesh.facevarying_normals[9 * prim_id + 6];
|
|
||||||
n2[1] = mesh.facevarying_normals[9 * prim_id + 7];
|
|
||||||
n2[2] = mesh.facevarying_normals[9 * prim_id + 8];
|
|
||||||
N = Lerp3(n0, n1, n2, isect.u, isect.v);
|
|
||||||
} else {
|
|
||||||
unsigned int f0, f1, f2;
|
|
||||||
f0 = mesh.faces[3 * prim_id + 0];
|
|
||||||
f1 = mesh.faces[3 * prim_id + 1];
|
|
||||||
f2 = mesh.faces[3 * prim_id + 2];
|
|
||||||
|
|
||||||
float3 v0, v1, v2;
|
|
||||||
v0[0] = mesh.vertices[3 * f0 + 0];
|
|
||||||
v0[1] = mesh.vertices[3 * f0 + 1];
|
|
||||||
v0[2] = mesh.vertices[3 * f0 + 2];
|
|
||||||
v1[0] = mesh.vertices[3 * f1 + 0];
|
|
||||||
v1[1] = mesh.vertices[3 * f1 + 1];
|
|
||||||
v1[2] = mesh.vertices[3 * f1 + 2];
|
|
||||||
v2[0] = mesh.vertices[3 * f2 + 0];
|
|
||||||
v2[1] = mesh.vertices[3 * f2 + 1];
|
|
||||||
v2[2] = mesh.vertices[3 * f2 + 2];
|
|
||||||
CalcNormal(N, v0, v1, v2);
|
|
||||||
}
|
|
||||||
|
|
||||||
config.normalImage[4 * (y * config.width + x) + 0] =
|
|
||||||
0.5f * N[0] + 0.5f;
|
|
||||||
config.normalImage[4 * (y * config.width + x) + 1] =
|
|
||||||
0.5f * N[1] + 0.5f;
|
|
||||||
config.normalImage[4 * (y * config.width + x) + 2] =
|
|
||||||
0.5f * N[2] + 0.5f;
|
|
||||||
config.normalImage[4 * (y * config.width + x) + 3] = 1.0f;
|
|
||||||
|
|
||||||
config.depthImage[4 * (y * config.width + x) + 0] =
|
|
||||||
isect.t;
|
|
||||||
config.depthImage[4 * (y * config.width + x) + 1] =
|
|
||||||
isect.t;
|
|
||||||
config.depthImage[4 * (y * config.width + x) + 2] =
|
|
||||||
isect.t;
|
|
||||||
config.depthImage[4 * (y * config.width + x) + 3] = 1.0f;
|
|
||||||
|
|
||||||
float3 UV;
|
|
||||||
if (mesh.facevarying_uvs.size() > 0) {
|
|
||||||
float3 uv0, uv1, uv2;
|
|
||||||
uv0[0] = mesh.facevarying_uvs[6 * prim_id + 0];
|
|
||||||
uv0[1] = mesh.facevarying_uvs[6 * prim_id + 1];
|
|
||||||
uv1[0] = mesh.facevarying_uvs[6 * prim_id + 2];
|
|
||||||
uv1[1] = mesh.facevarying_uvs[6 * prim_id + 3];
|
|
||||||
uv2[0] = mesh.facevarying_uvs[6 * prim_id + 4];
|
|
||||||
uv2[1] = mesh.facevarying_uvs[6 * prim_id + 5];
|
|
||||||
|
|
||||||
UV = Lerp3(uv0, uv1, uv2, isect.u, isect.v);
|
|
||||||
|
|
||||||
config.texcoordImage[4 * (y * config.width + x) + 0] = UV[0];
|
|
||||||
config.texcoordImage[4 * (y * config.width + x) + 1] = UV[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch texture
|
|
||||||
unsigned int material_id =
|
|
||||||
mesh.material_ids[isect.prim_id];
|
|
||||||
|
|
||||||
float diffuse_col[3];
|
|
||||||
int diffuse_texid = materials[material_id].diffuse_texid;
|
|
||||||
if (diffuse_texid >= 0) {
|
|
||||||
FetchTexture(textures[diffuse_texid], UV[0], UV[1], diffuse_col);
|
|
||||||
} else {
|
|
||||||
diffuse_col[0] = materials[material_id].diffuse[0];
|
|
||||||
diffuse_col[1] = materials[material_id].diffuse[1];
|
|
||||||
diffuse_col[2] = materials[material_id].diffuse[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
float specular_col[3];
|
|
||||||
int specular_texid = materials[material_id].specular_texid;
|
|
||||||
if (specular_texid >= 0) {
|
|
||||||
FetchTexture(textures[specular_texid], UV[0], UV[1], specular_col);
|
|
||||||
} else {
|
|
||||||
specular_col[0] = materials[material_id].specular[0];
|
|
||||||
specular_col[1] = materials[material_id].specular[1];
|
|
||||||
specular_col[2] = materials[material_id].specular[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simple shading
|
|
||||||
float NdotV = fabsf(vdot(N, dir));
|
|
||||||
|
|
||||||
if (config.pass == 0) {
|
|
||||||
rgba[4 * (y * config.width + x) + 0] = NdotV * diffuse_col[0];
|
|
||||||
rgba[4 * (y * config.width + x) + 1] = NdotV * diffuse_col[1];
|
|
||||||
rgba[4 * (y * config.width + x) + 2] = NdotV * diffuse_col[2];
|
|
||||||
rgba[4 * (y * config.width + x) + 3] = 1.0f;
|
|
||||||
sample_counts[y * config.width + x] =
|
|
||||||
1; // Set 1 for the first pass
|
|
||||||
} else { // additive.
|
|
||||||
rgba[4 * (y * config.width + x) + 0] += NdotV * diffuse_col[0];
|
|
||||||
rgba[4 * (y * config.width + x) + 1] += NdotV * diffuse_col[1];
|
|
||||||
rgba[4 * (y * config.width + x) + 2] += NdotV * diffuse_col[2];
|
|
||||||
rgba[4 * (y * config.width + x) + 3] += 1.0f;
|
|
||||||
sample_counts[y * config.width + x]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
{
|
|
||||||
if (config.pass == 0) {
|
|
||||||
// clear pixel
|
|
||||||
rgba[4 * (y * config.width + x) + 0] = 0.0f;
|
|
||||||
rgba[4 * (y * config.width + x) + 1] = 0.0f;
|
|
||||||
rgba[4 * (y * config.width + x) + 2] = 0.0f;
|
|
||||||
rgba[4 * (y * config.width + x) + 3] = 0.0f;
|
|
||||||
aux_rgba[4 * (y * config.width + x) + 0] = 0.0f;
|
|
||||||
aux_rgba[4 * (y * config.width + x) + 1] = 0.0f;
|
|
||||||
aux_rgba[4 * (y * config.width + x) + 2] = 0.0f;
|
|
||||||
aux_rgba[4 * (y * config.width + x) + 3] = 0.0f;
|
|
||||||
sample_counts[y * config.width + x] =
|
|
||||||
1; // Set 1 for the first pass
|
|
||||||
} else {
|
|
||||||
sample_counts[y * config.width + x]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No super sampling
|
|
||||||
config.normalImage[4 * (y * config.width + x) + 0] = 0.0f;
|
|
||||||
config.normalImage[4 * (y * config.width + x) + 1] = 0.0f;
|
|
||||||
config.normalImage[4 * (y * config.width + x) + 2] = 0.0f;
|
|
||||||
config.normalImage[4 * (y * config.width + x) + 3] = 0.0f;
|
|
||||||
config.positionImage[4 * (y * config.width + x) + 0] = 0.0f;
|
|
||||||
config.positionImage[4 * (y * config.width + x) + 1] = 0.0f;
|
|
||||||
config.positionImage[4 * (y * config.width + x) + 2] = 0.0f;
|
|
||||||
config.positionImage[4 * (y * config.width + x) + 3] = 0.0f;
|
|
||||||
config.depthImage[4 * (y * config.width + x) + 0] = 0.0f;
|
|
||||||
config.depthImage[4 * (y * config.width + x) + 1] = 0.0f;
|
|
||||||
config.depthImage[4 * (y * config.width + x) + 2] = 0.0f;
|
|
||||||
config.depthImage[4 * (y * config.width + x) + 3] = 0.0f;
|
|
||||||
config.texcoordImage[4 * (y * config.width + x) + 0] = 0.0f;
|
|
||||||
config.texcoordImage[4 * (y * config.width + x) + 1] = 0.0f;
|
|
||||||
config.texcoordImage[4 * (y * config.width + x) + 2] = 0.0f;
|
|
||||||
config.texcoordImage[4 * (y * config.width + x) + 3] = 0.0f;
|
|
||||||
config.varycoordImage[4 * (y * config.width + x) + 0] = 0.0f;
|
|
||||||
config.varycoordImage[4 * (y * config.width + x) + 1] = 0.0f;
|
|
||||||
config.varycoordImage[4 * (y * config.width + x) + 2] = 0.0f;
|
|
||||||
config.varycoordImage[4 * (y * config.width + x) + 3] = 0.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int x = 0; x < config.width; x++) {
|
|
||||||
aux_rgba[4 * (y * config.width + x) + 0] = 0.0f;
|
|
||||||
aux_rgba[4 * (y * config.width + x) + 1] = 0.0f;
|
|
||||||
aux_rgba[4 * (y * config.width + x) + 2] = 0.0f;
|
|
||||||
aux_rgba[4 * (y * config.width + x) + 3] = 0.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& t : workers) {
|
|
||||||
t.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (!cancelFlag);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace example
|
|
@ -1,30 +0,0 @@
|
|||||||
#ifndef EXAMPLE_RENDER_H_
|
|
||||||
#define EXAMPLE_RENDER_H_
|
|
||||||
|
|
||||||
#include <atomic> // C++11
|
|
||||||
|
|
||||||
#include "render-config.h"
|
|
||||||
#include "nanosg.h"
|
|
||||||
#include "mesh.h"
|
|
||||||
#include "material.h"
|
|
||||||
|
|
||||||
namespace example {
|
|
||||||
|
|
||||||
struct Asset {
|
|
||||||
std::vector<Mesh<float> > meshes;
|
|
||||||
std::vector<Material> materials;
|
|
||||||
std::vector<Texture> textures;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Renderer {
|
|
||||||
public:
|
|
||||||
Renderer() {}
|
|
||||||
~Renderer() {}
|
|
||||||
|
|
||||||
/// Returns false when the rendering was canceled.
|
|
||||||
static bool Render(float* rgba, float* aux_rgba, int *sample_counts, float quat[4],
|
|
||||||
const nanosg::Scene<float, Mesh<float>> &scene, const Asset &asset, const RenderConfig& config, std::atomic<bool>& cancel_flag);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // EXAMPLE_RENDER_H_
|
|
Loading…
x
Reference in New Issue
Block a user