Ber*_*own 25 c# java math 3d projection
假设我有一个如下所示的数据结构:
Camera {
double x, y, z
/** ideally the camera angle is positioned to aim at the 0,0,0 point */
double angleX, angleY, angleZ;
}
SomePointIn3DSpace {
double x, y, z
}
ScreenData {
/** Convert from some point 3d space to 2d space, end up with x, y */
int x_screenPositionOfPt, y_screenPositionOfPt
double zFar = 100;
int width=640, height=480
}
Run Code Online (Sandbox Code Playgroud)
...
没有屏幕剪辑或其他任何东西,我如何在空间中给出一些3d点的情况下计算某个点的屏幕x,y位置.我想将这个3d点投影到2d屏幕上.
Camera.x = 0
Camera.y = 10;
Camera.z = -10;
/** ideally, I want the camera to point at the ground at 3d space 0,0,0 */
Camera.angleX = ???;
Camera.angleY = ????
Camera.angleZ = ????;
SomePointIn3DSpace.x = 5;
SomePointIn3DSpace.y = 5;
SomePointIn3DSpace.z = 5;
Run Code Online (Sandbox Code Playgroud)
ScreenData.x和y是空间中3d点的屏幕x位置.我该如何计算这些值?
我可以使用这里找到的方程式,但我不明白屏幕宽度/高度是如何发挥作用的.此外,我不知道在wiki条目中观众的位置与摄像机位置有什么关系.
Lia*_*m M 50
"完成的方式"是使用同质变换和坐标.你在空间中占据一席之地:
这变得非常模糊,但我会尝试覆盖重要的部分,并留下一些给你.我假设您了解矩阵数学的基础知识:).
同质向量,点,变换
在3D中,同质点将是[x,y,z,1]形式的列矩阵.最后一个组件是'w',一个缩放因子,对于向量是0:这会产生无法转换向量的影响,这在数学上是正确的.我们不会去那里,我们正在谈论要点.
均匀变换是4x4矩阵,因为它们允许将平移表示为矩阵乘法,而不是加法,这对于你的视频来说是很好的和快速的.也很方便,因为我们可以通过将它们相乘来表示连续变换.我们通过执行变换*点将变换应用于点.
有3个主要的同质转换:
还有其他一些,特别是"看待"转型,值得探讨.但是,我只是想简要列出一些链接.应用于点的移动,缩放和旋转的连续应用共同是模型变换矩阵,并且将它们相对于相机放置在场景中.重要的是要意识到我们正在做的事情类似于在相机周围移动物体,而不是相反.
正视和透视
要从世界坐标转换为屏幕坐标,首先要使用投影矩阵,它通常有两种形式:
正投影矩阵构造如下:
参数包括:
我觉得这很简单.你建立的是一个空间区域,它将出现在屏幕上,你可以剪辑它.这里很简单,因为可见空间区域是一个矩形.透视剪辑更复杂,因为屏幕上显示的区域或观看体积是一个截头.
如果你对维基百科的透视投影很难,这里是建立一个合适的矩阵的代码,由geeks3D提供
void BuildPerspProjMat(float *m, float fov, float aspect,
float znear, float zfar)
{
float xymax = znear * tan(fov * PI_OVER_360);
float ymin = -xymax;
float xmin = -xymax;
float width = xymax - xmin;
float height = xymax - ymin;
float depth = zfar - znear;
float q = -(zfar + znear) / depth;
float qn = -2 * (zfar * znear) / depth;
float w = 2 * znear / width;
w = w / aspect;
float h = 2 * znear / height;
m[0] = w;
m[1] = 0;
m[2] = 0;
m[3] = 0;
m[4] = 0;
m[5] = h;
m[6] = 0;
m[7] = 0;
m[8] = 0;
m[9] = 0;
m[10] = q;
m[11] = -1;
m[12] = 0;
m[13] = 0;
m[14] = qn;
m[15] = 0;
}
Run Code Online (Sandbox Code Playgroud)
变量是:
生成的矩阵是列专业,在上面的代码中索引如下:
0 4 8 12
1 5 9 13
2 6 10 14
3 7 11 15
Run Code Online (Sandbox Code Playgroud)
视口转换,屏幕坐标
这两种转换都需要另一个矩阵矩阵将事物放在屏幕坐标中,称为视口转换.这里描述的,我不会介绍它(这很简单).
因此,对于点p,我们将:
摘要
我希望它涵盖了大部分内容.上面有漏洞,地方含糊不清,发布下面的任何问题.这个主题通常值得在教科书的整个章节,我尽我所能提炼过程,希望对你有利!
我链接到上面这个,但我强烈建议你阅读这个,并下载二进制文件.它是一个很好的工具,可以帮助您进一步了解这些转换以及它如何在屏幕上获取点:
http://www.songho.ca/opengl/gl_transform.html
就实际工作而言,您需要为均匀变换实现4x4矩阵类以及可以与其相乘以应用变换的同类点类(记住,[x,y,z,1]).您需要生成如上所述和链接中的转换.一旦理解了这个程序,就不那么困难了.祝你好运:).
Dr.*_*ABT 10
@BerlinBrown就像一般性评论一样,你不应该将你的相机旋转存储为X,Y,Z角度,因为这会导致模糊.
例如,x = 60度与-300度相同.当使用x,y和z时,模糊可能性的数量非常高.
相反,尝试在3D空间中使用两个点,相机位置使用x1,y1,z1,相机"目标"使用x2,y2,z2.角度可以向/从位置/目标向后计算,但在我看来,不建议这样做.使用摄像机位置/目标可以构建一个"LookAt"向量,它是摄像机方向的单位向量(v').由此您还可以构建一个LookAt矩阵,它是一个4x4矩阵,用于将3D空间中的对象投影到2D空间中的像素.
请参阅此相关问题,我将讨论如何计算矢量R,该矢量R位于与摄像机正交的平面中.
给定摄像机的矢量目标,v = xi,yj,zk
归一化矢量,v'= xi,yj,zk/sqrt(xi ^ 2 + yj ^ 2 + zk ^ 2)
设U =全局世界向上矢量u = 0,0,1
然后我们可以计算R =水平向量,它平行于摄像机的视图方向R = v'^ U,
其中^是叉积,由
a ^ b =(a2b3 - a3b2)i +给出(a3b1-a1b3)j +(a1b2-a2b1)k这将为您提供一个看起来像这样的矢量.
这可能适用于您的问题,因为一旦您拥有LookAt Vector v',正交矢量R就可以开始从3D空间中的点投射到相机的平面上.
基本上所有这些3D操纵问题都归结为将世界空间中的一个点转换为局部空间,其中局部x,y,z轴与相机对齐.那有意义吗?因此,如果你有一个点,Q = x,y,z,你知道R和v'(摄像机轴),那么你可以使用简单的矢量操作将它投影到"屏幕".可以使用Vectors上的点积运算符找出所涉及的角度.
小智 5
在维基百科之后,首先计算"d":
http://upload.wikimedia.org/wikipedia/en/math/6/0/b/60b64ec331ba2493a2b93e8829e864b6.png
为此,请在代码中构建这些矩阵.从示例到变量的映射:
θ= Camera.angle*
a = SomePointIn3DSpace
c = Camera.x | y | z
或者,只需单独执行方程式而不使用矩阵,您的选择:
http://upload.wikimedia.org/wikipedia/en/math/1/c/8/1c89722619b756d05adb4ea38ee6f62b.png
现在我们计算"b",一个2D点:
http://upload.wikimedia.org/wikipedia/en/math/2/5/6/256a0e12b8e6cc7cd71fa9495c0c3668.png
在这种情况下,ex和ey是观众的位置,我相信在大多数图形系统中,屏幕尺寸的一半(0.5)用于默认设置(0,0)屏幕的中心,但你可以使用任何值(玩转).ez是视野发挥作用的地方.这是你缺少的一件事.选择一个fov角度并计算ez为:
ez = 1/tan(fov/2)
最后,要获得bx和实际像素,您必须按与屏幕尺寸相关的因子进行缩放.例如,如果b从(0,0)映射到(1,1),则可以将x缩放1920,并将y缩放1080以用于1920 x 1080显示.这样任何屏幕尺寸都会显示相同的内容.当然,实际的3D图形系统中还涉及许多其他因素,但这是基本版本.