0

So basically I'm trying to make a simple open gl 3D graphics engine using my own linear algebra to make projection and transformation matrices. OpenGL has a class called glUniformMatrix4fv() which I use to pass the matrices as a float[].

Here is my "Matrix" class to construct a float[] for that openGl method:

private float[] m= {
        1,0,0,0,
        0,1,0,0,
        0,0,1,0,
        0,0,0,1
    };

public Matrix() {}

public Matrix(float[] m) {
    this.m=m;
}
//gets value at x,y coords of matrix
public float getValue(int x,int y) {
    return m[y*4 + x];
}
//sets value of x,y coord to n
public void setValue(int x,int y,float n) {
    m[y*4 + x]=n;
}

To construct a transformation for object translation and rotation I first create translation Matrix (s is for scale). Also a vertex is basically just a size 4 float array I have my Vector/vertex info in:

public Matrix createTranslationMatrix(Vertex pos,float s) {
    Matrix m=new Matrix();
    
    m.setValue(0,0,s);
    m.setValue(1,1,s);
    m.setValue(2,2,s);
    
    m.setValue(3,0,pos.getValue(0));
    m.setValue(3,1,pos.getValue(1));
    m.setValue(3,2,pos.getValue(2));
    
    return m;
    
}

Then I create a rotation matrix which is a combo of x, y, and z rotation of object around origin

public Matrix createRotationMatrix(Vertex rot) {
    //if rotation is screwed up maybe mess around with order of these :)
    Matrix rotX=createRotationMatrixX(rot.getValue(0));
    Matrix rotY=createRotationMatrixY(rot.getValue(1));
    Matrix rotZ=createRotationMatrixZ(rot.getValue(2));
    Matrix returnValue=multiply(rotX,rotY);
    returnValue=multiply(returnValue,rotZ);
    return returnValue;
}


private Matrix createRotationMatrixX(float num) {
    float n=num;
    n=(float)Math.toRadians(n);
    Matrix rot=new Matrix();
    
    rot.setValue(1, 1, (float)Math.cos(n));
    rot.setValue(1, 2, (float)Math.sin(n));
    rot.setValue(2, 1, (float)-Math.sin(n));
    rot.setValue(2, 2, (float)Math.cos(n));
    
    return rot;
}
//rotation mat Y
private Matrix createRotationMatrixY(float num) {
    float n=num;
    n=(float)Math.toRadians(n);
    Matrix rot=new Matrix();
    
    rot.setValue(0, 0, (float)Math.cos(n));
    rot.setValue(0, 2, (float)-Math.sin(n));
    rot.setValue(2, 0, (float)Math.sin(n));
    rot.setValue(2, 2, (float)Math.cos(n));
    return rot;
}

//rotation mat Z
private Matrix createRotationMatrixZ(float num) {
    float n=num;
    n=(float)Math.toRadians(n);
    Matrix rot=new Matrix();
    
    rot.setValue(0, 0, (float)Math.cos(n));
    rot.setValue(0, 1, (float)Math.sin(n));
    rot.setValue(1, 0, (float)-Math.sin(n));
    rot.setValue(1, 1, (float)Math.cos(n));
    
    
    return rot;
    
}

I combine the translation and create my objectTransform float[] using a matrix with multiply(rotationMat,translationMat):

public Matrix multiply(Matrix a, Matrix b){
    Matrix m=new Matrix();
    for(int y=0;y<4;y++) {
        for(int x=0;x<4;x++) {
            //if this doesn't work maybe try switching x and y around?
            m.setValue(x,y,a.getValue(x,0)*b.getValue(0,y) + a.getValue(x,1)*b.getValue(1,y) + a.getValue(x,2)*b.getValue(2,y) + a.getValue(x,3)*b.getValue(3, y));
        }
    }
    return m;
}

And my code for my worldTransorm is defined from by combining a transformation with negative values for position and rotation (so it moves vertex and rotates opposite from camera position and rotation), then combinging rotation and transformation like so multiply(translationMat,rotationMat) , so it theoretically moves opposite camera pos, THEN rotates opposite camera rotation.

then I create my projection using this function:

public Matrix createProjectionMatrix(float fov, float aspectRatio, float near, float far) {
    
    float fovRad=1/(float)Math.tan(Math.toRadians(fov*.5));
    Matrix projection=new Matrix(base);
    projection.setValue(0,0,aspectRatio*fovRad);
    projection.setValue(1,1,fovRad);
    projection.setValue(2,2,far/(far-near));
    
    projection.setValue(2,3,(-far*near)/(far-near));
    
    projection.setValue(3,2,1);
    projection.setValue(3,3,0);
    
    return projection;
}

I combine my projection , worldTransform, and objectTransform with my Vec3 position (vector with mesh coordinates I import). These are all multiplied together in my openGL shader class like so:

gl_Position=projection * worldTransform * objectTransform * vec4(position,1);

Write now if I back my camera up by 3, rotate it around with hopes of finding the "triangle" mesh I made

        float[] verts= {
                //top left tri
                -.5f,-.5f,0,
                0,.5f,0,
                .5f,-.5f,0,
        };

Then I get a really small pixel moving really fast accross my screen from top to bottom. I also have the object spinning, but that (if my code worked properly) shouldn't be an issue, but if I don't have the object spinning, then I don't see any pixel at all. So my thinking is the object transformation is applying like the world transormation should be working, moving the vertex by "translation" then rotating it, or the triangle is really small and not scaled properly (do I have to offset it somehow?), but then it shouldn't be flying off the screen repeatedly as if its rotating around the camera. I've tried switching multiplication of translation and rotation for both types of transforms, but either the triangle doesn't appear at all or I just see a teensy tiny little pixel, almost orbitting the camera at high speeds (when I should see just the triangle and camera rotating seperately)

I know its a lot to ask but what am I doing wrong? Do I need to transpose something? Is my projection matrix out of wack? I feel like everything should be right :(

kibby
  • 23
  • 4
  • what are the values of your triangle vertexes after transformation? Where do you do the perspective divide? Where do you rescale to screen coordinates? You can crosscheck the math with example in here [Understanding 4x4 homogenous transform matrices](https://stackoverflow.com/a/28084380/2521214) btw if you want to have GLSL like math you can check my [GLSL_math.h](https://ulozto.net/tamhle/Lac6wsTA65Ni#!ZJD0MwR2AJR0ZmR5LJAyZwHlLJH1MJyBAGL0I3MvJKDlF2L3LD==) also this [nd_math.h](https://stackoverflow.com/a/55439139/2521214) might be interesting for you – Spektre Feb 21 '22 at 11:48
  • and as you are doing this for gfx purposes check this out [4D reper](https://stackoverflow.com/a/62466260/2521214) however its 4D but you can downgrade it to 3D easily ... – Spektre Feb 21 '22 at 11:50
  • Thanks so much, those help a lot. I'm not doing a perspective divide, and I'm not scaling to screen coordinates. I watched a video where a dude made a projection Matrix and just plopped it in but I think he was using another program to construct it, So I assumed openGl just offsets it for you depending on the screen dimensions as long as you project it into space. This might be a dumb question, but how do I check my triangle vertices after transformation? Shaders are written in... c... right? Can I print them out within the shader as they are being created? I don't use c very much – kibby Feb 22 '22 at 02:52
  • if you are using OpenGL then it is doing the scaling and perspective divide on its own (using `w` coordinate instead of `z`). To ceck the vertexes after transform you either multiply your matrices and vertex together on CPU side (in the same order as your gfx engine does). OpenGL window usually visible range of x,y on `<-1.0,+1.0>` interval. And the scaling is done using `glViewBox(...)` settings and `GL_PROJECTION_MATRIX`. If you are SW rendering to bitmap then you have to scale to its resolutionn. You can use [gluPerspective](https://stackoverflow.com/a/62243585/2521214) for the projection. – Spektre Feb 22 '22 at 07:33
  • that one will store the divide to `w`... btw from a quick crosscheck you are implementing the `aspectRatio` wrongly ... you should multiply angle inside the cotangens instead of outside ... – Spektre Feb 22 '22 at 07:44
  • 1
    ... I'm such an idiot thanks for your help all I had to do was store in w it works now – kibby Feb 27 '22 at 15:53
  • been there too before I converted to OpenGL decades ago it was usual to use `z` coordinate instead of `w` due various reasons that are no longer valid ... – Spektre Feb 27 '22 at 15:55

0 Answers0