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 #include <type_traits>
31 
32 class CE_Context;
33 
34 namespace GU_SurfaceDeform
35 {
36 
37 template <typename T, typename Container>
39 {
40  Container& myContainer;
41 
42  ArrayAccessorBracketPolicy(Container& container)
43  : myContainer(container) {}
44 
45  inline T get(size_t i) const noexcept
46  {
47  return myContainer[i];
48  }
49 
50  inline void set(size_t i, const T &value) noexcept
51  {
52  myContainer[i] = value;
53  }
54 
55  inline size_t size() const noexcept
56  {
57  return myContainer.size();
58  }
59 };
60 
61 template <typename T, typename Container, typename Policy>
63 {
64  using value_type = T;
65  Policy policy;
66 
67  ArrayAccessor(Container& container)
68  : policy(container) {}
69 
70  ArrayAccessor(Container& container, Policy &policy)
71  : policy(policy) {}
72 
73  inline T operator[](size_t i) const noexcept {
74  return policy.get(i);
75  }
76 
77  inline void set(size_t i, const T &value) noexcept {
78  policy.set(i, value);
79  }
80 
81  inline size_t size() const noexcept {
82  return policy.size();
83  }
84 };
85 
86 /// As surfaceInterpOffsets(), but the caller decides which intersector each
87 /// position is projected against: resolve(i, pos, mininfo) fills in mininfo,
88 /// leaving it untouched to drop position i from the capture. Used to restrict
89 /// a capture to the surface pieces matching the position's id.
90 ///
91 /// ptcapture picks its own point form: a GA_OffsetArray takes the surface
92 /// offsets, a UT_IntArray the point indices the GPU kernels index by.
93 template<typename PA, typename RESOLVER, typename PTARRAY>
94 void
96  UT_IntArray &primptstarts,
97  PTARRAY &ptcapture,
98  UT_FloatArray &ptweights,
99  const PA &positions,
100  const GU_Detail &surfacegdp,
101  const RESOLVER &resolve)
102 {
103  using PtType = typename PTARRAY::value_type;
104  static_assert(
105  std::is_same_v<PtType, GA_Offset> || std::is_same_v<PtType, int>,
106  "surface capture points come out as GA_Offset or point index");
107 
108  utZoneScoped;
109  GA_OffsetArray primoffsets;
110  UT_Vector3Array primuvs;
111  UT_IntArray primptcounts;
112 
113  primoffsets.setSizeNoInit(positions.size());
114  primuvs.setSizeNoInit(positions.size());
115 
116  primptcounts.setSizeNoInit(positions.size());
117  primptstarts.setSizeNoInit(positions.size()+1);
118 
119  {
120  utZoneScopedN("counts");
122  UT_BlockedRange<exint>(0, positions.size()),
123  [&](const UT_BlockedRange<exint> &r)
124  {
125  utZoneScopedN("task");
126  for (exint i = r.begin(), end = r.end(); i < end; ++i)
127  {
128  UT_Vector3 pos = positions[i];
129 
130  GU_MinInfo mininfo{};
131  resolve(i, pos, mininfo);
132 
133  GA_Offset primoff = mininfo.prim.offset();
134 
135  if (primoff != GA_INVALID_OFFSET)
136  {
137  primoffsets[i] = primoff;
138  primuvs[i] = UT_Vector3(mininfo.u1, mininfo.v1, 0.0f);
139  primptcounts[i] = surfacegdp.getPrimitiveVertexCount(primoff);
140  }
141  else
142  {
143  primoffsets[i] = GA_INVALID_OFFSET;
144  primuvs[i] = UT_Vector3(0.0f);
145  primptcounts[i] = 0;
146  }
147  }
148  });
149  }
150 
151  {
152  utZoneScopedN("scan");
153  primptstarts[0] = 0;
154  std::inclusive_scan(
155  primptcounts.begin(), primptcounts.end(),
156  primptstarts.begin() + 1);
157  }
158 
159  GA_Size offsetcount = primptstarts[primptstarts.size()-1];
160  ptcapture.setSizeNoInit(offsetcount);
161  ptweights.setSizeNoInit(offsetcount);
162 
163  {
164  utZoneScopedN("offsets");
166  UT_BlockedRange<exint>(0, positions.size()),
167  [&](const UT_BlockedRange<exint> &r)
168  {
169  utZoneScopedN("task");
170  for (exint i = r.begin(), end = r.end(); i < end; ++i)
171  {
172  GA_Offset primoff = primoffsets[i];
173  UT_Vector3 primuv = primuvs[i];
174 
175  if (primoff == GA_INVALID_OFFSET)
176  continue;
177 
179  UT_Array<float> weights;
181  &surfacegdp, primoff, offsets, weights, primuv, true);
182 
183  for (int j=0; j<offsets.size(); ++j)
184  {
185  if constexpr (std::is_same_v<PtType, GA_Offset>)
186  ptcapture[primptstarts[i] + j] = offsets[j];
187  else
188  ptcapture[primptstarts[i] + j] =
189  surfacegdp.pointIndex(offsets[j]);
190  ptweights[primptstarts[i] + j] = weights[j];
191  }
192  }
193  });
194  }
195 }
196 
197 template<typename PA, typename PTARRAY>
198 void
200  UT_IntArray &primptstarts,
201  PTARRAY &ptcapture,
202  UT_FloatArray &ptweights,
203  const PA &positions,
204  const GU_Detail &surfacegdp,
205  const GU_RayIntersect &rayintersect)
206 {
208  primptstarts, ptcapture, ptweights, positions, surfacegdp,
209  [&rayintersect](exint, const UT_Vector3 &pos, GU_MinInfo &mininfo)
210  {
211  rayintersect.minimumPoint(pos, mininfo);
212  });
213 }
214 
215 GU_API void
217  const GU_Detail &gdp,
218  const GA_ROHandleV3 &poshandle,
219  GA_AttributeUPtr &nmlowner,
220  GA_AttributeUPtr &tanowner);
221 
222 template <
223  typename OUTPOS,
224  typename INPOS,
225  typename DEFRESTPOS,
226  typename DEFANIMPOS>
227 void
229  OUTPOS &newposdata,
230  const INPOS &points,
231  const DEFRESTPOS &constrestpos,
232  const DEFANIMPOS &constanimpos,
233  const GU_Detail &defgdp,
234  const GA_ROHandleV3 restnmlattrib,
235  const GA_ROHandleV3 resttanattrib,
236  const GA_ROHandleV3 animnmlattrib,
237  const GA_ROHandleV3 animtanattrib,
238  const UT_IntArray &primptstarts,
239  const GA_OffsetArray &ptoffsets,
240  const UT_FloatArray &ptweights)
241 {
242  utZoneScoped;
243  using value_type = typename OUTPOS::value_type;
245  UT_BlockedRange<exint>(0, points.size()),
246  [&](const UT_BlockedRange<exint> &r)
247  {
248  for (exint i = r.begin(), end = r.end(); i < end; ++i)
249  {
250  GA_Size ptstart = primptstarts[i];
251  GA_Size ptend = primptstarts[i + 1];
252  if (ptstart != ptend)
253  {
254  UT_Vector3 restpos(0.0f);
255  UT_Vector3 animpos(0.0f);
256 
257  UT_Vector3 restnml(0.0f);
258  UT_Vector3 animnml(0.0f);
259 
260  UT_Vector3 resttan(0.0f);
261  UT_Vector3 animtan(0.0f);
262 
263  for (int j = ptstart; j < ptend; ++j)
264  {
265  GA_Offset ptoff = ptoffsets[j];
266  GA_Size index = defgdp.pointIndex(ptoff);
267 
268  float w = ptweights[j];
269  restpos += w * constrestpos[index];
270  animpos += w * constanimpos[index];
271 
272  restnml += w * restnmlattrib.get(ptoff);
273  animnml += w * animnmlattrib.get(ptoff);
274 
275  resttan += w * resttanattrib.get(ptoff);
276  animtan += w * animtanattrib.get(ptoff);
277  }
278 
279  restnml.normalize();
280  animnml.normalize();
281 
282  resttan.normalize();
283  animtan.normalize();
284 
285  UT_Matrix3 deformrot;
286  deformrot.lookat(UT_Vector3(0.0f), animnml, animtan);
287  UT_Matrix4 deformspace(deformrot);
288  deformspace.translate(animpos);
289 
290  UT_Matrix3 restrot;
291  restrot.lookat(UT_Vector3(0.0f), restnml, resttan);
292  UT_Matrix4 restspace(restrot);
293  restspace.translate(restpos);
294 
295  restspace.invert();
296 
297  if constexpr(std::is_same_v<value_type, UT_Matrix4>)
298  {
299  newposdata.set(i, restspace * deformspace);
300  }
301  else
302  {
303  UT_Vector3 pos(points[i].data());
304  pos *= restspace * deformspace;
305 
306  newposdata.set(i, pos);
307  }
308  }
309  else
310  {
311  // fall back to undeformed xform/position
312  if constexpr(std::is_same_v<value_type, UT_Matrix4>)
313  {
314  newposdata.set(i, UT_Matrix4(1.0f));
315  }
316  else
317  {
318  newposdata.set(i, points[i].data());
319  }
320  }
321  }
322  });
323 }
324 
326 {
327 public:
328  void init(const GU_Detail &surfaceGdp);
329 
330  // Project positions onto rest surface mesh.
331  // Outputs per-position: contributing mesh point indices + barycentric
332  // weights.
333  // PA must support operator[](int) -> UT_Vector3 and size() -> int.
334  template<typename PA>
335  void project(
336  UT_IntArray &ptStarts,
337  UT_IntArray &ptIndices,
338  UT_FloatArray &ptWeights,
339  const PA &positions)
340  {
342  ptStarts,
343  ptIndices,
344  ptWeights,
345  positions,
346  *myRestSurface,
347  *myRayIntersect);
348  }
349 
350  const GU_Detail &restSurface() const { return *myRestSurface; }
351 
352 private:
353  UT_UniquePtr<GU_Detail> myRestSurface;
354  UT_UniquePtr<GU_RayIntersect> myRayIntersect;
355 };
356 
357 /// CPU-side capture for subdivision surface deformation.
358 /// Copies the rest surface and projects positions onto it via ray
359 /// intersection. The GT topology building and ptex conversion must
360 /// be performed externally (GT symbols can't link from GU).
362 {
363 public:
364  /// Copy rest surface and build ray intersect.
365  void init(const GU_Detail &restSurfaceGdp);
366 
367  /// Project positions onto the rest surface coarse mesh.
368  /// Outputs per-position: coarse face index (prim index into rest gdp),
369  /// barycentric u/v. Face index is -1 if the point was not captured.
370  /// PA must support operator[](int) -> UT_Vector3 and size() -> int.
371  /// Returns false on hard errors (invalid state).
372  template<typename PA>
373  bool project(
374  UT_IntArray &coarseFace,
375  UT_FloatArray &coarseU,
376  UT_FloatArray &coarseV,
377  const PA &positions)
378  {
379  utZoneScoped;
380  if (!myRayIntersect || !myRestSurface)
381  return false;
382 
383  const exint numpts = positions.size();
384  coarseFace.setSizeNoInit(numpts);
385  coarseU.setSizeNoInit(numpts);
386  coarseV.setSizeNoInit(numpts);
387 
388  {
389  utZoneScopedN("subd_project_ray");
391  UT_BlockedRange<exint>(0, numpts),
392  [&](const UT_BlockedRange<exint> &r)
393  {
394  for (exint i = r.begin(), end = r.end(); i < end; ++i)
395  {
396  GU_MinInfo mininfo{};
397  myRayIntersect->minimumPoint(positions[i], mininfo);
398  GA_Offset primoff = mininfo.prim.offset();
399  if (primoff != GA_INVALID_OFFSET)
400  {
401  coarseFace[i] =
402  (int)myRestSurface->primitiveIndex(primoff);
403  coarseU[i] = mininfo.u1;
404  coarseV[i] = mininfo.v1;
405  }
406  else
407  {
408  coarseFace[i] = -1;
409  coarseU[i] = 0.5f;
410  coarseV[i] = 0.5f;
411  }
412  }
413  });
414  }
415 
416  return true;
417  }
418 
419  bool isValid() const { return myRestSurface != nullptr; }
420  const GU_Detail &restSurface() const { return *myRestSurface; }
421 
422 private:
423  UT_UniquePtr<GU_Detail> myRestSurface;
424  UT_UniquePtr<GU_RayIntersect> myRayIntersect;
425 };
426 
427 GU_API void
429  CE_Context &context,
430  bool recompile,
431  int nprims,
432  CE_Array<float> &surfacexform,
433  const cl::Buffer &surfacePtStarts,
434  const cl::Buffer &surfacePtIndices,
435  const cl::Buffer &surfacePtWeights,
436  const cl::Buffer &restPos,
437  const cl::Buffer &restNml,
438  const cl::Buffer &restTan,
439  const cl::Buffer &animPos,
440  const cl::Buffer &animNml,
441  const cl::Buffer &animTan,
442  const cl::Buffer *grp = nullptr);
443 
444 GU_API void
446  CE_Context &context,
447  bool recompile,
448  int nprims,
449  CE_Array<float> &surfacexform,
450  const cl::Buffer &restPos,
451  const cl::Buffer &restNml,
452  const cl::Buffer &restTan,
453  const cl::Buffer &animPos,
454  const cl::Buffer &animNml,
455  const cl::Buffer &animTan,
456  const cl::Buffer *grp = nullptr);
457 
458 GU_API void
460  CE_Context &context,
461  bool recompile,
462  int npts,
463  const cl::Buffer &outPos,
464  const cl::Buffer &inPos,
465  const cl::Buffer &surfacexform,
466  const cl::Buffer &pointPrimsIndex,
467  const cl::Buffer &pointPrims,
468  const cl::Buffer *grp = nullptr,
469  const cl::Buffer *mask = nullptr);
470 
471 GU_API void
472 xform(
473  CE_Context &context,
474  bool recompile,
475  int npts,
476  const cl::Buffer &outPos,
477  const cl::Buffer &inPos,
478  const cl::Buffer &surfacexform,
479  const cl::Buffer *grp = nullptr);
480 
481 }
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)
void surfaceInterpOffsets(UT_IntArray &primptstarts, PTARRAY &ptcapture, UT_FloatArray &ptweights, const PA &positions, const GU_Detail &surfacegdp, const GU_RayIntersect &rayintersect)
GLdouble GLdouble GLint GLint const GLdouble * points
Definition: glad.h:2676
GLboolean * data
Definition: glcorearb.h:131
void surfaceInterpOffsetsFromResolver(UT_IntArray &primptstarts, PTARRAY &ptcapture, UT_FloatArray &ptweights, const PA &positions, const GU_Detail &surfacegdp, const RESOLVER &resolve)
#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
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 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