Vuo  2.3.2
VuoMeshParametric.cc
Go to the documentation of this file.
1 
10 #include "VuoMeshParametric.h"
11 #include <muParser/muParser.h>
12 #include "VuoMeshUtility.h"
13 
14 #include "module.h"
15 
16 extern "C"
17 {
18 #ifdef VUO_COMPILER
20  "title" : "VuoMeshParametric",
21  "dependencies" : [
22  "muparser",
23  "VuoMathExpressionParser",
24  "VuoMeshUtility"
25  ]
26  });
27 #endif
28 }
29 
33 static inline void add(float *normals, int index, VuoPoint3d normal)
34 {
35  normals[index * 3 ] += normal.x;
36  normals[index * 3 + 1] += normal.y;
37  normals[index * 3 + 2] += normal.z;
38 }
39 
43 VuoMesh VuoMeshParametric_generate(VuoReal time, VuoText xExp, VuoText yExp, VuoText zExp, VuoInteger uSubdivisions, VuoInteger vSubdivisions, bool closeU, VuoReal uMin, VuoReal uMax, bool closeV, VuoReal vMin, VuoReal vMax, VuoDictionary_VuoText_VuoReal *constants)
44 {
45  if (uSubdivisions < 2 || vSubdivisions < 2 || !xExp || !yExp || !zExp)
46  return nullptr;
47 
48  mu::Parser xParser, yParser, zParser;
49 
50  xParser.SetExpr(xExp);
51  yParser.SetExpr(yExp);
52  zParser.SetExpr(zExp);
53 
54  mu::value_type uVar = 0;
55  mu::value_type vVar = 0;
56 
57  xParser.DefineVar("u", &uVar); xParser.DefineVar("U", &uVar);
58  yParser.DefineVar("u", &uVar); yParser.DefineVar("U", &uVar);
59  zParser.DefineVar("u", &uVar); zParser.DefineVar("U", &uVar);
60  xParser.DefineVar("v", &vVar); xParser.DefineVar("V", &vVar);
61  yParser.DefineVar("v", &vVar); yParser.DefineVar("V", &vVar);
62  zParser.DefineVar("v", &vVar); zParser.DefineVar("V", &vVar);
63 
64  mu::value_type iVar = 0;
65  mu::value_type jVar = 0;
66 
67  xParser.DefineVar("i", &iVar); xParser.DefineVar("I", &iVar);
68  yParser.DefineVar("i", &iVar); yParser.DefineVar("I", &iVar);
69  zParser.DefineVar("i", &iVar); zParser.DefineVar("I", &iVar);
70  xParser.DefineVar("j", &jVar); xParser.DefineVar("J", &jVar);
71  yParser.DefineVar("j", &jVar); yParser.DefineVar("J", &jVar);
72  zParser.DefineVar("j", &jVar); zParser.DefineVar("J", &jVar);
73 
74  xParser.DefineConst("time", (double)time); xParser.DefineConst("Time", (double)time); xParser.DefineConst("TIME", (double)time);
75  yParser.DefineConst("time", (double)time); yParser.DefineConst("Time", (double)time); yParser.DefineConst("TIME", (double)time);
76  zParser.DefineConst("time", (double)time); zParser.DefineConst("Time", (double)time); zParser.DefineConst("TIME", (double)time);
77 
81 
82  if (constants)
83  {
84  unsigned long constantCount = VuoListGetCount_VuoText(constants->keys);
85  VuoText *constantKeys = VuoListGetData_VuoText(constants->keys);
86  VuoReal *constantValues = VuoListGetData_VuoReal(constants->values);
87  for (unsigned long i = 0; i < constantCount; ++i)
88  {
89  xParser.DefineConst(constantKeys[i], constantValues[i]);
90  yParser.DefineConst(constantKeys[i], constantValues[i]);
91  zParser.DefineConst(constantKeys[i], constantValues[i]);
92  }
93  }
94 
95  int width = uSubdivisions;
96  int height = vSubdivisions;
97 
98  float ustep = 1./(width-1.), vstep = 1./(height-1.);
99 
100  int vertexCount = width * height;
101 
102  unsigned int elementCount = ((uSubdivisions-1)*(vSubdivisions-1))*3*2;
103  float *positions, *normals, *textureCoordinates;
104  unsigned int *elements;
105  VuoMesh_allocateCPUBuffers(vertexCount, &positions, &normals, &textureCoordinates, nullptr, elementCount, &elements);
106  bzero(normals, sizeof(float) * 3 * vertexCount);
107 
108  try
109  {
110  int i = 0;
111  float u = 0., v = 0.;
112  for(int y = 0; y < height; y++)
113  {
114  vVar = VuoReal_lerp(vMin, vMax, (closeV && y==height-1) ? 0 : v);
115  for(int x = 0; x < width; x++)
116  {
117  uVar = VuoReal_lerp(uMin, uMax, (closeU && x==width-1) ? 0 : u);
118 
119  iVar = x + 1;
120  jVar = y + 1;
121 
122  positions[i * 3 ] = xParser.Eval();
123  positions[i * 3 + 1] = yParser.Eval();
124  positions[i * 3 + 2] = zParser.Eval();
125 
126  textureCoordinates[i * 2 ] = u;
127  textureCoordinates[i * 2 + 1] = v;
128 
129  u += ustep;
130  i++;
131  }
132 
133  u = 0.;
134  v += vstep;
135  }
136  }
137  catch (mu::Parser::exception_type &e)
138  {
139  VUserLog("Error: %s", e.GetMsg().c_str());
140  free(positions);
141  free(normals);
142  free(textureCoordinates);
143  return nullptr;
144  }
145 
146  // wind triangles
147 
148  width = uSubdivisions-1;
149  height = vSubdivisions-1;
150 
151  // Prepare an array to count how many neighboring face normals have been added to the vertex normal, so we can divide later to get the average.
152  unsigned int* normalCount = (unsigned int*)calloc(sizeof(unsigned int) * vertexCount, sizeof(unsigned int));
153 
154  int index = 0;
155  int one, two, three, four;
156  int row = 0;
157  index = 0;
158 
159  int stride = width+1;
160 
161  for(int y=0;y<height;++y)
162  {
163  for(int x=0;x<width;++x)
164  {
165  one = x + row;
166  two = x+row+1;
167  three = x+row+stride;
168  four = x+row+stride+1;
169 
170  // calculate face normal, add to normals, augment normalCount for subsequent averaging
171  VuoPoint3d faceNormal = VuoMeshUtility_faceNormal(
172  VuoPoint3d_makeFromArray(&positions[one * 3]),
173  VuoPoint3d_makeFromArray(&positions[two * 3]),
174  VuoPoint3d_makeFromArray(&positions[three * 3]));
175 
176  add(normals, one, faceNormal);
177  add(normals, two, faceNormal);
178  add(normals, three, faceNormal);
179  add(normals, four, faceNormal);
180 
181  normalCount[one]++;
182  normalCount[two]++;
183  normalCount[three]++;
184  normalCount[four]++;
185 
186  if(closeU && x == width-1)
187  {
188  // Add the first face in row normal to right-most vertices
189  VuoPoint3d uNrm = VuoMeshUtility_faceNormal(
190  VuoPoint3d_makeFromArray(&positions[row * 3]),
191  VuoPoint3d_makeFromArray(&positions[(row + 1) * 3]),
192  VuoPoint3d_makeFromArray(&positions[(row + stride) * 3]));
193 
194  add(normals, two, uNrm);
195  add(normals, four, uNrm);
196  // And add the current face normal to the origin row vertex normals
197  add(normals, row, faceNormal);
198  add(normals, row + stride, faceNormal);
199 
200  normalCount[two]++;
201  normalCount[four]++;
202  normalCount[row]++;
203  normalCount[row+stride]++;
204  }
205 
206  if(closeV && y==height-1)
207  {
208  VuoPoint3d vNrm = VuoMeshUtility_faceNormal(
209  VuoPoint3d_makeFromArray(&positions[x * 3]),
210  VuoPoint3d_makeFromArray(&positions[(x + 1) * 3]),
211  VuoPoint3d_makeFromArray(&positions[(x + stride) * 3]));
212 
213  add(normals, three, vNrm);
214  add(normals, four, vNrm);
215  add(normals, x, faceNormal);
216  add(normals, x + 1, faceNormal);
217 
218  normalCount[three]++;
219  normalCount[four]++;
220  normalCount[x]++;
221  normalCount[x+1]++;
222  }
223 
224  // Elements are wound to be front-facing for Vuo's right-handed coordinate system.
225  // Order the elements so that the diagonal edge of each triangle
226  // is last, so that vuo.shader.make.wireframe can optionally omit them.
227  elements[index ] = three;
228  elements[index + 1] = one;
229  elements[index + 2] = two;
230  elements[index + 3] = two;
231  elements[index + 4] = four;
232  elements[index + 5] = three;
233 
234  index += 6;
235  }
236  row += stride;
237  }
238 
239  // average normals
240  for(int i = 0; i < vertexCount; i++)
241  {
242  normals[i * 3 ] /= normalCount[i];
243  normals[i * 3 + 1] /= normalCount[i];
244  normals[i * 3 + 2] /= normalCount[i];
245  }
246  free(normalCount);
247 
248  return VuoMesh_makeFromCPUBuffers(vertexCount,
249  positions, normals, textureCoordinates, nullptr,
250  elementCount, elements, VuoMesh_IndividualTriangles);
251 }