Page 1 of 1

View frustrum culling, one cam watching another

Posted: Tue Apr 19, 2005 11:49 pm
by srfnaked99
Here's what I have so far: two viewports and two cameras (one for the player's view and one pic-in-pic for the sky view). What I'm trying to do is get the sky view to only show the parts of the scene being rendered in the player's view (essentially, only show the polygons that lie within the player cam's view frustrum). I know it's not a very practical thing to need, but it's for a lab assignment. Any advice?

Posted: Wed Apr 20, 2005 12:33 pm
by :wumpus:
I don't know if it is the easiest way but you can solve this using manual clipping planes (RenderSystem::setClipPlanes).

Posted: Wed Apr 20, 2005 1:46 pm
by sinbad
Funnily enough I had a wish to do this a while back but never got around to doing it.

I think the simplest way to resolve it is to be able to optionally attach an alternate Frustum to the camera as the culling region. This could be used for findVisibleObjects but not for rendering. It's probably not that complicated to implement.

Posted: Wed Apr 20, 2005 2:19 pm
by :wumpus:
Wouldn't that cull on object basis instead of polygon basis? My solution would give the 'cut' effect at the frustrum edges. But I'm not sure what he wants..

Posted: Wed Apr 20, 2005 2:56 pm
by DWORD
Maybe a combination of both would be optimal?

Posted: Wed Apr 20, 2005 2:58 pm
by :wumpus:
sinbad wrote: I think the simplest way to resolve it is to be able to optionally attach an alternate Frustum to the camera as the culling region. This could be used for findVisibleObjects but not for rendering. It's probably not that complicated to implement.
I agree this is generally useful. It could also be used to cull in the distance, in case no far clipping plane is used due to stencil shadows.

Posted: Wed Apr 20, 2005 4:19 pm
by srfnaked99
:wumpus: wrote:I don't know if it is the easiest way but you can solve this using manual clipping planes (RenderSystem::setClipPlanes).
Thanks, I'll give that a shot. I got it working on a per object basis, but the entire ground mesh is still showing up and I'd like for that to be cut at the frustrum too.

Also, we are supposed to make it so that you can turn on a wireframe display of the player cam's frustrum. I did this using Camera::getWorldSpaceCorners() and the Line3D add-on class, but I feel like there has to be a better way. Here is my approach:

// draws a wireframe frustrum for the player's cam
void PlayState::updateFrustrum() {
SceneNode::ObjectIterator itr = mFrustrumNode->getAttachedObjectIterator();
while (itr.hasMoreElements()) {
delete itr.getNext();
}

Vector3 facingDir = mCamera->getDirection().normalisedCopy();

const Vector3 *topRightNear = mCamera->getWorldSpaceCorners();
const Vector3 *topLeftNear = topRightNear + 1;
const Vector3 *botLeftNear = topLeftNear + 1;
const Vector3 *botRightNear = botLeftNear + 1;
const Vector3 *topRightFar = botRightNear + 1;
const Vector3 *topLeftFar = topRightFar + 1;
const Vector3 *botLeftFar = topLeftFar + 1;
const Vector3 *botRightFar = botLeftFar + 1;

mFrustrumNode->detachAllObjects();

/*
facingDir offsets keep the frustrum from being
displayed in the player's viewport
*/

Line3D *nearRect = new Line3D();
nearRect->addPoint(*topRightNear - facingDir);
nearRect->addPoint(*topLeftNear - facingDir);
nearRect->addPoint(*botLeftNear - facingDir);
nearRect->addPoint(*botRightNear - facingDir);
nearRect->addPoint(*topRightNear - facingDir);
nearRect->drawLines();
mFrustrumNode->attachObject(nearRect);

Line3D *farRect = new Line3D();
farRect->addPoint(*topRightFar + facingDir);
farRect->addPoint(*topLeftFar + facingDir);
farRect->addPoint(*botLeftFar + facingDir);
farRect->addPoint(*botRightFar + facingDir);
farRect->addPoint(*topRightFar + facingDir);
farRect->drawLines();
mFrustrumNode->attachObject(farRect);

Line3D *rightEdges = new Line3D();
rightEdges->addPoint(*topRightFar + facingDir);
rightEdges->addPoint(*topRightNear - facingDir);
rightEdges->addPoint(*botRightNear - facingDir);
rightEdges->addPoint(*botRightFar + facingDir);
rightEdges->drawLines();
mFrustrumNode->attachObject(rightEdges);

Line3D *leftEdges = new Line3D();
leftEdges->addPoint(*topLeftFar + facingDir);
leftEdges->addPoint(*topLeftNear - facingDir);
leftEdges->addPoint(*botLeftNear - facingDir);
leftEdges->addPoint(*botLeftFar + facingDir);
leftEdges->drawLines();
mFrustrumNode->attachObject(leftEdges);
}

Posted: Wed Apr 20, 2005 5:24 pm
by gfm
Maybe a volume rendering trick could work here. Just turn everything outside the first camera's field of view into hundreds of black boxes.

Here's another idea.. just render big black triangles in front of the secondary camera where you don't want the person to be able to see. Place the triangles along the secondary camera's near plane so that nothing can jump in front of them. It won't be simple, but you can calculate the position for the triangles by building a line equation that boxes the first camera's view frustrum and then projecting those lines into the second camera's near plane.