Fermat
uv_bvh_view.h
1 /*
2  * Fermat
3  *
4  * Copyright (c) 2015-2019, NVIDIA CORPORATION. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the NVIDIA CORPORATION nor the
14  * names of its contributors may be used to endorse or promote products
15  * derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #pragma once
30 
31 #include <mesh/MeshStorage.h>
32 #include <vtl.h>
33 #include <cugar/linalg/vector.h>
34 #include <cugar/linalg/bbox.h>
35 
38 struct __align__(8) UVBvh_node
39 {
40  typedef uint32_t Type;
41  const static uint32_t kLeaf = (1u << 31u);
42  const static uint32_t kInternal = 0x00000000u;
43  const static uint32_t kInvalid = uint32_t(-1);
44  const static uint32_t kIndexMask = ~(7u << 29u);
45 
48  CUGAR_HOST_DEVICE UVBvh_node() {}
49 
53  CUGAR_HOST_DEVICE UVBvh_node(const Type type, const uint32_t size, const uint32_t index, const uint32_t skip_node)
54  {
55  m_packed_data = (type | ((size-1) << 29) | index);
56  m_skip_node = skip_node;
57  }
58 
61  CUGAR_HOST_DEVICE bool is_leaf() const { return (m_packed_data & kLeaf) != 0u; }
62 
65  CUGAR_HOST_DEVICE uint32_t get_index() const { return m_packed_data & kIndexMask; }
66 
69  CUGAR_HOST_DEVICE uint32_t get_leaf_index() const { return m_packed_data & kIndexMask; }
70 
73  CUGAR_HOST_DEVICE uint32_t get_child_count() const { return 1u + ((m_packed_data >> 29) & 3u); }
74 
77  CUGAR_HOST_DEVICE uint32_t get_size() const { return 1u + ((m_packed_data >> 29) & 3u); }
78 
82  CUGAR_HOST_DEVICE uint32_t get_child(const uint32_t i) const { return get_index() + i; }
83 
86  CUGAR_HOST_DEVICE uint32_t get_skip_node() const { return m_skip_node; }
87 
88  uint32_t m_packed_data;
89  uint32_t m_skip_node;
93 };
94 
97 struct UVBvhView
98 {
99  FERMAT_HOST_DEVICE
100  UVBvhView(const UVBvh_node* _nodes = NULL, const cugar::Bbox2f* _bboxes = NULL, const uint32_t* _index = NULL) :
101  nodes(_nodes), bboxes(_bboxes), index(_index) {}
102 
103  const UVBvh_node* nodes;
104  const cugar::Bbox2f* bboxes;
105  const uint32_t* index;
106 };
107 
108 struct UVHit
109 {
110  CUGAR_FORCEINLINE CUGAR_HOST_DEVICE
111  UVHit() {}
112 
113  CUGAR_FORCEINLINE CUGAR_HOST_DEVICE
114  UVHit(const uint32_t _triId, const float _u, const float _v) { triId = _triId; u = _u; v = _v; }
115 
116  uint32_t triId;
117  float u;
118  float v;
119 };
120 
121 CUGAR_HOST_DEVICE
122 inline UVHit locate(const UVBvhView& uvbvh, const MeshView& mesh, const uint32_t group_id, const float2 st)
123 {
124  const MeshStorage::texture_triangle* triangle_indices = reinterpret_cast<const MeshStorage::texture_triangle*>(mesh.texture_indices);
125  const float2* triangle_data = reinterpret_cast<const float2*>(mesh.texture_data);
126 
127  // start from the corresponding root node
128  uint32_t node_index = group_id;
129 
130  // traverse until we land on the invalid node
131  while (node_index != UVBvh_node::kInvalid)
132  {
133  // fetch the current node
134  const UVBvh_node node = uvbvh.nodes[node_index];
135 
136  #define COMBINED_CHILDREN_TEST
137  #if defined(COMBINED_CHILDREN_TEST)
138  if (!node.is_leaf())
139  {
140  const uint32_t child_index = node.get_index();
141 
142  const float4 child_bbox1 = reinterpret_cast<const float4*>(uvbvh.bboxes)[ child_index ];
143  const float4 child_bbox2 = reinterpret_cast<const float4*>(uvbvh.bboxes)[ child_index+1 ];
144 
145  if (st.x >= child_bbox1.x && st.x <= child_bbox1.z &&
146  st.y >= child_bbox1.y && st.y <= child_bbox1.w)
147  {
148  node_index = child_index;
149  continue;
150  }
151 
152  if (st.x >= child_bbox2.x && st.x <= child_bbox2.z &&
153  st.y >= child_bbox2.y && st.y <= child_bbox2.w)
154  {
155  node_index = child_index + 1;
156  continue;
157  }
158  }
159  #else
160  // test the bbox independently of whether this node is internal or a leaf
161  const float4 node_bbox = reinterpret_cast<const float4*>(uvbvh.bboxes)[node_index];
162 
163  if (st.x < node_bbox.x || st.x > node_bbox.z &&
164  st.y < node_bbox.y || st.y > node_bbox.w)
165  {
166  // jump to the skip node
167  node_index = node.get_skip_node();
168  continue;
169  }
170 
171  if (!node.is_leaf())
172  {
173  // step directly into the child, without any test
174  node_index = node.get_index();
175  continue;
176  }
177  #endif
178  else
179  {
180  // perform point-in-triangle tests against all prims in the leaf
181  const uint32_t leaf_begin = node.get_leaf_index();
182  const uint32_t leaf_end = leaf_begin + node.get_size();
183 
184  for (uint32_t l = leaf_begin; l < leaf_end; ++l)
185  {
186  // load the triangle
187  const uint32_t tri_idx = uvbvh.index[l];
188  const MeshStorage::texture_triangle tri = triangle_indices[ tri_idx ];
189 
190  // compute the barycentric coordinates of our st point
191  const float2 p1 = triangle_data[ tri.x ];
192  const float2 p2 = triangle_data[ tri.y ];
193  const float2 p0 = triangle_data[ tri.z ];
194 
195  #if 0
199 
200  const double den = v0.x * v1.y - v1.x * v0.y;
201  const double inv_den = 1.0f / den;
202  const double u = (v2.x * v1.y - v1.x * v2.y) * inv_den;
203  const double v = (v0.x * v2.y - v2.x * v0.y) * inv_den;
204  #else
205  const cugar::Vector2f v0 = cugar::Vector2f(p1) - cugar::Vector2f(p0);
206  const cugar::Vector2f v1 = cugar::Vector2f(p2) - cugar::Vector2f(p0);
207  const cugar::Vector2f v2 = cugar::Vector2f(st) - cugar::Vector2f(p0);
208 
209  const float den = v0.x * v1.y - v1.x * v0.y;
210  const float inv_den = 1.0f / den;
211  const float u = (v2.x * v1.y - v1.x * v2.y) * inv_den;
212  const float v = (v0.x * v2.y - v2.x * v0.y) * inv_den;
213  #endif
214 
215  // check whether we are inside the triangle
216  if (u >= 0.0f && v >= 0.0f && u + v <= 1.0f)
217  return UVHit( tri_idx, float(u), float(v) );
218  }
219  }
220 
221  // jump to the skip node
222  node_index = node.get_skip_node();
223  }
224 
225  // no triangle found
226  return UVHit(uint32_t(-1), -1.0f, -1.0f);
227 }
228 
229 CUGAR_HOST_DEVICE
230 inline uint32 locate(const UVBvhView& uvbvh, const VTL* vtls, const uint32_t prim_id, const float2 uv)
231 {
232  // shift the st coordinates into the proper square, determined by the primitive id
233  const float2 st = make_float2( uv.x + prim_id, uv.y );
234 
235  // start from the corresponding root node
236  uint32_t node_index = 0u;
237 
238  // traverse until we land on the invalid node
239  while (node_index != UVBvh_node::kInvalid)
240  {
241  // fetch the current node
242  const UVBvh_node node = uvbvh.nodes[node_index];
243 
244  #define COMBINED_CHILDREN_TEST
245  #if defined(COMBINED_CHILDREN_TEST)
246  if (!node.is_leaf())
247  {
248  const uint32_t child_index = node.get_index();
249 
250  const float4 child_bbox1 = reinterpret_cast<const float4*>(uvbvh.bboxes)[ child_index ];
251  const float4 child_bbox2 = reinterpret_cast<const float4*>(uvbvh.bboxes)[ child_index+1 ];
252 
253  if (st.x >= child_bbox1.x && st.x <= child_bbox1.z &&
254  st.y >= child_bbox1.y && st.y <= child_bbox1.w)
255  {
256  node_index = child_index;
257  continue;
258  }
259 
260  if (st.x >= child_bbox2.x && st.x <= child_bbox2.z &&
261  st.y >= child_bbox2.y && st.y <= child_bbox2.w)
262  {
263  node_index = child_index + 1;
264  continue;
265  }
266  }
267  #else
268  // test the bbox independently of whether this node is internal or a leaf
269  const float4 node_bbox = reinterpret_cast<const float4*>(uvbvh.bboxes)[node_index];
270 
271  if (st.x < node_bbox.x || st.x > node_bbox.z &&
272  st.y < node_bbox.y || st.y > node_bbox.w)
273  {
274  // jump to the skip node
275  node_index = node.get_skip_node();
276  continue;
277  }
278 
279  if (!node.is_leaf())
280  {
281  // step directly into the child, without any test
282  node_index = node.get_index();
283  continue;
284  }
285  #endif
286  else
287  {
288  // perform point-in-triangle tests against all prims in the leaf
289  const uint32_t leaf_begin = node.get_leaf_index();
290  const uint32_t leaf_end = leaf_begin + node.get_size();
291 
292  for (uint32_t l = leaf_begin; l < leaf_end; ++l)
293  {
294  // load the triangle
295  const uint32_t vtl_idx = uvbvh.index[l];
296  const VTL vtl = vtls[ vtl_idx ];
297 
298  // compute the barycentric coordinates of our st point
299  const float2 p1 = vtl.uv0;
300  const float2 p2 = vtl.uv1;
301  const float2 p0 = vtl.uv2;
302 
303  #if 0
307 
308  const double den = v0.x * v1.y - v1.x * v0.y;
309  const double inv_den = 1.0f / den;
310  const double u = (v2.x * v1.y - v1.x * v2.y) * inv_den;
311  const double v = (v0.x * v2.y - v2.x * v0.y) * inv_den;
312  #else
313  const cugar::Vector2f v0 = cugar::Vector2f(p1) - cugar::Vector2f(p0);
314  const cugar::Vector2f v1 = cugar::Vector2f(p2) - cugar::Vector2f(p0);
315  const cugar::Vector2f v2 = cugar::Vector2f(uv) - cugar::Vector2f(p0);
316 
317  const float den = v0.x * v1.y - v1.x * v0.y;
318  const float inv_den = 1.0f / den;
319  const float u = (v2.x * v1.y - v1.x * v2.y) * inv_den;
320  const float v = (v0.x * v2.y - v2.x * v0.y) * inv_den;
321  #endif
322 
323  // check whether we are inside the triangle
324  if (u >= 0.0f && v >= 0.0f && u + v <= 1.0f)
325  return vtl_idx;
326  }
327  }
328 
329  // jump to the skip node
330  node_index = node.get_skip_node();
331  }
332 
333  // no VTL found
334  return uint32(-1);
335 }
Definition: uv_bvh_view.h:108
Definition: bbox.h:59
Defines an axis-aligned bounding box class.
Definition: vtl.h:44
Definition: vector.h:54
Definition: MeshView.h:96
Definition: uv_bvh_view.h:97