简体   繁体   中英

Why is my rotation matrix giving an extra translation?

A couple weeks ago I decided to make my own simple 3d game engine. I've followed a couple tutorials online, and I looked at many videos, and so far, I've gotten I pretty good engine. But I have one problem. When I rotate or scale an object, it seems that its center is the top-left corner of the screen instead of its real center. For example, when I rotate an object, it rotates around the left edge of the screen, and when I scale it, is scales towards the corner of the screen or away from the corner of the screen. Here's my code:

Mesh Class

package com.cub.cubefront.mesh;

import com.cub.cubefront.math.Matrix4f;
import com.cub.cubefront.math.Vector3f;

public class Mesh {

    private Vector3f[] verts;
    private Vector3f center;

    private double rotX = 0;
    private double rotY = 0;
    private double rotZ = 0;

    private double scaleX = 1;
    private double scaleY = 1;
    private double scaleZ = 1;

    private double translateX = 0;
    private double translateY = 0;
    private double translateZ = 0;

public Mesh(int arg0) {
    verts = new Vector3f[arg0];
}

public Vector3f getVertexAt(int arg0) {
    return verts[arg0 - 1];
}

public Vector3f[] getVerticies() {
    return verts;
}

public int getVerticiesCount() {
    return verts.length;
}

public void setVertexAt(int arg0, Vector3f arg1) {
    verts[arg0 - 1] = arg1;
}

public void setRotationPoint(Vector3f arg0) {
    this.center = arg0;
}

public Vector3f getRotationPoint() {
    return center;
}

public Vector3f getCenter() {
    int arg0 = verts.length;
    double centerX = 0;
    double centerY = 0;
    double centerZ = 0;
    for (int i = 0; i < arg0; i++) {
        centerX += verts[i].getX();
        centerY += verts[i].getY();
        centerZ += verts[i].getZ();
    }
    return new Vector3f((float)(centerX / arg0), (float)(centerY / arg0), (float)(centerZ / arg0));
}

public void rotateX(double arg0) {
    this.rotX += Math.toRadians(arg0);
}

public void setRotationX(double arg0) {
    this.rotX = Math.toRadians(arg0);
}

public Matrix4f getXRotationAsMatrix() {
    return new Matrix4f(new double[][] { // YZ rotation matrix (X)
        { 1, 0, 0, 0 },
        { 0, Math.cos(rotX), Math.sin(rotX), 0 },
        { 0, -Math.sin(rotX), Math.cos(rotX), 0 },
        { 0, 0, 0, 1 }
    });
}

public Matrix4f getZRotationAsMatrix() {
    return new Matrix4f(new double[][] { // XY rotation matrix (Z)
        { Math.cos(rotZ), -Math.sin(rotZ), 0, 0 },
        { Math.sin(rotZ), Math.cos(rotZ), 0, 0 },
        { 0, 0, 1, 0 },
        { 0, 0, 0, 1 }
    });
}

public void rotateY(double arg0) {
    this.rotY += Math.toRadians(arg0);
}

public void setRotationY(double arg0) {
    this.rotY = Math.toRadians(arg0);
}

public Matrix4f getYRotationAsMatrix() {
    return new Matrix4f(new double[][] { // XZ rotation matrix (Y)
        { Math.cos(rotY), 0, Math.sin(rotY), 0 },
        { 0, 1, 0, 0 },
        { -Math.sin(rotY), 0, Math.cos(rotY), 0},
        { 0, 0, 0, 1 }
    });
}

public void setRotationZ(double arg0) {
    this.rotZ = Math.toRadians(arg0);
}

public void rotateZ(double arg0) {
    this.rotZ += Math.toRadians(arg0);
}

public Matrix4f getRotation() {
    return getZRotationAsMatrix().multiply(getXRotationAsMatrix()).multiply(getYRotationAsMatrix());
}

public void setScaleX(double arg0) {
    this.scaleX = arg0;
}

public void scaleX(double arg0) {
    this.scaleX += arg0;
}

public double getScaleX() {
    return scaleX;
}

public void setScaleY(double arg0) {
    this.scaleY = arg0;
}

public void scaleY(double arg0) {
    this.scaleY += arg0;
}

public double getScaleY() {
    return scaleY;
}

public void setScaleZ(double arg0) {
    this.scaleZ = arg0;
}

public void scaleZ(double arg0) {
    this.scaleZ += arg0;
}

public double getScaleZ() {
    return scaleZ;
}

public void setScale(double arg0) {
    setScaleX(arg0);
    setScaleY(arg0);
    setScaleZ(arg0);
}

public void setScale(double[][] arg0) {
    this.scaleX = arg0[0][0];
    this.scaleY = arg0[1][1];
    this.scaleZ = arg0[2][2];
}

public void setScale(Matrix4f arg0) {
    this.scaleX = arg0.getValueAt(0, 0);
    this.scaleY = arg0.getValueAt(1, 1);
    this.scaleZ = arg0.getValueAt(2, 2);
}

public void scale(double arg0) {
    scaleX(arg0);
    scaleY(arg0);
    scaleZ(arg0);
}

public Matrix4f getScale() {
    return new Matrix4f(new double[][] {
            { getScaleX(), 0, 0, 0 },
            { 0, getScaleY(), 0, 0 },
            { 0, 0, getScaleZ(), 0 },
            { 0, 0, 0, 1 }
    });
}

public void translateX(double arg0) {
    this.translateX += arg0;
}

public void translateY(double arg0) {
    this.translateY += arg0;
}

public void translateZ(double arg0) {
    this.translateZ += arg0;
}

public Matrix4f getTranslation() {
    return new Matrix4f(new double[][] {
        { 1, 0, 0, translateX },
        { 0, 1, 0, translateY },
        { 0, 0, 1, translateZ },
        { 0, 0, 0, 1 }
    });
}

}

Scene Class

package com.cub.cubefront;

import com.cub.cubefront.graphics.Bitmap;
import com.cub.cubefront.input.InputHandler;
import com.cub.cubefront.math.Matrix4f;
import com.cub.cubefront.math.Vector2f;
import com.cub.cubefront.math.Vector3f;
import com.cub.cubefront.mesh.Camera;
import com.cub.cubefront.mesh.Mesh;

public class Scene extends Bitmap {

private Camera defaultCam;

public InputHandler input = new InputHandler();

public Scene() {
    super(MainEngine.getWidth(), MainEngine.getHeight());
    defaultCam = new Camera();
}

public void update() { }

public void start() { }

public void render() { }

public void render(Mesh arg0) {
    Matrix4f trans = arg0.getRotation().multiply(arg0.getScale().multiply(arg0.getTranslation()));
    for (int i = 1; i < arg0.getVerticiesCount()+1; i++) { // Depth: Manipulate x and y with z
        Vector3f v1 = trans.transform(arg0.getVertexAt(i));
        for (int n = 1; n < i; n++) {
            Vector3f v2 = trans.transform(arg0.getVertexAt(n));
            drawLine(
                new Vector2f((v1.getX()), (v1.getY())),
                new Vector2f((v2.getX()), (v2.getY()))
            );
        }
    }
}

public void clear() {
    for (int i = 0; i < pixels.length; i++) {
        pixels[i] = 0;
    }
}

public Camera getCamera() {
    return defaultCam;
}

public void setCamera(Camera defaultCam) {
    this.defaultCam = defaultCam;
}

}

Matrix4f Class

package com.cub.cubefront.math;

public class Matrix4f {

private double[][] values;

public Matrix4f() {
    values = new double[4][4];
    setValues();
}

public Matrix4f(double[][] arg0) {
    setValues(arg0);
}

private Matrix4f setValues() {
    values[0][0] = 1;  values[0][1] = 0;  values[0][2] = 0;  values[0][3] = 0;
    values[1][0] = 0;  values[1][1] = 1;  values[1][2] = 0;  values[1][3] = 0;
    values[2][0] = 0;  values[2][1] = 0;  values[2][2] = 1;  values[2][3] = 0;
    values[3][0] = 0;  values[3][1] = 0;  values[3][2] = 0;  values[3][3] = 1;
    return this;
}

public Matrix4f multiply(Matrix4f arg0) {
    double res[][] = new double[4][4];
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            for (int k = 0; k < 4; k++) {
                res[i][j] += values[i][k] * arg0.getValueAt(k, j);
            }
        }
    }

    return new Matrix4f(res);
}

public double[][] getValues() {
    return values;
}

public double getValueAt(int arg0, int arg1) {
    return values[arg0][arg1];
}

public void setValues(double[][] arg0) {
    this.values = arg0;
}

public void setValueAt(int arg0, int arg1, double arg2) {
    values[arg0][arg1] = arg2;
}

public Vector3f transform(Vector3f arg0) {
    return new Vector3f(
        (float)(arg0.getX() * values[0][0] + arg0.getY() * values[1][0] + arg0.getZ() * values[2][0]),
        (float)(arg0.getX() * values[0][1] + arg0.getY() * values[1][1] + arg0.getZ() * values[2][1]),
        (float)(arg0.getY() * values[0][2] + arg0.getY() * values[1][2] + arg0.getZ() * values[2][2])
    );
}

}

Please look at these pictures if you still don't know what I mean.

Picture #1:

Still Triangle

Picture #2:

Triangle Rotated 30 Degrees

Do you see how it rotates around the corner instead of its center? Thanks for your effort in trying to help!

This usually happens when you make Transformations without reseting your object to Origin before affecting it. Remember that Matrix order matters. Rotations take place relative to the Origin, so if your object is not on Origin then it will rotate oddly.

Try rotating it after translating it to (0,0,0) . Then apply the desired translation to the triangle (That is translate to origin, rotate, return to original position).

Hope it helps.

EDIT

In general if you want to rotate a Polygon arround a fixed point you should translate the polygon in such way that the desired point is in (0,0,0) . Then procede with rotation and finally return to original position.

Say you have a Triangle with vertex (1,1) , (3,1) and (2,3) . If you want to rotate around the center of that triangle (which is (2,2) ) you should:

  1. Substract (2,2) from each vertex (making (2,2) the origin)
  2. Then rotate the desired angle
  3. Add (2,2) to each vertex, returning to original position.

This same principles apply to 3 Dimensions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM