Jump to content

how to get frustum from a projection matrix?


photo

Recommended Posts

I've saw there is a function

mat4 frustum(float left,float right,float bottom,float top,float znear,float zfar);

to convert frustum data to a projection matrix, but how can I get the frustum data from a porjection matrix?

Link to comment

Player player = engine.game.getPlayer();
mat4 projection = player.getProjection();
projection.m00 *= float(engine.app.getHeight()) / engine.app.getWidth();
mat4 modelview = player.getOffset() * player.getModelview();

 

Those two matrices represent view frustum that is used in render pipeline. I.e. you could use this code to get all visible objects:

Node objects[0];
engine.world.getIntersectionObjects(projection, modelview, objects);

 

P.S. Using this code to hide invisible objects in scene samples/stress/clutter_00 gives huge performance boost meaning of relatively weak spatial tree implementation for such scenes.

Link to comment

Well, I'd suggest you to look at the source code: engine\math\MathLib.cpp, method:

mat4 frustum(float l,float r,float b,float t,float n,float f);

 

If you don't have a source, just ask engine crew to post this method.

Link to comment

well, i've checked the source, but reverse calculate multple value from mulitple variables, seems little difficult. :( :blink:

 

I think there must be another way to calculate the left/right/top/bottom value from near/far/fov/aspect. but how?

Link to comment

The parameters (l, r, b, t, n, f) determine the view frustum of the

camera.

 

mat4 frustum(float l,float r,float b,float t,float n,float f) {
mat4 ret;
float rl = r - l;
float tb = t - b;
float fn = f - n;
ret.m00 = 2.0f * n / rl; ret.m01 = 0.0f;          ret.m02 = (r + l) / rl;  ret.m03 = 0.0f;
ret.m10 = 0.0f;          ret.m11 = 2.0f * n / tb; ret.m12 = (t + :( / tb;  ret.m13 = 0.0f;
ret.m20 = 0.0f;          ret.m21 = 0.0f;          ret.m22 = -(f + n) / fn; ret.m23 = -2.0f * f * n / fn;
ret.m30 = 0.0f;          ret.m31 = 0.0f;          ret.m32 = -1.0f;         ret.m33 = 0.0f;
return ret;
}

 

The horizontal field of view is determined by the angle between the

left and the right planes (determined by l and r) of the frustum. In the

same manner, the vertical field of view is determined by the angle between

the top and the bottom planes (determined by t and b ).

So the view frustum matrix is more common matrix for performing projection expressed in terms of the six-tuple(l, r, b, t, n, f),

The perspective matrix expressed in terms (fov, aspect, n, f) created from frustum matrix by r = -l and t = -b.

 

mat4 perspective(float fov,float aspect,float n,float f) {
mat4 ret;
float h = 1.0f;
float w = aspect;
if(!compare(fov,90.0f)) {
	h = Math::tanf(fov * DEG2RAD * 0.5f);
	w = h * aspect;
}
float fn = f - n;
ret.m00 = 1.0f / w; ret.m01 = 0.0f;     ret.m02 = 0.0f;          ret.m03 = 0.0f;
ret.m10 = 0.0f;     ret.m11 = 1.0f / h; ret.m12 = 0.0f;          ret.m13 = 0.0f;
ret.m20 = 0.0f;     ret.m21 = 0.0f;     ret.m22 = -(f + n) / fn; ret.m23 = -2.0f * f * n / fn;
ret.m30 = 0.0f;     ret.m31 = 0.0f;     ret.m32 = -1.0f;         ret.m33 = 0.0f;
return ret;
}

 

From player you can get the perspective matrix, z near and f near, so you can find l , r , b , t,

solving a simple equations taking into account the equality of the relevant matrix members.

Link to comment

well, finally I've got this:

float fov = org.getFov();

float ymax = n * tan(fov*PI/360.0);
float ymin = - ymax;

float xmin = ymin * aspect;
float xmax = ymax *aspect ;

mat4 proj = frustum(xmin, xmax, ymin, ymax, n, f);

 

I've looked the unigine's player class, it seems the player class always use 1.0 as aspect, so it comes with above code.

 

I've tested this with two PlayerDummy, the second player using projection matrix calculated by the frustum function, it looks exactly same as the first. no matter I change fov/near/far value of first player, the second player is always same. ( at least the visualizer draws the same cone)

Link to comment
×
×
  • Create New...