mirror of
https://git.mirrors.martin98.com/https://github.com/syoyo/tinygltf.git
synced 2025-06-04 11:25:59 +08:00
Add the current code of nanort + nanosg
This implementation will be based on commit b31dc0bd92eb7ac896079849a2205fac4abbd087 from the nanort project Signed-off by: Arthur Brainville (Ybalrid) <ybalrid@ybalrid.info>
This commit is contained in:
parent
fb7ebb955e
commit
c81be8f87d
130
examples/raytrace/README.md
Normal file
130
examples/raytrace/README.md
Normal file
@ -0,0 +1,130 @@
|
||||
# NanoSG
|
||||
|
||||
Simple, minimal and header-only scene graph library for NanoRT.
|
||||
|
||||
NanoSG itself shoud be compiled with C++-03 compiler, but demo code uses C++11 features.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Build
|
||||
|
||||
### Linux or macOS
|
||||
|
||||
```
|
||||
$ premake5 gmake
|
||||
$ make
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
```
|
||||
$ premake5 vs2015
|
||||
```
|
||||
|
||||
## Data structure
|
||||
|
||||
### Node
|
||||
|
||||
Node represents scene graph node. Tansformation node or Mesh(shape) node.
|
||||
Node is interpreted as transformation node when passing `nullptr` to Node class constructure.
|
||||
|
||||
Node can contain multiple children.
|
||||
|
||||
### Scene
|
||||
|
||||
Scene contains root nodes and provides the method to find an intersection of nodes.
|
||||
|
||||
## User defined data structure
|
||||
|
||||
Following are required in user application.
|
||||
|
||||
### Mesh class
|
||||
|
||||
Current example code assumes mesh is all composed of triangle meshes.
|
||||
|
||||
Following method must be implemented for `Scene::Traversal`.
|
||||
|
||||
```
|
||||
///
|
||||
/// Get the geometric normal and the shading normal at `face_idx' th face.
|
||||
///
|
||||
template<typename T>
|
||||
void GetNormal(T Ng[3], T Ns[3], const unsigned int face_idx, const T u, const T v) const;
|
||||
```
|
||||
|
||||
### Intersection class
|
||||
|
||||
Represents intersection(hit) information.
|
||||
|
||||
### Transform
|
||||
|
||||
Transformation is done in the following procedure.
|
||||
|
||||
`M' = parent_xform x local_xform x local_pivot`
|
||||
|
||||
## Memory management
|
||||
|
||||
`Scene` and `Node` does not create a copy of asset data(e.g. vertices, indices). Thus user must care about memory management of scene assets in user side.
|
||||
|
||||
## API
|
||||
|
||||
API is still subject to change.
|
||||
|
||||
### Node
|
||||
|
||||
```
|
||||
void Node::SetName(const std::string &name);
|
||||
```
|
||||
|
||||
Set (unique) name for the node.
|
||||
|
||||
```
|
||||
void Node::AddChild(const type &child);
|
||||
```
|
||||
|
||||
Add node as child node.
|
||||
|
||||
```
|
||||
void Node::SetLocalXform(const T xform[4][4]) {
|
||||
```
|
||||
|
||||
Set local transformation matrix. Default is identity matrix.
|
||||
|
||||
### Scene
|
||||
|
||||
```
|
||||
bool Scene::AddNode(const Node<T, M> &node);
|
||||
```
|
||||
|
||||
Add a node to the scene.
|
||||
|
||||
```
|
||||
bool Scene::Commit() {
|
||||
```
|
||||
|
||||
Commit the scene. After adding nodes to the scene or changed transformation matrix, call this `Commit` before tracing rays.
|
||||
`Commit` triggers BVH build in each nodes and updates node's transformation matrix.
|
||||
|
||||
```
|
||||
template<class H>
|
||||
bool Scene::Traverse(nanort::Ray<T> &ray, H *isect, const bool cull_back_face = false) const;
|
||||
```
|
||||
|
||||
Trace ray into the scene and find an intersection.
|
||||
Returns `true` when there is an intersection and hit information is stored in `isect`.
|
||||
|
||||
## TODO
|
||||
|
||||
* [ ] Compute pivot point of each node(mesh).
|
||||
|
||||
## 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
|
BIN
examples/raytrace/bin/native/Release/view
Executable file
BIN
examples/raytrace/bin/native/Release/view
Executable file
Binary file not shown.
9
examples/raytrace/config.json
Normal file
9
examples/raytrace/config.json
Normal file
@ -0,0 +1,9 @@
|
||||
{ "obj_filename" : "../common/cornellbox_suzanne.obj",
|
||||
"scene_scale" : 1.0,
|
||||
"width" : 512,
|
||||
"height" : 512,
|
||||
"eye" : [0, 2.5, 15],
|
||||
"up" : [0, 1, 0],
|
||||
"look_at" : [0, 0, 0],
|
||||
"dummy" : 0
|
||||
}
|
BIN
examples/raytrace/images/nanosg-demo.png
Normal file
BIN
examples/raytrace/images/nanosg-demo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 122 KiB |
25
examples/raytrace/imgui.ini
Normal file
25
examples/raytrace/imgui.ini
Normal file
@ -0,0 +1,25 @@
|
||||
[Debug]
|
||||
Pos=60,60
|
||||
Size=400,400
|
||||
Collapsed=0
|
||||
|
||||
[UI]
|
||||
Pos=-41,636
|
||||
Size=469,191
|
||||
Collapsed=0
|
||||
|
||||
[Render]
|
||||
Pos=583,717
|
||||
Size=410,425
|
||||
Collapsed=0
|
||||
|
||||
[Scene]
|
||||
Pos=60,60
|
||||
Size=256,206
|
||||
Collapsed=0
|
||||
|
||||
[Transform]
|
||||
Pos=579,636
|
||||
Size=235,167
|
||||
Collapsed=0
|
||||
|
1032
examples/raytrace/main.cc
Normal file
1032
examples/raytrace/main.cc
Normal file
File diff suppressed because it is too large
Load Diff
75
examples/raytrace/material.h
Normal file
75
examples/raytrace/material.h
Normal file
@ -0,0 +1,75 @@
|
||||
#ifndef EXAMPLE_MATERIAL_H_
|
||||
#define EXAMPLE_MATERIAL_H_
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#if __has_warning("-Wzero-as-null-pointer-constant")
|
||||
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace example {
|
||||
|
||||
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;
|
||||
int _pad_;
|
||||
unsigned char* image;
|
||||
|
||||
Texture() {
|
||||
width = -1;
|
||||
height = -1;
|
||||
components = -1;
|
||||
image = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace example
|
||||
|
||||
|
||||
#endif // EXAMPLE_MATERIAL_H_
|
216
examples/raytrace/matrix.cc
Normal file
216
examples/raytrace/matrix.cc
Normal file
@ -0,0 +1,216 @@
|
||||
#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]);
|
||||
}
|
188
examples/raytrace/mesh.h
Normal file
188
examples/raytrace/mesh.h
Normal file
@ -0,0 +1,188 @@
|
||||
#ifndef EXAMPLE_MESH_H_
|
||||
#define EXAMPLE_MESH_H_
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
namespace example {
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline void lerp(T dst[3], const T v0[3], const T v1[3], const T v2[3], float u, float v) {
|
||||
dst[0] = (static_cast<T>(1.0) - u - v) * v0[0] + u * v1[0] + v * v2[0];
|
||||
dst[1] = (static_cast<T>(1.0) - u - v) * v0[1] + u * v1[1] + v * v2[1];
|
||||
dst[2] = (static_cast<T>(1.0) - u - v) * v0[2] + u * v1[2] + v * v2[2];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T vlength(const T v[3]) {
|
||||
const T d = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
|
||||
if (std::fabs(d) > std::numeric_limits<T>::epsilon()) {
|
||||
return std::sqrt(d);
|
||||
} else {
|
||||
return static_cast<T>(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void vnormalize(T dst[3], const T v[3]) {
|
||||
dst[0] = v[0];
|
||||
dst[1] = v[1];
|
||||
dst[2] = v[2];
|
||||
const T len = vlength(v);
|
||||
if (std::fabs(len) > std::numeric_limits<T>::epsilon()) {
|
||||
const T inv_len = static_cast<T>(1.0) / len;
|
||||
dst[0] *= inv_len;
|
||||
dst[1] *= inv_len;
|
||||
dst[2] *= inv_len;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void vcross(T dst[3], const T a[3], const T b[3]) {
|
||||
dst[0] = a[1] * b[2] - a[2] * b[1];
|
||||
dst[1] = a[2] * b[0] - a[0] * b[2];
|
||||
dst[2] = a[0] * b[1] - a[1] * b[0];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void vsub(T dst[3], const T a[3], const T b[3]) {
|
||||
dst[0] = a[0] - b[0];
|
||||
dst[1] = a[1] - b[1];
|
||||
dst[2] = a[2] - b[2];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void calculate_normal(T Nn[3], const T v0[3], const T v1[3], const T v2[3]) {
|
||||
T v10[3];
|
||||
T v20[3];
|
||||
|
||||
vsub(v10, v1, v0);
|
||||
vsub(v20, v2, v0);
|
||||
|
||||
T N[3];
|
||||
vcross(N, v20, v10);
|
||||
vnormalize(Nn, N);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class Mesh {
|
||||
public:
|
||||
explicit Mesh(const size_t vertex_stride) :
|
||||
stride(vertex_stride) {
|
||||
}
|
||||
|
||||
std::string name;
|
||||
|
||||
std::vector<T> vertices; /// stride * num_vertices
|
||||
std::vector<T> facevarying_normals; /// [xyz] * 3(triangle) * num_faces
|
||||
std::vector<T> facevarying_tangents; /// [xyz] * 3(triangle) * num_faces
|
||||
std::vector<T> facevarying_binormals; /// [xyz] * 3(triangle) * num_faces
|
||||
std::vector<T> facevarying_uvs; /// [xy] * 3(triangle) * num_faces
|
||||
std::vector<T>
|
||||
facevarying_vertex_colors; /// [xyz] * 3(triangle) * num_faces
|
||||
std::vector<unsigned int> faces; /// triangle x num_faces
|
||||
std::vector<unsigned int> material_ids; /// index x num_faces
|
||||
|
||||
T pivot_xform[4][4];
|
||||
size_t stride; /// stride for vertex data.
|
||||
|
||||
// --- Required methods in Scene::Traversal. ---
|
||||
|
||||
///
|
||||
/// Get the geometric normal and the shading normal at `face_idx' th face.
|
||||
///
|
||||
void GetNormal(T Ng[3], T Ns[3], const unsigned int face_idx, const T u, const T v) const {
|
||||
// Compute geometric normal.
|
||||
unsigned int f0, f1, f2;
|
||||
T v0[3], v1[3], v2[3];
|
||||
|
||||
f0 = faces[3 * face_idx + 0];
|
||||
f1 = faces[3 * face_idx + 1];
|
||||
f2 = faces[3 * face_idx + 2];
|
||||
|
||||
v0[0] = vertices[3 * f0 + 0];
|
||||
v0[1] = vertices[3 * f0 + 1];
|
||||
v0[2] = vertices[3 * f0 + 2];
|
||||
|
||||
v1[0] = vertices[3 * f1 + 0];
|
||||
v1[1] = vertices[3 * f1 + 1];
|
||||
v1[2] = vertices[3 * f1 + 2];
|
||||
|
||||
v2[0] = vertices[3 * f2 + 0];
|
||||
v2[1] = vertices[3 * f2 + 1];
|
||||
v2[2] = vertices[3 * f2 + 2];
|
||||
|
||||
calculate_normal(Ng, v0, v1, v2);
|
||||
|
||||
if (facevarying_normals.size() > 0) {
|
||||
|
||||
T n0[3], n1[3], n2[3];
|
||||
|
||||
n0[0] = facevarying_normals[9 * face_idx + 0];
|
||||
n0[1] = facevarying_normals[9 * face_idx + 1];
|
||||
n0[2] = facevarying_normals[9 * face_idx + 2];
|
||||
|
||||
n1[0] = facevarying_normals[9 * face_idx + 3];
|
||||
n1[1] = facevarying_normals[9 * face_idx + 4];
|
||||
n1[2] = facevarying_normals[9 * face_idx + 5];
|
||||
|
||||
n2[0] = facevarying_normals[9 * face_idx + 6];
|
||||
n2[1] = facevarying_normals[9 * face_idx + 7];
|
||||
n2[2] = facevarying_normals[9 * face_idx + 8];
|
||||
|
||||
lerp(Ns, n0, n1, n2, u, v);
|
||||
|
||||
} else {
|
||||
|
||||
// Use geometric normal.
|
||||
Ns[0] = Ng[0];
|
||||
Ns[1] = Ng[1];
|
||||
Ns[2] = Ng[2];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// --- end of required methods in Scene::Traversal. ---
|
||||
|
||||
///
|
||||
/// Get texture coordinate at `face_idx' th face.
|
||||
///
|
||||
void GetTexCoord(T tcoord[3], const unsigned int face_idx, const T u, const T v) {
|
||||
|
||||
if (facevarying_uvs.size() > 0) {
|
||||
|
||||
T t0[3], t1[3], t2[3];
|
||||
|
||||
t0[0] = facevarying_uvs[6 * face_idx + 0];
|
||||
t0[1] = facevarying_uvs[6 * face_idx + 1];
|
||||
t0[2] = static_cast<T>(0.0);
|
||||
|
||||
t1[0] = facevarying_uvs[6 * face_idx + 2];
|
||||
t1[1] = facevarying_uvs[6 * face_idx + 3];
|
||||
t1[2] = static_cast<T>(0.0);
|
||||
|
||||
t2[0] = facevarying_uvs[6 * face_idx + 4];
|
||||
t2[1] = facevarying_uvs[6 * face_idx + 5];
|
||||
t2[2] = static_cast<T>(0.0);
|
||||
|
||||
lerp(tcoord, t0, t1, t2, u, v);
|
||||
|
||||
} else {
|
||||
|
||||
tcoord[0] = static_cast<T>(0.0);
|
||||
tcoord[1] = static_cast<T>(0.0);
|
||||
tcoord[2] = static_cast<T>(0.0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace example
|
||||
|
||||
#endif // EXAMPLE_MESH_H_
|
876
examples/raytrace/nanosg.h
Normal file
876
examples/raytrace/nanosg.h
Normal file
@ -0,0 +1,876 @@
|
||||
/*
|
||||
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 <iostream>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
#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(const 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(), mesh_->stride);
|
||||
nanort::TriangleSAHPred<float> triangle_pred(
|
||||
mesh_->vertices.data(), mesh_->faces.data(), mesh_->stride);
|
||||
|
||||
bool ret =
|
||||
accel_.Build(static_cast<unsigned 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_;
|
||||
int _pad_;
|
||||
};
|
||||
|
||||
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) ? 1 : 0;
|
||||
ray_dir_sign_[1] = ray.dir[1] < static_cast<T>(0.0) ? 1 : 0;
|
||||
ray_dir_sign_[2] = ray.dir[2] < static_cast<T>(0.0) ? 1 : 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();
|
||||
(void)stats;
|
||||
|
||||
// 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(),
|
||||
node.GetMesh()->stride);
|
||||
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);
|
||||
// printf("tworld %f, tnear %f\n", t_world, t_nearest);
|
||||
|
||||
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_
|
459
examples/raytrace/obj-loader.cc
Normal file
459
examples/raytrace/obj-loader.cc
Normal file
@ -0,0 +1,459 @@
|
||||
#include "obj-loader.h"
|
||||
#include "../../nanort.h" // for float3
|
||||
|
||||
#define TINYOBJLOADER_IMPLEMENTATION
|
||||
#include "tiny_obj_loader.h"
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast"
|
||||
#pragma clang diagnostic ignored "-Wreserved-id-macro"
|
||||
#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
|
||||
#pragma clang diagnostic ignored "-Wcast-align"
|
||||
#pragma clang diagnostic ignored "-Wpadded"
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast"
|
||||
#pragma clang diagnostic ignored "-Wsign-conversion"
|
||||
#pragma clang diagnostic ignored "-Wvariadic-macros"
|
||||
#pragma clang diagnostic ignored "-Wc++11-extensions"
|
||||
#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
|
||||
#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
|
||||
#if __has_warning("-Wdouble-promotion")
|
||||
#pragma clang diagnostic ignored "-Wdouble-promotion"
|
||||
#endif
|
||||
#if __has_warning("-Wcomma")
|
||||
#pragma clang diagnostic ignored "-Wcomma"
|
||||
#endif
|
||||
#if __has_warning("-Wcast-qual")
|
||||
#pragma clang diagnostic ignored "-Wcast-qual"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#ifdef NANOSG_USE_CXX11
|
||||
#include <unordered_map>
|
||||
#else
|
||||
#include <map>
|
||||
#endif
|
||||
|
||||
#define USE_TEX_CACHE 1
|
||||
|
||||
namespace example {
|
||||
|
||||
typedef nanort::real3<float> float3;
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wexit-time-destructors"
|
||||
#pragma clang diagnostic ignored "-Wglobal-constructors"
|
||||
#endif
|
||||
|
||||
// TODO(LTE): Remove global static definition.
|
||||
#ifdef NANOSG_USE_CXX11
|
||||
static std::unordered_map<std::string, int> hashed_tex;
|
||||
#else
|
||||
static std::map<std::string, int> hashed_tex;
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static std::string GetBaseDir(const std::string &filepath) {
|
||||
if (filepath.find_last_of("/\\") != std::string::npos)
|
||||
return filepath.substr(0, filepath.find_last_of("/\\"));
|
||||
return "";
|
||||
}
|
||||
|
||||
static int LoadTexture(const std::string &filename,
|
||||
std::vector<Texture> *textures) {
|
||||
int idx;
|
||||
|
||||
if (filename.empty()) return -1;
|
||||
|
||||
std::cout << " Loading texture : " << filename << std::endl;
|
||||
Texture texture;
|
||||
|
||||
// tigra: find in cache. get index
|
||||
if (USE_TEX_CACHE) {
|
||||
if (hashed_tex.find(filename) != hashed_tex.end()) {
|
||||
puts("from cache");
|
||||
return hashed_tex[filename];
|
||||
}
|
||||
}
|
||||
|
||||
int w, h, n;
|
||||
unsigned char *data = stbi_load(filename.c_str(), &w, &h, &n, 0);
|
||||
if (data) {
|
||||
texture.width = w;
|
||||
texture.height = h;
|
||||
texture.components = n;
|
||||
|
||||
size_t n_elem = size_t(w * h * n);
|
||||
texture.image = new unsigned char[n_elem];
|
||||
for (size_t i = 0; i < n_elem; i++) {
|
||||
texture.image[i] = data[i];
|
||||
}
|
||||
|
||||
free(data);
|
||||
|
||||
textures->push_back(texture);
|
||||
|
||||
idx = int(textures->size()) - 1;
|
||||
|
||||
// tigra: store index to cache
|
||||
if (USE_TEX_CACHE) {
|
||||
hashed_tex[filename] = idx;
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
std::cout << " Failed to load : " << filename << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ComputeBoundingBoxOfMesh(float bmin[3], float bmax[3],
|
||||
const example::Mesh<float> &mesh) {
|
||||
bmin[0] = bmin[1] = bmin[2] = std::numeric_limits<float>::max();
|
||||
bmax[0] = bmax[1] = bmax[2] = -std::numeric_limits<float>::max();
|
||||
|
||||
for (size_t i = 0; i < mesh.vertices.size() / 3; i++) {
|
||||
bmin[0] = std::min(bmin[0], mesh.vertices[3 * i + 0]);
|
||||
bmin[1] = std::min(bmin[1], mesh.vertices[3 * i + 1]);
|
||||
bmin[2] = std::min(bmin[1], mesh.vertices[3 * i + 2]);
|
||||
|
||||
bmax[0] = std::max(bmax[0], mesh.vertices[3 * i + 0]);
|
||||
bmax[1] = std::max(bmax[1], mesh.vertices[3 * i + 1]);
|
||||
bmax[2] = std::max(bmax[2], mesh.vertices[3 * i + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
bool LoadObj(const std::string &filename, float scale,
|
||||
std::vector<Mesh<float> > *meshes,
|
||||
std::vector<Material> *out_materials,
|
||||
std::vector<Texture> *out_textures) {
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
std::string err;
|
||||
|
||||
std::string basedir = GetBaseDir(filename) + "/";
|
||||
const char *basepath = (basedir.compare("/") == 0) ? NULL : basedir.c_str();
|
||||
|
||||
// auto t_start = std::chrono::system_clock::now();
|
||||
|
||||
bool ret =
|
||||
tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename.c_str(),
|
||||
basepath, /* triangulate */ true);
|
||||
|
||||
// auto t_end = std::chrono::system_clock::now();
|
||||
// std::chrono::duration<double, std::milli> ms = t_end - t_start;
|
||||
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// std::cout << "[LoadOBJ] Parse time : " << ms.count() << " [msecs]"
|
||||
// << std::endl;
|
||||
|
||||
std::cout << "[LoadOBJ] # of shapes in .obj : " << shapes.size() << std::endl;
|
||||
std::cout << "[LoadOBJ] # of materials in .obj : " << materials.size()
|
||||
<< std::endl;
|
||||
|
||||
{
|
||||
size_t total_num_vertices = 0;
|
||||
size_t total_num_faces = 0;
|
||||
|
||||
total_num_vertices = attrib.vertices.size() / 3;
|
||||
std::cout << " vertices : " << attrib.vertices.size() / 3 << std::endl;
|
||||
|
||||
for (size_t i = 0; i < shapes.size(); i++) {
|
||||
std::cout << " shape[" << i << "].name : " << shapes[i].name
|
||||
<< std::endl;
|
||||
std::cout << " shape[" << i
|
||||
<< "].indices : " << shapes[i].mesh.indices.size() << std::endl;
|
||||
assert((shapes[i].mesh.indices.size() % 3) == 0);
|
||||
|
||||
total_num_faces += shapes[i].mesh.indices.size() / 3;
|
||||
|
||||
// tigra: empty name convert to _id
|
||||
if (shapes[i].name.length() == 0) {
|
||||
#ifdef NANOSG_USE_CXX11
|
||||
shapes[i].name = "_" + std::to_string(i);
|
||||
#else
|
||||
std::stringstream ss;
|
||||
ss << i;
|
||||
shapes[i].name = "_" + ss.str();
|
||||
#endif
|
||||
std::cout << " EMPTY shape[" << i << "].name, new : " << shapes[i].name
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
std::cout << "[LoadOBJ] # of faces: " << total_num_faces << std::endl;
|
||||
std::cout << "[LoadOBJ] # of vertices: " << total_num_vertices << std::endl;
|
||||
}
|
||||
|
||||
// TODO(LTE): Implement tangents and binormals
|
||||
|
||||
for (size_t i = 0; i < shapes.size(); i++) {
|
||||
Mesh<float> mesh(/* stride */ sizeof(float) * 3);
|
||||
|
||||
mesh.name = shapes[i].name;
|
||||
|
||||
const size_t num_faces = shapes[i].mesh.indices.size() / 3;
|
||||
mesh.faces.resize(num_faces * 3);
|
||||
mesh.material_ids.resize(num_faces);
|
||||
mesh.facevarying_normals.resize(num_faces * 3 * 3);
|
||||
mesh.facevarying_uvs.resize(num_faces * 3 * 2);
|
||||
mesh.vertices.resize(num_faces * 3 * 3);
|
||||
|
||||
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
|
||||
// reorder vertices. may create duplicated vertices.
|
||||
size_t f0 = size_t(shapes[i].mesh.indices[3 * f + 0].vertex_index);
|
||||
size_t f1 = size_t(shapes[i].mesh.indices[3 * f + 1].vertex_index);
|
||||
size_t f2 = size_t(shapes[i].mesh.indices[3 * f + 2].vertex_index);
|
||||
|
||||
mesh.vertices[9 * f + 0] = scale * attrib.vertices[3 * f0 + 0];
|
||||
mesh.vertices[9 * f + 1] = scale * attrib.vertices[3 * f0 + 1];
|
||||
mesh.vertices[9 * f + 2] = scale * attrib.vertices[3 * f0 + 2];
|
||||
|
||||
mesh.vertices[9 * f + 3] = scale * attrib.vertices[3 * f1 + 0];
|
||||
mesh.vertices[9 * f + 4] = scale * attrib.vertices[3 * f1 + 1];
|
||||
mesh.vertices[9 * f + 5] = scale * attrib.vertices[3 * f1 + 2];
|
||||
|
||||
mesh.vertices[9 * f + 6] = scale * attrib.vertices[3 * f2 + 0];
|
||||
mesh.vertices[9 * f + 7] = scale * attrib.vertices[3 * f2 + 1];
|
||||
mesh.vertices[9 * f + 8] = scale * attrib.vertices[3 * f2 + 2];
|
||||
|
||||
mesh.faces[3 * f + 0] = static_cast<unsigned int>(3 * f + 0);
|
||||
mesh.faces[3 * f + 1] = static_cast<unsigned int>(3 * f + 1);
|
||||
mesh.faces[3 * f + 2] = static_cast<unsigned int>(3 * f + 2);
|
||||
|
||||
mesh.material_ids[f] =
|
||||
static_cast<unsigned int>(shapes[i].mesh.material_ids[f]);
|
||||
}
|
||||
|
||||
if (attrib.normals.size() > 0) {
|
||||
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
|
||||
size_t f0, f1, f2;
|
||||
|
||||
f0 = size_t(shapes[i].mesh.indices[3 * f + 0].normal_index);
|
||||
f1 = size_t(shapes[i].mesh.indices[3 * f + 1].normal_index);
|
||||
f2 = size_t(shapes[i].mesh.indices[3 * f + 2].normal_index);
|
||||
|
||||
if (f0 > 0 && f1 > 0 && f2 > 0) {
|
||||
float n0[3], n1[3], n2[3];
|
||||
|
||||
n0[0] = attrib.normals[3 * f0 + 0];
|
||||
n0[1] = attrib.normals[3 * f0 + 1];
|
||||
n0[2] = attrib.normals[3 * f0 + 2];
|
||||
|
||||
n1[0] = attrib.normals[3 * f1 + 0];
|
||||
n1[1] = attrib.normals[3 * f1 + 1];
|
||||
n1[2] = attrib.normals[3 * f1 + 2];
|
||||
|
||||
n2[0] = attrib.normals[3 * f2 + 0];
|
||||
n2[1] = attrib.normals[3 * f2 + 1];
|
||||
n2[2] = attrib.normals[3 * f2 + 2];
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 0] = n0[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 1] = n0[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 2] = n0[2];
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 0] = n1[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 1] = n1[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 2] = n1[2];
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 0] = n2[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 1] = n2[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 2] = n2[2];
|
||||
} else { // face contains invalid normal index. calc geometric normal.
|
||||
f0 = size_t(shapes[i].mesh.indices[3 * f + 0].vertex_index);
|
||||
f1 = size_t(shapes[i].mesh.indices[3 * f + 1].vertex_index);
|
||||
f2 = size_t(shapes[i].mesh.indices[3 * f + 2].vertex_index);
|
||||
|
||||
float3 v0, v1, v2;
|
||||
|
||||
v0[0] = attrib.vertices[3 * f0 + 0];
|
||||
v0[1] = attrib.vertices[3 * f0 + 1];
|
||||
v0[2] = attrib.vertices[3 * f0 + 2];
|
||||
|
||||
v1[0] = attrib.vertices[3 * f1 + 0];
|
||||
v1[1] = attrib.vertices[3 * f1 + 1];
|
||||
v1[2] = attrib.vertices[3 * f1 + 2];
|
||||
|
||||
v2[0] = attrib.vertices[3 * f2 + 0];
|
||||
v2[1] = attrib.vertices[3 * f2 + 1];
|
||||
v2[2] = attrib.vertices[3 * f2 + 2];
|
||||
|
||||
float3 N;
|
||||
CalcNormal(N, v0, v1, v2);
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 0] = N[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 1] = N[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 2] = N[2];
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 0] = N[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 1] = N[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 2] = N[2];
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 0] = N[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 1] = N[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 2] = N[2];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// calc geometric normal
|
||||
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
|
||||
size_t f0, f1, f2;
|
||||
|
||||
f0 = size_t(shapes[i].mesh.indices[3 * f + 0].vertex_index);
|
||||
f1 = size_t(shapes[i].mesh.indices[3 * f + 1].vertex_index);
|
||||
f2 = size_t(shapes[i].mesh.indices[3 * f + 2].vertex_index);
|
||||
|
||||
float3 v0, v1, v2;
|
||||
|
||||
v0[0] = attrib.vertices[3 * f0 + 0];
|
||||
v0[1] = attrib.vertices[3 * f0 + 1];
|
||||
v0[2] = attrib.vertices[3 * f0 + 2];
|
||||
|
||||
v1[0] = attrib.vertices[3 * f1 + 0];
|
||||
v1[1] = attrib.vertices[3 * f1 + 1];
|
||||
v1[2] = attrib.vertices[3 * f1 + 2];
|
||||
|
||||
v2[0] = attrib.vertices[3 * f2 + 0];
|
||||
v2[1] = attrib.vertices[3 * f2 + 1];
|
||||
v2[2] = attrib.vertices[3 * f2 + 2];
|
||||
|
||||
float3 N;
|
||||
CalcNormal(N, v0, v1, v2);
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 0] = N[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 1] = N[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 2] = N[2];
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 0] = N[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 1] = N[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 2] = N[2];
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 0] = N[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 1] = N[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 2] = N[2];
|
||||
}
|
||||
}
|
||||
|
||||
if (attrib.texcoords.size() > 0) {
|
||||
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
|
||||
size_t f0, f1, f2;
|
||||
|
||||
f0 = size_t(shapes[i].mesh.indices[3 * f + 0].texcoord_index);
|
||||
f1 = size_t(shapes[i].mesh.indices[3 * f + 1].texcoord_index);
|
||||
f2 = size_t(shapes[i].mesh.indices[3 * f + 2].texcoord_index);
|
||||
|
||||
if (f0 > 0 && f1 > 0 && f2 > 0) {
|
||||
float3 n0, n1, n2;
|
||||
|
||||
n0[0] = attrib.texcoords[2 * f0 + 0];
|
||||
n0[1] = attrib.texcoords[2 * f0 + 1];
|
||||
|
||||
n1[0] = attrib.texcoords[2 * f1 + 0];
|
||||
n1[1] = attrib.texcoords[2 * f1 + 1];
|
||||
|
||||
n2[0] = attrib.texcoords[2 * f2 + 0];
|
||||
n2[1] = attrib.texcoords[2 * f2 + 1];
|
||||
|
||||
mesh.facevarying_uvs[2 * (3 * f + 0) + 0] = n0[0];
|
||||
mesh.facevarying_uvs[2 * (3 * f + 0) + 1] = n0[1];
|
||||
|
||||
mesh.facevarying_uvs[2 * (3 * f + 1) + 0] = n1[0];
|
||||
mesh.facevarying_uvs[2 * (3 * f + 1) + 1] = n1[1];
|
||||
|
||||
mesh.facevarying_uvs[2 * (3 * f + 2) + 0] = n2[0];
|
||||
mesh.facevarying_uvs[2 * (3 * f + 2) + 1] = n2[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute pivot translation and add offset to the vertices.
|
||||
float bmin[3], bmax[3];
|
||||
ComputeBoundingBoxOfMesh(bmin, bmax, mesh);
|
||||
|
||||
float bcenter[3];
|
||||
bcenter[0] = 0.5f * (bmax[0] - bmin[0]) + bmin[0];
|
||||
bcenter[1] = 0.5f * (bmax[1] - bmin[1]) + bmin[1];
|
||||
bcenter[2] = 0.5f * (bmax[2] - bmin[2]) + bmin[2];
|
||||
|
||||
for (size_t v = 0; v < mesh.vertices.size() / 3; v++) {
|
||||
mesh.vertices[3 * v + 0] -= bcenter[0];
|
||||
mesh.vertices[3 * v + 1] -= bcenter[1];
|
||||
mesh.vertices[3 * v + 2] -= bcenter[2];
|
||||
}
|
||||
|
||||
mesh.pivot_xform[0][0] = 1.0f;
|
||||
mesh.pivot_xform[0][1] = 0.0f;
|
||||
mesh.pivot_xform[0][2] = 0.0f;
|
||||
mesh.pivot_xform[0][3] = 0.0f;
|
||||
|
||||
mesh.pivot_xform[1][0] = 0.0f;
|
||||
mesh.pivot_xform[1][1] = 1.0f;
|
||||
mesh.pivot_xform[1][2] = 0.0f;
|
||||
mesh.pivot_xform[1][3] = 0.0f;
|
||||
|
||||
mesh.pivot_xform[2][0] = 0.0f;
|
||||
mesh.pivot_xform[2][1] = 0.0f;
|
||||
mesh.pivot_xform[2][2] = 1.0f;
|
||||
mesh.pivot_xform[2][3] = 0.0f;
|
||||
|
||||
mesh.pivot_xform[3][0] = bcenter[0];
|
||||
mesh.pivot_xform[3][1] = bcenter[1];
|
||||
mesh.pivot_xform[3][2] = bcenter[2];
|
||||
mesh.pivot_xform[3][3] = 1.0f;
|
||||
|
||||
meshes->push_back(mesh);
|
||||
}
|
||||
|
||||
// material_t -> Material and Texture
|
||||
out_materials->resize(materials.size());
|
||||
out_textures->resize(0);
|
||||
for (size_t i = 0; i < materials.size(); i++) {
|
||||
(*out_materials)[i].diffuse[0] = materials[i].diffuse[0];
|
||||
(*out_materials)[i].diffuse[1] = materials[i].diffuse[1];
|
||||
(*out_materials)[i].diffuse[2] = materials[i].diffuse[2];
|
||||
(*out_materials)[i].specular[0] = materials[i].specular[0];
|
||||
(*out_materials)[i].specular[1] = materials[i].specular[1];
|
||||
(*out_materials)[i].specular[2] = materials[i].specular[2];
|
||||
|
||||
(*out_materials)[i].id = int(i);
|
||||
|
||||
// map_Kd
|
||||
(*out_materials)[i].diffuse_texid =
|
||||
LoadTexture(materials[i].diffuse_texname, out_textures);
|
||||
// map_Ks
|
||||
(*out_materials)[i].specular_texid =
|
||||
LoadTexture(materials[i].specular_texname, out_textures);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace example
|
19
examples/raytrace/obj-loader.h
Normal file
19
examples/raytrace/obj-loader.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef EXAMPLE_OBJ_LOADER_H_
|
||||
#define EXAMPLE_OBJ_LOADER_H_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "mesh.h"
|
||||
#include "material.h"
|
||||
|
||||
namespace example {
|
||||
|
||||
///
|
||||
/// Loads wavefront .obj mesh
|
||||
///
|
||||
bool LoadObj(const std::string &filename, float scale, std::vector<Mesh<float> > *meshes, std::vector<Material> *materials, std::vector<Texture> *textures);
|
||||
|
||||
}
|
||||
|
||||
#endif // EXAMPLE_OBJ_LOADER_H_
|
114
examples/raytrace/premake5.lua
Normal file
114
examples/raytrace/premake5.lua
Normal file
@ -0,0 +1,114 @@
|
||||
newoption {
|
||||
trigger = "with-gtk3nfd",
|
||||
description = "Build with native file dialog support(GTK3 required. Linux only)"
|
||||
}
|
||||
|
||||
newoption {
|
||||
trigger = "asan",
|
||||
description = "Enable Address Sanitizer(gcc5+ ang clang only)"
|
||||
}
|
||||
|
||||
sources = {
|
||||
"main.cc",
|
||||
"render.cc",
|
||||
"render-config.cc",
|
||||
"obj-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 "NanoSGSolution"
|
||||
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"
|
116
examples/raytrace/render-config.cc
Normal file
116
examples/raytrace/render-config.cc
Normal file
@ -0,0 +1,116 @@
|
||||
#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("obj_filename") != o.end()) {
|
||||
if (o["obj_filename"].is<std::string>()) {
|
||||
config->obj_filename = o["obj_filename"].get<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
if (o.find("eson_filename") != o.end()) {
|
||||
if (o["eson_filename"].is<std::string>()) {
|
||||
config->eson_filename = o["eson_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;
|
||||
}
|
||||
}
|
42
examples/raytrace/render-config.h
Normal file
42
examples/raytrace/render-config.h
Normal file
@ -0,0 +1,42 @@
|
||||
#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 obj_filename;
|
||||
std::string eson_filename;
|
||||
float scene_scale;
|
||||
|
||||
} RenderConfig;
|
||||
|
||||
/// Loads config from JSON file.
|
||||
bool LoadRenderConfig(example::RenderConfig *config, const char *filename);
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // RENDER_CONFIG_H
|
560
examples/raytrace/render.cc
Normal file
560
examples/raytrace/render.cc
Normal file
@ -0,0 +1,560 @@
|
||||
/*
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 // TODO(LTE): Not used method. Delete.
|
||||
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];
|
||||
ray.dir[1] = dir[1];
|
||||
ray.dir[2] = dir[2];
|
||||
|
||||
return ray;
|
||||
}
|
||||
#endif
|
||||
|
||||
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,
|
||||
int &_showBufferMode
|
||||
) {
|
||||
//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;
|
||||
|
||||
//for modes not a "color"
|
||||
if(_showBufferMode != SHOW_BUFFER_COLOR)
|
||||
{
|
||||
//only one pass
|
||||
if(config.pass > 0)
|
||||
continue;
|
||||
|
||||
//to the center of pixel
|
||||
u0 = 0.5f;
|
||||
u1 = 0.5f;
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
//tigra: add default material
|
||||
const Material &default_material = asset.default_material;
|
||||
|
||||
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];
|
||||
|
||||
//printf("material_id=%d materials=%lld\n", material_id, materials.size());
|
||||
|
||||
float diffuse_col[3];
|
||||
|
||||
float specular_col[3];
|
||||
|
||||
//tigra: material_id is ok
|
||||
if(material_id>=0 && material_id<materials.size())
|
||||
{
|
||||
//printf("ok mat\n");
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
else
|
||||
//tigra: wrong material_id, use default_material
|
||||
{
|
||||
|
||||
//printf("default_material\n");
|
||||
|
||||
diffuse_col[0] = default_material.diffuse[0];
|
||||
diffuse_col[1] = default_material.diffuse[1];
|
||||
diffuse_col[2] = default_material.diffuse[2];
|
||||
specular_col[0] = default_material.specular[0];
|
||||
specular_col[1] = default_material.specular[1];
|
||||
specular_col[2] = default_material.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
|
45
examples/raytrace/render.h
Normal file
45
examples/raytrace/render.h
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef EXAMPLE_RENDER_H_
|
||||
#define EXAMPLE_RENDER_H_
|
||||
|
||||
#include <atomic> // C++11
|
||||
|
||||
//mode definitions now here
|
||||
|
||||
#define SHOW_BUFFER_COLOR (0)
|
||||
#define SHOW_BUFFER_NORMAL (1)
|
||||
#define SHOW_BUFFER_POSITION (2)
|
||||
#define SHOW_BUFFER_DEPTH (3)
|
||||
#define SHOW_BUFFER_TEXCOORD (4)
|
||||
#define SHOW_BUFFER_VARYCOORD (5)
|
||||
|
||||
#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;
|
||||
|
||||
//tigra: add default material
|
||||
Material default_material;
|
||||
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,
|
||||
int& _showBufferMode
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
#endif // EXAMPLE_RENDER_H_
|
339
examples/raytrace/viwewer.make
Normal file
339
examples/raytrace/viwewer.make
Normal file
@ -0,0 +1,339 @@
|
||||
# GNU Make project makefile autogenerated by Premake
|
||||
|
||||
ifndef config
|
||||
config=release_native
|
||||
endif
|
||||
|
||||
ifndef verbose
|
||||
SILENT = @
|
||||
endif
|
||||
|
||||
.PHONY: clean prebuild prelink
|
||||
|
||||
ifeq ($(config),release_native)
|
||||
RESCOMP = windres
|
||||
TARGETDIR = bin/native/Release
|
||||
TARGET = $(TARGETDIR)/view
|
||||
OBJDIR = obj/native/Release
|
||||
DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1
|
||||
INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm
|
||||
FORCE_INCLUDE +=
|
||||
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
|
||||
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -O2 -g
|
||||
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -O2 -g -std=c++11
|
||||
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
|
||||
LIBS += -lX11 -lpthread -ldl
|
||||
LDDEPS +=
|
||||
ALL_LDFLAGS += $(LDFLAGS)
|
||||
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
|
||||
define PREBUILDCMDS
|
||||
endef
|
||||
define PRELINKCMDS
|
||||
endef
|
||||
define POSTBUILDCMDS
|
||||
endef
|
||||
all: prebuild prelink $(TARGET)
|
||||
@:
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(config),release_x64)
|
||||
RESCOMP = windres
|
||||
TARGETDIR = bin/x64/Release
|
||||
TARGET = $(TARGETDIR)/view
|
||||
OBJDIR = obj/x64/Release
|
||||
DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1
|
||||
INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm
|
||||
FORCE_INCLUDE +=
|
||||
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
|
||||
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m64 -O2 -g
|
||||
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m64 -O2 -g -std=c++11
|
||||
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
|
||||
LIBS += -lX11 -lpthread -ldl
|
||||
LDDEPS +=
|
||||
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib64 -m64
|
||||
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
|
||||
define PREBUILDCMDS
|
||||
endef
|
||||
define PRELINKCMDS
|
||||
endef
|
||||
define POSTBUILDCMDS
|
||||
endef
|
||||
all: prebuild prelink $(TARGET)
|
||||
@:
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(config),release_x32)
|
||||
RESCOMP = windres
|
||||
TARGETDIR = bin/x32/Release
|
||||
TARGET = $(TARGETDIR)/view
|
||||
OBJDIR = obj/x32/Release
|
||||
DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1
|
||||
INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm
|
||||
FORCE_INCLUDE +=
|
||||
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
|
||||
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m32 -O2 -g
|
||||
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m32 -O2 -g -std=c++11
|
||||
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
|
||||
LIBS += -lX11 -lpthread -ldl
|
||||
LDDEPS +=
|
||||
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib32 -m32
|
||||
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
|
||||
define PREBUILDCMDS
|
||||
endef
|
||||
define PRELINKCMDS
|
||||
endef
|
||||
define POSTBUILDCMDS
|
||||
endef
|
||||
all: prebuild prelink $(TARGET)
|
||||
@:
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(config),debug_native)
|
||||
RESCOMP = windres
|
||||
TARGETDIR = bin/native/Debug
|
||||
TARGET = $(TARGETDIR)/view_debug
|
||||
OBJDIR = obj/native/Debug
|
||||
DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1 -DDEBUG
|
||||
INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm
|
||||
FORCE_INCLUDE +=
|
||||
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
|
||||
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -g
|
||||
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -g -std=c++11
|
||||
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
|
||||
LIBS += -lX11 -lpthread -ldl
|
||||
LDDEPS +=
|
||||
ALL_LDFLAGS += $(LDFLAGS)
|
||||
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
|
||||
define PREBUILDCMDS
|
||||
endef
|
||||
define PRELINKCMDS
|
||||
endef
|
||||
define POSTBUILDCMDS
|
||||
endef
|
||||
all: prebuild prelink $(TARGET)
|
||||
@:
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(config),debug_x64)
|
||||
RESCOMP = windres
|
||||
TARGETDIR = bin/x64/Debug
|
||||
TARGET = $(TARGETDIR)/view_debug
|
||||
OBJDIR = obj/x64/Debug
|
||||
DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1 -DDEBUG
|
||||
INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm
|
||||
FORCE_INCLUDE +=
|
||||
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
|
||||
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m64 -g
|
||||
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m64 -g -std=c++11
|
||||
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
|
||||
LIBS += -lX11 -lpthread -ldl
|
||||
LDDEPS +=
|
||||
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib64 -m64
|
||||
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
|
||||
define PREBUILDCMDS
|
||||
endef
|
||||
define PRELINKCMDS
|
||||
endef
|
||||
define POSTBUILDCMDS
|
||||
endef
|
||||
all: prebuild prelink $(TARGET)
|
||||
@:
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(config),debug_x32)
|
||||
RESCOMP = windres
|
||||
TARGETDIR = bin/x32/Debug
|
||||
TARGET = $(TARGETDIR)/view_debug
|
||||
OBJDIR = obj/x32/Debug
|
||||
DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1 -DDEBUG
|
||||
INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm
|
||||
FORCE_INCLUDE +=
|
||||
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
|
||||
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m32 -g
|
||||
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m32 -g -std=c++11
|
||||
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
|
||||
LIBS += -lX11 -lpthread -ldl
|
||||
LDDEPS +=
|
||||
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib32 -m32
|
||||
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
|
||||
define PREBUILDCMDS
|
||||
endef
|
||||
define PRELINKCMDS
|
||||
endef
|
||||
define POSTBUILDCMDS
|
||||
endef
|
||||
all: prebuild prelink $(TARGET)
|
||||
@:
|
||||
|
||||
endif
|
||||
|
||||
OBJECTS := \
|
||||
$(OBJDIR)/X11OpenGLWindow.o \
|
||||
$(OBJDIR)/glew.o \
|
||||
$(OBJDIR)/ImGuizmo.o \
|
||||
$(OBJDIR)/imgui.o \
|
||||
$(OBJDIR)/imgui_draw.o \
|
||||
$(OBJDIR)/imgui_impl_btgui.o \
|
||||
$(OBJDIR)/trackball.o \
|
||||
$(OBJDIR)/main.o \
|
||||
$(OBJDIR)/matrix.o \
|
||||
$(OBJDIR)/obj-loader.o \
|
||||
$(OBJDIR)/render-config.o \
|
||||
$(OBJDIR)/render.o \
|
||||
|
||||
RESOURCES := \
|
||||
|
||||
CUSTOMFILES := \
|
||||
|
||||
SHELLTYPE := msdos
|
||||
ifeq (,$(ComSpec)$(COMSPEC))
|
||||
SHELLTYPE := posix
|
||||
endif
|
||||
ifeq (/bin,$(findstring /bin,$(SHELL)))
|
||||
SHELLTYPE := posix
|
||||
endif
|
||||
|
||||
$(TARGET): $(GCH) ${CUSTOMFILES} $(OBJECTS) $(LDDEPS) $(RESOURCES)
|
||||
@echo Linking viwewer
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(TARGETDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(TARGETDIR))
|
||||
endif
|
||||
$(SILENT) $(LINKCMD)
|
||||
$(POSTBUILDCMDS)
|
||||
|
||||
clean:
|
||||
@echo Cleaning viwewer
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) rm -f $(TARGET)
|
||||
$(SILENT) rm -rf $(OBJDIR)
|
||||
else
|
||||
$(SILENT) if exist $(subst /,\\,$(TARGET)) del $(subst /,\\,$(TARGET))
|
||||
$(SILENT) if exist $(subst /,\\,$(OBJDIR)) rmdir /s /q $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
|
||||
prebuild:
|
||||
$(PREBUILDCMDS)
|
||||
|
||||
prelink:
|
||||
$(PRELINKCMDS)
|
||||
|
||||
ifneq (,$(PCH))
|
||||
$(OBJECTS): $(GCH) $(PCH)
|
||||
$(GCH): $(PCH)
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) -x c++-header $(ALL_CXXFLAGS) -o "$@" -MF "$(@:%.gch=%.d)" -c "$<"
|
||||
endif
|
||||
|
||||
$(OBJDIR)/X11OpenGLWindow.o: ../common/OpenGLWindow/X11OpenGLWindow.cpp
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/glew.o: ../common/ThirdPartyLibs/Glew/glew.c
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/ImGuizmo.o: ../common/imgui/ImGuizmo.cpp
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/imgui.o: ../common/imgui/imgui.cpp
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/imgui_draw.o: ../common/imgui/imgui_draw.cpp
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/imgui_impl_btgui.o: ../common/imgui/imgui_impl_btgui.cpp
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/trackball.o: ../common/trackball.cc
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/main.o: main.cc
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/matrix.o: matrix.cc
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/obj-loader.o: obj-loader.cc
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/render-config.o: render-config.cc
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/render.o: render.cc
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
|
||||
-include $(OBJECTS:%.o=%.d)
|
||||
ifneq (,$(PCH))
|
||||
-include $(OBJDIR)/$(notdir $(PCH)).d
|
||||
endif
|
Loading…
x
Reference in New Issue
Block a user