# Portal View/Projection Matrix near plane

For RenderToTexture/Camera based portal rendering, the basics seems simple enough.

However, with a free camera, most of the time it is going to be looking at such portals at an angle:

Now a regular near clipping plane will not always work here, it will either intersect with the wall the portal is sitting on, or possibly with objects in front of the wall.

The desired near clipping plane would be aligned like the portal, producing a view volume more like this:

or this in 3D:

So here is my question:

How does one construct or "truncate" a view/projection matrix to achieve such an off-camera-normal (near) clipping plane?

• Would it work to simply contain the room in a bounding box and cull everything not in the box rather than mess with an angled near plane? – Steve H Nov 6 '12 at 13:23
• I don't think so, as the problem is with the near plane intersecting the wall of the room or objects inside it. – user13213 Nov 6 '12 at 17:17
• I don't understand that statement. None of your diagrams show the near plane intersecting a wall. – Steve H Nov 8 '12 at 0:18

You want to use the following technique to modify the projection matrix. It moves the near plane to a given location (like the plane of the portal).

http://www.terathon.com/lengyel/Lengyel-Oblique.pdf

• Can you please outline the most central parts directly in your answer, as link-only answers are not optimal. Thank you. – Philip Allgaier Nov 17 '14 at 10:20

I have not implemented this myself, but I would imagine using the the stencil buffer would solve your problem. Render the portal to the stencil buffer and then render the objects in the portal's frustum. You will then get pixel-perfect culling of the object.

Here's a website with some details:

http://th0mas.nl/2013/05/rendering-recursive-portals-with-opengl/

Adapted from this page, which was linked in Eric Lengyel's paper. Given a view matrix, projection matrix, and a point and a normal for the desired plane, it produces the right projection matrix.

rplane plane;

D3DXPlaneFromPointNormal(&plane, &p, &normal);

D3DXMATRIX matClipProj, WorldToProjection;

WorldToProjection = matView * matProjection;

D3DXMatrixInverse(&WorldToProjection, NULL, &WorldToProjection);
D3DXMatrixTranspose(&WorldToProjection, &WorldToProjection);

D3DXVECTOR4 clipPlane(plane.a, plane.b, plane.c, plane.d);
D3DXVECTOR4 projClipPlane;

// transform clip plane into projection space
D3DXVec4Transform(&projClipPlane, &clipPlane, &WorldToProjection);
D3DXMatrixIdentity(&matClipProj);

if (projClipPlane.w == 0)  // or less than a really small value
{
// plane is perpendicular to the near plane
return;
}

if (projClipPlane.w > 0)
{
// flip plane to point away from eye
D3DXVECTOR4 clipPlane(-plane.a, -plane.b, -plane.c, -plane.d);

// transform clip plane into projection space
D3DXVec4Transform(&projClipPlane, &clipPlane, &WorldToProjection);

}

// put projection space clip plane in Z column
matClipProj(0, 2) = projClipPlane.x;
matClipProj(1, 2) = projClipPlane.y;
matClipProj(2, 2) = projClipPlane.z;
matClipProj(3, 2) = projClipPlane.w;

// multiply into projection matrix
D3DXMATRIX projClipMatrix = matProjection * matClipProj;

matProjection = projClipMatrix;