Fermat
mesh_utils.h
1 /*
2  * Fermat
3  *
4  * Copyright (c) 2016-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 <mesh/MeshCompression.h>
33 #include <vertex.h>
34 #include <cugar/basic/cuda/pointers.h>
35 #include <cugar/linalg/vector.h>
36 #include <cugar/linalg/matrix.h>
38 
39 #define NORMAL_COMPRESSION 1
40 #define TEX_COORD_COMPRESSION 1
41 #define UNIFIED_VERTEX_ATTRIBUTES 1
42 
45 
48 
49 enum TextureSet
50 {
51  kTextureCoords0 = 0,
52  kLightmapCoords = 1
53 };
54 
55 template <typename T>
57 
58 template <>
60 {
61  FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
62  static int3 load(const int* indices, const uint32 tri_idx) { return reinterpret_cast<const int3*>(indices)[tri_idx]; }
63 };
64 
65 template <>
67 {
68  FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
69  static int3 load(const int* indices, const uint32 tri_idx)
70  {
71  #ifdef FERMAT_DEVICE_COMPILATION
72  const int4 i4 = cugar::cuda::load<cugar::cuda::LOAD_DEFAULT>( reinterpret_cast<const int4*>(indices) + tri_idx );
73 // const int4 i4 = reinterpret_cast<const int4*>(indices)[tri_idx];
74  #else
75  const int4 i4 = reinterpret_cast<const int4*>(indices)[tri_idx];
76  #endif
77  return make_int3(i4.x, i4.y, i4.z);
78  }
79 };
80 
81 template <typename T>
83 
84 template <>
85 struct load_vertex_dispatch<float3>
86 {
87  FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
88  static float3 load(const MeshView& mesh, const uint32 vert_idx) { return reinterpret_cast<const float3*>(mesh.vertex_data)[vert_idx]; }
89 };
90 
91 template <>
92 struct load_vertex_dispatch<float4>
93 {
94  FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
95  static float4 load4(const MeshView& mesh, const uint32 vert_idx)
96  {
97  #ifdef FERMAT_DEVICE_COMPILATION
98  return cugar::cuda::load<cugar::cuda::LOAD_LDG>( reinterpret_cast<const float4*>(mesh.vertex_data) + vert_idx );
99  #else
100  return reinterpret_cast<const float4*>(mesh.vertex_data)[vert_idx];
101  #endif
102  }
103 
104  FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
105  static float3 load(const MeshView& mesh, const uint32 vert_idx)
106  {
107  const float4 v4 = load4( mesh, vert_idx );
108 
109  return make_float3(v4.x, v4.y, v4.z);
110  }
111 };
112 
113 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
114 cugar::Vector3f vertex_comp(const cugar::Vector3f& v) { return v; }
115 
116 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
117 cugar::Vector3f vertex_comp(const cugar::Vector4f& v) { return v.xyz(); }
118 
119 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
120 cugar::Vector3f load_vertex(const MeshView& mesh, const uint32 vert_idx)
121 {
122  return load_vertex_dispatch<MeshView::vertex_type>::load( mesh, vert_idx );
123 }
124 
125 #if UNIFIED_VERTEX_ATTRIBUTES
126 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
127 cugar::Vector4f load_full_vertex(const MeshView& mesh, const uint32 vert_idx)
128 {
130 }
131 #endif
132 
135 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
136 int3 load_vertex_triangle(const int* triangle_indices, const uint32 tri_idx)
137 {
138  return load_triangle_dispatch<MeshStorage::vertex_triangle>::load( triangle_indices, tri_idx );
139 }
140 
143 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
144 int3 load_normal_triangle(const int* triangle_indices, const uint32 tri_idx)
145 {
146  return load_triangle_dispatch<MeshStorage::normal_triangle>::load( triangle_indices, tri_idx );
147 }
148 
151 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
152 int3 load_texture_triangle(const int* triangle_indices, const uint32 tri_idx)
153 {
154  return load_triangle_dispatch<MeshStorage::texture_triangle>::load( triangle_indices, tri_idx );
155 }
156 
159 FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
160 int3 load_lightmap_triangle(const int* triangle_indices, const uint32 tri_idx)
161 {
162  return load_triangle_dispatch<MeshStorage::lightmap_triangle>::load( triangle_indices, tri_idx );
163 }
164 
167 FERMAT_HOST_DEVICE inline
168 float prim_area(const MeshView& mesh, const uint32 tri_id)
169 {
170  FERMAT_ASSERT(tri_id < uint32(mesh.num_triangles));
171  const int3 tri = load_vertex_triangle( mesh.vertex_indices, tri_id );
172  const cugar::Vector3f vp0 = load_vertex(mesh, tri.x);
173  const cugar::Vector3f vp1 = load_vertex(mesh, tri.y);
174  const cugar::Vector3f vp2 = load_vertex(mesh, tri.z);
175 
176  const cugar::Vector3f dp_du = vp0 - vp2;
177  const cugar::Vector3f dp_dv = vp1 - vp2;
178 
179  return 0.5f * cugar::length(cugar::cross(dp_du, dp_dv));
180 }
181 
184 FERMAT_HOST_DEVICE inline
185 void setup_differential_geometry(const MeshView& mesh, const uint32 tri_id, const float u, const float v, VertexGeometry* geom, float* pdf = 0)
186 {
187 #if UNIFIED_VERTEX_ATTRIBUTES
188  FERMAT_ASSERT(tri_id < uint32(mesh.num_triangles));
189  const int3 tri = load_vertex_triangle( mesh.vertex_indices, tri_id );
190  const cugar::Vector4f vp0_w = load_full_vertex(mesh, tri.x);
191  const cugar::Vector4f vp1_w = load_full_vertex(mesh, tri.y);
192  const cugar::Vector4f vp2_w = load_full_vertex(mesh, tri.z);
193 
194  const cugar::Vector3f vp0 = vp0_w.xyz();
195  const cugar::Vector3f vp1 = vp1_w.xyz();
196  const cugar::Vector3f vp2 = vp2_w.xyz();
197 
198  geom->position = vp2 * (1.0f - u - v) + vp0 * u + vp1 * v; // P = rays[idx].origin + hit.t * rays[idx].dir;
199  const cugar::Vector3f dp_du = vp0 - vp2;
200  const cugar::Vector3f dp_dv = vp1 - vp2;
201  //geom->dp_du = dp_du;
202  //geom->dp_dv = dp_dv;
203  geom->normal_g = cugar::normalize(cugar::cross(dp_du, dp_dv));
204  if (pdf)
205  *pdf = 2.0f / cugar::length(cugar::cross(dp_du, dp_dv));
206 
207  // unpack the normals
208  {
209  const cugar::Vector3f vn0 = cugar::unpack_normal(cugar::binary_cast<uint32>( vp0_w.w ));
210  const cugar::Vector3f vn1 = cugar::unpack_normal(cugar::binary_cast<uint32>( vp1_w.w ));
211  const cugar::Vector3f vn2 = cugar::unpack_normal(cugar::binary_cast<uint32>( vp2_w.w ));
212 
213  const cugar::Vector3f N = cugar::normalize(vn2 * (1.0f - u - v) + vn0 * u + vn1 * v);
214 
215  geom->normal_s = N;
216  geom->tangent = cugar::orthogonal(N);
217  geom->binormal = cugar::cross(N, geom->tangent);
218  }
219 #else
220  FERMAT_ASSERT(tri_id < uint32(mesh.num_triangles));
221  const int3 tri = load_vertex_triangle( mesh.vertex_indices, tri_id );
222  const cugar::Vector3f vp0 = load_vertex(mesh, tri.x);
223  const cugar::Vector3f vp1 = load_vertex(mesh, tri.y);
224  const cugar::Vector3f vp2 = load_vertex(mesh, tri.z);
225 
226  geom->position = vp2 * (1.0f - u - v) + vp0 * u + vp1 * v; // P = rays[idx].origin + hit.t * rays[idx].dir;
227  const cugar::Vector3f dp_du = vp0 - vp2;
228  const cugar::Vector3f dp_dv = vp1 - vp2;
229  //geom->dp_du = dp_du;
230  //geom->dp_dv = dp_dv;
231  geom->normal_g = cugar::normalize(cugar::cross(dp_du, dp_dv));
232  if (pdf)
233  *pdf = 2.0f / cugar::length(cugar::cross(dp_du, dp_dv));
234 
235  if (mesh.normal_indices && mesh.normal_data)
236  {
237  #if NORMAL_COMPRESSION
238  const int3 tri = load_normal_triangle( mesh.normal_indices_comp, tri_id );
239  const cugar::Vector3f vn0 = tri.x >= 0 ? cugar::unpack_normal(tri.x) : geom->normal_g;
240  const cugar::Vector3f vn1 = tri.y >= 0 ? cugar::unpack_normal(tri.y) : geom->normal_g;
241  const cugar::Vector3f vn2 = tri.z >= 0 ? cugar::unpack_normal(tri.z) : geom->normal_g;
242  #else
243  const int3 tri = load_normal_triangle( mesh.normal_indices, tri_id );
244  FERMAT_ASSERT(
245  (tri.x < 0 || tri.x < mesh.num_normals) &&
246  (tri.y < 0 || tri.y < mesh.num_normals) &&
247  (tri.z < 0 || tri.z < mesh.num_normals));
248  const cugar::Vector3f vn0 = tri.x >= 0 ? cugar::unpack_normal(mesh.normal_data_comp[tri.x]) : geom->normal_g;
249  const cugar::Vector3f vn1 = tri.y >= 0 ? cugar::unpack_normal(mesh.normal_data_comp[tri.y]) : geom->normal_g;
250  const cugar::Vector3f vn2 = tri.z >= 0 ? cugar::unpack_normal(mesh.normal_data_comp[tri.z]) : geom->normal_g;
251  //const cugar::Vector3f vn0 = tri.x >= 0 ? reinterpret_cast<const float3*>(mesh.normal_data)[tri.x] : geom->normal_g;
252  //const cugar::Vector3f vn1 = tri.y >= 0 ? reinterpret_cast<const float3*>(mesh.normal_data)[tri.y] : geom->normal_g;
253  //const cugar::Vector3f vn2 = tri.z >= 0 ? reinterpret_cast<const float3*>(mesh.normal_data)[tri.z] : geom->normal_g;
254  #endif
255  const cugar::Vector3f N = cugar::normalize(vn2 * (1.0f - u - v) + vn0 * u + vn1 * v);
256 
257  geom->normal_s = N;
258  geom->tangent = cugar::orthogonal(N);
259  geom->binormal = cugar::cross(N, geom->tangent);
260  }
261  else
262  {
263  geom->normal_s = geom->normal_g;
264  geom->tangent = cugar::orthogonal(geom->normal_g);
265  geom->binormal = cugar::cross(geom->normal_g, geom->tangent);
266  }
267 #endif
268 
269  #if TEX_COORD_COMPRESSION
270  if (mesh.texture_indices_comp)
271  {
272  const int3 tri = load_texture_triangle( mesh.texture_indices_comp, tri_id );
273  const cugar::Vector2f vt0 = tri.x >= 0 ? decompress_tex_coord(mesh, tri.x) : cugar::Vector2f(1.0f,0.0f);
274  const cugar::Vector2f vt1 = tri.y >= 0 ? decompress_tex_coord(mesh, tri.y) : cugar::Vector2f(0.0f,1.0f);
275  const cugar::Vector2f vt2 = tri.z >= 0 ? decompress_tex_coord(mesh, tri.z) : cugar::Vector2f(0.0f,0.0f);
276  #else
277  if (mesh.texture_indices && mesh.texture_data)
278  {
279  const int3 tri = load_texture_triangle( mesh.texture_indices, tri_id );
280  const cugar::Vector2f vt0 = tri.x >= 0 ? reinterpret_cast<const float2*>(mesh.texture_data)[tri.x] : cugar::Vector2f(1.0f,0.0f);
281  const cugar::Vector2f vt1 = tri.y >= 0 ? reinterpret_cast<const float2*>(mesh.texture_data)[tri.y] : cugar::Vector2f(0.0f,1.0f);
282  const cugar::Vector2f vt2 = tri.z >= 0 ? reinterpret_cast<const float2*>(mesh.texture_data)[tri.z] : cugar::Vector2f(0.0f,0.0f);
283  #endif
284  const cugar::Vector2f st = vt2 * (1.0f - u - v) + vt0 * u + vt1 * v;
285  geom->texture_coords = cugar::Vector4f(st.x, st.y, 0.0f, 0.0f);
286  }
287  else
288  geom->texture_coords = cugar::Vector4f(u, v, 0.0f, 0.0f);
289 
290  #if TEX_COORD_COMPRESSION
291  if (mesh.lightmap_indices_comp)
292  {
293  const int3 tri = load_lightmap_triangle( mesh.lightmap_indices_comp, tri_id );
294  const cugar::Vector2f vt0 = tri.x >= 0 ? decompress_lightmap_coord(mesh, tri.x) : cugar::Vector2f(1.0f,0.0f);
295  const cugar::Vector2f vt1 = tri.y >= 0 ? decompress_lightmap_coord(mesh, tri.y) : cugar::Vector2f(0.0f,1.0f);
296  const cugar::Vector2f vt2 = tri.z >= 0 ? decompress_lightmap_coord(mesh, tri.z) : cugar::Vector2f(0.0f,0.0f);
297  #else
298  if (mesh.lightmap_indices && mesh.lightmap_data)
299  {
300  const int3 tri = load_lightmap_triangle( mesh.lightmap_indices, tri_id );
301  const cugar::Vector2f vt0 = tri.x >= 0 ? reinterpret_cast<const float2*>(mesh.lightmap_data)[tri.x] : cugar::Vector2f(1.0f,0.0f);
302  const cugar::Vector2f vt1 = tri.y >= 0 ? reinterpret_cast<const float2*>(mesh.lightmap_data)[tri.y] : cugar::Vector2f(0.0f,1.0f);
303  const cugar::Vector2f vt2 = tri.z >= 0 ? reinterpret_cast<const float2*>(mesh.lightmap_data)[tri.z] : cugar::Vector2f(0.0f,0.0f);
304  #endif
305  const cugar::Vector2f st = vt2 * (1.0f - u - v) + vt0 * u + vt1 * v;
306  geom->lightmap_coords = cugar::Vector2f(st.x, st.y);
307  }
308  else
309  geom->lightmap_coords = cugar::Vector2f(0.0f, 0.0f);
310 }
311 
314 FERMAT_HOST_DEVICE inline
315 void setup_differential_geometry(const MeshView& mesh, const VertexGeometryId v, VertexGeometry* geom, float* pdf = 0)
316 {
317  setup_differential_geometry(mesh, v.prim_id, v.uv.x, v.uv.y, geom, pdf);
318 }
319 
322 FERMAT_HOST_DEVICE inline
323 cugar::Vector3f interpolate_position(const MeshView& mesh, const uint32 tri_id, const float u, const float v, float* pdf = 0)
324 {
325  const int3 tri = load_vertex_triangle( mesh.vertex_indices, tri_id );
326  const cugar::Vector3f vp0 = load_vertex(mesh, tri.x);
327  const cugar::Vector3f vp1 = load_vertex(mesh, tri.y);
328  const cugar::Vector3f vp2 = load_vertex(mesh, tri.z);
329 
330  const cugar::Vector3f dp_du = vp0 - vp2;
331  const cugar::Vector3f dp_dv = vp1 - vp2;
332 
333  if (pdf)
334  *pdf = 2.0f / cugar::length(cugar::cross(dp_du, dp_dv));
335 
336  return vp2 * (1.0f - u - v) + vp0 * u + vp1 * v; // P = rays[idx].origin + hit.t * rays[idx].dir;
337 }
338 
341 FERMAT_HOST_DEVICE inline
342 cugar::Vector3f interpolate_position(const MeshView& mesh, const VertexGeometryId v, float* pdf = 0)
343 {
344  return interpolate_position(mesh, v.prim_id, v.uv.x, v.uv.y, pdf);
345 }
346 
349 FERMAT_HOST_DEVICE inline
350 cugar::Vector3f interpolate_normal(const MeshView& mesh, const uint32 tri_id, const float u, const float v)
351 {
352 #if UNIFIED_VERTEX_ATTRIBUTES
353  const int3 tri = load_vertex_triangle( mesh.vertex_indices, tri_id );
354  const cugar::Vector3f vn0 = cugar::unpack_normal( cugar::binary_cast<uint32>( fetch_vertex(mesh, tri.z).w ) );
355  const cugar::Vector3f vn1 = cugar::unpack_normal( cugar::binary_cast<uint32>( fetch_vertex(mesh, tri.y).w ) );
356  const cugar::Vector3f vn2 = cugar::unpack_normal( cugar::binary_cast<uint32>( fetch_vertex(mesh, tri.z).w ) );
357 
358  const cugar::Vector3f N = cugar::normalize(vn2 * (1.0f - u - v) + vn0 * u + vn1 * v);
359 
360  return N;
361 #else
362  cugar::Vector3f Ng;
363  {
364  const int3 tri = load_vertex_triangle( mesh.vertex_indices, tri_id );
365  const cugar::Vector3f vp0 = load_vertex(mesh, tri.z);
366  const cugar::Vector3f vp1 = load_vertex(mesh, tri.y);
367  const cugar::Vector3f vp2 = load_vertex(mesh, tri.z);
368 
369  const cugar::Vector3f dp_du = vp0 - vp2;
370  const cugar::Vector3f dp_dv = vp1 - vp2;
371  Ng = cugar::normalize(cugar::cross(dp_du, dp_dv));
372  }
373 
374  if (mesh.normal_indices && mesh.normal_data)
375  {
376  #if NORMAL_COMPRESSION
377  const int3 tri = load_normal_triangle( mesh.normal_indices_comp, tri_id );
378  const cugar::Vector3f vn0 = tri.x >= 0 ? cugar::unpack_normal(tri.x) : Ng;
379  const cugar::Vector3f vn1 = tri.y >= 0 ? cugar::unpack_normal(tri.y) : Ng;
380  const cugar::Vector3f vn2 = tri.z >= 0 ? cugar::unpack_normal(tri.z) : Ng;
381  #else
382  const int3 tri = load_normal_triangle( mesh.normal_indices, tri_id );
383  const cugar::Vector3f vn0 = tri.x >= 0 ? reinterpret_cast<const float3*>(mesh.normal_data)[tri.x] : Ng;
384  const cugar::Vector3f vn1 = tri.y >= 0 ? reinterpret_cast<const float3*>(mesh.normal_data)[tri.y] : Ng;
385  const cugar::Vector3f vn2 = tri.z >= 0 ? reinterpret_cast<const float3*>(mesh.normal_data)[tri.z] : Ng;
386  #endif
387  const cugar::Vector3f N = cugar::normalize(vn2 * (1.0f - u - v) + vn0 * u + vn1 * v);
388 
389  return N;
390  }
391  else
392  return Ng;
393 #endif
394 }
395 
398 FERMAT_HOST_DEVICE inline
400 {
401  return interpolate_normal(mesh, v.prim_id, v.uv.x, v.uv.y);
402 }
403 
404 
411 template <TextureSet TEXTURE_SET>
412 FERMAT_HOST_DEVICE inline
413 cugar::Matrix2x2f prim_dst_duv(const MeshView& mesh, const uint32 tri_id)
414 {
415  FERMAT_ASSERT(tri_id < uint32(mesh.num_triangles));
416  if (TEXTURE_SET == kTextureCoords0 && mesh.texture_indices)
417  {
418  const int3 tri = load_texture_triangle( mesh.texture_indices, tri_id );
419  const cugar::Vector2f vt0 = tri.x >= 0 ? reinterpret_cast<const float2*>(mesh.texture_data)[tri.x] : cugar::Vector2f(1.0f,0.0f);
420  const cugar::Vector2f vt1 = tri.y >= 0 ? reinterpret_cast<const float2*>(mesh.texture_data)[tri.y] : cugar::Vector2f(0.0f,1.0f);
421  const cugar::Vector2f vt2 = tri.z >= 0 ? reinterpret_cast<const float2*>(mesh.texture_data)[tri.z] : cugar::Vector2f(0.0f,0.0f);
422 
423  // build the matrix which sends:
424  // u=(1,0) in dst_du
425  // v=(0,1) in dst_dv
427  M[0] = vt0 - vt2; // dst_du
428  M[1] = vt1 - vt2; // dst_dv
429  return cugar::transpose(M);
430  }
431  else if (TEXTURE_SET == kLightmapCoords && mesh.lightmap_indices)
432  {
433  const int3 tri = load_lightmap_triangle( mesh.lightmap_indices, tri_id );
434  const cugar::Vector2f vt0 = tri.x >= 0 ? reinterpret_cast<const float2*>(mesh.lightmap_data)[tri.x] : cugar::Vector2f(1.0f,0.0f);
435  const cugar::Vector2f vt1 = tri.y >= 0 ? reinterpret_cast<const float2*>(mesh.lightmap_data)[tri.y] : cugar::Vector2f(0.0f,1.0f);
436  const cugar::Vector2f vt2 = tri.z >= 0 ? reinterpret_cast<const float2*>(mesh.lightmap_data)[tri.z] : cugar::Vector2f(0.0f,0.0f);
437 
438  // build the matrix which sends:
439  // u=(1,0) in dst_du
440  // v=(0,1) in dst_dv
442  M[0] = vt0 - vt2; // dst_du
443  M[1] = vt1 - vt2; // dst_dv
444  return cugar::transpose(M);
445  }
446  return cugar::Matrix2x2f::one();
447 }
448 
455 template <TextureSet TEXTURE_SET>
456 FERMAT_HOST_DEVICE inline
457 cugar::Matrix2x2f prim_duv_dst(const MeshView& mesh, const uint32 tri_id)
458 {
459  const cugar::Matrix2x2f dst_duv = prim_dst_duv<TEXTURE_SET>(mesh, tri_id);
461  cugar::invert(dst_duv, R);
462  return R;
463 }
464 
471 FERMAT_HOST_DEVICE inline
472 cugar::Matrix3x2f prim_dp_duv(const MeshView& mesh, const uint32 tri_id)
473 {
474  FERMAT_ASSERT(tri_id < uint32(mesh.num_triangles));
475  const int3 tri = load_vertex_triangle( mesh.vertex_indices, tri_id );
476  const cugar::Vector3f vp0 = load_vertex(mesh, tri.x);
477  const cugar::Vector3f vp1 = load_vertex(mesh, tri.y);
478  const cugar::Vector3f vp2 = load_vertex(mesh, tri.z);
479 
480  const cugar::Vector3f dp_du = vp0 - vp2;
481  const cugar::Vector3f dp_dv = vp1 - vp2;
482 
483  // build the matrix which sends:
484  // u=(1,0,0) in dp_dpu
485  // v=(0,1,0) in dp_dpv
487  M[0][0] = dp_du.x;
488  M[1][0] = dp_du.y;
489  M[2][0] = dp_du.z;
490  M[0][1] = dp_dv.x;
491  M[1][1] = dp_dv.y;
492  M[2][1] = dp_dv.z;
493  return M;
494 }
495 
503 FERMAT_HOST_DEVICE inline
504 cugar::Matrix3x3f prim_dp_duvw(const MeshView& mesh, const uint32 tri_id)
505 {
506  FERMAT_ASSERT(tri_id < uint32(mesh.num_triangles));
507  const int3 tri = load_vertex_triangle( mesh.vertex_indices, tri_id );
508  const cugar::Vector3f vp0 = load_vertex(mesh, tri.x);
509  const cugar::Vector3f vp1 = load_vertex(mesh, tri.y);
510  const cugar::Vector3f vp2 = load_vertex(mesh, tri.z);
511 
512  const cugar::Vector3f dp_du = vp0 - vp2;
513  const cugar::Vector3f dp_dv = vp1 - vp2;
514  const cugar::Vector3f dp_dw = cugar::cross(dp_du, dp_dv);
515 
516  // build the matrix which sends:
517  // u=(1,0,0) in dp_du
518  // v=(0,1,0) in dp_dv
519  // w=(0,0,1) in dp_dw
521  M[0][0] = dp_du.x;
522  M[1][0] = dp_du.y;
523  M[2][0] = dp_du.z;
524  M[0][1] = dp_dv.x;
525  M[1][1] = dp_dv.y;
526  M[2][1] = dp_dv.z;
527  M[0][2] = dp_dw.x;
528  M[1][2] = dp_dw.y;
529  M[2][2] = dp_dw.z;
530  return M;
531 }
532 
539 template <TextureSet TEXTURE_SET>
540 FERMAT_HOST_DEVICE inline
541 cugar::Matrix3x2f prim_dp_dst(const MeshView& mesh, const uint32 tri_id)
542 {
543  FERMAT_ASSERT(tri_id < uint32(mesh.num_triangles));
544  return prim_dp_duv( mesh, tri_id ) * prim_duv_dst<TEXTURE_SET>( mesh, tri_id );
545 }
546 
554 FERMAT_HOST_DEVICE inline
555 cugar::Matrix3x3f prim_duvw_dp(const MeshView& mesh, const uint32 tri_id)
556 {
557  // build the matrix which sends:
558  // dp_du in u=(1,0,0)
559  // dp_dv in v=(0,1,0)
560  // dp_dw in w=(0,0,1)
561  const cugar::Matrix3x3f dp_duvw = prim_dp_duvw(mesh,tri_id);
563  cugar::invert( dp_duvw, R );
564  return R;
565 }
566 
574 FERMAT_HOST_DEVICE inline
575 cugar::Matrix2x2f prim_dtb_duv(const MeshView& mesh, const uint32 tri_id)
576 {
577  FERMAT_ASSERT(tri_id < uint32(mesh.num_triangles));
578  const int3 tri = load_vertex_triangle( mesh.vertex_indices, tri_id );
579  const cugar::Vector3f vp0 = load_vertex(mesh, tri.x);
580  const cugar::Vector3f vp1 = load_vertex(mesh, tri.y);
581  const cugar::Vector3f vp2 = load_vertex(mesh, tri.z);
582 
583  const cugar::Vector3f dp_du = vp0 - vp2;
584  const cugar::Vector3f dp_dv = vp1 - vp2;
585  const cugar::Vector3f dp_dw = cugar::cross(dp_du, dp_dv);
586  const cugar::Vector3f n = cugar::normalize(dp_dw);
587  const cugar::Vector3f t = cugar::normalize(dp_du); //cugar::orthogonal(n);
588  const cugar::Vector3f b = cugar::cross(n, t);
589 
590  // build the matrix which sends:
591  // u=(1,0) in the coordinates of dp_dpu wrt (t,b), and
592  // v=(0,1) in the coordinates of dp_dpv wrt (t,b)
594  M[0][0] = cugar::dot(dp_du, t);
595  M[1][0] = 0.0f;
596  M[0][1] = cugar::dot(dp_dv, t);
597  M[1][1] = cugar::dot(dp_dv, b);
598  return M;
599 }
600 
608 FERMAT_HOST_DEVICE inline
609 cugar::Matrix2x2f prim_duv_dtb(const MeshView& mesh, const uint32 tri_id)
610 {
611  // build the matrix which sends:
612  // t in u=(1,0)
613  // b in v=(0,1)
614  const cugar::Matrix2x2f dtb_duv = prim_dtb_duv(mesh,tri_id);
616  cugar::invert( dtb_duv, R );
617  return R;
618 }
619 
626 FERMAT_HOST_DEVICE inline
627 cugar::Matrix2x3f prim_duv_dp(const MeshView& mesh, const uint32 tri_id)
628 {
629  // build the matrix which sends:
630  // dp_du in u=(1,0)
631  // dp_dv in v=(0,1)
632  const cugar::Matrix3x3f duvw_dp = prim_duvw_dp(mesh,tri_id);
634  R[0] = duvw_dp[0];
635  R[1] = duvw_dp[1];
636  return R;
637 }
638 
646 template <TextureSet TEXTURE_SET>
647 FERMAT_HOST_DEVICE inline
648 cugar::Matrix2x3f prim_dst_dp(const MeshView& mesh, const uint32 tri_id)
649 {
650  // build the matrix which sends:
651  // dp_du in dst_du
652  // dp_dv in dst_dv
653  const cugar::Matrix2x2f dst_duv = prim_dst_duv<TEXTURE_SET>(mesh,tri_id);
654  const cugar::Matrix2x3f duv_dp = prim_duv_dp(mesh,tri_id);
655  return dst_duv * duv_dp;
656 }
657 
665 template <TextureSet TEXTURE_SET>
666 FERMAT_HOST_DEVICE inline
667 cugar::Matrix2x2f prim_dst_dtb(const MeshView& mesh, const uint32 tri_id)
668 {
669  // build the matrix which sends:
670  // t=(1,0) in dst_dt
671  // b=(0,1) in dst_db
672  const cugar::Matrix2x2f dst_duv = prim_dst_duv<TEXTURE_SET>(mesh,tri_id);
673  const cugar::Matrix2x2f duv_dtb = prim_duv_dtb(mesh,tri_id);
674  return dst_duv * duv_dtb;
675 }
676 
684 template <TextureSet TEXTURE_SET>
685 FERMAT_HOST_DEVICE inline
686 cugar::Matrix2x2f prim_dtb_dst(const MeshView& mesh, const uint32 tri_id)
687 {
688  const cugar::Matrix2x2f duv_dst = prim_duv_dst<TEXTURE_SET>(mesh,tri_id);
689  const cugar::Matrix2x2f dtb_duv = prim_duv_dtb(mesh,tri_id);
690  return dtb_duv * duv_dst;
691 }
692 
696 template <TextureSet TEXTURE_SET>
697 FERMAT_HOST_DEVICE inline
698 cugar::Vector2f prim_dst_ellipse_size(const MeshView& mesh, const uint32 tri_id)
699 {
700  // if we consider the transformation of the unit-circle defined by the equation: Y = dst_dtb * X
701  // the semi-axes of the resulting ellipse can be obtained looking at the SVD of dst_dtb
702  const cugar::Matrix2x2f dst_dtb = prim_dst_dtb<TEXTURE_SET>(mesh,tri_id);
703  return cugar::singular_values(dst_dtb);
704 }
705 
712 template <TextureSet TEXTURE_SET>
713 FERMAT_HOST_DEVICE inline
714 void prim_dst_ellipse(const MeshView& mesh, const uint32 tri_id, cugar::Matrix2x2f& u, cugar::Vector2f& s)
715 {
716  // if we consider the transformation of the unit-circle defined by the equation: Y = dst_dtb * X
717  // the semi-axes of the resulting ellipse can be obtained looking at the SVD of dst_dtb
718  const cugar::Matrix2x2f dst_dtb = prim_dst_dtb<TEXTURE_SET>(mesh,tri_id);
720  cugar::svd(dst_dtb, u, s, v);
721 }
722 
FERMAT_HOST_DEVICE cugar::Matrix3x3f prim_dp_duvw(const MeshView &mesh, const uint32 tri_id)
Definition: mesh_utils.h:504
FERMAT_HOST_DEVICE cugar::Matrix2x2f prim_duv_dtb(const MeshView &mesh, const uint32 tri_id)
Definition: mesh_utils.h:609
CUGAR_HOST_DEVICE Vector2f singular_values(const Matrix2x2f &m)
Definition: matrix_inline.h:726
CUGAR_FORCEINLINE CUGAR_HOST_DEVICE T load(const T *ptr)
Definition: pointers.h:99
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE int3 load_normal_triangle(const int *triangle_indices, const uint32 tri_idx)
Definition: mesh_utils.h:144
Definition: vertex.h:105
FERMAT_HOST_DEVICE cugar::Matrix2x2f prim_dst_dtb(const MeshView &mesh, const uint32 tri_id)
Definition: mesh_utils.h:667
FERMAT_HOST_DEVICE float prim_area(const MeshView &mesh, const uint32 tri_id)
Definition: mesh_utils.h:168
FERMAT_HOST_DEVICE cugar::Matrix2x3f prim_dst_dp(const MeshView &mesh, const uint32 tri_id)
Definition: mesh_utils.h:648
FERMAT_HOST_DEVICE cugar::Matrix2x3f prim_duv_dp(const MeshView &mesh, const uint32 tri_id)
Definition: mesh_utils.h:627
Defines various spherical mappings.
FERMAT_HOST_DEVICE cugar::Matrix2x2f prim_dtb_duv(const MeshView &mesh, const uint32 tri_id)
Definition: mesh_utils.h:575
Definition: vertex.h:92
FERMAT_HOST_DEVICE cugar::Matrix3x3f prim_duvw_dp(const MeshView &mesh, const uint32 tri_id)
Definition: mesh_utils.h:555
FERMAT_HOST_DEVICE void setup_differential_geometry(const MeshView &mesh, const uint32 tri_id, const float u, const float v, VertexGeometry *geom, float *pdf=0)
Definition: mesh_utils.h:185
Definition: mesh_utils.h:56
CUGAR_HOST_DEVICE void svd(const Matrix2x2f &m, Matrix2x2f &u, Vector2f &s, Matrix2x2f &v)
Definition: matrix_inline.h:752
Definition: mesh_utils.h:82
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE int3 load_texture_triangle(const int *triangle_indices, const uint32 tri_idx)
Definition: mesh_utils.h:152
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE int3 load_vertex_triangle(const int *triangle_indices, const uint32 tri_idx)
Definition: mesh_utils.h:136
FERMAT_HOST_DEVICE cugar::Matrix2x2f prim_duv_dst(const MeshView &mesh, const uint32 tri_id)
Definition: mesh_utils.h:457
FERMAT_HOST_DEVICE cugar::Vector2f prim_dst_ellipse_size(const MeshView &mesh, const uint32 tri_id)
Definition: mesh_utils.h:698
FERMAT_HOST_DEVICE cugar::Matrix2x2f prim_dst_duv(const MeshView &mesh, const uint32 tri_id)
Definition: mesh_utils.h:413
Definition: MeshView.h:96
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE int3 load_lightmap_triangle(const int *triangle_indices, const uint32 tri_idx)
Definition: mesh_utils.h:160
FERMAT_HOST_DEVICE cugar::Matrix3x2f prim_dp_duv(const MeshView &mesh, const uint32 tri_id)
Definition: mesh_utils.h:472
FERMAT_HOST_DEVICE cugar::Matrix3x2f prim_dp_dst(const MeshView &mesh, const uint32 tri_id)
Definition: mesh_utils.h:541
FERMAT_HOST_DEVICE cugar::Vector3f interpolate_position(const MeshView &mesh, const uint32 tri_id, const float u, const float v, float *pdf=0)
Definition: mesh_utils.h:323
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE const MeshView::vertex_type & fetch_vertex(const MeshView &mesh, const uint32 vert_idx)
Definition: MeshView.h:150
CUGAR_FORCEINLINE CUGAR_HOST_DEVICE uint32 length(const vector_view< Iterator > &vec)
Definition: vector_view.h:228
FERMAT_HOST_DEVICE cugar::Matrix2x2f prim_dtb_dst(const MeshView &mesh, const uint32 tri_id)
Definition: mesh_utils.h:686
FERMAT_HOST_DEVICE cugar::Vector3f interpolate_normal(const MeshView &mesh, const uint32 tri_id, const float u, const float v)
Definition: mesh_utils.h:350
FERMAT_HOST_DEVICE void prim_dst_ellipse(const MeshView &mesh, const uint32 tri_id, cugar::Matrix2x2f &u, cugar::Vector2f &s)
Definition: mesh_utils.h:714