I can't translate points in my 3D graphics engine (java)

72 views Asked by At

I'm following javidx9's tutorial on youtube about making a 3D graphics engine (I'm doing it in java, rather than C++, but I'm pretty closely following his steps), and I'm at the point where we move the cube away from the 'camera' to better see it (35:49, if you're curious), but as soon as I add the relevant lines of code and run it, nothing shows up. When I take them away, it comes back, and I have no idea what's happening. Code is below, sorry it's kind of long and probably poorly written (using Graphics2D for display):

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Main {

    static Frame frame;
    static double FOV = Math.PI / 2;
    static int w = 400;
    static int h = 400;
    static double a = h / w;
    static double f = 1 / Math.tan(FOV / 2);
    static double zFar = 1000;
    static double zNear = 0.1;
    static double q = zFar / (zFar - zNear);
    static double[][] matProj = new double[4][4];

    public static void main(String[] args) {
    
        frame = new Frame();

    }

    static void draw() {
    
        Mesh cubeMesh = new Mesh();

        //south
        cubeMesh.addTri(0, 0, 0, 0, 1, 0, 1, 1, 0);
        cubeMesh.addTri(0, 0, 0, 1, 1, 0, 1, 0, 0);
    
        //east
        cubeMesh.addTri(1, 0, 0, 1, 1, 0, 1, 1, 1);
        cubeMesh.addTri(1, 0, 0, 1, 1, 1, 1, 0, 1);
    
        //north
        cubeMesh.addTri(1, 0, 1, 1, 1, 1, 0, 1, 1);
        cubeMesh.addTri(1, 0, 1, 0, 1, 1, 0, 0, 1);
    
        //west
        cubeMesh.addTri(0, 0, 1, 0, 1, 1, 0, 1, 0);
        cubeMesh.addTri(0, 0, 1, 0, 1, 0, 0, 0, 0);
    
        //top
        cubeMesh.addTri(0, 1, 0, 0, 1, 1, 1, 1, 1);
        cubeMesh.addTri(0, 1, 0, 1, 1, 1, 1, 1, 0);
    
        //bottom
        cubeMesh.addTri(1, 0, 1, 0, 0, 1, 0, 0, 0);
        cubeMesh.addTri(1, 0, 1, 0, 0, 0, 1, 0, 0);
    
        matProj[0][0] = a * f;
        matProj[1][1] = f;
        matProj[2][2] = q;
        matProj[3][2] = -1 * q * zNear;
        matProj[2][3] = 1;
        matProj[3][3] = 0;
    
        frame.graphics.g2D.setColor(Color.WHITE);
        frame.graphics.g2D.setStroke(new BasicStroke(2));
    
        for(TrianglePoints i : cubeMesh.triangles) {
        
            TrianglePoints translated = i;
        
            translated.p1[2] = i.p1[2] + 3; //when I comment out these lines, it works, but then of course the cube isn't translated
            translated.p2[2] = i.p2[2] + 3;
            translated.p3[2] = i.p3[2] + 3;
        
            int[] xPoints = {(int) MultiplyMatrixVector(translated.p1, matProj)[0], (int) MultiplyMatrixVector(translated.p2, matProj)[0], (int) MultiplyMatrixVector(translated.p3, matProj)[0]};
            int[] yPoints = {(int) MultiplyMatrixVector(translated.p1, matProj)[1], (int) MultiplyMatrixVector(translated.p2, matProj)[1], (int) MultiplyMatrixVector(translated.p3, matProj)[1]};
        
            for(int j = 0; j < xPoints.length; j++) {
                xPoints[j] += 1;
                xPoints[j] *= (0.5 * w);
                yPoints[j] += 1;
                yPoints[j] *= (0.5 * w);
            }
        
            frame.graphics.g2D.drawPolygon(xPoints, yPoints, 3);
        
         }
    }

    private static double[] MultiplyMatrixVector(double[] i, double[][] m) {
    
        double[] o = new double[3];
    
        o[0] = i[0] * m[0][0] + i[1] * m[1][0] + i[2] * m[2][0] + m[3][0];
        o[1] = i[0] * m[0][1] + i[1] * m[1][1] + i[2] * m[2][1] + m[3][1];
        o[2] = i[0] * m[0][2] + i[1] * m[1][2] + i[2] * m[2][2] + m[3][2];
        double w = i[0] * m[0][3] + i[1] * m[1][3] + i[2] * m[2][3] + m[3][3];
    
        if(w != 0) {    //I think this might be where the issue is, when I translate it w won't be 0, but I don't know how that would make it not work, I have to divide by w here.
            o[0] /= w;
            o[1] /= w;
            o[2] /= w;
        }
    
        return o;
    
    }

}

class Frame extends JFrame {

    private static final long serialVersionUID = 1L;
    GraphicsC graphics = new GraphicsC();

    Frame(){
    
        this.setSize(Main.w, Main.h);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.add(graphics);
        this.setVisible(true);
    
    }

}

class GraphicsC extends JPanel {

    private static final long serialVersionUID = 1L;
    Graphics2D g2D;

    public void paintComponent(Graphics g) {
    
        super.paintComponent(g);
        this.setBackground(Color.BLACK);
    
        g2D = (Graphics2D) g;
    
        Main.draw();
    
    }

}

class TrianglePoints {

    double[] p1 = new double[3];
    double[] p2 = new double[3];
    double[] p3 = new double[3];

    TrianglePoints(double[] p1, double[] p2, double[] p3) {
        this.p1 = p1;
        this.p2 = p2;
        this.p3 = p3;
    }

}

class Mesh {

    List<TrianglePoints> triangles = new ArrayList<TrianglePoints>();

    void addTri(double a, double b, double c, double d, double e, double f, double g, double h, double i) {
        double[] p1 = {a, b, c};
        double[] p2 = {d, e, f};
        double[] p3 = {g, h, i};
        triangles.add(new TrianglePoints(p1, p2, p3));
    }

}
1

There are 1 answers

0
YellowAfterlife On

I highly suspect your issue to be that in C++, doing (timestamp)

triTranslated = tri;

will in fact make a copy of the triangle, whereas your code merely gets a reference, therefore your triangles drift away at pace of 3 units per render, likely vanishing out of view before you could see anything.