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