HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GU_SurfaceDeform.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: GU_SurfaceDeform.h ( GU Library, C++)
7  *
8  * COMMENTS: Surface deform capture, frame computation, and GPU deformation.
9  */
10 
11 #pragma once
12 
13 #include "GU_API.h"
14 #include "GU_Detail.h"
15 #include "GU_RayIntersect.h"
16 
17 #include <CE/CE_Array.h>
18 #include <GA/GA_Handle.h>
19 #include <GA/GA_Types.h>
20 #include <GEO/GEO_Interpolate.h>
21 #include <UT/UT_Array.h>
22 #include <UT/UT_ErrorLog.h>
23 #include <UT/UT_Matrix3.h>
24 #include <UT/UT_Matrix4.h>
25 #include <UT/UT_Tracing.h>
26 #include <UT/UT_UniquePtr.h>
27 #include <UT/UT_Vector3.h>
28 
29 #include <numeric>
30 
31 class CE_Context;
32 
33 namespace GU_SurfaceDeform
34 {
35 
36 template <typename T, typename Container>
38 {
39  Container& myContainer;
40 
41  ArrayAccessorBracketPolicy(Container& container)
42  : myContainer(container) {}
43 
44  inline T get(size_t i) const noexcept
45  {
46  return myContainer[i];
47  }
48 
49  inline void set(size_t i, const T &value) noexcept
50  {
51  myContainer[i] = value;
52  }
53 
54  inline size_t size() const noexcept
55  {
56  return myContainer.size();
57  }
58 };
59 
60 template <typename T, typename Container, typename Policy>
62 {
63  using value_type = T;
64  Policy policy;
65 
66  ArrayAccessor(Container& container)
67  : policy(container) {}
68 
69  ArrayAccessor(Container& container, Policy &policy)
70  : policy(policy) {}
71 
72  inline T operator[](size_t i) const noexcept {
73  return policy.get(i);
74  }
75 
76  inline void set(size_t i, const T &value) noexcept {
77  policy.set(i, value);
78  }
79 
80  inline size_t size() const noexcept {
81  return policy.size();
82  }
83 };
84 
85 template<typename PA>
86 void
88  UT_IntArray &primptstarts,
89  GA_OffsetArray &ptoffsets,
90  UT_FloatArray &ptweights,
91  const PA &positions,
92  const GU_Detail &surfacegdp,
93  const GU_RayIntersect &rayintersect)
94 {
96  GA_OffsetArray primoffsets;
97  UT_Vector3Array primuvs;
98  UT_IntArray primptcounts;
99 
100  primoffsets.setSizeNoInit(positions.size());
101  primuvs.setSizeNoInit(positions.size());
102 
103  primptcounts.setSizeNoInit(positions.size());
104  primptstarts.setSizeNoInit(positions.size()+1);
105 
106  {
107  utZoneScopedN("counts");
109  UT_BlockedRange<exint>(0, positions.size()),
110  [&](const UT_BlockedRange<exint> &r)
111  {
112  utZoneScopedN("task");
113  for (exint i = r.begin(), end = r.end(); i < end; ++i)
114  {
115  UT_Vector3 pos = positions[i];
116 
117  GU_MinInfo mininfo{};
118  rayintersect.minimumPoint(pos, mininfo);
119 
120  GA_Offset primoff = mininfo.prim.offset();
121 
122  if (primoff != GA_INVALID_OFFSET)
123  {
124  primoffsets[i] = primoff;
125  primuvs[i] = UT_Vector3(mininfo.u1, mininfo.v1, 0.0f);
126  primptcounts[i] = surfacegdp.getPrimitiveVertexCount(primoff);
127  }
128  else
129  {
130  primoffsets[i] = GA_INVALID_OFFSET;
131  primuvs[i] = UT_Vector3(0.0f);
132  primptcounts[i] = 0;
133  }
134  }
135  });
136  }
137 
138  {
139  utZoneScopedN("scan");
140  primptstarts[0] = 0;
141  std::inclusive_scan(
142  primptcounts.begin(), primptcounts.end(),
143  primptstarts.begin() + 1);
144  }
145 
146  GA_Size offsetcount = primptstarts[primptstarts.size()-1];
147  ptoffsets.setSizeNoInit(offsetcount);
148  ptweights.setSizeNoInit(offsetcount);
149 
150  {
151  utZoneScopedN("offsets");
153  UT_BlockedRange<exint>(0, positions.size()),
154  [&](const UT_BlockedRange<exint> &r)
155  {
156  utZoneScopedN("task");
157  for (exint i = r.begin(), end = r.end(); i < end; ++i)
158  {
159  GA_Offset primoff = primoffsets[i];
160  UT_Vector3 primuv = primuvs[i];
161 
162  if (primoff == GA_INVALID_OFFSET)
163  continue;
164 
166  UT_Array<float> weights;
168  &surfacegdp, primoff, offsets, weights, primuv, true);
169 
170  for (int j=0; j<offsets.size(); ++j)
171  {
172  ptoffsets[primptstarts[i] + j] = offsets[j];
173  ptweights[primptstarts[i] + j] = weights[j];
174  }
175  }
176  });
177  }
178 }
179 
180 GU_API void
182  const GU_Detail &gdp,
183  const GA_ROHandleV3 &poshandle,
184  GA_AttributeUPtr &nmlowner,
185  GA_AttributeUPtr &tanowner);
186 
187 template <
188  typename OUTPOS,
189  typename INPOS,
190  typename DEFRESTPOS,
191  typename DEFANIMPOS>
192 void
194  OUTPOS &newposdata,
195  const INPOS &points,
196  const DEFRESTPOS &constrestpos,
197  const DEFANIMPOS &constanimpos,
198  const GU_Detail &defgdp,
199  const GA_ROHandleV3 restnmlattrib,
200  const GA_ROHandleV3 resttanattrib,
201  const GA_ROHandleV3 animnmlattrib,
202  const GA_ROHandleV3 animtanattrib,
203  const UT_IntArray &primptstarts,
204  const GA_OffsetArray &ptoffsets,
205  const UT_FloatArray &ptweights)
206 {
207  utZoneScoped;
208  using value_type = typename OUTPOS::value_type;
210  UT_BlockedRange<exint>(0, points.size()),
211  [&](const UT_BlockedRange<exint> &r)
212  {
213  for (exint i = r.begin(), end = r.end(); i < end; ++i)
214  {
215  GA_Size ptstart = primptstarts[i];
216  GA_Size ptend = primptstarts[i + 1];
217  if (ptstart != ptend)
218  {
219  UT_Vector3 restpos(0.0f);
220  UT_Vector3 animpos(0.0f);
221 
222  UT_Vector3 restnml(0.0f);
223  UT_Vector3 animnml(0.0f);
224 
225  UT_Vector3 resttan(0.0f);
226  UT_Vector3 animtan(0.0f);
227 
228  for (int j = ptstart; j < ptend; ++j)
229  {
230  GA_Offset ptoff = ptoffsets[j];
231  GA_Size index = defgdp.pointIndex(ptoff);
232 
233  float w = ptweights[j];
234  restpos += w * constrestpos[index];
235  animpos += w * constanimpos[index];
236 
237  restnml += w * restnmlattrib.get(ptoff);
238  animnml += w * animnmlattrib.get(ptoff);
239 
240  resttan += w * resttanattrib.get(ptoff);
241  animtan += w * animtanattrib.get(ptoff);
242  }
243 
244  restnml.normalize();
245  animnml.normalize();
246 
247  resttan.normalize();
248  animtan.normalize();
249 
250  UT_Matrix3 deformrot;
251  deformrot.lookat(UT_Vector3(0.0f), animnml, animtan);
252  UT_Matrix4 deformspace(deformrot);
253  deformspace.translate(animpos);
254 
255  UT_Matrix3 restrot;
256  restrot.lookat(UT_Vector3(0.0f), restnml, resttan);
257  UT_Matrix4 restspace(restrot);
258  restspace.translate(restpos);
259 
260  restspace.invert();
261 
262  if constexpr(std::is_same_v<value_type, UT_Matrix4>)
263  {
264  newposdata.set(i, restspace * deformspace);
265  }
266  else
267  {
268  UT_Vector3 pos(points[i].data());
269  pos *= restspace * deformspace;
270 
271  newposdata.set(i, pos);
272  }
273  }
274  else
275  {
276  // fall back to undeformed xform/position
277  if constexpr(std::is_same_v<value_type, UT_Matrix4>)
278  {
279  newposdata.set(i, UT_Matrix4(1.0f));
280  }
281  else
282  {
283  newposdata.set(i, points[i].data());
284  }
285  }
286  }
287  });
288 }
289 
291 {
292 public:
293  void init(const GU_Detail &surfaceGdp);
294 
295  // Project positions onto rest surface mesh.
296  // Outputs per-position: contributing mesh point indices + barycentric
297  // weights.
298  // PA must support operator[](int) -> UT_Vector3 and size() -> int.
299  template<typename PA>
300  void project(
301  UT_IntArray &ptStarts,
302  UT_IntArray &ptIndices,
303  UT_FloatArray &ptWeights,
304  const PA &positions)
305  {
306  GA_OffsetArray ptoffsets;
307 
309  ptStarts,
310  ptoffsets,
311  ptWeights,
312  positions,
313  *myRestSurface,
314  *myRayIntersect);
315 
316  // Convert GA_Offsets to point indices
317  ptIndices.setSizeNoInit(ptoffsets.size());
319  UT_BlockedRange<exint>(0, ptoffsets.size()),
320  [&](const UT_BlockedRange<exint> &r)
321  {
322  for (exint i = r.begin(), end = r.end(); i < end; ++i)
323  {
324  ptIndices[i] = myRestSurface->pointIndex(ptoffsets[i]);
325  }
326  });
327  }
328 
329  const GU_Detail &restSurface() const { return *myRestSurface; }
330 
331 private:
332  UT_UniquePtr<GU_Detail> myRestSurface;
333  UT_UniquePtr<GU_RayIntersect> myRayIntersect;
334 };
335 
336 /// CPU-side capture for subdivision surface deformation.
337 /// Copies the rest surface and projects positions onto it via ray
338 /// intersection. The GT topology building and ptex conversion must
339 /// be performed externally (GT symbols can't link from GU).
341 {
342 public:
343  /// Copy rest surface and build ray intersect.
344  void init(const GU_Detail &restSurfaceGdp);
345 
346  /// Project positions onto the rest surface coarse mesh.
347  /// Outputs per-position: coarse face index (prim index into rest gdp),
348  /// barycentric u/v. Face index is -1 if the point was not captured.
349  /// PA must support operator[](int) -> UT_Vector3 and size() -> int.
350  /// Returns false on hard errors (invalid state).
351  template<typename PA>
352  bool project(
353  UT_IntArray &coarseFace,
354  UT_FloatArray &coarseU,
355  UT_FloatArray &coarseV,
356  const PA &positions)
357  {
358  utZoneScoped;
359  if (!myRayIntersect || !myRestSurface)
360  return false;
361 
362  const exint numpts = positions.size();
363  coarseFace.setSizeNoInit(numpts);
364  coarseU.setSizeNoInit(numpts);
365  coarseV.setSizeNoInit(numpts);
366 
367  {
368  utZoneScopedN("subd_project_ray");
370  UT_BlockedRange<exint>(0, numpts),
371  [&](const UT_BlockedRange<exint> &r)
372  {
373  for (exint i = r.begin(), end = r.end(); i < end; ++i)
374  {
375  GU_MinInfo mininfo{};
376  myRayIntersect->minimumPoint(positions[i], mininfo);
377  GA_Offset primoff = mininfo.prim.offset();
378  if (primoff != GA_INVALID_OFFSET)
379  {
380  coarseFace[i] =
381  (int)myRestSurface->primitiveIndex(primoff);
382  coarseU[i] = mininfo.u1;
383  coarseV[i] = mininfo.v1;
384  }
385  else
386  {
387  coarseFace[i] = -1;
388  coarseU[i] = 0.5f;
389  coarseV[i] = 0.5f;
390  }
391  }
392  });
393  }
394 
395  return true;
396  }
397 
398  bool isValid() const { return myRestSurface != nullptr; }
399  const GU_Detail &restSurface() const { return *myRestSurface; }
400 
401 private:
402  UT_UniquePtr<GU_Detail> myRestSurface;
403  UT_UniquePtr<GU_RayIntersect> myRayIntersect;
404 };
405 
406 GU_API void
408  CE_Context &context,
409  bool recompile,
410  int nprims,
411  CE_Array<float> &surfacexform,
412  const cl::Buffer &surfacePtStarts,
413  const cl::Buffer &surfacePtIndices,
414  const cl::Buffer &surfacePtWeights,
415  const cl::Buffer &restPos,
416  const cl::Buffer &restNml,
417  const cl::Buffer &restTan,
418  const cl::Buffer &animPos,
419  const cl::Buffer &animNml,
420  const cl::Buffer &animTan,
421  const cl::Buffer *grp = nullptr);
422 
423 GU_API void
425  CE_Context &context,
426  bool recompile,
427  int nprims,
428  CE_Array<float> &surfacexform,
429  const cl::Buffer &restPos,
430  const cl::Buffer &restNml,
431  const cl::Buffer &restTan,
432  const cl::Buffer &animPos,
433  const cl::Buffer &animNml,
434  const cl::Buffer &animTan,
435  const cl::Buffer *grp = nullptr);
436 
437 GU_API void
439  CE_Context &context,
440  bool recompile,
441  int npts,
442  const cl::Buffer &outPos,
443  const cl::Buffer &inPos,
444  const cl::Buffer &surfacexform,
445  const cl::Buffer &pointPrimsIndex,
446  const cl::Buffer &pointPrims,
447  const cl::Buffer *grp = nullptr,
448  const cl::Buffer *mask = nullptr);
449 
450 GU_API void
451 xform(
452  CE_Context &context,
453  bool recompile,
454  int npts,
455  const cl::Buffer &outPos,
456  const cl::Buffer &inPos,
457  const cl::Buffer &surfacexform,
458  const cl::Buffer *grp = nullptr);
459 
460 }
typedef int(APIENTRYP RE_PFNGLXSWAPINTERVALSGIPROC)(int)
void UTparallelFor(const Range &range, const Body &body, const int subscribe_ratio=2, const int min_grain_size=1, const bool force_use_task_scope=true)
GLdouble GLdouble GLint GLint const GLdouble * points
Definition: glad.h:2676
GLboolean * data
Definition: glcorearb.h:131
#define utZoneScoped
Definition: UT_Tracing.h:221
GLsizei const GLfloat * value
Definition: glcorearb.h:824
void setSizeNoInit(exint newsize)
Definition: UT_Array.h:719
UT_Vector3T< float > UT_Vector3
int64 exint
Definition: SYS_Types.h:125
GU_API void computeWeightedXform(CE_Context &context, bool recompile, int nprims, CE_Array< float > &surfacexform, const cl::Buffer &surfacePtStarts, const cl::Buffer &surfacePtIndices, const cl::Buffer &surfacePtWeights, const cl::Buffer &restPos, const cl::Buffer &restNml, const cl::Buffer &restTan, const cl::Buffer &animPos, const cl::Buffer &animNml, const cl::Buffer &animTan, const cl::Buffer *grp=nullptr)
void deform(OUTPOS &newposdata, const INPOS &points, const DEFRESTPOS &constrestpos, const DEFANIMPOS &constanimpos, const GU_Detail &defgdp, const GA_ROHandleV3 restnmlattrib, const GA_ROHandleV3 resttanattrib, const GA_ROHandleV3 animnmlattrib, const GA_ROHandleV3 animtanattrib, const UT_IntArray &primptstarts, const GA_OffsetArray &ptoffsets, const UT_FloatArray &ptweights)
const GU_Detail & restSurface() const
GEO_ConstPrimitiveP prim
void UTparallelForLightItems(const Range &range, const Body &body, const bool force_use_task_scope=true)
int minimumPoint(const UT_Vector3 &p, GU_MinInfo &mininfo, const GEO_Primitive *prim=0) const
void project(UT_IntArray &ptStarts, UT_IntArray &ptIndices, UT_FloatArray &ptWeights, const PA &positions)
exint size() const
Definition: UT_Array.h:667
uint64 value_type
Definition: GA_PrimCompat.h:29
exint GA_Size
Defines the bit width for index and offset types in GA.
Definition: GA_Types.h:243
UT_Matrix4T< float > UT_Matrix4
#define GA_INVALID_OFFSET
Definition: GA_Types.h:694
std::unique_ptr< T, Deleter > UT_UniquePtr
A smart pointer for unique ownership of dynamically allocated objects.
Definition: UT_UniquePtr.h:39
GLuint GLsizei const GLuint const GLintptr * offsets
Definition: glcorearb.h:2621
GA_Size GA_Offset
Definition: GA_Types.h:653
#define utZoneScopedN(name)
Definition: UT_Tracing.h:222
GLfloat f
Definition: glcorearb.h:1926
size_t size() const noexcept
void set(size_t i, const T &value) noexcept
ArrayAccessor(Container &container)
GLuint GLuint end
Definition: glcorearb.h:475
GEO_API void GEOgetInterpolationWeights(const GEO_Detail *detail, GA_Offset primoff, UT_Array< GA_Offset > &offsets, UT_Array< float > &weights, const UT_Vector3 &uvw, bool is_point_offsets=false)
GLint GLuint mask
Definition: glcorearb.h:124
iterator begin()
Definition: UT_Array.h:1039
void set(size_t i, const T &value) noexcept
SYS_FORCE_INLINE T get(GA_Offset off, int comp=0) const
Definition: GA_Handle.h:210
#define GU_API
Definition: GU_API.h:14
void lookat(const UT_Vector3T< S > &from, const UT_Vector3T< S > &to, T roll=0)
const GU_Detail & restSurface() const
SYS_FORCE_INLINE GA_Offset offset() const
UT_UniquePtr< GA_Attribute > GA_AttributeUPtr
Definition: GA_Attribute.h:995
SYS_FORCE_INLINE GA_Index pointIndex(GA_Offset offset) const
Given a point's data offset, return its index.
Definition: GA_Detail.h:358
GLint j
Definition: glad.h:2733
void surfaceInterpOffsets(UT_IntArray &primptstarts, GA_OffsetArray &ptoffsets, UT_FloatArray &ptweights, const PA &positions, const GU_Detail &surfacegdp, const GU_RayIntersect &rayintersect)
void translate(T dx, T dy, T dz=0)
Definition: UT_Matrix4.h:769
GU_API void computeFrames(const GU_Detail &gdp, const GA_ROHandleV3 &poshandle, GA_AttributeUPtr &nmlowner, GA_AttributeUPtr &tanowner)
T operator[](size_t i) const noexcept
GLuint index
Definition: glcorearb.h:786
bool project(UT_IntArray &coarseFace, UT_FloatArray &coarseU, UT_FloatArray &coarseV, const PA &positions)
GU_API void computeXform(CE_Context &context, bool recompile, int nprims, CE_Array< float > &surfacexform, const cl::Buffer &restPos, const cl::Buffer &restNml, const cl::Buffer &restTan, const cl::Buffer &animPos, const cl::Buffer &animNml, const cl::Buffer &animTan, const cl::Buffer *grp=nullptr)
GU_API void indexedXform(CE_Context &context, bool recompile, int npts, const cl::Buffer &outPos, const cl::Buffer &inPos, const cl::Buffer &surfacexform, const cl::Buffer &pointPrimsIndex, const cl::Buffer &pointPrims, const cl::Buffer *grp=nullptr, const cl::Buffer *mask=nullptr)
GU_API void xform(CE_Context &context, bool recompile, int npts, const cl::Buffer &outPos, const cl::Buffer &inPos, const cl::Buffer &surfacexform, const cl::Buffer *grp=nullptr)
int invert(T tol=0.0F)
Memory buffer interface.
Definition: cl.hpp:1867
ArrayAccessor(Container &container, Policy &policy)
GLubyte GLubyte GLubyte GLubyte w
Definition: glcorearb.h:857
SYS_FORCE_INLINE UT_StorageMathFloat_t< T > normalize() noexcept
Definition: UT_Vector3.h:378
SYS_FORCE_INLINE GA_Size getPrimitiveVertexCount(GA_Offset primoff) const
Definition: GA_Primitive.h:908
GLboolean r
Definition: glcorearb.h:1222
Declare prior to use.
iterator end()
End iterator.
Definition: UT_Array.h:1044