# Calculating view frustums in portal rendering system

This topic is 4340 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I am attempting to write a portal rendering system and I think I have it figured out for the most part, except for when it comes to calculating a new view frustum for each portal. As an example of what I am trying to do, observe this picture. I can find the begining frustum by simply calling this:
D3DXMATRIX ViewProj;
D3DXMatrixMultiply(&ViewProj, &View, &Proj);

//Near Plane
Planes[0].a = ViewProj._14 + ViewProj._13;
Planes[0].b = ViewProj._24 + ViewProj._23;
Planes[0].c = ViewProj._34 + ViewProj._33;
Planes[0].d = ViewProj._44 + ViewProj._43;
D3DXPlaneNormalize(&Planes[0], &Planes[0]);

//Far Plane
Planes[1].a = ViewProj._14 - ViewProj._13;
Planes[1].b = ViewProj._24 - ViewProj._23;
Planes[1].c = ViewProj._34 - ViewProj._33;
Planes[1].d = ViewProj._44 - ViewProj._43;
D3DXPlaneNormalize(&Planes[1], &Planes[1]);

//Left Plane
Planes[2].a = ViewProj._14 + ViewProj._11;
Planes[2].b = ViewProj._24 + ViewProj._21;
Planes[2].c = ViewProj._34 + ViewProj._31;
Planes[2].d = ViewProj._44 + ViewProj._41;
D3DXPlaneNormalize(&Planes[2], &Planes[2]);

//Right Plane
Planes[3].a = ViewProj._14 - ViewProj._11;
Planes[3].b = ViewProj._24 - ViewProj._21;
Planes[3].c = ViewProj._34 - ViewProj._31;
Planes[3].d = ViewProj._44 - ViewProj._41;
D3DXPlaneNormalize(&Planes[3], &Planes[3]);

//Top Plane
Planes[4].a = ViewProj._14 - ViewProj._12;
Planes[4].b = ViewProj._24 - ViewProj._22;
Planes[4].c = ViewProj._34 - ViewProj._32;
Planes[4].d = ViewProj._44 - ViewProj._42;
D3DXPlaneNormalize(&Planes[4], &Planes[4]);

//Bottom Plane
Planes[5].a = ViewProj._14 + ViewProj._12;
Planes[5].b = ViewProj._24 + ViewProj._22;
Planes[5].c = ViewProj._34 + ViewProj._32;
Planes[5].d = ViewProj._44 + ViewProj._42;
D3DXPlaneNormalize(&Planes[5], &Planes[5]);


The area I am having trouble with is creating the new view frustum for each portal. How would I go about using the current view frustum and a quad (set of four points representing the portal) to create a new view frustum? Thank you in advance, -Chris

##### Share on other sites
Quote:
 Original post by bengaltgrsThe area I am having trouble with is creating the new view frustum for each portal. How would I go about using the current view frustum and a quad (set of four points representing the portal) to create a new view frustum?
I haven't written a portal engine myself, so this is not from experience, but here's one way you might go about it...

The portal needn't necessarily be a quad; it can be any convex polygon. The first step is to clip the portal to the frustum. This involves clipping it in succession against each plane of the frustum. For this you'll need a good polygon-to-plane clipping function (it can take a little work to make such a function robust).

Once the portal is clipped to the frustum, you have a new convex polygon. The new volume is then built from the near and far planes of the original frustum, and additional planes formed from the camera position and each edge of the portal.

This is a 'brute force' approach, but could probably be optimized in various ways, such as by exploiting coherency and clipping information.

##### Share on other sites
The C4 Engine uses portals pretty extensively. The polygon clipping code that I use can be found here:

http://www.terathon.com/code/clipping.html

##### Share on other sites
I was actually planning on setting it up so that each portal would have to be a quad, just to make it the programming part of it a little easier for me. The clipping of polygons out of the frustum I had already written actually, I just wasn't sure how to compute a new frustum given the current view and the portal quad. I did just realize however, that for each of the six planes that make up the view frustum, I can use the two points of the portal that are parallel with the plane in question (i.e. the two top points to find the top plane of the frustum) and project one point from the camera position to find a third point. From there I can call D3DXPlaneFromPoints which takes the three points and creates the needed plane.

Thank you again for the replies,
-Chris

##### Share on other sites
ok here's my ide for doing it (tested and works wihout problems)
it gives you 4 clip planes equivalent to finding screen space bounding
rectangle of your portal and recalculating 4 planes

1. extract original planes of view frustum from matrices
2. clip your portal polygon (can be any convex polygon) to clipping frustum
(ignoring near and far planes)
3. for each vertex of clipped polygon calculate distances to pairs of clip planes (horizontal and vertical) and calculate t=d1/(d1+d2)
4. find min/max t
5. use min/max t to interpolate equations of planes flipping one of them depending what plane do you want to calculate
for example.

so if you take 2 clip planes( left and right)
and want to calculate new left and right for given portal
you find min/max and then

new_left=old_left*(1-tmin)-old_right*tmin;
new_right=-old_left*(1-tmax)+old_right*tmax;

same for top/bottom

##### Share on other sites
Linear interpolation does sound like a pretty fast way of doing it, but how would I get the min/max values? Would I get the screen space coordiantes of the points of the quad and use those?

Thanks,
-Chris

##### Share on other sites
no you don't use screen space at all. that's whole idea.
for each vertex you calculate distances to 2 planes
and calculate t=d1/(d1+d2) where for example
d1 is distance to left and d2 to right plane (or top bottom)
and you select smalest and largest 't' for your portal polygon
and use it for interpolation.
it's all done in world space.

##### Share on other sites
So as it turns out, the very first method I came up with is the one that works, I just never fully tested it to make sure. Using this method requires that the shape of the portal be a rectangle, but the rectangle can be moved or rotated in any way, and still work fine. Here is the code to create a new view frustum from a rectangle:

D3DXVECTOR3 Points[4];Points[0] = D3DXVECTOR3(0.0f, 1.0f, -2.0f);Points[1] = D3DXVECTOR3(0.0f, 4.0f, -2.0f);Points[2] = D3DXVECTOR3(0.0f, 4.0f,  2.0f);Points[3] = D3DXVECTOR3(0.0f, 1.0f,  2.0f);D3DXPLANE Plane[6];D3DXVECTOR3 ProjPoint;D3DXVECTOR3 Dir;float FarClipDist = 150.0f;//Near planeD3DXPlaneFromPointNormal(&Plane[0], &ActiveCamera->Position, &ActiveCamera->LookVector);//Far planeD3DXPlaneFromPointNormal(&Plane[1], &(ActiveCamera->Position + (FarClipDist * ActiveCamera->LookVector)), &(-ActiveCamera->LookVector));//Left planeDir = Points[0] - ActiveCamera->Position;D3DXVec3Normalize(&Dir, &Dir);ProjPoint = Points[0] + Dir;D3DXPlaneFromPoints(&Plane[2], &Points[0], &ProjPoint, &Points[1]); //Right planeDir = Points[2] - ActiveCamera->Position;D3DXVec3Normalize(&Dir, &Dir);ProjPoint = Points[2] + Dir;D3DXPlaneFromPoints(&Plane[3], &Points[2], &ProjPoint, &Points[3]);//Top planeDir = Points[1] - ActiveCamera->Position;D3DXVec3Normalize(&Dir, &Dir);ProjPoint = Points[1] + Dir;D3DXPlaneFromPoints(&Plane[4], &Points[1], &ProjPoint, &Points[2]);//Bottom planeDir = Points[3] - ActiveCamera->Position;D3DXVec3Normalize(&Dir, &Dir);ProjPoint = Points[3] + Dir;D3DXPlaneFromPoints(&Plane[5], &Points[3], &ProjPoint, &Points[0]);

I do have one final question about portal rendering. My portal rendering is setup to frutum check all of the objects inside the room it is rendering including the walls/floor/ceiling. Obviously there will be times when only a very small section of a wall will be visible through the portal, but since part of it is visible, the whole thing will be rendered. This will cause the game to render much more than it needs to, which I am obviously trying to limit. So my question is, and keep in mind I am using DirectX, would it be a good idea to use user clip planes? This way, it would be garunteed that the only pixels that get rendered are the ones visible through the portal. The game is rendered entirely in HLSL shaders, and uses PS 2.0 extensively right now, but I intend to allow for a PS 1.1 option. I know the lowest card with PS 1.1 support is the GeForce3, but what I do not know is if it is capable of supporting 6 user clip planes. Also, since the portal rendering will cut out most of what is not in view, would it be faster to just not use clipping planes at all?

Thanks,
-Chris

##### Share on other sites
The way i use to do that is using scissor test. First u project the portal verts on screen (2D space), and then find a rectangle that fits it. So u enable scissor test, and use this rect as it parameter (glScissor(x,y,width,height), then only this region is rendered.
Hope this helps!

##### Share on other sites
Having a perfect portal system (zero overdraw) on modern GPU's is a waste of CPU resources and will be sub-optimal.

Using a sloppy-portal system such as described is surely the way to go these days. Yes you will have overdraw. No you probably can't do much better in regards to performance.

Overdraw isnt the big killer it used to be and portal engines by their nature render near geometry before far geometry: So the GPU is able to ignore lots of overdraw before the requests propagate to the fragment shader (so its not going to kill your fill rate)

##### Share on other sites
By the way, if u r using shadow volumes, at least for shadows is better to have good scissors around portals and lights...if u think a little u will find some good heuristics to fit light scissor to portal scissor, depending in witch cell is the camera and witch one is the light...in this case (shadows), the fill-rate is reduced a lot...the first pass (no lights, only ambient and z-write), i do not use glScissor, since i think its better to sort by material rather than cells (in this case u could use a new scissor for each change of cell)...

##### Share on other sites
I actually am using shadow volumes and dynamic lights for everything in my scene, which made the design of the portal rendering a little more interesting. As a very general overview, it uses the idea of projecting bounding volumes from lights through portals to determine which objects on the other side of the portal get rendered by that light. Oh, and glScissor does look like an useful function, but I am using DirectX.

-Chris

##### Share on other sites
DirectX 9 has D3DRS_SCISSORTESTENABLE and IDirect3DDevice9::SetScissorRect().

If you're doing dynamic lights and shadows in portal systems, you'll probably find the following presentation interesting:

http://www.terathon.com/gdc06_lengyel.ppt

##### Share on other sites
Very nice paper. Interestingly enough, the way I designed the portal rendering system for my game/engine is almost exactly as you described there.

-Chris