Camera rotation

Started by AleNovi, May 27, 2017, 12:41:49 AM

Previous topic - Next topic

AleNovi

Hi All!
I'm starting to develop an application that should display a 3D model, but i can't understand how correctly rotate camera around object.
I tried to use this guide http://www.jpct.net/wiki/index.php?title=MultiTouch_camera_controls but it not exactly what i need.
I want to rotate camera like in this app https://play.google.com/store/apps/details?id=com.tdcp.threedc or this https://play.google.com/store/apps/details?id=jquinn.qubism.android
Now i have this code to move camera, based on guide which i wrote above.
    private void moveCamera() {
        Movement movement = _movementhandler.getMovement();
        SimpleVector cam_pos = new SimpleVector();
        Object3D MyObject = one_layer.get(one_layer.size()/2);

        if (movement.hasMovement()) {
            Camera camera = world.getCamera();
            camera.getPosition(cam_pos);
           
            SimpleVector backVect = MyObject.getTransformedCenter();
            backVect.scalarMul(-1.0f);
            Matrix rotationmatrix = new Matrix();
            rotationmatrix.translate(backVect);
            rotationmatrix.rotateY(movement.cameraRotationY);
            rotationmatrix.translate(MyObject.getTransformedCenter());

            cam_pos.matMul(rotationmatrix);
            camera.setPosition(cam_pos);
            camera.lookAt(one_layer.get(one_layer.size()/2).getTransformedCenter());

            camera.moveCamera(Camera.CAMERA_MOVEUP, movement.worldRotationX*10);
            camera.moveCamera(Camera.CAMERA_MOVEIN, movement.cameraMovementZ);
        }
    }


The camera twitches during the rotation so I probably need to change the code.
Maybe someone knows good examples with the source code. I will be grateful for any help.

EgonOlsen

When is this method called and what is 'movement'?

AleNovi

This method called in onDrawFrame:
public void onDrawFrame(GL10 gl) {
               if (!stop) {
                    fb.clear(back);
                    mSkybox.render(world,fb);
                    world.renderScene(fb);
                    world.draw(fb);
                    moveCamera();
                    fb.display();
                } else {
                    if (fb != null) {
                        fb.dispose();
                        fb = null;
                    }
                }
        }


'movement' i took from this example http://www.jpct.net/wiki/index.php?title=MultiTouch_camera_controls

EgonOlsen

I see... Looks fine to me at first glance. What exactly goes wrong. I'm not sure what you mean by twitching? Some glitch in the rotation that happens every now and then?

EgonOlsen

And by the way: The HelloWorld example rotates an object on swipe as well, but I guess that's not exactly what you want?!

AleNovi

The crux of the problem: that example turns the camera around its axis in single touch. In multi touch it moves camera left/right/up/down and in/out.
I need the camera to rotate around the object in the single touch mode.
I recorded a video for a visual display of the problem https://youtu.be/cEzp2dDiYgc
During movement on the vertical axis, the camera is twitching

AeroShark333

#6
Ah... I used to have an issue similar to yours, this is how I fixed it.
I avoid using the Camera.lookAt method because I think that's where the vertical twitching you described happens.

Anyway, my fix:

Create 2 variables for touch input:
private float touchX;
private float touchY;

In your touch listener:
touchX += some calculation for a dragging single finger;
touchY += some calculation for a dragging single finger;

In OnDraw:
camera.rotateX(touchY);
touchY = 0.0f;
camera.rotateY(touchX);
touchX = 0.0f;
camera.setPosition(someObjectYouWantToRotateAround.getTransformedCenter());
camera.moveCamera(Camera.MOVEOUT, someRadiusYouWantToRotateAroundTheObject);

Maybe not the neatest way but it worked for me :)

AleNovi

Thanks for reply. I tried this method and camera not twitching but now i need to lock camera's z axis.
    private void moveCamera() {
        Movement movement = _movementhandler.getMovement();
        SimpleVector cam_pos = new SimpleVector();
        Object3D MyObject = one_layer.get(one_layer.size()/2);

        if (movement.hasMovement()) {
            Camera camera = world.getCamera();
            camera.getPosition(cam_pos);
            camera_z-=movement.cameraMovementZ;//variable to add distance to object
            camera.rotateX(-movement.worldRotationX);
            movement.worldRotationX = 0.0f;
            camera.rotateY(-movement.cameraRotationY);
            movement.cameraRotationY = 0.0f;

            camera.setPosition(MyObject.getTransformedCenter());
            camera.moveCamera(Camera.CAMERA_MOVEOUT, camera_z);
            camera.moveCamera(Camera.CAMERA_MOVEIN, movement.cameraMovementZ);
        }
    }

In other words, the camera should always look at the object having 0 degrees of rotation along the Z axis.
how to do it in best way w/o camera.lookAt?

AeroShark333

#8
Hmmm, perhaps it would work to keep a variable of the total rotation in X and Y.
And in onDraw clear the camera rotation everytime and apply the total (cumulative) X and Y rotations... (I think that should avoid getting a rotation in Z). (Clearing the rotation here means resetting te camera to the default rotation)

I don't really know how to do this otherwise, sorry.

AleNovi

I made some tests and this code works fine except one thing - when camera's x rotate reaches +/- 90 degrees it twitches. I really don't know how to fix it. I tried to made limits (rotate camera's x only when summary angle in -1.56f<x<1.56f range) but there was one more bug - when i rotate camera's Y axis, X axis rotates too and my limit variable = 1.56f when real angle= 1.0f or less. Is there any way to get the current value of the camera's rotation angle except to create a variable that will sum the total rotation?
    private void moveCamera() {
        Movement movement = _movementhandler.getMovement();
        Object3D MyObject = one_layer.get(0);

        if (movement.hasMovement()) {

            Camera camera = world.getCamera();

            if(camera_z-movement.cameraMovementZ>10 && camera_z-movement.cameraMovementZ<200)
            camera_z-=movement.cameraMovementZ;

            camera.rotateX(-movement.worldRotationX);
            camera.rotateY(-movement.cameraRotationY);
     
            camera.setPosition(MyObject.getTransformedCenter());
            camera.moveCamera(Camera.CAMERA_MOVEOUT, camera_z);
            camera.lookAt(MyObject.getTransformedCenter());
        }

EgonOlsen

There's calcAngle() in SimpleVector. You could use it to calculate the angle between, for example (1,0,0) and the vector returned by Camera.getXAxis(), but I'm not sure if this the best idea. Another way is described here: http://www.jpct.net/forum2/index.php/topic,2254.0/

Anyway, I'm still confused about what you actually need. Or in other words: I don't see the difference between the video example that you've posted and what the HelloWorld example does!? I'm not sure what exactly you mean by this single touch/multi touch thing...!?

AleNovi

Thank You very much! That was exactly what i needed!
I created limit in 1.56f and camera now don't twitches at 90 degrees.
SimpleVector limit_vector = new SimpleVector(0,1,0);
float angle = limit_vector.calcAngle(camera.getYAxis());
if(angle+Math.abs(movement.worldRotationX)<1.56f){
    camera.rotateX(-movement.worldRotationX);
    camera.rotateY(-movement.cameraRotationY);
} else {
    camera.rotateY(-movement.cameraRotationY/10);
}