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:
Arthur Brainville (Ybalrid) 2018-02-18 19:13:57 +01:00
parent c7ae1a3e76
commit fb7ebb955e
No known key found for this signature in database
GPG Key ID: BC05C4812A06BCF3
13 changed files with 0 additions and 5453 deletions

View File

@ -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

View File

@ -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

View File

@ -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_

View File

@ -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]);
}

View File

@ -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

View File

@ -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_

View File

@ -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"

View File

@ -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;
}
}

View File

@ -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

View File

@ -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

View File

@ -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_