0
votes

I would like to produce a projection matrix that will render an object from an arbitrary camera. I've managed to setup a viewMatrix that will look at the object from an arbitrary eye position, but I'm having difficulty setting up the projection matrix.

Given that an object centred at (x,y,z) who's furthest point is r from the centre can for any arbitrary orientation can be entirely enclosed within a sphere of radius r with origin (x,y,z), I calculated my perspective matrix as follows:

float dist2Object = (float) Math.sqrt(vec.lengthSquared());

float objectRadius = (float) Math.sqrt(3 * Math.pow(0.5, 2));
float far = dist2Object + objectRadius;
float near = dist2Object - objectRadius;

// fov_2 = FOV / 2
float fov_2 = (float) (Math.asin(objectRadius / dist2Object));

float r = (float) (Math.tan(fov_2));
float frustum_length = far - near;

depthProjectionMatrix.m00 = 1 / r;
depthProjectionMatrix.m11 = depthProjectionMatrix.m00;
depthProjectionMatrix.m22 = -((far + near) / frustum_length);
depthProjectionMatrix.m23 = -1;
depthProjectionMatrix.m32 = -((2 * near * far) / frustum_length);
depthProjectionMatrix.m33 = 0;

In my example:

  • vec is a vector from the camera to the object
  • the object is a cube who's furthest vertex is (0.5, 0.5, 0.5), giving a r of sqrt(0.75)

As far as I can tell, the geometry and trigonometry should be correct, but rendering the coordinates using the following fragment shader:

#version 150 core

in vec3 pCoord;

out vec4 out_Color;

void main(void) {
    out_Color = vec4(0,1,0,1);
    if(pCoord.x <= -1){
        out_Color = vec4(1,0,0,1);
    }
    if(pCoord.x >= 1){
        out_Color = vec4(0,0,1,1);
    }
    if(pCoord.z <= -1){
        out_Color = vec4(1,0,1,1);
    }
    if(pCoord.z >= 1){
        out_Color = vec4(1,0,1,1);
    }
}

shown at image shows that the FOV is too narrow and that the near and far planes are also too narrow.

How can I fix this?

1
If you want near and far to be just touching the object, then the camera to object distance would have to enter your formulas. I don't see this in the code.Dawnkeeper
@Dawnkeeper The vector from the camera to the object is stored in vec and the distance to between camera and object is stored in dist2Object.AdvancedGarde89

1 Answers

0
votes

Haven't done this in a while, but it seem you are missing the viewport size in your calculation. Here is what I used for a project. Mind that the matrix here starts with _11 where you use m00:

double aspectRatio = (double)this.viewPort.Width /(double)this.viewPort.Height;
double fov = Math.toRadians(fieldOfView/2.0);
double size = nearClip * Math.tan(fov);

double left = -size* aspectRatio, right = size* aspectRatio, bottom = -size , top = size ;

projectionMatrix.resetToZero();

// the values in comments are for non symetrical frustrum 

// First Column
projectionMatrix._11 = (float) (nearClip/right);//(float) ((2 * nearClip )/ (double)(right - left));

// Second Column
projectionMatrix._22 = (float)(nearClip/top);//(float) (2 * nearClip / (double)(top - bottom));

// Third Column
projectionMatrix._31 = 0;//(float) ((right + left) / (right - left));
projectionMatrix._32 = 0;//(float) ((top + bottom) / (top - bottom));
projectionMatrix._33 = -1*(farClip + nearClip) / (float)(farClip - nearClip);
projectionMatrix._34 = -1;

// Fourth Column
projectionMatrix._43 = -(2 * farClip * nearClip) / (float)(farClip - nearClip);