我正在使用 3d 引擎,需要使用透视投影在 3d 世界空间和 2d 屏幕空间之间进行转换,因此我可以将 2d 文本标签放置在 3d 空间中的项目上。 我看过一些关于这个问题的各种答案的帖子,但他们似乎使用了我没有的组件。
我有一个Camera对象,只能设置它的当前位置和观察位置,它不能滚动。相机沿着路径移动,某些目标物体可能会出现在其视野中然后消失。 我只有以下值
任何人都可以给我一个仅使用这些组件即可完成此操作的算法吗?
非常感谢。
所有图形引擎都使用矩阵在不同坐标系统之间进行转换。事实上 OpenGL 和 DirectX 使用它们,因为它们是标准方式。
相机通常使用您拥有的参数构建矩阵:
视图矩阵(将世界变换为从相机位置观察的方式的位置),它使用观察位置和相机位置(也是向上向量,通常为 0,1,0)
投影矩阵(从3D坐标转换为2D坐标),它使用fov、near、far和aspect。
您可以在互联网上搜索创建矩阵的 opengl 函数,找到如何构造矩阵的信息:
gluLookat 创建一个视图矩阵
gluPerspective:创建投影矩阵
但是我无法想象一个引擎不允许你获取这些矩阵,因为我可以向你保证它们在某个地方,引擎正在使用它。
一旦获得这些矩阵,将它们相乘即可得到视图投影矩阵。该矩阵从世界坐标变换到屏幕坐标。因此,只需将矩阵与您想知道的位置相乘(以向量 4 格式,即 4° 分量 1.0)。
但是等等,结果将是齐次坐标,你需要将结果向量的 X,Y,Z 除以 W,然后你就得到了归一化屏幕坐标中的位置(0 表示中心,1 表示右侧,-1意味着向左,等等)。
从这里可以很容易地转换乘以宽度和高度。
我有一些幻灯片解释了这一切:https://docs.google.com/presentation/d/13crrSCPonJcxAjGaS5HJOat3MpE0lmEtqxeVr4tVLDs/present?slide=id.i0
祝你好运:)
P.S:当你使用 3D 时,理解三个矩阵(模型、视图和投影)非常重要,否则你每次都会绊倒。
这样我就可以在项目上放置二维文本标签 在 3D 空间
你查过“广告牌”技巧吗?有时,您只需要知道要搜索的正确术语即可。这是指始终面向相机的多边形(通常是矩形),无论相机位置或方向如何。
假设您知道相机在世界空间中的方向,并使用 unit 向量表示相机框架向前/向右/向上方向,您可以:
您需要知道近平面的世界大小:
#define DEGTORAD 0.01745329252
float aspectRatio = w / (float)h; // window/viewport dimensions
float nearPlaneHeight = 2 * tan(fovY * 0.5f * DEGTORAD) * nearPlaneDist;
float nearPlaneWidth = nearPlaneHeight * aspectRatio;
如果给定的世界点位于近平面前面,则此函数返回 true:
bool getScreenPos(vec3 worldPos, vec2& screenPos) {
vec3 nearPlaneCenter = camera.location + nearPlaneDist * camera.forward;
float dot1 = dot(camera.forward, camera.location);
float dot2 = dot(camera.forward, nearPlaneCenter);
float dot3 = dot(camera.forward, worldPos);
if ( (dot3 < dot2 && dot1 < dot2) || (dot3 > dot2 && dot1 > dot2)) {
return false; // camera and target are on same side of near plane
}
// distance from camera to near plane, as a fraction of distance from camera to target
float fraction = (dot2 - dot1) / (dot3 - dot1);
vec3 cameraToTarget = worldPos - camera.location;
vec3 pointOnNearPlane = camera.location + fractionToNearPlane * cameraToTarget;
// this is a line on the near plane, from its center to where the ray intersects
vec3 projOnNearPlane = pointOnNearPlane - nearPlaneCenter;
// these are the component-wise magnitudes of that line in the camera frame
float rightDot = dot(projOnNearPlane, camera.right);
float upDot = dot(projOnNearPlane, camera.up);
screenPos.x = w/2 + w * rightDot / nearPlaneWidth;
screenPos.y = h/2 - h * upDot / nearPlaneHeight;
return true;
}