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
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
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
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;
}
}