Skip to content

Commit 12d7a96

Browse files
author
Xavier Martinez
committed
First commit
1 parent b093c46 commit 12d7a96

File tree

423 files changed

+62803
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

423 files changed

+62803
-0
lines changed

AOEmbree.cpp

Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
#include <embree3/rtcore.h>
2+
#include <stdio.h>
3+
#include <math.h>
4+
#include <limits>
5+
6+
#include "AOEmbree.h"
7+
8+
9+
void errorFunction(void* userPtr, enum RTCError error, const char* str)
10+
{
11+
printf("error %d: %s\n", error, str);
12+
}
13+
14+
15+
RTCDevice initializeDevice()
16+
{
17+
RTCDevice device = rtcNewDevice(NULL);
18+
19+
if (!device)
20+
printf("error %d: cannot create device\n", rtcGetDeviceError(NULL));
21+
22+
rtcSetDeviceErrorFunction(device, errorFunction, NULL);
23+
return device;
24+
}
25+
26+
RTCScene initializeScene(RTCDevice device)
27+
{
28+
RTCScene scene = rtcNewScene(device);
29+
30+
/*
31+
* Create a triangle mesh geometry, and initialize a single triangle.
32+
* You can look up geometry types in the API documentation to
33+
* find out which type expects which buffers.
34+
*
35+
* We create buffers directly on the device, but you can also use
36+
* shared buffers. For shared buffers, special care must be taken
37+
* to ensure proper alignment and padding. This is described in
38+
* more detail in the API documentation.
39+
*/
40+
RTCGeometry geom = rtcNewGeometry(device, RTC_GEOMETRY_TYPE_TRIANGLE);
41+
42+
43+
float* vertices = (float*) rtcSetNewGeometryBuffer(geom,
44+
RTC_BUFFER_TYPE_VERTEX,
45+
0,
46+
RTC_FORMAT_FLOAT3,
47+
3 * sizeof(float),
48+
3);
49+
50+
unsigned* indices = (unsigned*) rtcSetNewGeometryBuffer(geom,
51+
RTC_BUFFER_TYPE_INDEX,
52+
0,
53+
RTC_FORMAT_UINT3,
54+
3 * sizeof(unsigned),
55+
1);
56+
57+
if (vertices && indices)
58+
{
59+
vertices[0] = 0.f; vertices[1] = 0.f; vertices[2] = 0.f;
60+
vertices[3] = 1.f; vertices[4] = 0.f; vertices[5] = 0.f;
61+
vertices[6] = 0.f; vertices[7] = 1.f; vertices[8] = 0.f;
62+
63+
indices[0] = 0; indices[1] = 1; indices[2] = 2;
64+
}
65+
66+
/*
67+
* You must commit geometry objects when you are done setting them up,
68+
* or you will not get any intersections.
69+
*/
70+
rtcCommitGeometry(geom);
71+
72+
/*
73+
* In rtcAttachGeometry(...), the scene takes ownership of the geom
74+
* by increasing its reference count. This means that we don't have
75+
* to hold on to the geom handle, and may release it. The geom object
76+
* will be released automatically when the scene is destroyed.
77+
*
78+
* rtcAttachGeometry() returns a geometry ID. We could use this to
79+
* identify intersected objects later on.
80+
*/
81+
rtcAttachGeometry(scene, geom);
82+
rtcReleaseGeometry(geom);
83+
84+
/*
85+
* Like geometry objects, scenes must be committed. This lets
86+
* Embree know that it may start building an acceleration structure.
87+
*/
88+
rtcCommitScene(scene);
89+
90+
return scene;
91+
}
92+
93+
bool castRay(RTCScene scene,
94+
float ox, float oy, float oz,
95+
float dx, float dy, float dz, float maxDist)
96+
{
97+
/*
98+
* The intersect context can be used to set intersection
99+
* filters or flags, and it also contains the instance ID stack
100+
* used in multi-level instancing.
101+
*/
102+
struct RTCIntersectContext context;
103+
rtcInitIntersectContext(&context);
104+
105+
/*
106+
* The ray hit structure holds both the ray and the hit.
107+
* The user must initialize it properly -- see API documentation
108+
* for rtcIntersect1() for details.
109+
*/
110+
struct RTCRayHit rayhit;
111+
rayhit.ray.org_x = ox;
112+
rayhit.ray.org_y = oy;
113+
rayhit.ray.org_z = oz;
114+
rayhit.ray.dir_x = dx;
115+
rayhit.ray.dir_y = dy;
116+
rayhit.ray.dir_z = dz;
117+
rayhit.ray.tnear = 0;
118+
rayhit.ray.tfar = maxDist;
119+
rayhit.ray.mask = 0;
120+
rayhit.ray.flags = 0;
121+
rayhit.hit.geomID = RTC_INVALID_GEOMETRY_ID;
122+
rayhit.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
123+
124+
/*
125+
* There are multiple variants of rtcIntersect. This one
126+
* intersects a single ray with the scene.
127+
*/
128+
rtcIntersect1(scene, &context, &rayhit);
129+
130+
// printf("%f, %f, %f: ", ox, oy, oz);
131+
if (rayhit.hit.geomID != RTC_INVALID_GEOMETRY_ID)
132+
{
133+
/* Note how geomID and primID identify the geometry we just hit.
134+
* We could use them here to interpolate geometry information,
135+
* compute shading, etc.
136+
* Since there is only a single triangle in this scene, we will
137+
* get geomID=0 / primID=0 for all hits.
138+
* There is also instID, used for instancing. See
139+
* the instancing tutorials for more information */
140+
// printf("Found intersection on geometry %d, primitive %d at tfar=%f\n",
141+
// rayhit.hit.geomID,
142+
// rayhit.hit.primID,
143+
// rayhit.ray.tfar);
144+
return true;
145+
}
146+
return false;
147+
// else
148+
// printf("Did not find any intersection.\n");
149+
}
150+
151+
152+
void computeAOPerVert(float *verts, float *norms, int *tris, float *result,
153+
int vcount, int icount,
154+
int samplesAO, float maxDist) {
155+
156+
157+
RTCDevice device = initializeDevice();
158+
159+
RTCScene scene = rtcNewScene(device);
160+
161+
RTCGeometry geom = rtcNewGeometry(device, RTC_GEOMETRY_TYPE_TRIANGLE);
162+
163+
164+
float* vertices = (float*) rtcSetNewGeometryBuffer(geom,
165+
RTC_BUFFER_TYPE_VERTEX,
166+
0,
167+
RTC_FORMAT_FLOAT3,
168+
3 * sizeof(float),
169+
vcount);
170+
171+
unsigned* indices = (unsigned*) rtcSetNewGeometryBuffer(geom,
172+
RTC_BUFFER_TYPE_INDEX,
173+
0,
174+
RTC_FORMAT_UINT3,
175+
3 * sizeof(unsigned),
176+
icount);
177+
178+
179+
for (int i = 0; i < vcount * 3; i++) {
180+
vertices[i] = verts[i];
181+
}
182+
for (int i = 0; i < icount * 3; i++) {
183+
indices[i] = tris[i];
184+
}
185+
186+
rtcCommitGeometry(geom);
187+
rtcAttachGeometry(scene, geom);
188+
rtcReleaseGeometry(geom);
189+
190+
rtcCommitScene(scene);
191+
192+
std::vector<vec3> rayDir;
193+
194+
//Compute semi-sphere ray directions
195+
int samples = samplesAO * 2;
196+
float golden_angle = M_PI * (3 - sqrtf(5));
197+
float start = 1 - 1.0f / (int)samples;
198+
float end = 1.0f / (int)samples - 1;
199+
200+
for (int i = 0; i < (int)samples; i++) {
201+
float theta = golden_angle * i;
202+
float z = start + i * (end - start) / (int)samples;
203+
float radius = sqrtf(1 - z * z);
204+
float x = radius * cos(theta);
205+
float y = radius * sin(theta);
206+
if (y > 0.0f)//Only keep the upper half of the sphere
207+
rayDir.push_back(vec3(x, y, z));
208+
}
209+
210+
float step = 1.0f / samplesAO;
211+
212+
for (int i = 0 ; i < vcount; i++) {
213+
214+
float totalAO = 0.0f;
215+
216+
vec3 oriVec(0, 1, 0);
217+
218+
vec3 normal(norms[i * 3], norms[i * 3 + 1], norms[i * 3 + 2]);
219+
220+
quat q = glm::rotation(oriVec, normal);
221+
222+
for (int s = 0; s < rayDir.size(); s++) {
223+
vec3 dir (
224+
rayDir[s].x + vertices[i * 3],
225+
rayDir[s].y + vertices[i * 3 + 1],
226+
rayDir[s].z + vertices[i * 3 + 2]);
227+
228+
229+
quat dirq = quat(dir.x, dir.y, dir.z, 0.0f);
230+
quat tmp = q * dirq * conjugate(q);
231+
vec3 rotatedDir(tmp.x, tmp.y, tmp.z);
232+
rotatedDir = normalize(rotatedDir);
233+
234+
235+
bool inter = castRay(scene, vertices[i * 3], vertices[i * 3 + 1], vertices[i * 3 + 2],
236+
rotatedDir.x, rotatedDir.y, rotatedDir.z, maxDist);
237+
238+
239+
if (inter) {
240+
totalAO += step;
241+
}
242+
}
243+
result[i] = totalAO;
244+
}
245+
246+
/* Though not strictly necessary in this example, you should
247+
* always make sure to release resources allocated through Embree. */
248+
rtcReleaseScene(scene);
249+
rtcReleaseDevice(device);
250+
251+
252+
253+
}
254+
255+
int main(int argc, char **argv) {
256+
257+
int samplesAO = 128;
258+
float maxDist = 10.0f;
259+
260+
std::ifstream infile(argv[1]);
261+
262+
std::vector<float> verts;
263+
std::vector<float> norms;
264+
std::vector<int> ids;
265+
266+
std::string line;
267+
while (std::getline(infile, line))
268+
{
269+
270+
if (line.size() > 0 && line[0] == 'v' && line[1] == ' ') {
271+
std::vector<std::string> words;
272+
split1(line.c_str(), words);
273+
float x = std::stof(words[1]);
274+
float y = std::stof(words[2]);
275+
float z = std::stof(words[3]);
276+
verts.push_back(x);
277+
verts.push_back(y);
278+
verts.push_back(z);
279+
}
280+
else if (line.size() > 0 && line[0] == 'f') {
281+
std::vector<std::string> words;
282+
split1(line.c_str(), words);
283+
ids.push_back(std::stoi(words[1]) - 1);
284+
ids.push_back(std::stoi(words[2]) - 1);
285+
ids.push_back(std::stoi(words[3]) - 1);
286+
}
287+
if (line.size() > 0 && line[0] == 'v' && line[1] == 'n') {
288+
std::vector<std::string> words;
289+
split1(line.c_str(), words);
290+
float x = std::stof(words[1]);
291+
float y = std::stof(words[2]);
292+
float z = std::stof(words[3]);
293+
norms.push_back(x);
294+
norms.push_back(y);
295+
norms.push_back(z);
296+
}
297+
}
298+
float *result = new float[verts.size() / 3];
299+
computeAOPerVert(verts.data(), norms.data(), ids.data(), result,
300+
verts.size() / 3, ids.size() / 3,
301+
samplesAO, maxDist);
302+
303+
304+
for (int i = 0; i < verts.size() / 3; i++) {
305+
printf("v %.6f %.6f %.6f %.3f %.3f %.3f\n",
306+
verts[i * 3], verts[i * 3 + 1], verts[i * 3 + 2], result[i], result[i], result[i]);
307+
}
308+
309+
for (int i = 0; i < ids.size() / 3; i++) {
310+
printf("f %d %d %d\n", ids[i * 3] + 1, ids[i * 3 + 1] + 1, ids[i * 3 + 2] + 1);
311+
}
312+
313+
return 0;
314+
}

AOEmbree.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#include <vector>
2+
#include <embree3/rtcore.h>
3+
4+
#include <fstream>
5+
#include <sstream>
6+
#include <string>
7+
8+
#include <iostream>
9+
10+
#include "glm/glm.hpp"
11+
// #include <glm/gtx/quaternion.hpp>
12+
#include "glm/gtc/quaternion.hpp"
13+
#include "glm/gtx/quaternion.hpp"
14+
using namespace glm;
15+
16+
// struct float3
17+
// {
18+
// float x;
19+
// float y;
20+
// float z;
21+
// };
22+
23+
24+
void computeAOPerVert(float *vertices, float *normals, int *indices, float *result,
25+
int vcount, int icount,
26+
int samplesAO, float maxDist);
27+
28+
29+
template <class Container>
30+
void split1(const std::string& str, Container& cont)
31+
{
32+
std::istringstream iss(str);
33+
std::copy(std::istream_iterator<std::string>(iss),
34+
std::istream_iterator<std::string>(),
35+
std::back_inserter(cont));
36+
}

CMakeLists.txt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
cmake_minimum_required(VERSION 3.5)
2+
project(AOEmbree)
3+
set(CMAKE_CXX_STANDARD 11)
4+
5+
set(CMAKE_BUILD_TYPE Release)
6+
7+
8+
if (POLICY CMP0074)
9+
cmake_policy(SET CMP0074 NEW)
10+
endif()
11+
12+
find_package(embree 3.0 REQUIRED)
13+
14+
INCLUDE_DIRECTORIES(${EMBREE_INCLUDE_DIRS})
15+
16+
add_executable(AOEmbree AOEmbree.cpp)
17+
18+
set(CMAKE_CXX_FLAGS_RELEASE "-O2")
19+
20+
target_compile_definitions(AOEmbree PUBLIC NOMINMAX)
21+
TARGET_LINK_LIBRARIES(AOEmbree ${EMBREE_LIBRARY})
22+
23+

0 commit comments

Comments
 (0)