Author Topic: Strange camera rotation  (Read 2965 times)

Offline Firzen

  • byte
  • *
  • Posts: 12
    • View Profile
Strange camera rotation
« on: April 29, 2015, 05:39:22 pm »
Hello,

I have problem with camera oriantation during camera rotation. The description of problem is here: http://stackoverflow.com/questions/29947901/jpct-strange-camera-rotation
Is there someone who can help me with that?

Thanks in advance!

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Strange camera rotation
« Reply #1 on: April 29, 2015, 09:48:26 pm »
I've answered in that Stackover thread of yours.

Offline Firzen

  • byte
  • *
  • Posts: 12
    • View Profile
Re: Strange camera rotation
« Reply #2 on: May 05, 2015, 03:34:00 pm »
Hi, I am finally returning back to work on this project..
I will continue here instead of StackOverflow because it will be longer.

I have tried to fix my problem with code you adviced to me but jPCT still does the same... Surely I could rotate the cube instead of camera but I have tried that before and there was problem with Rubik's cube moves. These rotations are not so easy and because of that I want to rotate camera instead of rotating objects. IMHO there should be no problem.

Frontend of my project currently contains only 3 important files. In Main.java you can see part of code where I added the code you have adviced to me.

Thanks in advance!

Main.java
Code: [Select]
package main;

import java.awt.Color;
import java.util.List;

import com.threed.jpct.Camera;
import com.threed.jpct.Config;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.IRenderer;
import com.threed.jpct.Object3D;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.World;

import cube.Move;
import cube.enums.BasicMove;
import cube.geom.Point3D;
import exceptions.FilterCharsError;
import exceptions.ParseException;
import exceptions.PointException;

public class Main {
private World world;
private FrameBuffer buffer;
private Cube3D cube;

private SimpleVector cameraPos = new SimpleVector(-20, 0, 0);
private SimpleVector cubeCenter = new SimpleVector(2, 2, 2);
private SimpleVector cameraUpVector = new SimpleVector(0, 1, 0);

public void printCube() throws ParseException, FilterCharsError, PointException {
Config.lightMul = 2;
initWorld();

cube.setRotationPivot(new Point3D(2, 2, 2));

world.getCamera().setPosition(cameraPos);
world.getCamera().lookAt(cubeCenter);

SimpleVector upVector = world.getCamera().getUpVector();
world.getCamera().setOrientation(world.getCamera().getDirection(), upVector);

cube.doMove(new Move(BasicMove.UP));

startPaintLoop();
}

private void startPaintLoop() throws PointException {

while (!org.lwjgl.opengl.Display.isCloseRequested()) {
refreshScene();

// *****************************************************************
// HERE I ADDED CODE THAT SHOULD SET FIXED CAMERA ORIENTATION
// *****************************************************************
world.getCamera().moveCamera(Camera.CAMERA_MOVEIN, cameraPos.distance(new SimpleVector(2, 2, 2)));
cameraPos.rotateAxis(new SimpleVector(0, 0, 1), (float) Math.toRadians(1));
world.getCamera().moveCamera(Camera.CAMERA_MOVEOUT, cameraPos.distance(new SimpleVector(2, 2, 2)));
world.getCamera().setPosition(cameraPos);
world.getCamera().lookAt(cubeCenter);

try {
Thread.sleep(50);
} catch (InterruptedException e) {

}
}

buffer.disableRenderer(IRenderer.RENDERER_OPENGL);
buffer.dispose();
System.exit(0);
}

private void initWorld() {
world = new World();
world.setAmbientLight(20, 20, 20);
world.addLight(new SimpleVector(-15, -10, -14), new Color(200, 200, 200));
world.addLight(new SimpleVector(0, -30, 0), new Color(200, 200, 200));

world.getCamera().setPosition(cameraPos);

buffer = new FrameBuffer(640, 480, FrameBuffer.SAMPLINGMODE_NORMAL);
buffer.disableRenderer(IRenderer.RENDERER_SOFTWARE);
buffer.enableRenderer(IRenderer.RENDERER_OPENGL);

world.getCamera().lookAt(cubeCenter);
cube = new Cube3D(3, world, buffer);
List<Field3D> fields = cube.getFields();

for(Object3D c : fields) {
world.addObject(c);
}
}

private void refreshScene() {
buffer.clear(java.awt.Color.BLUE);
world.renderScene(buffer);
world.draw(buffer);
buffer.update();
buffer.displayGLOnly();
}

public static void main(String[] args) throws ParseException,
FilterCharsError, PointException {
Main m = new Main();
m.printCube();
}
}

Cube3D.java
Code: [Select]
package main;

import java.util.ArrayList;
import java.util.List;

import com.threed.jpct.FrameBuffer;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.Texture;
import com.threed.jpct.TextureInfo;
import com.threed.jpct.TextureManager;
import com.threed.jpct.World;

import cube.Move;
import cube.enums.BasicMove;
import cube.enums.SideType;
import cube.geom.Point3D;
import exceptions.FilterCharsError;
import exceptions.ParseException;
import exceptions.PointException;

public class Cube3D {
private int size;
private List<Field3D> fields = new ArrayList<Field3D>();
private FrameBuffer buffer;
private World world;

private TextureInfo red = new TextureInfo(TextureManager.getInstance().getTextureID("red"));
private TextureInfo blue = new TextureInfo(TextureManager.getInstance().getTextureID("blue"));
private TextureInfo green = new TextureInfo(TextureManager.getInstance().getTextureID("green"));
private TextureInfo yellow = new TextureInfo(TextureManager.getInstance().getTextureID("yellow"));
private TextureInfo orange = new TextureInfo(TextureManager.getInstance().getTextureID("orange"));
private TextureInfo white = new TextureInfo(TextureManager.getInstance().getTextureID("white"));

public Cube3D(int size, World world, FrameBuffer buffer) {
setWorld(world);
setBuffer(buffer);
loadTextures();
setSize(size);
}

private void loadTextures() {
TextureManager.getInstance().addTexture("red",
new Texture("/home/firzen/develop/bakalarka/CubeGui/res/red.jpg"));
TextureManager.getInstance().addTexture("blue",
new Texture("/home/firzen/develop/bakalarka/CubeGui/res/blue.jpg"));
TextureManager.getInstance().addTexture("green",
new Texture("/home/firzen/develop/bakalarka/CubeGui/res/green.jpg"));
TextureManager.getInstance().addTexture("yellow",
new Texture("/home/firzen/develop/bakalarka/CubeGui/res/yellow.jpg"));
TextureManager.getInstance().addTexture("orange",
new Texture("/home/firzen/develop/bakalarka/CubeGui/res/orange.jpg"));
TextureManager.getInstance().addTexture("white",
new Texture("/home/firzen/develop/bakalarka/CubeGui/res/white.jpg"));

red = new TextureInfo(TextureManager.getInstance().getTextureID("red"));
blue = new TextureInfo(TextureManager.getInstance().getTextureID("blue"));
green = new TextureInfo(TextureManager.getInstance().getTextureID("green"));
yellow = new TextureInfo(TextureManager.getInstance().getTextureID("yellow"));
orange = new TextureInfo(TextureManager.getInstance().getTextureID("orange"));
white = new TextureInfo(TextureManager.getInstance().getTextureID("white"));
}

private Field3D createField(SimpleVector move) {
Field3D box = new Field3D(1000, world, buffer);

SimpleVector upperLeftFront = new SimpleVector(-1 + move.x,-1 + move.y,-1 + move.z);
SimpleVector upperRightFront = new SimpleVector(1 + move.x,-1 + move.y,-1 + move.z);
SimpleVector lowerLeftFront = new SimpleVector(-1 + move.x,1 + move.y,-1 + move.z);
SimpleVector lowerRightFront = new SimpleVector(1 + move.x,1 + move.y,-1 + move.z);

SimpleVector upperLeftBack = new SimpleVector(-1 + move.x, -1 + move.y, 1 + move.z);
SimpleVector upperRightBack = new SimpleVector(1 + move.x, -1 + move.y, 1 + move.z);
SimpleVector lowerLeftBack = new SimpleVector(-1 + move.x, 1 + move.y, 1 + move.z);
SimpleVector lowerRightBack = new SimpleVector(1 + move.x, 1 + move.y, 1 + move.z);

// Front
box.addTriangle(upperLeftFront, lowerLeftFront, upperRightFront, yellow);
box.addTriangle(upperRightFront, lowerLeftFront, lowerRightFront, yellow);

// Back
box.addTriangle(upperLeftBack, upperRightBack, lowerLeftBack, white);
box.addTriangle(upperRightBack, lowerRightBack, lowerLeftBack, white);

// Upper
box.addTriangle(upperLeftBack, upperLeftFront, upperRightBack, red);
box.addTriangle(upperRightBack, upperLeftFront, upperRightFront, red);

// Lower
box.addTriangle(lowerLeftBack, lowerRightBack, lowerLeftFront, orange);
box.addTriangle(lowerRightBack, lowerRightFront, lowerLeftFront, orange);

// Left
box.addTriangle(upperLeftFront, upperLeftBack, lowerLeftFront, green);
box.addTriangle(upperLeftBack, lowerLeftBack, lowerLeftFront, green);

// Right
box.addTriangle(upperRightFront, lowerRightFront, upperRightBack, blue);
box.addTriangle(upperRightBack, lowerRightFront, lowerRightBack, blue);

box.build();
return box;
}

private void initCube(int size) {
fields.clear();

for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++) {
for(int k = 0; k < size; k++) {
Field3D field = createField(new SimpleVector(i * 2, j * 2, k * 2));
field.setLocation(new Point3D(i, j, k));
fields.add(field);
}
}
}
}

public void doMoves(String str) throws PointException, ParseException,
FilterCharsError {
List<Move> moves = Move.parseMoves(str);
for(Move m : moves) {
System.out.println(m);
doMove(m);
}
}

// XXX temporary
public void doMove(Move move) throws PointException {
doMove(move, false);
}

public void doMove(Move move, boolean test) throws PointException {
List<Field3D> fields = getFieldsAtLevel(move);

Point3D sum = new Point3D();
for(Field3D field : fields) {
sum = Point3D.plus(sum, field.getLocation());
}

sum = Point3D.divide(sum, fields.size());

System.out.println("Rotation center: " + sum);

setFieldsInnerCenter(fields, sum);

boolean rotate = true;
while(rotate) {
for(Field3D field : fields) {
rotate = field.rotateStep(move);
}

refreshScene();

try {
Thread.sleep(200);
} catch (InterruptedException e) {

}
}

for(Field3D field : fields) {
field.resetRotations();
field.setLastAxis(getRotationAxisFromMove(move));
}
}

private void setFieldsInnerCenter(List<Field3D> fields, Point3D pivot) {
for(Field3D field : fields) {
field.setInnerCenter(pivot);
}
}

private RotationAxis getRotationAxisFromMove(Move move) {
BasicMove bm = move.getBasicMove();
switch(bm) {
case BACK: return RotationAxis.Y;
case BACK_INVERTED: return RotationAxis.Y;
case DOWN: return RotationAxis.Z;
case DOWN_INVERTED: return RotationAxis.Z;
case FRONT: return RotationAxis.Y;
case FRONT_INVERTED: return RotationAxis.Y;
case LEFT: return RotationAxis.X;
case LEFT_INVERTED: return RotationAxis.X;
case RIGHT: return RotationAxis.X;
case RIGHT_INVERTED: return RotationAxis.X;
case UP: return RotationAxis.Z;
case UP_INVERTED: return RotationAxis.Z;
}

return null;
}

// XXX temp
private void printFields(List<Field3D> fields) {
for(Field3D field : fields) {
System.out.println(field.getLocation());
}
}

private void refreshScene() {
buffer.clear(java.awt.Color.BLUE);
world.renderScene(buffer);
world.draw(buffer);
buffer.update();
buffer.displayGLOnly();
}

public void rotateX(double angle) {
for(Field3D field : fields) {
field.rotateWholeX((float) Math.toRadians(angle));
}
refreshScene();
}

public void rotateY(double angle) {
for(Field3D field : fields) {
field.rotateWholeY((float) Math.toRadians(angle));
}
refreshScene();
}

public void rotateZ(double angle) {
for(Field3D field : fields) {
field.rotateWholeZ((float) Math.toRadians(angle));
}
refreshScene();
}

public Field3D getField(int x, int y, int z) {
return getField(new Point3D(x, y, z));
}

public Field3D getField(Point3D location) {
for(Field3D field : fields) {
if(field.getLocation().equals(location)) {
return field;
}
}
return null;
}

public List<Field3D> getFieldsAtLevel(Move move) {
List<Field3D> output = new ArrayList<Field3D>();
SideType side = SideType.parseBasicMove(move.getBasicMove());
int level = move.getLevel();
if(side == SideType.DOWN || side == SideType.RIGHT
|| side == SideType.FRONT) {
level = size - level - 1;
}

if(side == SideType.UP || side == SideType.DOWN) {
for(int y = 0; y < size; y++) {
for(int x = 0; x < size; x++) {
Field3D f = getField(x, y, level);
if(f != null) {
output.add(f);
}
}
}
}
else if(side == SideType.LEFT || side == SideType.RIGHT) {
for(int z = 0; z < size; z++) {
for(int y = 0; y < size; y++) {
Field3D f = getField(level, y, z);
if(f != null) {
output.add(f);
}
}
}
}
else if(side == SideType.FRONT || side == SideType.BACK) {
for(int z = 0; z < size; z++) {
for(int x = 0; x < size; x++) {
Field3D f = getField(x, level, z);
if(f != null) {
output.add(f);
}
}
}
}

return output;
}

public void setRotationPivot(Point3D center) {
setRotationPivot(point3DtoSimpleVector(center));
}

public void setRotationPivot(SimpleVector vector) {
for(Field3D field : fields) {
field.setRotationPivot(vector);
}
}

private SimpleVector point3DtoSimpleVector(Point3D pt) {
return new SimpleVector(pt.getX(), pt.getY(), pt.getZ());
}

public List<Field3D> getFields() {
return fields;
}

public void setFields(List<Field3D> fields) {
this.fields = fields;
}

public int getSize() {
return size;
}

public void setSize(int size) {
this.size = size;
initCube(size);
}

public FrameBuffer getBuffer() {
return buffer;
}

public void setBuffer(FrameBuffer buffer) {
this.buffer = buffer;
}

public World getWorld() {
return world;
}

public void setWorld(World world) {
this.world = world;
}
}

Field3D.java
Code: [Select]
package main;

import com.threed.jpct.FrameBuffer;
import com.threed.jpct.Matrix;
import com.threed.jpct.Object3D;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.World;

import cube.AbstractField;
import cube.Move;
import cube.enums.BasicMove;
import cube.geom.Point3D;
import exceptions.PointException;

public class Field3D extends Object3D implements AbstractField {
private static final long serialVersionUID = 1L;

private Point3D location;
private FrameBuffer buffer;
private World world;
private RotationAxis lastAxis = null;
private Point3D innerCenter = new Point3D();

private int rotationsRemaining = -1;

public Field3D(int arg0, World world, FrameBuffer buffer) {
super(arg0);
setWorld(world);
setBuffer(buffer);
}

@Override
public Point3D getLocation() {
return location;
}

@Override
public void setLocation(Point3D location) {
this.location = location;
}


public boolean rotateStep(Move move) throws PointException {

return rotateStep(move.getBasicMove());
}

private boolean rotateStep(BasicMove move) throws PointException {
final int parts = 7;

if(rotationsRemaining == -1) {
rotationsRemaining = parts;
}

final float partialAngle = getTotalAngle(move) / (float) parts;

if(rotationsRemaining > 0) {
rotate(move, partialAngle);
rotationsRemaining--;
return true;
}
else {
Point3D before = location.getClone();
float angle = getTotalAngle(move);

if(!BasicMove.FRONT.equals(move) && !BasicMove.BACK.equals(move)) {
angle = -angle;
}

location.rotate(move, innerCenter, angle);
System.out.println(before + " vs " + location + "; angle: " + getTotalAngle(move));
return false;
}
}

public void rotate(BasicMove move, float angle) throws PointException {
switch(move) {
case LEFT: rotateX((float) Math.toRadians(angle));
break;
case RIGHT: rotateX((float) Math.toRadians(angle));
break;
case UP: rotateZ((float) Math.toRadians(angle));
break;
case DOWN: rotateZ((float) Math.toRadians(angle));
break;
case FRONT: rotateY((float) Math.toRadians(angle));
break;
case BACK: rotateY((float) Math.toRadians(angle));
break;

case LEFT_INVERTED: rotate(BasicMove.RIGHT, angle); break;
case RIGHT_INVERTED: rotate(BasicMove.LEFT, angle); break;
case UP_INVERTED: rotate(BasicMove.DOWN, angle); break;
case DOWN_INVERTED: rotate(BasicMove.UP, angle); break;
case FRONT_INVERTED: rotate(BasicMove.BACK, angle); break;
case BACK_INVERTED: rotate(BasicMove.FRONT, angle); break;
}
}

/**
* Vrátí úhel ve stupních, o který je třeba rotovat dílek při daném tahu
* na kostce.
* @param move BasicMove
* @return float
*/
private float getTotalAngle(BasicMove move) {
switch(move) {
case LEFT: return -90f;
case RIGHT: return 90f;
case UP: return -90f;
case DOWN: return 90f;
case FRONT: return 90f;
case BACK: return -90f;

case LEFT_INVERTED: return getTotalAngle(BasicMove.RIGHT);
case RIGHT_INVERTED: return getTotalAngle(BasicMove.LEFT);
case UP_INVERTED: return getTotalAngle(BasicMove.DOWN);
case DOWN_INVERTED: return getTotalAngle(BasicMove.UP);
case FRONT_INVERTED: return getTotalAngle(BasicMove.BACK);
case BACK_INVERTED: return getTotalAngle(BasicMove.FRONT);

default: return 0f;
}
}

private Matrix getRotationMatrixX(float angle) {
Matrix m = new Matrix();
m.setRow(0, 1, 0, 0, 0);
m.setRow(1, 0, (float) Math.cos(angle), (float) -Math.sin(angle), 0);
m.setRow(2, 0, (float) Math.sin(angle), (float) Math.cos(angle), 0);
m.setRow(3, 0, 0, 0, 1);
return m;
}

private Matrix getRotationMatrixY(float angle) {
Matrix m = new Matrix();
m.setRow(0, (float) Math.cos(angle), 0, (float) Math.sin(angle), 0);
m.setRow(1, 0, 1, 0, 0);
m.setRow(2, (float) -Math.sin(angle), 0, (float) Math.cos(angle), 0);
m.setRow(3, 0, 0, 0, 1);
return m;
}

private Matrix getRotationMatrixZ(float angle) {
Matrix m = new Matrix();
m.setRow(0, (float) Math.cos(angle), (float) -Math.sin(angle), 0, 0);
m.setRow(1, (float) Math.sin(angle), (float) Math.cos(angle), 0, 0);
m.setRow(2, 0, 0, 1, 0);
m.setRow(3, 0, 0, 0, 1);
return m;
}

public void rotateWholeX(float angle) {
Matrix m = getRotationMatrix();
m.matMul(getRotationMatrixX(angle));
setRotationMatrix(m);
}

public void rotateWholeY(float angle) {
Matrix m = getRotationMatrix();
m.matMul(getRotationMatrixY(angle));
setRotationMatrix(m);
}

public void rotateWholeZ(float angle) {
Matrix m = getRotationMatrix();
m.matMul(getRotationMatrixZ(angle));
setRotationMatrix(m);
}

@Override
public void rotateX(float angle) {
rotateWholeX(angle);
}

@Override
public void rotateY(float angle) {
rotateWholeY(angle);
}

@Override
public void rotateZ(float angle) {
rotateWholeZ(angle);
}

// @Override
// public void rotateX(float angle) {
// System.out.println("rotate x, last " + lastAxis);
//
// if(lastAxis != null && lastAxis.equals(RotationAxis.Z)) {
// setLastAxis(null);
// rotateY(-angle);
// setLastAxis(RotationAxis.Z);
// }
// else {
// Matrix m = getRotationMatrix();
//
// SimpleVector axis = new SimpleVector(1, 0, 0);
// axis.rotate(m);
//
// rotateAxis(axis, angle);
// }
// }
//
// @Override
// public void rotateY(float angle) {
// System.out.println("rotate y");
//
// if(lastAxis != null && lastAxis.equals(RotationAxis.Z)) {
// rotateX(angle);
// }
// else {
// Matrix m = getRotationMatrix();
//
// SimpleVector axis = new SimpleVector(0, 1, 0);
// axis.rotate(m);
//
// rotateAxis(axis, angle);
// }
// }
//
// @Override
// public void rotateZ(float angle) {
// System.out.println("rotate z");
//
// Matrix m = getRotationMatrix();
//
// SimpleVector axis = new SimpleVector(0, 0, 1);
// axis.rotate(m);
//
// rotateAxis(axis, angle);
// }

public void rotate(Move move, float angle)
throws PointException {
rotate(move.getBasicMove(), angle);
}

public FrameBuffer getBuffer() {
return buffer;
}

public void setBuffer(FrameBuffer buffer) {
this.buffer = buffer;
}

public World getWorld() {
return world;
}

public void setWorld(World world) {
this.world = world;
}

public void resetRotations() {
rotationsRemaining = -1;
}

public RotationAxis getLastAxis() {
return lastAxis;
}

public void setLastAxis(RotationAxis lastAxis) {
this.lastAxis = lastAxis;
}

public Point3D getInnerCenter() {
return innerCenter;
}

public void setInnerCenter(Point3D innerCenter) {
this.innerCenter = innerCenter;
}
}

Offline Firzen

  • byte
  • *
  • Posts: 12
    • View Profile
Re: Strange camera rotation
« Reply #3 on: May 05, 2015, 06:16:24 pm »
I have finally got this work thanks to one of your examples, so you can ignore my previous post.
Thank you very much!

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Strange camera rotation
« Reply #4 on: May 05, 2015, 08:15:48 pm »
Cool! Glad you made it work. What did you do to solve it?

Offline Firzen

  • byte
  • *
  • Posts: 12
    • View Profile
Re: Strange camera rotation
« Reply #5 on: May 13, 2015, 09:13:56 pm »
Thanks! Currently I do not have much time for explaining the solution, but after finishing my school work I could post it here.