opengl:避免在透视模式下剪辑?

时间:2015-01-22 17:19:47

标签: opengl projection perspective clipping culling

很抱歉我之前没有明确解释过我的问题,我改变如下。看起来解决方案是即时更改投影矩阵?让我做一些研究,看看如何正确地做到这一点。

我的情况是:===> 说,现在,我在windows7下的窗口中创建了一个3D框,并启用了透视模式。从用户的角度来看,当用户移动(旋转/翻译)此框时,当框不在窗口时,应该剪切/(部分隐藏),这是正确的。但是当盒子在窗口内移动时,盒子应该总是完全显示(没有剪裁!),对吗?但我的问题是,有时,当用户在窗口内移动框时,他会看到此框的某些部分被剪裁(例如,此框的一个顶点被剪掉)。没有限制用户可以移动此框。

我的理解是:===> 当用户移动盒子时,这个盒子没有截止,这就是为什么它被剪裁了。 在这种情况下,我的代码应该在运行中调整平截头体(然后,投影矩阵被更改)或动态调整相机(也许,调整近远平面)或做其他事情?

我的问题是:===> 什么是避免这种剪辑的流行技术?并确保用户感觉他们正在顺利移动盒子,没有任何“混蛋”(就像突然,当用户移动盒子时,盒子的位置被跳到另一个位置(因为我们的平截头体突然变大)。 我认为这是一个非常经典的问题,应该有一个完美的解决方案。任何代码/参考都表示赞赏!

我附上了一张图片来展示问题。enter image description here

谢谢!

3 个答案:

答案 0 :(得分:0)

我怀疑你的视锥体太窄了。因此,当您旋转对象时,它的一部分移动到可视区域之外。作为实验,尝试增加您的平截头体角度,将您的远值增加到1000或甚至10000,然后将相机从中心向后移动(z平面上的负值更高)。这应该会产生一个非常大的平截头体,您的对象应该适合它。运行你的项目并旋转 - 如果裁剪效果消失,你知道你的问题是截头锥体或模型比例(或两者)。

答案 1 :(得分:0)

这在我身上发生,并且调整透视矩阵不允许在.5以下的近平面没有我所有的对象消失。

然后我在某处读到: 深度钳制。 -对顶点Z位置的裁剪行为 (即:-w_c \ le z_c \ le w_c)可以通过激活深度夹紧来关闭。

glEnable(GL_DEPTH_CLAMP);

我可以靠近我的物体而不会被剪掉。

我不知道这样做是否会导致其他问题,但是到目前为止,我还没有遇到任何问题。

答案 2 :(得分:-3)

在每次重绘之前调用此代码。我不知道你是如何旋转/翻译的(计时器或鼠标),但无论如何,下面描述的方法可以顺利完成并且对用户来说是自然的。

如果您的物体被近处平面剪裁,请将近切割平面移回相机(在此代码中,增加VIEWPLANEOFFSET)。如果相机距离太近而无法让近处飞机向后移动足够远,则可能还需要将相机移回。

如果您的物体被左,右,顶部或底部剪裁平面剪裁,请调整相机光圈。

这将在下面详细讨论。

// ******************************* 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);

您将看到View矩阵,我们只定义相机(眼睛)位置和视图方向。这里还没有剪辑,但相机位置将限制我们可以看到的内容,如果它太靠近物体,我们将限制我们如何设置附近截止飞机。我无法想到任何不将相机放回相当远的原因。

// ********************************************** 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);

Projection矩阵是定义裁剪平截头体的位置。同样,如果相机距离太近,我们将无法设置近截止平面,以避免在物体距离原点的距离大于物体时剪切物体。虽然我看不出任何理由不将相机设置得相当远,但有理由(深度剔除的准确性)不要将近/远剪裁平面设置得比你需要的更远。

在此代码中,直接使用相机光圈,但如果您使用glFrustum之类的东西来创建投影矩阵,则从相机光圈计算左右剪裁平面是个不错的主意。这样,您可以通过改变相机光圈(可能是mouseDown方法)来创建缩放效果,这样用户就可以根据自己的喜好放大或缩小。增大光圈有效地缩小。有效地减小光圈放大。

// ********************************************** 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);

编辑:

以下是一些说明如何从相机光圈计算左右剪裁平面的代码:

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;
}