Rajawali / Rajawali

Android OpenGL ES 2.0/3.0 Engine
https://rajawali.github.io/Rajawali/
Other
2.35k stars 703 forks source link

Rajawali 3D object rotation #346

Closed leandersabel closed 11 years ago

leandersabel commented 11 years ago

First of all a great thank you for your awesome work with Rajawali. :)

I am a computer science student and had to create a dice application for android as my last assignment. I followed some of your tutorials and imported a Blender .obj file into Rajawali and can spin it with touch or accelerometer input.

I have encountered one small problem

private BaseObject3D dice;
...
dice.rotateAround(new Number3D(1, 0, 0), (float) <some angle>), true);

This all works very well and I can spin the dice the way I want to. But whenever I call:

dice.getRotation()

or any specific rotation like x, y, z its always zero. I have seen some value change in the quaternions but I am not quite sure what to make of that. :)

So I guess my question is: Is there an easy way to get my current rotation so I can make a smooth rotation to the next surface when the dice rotation slows past a threshold?

The code is available here Rotation happens at line 128.

Any help is greatly appreciated! Leander

ccoffey commented 11 years ago

Hi Leander,

the 32nd RajawaliExample "UI Fragments" uses RotateAnimation3D and onAnimationUpdate to keep track of a rotation angle during animation.

This allows you to cancel any executing rotation animation and have another one continue (smoothly) from where it stopped. To test this, simply choose different options from the list-view faster than the animation can get to its target.

You might have to build the examples from source. https://github.com/MasDennis/RajawaliExamples As I don't think the app on GooglePlay has been updated yet.

I hope this helps, Cathal

alenko commented 11 years ago

I have one question, about animating objects.

Can i simply animate(rotate or setposition) onDrawFrame, or not, why is bad?

Davhed commented 11 years ago

I keep looking for an answer to that question Alen. I have many many animation happening onDrawFrame and so far haven't had any trouble. The worst I've seen is some delays when I'm pushing too much data to the GPU each frame...but Andrew's ETC1 compression plus my alpha map shader completely fixed this.

Davhed commented 11 years ago

Leander, I am a little confused by your renderer, but I could be overlooking something you are doing in another class. Also, I am most definitely not a computer scientist, but I've been using Rajawali for about 6 months now.

I think they key issue is that rotateAround produces an "orbit" animation . So your object will encircle the target. This will not update the object's rotation property AFAIK, instead it changes its position. If you want to use the X,Y,Z rotation of the BaseObject3D you should use BaseObject3D.setRotation() or setRotX(), setRotY(), setRotZ(). Then getRotation() should return something other than 0.

To solve the issue using your current class structure that a look at Cathal's suggestion and fragment code.

leandersabel commented 11 years ago

Thank you for your replies. I used dice.setRotX() and dice.setRotY before but I had a little problem. I have tried to illustrate this in the graphic below. The dice should move "naturally" based on the user input so a drag to the right should cause the dice to spin in that direction. (picture on the left) When the dice is upside down (picture on the right) however, a drag to the right causes it to spin in the "wrong" direction. (Its still spinning in the same direction, just upside down and thus looks wrong)

I did not have this issue with rotateAround so I ended up using that. If you have a good idea how to fix this with setRot() I'd be happy to try that out.

I am really quite bad at openGL and 3D graphics but I am trying to do more in this area as it is really quite nice.

illustration

Here is also a screenshot of the dice application :) Dice_app

Davhed commented 11 years ago

I understand the issue you're having. The transformation is oriented to the object's current position/rotation, rather than being oriented to the world. So when dice is upside-down it will appear to spin opposite of the user swipe.

Maybe you can make the animation conditional on the orientation of dice:

if(dice.getRotX == 180)
    dice.setRotY(-yRotOffset);
else
    dice.setRotY(yRotOffset);

Or rather than changing the entire rotation equation just have the direction change on some desired condition.

Another option would be to nest your dice into a null object container:

BaseObject3D container = new BaseObject3D()
container.addChild(dice);
addChild(container);

This will allow you to tumble dice along the X or Z axis when a user swipes up or down, and then spin the container along the Y axis when the user swipes left/right. That way container is always oriented with up = y, so you'll never have it spinning backwards. I admit this isn't completely thought through so you could find some other difficulties in transforming dice in this scenario.

To access the child dice.setRotation() you will need to either create a pointer that is accessible to the class, or you'll have get the child via container.getChildAt(index), or various other ways.

In my first Live Wallpaper I used this technique for the propeller of my airplane. :https://play.google.com/store/apps/details?id=com.evvid.wallpapers.aviation3dfree.lightplane

The fuselage, propeller, window, and pilot are all separate objects that have been grouped into a parentObj. The propeller spins along its own Z axis and then I transform the parentObj to move the whole plane. This preserves the propeller's orientation correctly. I think this is similar to you scenario.

alenko commented 11 years ago

i wanted to know, what is the difference, from animate3d and rotating on drawframe

Davhed commented 11 years ago

https://github.com/MasDennis/Rajawali/blob/master/src/rajawali/animation/Animation3D.java

Animation3D is threaded, onDrawFrame animation would be part of the main GL thread. So you could eventually slow down the GL thread by having too many calculations happening in onDrawFrame. At least that's how I understand it.

ToxicBakery commented 11 years ago

Animation3D moves based on real time. onDrawFrame moves as fast as the GPU/CPU can handle it or limited by your set FPS.

Animation3D provides a simple way of making objects move at a desired speed using real world time. Imagine running an animation on two devices at the same time. Using Animation3D, the animations should end at exactly the same time (theoretically) while animations done with onDrawFrame will vary in end times based on an infinite unknown number of variables such as background apps, hardware, phone state changes, its cold outside, etc.

alenko commented 11 years ago

Thx for this Toxic, I was looking the code(didnt before), and yes i see how does it work, its time based not fps, while ondrawframe is fps, means how much fps device can handle and thats bad.

ToxicBakery commented 11 years ago

No problem, has that resolved all your questions?

alenko commented 11 years ago

yes indeed it did on mine ;)