Revision 649544b8
Added by Leszek Koltunski over 7 years ago
src/main/java/org/distorted/library/type/Dynamic.java | ||
---|---|---|
102 | 102 |
|
103 | 103 |
protected Vector<VectorNoise> vn; |
104 | 104 |
protected float[] mFactor; |
105 |
protected float[][] baseV; |
|
106 |
private float[] buffer; |
|
107 |
|
|
108 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
109 |
// the coefficients of the X(t), Y(t) and Z(t) polynomials: X(t) = ax*T^3 + bx*T^2 + cx*t + dx etc. |
|
110 |
// (tangent) is the vector tangent to the path. |
|
111 |
// (cached) is the original vector from vv (copied here so when interpolating we can see if it is |
|
112 |
// still valid and if not - rebuild the Cache |
|
113 |
|
|
114 |
protected class VectorCache |
|
115 |
{ |
|
116 |
float[] a; |
|
117 |
float[] b; |
|
118 |
float[] c; |
|
119 |
float[] d; |
|
120 |
float[] tangent; |
|
121 |
float[] cached; |
|
122 |
|
|
123 |
VectorCache(int dim) |
|
124 |
{ |
|
125 |
a = new float[dim]; |
|
126 |
b = new float[dim]; |
|
127 |
c = new float[dim]; |
|
128 |
d = new float[dim]; |
|
129 |
tangent = new float[dim]; |
|
130 |
cached = new float[dim]; |
|
131 |
} |
|
132 |
} |
|
133 |
|
|
134 |
protected Vector<VectorCache> vc; |
|
135 |
protected VectorCache tmp1, tmp2; |
|
105 | 136 |
|
106 | 137 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
107 | 138 |
// hide this from Javadoc |
108 | 139 |
|
109 |
Dynamic() |
|
140 |
protected Dynamic() |
|
141 |
{ |
|
142 |
} |
|
143 |
|
|
144 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
145 |
|
|
146 |
protected Dynamic(int duration, float count, int dimension) |
|
110 | 147 |
{ |
148 |
vc = new Vector<>(); |
|
149 |
vn = null; |
|
150 |
numPoints = 0; |
|
151 |
cacheDirty = false; |
|
152 |
mMode = MODE_LOOP; |
|
153 |
mDuration = duration; |
|
154 |
mCount = count; |
|
155 |
mDimension = dimension; |
|
156 |
|
|
157 |
baseV = new float[mDimension][mDimension]; |
|
158 |
buffer= new float[mDimension]; |
|
111 | 159 |
} |
112 | 160 |
|
113 | 161 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
... | ... | |
194 | 242 |
} |
195 | 243 |
} |
196 | 244 |
|
245 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
246 |
// debugging only |
|
247 |
|
|
248 |
private void printBase(String str) |
|
249 |
{ |
|
250 |
String s; |
|
251 |
float t; |
|
252 |
|
|
253 |
for(int i=0; i<mDimension; i++) |
|
254 |
{ |
|
255 |
s = ""; |
|
256 |
|
|
257 |
for(int j=0; j<mDimension; j++) |
|
258 |
{ |
|
259 |
t = ((int)(1000*baseV[i][j]))/(1000.0f); |
|
260 |
s+=(" "+t); |
|
261 |
} |
|
262 |
android.util.Log.e("dynamic", str+" base "+i+" : " + s); |
|
263 |
} |
|
264 |
} |
|
265 |
|
|
266 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
267 |
// debugging only |
|
268 |
|
|
269 |
private void checkBase() |
|
270 |
{ |
|
271 |
float tmp; |
|
272 |
|
|
273 |
for(int i=0; i<mDimension; i++) |
|
274 |
for(int j=i+1; j<mDimension; j++) |
|
275 |
{ |
|
276 |
tmp = 0.0f; |
|
277 |
|
|
278 |
for(int k=0; k<mDimension; k++) |
|
279 |
{ |
|
280 |
tmp += baseV[i][k]*baseV[j][k]; |
|
281 |
} |
|
282 |
|
|
283 |
android.util.Log.e("dynamic", "vectors "+i+" and "+j+" : "+tmp); |
|
284 |
} |
|
285 |
|
|
286 |
for(int i=0; i<mDimension; i++) |
|
287 |
{ |
|
288 |
tmp = 0.0f; |
|
289 |
|
|
290 |
for(int k=0; k<mDimension; k++) |
|
291 |
{ |
|
292 |
tmp += baseV[i][k]*baseV[i][k]; |
|
293 |
} |
|
294 |
|
|
295 |
android.util.Log.e("dynamic", "length of vector "+i+" : "+Math.sqrt(tmp)); |
|
296 |
} |
|
297 |
} |
|
298 |
|
|
299 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
300 |
// helper function in case we are interpolating through exactly 2 points |
|
301 |
|
|
302 |
protected void computeOrthonormalBase2(Static1D curr, Static1D next) |
|
303 |
{ |
|
304 |
switch(mDimension) |
|
305 |
{ |
|
306 |
case 1: baseV[0][0] = (next.x-curr.x); |
|
307 |
break; |
|
308 |
case 2: Static2D curr2 = (Static2D)curr; |
|
309 |
Static2D next2 = (Static2D)next; |
|
310 |
baseV[0][0] = (next2.x-curr2.x); |
|
311 |
baseV[0][1] = (next2.y-curr2.y); |
|
312 |
break; |
|
313 |
case 3: Static3D curr3 = (Static3D)curr; |
|
314 |
Static3D next3 = (Static3D)next; |
|
315 |
baseV[0][0] = (next3.x-curr3.x); |
|
316 |
baseV[0][1] = (next3.y-curr3.y); |
|
317 |
baseV[0][2] = (next3.z-curr3.z); |
|
318 |
break; |
|
319 |
case 4: Static4D curr4 = (Static4D)curr; |
|
320 |
Static4D next4 = (Static4D)next; |
|
321 |
baseV[0][0] = (next4.x-curr4.x); |
|
322 |
baseV[0][1] = (next4.y-curr4.y); |
|
323 |
baseV[0][2] = (next4.z-curr4.z); |
|
324 |
baseV[0][3] = (next4.w-curr4.w); |
|
325 |
break; |
|
326 |
case 5: Static5D curr5 = (Static5D)curr; |
|
327 |
Static5D next5 = (Static5D)next; |
|
328 |
baseV[0][0] = (next5.x-curr5.x); |
|
329 |
baseV[0][1] = (next5.y-curr5.y); |
|
330 |
baseV[0][2] = (next5.z-curr5.z); |
|
331 |
baseV[0][3] = (next5.w-curr5.w); |
|
332 |
baseV[0][4] = (next5.v-curr5.v); |
|
333 |
break; |
|
334 |
default: throw new RuntimeException("Unsupported dimension"); |
|
335 |
} |
|
336 |
|
|
337 |
if( baseV[0][0] == 0.0f ) |
|
338 |
{ |
|
339 |
baseV[1][0] = 1.0f; |
|
340 |
baseV[1][1] = 0.0f; |
|
341 |
} |
|
342 |
else |
|
343 |
{ |
|
344 |
baseV[1][0] = 0.0f; |
|
345 |
baseV[1][1] = 1.0f; |
|
346 |
} |
|
347 |
|
|
348 |
for(int i=2; i<mDimension; i++) |
|
349 |
{ |
|
350 |
baseV[1][i] = 0.0f; |
|
351 |
} |
|
352 |
|
|
353 |
computeOrthonormalBase(); |
|
354 |
} |
|
355 |
|
|
356 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
357 |
// helper function in case we are interpolating through more than 2 points |
|
358 |
|
|
359 |
protected void computeOrthonormalBaseMore(float time,VectorCache vc) |
|
360 |
{ |
|
361 |
for(int i=0; i<mDimension; i++) |
|
362 |
{ |
|
363 |
baseV[0][i] = (3*vc.a[i]*time+2*vc.b[i])*time+vc.c[i]; |
|
364 |
baseV[1][i] = 6*vc.a[i]*time+2*vc.b[i]; |
|
365 |
} |
|
366 |
|
|
367 |
computeOrthonormalBase(); |
|
368 |
} |
|
369 |
|
|
370 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
371 |
// When this function gets called, baseV[0] and baseV[1] should have been filled with two mDimension-al |
|
372 |
// vectors. This function then fills the rest of the baseV array with a mDimension-al Orthonormal base. |
|
373 |
// (mDimension-2 vectors, pairwise orthogonal to each other and to the original 2). The function always |
|
374 |
// leaves base[0] alone but generally speaking must adjust base[1] to make it orthogonal to base[0]! |
|
375 |
// The whole baseV is then used to compute Noise. |
|
376 |
// |
|
377 |
// When computing noise of a point travelling along a N-dimensional path, there are three cases: |
|
378 |
// a) we may be interpolating through 1 point, i.e. standing in place - nothing to do in this case |
|
379 |
// b) we may be interpolating through 2 points, i.e. travelling along a straight line between them - |
|
380 |
// then pass the velocity vector in baseV[0] and anything linearly independent in base[1]. |
|
381 |
// The output will then be discontinuous in dimensions>2 (sad corollary from the Hairy Ball Theorem) |
|
382 |
// but we don't care - we are travelling along a straight line, so velocity (aka baseV[0]!) does |
|
383 |
// not change. |
|
384 |
// c) we may be interpolating through more than 2 points. Then interpolation formulas ensure the path |
|
385 |
// will never be a straight line, even locally -> we can pass in baseV[0] and baseV[1] the velocity |
|
386 |
// and the acceleration (first and second derivatives of the path) which are then guaranteed to be |
|
387 |
// linearly independent. Then we can ensure this is continuous in dimensions <=4. This leaves |
|
388 |
// dimension 5 (ATM WAVE is 5-dimensional) discontinuous -> WAVE will suffer from chaotic noise. |
|
389 |
// |
|
390 |
// Bear in mind here the 'normal' in 'orthonormal' means 'length equal to the length of the original |
|
391 |
// velocity vector' (rather than the standard 1) |
|
392 |
|
|
393 |
protected void computeOrthonormalBase() |
|
394 |
{ |
|
395 |
int non_zeros=0; |
|
396 |
int last_non_zero=-1; |
|
397 |
float value; |
|
398 |
for(int i=0; i<mDimension; i++) |
|
399 |
{ |
|
400 |
value = baseV[0][i]; |
|
401 |
|
|
402 |
if( value != 0.0f ) |
|
403 |
{ |
|
404 |
non_zeros++; |
|
405 |
last_non_zero=i; |
|
406 |
} |
|
407 |
} |
|
408 |
// velocity is the 0 vector -> two consecutive points we are interpolating |
|
409 |
if( non_zeros==0 ) // through are identical -> no noise, set the base to 0 vectors. |
|
410 |
{ |
|
411 |
for(int i=0; i<mDimension-1; i++) |
|
412 |
for(int j=0; j<mDimension; j++) |
|
413 |
baseV[i+1][j]= 0.0f; |
|
414 |
} |
|
415 |
else |
|
416 |
{ |
|
417 |
for(int i=0; i<mDimension-1; i++) |
|
418 |
for(int j=0; j<mDimension; j++) |
|
419 |
{ |
|
420 |
if( (i<last_non_zero && j==i) || (i>=last_non_zero && j==i+1) ) |
|
421 |
baseV[i+1][j]= baseV[0][last_non_zero]; |
|
422 |
else |
|
423 |
baseV[i+1][j]= 0.0f; |
|
424 |
} |
|
425 |
|
|
426 |
// That's it if velocity vector is already one of the standard orthonormal |
|
427 |
// vectors. Otherwise (i.e. non_zeros>1) velocity is linearly independent |
|
428 |
// to what's in baseV right now and we can use (modified!) Gram-Schmidt. |
|
429 |
// |
|
430 |
// b[0] = b[0] |
|
431 |
// b[1] = b[1] - (<b[1],b[0]>/<b[0],b[0]>)*b[0] |
|
432 |
// b[2] = b[2] - (<b[2],b[0]>/<b[0],b[0]>)*b[0] - (<b[2],b[1]>/<b[1],b[1]>)*b[1] |
|
433 |
// b[3] = b[3] - (<b[3],b[0]>/<b[0],b[0]>)*b[0] - (<b[3],b[1]>/<b[1],b[1]>)*b[1] - (<b[3],b[2]>/<b[2],b[2]>)*b[2] |
|
434 |
// |
|
435 |
// then b[i] = b[i] / |b[i]| |
|
436 |
|
|
437 |
if( non_zeros>1 ) |
|
438 |
{ |
|
439 |
float tmp; |
|
440 |
|
|
441 |
for(int i=1; i<mDimension; i++) |
|
442 |
{ |
|
443 |
buffer[i-1]=0.0f; |
|
444 |
|
|
445 |
for(int k=0; k<mDimension; k++) |
|
446 |
{ |
|
447 |
value = baseV[i-1][k]; |
|
448 |
buffer[i-1] += value*value; |
|
449 |
} |
|
450 |
|
|
451 |
for(int j=0; j<i; j++) |
|
452 |
{ |
|
453 |
tmp = 0.0f; |
|
454 |
|
|
455 |
for(int k=0;k<mDimension; k++) |
|
456 |
{ |
|
457 |
tmp += baseV[i][k]*baseV[j][k]; |
|
458 |
} |
|
459 |
|
|
460 |
tmp /= buffer[j]; |
|
461 |
|
|
462 |
for(int k=0;k<mDimension; k++) |
|
463 |
{ |
|
464 |
baseV[i][k] -= tmp*baseV[j][k]; |
|
465 |
} |
|
466 |
} |
|
467 |
} |
|
468 |
|
|
469 |
buffer[mDimension-1]=0.0f; |
|
470 |
for(int k=0; k<mDimension; k++) |
|
471 |
{ |
|
472 |
value = baseV[mDimension-1][k]; |
|
473 |
buffer[mDimension-1] += value*value; |
|
474 |
} |
|
475 |
|
|
476 |
for(int i=1; i<mDimension; i++) |
|
477 |
{ |
|
478 |
tmp = (float)Math.sqrt(buffer[0]/buffer[i]); |
|
479 |
|
|
480 |
for(int k=0;k<mDimension; k++) |
|
481 |
{ |
|
482 |
baseV[i][k] *= tmp; |
|
483 |
} |
|
484 |
} |
|
485 |
} |
|
486 |
} |
|
487 |
|
|
488 |
//printBase("end"); |
|
489 |
//checkBase(); |
|
490 |
} |
|
491 |
|
|
197 | 492 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
198 | 493 |
// internal debugging only! |
199 | 494 |
|
Also available in: Unified diff
Completely redesign Noise in the Dynamics and move all the complexity to the parent class.
something does not work with it now :)