3D三角形随相机旋转异常问题求助
问题
我正在开发一款程序,可输入右手坐标系下的三个坐标生成三角形,并实现相机绕三角形旋转。我理解的实现步骤如下:
- 创建透视投影矩阵:
std::array<std::array<float, 4>, 4> CreateProjectionMatrix(float fov, float aspectRatio, float nearPlane, float farPlane) { float f = 1.0f / std::tan((fov * 3.141 / 180) / 2.0f); std::array<std::array<float, 4>, 4> projectionMatrix = { f / aspectRatio, 0.0f, 0.0f, 0.0f, 0.0f, f, 0.0f, 0.0f, 0.0f, 0.0f, (farPlane + nearPlane) / (nearPlane - farPlane), (2.0f * farPlane * nearPlane) / (nearPlane - farPlane), 0.0f, 0.0f, -1.0f, 0.0f }; return projectionMatrix; }
- 创建视图/相机矩阵:
std::array<std::array<float, 4>, 4> createViewMatrix( Vec4<float> cameraPosition, float pitch, float yaw, float roll) { pitch = toRadians(pitch); yaw = toRadians(yaw); roll = toRadians(roll); float cosPitch = cos(pitch); float sinPitch = sin(pitch); float cosYaw = cos(yaw); float sinYaw = sin(yaw); Vec4<float> xaxis( cosYaw, 0, -sinYaw ); Vec4<float> yaxis(sinYaw * sinPitch, cosPitch, cosYaw * sinPitch); Vec4<float> zaxis(sinYaw * cosPitch, -sinPitch, cosPitch * cosYaw); std::array<std::array<float, 4>, 4> viewMatrix = { xaxis.x(), yaxis.x(), zaxis.x(), 0, xaxis.y(), yaxis.y(), zaxis.y(), 0, xaxis.z(), yaxis.z(), zaxis.z(), 0, -dot(xaxis, cameraPosition), -dot(yaxis, cameraPosition), -dot(zaxis, cameraPosition), 1 }; return viewMatrix; }
- 创建模型矩阵:我认为无需使用,因所有点接近坐标中心,但可能有误。
- 按正确顺序相乘矩阵:
PointsB = Point * (projectionMatrix * viewMatrix)
当前代码如下:
// 输入参数 float CAMERA_X = 0; float CAMERA_Y = 0; float CAMERA_Z = 0.5; float FOV = 90; const float ASPECT_RATIO = 16.0f / 9.0f; const float NEAR_PLANE = 0.1f; const float FAR_PLANE = 1000.0f; float CAMERA_Y_ANGLE = 45.f; // 三角形顶点 Vec4 p1(-100, 0, 0); // 投影后输出:360 259 Vec4 p2(100, 0, -100); // 投影后输出:398 305 Vec4 p3(100, 0, 100); // 投影后输出:394 301 Vec2D<float> Project(Vec4<float> point) { auto projectionMatrix = CreateProjectionMatrix(FOV, ASPECT_RATIO, NEAR_PLANE, FAR_PLANE); auto viewMatrix = createViewMatrix(Vec4<float>(0, 0, 0), 0, CAMERA_Y_ANGLE, 0); auto ViewProj = MultiplyMatrices(projectionMatrix, viewMatrix); Vec4<float> projectedPoint( point.x() * ViewProj[0][0] + point.y() * ViewProj[1][0] + point.z() * ViewProj[2][0] + ViewProj[3][0], point.x() * ViewProj[0][1] + point.y() * ViewProj[1][1] + point.z() * ViewProj[2][1] + ViewProj[3][1], point.x() * ViewProj[0][2] + point.y() * ViewProj[1][2] + point.z() * ViewProj[2][2] + ViewProj[3][2], point.x() * ViewProj[0][3] + point.y() * ViewProj[1][3] + point.z() * ViewProj[2][3] + ViewProj[3][3] ); if (projectedPoint.w() != 0.0f) { projectedPoint.set_x(projectedPoint.x() / projectedPoint.w()); projectedPoint.set_y(projectedPoint.y() / projectedPoint.w()); projectedPoint.set_z(projectedPoint.z() / projectedPoint.w()); } // 窗口尺寸为800*600,因为投影点为负数,这里是临时解决方案 return VectorHelpers<float>(projectedPoint.x() + 400, projectedPoint.z() + 300); }
目前效果仅为三角形在窗口中心自转,而非相机绕物体移动。我猜测是点的相对关系错误或坐标系混淆,寻求帮助及代码示例。
补充:当前三角形沿Y轴自转,我需要实现相机绕三角形移动,比如相机Y轴旋转180度时,因朝向背离三角形而不可见。
解决方案
主要问题出在投影和视图矩阵,以下是修正后的代码(改为左手坐标系),虽无裁剪逻辑导致近距离物体显示异常,但功能正常:
std::array<std::array<float, 4>, 4> createViewMatrix( Vec4<float> cameraPosition, Vec4<float> cameraTarget, Vec4<float> cameraUpVector) { Vec4<float> A = Normalize(cameraPosition - cameraTarget); Vec4<float> B = Normalize(Cross(cameraUpVector, A)); Vec4<float> C = Cross(A, B); std::array<std::array<float, 4>, 4> viewMatrix = { B.x(), C.x(), A.x(), 0, B.y(), C.y(), A.y(), 0, B.z(), C.z(), A.z(), 0, -dot(B, cameraPosition), -dot(C, cameraPosition), -dot(A, cameraPosition), 1 }; return viewMatrix; } std::array<std::array<float, 4>, 4> CreateProjectionMatrix(float fov, float aspectRatio, float nearPlane, float farPlane) { float f = 1.0f / std::tan((fov * 3.141 / 180) / 2.0f); std::array<std::array<float, 4>, 4> projectionMatrix = { f / aspectRatio, 0.0f, 0.0f, 0.0f, 0.0f, f, 0.0f, 0.0f, 0.0f, 0.0f, farPlane / (nearPlane - farPlane), -1, 0.0f, 0.0f, (nearPlane * farPlane) / (nearPlane - farPlane), 0.0f }; return projectionMatrix; } Vec2D<float> Project(Vec4<float> point) { std::array<std::array<float, 4>, 4> ObjectMatrix = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 }; auto projectionMatrix = CreateProjectionMatrix(FOV, ASPECT_RATIO, NEAR_PLANE, FAR_PLANE); auto viewMatrix = createViewMatrix(CameraPosition, CameraTarget, CameraUpVector); auto ViewProj = ObjectMatrix * viewMatrix * projectionMatrix; Vec4<float> projectedPoint( point.x() * ViewProj[0][0] + point.y() * ViewProj[1][0] + point.z() * ViewProj[2][0] + ViewProj[3][0], point.x() * ViewProj[0][1] + point.y() * ViewProj[1][1] + point.z() * ViewProj[2][1] + ViewProj[3][1], point.x() * ViewProj[0][2] + point.y() * ViewProj[1][2] + point.z() * ViewProj[2][2] + ViewProj[3][2], point.x() * ViewProj[0][3] + point.y() * ViewProj[1][3] + point.z() * ViewProj[2][3] + ViewProj[3][3] ); projectedPoint.set_x(projectedPoint.x() / projectedPoint.z()); projectedPoint.set_y(projectedPoint.y() / projectedPoint.z()); if (projectedPoint.z() < 0.01) { // 不绘制该点 return Vec2D<float>(0, 0); } auto x = projectedPoint.x() * 600.f + 600.f / 2.0f; auto y = -projectedPoint.y() * 600.f + 600.f / 2.0f; // 窗口尺寸为600*600 return Vec2D<float>(x, y); }
内容的提问来源于stack exchange,提问作者Thomas2806
相关产品推荐
相关产品推荐

