I am working in ARCore Android and I want to rotate 3D model on button click.
I have done rotation but the problem is that it would not rotate on current position, i.e. if model is moved somewhere else on plane it come back to its initial position where model is projected and here we can see rotation. I want to rotate my model anywhere on plane and it remains there.
Here is my code
private void rotateRight(TransformableNode node, AxisClass objAxis, Vector3 pos) {
node.getRotationController().setEnabled(true);
node.getScaleController().setEnabled(true);
node.getTranslationController().setEnabled(false);
Quaternion rightMoveVector = new Quaternion();
rightMoveVector = tNode.getLocalRotation();
Quaternion orientations = new Quaternion();
Quaternion orientation = Quaternion.axisAngle(new Vector3(pos.x, 1.0f, pos.z), rotateAngle);
node.setLocalRotation(Quaternion.axisAngle(new Vector3(0.0f, 1.0f, 0.0f), rotateAngle));
rotateAngle = rotateAngle + 30;
objAxis.setRotateRight(String.valueOf(rotateAngle));
objAxis.setY_axis(String.valueOf(Math.toRadians(rotateAngle)));
}
i am answering my own question, it would be helpful for someone.
for model rotation you have to override onupdate method in sceneform android.
after performing rotation you have to set model position so that it remains on its position.
Quaternion q1 = tNode.getLocalRotation();
Quaternion q2 = Quaternion.axisAngle(new Vector3(0f, 1f, 0f), -2f);
tNode.setLocalRotation(Quaternion.multiply(q1, q2));
tNode.setLocalPosition(localPosition);
Related
i try to rotate a 3D instance when I move the mouse. i use Orthographic Camera, and i have a tiled isomap in background.
[EDIT] I use this code :
public boolean mouseMoved (int x, int y) {
Vector3 direction = new Vector3();
Vector3 worldCoordinate = cam.unproject(new Vector3(x, y, 0));
direction = (worldCoordinate).sub(position).nor();
direction.set(-direction.x, -direction.y, -direction.z);
Matrix4 instanceRotation = instance.transform.cpy().mul(instance.transform);
instanceRotation.setToLookAt(direction, new Vector3(0,-1,0));
instanceRotation.rotate(0, 0, 1, 180);
quat = new Quaternion();
instanceRotation.getRotation(quat);
instance.transform.set(position, quat);
return false;
}
Now, the instance follows the cursor, but in all axes. I just want to turn on the Y axis. I can change quat.x = 0 and quat.z = 0 to lock the rotation. After that, the rotation only works on the Y axis. But, the model should turn over if my cursor is at the top of the screen, but it remains facing, no matter where my cursor is.
I don't know how to convert the coordinates to tell my rotation that it needs to turn over. And to modify the quat in this way is not very elegant
Edit : Some image for illustrate what i want
Here, with cursor in the bottom of the screen, the model turn to look in good direction :
Here, the model dont turn over, like the cursor is in bottom of the screen :
I use libGDX for a 3D game. In this game an 3D arrow should indicate a certain direction in 3D space. As the player is moving, the direction of the 3D arrow is updated for every frame.
I want to place the arrow in the direction, the camera is looking 3 units before the camera, so that the arrow is always visible. Therefore I added the camera direction to the current camera position and used this as translation part for the arrow. The direction is calculated by substracting the arrow position from the target.
All this works fine, the arrow is displayed at the right position and it moves. The problem is, it sometimes points to the target, and sometimes not.
Here my code:
Vector3 targetPosition = new Vector3(1, 1, 10);
Vector3 cameraPosition = gameController.getCamera().position.cpy();
Vector3 cameraDirection = gameController.getCamera().direction.cpy();
Vector3 up = gameController.getCamera().up.cpy();
Vector3 arrowPosition = cameraDirection.scl(3).add(cameraPosition);
Vector3 arrowDirection = targetPosition.cpy();
arrowDirection = arrowDirection.sub(arrowPosition).nor();
Matrix4 transformationMatrix = new Matrix4();
// calculate orthogonal up vector
up.crs(arrowDirection).crs(arrowDirection);
arrowModel.transform = transformationMatrix.setToLookAt(arrowDirection,
up).trn(arrowPosition);
To avoid that the vectors are calculated wrong, some debug lines were added:
modelBuilder.begin();
MeshPartBuilder partBuilder = modelBuilder.part("lines", GL20.GL_LINES,
Usage.Position,
new Material(ColorAttribute.createDiffuse(Color.GREEN)));
Vector3 linePos = arrowPosition.cpy();
partBuilder.line(linePos.cpy().add(arrowDirection), linePos);
partBuilder.line(linePos.cpy().add(up), linePos);
debugModel = new ModelInstance(modelBuilder.end());
As a result, I see a correct green line for the up vector (current up vector of the camera), and a green line pointing correctly to my target, the green cube. The arrow does something other:
http://www.directupload.net/file/d/3638/2ka7kvvj_jpg.htm
In the picture the arrow is quite near the right direction (green line), there are other situations, where it points in the completely wrong direction.
I used quite a lot combinations of .translate, .trn, .setToLookAt, and .rotate but all of them showed similar, wrong results.
Do you have an idea what went wrong here?
I have a texture of a circle, which gets drawn to a new position when a touch drag occurs. It isn’t set up as a body.
I have made a physics map using Aurelien Ribon's Physics Body Editor Loader GUI to the circle's upper and lower part, and I’d like to draw that mask over the texture’s position, and to its new position when a drag occurs.
How can I do this? In my create method I initialize the variables, the mask gets drawn to the texture’s initial position, but when I move it the mask stays at the circle’s initial position.
Here's my code:
Create() method:
//... rest of the method ommited for clarity
karika = gameWorld.getKarika();
World world = new World(new Vector2(0, 0), false);
Box2DDebugRenderer renderer = new Box2DDebugRenderer();
BodyEditorLoader karikaLoader = new BodyEditorLoader(Gdx.files.internal("data/collision-masks/karika.json"));
BodyDef karikaDef = new BodyDef();
karikaDef.type = BodyType.DynamicBody;
karikaDef.position.set(karika.getPosition().x, karika.getPosition().y);
karikaDef.angle = karika.getRotation();
Body karikaBody = world.createBody(karikaDef);
FixtureDef karikaFixture = new FixtureDef();
karikaFixture.density = 0.5f;
karikaFixture.friction = 0.8f;
karikaFixture.restitution = 0.6f;
karikaLoader.attachFixture(karikaBody, "karika", karikaFixture, karika.getWidth());
Vector2 karikaBodyOrigin = karikaLoader.getOrigin("karika", karika.getWidth()).cpy();
//rest of the method ommited for clarity
My render() method:
//...
batch.begin();
batch.draw(karikaTexture, karika.getPosition().x, karika.getPosition().y, karika.getWidth() / 2, karika.getHeight() / 2, karika.getWidth(), karika.getHeight(), 1, 1, karika.getRotation(), 0, 0, karikaTexture.getWidth(), karikaTexture.getHeight(), false, false);
batch.end();
renderer.render(world, cam.combined);
world.step(1 / 60f, 6, 2);
//...
The texture that is being drawn in the render method is my circle's texture. As said before, I haven't set that up as a body, only the collision mask.
What I'd like to do, is attach the mask to the texture, and keep up with it's position, for example when I drag the circle, the mask should stay on the circle.
Look into the DebugRenderer. It works very well, and does precisely what you're asking.
Here's how to use it.
debugRenderer.render(this.world, camera.combined);
And here's a more thorough tutorial.
I recommend you assign your circle's position using physics object's position rather than trying to assign the physics object to your texture's position.
In your code, it looks like you create your karikaBody using the current position of karika, but the karikaBody position is never being updated after that. So your "collision mask" (your physics body) position never changes.
I want to create a camera moving above a tiled plane. The camera is supposed to move in the XY-plane only and to look straight down all the time. With an orthogonal projection I expect a pseudo-2D renderer.
My problem is, that I don't know how to translate the camera. After some research it seems to me, that there is nothing like a "camera" in OpenGL and I have to translate the whole world. Changing the eye-position and view center coordinates in the Matrix.setLookAtM-function just leads to distorted results.
Translating the whole MVP-Matrix does not work either.
I'm running out of ideas now; do I have to translate every single vertex every frame directly in the vertex buffer? That does not seem plausible to me.
I derived GLSurfaceView and implemented the following functions to setup and update the scene:
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
// Setup the projection Matrix for an orthogonal view
Matrix.orthoM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}
public void onDrawFrame(GL10 unused) {
// Draw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
//Setup the camera
float[] camPos = { 0.0f, 0.0f, -3.0f }; //no matter what else I put in here the camera seems to point
float[] lookAt = { 0.0f, 0.0f, 0.0f }; // to the coordinate center and distorts the square
// Set the camera position (View matrix)
Matrix.setLookAtM( vMatrix, 0, camPos[0], camPos[1], camPos[2], lookAt[0], lookAt[1], lookAt[2], 0f, 1f, 0f);
// Calculate the projection and view transformation
Matrix.multiplyMM( mMVPMatrix, 0, projMatrix, 0, vMatrix, 0);
//rotate the viewport
Matrix.setRotateM(mRotationMatrix, 0, getRotationAngle(), 0, 0, -1.0f);
Matrix.multiplyMM(mMVPMatrix, 0, mRotationMatrix, 0, mMVPMatrix, 0);
//I also tried to translate the viewport here
// (and several other places), but I could not find any solution
//draw the plane (actually a simple square right now)
mPlane.draw(mMVPMatrix);
}
Changing the eye-position and view center coordinates in the "LookAt"-function just leads to distorted results.
If you got this from the android tutorial, I think they have a bug in their code. (made a comment about it here)
Try the following fixes:
Use setLookatM to point to where you want the camera to be.
In the shader, change the gl_Position line
from: " gl_Position = vPosition * uMVPMatrix;"
to: " gl_Position = uMVPMatrix * vPosition;"
I'd think the //rotate the viewport section should be removed as well, as this is not rotating the camera properly. You can change the camera's orientation in the setlookat function.
I have a camera that orbits around a fixed point using quaternions. The problem is that as the camera rotates around the x-axis and passes over a pole, that the camera will flip and produce a mirrored image. This makes sense because the camera is facing the opposite way but the up vector of the camera hasn't changed. Clearly, a new up vector needs to be calculated from the look vector and the right vector but I can't seem to get it to work. Note: this uses http://commons.apache.org/math/api-2.2/org/apache/commons/math/geometry/Rotation.html to represent quaternions.
Anyway, I'm using the following basic procedure to rotate the camera.
The rotation quaternion is initialised to the identity [1, 0, 0, 0]:
private Rotation total = Rotation.IDENTITY;
And the up vector of the camera is initialised as:
private Vector3D up = new Vector3D(0, 1, 0);
Rotation is done by storing the current rotation of the camera as a quaternion and then applying any subsequent rotations to this quaternion, the combined quaternion (total) is then used to rotate the position of the camera. The following code describes this procedure:
/**
* Rotates the camera by combining the current rotation (total) with any new axis/angle representation of a new rotation (newAxis, rotation).
*/
public void rotateCamera() {
if (rotation != 0) {
//Construct quaternion from the new rotation:
Rotation local = new Rotation(Math.cos(rotation/2), Math.sin(rotation/2) * newAxis.getX(), Math.sin(rotation/2) * newAxis.getY(), Math.sin(rotation/2) * newAxis.getZ(), true);
//Generate new camera rotation quaternion from current rotation quaternion and new rotation quaternion:
total = total.applyTo(local);
//Rotate the position of the camera using the camera rotation quaternion:
cam = rotateVector(local, cam);
//rotation is complete so set the next rotation to 0
rotation = 0;
}
}
/**
* Rotate a vector around a quaternion rotation.
*
* #param rotation The quaternion rotation.
* #param vector A vector to be rotated.
* #return The rotated vector.
*/
public Vector3D rotateVector(Rotation rotation, Vector3D vector) {
//set world centre to origin, i.e. (width/2, height/2, 0) to (0, 0, 0)
vector = new Vector3D(vector.getX() - width/2, vector.getY() - height/2, vector.getZ());
//rotate vector
vector = rotation.applyTo(vector);
//set vector in world coordinates, i.e. (0, 0, 0) to (width/2, height/2, 0)
return new Vector3D(vector.getX() + width/2, vector.getY() + height/2, vector.getZ());
}
The fields newAxis and rotation which store the axis/angle of any new rotation are generated by key presses as follows:
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) {
camera.setAxis(new Vector3D(1, 0, 0));
camera.setRotation(0.1);
}
if (e.getKeyCode() == KeyEvent.VK_A) {
camera.setAxis(new Vector3D(0, 1, 0));
camera.setRotation(0.1);
}
if (e.getKeyCode() == KeyEvent.VK_S) {
camera.setAxis(new Vector3D(1, 0, 0));
camera.setRotation(-0.1);
}
if (e.getKeyCode() == KeyEvent.VK_D) {
camera.setAxis(new Vector3D(0, 1, 0));
camera.setRotation(-0.1);
}
}
During each render loop the rotateCamera() method is called and then the following code sets the camera:
glu.gluLookAt(camera.getCam().getX(), camera.getCam().getY(), camera.getCam().getZ(), camera.getView().getX(), camera.getView().getY(), camera.getView().getZ(), 0, 1, 0);
You're doing something weird. A unit quaternion represents an entire orientation. You wouldn't normally use an 'up' vector with it. But... it looks like you'd get the effect you want by just using a constant 'up' vector [0,1,0] instead of getting it from the quaternion.
It really sounds like you don't need quaternions. What you want is a constant 'up' vector of [0,1,0]. Then you want an 'at' point that is always the point you're orbiting. Then you want an 'eye' point that can be rotated (with respect to your orbit point) around the y-axis or around the axis defined by the cross-product between your 'up' vector and the vector between your orbit point and the 'eye' point.