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