1
votes

It looks like the solution is to change projection matrix on-the-fly? Let me do some research to see how to do it correctly.

My scenario is:===> Say, now, I created a 3D box in a window under windows7 with perspective mode enabled. From users point of view, when users move(rotate/translate) this box, when the box is out of the window, it should be clipped/(hidden partly), that's correct. But when the box is moved inside the window, the box should always be shown totally (not clipped!), right? But my problem is, sometime, when users move the box inside the window, he would see some parts of this box are clipped (for example, one vertex of this box is clipped away). There is no limit how much users can move this box.

My understanding is:===> when users move the box, this box is out of frustum, that's why it's clipped. In this case, my code should adjust the frustum on-the-fly (then, projection mattrix is changed) or adjust camera on-the-fly (maybe, adjust the near-far plane as well) or do something else?

My question is:===> what's the popular technique to avoid this kind of clipping? And make sure users feel they are moving box smoothly, not having any "jerk" (like, suddenly, the box's location is jumped to another location (because our frustum is suddenly changed largely) when users are moving the box ). I think this is a very classic problem, there should be a perfect solution. Any code/references are appreciated!

I attached a picture to show the problem:

enter image description here

3
I don't understand your question. You use some sort of self-made frustum culling to determine what objects shall not be drawn? If so, why you just don't do it after you rotate/translate them?HolyBlackCat
You need to post some code about how you're making the projection matrix. If you understand what the dimension possibilities are it should be no problem defining your projection matrix in terms of near/far or the camera aperture. It's the projection matrix (not the view matrix) you may want to redefine on the fly.jwlaughton
If it helps you, I've posted some Objective C code illustrating how the View and Projection matrices are calculated. These calculations are done on the fly in a method I call resizeGL. You'll see that the clipping is done in the projection matrix.jwlaughton
Hi jwlaughton, thanks! I am a little confused by your code. Which part of your code is re-calculating the projection matrix to avoid the clipping? thanks!Jay

3 Answers

1
votes

This was happening to me , and adjusting the perspective matrix did not allow a near plane below .5 without all my objects disappearing.

Then I read this somewhere: DEPTH CLAMPING. - The clipping behavior against the Z position of a vertex ( ie: -w_c \ le z_c \ le w_c ) can be turned off by activating depth clamping.

glEnable( GL_DEPTH_CLAMP ) ;

And I could get close to my objects without them being clipped away.

I do not know if doing this will cause other problems , but as of yet I have not encountered any.

0
votes

I would suspect that your frustum is too narrow. So, when you rotate your object parts of it are moving outside of the viewable area. As an experiment, try increasing your frustum angle, increasing your Far value to something like 1000 or even 10000 and move your camera further back from centre (higher negative value on the z-plane). This should generate a very large frustum that your object should fit within. Run your project and rotate - if the clipping effect is gone you know your problem is either with the frustum or the model scale (or both).

-2
votes

This code gets called before every redraw. I don't know how you're rotating/translating (timer or mouseDown), but in any case the methods described below can be done smoothly and appear natural to the user.

If your object is being clipped by the near plane, move the near cutoff plane back toward the camera (in this code, increase VIEWPLANEOFFSET). If the camera is too close to allow you to move the near plane far enough back, you may also need to move the camera back.

If your object is being clipped by the left, right, top or bottom clipping planes, adjust the camera aperture.

This is discussed in more detail below.

// ******************************* Distance of The Camera from the Origin

cameraRadius = sqrtf((camera.viewPos.x * camera.viewPos.x) + (camera.viewPos.y * camera.viewPos.y) + (camera.viewPos.z * camera.viewPos.z));

GLfloat phi = atanf(camera.viewPos.x/cameraRadius);
GLfloat theta = atanf(camera.viewPos.y/cameraRadius);

camera.viewUp.x = cosf(theta) * sinf(phi);
camera.viewUp.y = cosf(theta);
camera.viewUp.z = sinf(theta) * sinf(phi);

You'll see with the View matrix we're only defining the camera (eye) position and view direction. There's no clipping going on here yet, but the camera position will limit what we can see in that if it's too close to the object, we'll be limited in how we can set the near cutoff plane. I can't think of any reason not to set the camera back fairly far.

// ********************************************** Make the View Matrix

viewMatrix =  GLKMatrix4MakeLookAt(camera.viewPos.x, camera.viewPos.y, camera.viewPos.z, camera.viewPos.x + camera.viewDir.x, camera.viewPos.y + camera.viewDir.y, camera.viewPos.z + camera.viewDir.z, camera.viewUp.x, camera.viewUp.y, camera.viewUp.z);

The Projection matrix is where the clipping frustum is defined. Again, if the camera is too close, we won't be able to set the near cutoff plane to avoid clipping the object if it's bigger than our camera distance from the origin. While I can't see any reason not to set the camera back fairly far, there are reasons (accuracy of depth culling) not to set the near/far clipping planes any further apart than you need.

In this code the camera aperture is used directly, but if you're using something like glFrustum to create the Projection matrix, it's a good idea to calculate the left and right clipping planes from the camera aperture. This way you can create a zoom effect by varying the camera aperture (maybe in a mouseDown method) so the user can zoom in or out as he likes. Increasing the aperture effectively zooms out. Decreasing the aperture effectively zooms in.

// ********************************************** Make Projection Matrix

GLfloat aspectRatio;
GLfloat cameraNear, cameraFar;

// The Camera Near and Far Cutoff Planes

cameraNear = cameraRadius - VIEWPLANEOFFSET;
if (cameraNear < 0.00001)
    cameraNear = 0.00001;

cameraFar = cameraRadius + VIEWPLANEOFFSET;
if (cameraFar < 1.0)
    cameraFar = 1.0;

// Get The Current Frame

NSRect viewRect = [self frame];

camera.viewWidth = viewRect.size.width;
camera.viewHeight = viewRect.size.height;

// Calculate the Ratio of The View Width / View Height

aspectRatio = viewRect.size.width / viewRect.size.height;

float fieldOfView = GLKMathDegreesToRadians(camera.aperture);
projectionMatrix = GLKMatrix4MakePerspective(fieldOfView, aspectRatio, cameraNear, cameraFar);

EDIT:

Here is some code illustrating how to calculate left and right clipping planes from the camera aperture:

GLfloat ratio, apertureHalfAngle, width;
GLfloat cameraLeft, cameraRight, cameraTop, cameraBottom, cameraNear, cameraFar;
GLfloat shapeSize = 3.0;
GLfloat cameraRadius;

// Distance of The Camera from the Origin

cameraRadius = sqrtf((camera.viewPos.x * camera.viewPos.x) + (camera.viewPos.y * camera.viewPos.y) + (camera.viewPos.z * camera.viewPos.z));

// The Camera Near and Far Cutoff Planes

cameraNear = cameraRadius - (shapeSize * 0.5);
if (cameraNear < 0.00001)
    cameraNear = 0.00001;

cameraFar = cameraRadius + (shapeSize * 0.5);
if (cameraFar < 1.0)
    cameraFar = 1.0;

// Calculte the camera Aperture Half Angle (radians) from the Camera Aperture (degrees)

apertureHalfAngle = (camera.aperture / 2) * PI / 180.0; // half aperture degrees to radians

// Calculate the Width from 0 of the Left and Right Camera Cutoffs
// We Use Camera Radius Rather Than Camera Near For Our Own Reasons

width = cameraRadius * tanf(apertureHalfAngle);

NSRect viewRect = [self bounds];

camera.viewWidth = viewRect.size.width;
camera.viewHeight = viewRect.size.height;

// Calculate the Ratio of The View Width / View Height

ratio = camera.viewWidth / camera.viewHeight;

// Calculate the Camera Left, Right, Top and Bottom

if (ratio >= 1.0)
{
    cameraLeft  = -ratio * width;
    cameraRight = ratio * width;
    cameraTop = width;
    cameraBottom = -width;
} else {
    cameraLeft  = -width;
    cameraRight = width;
    cameraTop = width / ratio;
    cameraBottom = -width / ratio;
}