HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GEO_Interpolate.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: GEO_Interpolate.h (GEO Library, C++)
7  *
8  * COMMENTS: Declarations for attribute interpolation functions
9  */
10 
11 #pragma once
12 
13 #ifndef __GEO_Interpolate__
14 #define __GEO_Interpolate__
15 
16 #include "GEO_API.h"
17 #include <GA/GA_Handle.h>
18 #include <GA/GA_Types.h>
19 #include <UT/UT_Array.h>
20 #include <UT/UT_VectorTypes.h>
21 #include <UT/UT_PolySample.h>
22 #include <UT/UT_Vector3.h>
23 #include <SYS/SYS_Math.h>
24 
25 class GEO_Detail;
26 class GA_AttributeRefMap;
28 class GA_Attribute;
29 class GA_Range;
30 
32 {
34  fpreal blend = 0.0;
36  bool normalize = false;
37 };
38 
39 /// Interpoates attributes based on primitive index and (u,v,w)
40 /// INT must be int32 or int64.
41 template<typename INT>
43  const GEO_Detail *source,
44  const GA_AttributeRefMap &attribmap, // dest must be destrange type
45  const GA_Range &destrange,
46  const GA_ROHandleT<INT> &primnumattrib,
47  const GA_ROHandleV3 &primuvwattrib,
48  const GEO_InterpolationOptions &options);
49 
50 /// Interpoates attributes based on primitive number and (u,v,w),
51 /// and fills in computeindexattrib and computeweightattrib
52 /// with the point or vertex indices and weights that produced
53 /// the interpolation. computenumbersof determines whether
54 /// computeindexattrib receives point or vertex indices.
55 /// computeindexattrib and computeweightattrib must implement GA_AIFNumericArray.
56 /// INT must be int32 or int64.
57 template<typename INT>
59  const GEO_Detail *source,
60  const GA_AttributeRefMap &attribmap, // dest must be destrange type
61  const GA_Range &destrange,
62  const GA_ROHandleT<INT> &primnumattrib,
63  const GA_ROHandleV3 &primuvwattrib,
64  GA_AttributeOwner computenumbersof,
65  GA_Attribute *computeindexattrib,
66  GA_Attribute *computeweightattrib,
67  const GEO_InterpolationOptions &options);
68 
69 
70 /// Interpoates attributes based on arrays of indices and weights specified in
71 /// indexattrib and weightattrib. indexowner specifies whether the source
72 /// indices are for points, vertices, or primitives.
73 /// indexattrib and weightattrib must implement GA_AIFNumericArray.
75  const GEO_Detail *source,
76  const GA_AttributeRefMap &attribmap, // dest must be destrange type
77  const GA_Range &destrange,
78  GA_AttributeOwner indexowner,
79  const GA_Attribute *indexattrib,
80  const GA_Attribute *weightattrib,
81  const GEO_InterpolationOptions &options);
82 
83 template<typename T,typename S>
84 inline void GEOquadInterpolationWeights(T u, T v, S weights[4])
85 {
86  T u1 = 1-u;
87  T v1 = 1-v;
88  weights[0] = (u1 * v1);
89  weights[1] = (u1 * v);
90  weights[2] = (u * v);
91  weights[3] = (u * v1);
92 }
93 
94 template<typename T,typename S>
95 inline void GEOtriInterpolationWeights(T u, T v, S weights[3])
96 {
97  // Triangle - use barycentric coordinates
98 
99  // This is a hack to make sure we are given proper
100  // barycentric u, v coordinates. That is, we require
101  // u+v <= 1, and if that's not the case we hack it so
102  // u = 1-u, v = 1-v, thus ensuring u+v <= 1. (This
103  // assumes that u, v are each between 0 and 1)
104  // This is used for when evaluateInteriorPoint is
105  // called from POP_GenVar for birthing from a surface.
106  //
107  // Note we actually flip on the u+v = 1 axis instead
108  // of what is described above so slightly outside points
109  // do not teleport to opposite locations.
110  T uv = 1 - u - v;
111 
112  if (uv < 0)
113  {
114  u += uv;
115  v += uv;
116  uv = -uv;
117  }
118 
119  weights[0] = uv;
120  weights[1] = u;
121  weights[2] = v;
122 }
123 
124 template <typename T>
125 inline void
126 GEOgetXYProjection(const UT_Vector3T<T> &nml, int &x, int &y)
127 {
128  int z = (SYSabs(nml.y()) > SYSabs(nml.x())) ? 1 : 0;
129  if (SYSabs(nml.z()) > SYSabs(nml(z))) z = 2;
130  switch (z)
131  {
132  case 0: x = 1; y = 2; break;
133  case 1: x = 0; y = 2; break;
134  case 2: x = 0; y = 1; break;
135  }
136 }
137 
138 template<typename POLY>
139 static void
140 GEOprimUVWPrecompute(const POLY &poly, int &xaxis, int &yaxis, float &centrex, float &centrey)
141 {
142  // NOTE: This is trying to be equivalent to GU_RayPolyInfo, though that
143  // may not matter.
144 
145  GA_Size nvertices = poly.getFastVertexCount();
146  UT_Vector3 normal(0, 0, 0);
147  UT_Vector3 centre(0, 0, 0);
148  UT_Vector3 p2 = poly.getPos3(nvertices-1);
149  for (GA_Size i = 0; i < nvertices; ++i)
150  {
151  UT_Vector3 p1 = p2;
152  p2 = poly.getPos3(i);
153  centre += p2;
154  // Use Newell's method to accumulate the face normal
155  normal.normal(p1, p2);
156  }
157  // NOTE: GEOgetXYProjection works without normalizing normal
158  GEOgetXYProjection(normal, xaxis, yaxis);
159  centrex = centre[xaxis]/float(nvertices);
160  centrey = centre[yaxis]/float(nvertices);
161 }
162 
163 template<typename POLY>
164 static UT_Vector3
165 GEOprimUVWNonConvex(const POLY &poly, const UT_Vector3 &p, int xaxis, int yaxis, float centrex, float centrey, const float w=0)
166 {
167  // NOTE: Although this is slow to do for every point, it's what GU_RayPolyInfo::intersect does
168 
169  float x0 = p[xaxis];
170  float y0 = p[yaxis];
171 
172  const GA_Size n = poly.getFastVertexCount();
173 
174  UT_ASSERT_P(n >= 5);
175 
176  // Calculate the u & v values. Use UT_SampleTri2D.
177  UT_SampleTri2D sample;
178  GA_Size li = n-1;
179  UT_Vector3 p0 = poly.getPos3(li);
180  bool found = false;
181  UT_Vector3 output(0, 0, w);
182  for (GA_Size i = 0; i < n; ++i)
183  {
184  UT_Vector3 p1 = poly.getPos3(i);
185  sample.setVertices(p0[xaxis], p0[yaxis],
186  p1[xaxis], p1[yaxis],
187  centrex, centrey);
188  // If we have a valid hit, process into the correct space and break.
189  // Because of roundoff error, a point that should be inside may
190  // be incorrectly identified as outside, so we allow samples that
191  // are in [-1e-6, 1+1e-6] for all 3 barycentric coordinates.
192  if (sample.sample(x0, y0, output[0], output[1], 1e-6))
193  {
194  found = true;
195 
196  // With the tolerance, it might be just outside, in which case,
197  // keep checking for another triangle that might be a direct hit.
198  bool isedgecase = (output[0] < 0 || output[1] < 0 || output[0]+output[1] > 1);
199  if (isedgecase)
200  {
201  // Force it to be in range
202  output[0] = SYSclamp(output[0], 0.0f, 1.0f);
203  output[1] = SYSclamp(output[1], 0.0f, 1.0f);
204  if (output[0]+output[1] > 1)
205  output[1] = 1.0f - output[0];
206  }
207  // We have v == 1 being barycenter.
208  // u == 0 is li, and u == 1 is i.
209  if (output[1] != 1.0f)
210  output[0] /= 1.0f - output[1];
211  output[0] = (output[0] + float(li)) / float(n);
212 
213  if (!isedgecase)
214  break;
215  }
216  li = i;
217  p0 = p1;
218  }
219  if (found)
220  return output;
221 
222  // Nothing hit directly; restart and
223  // try clamping to triangle and getting min (2D) distance.
224  // NOTE: This is not guaranteed to get the minimum distance,
225  // even in 2D, because we're just clamping in parametric
226  // space. This is just to ensure that we always return
227  // something in the ballpark of the sample.
228  li = n-1;
229  p0 = poly.getPos3(li);
230  float mind2;
231  GA_Size outputli;
232  UT_Vector2 puv(p0[xaxis], p0[yaxis]);
233  UT_Vector2 pv(centrex, centrey);
234  UT_Vector2 ps(p[xaxis], p[yaxis]);
235  for (GA_Size i = 0; i < n; ++i)
236  {
237  UT_Vector3 p1 = poly.getPos3(i);
238  // Confusingly, du is p1-p0, and dv is centre-p0
239  UT_Vector2 pu(p1[xaxis], p1[yaxis]);
240  UT_Vector2 du = pu - puv;
241  UT_Vector2 dv = pv - puv;
242  UT_Vector2 s = ps - puv;
243  float scale = 1.0f / cross(du, dv);
244  if (!SYSisFinite(scale))
245  continue;
246  float u = scale * cross(s, dv);
247  float v = scale * cross(du, s);
248 
249  // Force it to be in range
250  u = SYSclamp(u, 0.0f, 1.0f);
251  v = SYSclamp(v, 0.0f, 1.0f);
252  if (u + v > 1.0f)
253  v = 1.0f - u;
254 
255  float weights[3];
256  GEOtriInterpolationWeights(u, v, weights);
257 
258  UT_Vector2 clampedp = weights[0]*puv + weights[1]*pu + weights[2]*pv;
259  float d2 = distance2d(clampedp, ps);
260  if (!found || d2 < mind2)
261  {
262  found = true;
263  mind2 = d2;
264  output[0] = u;
265  output[1] = v;
266  outputli = li;
267  }
268  li = i;
269  puv = pu;
270  }
271  // We have v == 1 being barycenter.
272  // u == 0 is li, and u == 1 is i.
273  if (output[1] != 1.0f)
274  output[0] /= 1.0f - output[1];
275  output[0] = (output[0] + float(outputli)) / float(n);
276  return output;
277 }
278 
279 /// Fill the offsets and weights arrays with the vertex/point offsets
280 /// and their corresponding interpolation weights for the given primitive
281 /// parametric space coordinate uvw, for the specified primitive.
282 ///
283 /// This acts like GEO_Primitive::computeInteriorPointWeights(), except that
284 /// it avoids hardening the primitive list if the primitive is a polygon or
285 /// tetrahedron, and if is_point_offsets is true, it will convert the offsets
286 /// to point offsets, instead of staying with vertex offsets.
287 GEO_API void
289  const GEO_Detail *detail,
290  GA_Offset primoff,
292  UT_Array<float> &weights,
293  const UT_Vector3 &uvw,
294  bool is_point_offsets=false);
295 
296 /// @{
297 /// Evaluate a GA_ROHandle based on the uvw position, can either evaluate
298 /// into a buffer or return the result.
299 ///
300 /// Uses GEOgetInterpolationWeights in order to interpolate vertex and point
301 /// attributes.
302 template <typename T>
303 GEO_API void
305  const GEO_Detail *gdp,
306  GA_Offset primoff,
307  const GA_ROHandleT<T> &h,
308  const UT_Vector3 &uvw,
309  T *buf,
310  int size);
311 
312 GEO_API void
314  const GEO_Detail *gdp,
315  GA_Offset primoff,
316  const GA_ROHandleS &h,
317  const UT_Vector3 &uvw,
319  int size);
320 
321 template <typename T>
324  const GEO_Detail *gdp,
325  GA_Offset primoff,
326  const GA_ROHandleT<T> &h,
327  const UT_Vector3 &uvw)
328 {
329  T buf;
330  GEOevaluateInteriorPoint(gdp, primoff, h, uvw, &buf, 1);
331  return buf;
332 }
333 
337  const GEO_Detail *gdp,
338  GA_Offset primoff,
339  const GA_ROHandleS &h,
340  const UT_Vector3 &uvw)
341 {
343  GEOevaluateInteriorPoint(gdp, primoff, h, uvw, &buf, 1);
344  return buf;
345 }
346 
347 #endif
void GEOquadInterpolationWeights(T u, T v, S weights[4])
Definition of a geometry attribute.
Definition: GA_Attribute.h:198
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glcorearb.h:2540
void geoInterpolateAttributes(const GEO_Detail *source, const GA_AttributeRefMap &attribmap, const GA_Range &destrange, const GA_ROHandleT< INT > &primnumattrib, const GA_ROHandleV3 &primuvwattrib, const GEO_InterpolationOptions &options)
GEO_API void GEOevaluateInteriorPoint(const GEO_Detail *gdp, GA_Offset primoff, const GA_ROHandleT< T > &h, const UT_Vector3 &uvw, T *buf, int size)
GA_API const UT_StringHolder uv
const GLdouble * v
Definition: glcorearb.h:837
bool SYSisFinite(fpreal64 f)
Definition: SYS_Math.h:201
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:848
constexpr SYS_FORCE_INLINE T & z() noexcept
Definition: UT_Vector3.h:667
GLdouble s
Definition: glad.h:3009
#define SYSabs(a)
Definition: SYS_Math.h:1572
GLint y
Definition: glcorearb.h:103
3D Vector class.
GLdouble u1
Definition: glad.h:2676
exint GA_Size
Defines the bit width for index and offset types in GA.
Definition: GA_Types.h:236
A range of elements in an index-map.
Definition: GA_Range.h:42
GLuint GLsizei const GLuint const GLintptr * offsets
Definition: glcorearb.h:2621
GA_Size GA_Offset
Definition: GA_Types.h:646
GA_API const UT_StringHolder scale
GLdouble n
Definition: glcorearb.h:2008
GLfloat f
Definition: glcorearb.h:1926
IMATH_NAMESPACE::V2f float
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:155
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
void setVertices(fpreal x0, fpreal y0, fpreal x1, fpreal y1, fpreal x2, fpreal y2)
Definition: UT_PolySample.h:74
UT_Vector3T< T > SYSclamp(const UT_Vector3T< T > &v, const UT_Vector3T< T > &min, const UT_Vector3T< T > &max)
Definition: UT_Vector3.h:1057
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)
GLsizei GLsizei GLchar * source
Definition: glcorearb.h:803
#define GEO_API
Definition: GEO_API.h:14
A handle to simplify manipulation of multiple attributes.
GLint GLenum GLint x
Definition: glcorearb.h:409
GLsizeiptr size
Definition: glcorearb.h:664
GLfloat GLfloat GLfloat GLfloat h
Definition: glcorearb.h:2002
GA_AttributeOwner
Definition: GA_Types.h:35
fpreal64 fpreal
Definition: SYS_Types.h:277
void GEOgetXYProjection(const UT_Vector3T< T > &nml, int &x, int &y)
GLfloat GLfloat v1
Definition: glcorearb.h:817
GLubyte GLubyte GLubyte GLubyte w
Definition: glcorearb.h:857
SYS_FORCE_INLINE void normal(const UT_Vector3T< T > &va, const UT_Vector3T< T > &vb)
Definition: UT_Vector3.h:539
constexpr SYS_FORCE_INLINE T & y() noexcept
Definition: UT_Vector3.h:665
int sample(fpreal x, fpreal y, float &u, float &v, fpreal tol=0.0)
Definition: UT_PolySample.h:85
SIM_DerVector3 cross(const SIM_DerVector3 &lhs, const SIM_DerVector3 &rhs)
void GEOtriInterpolationWeights(T u, T v, S weights[3])
T distance2d(const UT_Vector2T< T > &v1, const UT_Vector2T< T > &v2)
Definition: UT_Vector2.h:739
constexpr SYS_FORCE_INLINE T & x() noexcept
Definition: UT_Vector3.h:663