1

看起来解决方案是即时更改投影矩阵?让我做一些研究,看看如何正确地做到这一点。

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

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

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

我附上了一张图片来显示问题:

在此处输入图像描述

4

3 回答 3

1

这发生在我身上,调整透视矩阵不允许低于 0.5 的近平面而我的所有对象都消失了。

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

glEnable(GL_DEPTH_CLAMP);

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

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

于 2020-02-10T05:21:40.527 回答
0

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

于 2015-01-22T19:43:49.397 回答
-2

每次重绘之前都会调用此代码。我不知道您是如何旋转/平移的(计时器或 mouseDown),但无论如何,下面描述的方法都可以顺利完成,并且对用户来说看起来很自然。

如果您的对象被近平面剪裁,请将近截止平面移回相机(在此代码中,增加 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);

你会看到我们只定义了相机(眼睛)位置和视图方向的视图矩阵。这里还没有剪裁,但是相机位置会限制我们能看到的东西,如果它离物体太近,我们将受限于如何设置近截止平面。我想不出任何理由不将相机向后设置得相当远。

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

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

在此代码中,直接使用相机光圈,但如果您使用 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;
}
于 2015-01-22T18:52:48.057 回答