Revision d0418bda
Added by Leszek Koltunski over 5 years ago
src/main/java/org/distorted/examples/rubik/RubikRenderer.java | ||
---|---|---|
46 | 46 |
|
47 | 47 |
class RubikRenderer implements GLSurfaceView.Renderer |
48 | 48 |
{ |
49 |
static final int NUM_CUBES = 3;
|
|
49 |
static final int NUM_CUBES = 4;
|
|
50 | 50 |
private static final int SIZE = 200; |
51 | 51 |
private static final float CUBE_SCREEN_RATIO = 0.5f; |
52 | 52 |
|
... | ... | |
63 | 63 |
private Static4D[][][] mQuatScramble; |
64 | 64 |
private Static3D[][][] mRotationAxis; |
65 | 65 |
private Dynamic1D[][][] mRotationAngle; |
66 |
private Static3D[][][] mCurrentPosition; |
|
66 | 67 |
private Static1D mRotationAngleStatic; |
67 |
private int mRotAxis; |
|
68 |
private int mRotRow; |
|
68 |
private int mRotAxis, mRotRow; |
|
69 | 69 |
|
70 | 70 |
private int mScreenWidth, mScreenHeight; |
71 | 71 |
|
... | ... | |
91 | 91 |
mEffects = new DistortedEffects[NUM_CUBES][NUM_CUBES][NUM_CUBES]; |
92 | 92 |
Static3D[][][] cubeVectors = new Static3D[NUM_CUBES][NUM_CUBES][NUM_CUBES]; |
93 | 93 |
|
94 |
mQuatScramble = new Static4D[NUM_CUBES][NUM_CUBES][NUM_CUBES]; |
|
95 |
mRotationAxis = new Static3D[NUM_CUBES][NUM_CUBES][NUM_CUBES]; |
|
96 |
mRotationAngle= new Dynamic1D[NUM_CUBES][NUM_CUBES][NUM_CUBES]; |
|
94 |
mQuatScramble = new Static4D[NUM_CUBES][NUM_CUBES][NUM_CUBES]; |
|
95 |
mRotationAxis = new Static3D[NUM_CUBES][NUM_CUBES][NUM_CUBES]; |
|
96 |
mRotationAngle = new Dynamic1D[NUM_CUBES][NUM_CUBES][NUM_CUBES]; |
|
97 |
mCurrentPosition= new Static3D[NUM_CUBES][NUM_CUBES][NUM_CUBES]; |
|
97 | 98 |
|
98 |
float sinkDegree = 3.0f - 1.7f/NUM_CUBES; // f(1)=1.3, f(inf)=3
|
|
99 |
float sinkDegree = 3.0f - 1.8f/NUM_CUBES; // f(1)=1.2, f(inf)=3
|
|
99 | 100 |
|
100 | 101 |
VertexEffectSink sink = new VertexEffectSink( new Static1D(sinkDegree), |
101 | 102 |
new Static3D(SIZE*0.5f, SIZE*0.5f, SIZE*0.5f), |
... | ... | |
149 | 150 |
tmpTop = (y== NUM_CUBES -1 ? mapTop :mapBlack); |
150 | 151 |
tmpBottom= (y== 0 ? mapBottom:mapBlack); |
151 | 152 |
|
152 |
mCubes[x][y][z] = new MeshCubes(vertices,vertices,vertices, tmpFront, tmpBack, tmpLeft, tmpRight, tmpTop, tmpBottom); |
|
153 |
cubeVectors[x][y][z] = new Static3D( SIZE*(x-nc), SIZE*(y-nc), SIZE*(z-nc) ); |
|
154 |
mQuatScramble[x][y][z] = new Static4D(0,0,0,1); |
|
155 |
mRotationAngle[x][y][z] = new Dynamic1D(); |
|
156 |
mRotationAxis[x][y][z] = new Static3D(1,0,0); |
|
153 |
mCubes[x][y][z] = new MeshCubes(vertices,vertices,vertices, tmpFront, tmpBack, tmpLeft, tmpRight, tmpTop, tmpBottom); |
|
154 |
cubeVectors[x][y][z] = new Static3D( SIZE*(x-nc), SIZE*(y-nc), SIZE*(z-nc) ); |
|
155 |
mQuatScramble[x][y][z] = new Static4D(0,0,0,1); |
|
156 |
mRotationAngle[x][y][z] = new Dynamic1D(); |
|
157 |
mRotationAxis[x][y][z] = new Static3D(1,0,0); |
|
158 |
mCurrentPosition[x][y][z] = new Static3D(x,y,z); |
|
157 | 159 |
|
158 | 160 |
mEffects[x][y][z] = new DistortedEffects(); |
159 | 161 |
mEffects[x][y][z].apply(sink); |
... | ... | |
324 | 326 |
|
325 | 327 |
void continueRotation(float angle) |
326 | 328 |
{ |
327 |
mRotationAngleStatic.set1(120.0f*angle/mScreenMin);
|
|
329 |
mRotationAngleStatic.set1(200.0f*angle/mScreenMin);
|
|
328 | 330 |
} |
329 | 331 |
|
330 | 332 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
... | ... | |
360 | 362 |
{ |
361 | 363 |
mRotationAngle[x][y][z].removeAll(); |
362 | 364 |
mQuatScramble[x][y][z].set(RubikSurfaceView.quatMultiply(quat,mQuatScramble[x][y][z])); |
365 |
modifyCurrentPosition(x,y,z,quat); |
|
363 | 366 |
} |
364 | 367 |
} |
365 | 368 |
} |
... | ... | |
370 | 373 |
{ |
371 | 374 |
switch(vector) |
372 | 375 |
{ |
373 |
case RubikSurfaceView.VECTX: return x==row;
|
|
374 |
case RubikSurfaceView.VECTY: return y==row;
|
|
375 |
case RubikSurfaceView.VECTZ: return z==row;
|
|
376 |
case RubikSurfaceView.VECTX: return mCurrentPosition[x][y][z].get1()==row;
|
|
377 |
case RubikSurfaceView.VECTY: return mCurrentPosition[x][y][z].get2()==row;
|
|
378 |
case RubikSurfaceView.VECTZ: return mCurrentPosition[x][y][z].get3()==row;
|
|
376 | 379 |
} |
377 | 380 |
|
378 | 381 |
return false; |
379 | 382 |
} |
380 | 383 |
|
384 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
385 |
|
|
386 |
private void modifyCurrentPosition(int x, int y, int z, Static4D quat) |
|
387 |
{ |
|
388 |
Static3D current = mCurrentPosition[x][y][z]; |
|
389 |
float beforeX = current.get1(); |
|
390 |
float beforeY = current.get2(); |
|
391 |
float beforeZ = current.get3(); |
|
392 |
|
|
393 |
float diff = 0.5f*(NUM_CUBES-1); |
|
394 |
|
|
395 |
float cubitCenterX = beforeX - diff; |
|
396 |
float cubitCenterY = beforeY - diff; |
|
397 |
float cubitCenterZ = beforeZ - diff; |
|
398 |
|
|
399 |
Static4D cubitCenter = new Static4D(cubitCenterX, cubitCenterY, cubitCenterZ, 0); |
|
400 |
Static4D rotatedCenter = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat); |
|
401 |
|
|
402 |
float rotatedX = rotatedCenter.get1() + diff; |
|
403 |
float rotatedY = rotatedCenter.get2() + diff; |
|
404 |
float rotatedZ = rotatedCenter.get3() + diff; |
|
405 |
|
|
406 |
int roundedX = (int)(rotatedX+0.1f); |
|
407 |
int roundedY = (int)(rotatedY+0.1f); |
|
408 |
int roundedZ = (int)(rotatedZ+0.1f); |
|
409 |
|
|
410 |
//android.util.Log.e("rubik", "before: ("+((int)beforeX)+","+((int)beforeY)+","+((int)beforeZ)+") after: ("+roundedX+","+roundedY+","+roundedZ+")"); |
|
411 |
|
|
412 |
mCurrentPosition[x][y][z].set1(roundedX); |
|
413 |
mCurrentPosition[x][y][z].set2(roundedY); |
|
414 |
mCurrentPosition[x][y][z].set3(roundedZ); |
|
415 |
} |
|
416 |
|
|
381 | 417 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
382 | 418 |
|
383 | 419 |
float getScreenWidth() |
src/main/java/org/distorted/examples/rubik/RubikSurfaceView.java | ||
---|---|---|
100 | 100 |
{ |
101 | 101 |
case MotionEvent.ACTION_DOWN: mX = x; |
102 | 102 |
mY = y; |
103 |
|
|
104 | 103 |
mLastTouchedFace = faceTouched(x,y); |
105 | 104 |
|
106 |
if( mLastTouchedFace != NONE ) |
|
107 |
{ |
|
108 |
mRotating = true; |
|
109 |
} |
|
110 |
else |
|
111 |
{ |
|
112 |
mDragging = true; |
|
113 |
} |
|
105 |
if( mLastTouchedFace != NONE ) mRotating = true; |
|
106 |
else mDragging = true; |
|
107 |
|
|
114 | 108 |
break; |
115 | 109 |
case MotionEvent.ACTION_MOVE: if( mDragging ) |
116 | 110 |
{ |
... | ... | |
297 | 291 |
return new Static4D(tx,ty,tz,tw); |
298 | 292 |
} |
299 | 293 |
|
294 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
295 |
// rotate 'vector' by quat^(-1) ( i.e. return (quat^-1)*vector*quat ) |
|
296 |
|
|
297 |
static Static4D rotateVectorByInvertedQuat(Static4D vector, Static4D quat) |
|
298 |
{ |
|
299 |
float qx = quat.get1(); |
|
300 |
float qy = quat.get2(); |
|
301 |
float qz = quat.get3(); |
|
302 |
float qw = quat.get4(); |
|
303 |
|
|
304 |
Static4D quatInverted= new Static4D(-qx,-qy,-qz,qw); |
|
305 |
Static4D tmp = quatMultiply(quatInverted,vector); |
|
306 |
|
|
307 |
return quatMultiply(tmp,quat); |
|
308 |
} |
|
309 |
|
|
310 |
|
|
311 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
312 |
// rotate 'vector' by quat ( i.e. return quat*vector*(quat^-1) ) |
|
313 |
|
|
314 |
static Static4D rotateVectorByQuat(Static4D vector, Static4D quat) |
|
315 |
{ |
|
316 |
float qx = quat.get1(); |
|
317 |
float qy = quat.get2(); |
|
318 |
float qz = quat.get3(); |
|
319 |
float qw = quat.get4(); |
|
320 |
|
|
321 |
Static4D quatInverted= new Static4D(-qx,-qy,-qz,qw); |
|
322 |
Static4D tmp = quatMultiply(quat,vector); |
|
323 |
|
|
324 |
return quatMultiply(tmp,quatInverted); |
|
325 |
} |
|
326 |
|
|
300 | 327 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
301 | 328 |
|
302 | 329 |
private Static4D quatFromDrag(float dragX, float dragY) |
303 | 330 |
{ |
304 | 331 |
float axisX = dragY; // inverted X and Y - rotation axis is |
305 |
float axisY = dragX; // perpendicular to (dragX,dragY) |
|
332 |
float axisY = dragX; // perpendicular to (dragX,dragY) Why not (-dragY, dragX) ? because Y axis is also inverted!
|
|
306 | 333 |
float axisZ = 0; |
307 | 334 |
float axisL = (float)Math.sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ); |
308 | 335 |
|
... | ... | |
321 | 348 |
return new Static4D(0f, 0f, 0f, 1f); |
322 | 349 |
} |
323 | 350 |
|
324 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
325 |
|
|
326 |
private int returnFrontFace() |
|
327 |
{ |
|
328 |
Static4D rotated = rotateVector(new Static4D(0,0,1,0)); |
|
329 |
|
|
330 |
float rotatedX = rotated.get1(); |
|
331 |
float rotatedY = rotated.get2(); |
|
332 |
float rotatedZ = rotated.get3(); |
|
333 |
|
|
334 |
float absX = rotatedX>0 ? rotatedX : -rotatedX; |
|
335 |
float absY = rotatedY>0 ? rotatedY : -rotatedY; |
|
336 |
float absZ = rotatedZ>0 ? rotatedZ : -rotatedZ; |
|
337 |
|
|
338 |
if( absX>absY && absX>absZ ) return rotatedX>0 ? RIGHT:LEFT; |
|
339 |
if( absY>absX && absY>absZ ) return rotatedY>0 ? TOP:BOTTOM; |
|
340 |
if( absZ>absX && absZ>absY ) return rotatedZ>0 ? FRONT:BACK; |
|
341 |
|
|
342 |
return NONE; |
|
343 |
} |
|
344 |
|
|
345 | 351 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
346 | 352 |
|
347 | 353 |
private boolean faceIsVisible(int face) |
... | ... | |
349 | 355 |
float cameraDistance = mRenderer.returnCameraDistance(); |
350 | 356 |
float cubeHalfSize = mRenderer.returnCubeSize()*0.5f; |
351 | 357 |
|
352 |
Static4D rotated = rotateVector(new Static4D(0,0,cameraDistance,0));
|
|
358 |
Static4D rotated = rotateVectorByInvertedQuat(new Static4D(0,0,cameraDistance,0), mQuatAccumulated);
|
|
353 | 359 |
|
354 | 360 |
switch(face) |
355 | 361 |
{ |
... | ... | |
364 | 370 |
return false; |
365 | 371 |
} |
366 | 372 |
|
367 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
368 |
// rotate 'vector' by quaternion q=mQuatAccumulated^(-1) ( i.e. return (q^-1)*vector*q ) |
|
369 |
|
|
370 |
private Static4D rotateVector(Static4D vector) |
|
371 |
{ |
|
372 |
float qx = mQuatAccumulated.get1(); |
|
373 |
float qy = mQuatAccumulated.get2(); |
|
374 |
float qz = mQuatAccumulated.get3(); |
|
375 |
float qw = mQuatAccumulated.get4(); |
|
376 |
|
|
377 |
Static4D quatInverted= new Static4D(-qx,-qy,-qz,qw); |
|
378 |
Static4D tmp = quatMultiply(quatInverted,vector); |
|
379 |
|
|
380 |
return quatMultiply(tmp,mQuatAccumulated); |
|
381 |
} |
|
382 |
|
|
383 | 373 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
384 | 374 |
|
385 | 375 |
private int faceTouched(int xTouch, int yTouch) |
... | ... | |
417 | 407 |
float halfScrWidth = mRenderer.getScreenWidth() *0.5f; |
418 | 408 |
float halfScrHeight = mRenderer.getScreenHeight()*0.5f; |
419 | 409 |
Static4D touchPoint = new Static4D(x-halfScrWidth, halfScrHeight-y, 0, 0); |
420 |
Static4D rotatedTouchPoint= rotateVector(touchPoint);
|
|
410 |
Static4D rotatedTouchPoint= rotateVectorByInvertedQuat(touchPoint, mQuatAccumulated);
|
|
421 | 411 |
|
422 | 412 |
mPoiX = rotatedTouchPoint.get1(); |
423 | 413 |
mPoiY = rotatedTouchPoint.get2(); |
... | ... | |
431 | 421 |
float cameraDistance = mRenderer.returnCameraDistance(); |
432 | 422 |
|
433 | 423 |
Static4D cameraPoint = new Static4D(0, 0, cameraDistance, 0); |
434 |
Static4D rotatedCamera= rotateVector(cameraPoint);
|
|
424 |
Static4D rotatedCamera= rotateVectorByInvertedQuat(cameraPoint, mQuatAccumulated);
|
|
435 | 425 |
|
436 | 426 |
mCamX = rotatedCamera.get1(); |
437 | 427 |
mCamY = rotatedCamera.get2(); |
Also available in: Unified diff
Improve the Rubik App - rotation works now.