HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros 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 
31 /// Interpoates attributes based on primitive index and (u,v,w)
32 /// INT must be int32 or int64.
33 template<typename INT>
35  const GEO_Detail *source,
36  const GA_AttributeRefMap &attribmap,
37  const GA_Range &destrange,
38  const GA_ROHandleT<INT> &primnumattrib,
39  const GA_ROHandleV3 &primuvwattrib);
40 
41 /// Interpoates attributes based on primitive number and (u,v,w),
42 /// and fills in computeindexattrib and computeweightattrib
43 /// with the point or vertex indices and weights that produced
44 /// the interpolation. computenumbersof determines whether
45 /// computeindexattrib receives point or vertex indices.
46 /// computeindexattrib and computeweightattrib must implement GA_AIFNumericArray.
47 /// INT must be int32 or int64.
48 template<typename INT>
50  const GEO_Detail *source,
51  const GA_AttributeRefMap &attribmap,
52  const GA_Range &destrange,
53  const GA_ROHandleT<INT> &primnumattrib,
54  const GA_ROHandleV3 &primuvwattrib,
55  GA_AttributeOwner computenumbersof,
56  GA_Attribute *computeindexattrib,
57  GA_Attribute *computeweightattrib);
58 
59 
60 /// Interpoates attributes based on arrays of indices and weights specified in
61 /// indexattrib and weightattrib. indexowner specifies whether the source
62 /// indices are for points, vertices, or primitives.
63 /// indexattrib and weightattrib must implement GA_AIFNumericArray.
65  const GEO_Detail *source,
66  const GA_AttributeRefMap &attribmap,
67  const GA_Range &destrange,
68  GA_AttributeOwner indexowner,
69  const GA_Attribute *indexattrib,
70  const GA_Attribute *weightattrib);
71 
72 template<typename T,typename S>
73 inline void GEOquadInterpolationWeights(T u, T v, S weights[4])
74 {
75  T u1 = 1-u;
76  T v1 = 1-v;
77  weights[0] = (u1 * v1);
78  weights[1] = (u1 * v);
79  weights[2] = (u * v);
80  weights[3] = (u * v1);
81 }
82 
83 template<typename T,typename S>
84 inline void GEOtriInterpolationWeights(T u, T v, S weights[3])
85 {
86  // Triangle - use barycentric coordinates
87 
88  // This is a hack to make sure we are given proper
89  // barycentric u, v coordinates. That is, we require
90  // u+v <= 1, and if that's not the case we hack it so
91  // u = 1-u, v = 1-v, thus ensuring u+v <= 1. (This
92  // assumes that u, v are each between 0 and 1)
93  // This is used for when evaluateInteriorPoint is
94  // called from POP_GenVar for birthing from a surface.
95  //
96  // Note we actually flip on the u+v = 1 axis instead
97  // of what is described above so slightly outside points
98  // do not teleport to opposite locations.
99  T uv = 1 - u - v;
100 
101  if (uv < 0)
102  {
103  u += uv;
104  v += uv;
105  uv = -uv;
106  }
107 
108  weights[0] = uv;
109  weights[1] = u;
110  weights[2] = v;
111 }
112 
113 template <typename T>
114 inline void
115 GEOgetXYProjection(const UT_Vector3T<T> &nml, int &x, int &y)
116 {
117  int z = (SYSabs(nml.y()) > SYSabs(nml.x())) ? 1 : 0;
118  if (SYSabs(nml.z()) > SYSabs(nml(z))) z = 2;
119  switch (z)
120  {
121  case 0: x = 1; y = 2; break;
122  case 1: x = 0; y = 2; break;
123  case 2: x = 0; y = 1; break;
124  }
125 }
126 
127 template<typename POLY>
128 static void
129 GEOprimUVWPrecompute(const POLY &poly, int &xaxis, int &yaxis, float &centrex, float &centrey)
130 {
131  // NOTE: This is trying to be equivalent to GU_RayPolyInfo, though that
132  // may not matter.
133 
134  GA_Size nvertices = poly.getFastVertexCount();
135  UT_Vector3 normal(0, 0, 0);
136  UT_Vector3 centre(0, 0, 0);
137  UT_Vector3 p2 = poly.getPos3(nvertices-1);
138  for (GA_Size i = 0; i < nvertices; ++i)
139  {
140  UT_Vector3 p1 = p2;
141  p2 = poly.getPos3(i);
142  centre += p2;
143  // Use Newell's method to accumulate the face normal
144  normal.normal(p1, p2);
145  }
146  // NOTE: GEOgetXYProjection works without normalizing normal
147  GEOgetXYProjection(normal, xaxis, yaxis);
148  centrex = centre[xaxis]/float(nvertices);
149  centrey = centre[yaxis]/float(nvertices);
150 }
151 
152 template<typename POLY>
153 static UT_Vector3
154 GEOprimUVWNonConvex(const POLY &poly, const UT_Vector3 &p, int xaxis, int yaxis, float centrex, float centrey, const float w=0)
155 {
156  // NOTE: Although this is slow to do for every point, it's what GU_RayPolyInfo::intersect does
157 
158  float x0 = p[xaxis];
159  float y0 = p[yaxis];
160 
161  const GA_Size n = poly.getFastVertexCount();
162 
163  UT_ASSERT_P(n >= 5);
164 
165  // Calculate the u & v values. Use UT_SampleTri2D.
166  UT_SampleTri2D sample;
167  GA_Size li = n-1;
168  UT_Vector3 p0 = poly.getPos3(li);
169  bool found = false;
170  UT_Vector3 output(0, 0, w);
171  for (GA_Size i = 0; i < n; ++i)
172  {
173  UT_Vector3 p1 = poly.getPos3(i);
174  sample.setVertices(p0[xaxis], p0[yaxis],
175  p1[xaxis], p1[yaxis],
176  centrex, centrey);
177  // If we have a valid hit, process into the correct space and break.
178  // Because of roundoff error, a point that should be inside may
179  // be incorrectly identified as outside, so we allow samples that
180  // are in [-1e-6, 1+1e-6] for all 3 barycentric coordinates.
181  if (sample.sample(x0, y0, output[0], output[1], 1e-6))
182  {
183  found = true;
184 
185  // With the tolerance, it might be just outside, in which case,
186  // keep checking for another triangle that might be a direct hit.
187  bool isedgecase = (output[0] < 0 || output[1] < 0 || output[0]+output[1] > 1);
188  if (isedgecase)
189  {
190  // Force it to be in range
191  output[0] = SYSclamp(output[0], 0.0f, 1.0f);
192  output[1] = SYSclamp(output[1], 0.0f, 1.0f);
193  if (output[0]+output[1] > 1)
194  output[1] = 1.0f - output[0];
195  }
196  // We have v == 1 being barycenter.
197  // u == 0 is li, and u == 1 is i.
198  if (output[1] != 1.0f)
199  output[0] /= 1.0f - output[1];
200  output[0] = (output[0] + float(li)) / float(n);
201 
202  if (!isedgecase)
203  break;
204  }
205  li = i;
206  p0 = p1;
207  }
208  if (found)
209  return output;
210 
211  // Nothing hit directly; restart and
212  // try clamping to triangle and getting min (2D) distance.
213  // NOTE: This is not guaranteed to get the minimum distance,
214  // even in 2D, because we're just clamping in parametric
215  // space. This is just to ensure that we always return
216  // something in the ballpark of the sample.
217  li = n-1;
218  p0 = poly.getPos3(li);
219  float mind2;
220  GA_Size outputli;
221  UT_Vector2 puv(p0[xaxis], p0[yaxis]);
222  UT_Vector2 pv(centrex, centrey);
223  UT_Vector2 ps(p[xaxis], p[yaxis]);
224  for (GA_Size i = 0; i < n; ++i)
225  {
226  UT_Vector3 p1 = poly.getPos3(i);
227  // Confusingly, du is p1-p0, and dv is centre-p0
228  UT_Vector2 pu(p1[xaxis], p1[yaxis]);
229  UT_Vector2 du = pu - puv;
230  UT_Vector2 dv = pv - puv;
231  UT_Vector2 s = ps - puv;
232  float scale = 1.0f / cross(du, dv);
233  if (!SYSisFinite(scale))
234  continue;
235  float u = scale * cross(s, dv);
236  float v = scale * cross(du, s);
237 
238  // Force it to be in range
239  u = SYSclamp(u, 0.0f, 1.0f);
240  v = SYSclamp(v, 0.0f, 1.0f);
241  if (u + v > 1.0f)
242  v = 1.0f - u;
243 
244  float weights[3];
245  GEOtriInterpolationWeights(u, v, weights);
246 
247  UT_Vector2 clampedp = weights[0]*puv + weights[1]*pu + weights[2]*pv;
248  float d2 = distance2d(clampedp, ps);
249  if (!found || d2 < mind2)
250  {
251  found = true;
252  mind2 = d2;
253  output[0] = u;
254  output[1] = v;
255  outputli = li;
256  }
257  li = i;
258  puv = pu;
259  }
260  // We have v == 1 being barycenter.
261  // u == 0 is li, and u == 1 is i.
262  if (output[1] != 1.0f)
263  output[0] /= 1.0f - output[1];
264  output[0] = (output[0] + float(outputli)) / float(n);
265  return output;
266 }
267 
268 /// Fill the offsets and weights arrays with the vertex/point offsets
269 /// and their corresponding interpolation weights for the given primitive
270 /// parametric space coordinate uvw, for the specified primitive.
271 ///
272 /// This acts like GEO_Primitive::computeInteriorPointWeights(), except that
273 /// it avoids hardening the primitive list if the primitive is a polygon or
274 /// tetrahedron, and if is_point_offsets is true, it will convert the offsets
275 /// to point offsets, instead of staying with vertex offsets.
276 GEO_API void
278  const GEO_Detail *detail,
279  GA_Offset primoff,
281  UT_FloatArray &weights,
282  const UT_Vector3 &uvw,
283  bool is_point_offsets=false);
284 
285 #endif
void GEOquadInterpolationWeights(T u, T v, S weights[4])
Definition of a geometry attribute.
Definition: GA_Attribute.h:189
GA_API const UT_StringHolder uv
const GLdouble * v
Definition: glcorearb.h:836
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:847
#define SYSabs(a)
Definition: SYS_Math.h:1367
GLint y
Definition: glcorearb.h:102
void geoInterpolateAttributes(const GEO_Detail *source, const GA_AttributeRefMap &attribmap, const GA_Range &destrange, const GA_ROHandleT< INT > &primnumattrib, const GA_ROHandleV3 &primuvwattrib)
SYS_FORCE_INLINE T & x(void)
Definition: UT_Vector3.h:581
3D Vector class.
png_uint_32 i
Definition: png.h:2877
exint GA_Size
Defines the bit width for index and offset types in GA.
Definition: GA_Types.h:211
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:101
A range of elements in an index-map.
Definition: GA_Range.h:42
GLuint GLsizei const GLuint const GLintptr * offsets
Definition: glcorearb.h:2620
GA_Size GA_Offset
Definition: GA_Types.h:617
SYS_FORCE_INLINE T & z(void)
Definition: UT_Vector3.h:585
GA_API const UT_StringHolder scale
GLdouble n
Definition: glcorearb.h:2007
GLfloat f
Definition: glcorearb.h:1925
GEO_API void GEOgetInterpolationWeights(const GEO_Detail *detail, GA_Offset primoff, UT_Array< GA_Offset > &offsets, UT_FloatArray &weights, const UT_Vector3 &uvw, bool is_point_offsets=false)
void setVertices(fpreal x0, fpreal y0, fpreal x1, fpreal y1, fpreal x2, fpreal y2)
Definition: UT_PolySample.h:74
GLsizei GLsizei GLchar * source
Definition: glcorearb.h:802
#define GEO_API
Definition: GEO_API.h:10
A handle to simplify manipulation of multiple attributes.
SYS_FORCE_INLINE T & y(void)
Definition: UT_Vector3.h:583
GA_AttributeOwner
Definition: GA_Types.h:33
void GEOgetXYProjection(const UT_Vector3T< T > &nml, int &x, int &y)
GLint GLenum GLint x
Definition: glcorearb.h:408
GLfloat GLfloat v1
Definition: glcorearb.h:816
GLubyte GLubyte GLubyte GLubyte w
Definition: glcorearb.h:856
SYS_FORCE_INLINE void normal(const UT_Vector3T< T > &va, const UT_Vector3T< T > &vb)
Definition: UT_Vector3.h:457
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:492
bool SYSisFinite(fpreal16 f)
Definition: SYS_Math.h:198