Rotation and Scale, touch listener use

Disclaimer: I’ll say I have read the math for dummies, so I think I understand the rotations using lookat and stuff. But bear with me, because I’m still having issues.

First, my rotation. It almost works, except for some exception cases.

  1. If I drag diagonally across my screen, my wireframe sphere will rotate in 1 axis correctly, and the other access incorrectly. Ex: drag diagonally up and right, sphere will rotate right, but also rotate down instead of up.
  2. Somewhere during the rotation, sometimes an axis “flips”, such that something like dragging up causes the sphere to rotate downward.

I feel like these two issues are connected–I can’t see how though. Mind you, this is now trying to be done in a touchListener. In the code below, I got the analogListener working with swipe detection, but needed the touchListener for scale events too, so I dropped the analogListener’s use. I have it here for understanding purposes.

[java]
private TouchListener touchListener = new TouchListener() {

public void onTouch(String name, TouchEvent event, float tpf) {
	logger.log(Level.INFO,"{0} event",event.getType());
	Quaternion roll = null;
	switch(event.getType()){
		case DOWN:
			logger.log(Level.INFO,"down at {0} {1} ",new Object[]{event.getX(),event.getY()});
			break;
		case MOVE:
			logger.log(Level.INFO,"down moving at {0} {1} ",new Object[]{event.getDeltaX(),event.getDeltaY()});
			float x = event.getDeltaX();
			float y = event.getDeltaY();
			if(Math.abs(x) < 2){
				x = 0;
			}
			if(Math.abs(y) < 2){
				y = 0;
			}
			float[] angles = new float[]{FastMath.QUARTER_PI * y  * .01f,FastMath.QUARTER_PI * x * .01f,0};
			//float[] angles = new float[]{0,FastMath.QUARTER_PI * event.getDeltaX()* .01f,0};
			roll = new Quaternion().fromAngles(angles);
			roll.multLocal(lookAt);
			roll.multLocal(up);
			break;
		case SCALE_START:
			inputManager.removeListener(analogListener);
			logger.log(Level.INFO,"{0} scale start",event.getScaleFactor());
			scale_factor = event.getScaleFactor();
			break;
		case SCALE_MOVE:
			logger.log(Level.INFO,"{0} scale moving {1} {2}",new Object[]{event.getScaleFactor(),event.getScaleSpan(),event.isScaleSpanInProgress()});
			scale_factor = event.getScaleFactor();
			if(event.getScaleSpan() != previous_scalespan){
				scale_factor = event.getScaleFactor();
				previous_scalespan = event.getScaleSpan();
			} else {
				event.setConsumed();
			}
			break;
		case SCALE_END:
    			inputManager.addListener(analogListener,"down swipe", "left swipe", "up swipe","right swipe");
			logger.log(Level.INFO,"scale end");
			scale_factor =1; 
			break;
		default:
			scale_factor = 1;
			break;
		
		    
	}
	/*if(scale_factor > 1){
		scale_factor = 1.05f;
	} else if(scale_factor < 1) {
		scale_factor = .95f;
	}*/
}
    
};

private AnalogListener analogListener = new AnalogListener() {

    public void onAnalog(String name, float value, float tpf) {
	if(scale_factor == 1){
		logger.log(Level.INFO,"{0} + {1}",new Object[]{name,value});  
		Quaternion roll = new Quaternion();
		if(name.equals("up swipe")){
		    roll = new Quaternion().fromAngleAxis(-FastMath.QUARTER_PI * value * 10, Vector3f.UNIT_X);
		    roll.multLocal(lookAt);
		    roll.multLocal(up);
		}
		if(name.equals("right swipe")){
		    roll = new Quaternion().fromAngleAxis(FastMath.QUARTER_PI * value * 10, Vector3f.UNIT_Y);
		    roll.multLocal(lookAt);
		    roll.multLocal(up);
		}
		if(name.equals("down swipe")){
		    roll = new Quaternion().fromAngleAxis(FastMath.QUARTER_PI * value * 10, Vector3f.UNIT_X);
		    roll.multLocal(lookAt);
		    roll.multLocal(up);
		}
		if(name.equals("left swipe")){
		    roll = new Quaternion().fromAngleAxis(-FastMath.QUARTER_PI * value * 10, Vector3f.UNIT_Y);
		    roll.multLocal(lookAt);
		    roll.multLocal(up);
		}
	}
   // sphere.setLocalRotation(new Quaternion().fromAngles(0, 0, 0));
    }
    
};


@Override
public void simpleUpdate(float tpf) {
sphere.lookAt(lookAt, up);
sphere.scale(scale_factor);
if(sphere.getLocalScale().x > 2.5f){
	sphere.setLocalScale(new Vector3f(2.5f,2.5f,2.5f));
} else if(sphere.getLocalScale().x < .5f){
	sphere.setLocalScale(new Vector3f(.5f,.5f,.5f));
}
logger.log(Level.INFO,"sphere is now: {0}",sphere.getLocalScale());
    //TODO: add update code
}

[/java]

Also, when I scale the object any which way, all of a sudden, rotation along the x axis (up and down rotation) becomes locked. Why?

Alright, I solved my issue, I think. I just had to understand that quaternions rotate in y,z, then x. So if I just created a y quat, then multiplied by the x local, it seems to rotated just fine. And scaling doesn’t stop the rotation now.

Now, then next issue, if anyone still cares :). When I start the scale motion, there is a bit of rotation that occurs first. Is there any way to get rid of that? I’m going to see if I can detect two down events before an up event to stop rotation and let scaling occur, but I’m open to ideas.

HI @indiebynight, i have same problem. Copy your code and don’t know that is, lookAt and up… Please you help.

Yea, sure. Here’s my touch listener:

[java]private TouchListener touchListener = new TouchListener() {

public void onTouch(String name, TouchEvent event, float tpf) {
	logger.log(Level.INFO,"{0} event",event.getType());
	switch(event.getType()){
		case SCALE_START:
			//inputManager.removeListener(analogListener);
			logger.log(Level.INFO,"{0} scale start",event.getScaleFactor());
			scale_factor = event.getScaleFactor();
			scaling = true;
			break;
		case DOWN:
			
			down_count++;
			logger.log(Level.INFO,"down count {0}",down_count);
			break;
		case MOVE:
			logger.log(Level.INFO,"down count in move {0}",down_count);
			if(down_count != 2 && !sliding){
				logger.log(Level.INFO,"down moving at {0} {1} ",new Object[]{event.getDeltaX(),event.getDeltaY()});
				float x = event.getDeltaX();
				float y = event.getDeltaY();
				if(Math.abs(x) < 2){
					x = 0;
				}
				if(Math.abs(y) < 2){
					y = 0;
				}
				Quaternion roll = new Quaternion().fromAngleAxis(FastMath.QUARTER_PI * -y  * .01f, Vector3f.UNIT_X);
				Quaternion x_roll = new Quaternion().fromAngleAxis(FastMath.QUARTER_PI * x  * .01f, Vector3f.UNIT_Y);
				roll.multLocal(x_roll);
				roll.multLocal(lookAt);
				roll.multLocal(up);
			}
			break;
		case UP:

			if(sliding){
				planet.localToWorld(Vector3f.UNIT_Y, up);
				planet.localToWorld(Vector3f.UNIT_Z, lookAt);
			}
			sliding = false;
			down_count--;
			break;
		case SCALE_MOVE:
			logger.log(Level.INFO,"{0} scale moving {1} {2}",new Object[]{event.getScaleFactor(),event.getScaleSpan(),event.isScaleSpanInProgress()});
			scale_factor = event.getScaleFactor();
			if(scale_factor > 1){
				scale_factor = 1.01f;
			} else if (scale_factor < 1){
				scale_factor = .99f;	
			}
			/*if(event.getScaleSpan() != previous_scalespan){
				scale_factor = event.getScaleFactor();
				previous_scalespan = event.getScaleSpan();
			} else {
				event.setConsumed();
			}*/
			break;
		case SCALE_END:
			scaling = false;
    			//inputManager.addListener(analogListener,"down swipe", "left swipe", "up swipe","right swipe");
			logger.log(Level.INFO,"scale end");
			scale_factor =1; 
			break;
		default:
			scale_factor = 1;
			break;
		
		    
	}
}
    
};[/java]

Then, in the update, I just do planet.lookAt(lookAt,up);

Hope that helps!

thank you!
I am new in jmonkey. :S
Copy the code and does not work me. questions:

  • How var to begin: sliding, scaling, lookAt, up, scale_factor and down_count?
  • you say " just do planet.lookAt(lookAt,up);" when var modified: ‘lookAt’ and ‘up’?

I hope you understand me and help me.

…sorry my english. :facepalm:

Oh, no problem. So first of all, some of the code may be more than you need. The scaling and sliding variables are there because I also try to resize the object and when I try and use a nifty gui slider. But to start:

[java]Vector3f lookAt = new Vector3f(0,0,1);
Vector3f up = new Vector3f(0,1,0);[/java]

‘lookAt’ and ‘up’ are the two vectors that help define the orientation of a spatial. Every spatial has the lookAt method. By changing my two vectors, lookAt and up, I can rotate a spatial using its lookAt method to point in whatever direction I want it to. When a spatial is instantiated, the lookAt and up vectors are often just the Z-axis and the Y-axis, respectively.

So, here is my code, with the instantiated variables and update method:

CLICK ME FOR CODE

In my touchlistener, the roll.multLocal(lookAt), and roll.multLocal(up) are what actually change the lookAt and up vectors. The “multLocal” method actually stores the new vector inside the passed parameter. Then, you can see in my update method, that I do “planet.lookAt(lookAt,up)”. This continuously updates the spatials rotation.

Right now, I’ve moved my code inside a screencontroller in a separate class, but you won’t need that stuff. Tell me if you still need help. Just point to any piece of code and I’ll explain it more if needed.

Thank you very much @indiebynight.
Now, I completed the code and it works perfectly!!

Finally if you can help me. I would add complexity:

  • Rotation with 2 fingers: first finger as a central axis and second finger to move the 3D model in function to the central axis(first finger)
  • Add panning to 3D model with two fingers.

In any case, I appreciate your help

Regards

First off, good to hear. Glad I could help.

Unfortunately, you’ll have to be more explicit with the next part. What do you mean by, “first finger as a central axis”. And is panning not already done? Sorry, I don’t quite understand what you are trying to achieve.

Edit

Dear, there is an app: “AutoCAD 360”. It has a demo with a propeller. This example shows what I’m saying.

However, if I can help to make panning with 2 fingers would help me a lot.

Thanks again for the quick responses.

Alright. I didn’t get a chance today, but I’ll checkout the app and get back to you tomorrow.

Plus, I got an email update where you actually said “De nuevo gracias por las respuestas rápidas” which I understood to mean “Thanks again for the quick responses”. So if you feel like you can’t get something across in English, feel free to say it in Spanish as well. My Spanish speaking in high school may be a little rusty, but if it helps, I’m down to try and understand :slight_smile: