1

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

Community
  • 1
  • 1
Jay
  • 21
  • 1
  • 2
  • 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 Jan 22 '15 at 17:29
  • 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 Jan 22 '15 at 18:40
  • 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 Jan 22 '15 at 18:57
  • 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 Jan 27 '15 at 19:55

3 Answers3

1

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.

Tyranna
  • 11
  • 3
  • "I do not know if doing this will cause other problems , but as of yet I have not encountered any." If you rely on the depth test, it will create lots of problems. You should rather focus on fixing the "nd adjusting the perspective matrix did not allow a near plane below .5 " bug, becaue that is not how the math works. – derhass Feb 11 '20 at 14:15
0

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).

eric_the_animal
  • 432
  • 9
  • 19
-2

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;
}
jwlaughton
  • 905
  • 1
  • 6
  • 11
  • This doesn’t really answer the question. – Noah Witherspoon Jan 22 '15 at 19:14
  • @NoahWitherspoon Maybe that's because the question was unclear. Thanks for the help you gave. – jwlaughton Jan 22 '15 at 19:20
  • The question’s kind of unclear, but it is clearly asking about clipping in the view frustum, which your code doesn’t go into any detail about. Some explanation of the ideas there would have made this a worthwhile answer. – Noah Witherspoon Jan 22 '15 at 19:25
  • @NoahWitherspoon I'll be more conservative about my suggestions from now on. – jwlaughton Jan 22 '15 at 19:35
  • @NoahWitherspoon You know what Noah? I've only had an account at Stackoverflow for a brief time, and during that time I think I've helped several people in their development as programmers. That was my way of giving back to the community that has helped me over time. Your "police" of this response has made me reconsider my involvement and I'm "outta here". – jwlaughton Jan 22 '15 at 19:48
  • @NoahWitherspoon I see from a search: How did Joel allow his brilliant site to be taken over by the Q&A police? – jwlaughton Jan 22 '15 at 20:05
  • @NoahWitherspoon Did you look at my post with my previous comments in mind? or did you just "knee jerk" your response? – jwlaughton Jan 22 '15 at 20:36
  • I did, but it would have been more helpful with an explanation of what might cause the kind of problems the question mentioned and how to use the code you provided to avoid those problems. Code by itself in isolation is hard to do anything useful with when the question is this vague. – Noah Witherspoon Jan 22 '15 at 20:40
  • @NoahWitherspoon Whatever... I'm gone. – jwlaughton Jan 22 '15 at 20:43