每次重绘之前都会调用此代码。我不知道您是如何旋转/平移的(计时器或 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;
}