1 /*
2 The MIT License (MIT)
3
4 Copyright (c) 2015 - 2017 Light Transport Entertainment, Inc.
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 THE SOFTWARE.
23 */
24
25 #ifdef _WIN32
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <time.h>
29 #else
30 #include <fcntl.h>
31 #include <sys/mman.h>
32 #include <sys/stat.h>
33 #endif
34
35 #ifdef __clang__
36 #pragma clang diagnostic push
37 #pragma clang diagnostic ignored "-Weverything"
38 #endif
39
40
41 #ifdef _MSC_VER
42 #pragma warning(push)
43 #pragma warning(disable : 4324)
44 #pragma warning(disable : 4457)
45 #pragma warning(disable : 4456)
46 #endif
47
48 #include <embree2/rtcore.h>
49 #include <embree2/rtcore_ray.h>
50
51 #define STB_IMAGE_WRITE_IMPLEMENTATION
52 #include "stb_image_write.h"
53
54 #ifdef __clang__
55 #pragma clang diagnostic pop
56 #endif
57
58 #ifdef _MSC_VER
59 #pragma warning(pop)
60 #endif
61
62 #include <cstdio>
63 #include <cstdlib>
64 #include <iostream>
65
66 #include "obj-loader.h" // ../nanosg
67
vnormalize(float dst[3],const float v[3])68 static inline void vnormalize(float dst[3], const float v[3]) {
69 dst[0] = v[0];
70 dst[1] = v[1];
71 dst[2] = v[2];
72 const float len = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
73 if (std::fabs(len) > std::numeric_limits<float>::epsilon()) {
74 const float inv_len = 1.0f / len;
75 dst[0] *= inv_len;
76 dst[1] *= inv_len;
77 dst[2] *= inv_len;
78 }
79 }
80
MultV(float dst[3],const float m[4][4],const float v[3])81 static void MultV(float dst[3], const float m[4][4], const float v[3]) {
82 float tmp[3];
83 tmp[0] = m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2] + m[3][0];
84 tmp[1] = m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2] + m[3][1];
85 tmp[2] = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2];
86 dst[0] = tmp[0];
87 dst[1] = tmp[1];
88 dst[2] = tmp[2];
89 }
90
91 // Create TriangleMesh
CreateTriangleMesh(const example::Mesh<float> & mesh,RTCScene scene)92 static unsigned int CreateTriangleMesh(const example::Mesh<float> &mesh,
93 RTCScene scene) {
94 unsigned int geom_id = rtcNewTriangleMesh(
95 scene, RTC_GEOMETRY_STATIC,
96 /* numTriangles */ mesh.faces.size() / 3, mesh.vertices.size() / 3, 1);
97
98 float *vertices = reinterpret_cast<float *>(
99 rtcMapBuffer(scene, geom_id, RTC_VERTEX_BUFFER));
100 int *faces =
101 reinterpret_cast<int *>(rtcMapBuffer(scene, geom_id, RTC_INDEX_BUFFER));
102
103 for (size_t i = 0; i < mesh.vertices.size() / 3; i++) {
104 // TODO(LTE): Use instanciation for applying xform.
105 float v[3];
106 MultV(v, mesh.pivot_xform, &mesh.vertices[3 * i + 0]);
107
108 // Embree uses 4 floats(16 bytes stride)
109 vertices[4 * i + 0] = v[0];
110 vertices[4 * i + 1] = v[1];
111 vertices[4 * i + 2] = v[2];
112 vertices[4 * i + 3] = 0.0f;
113 }
114
115 for (size_t i = 0; i < mesh.faces.size() / 3; i++) {
116 faces[3 * i + 0] = static_cast<int>(mesh.faces[3 * i + 0]);
117 faces[3 * i + 1] = static_cast<int>(mesh.faces[3 * i + 1]);
118 faces[3 * i + 2] = static_cast<int>(mesh.faces[3 * i + 2]);
119 }
120
121 rtcUnmapBuffer(scene, geom_id, RTC_VERTEX_BUFFER);
122 rtcUnmapBuffer(scene, geom_id, RTC_INDEX_BUFFER);
123
124 return geom_id;
125 }
126
SaveImagePNG(const char * filename,const float * rgb,int width,int height)127 static void SaveImagePNG(const char *filename, const float *rgb, int width,
128 int height) {
129 unsigned char *bytes = new unsigned char[size_t(width * height * 3)];
130 for (int y = 0; y < height; y++) {
131 for (int x = 0; x < width; x++) {
132 const int index = y * width + x;
133 bytes[index * 3 + 0] = static_cast<unsigned char>(
134 std::max(0.0f, std::min(rgb[index * 3 + 0] * 255.0f, 255.0f)));
135 bytes[index * 3 + 1] = static_cast<unsigned char>(
136 std::max(0.0f, std::min(rgb[index * 3 + 1] * 255.0f, 255.0f)));
137 bytes[index * 3 + 2] = static_cast<unsigned char>(
138 std::max(0.0f, std::min(rgb[index * 3 + 2] * 255.0f, 255.0f)));
139 }
140 }
141 stbi_write_png(filename, width, height, 3, bytes, width * 3);
142 delete[] bytes;
143 }
144
145 #ifdef __clang__
146 // suppress RTC_INVALID_GEOMETRY_ID
147 #pragma clang diagnostic ignored "-Wold-style-cast"
148 #endif
149
main(int argc,char ** argv)150 int main(int argc, char **argv) {
151 (void)argc;
152 (void)argv;
153
154 if (argc < 2) {
155 std::cout << "render input.obj (obj_scale). " << std::endl;
156 }
157
158 std::string obj_filename = "../common/cornellbox_suzanne_lucy.obj";
159
160 if (argc > 1) {
161 obj_filename = argv[1];
162 }
163
164 float obj_scale = 1.0f;
165 if (argc > 2) {
166 obj_scale = float(atof(argv[2]));
167 }
168
169 RTCDevice device = rtcNewDevice(NULL);
170 RTCScene scene = rtcDeviceNewScene(
171 device, RTC_SCENE_STATIC | RTC_SCENE_INCOHERENT, RTC_INTERSECT1);
172
173 std::vector<example::Mesh<float> > meshes;
174 std::vector<example::Material> materials;
175 std::vector<example::Texture> textures;
176 {
177 // load .obj
178
179 bool ret = LoadObj(obj_filename, obj_scale, &meshes, &materials, &textures);
180 if (!ret) {
181 std::cerr << "Failed to load .obj [ " << obj_filename << " ]"
182 << std::endl;
183 return EXIT_FAILURE;
184 }
185
186 // Create meshes for ray tracing.
187 for (size_t i = 0; i < meshes.size(); i++) {
188 unsigned int mesh_id = CreateTriangleMesh(meshes[i], scene);
189 (void)mesh_id;
190 }
191
192 rtcCommit(scene);
193
194 RTCBounds bounds;
195 rtcGetBounds(scene, bounds);
196
197 std::cout << "Scene bounding min: " << bounds.lower_x << ", "
198 << bounds.lower_y << ", " << bounds.lower_z << std::endl;
199 std::cout << "Scene bounding max: " << bounds.upper_x << ", "
200 << bounds.upper_y << ", " << bounds.upper_z << std::endl;
201 }
202
203 int width = 512;
204 int height = 512;
205
206 std::vector<float> rgb;
207 rgb.resize(size_t(width * height * 3));
208
209 // Shoot rays.
210 #ifdef _OPENMP
211 #pragma omp parallel for
212 #endif
213 for (int y = 0; y < height; y++) {
214 std::cout << y << " / " << height << std::endl;
215 for (int x = 0; x < width; x++) {
216 // Simple camera. change eye pos and direction fit to .obj model.
217
218 RTCRay ray;
219 ray.org[0] = 0.0f;
220 ray.org[1] = 5.0f;
221 ray.org[2] = 20.0f;
222
223 float dir[3], ndir[3];
224 dir[0] = (x / float(width)) - 0.5f;
225 dir[1] = (y / float(height)) - 0.5f;
226 dir[2] = -1.0f;
227 vnormalize(ndir, dir);
228 ray.dir[0] = ndir[0];
229 ray.dir[1] = ndir[1];
230 ray.dir[2] = ndir[2];
231
232 float kFar = 1.0e+30f;
233 ray.tnear = 0.0f;
234 ray.tfar = kFar;
235
236 rtcIntersect(scene, ray);
237 if ((ray.tfar < kFar) && (ray.geomID != RTC_INVALID_GEOMETRY_ID) &&
238 (ray.primID != RTC_INVALID_GEOMETRY_ID)) {
239 const example::Mesh<float> &mesh = meshes[ray.geomID];
240 // std::cout << "tfar " << ray.tfar << std::endl;
241 // Write your shader here.
242 float normal[3];
243 normal[0] = 0.0f;
244 normal[1] = 0.0f;
245 normal[2] = 0.0f;
246 unsigned int fid = ray.primID;
247 if (mesh.facevarying_normals.size() > 0) {
248 // std::cout << "fid " << fid << std::endl;
249 normal[0] = mesh.facevarying_normals[9 * fid + 0];
250 normal[1] = mesh.facevarying_normals[9 * fid + 1];
251 normal[2] = mesh.facevarying_normals[9 * fid + 2];
252 }
253 // Flip Y
254 rgb[3 * size_t((height - y - 1) * width + x) + 0] =
255 0.5f * normal[0] + 0.5f;
256 rgb[3 * size_t((height - y - 1) * width + x) + 1] =
257 0.5f * normal[1] + 0.5f;
258 rgb[3 * size_t((height - y - 1) * width + x) + 2] =
259 0.5f * normal[2] + 0.5f;
260 }
261 }
262 }
263
264 // Save image.
265 SaveImagePNG("render.png", &rgb.at(0), width, height);
266
267 rtcDeleteScene(scene);
268 rtcDeleteDevice(device);
269
270 return EXIT_SUCCESS;
271 }
272