2011-12-16 107 views
3

我正在创建一个基于软件的3D渲染器来学习概念和数学。这很有趣,我有一个很好的旋转立方体在一个网格顶部作为一种地板。网格/楼层使用线段进行渲染。我有一个使用简单的查看转换定位和定位的虚拟相机。观察平面任意设置在与“眼睛”相距n的位置,或者在z = -n处。我应该如何处理剪切到观看平面的3D点的投影?

除了一件事以外,一切正常(从对象到世界到相机空间,剔除,项目,剪辑,渲染)。渲染网格时,线段端点可能会跨越虚拟相机的查看平面。我想渲染可见的部分,以便剪切到查看平面。剪辑的端点投影到查看平面。投影如下:

p'(x) = -n * p(x)/p(z) 
p'(y) = -n * p(y)/p(z) 

所有可能显示的点将有p(z) ≤ -n。被剪切到观看平面的点有p(z) = -n。因此,我有效:

p'(x) = p(x) 
p'(y) = p(y) 

对于这样一个点;一个正交投影。

这里的值可以很容易地位于查看平面上的窗口之外,这会导致视口转换将这些点发送出OS窗口的界限。其效果是我看到杂乱的线条周期性地飞来飞去。这太糟糕了。

简直就像说OpenGL那样做(我只是使用OpenGL!),我错过了什么?

谢谢(如果你做到了这一点!)。

下面是显示异常的截图。网格的右上角不在视野内。朝向网格左侧角落的线段位于相机后面,因此被裁剪。终点经历了(错误的)正投影,并在左场结束。

我没有做任何视锥体剔除(还)。也许我应该?

enter image description here

+0

我遵循你的逻辑,但对我来说,你似乎不应该有一个直线正投影这些点! – 2011-12-16 06:32:06

+0

这个问题混合了一些问题1)你混合了在窗口之外和观点之后的话题。 2)你提到了正射投影,但这看起来是一个与透视投影有关的问题。 – ideasman42 2016-12-28 04:41:38

回答

0

您应该能够摆脱这些点,你的屏幕空间以外的项目,而不需要看你的视锥体积。所以在你做截锥体筛选之前,你的屏幕空间裁剪算法是什么样的?看看这些算法:http://en.wikipedia.org/wiki/Line_clipping,看看你是否可以受益。

无论哪种方式,我认为你应该考虑让你的渲染器能够处理操作系统窗口之外的点。使用上述剪切算法,您可以剔除完全落在窗口外的线段,并且将只有一个点位于外部的线段或两个点位于外部的线段截断,但该线段将穿过屏幕空间。

0

刚刚看过这个相同的话题,我发现没有任何东西需要聪明才能执行此操作。

首先,它可能定义一个近平面和远平面,然后用这些平面剪切片段(see example)。

虽然这工作正常,但我想避免在投影之上进行额外的计算。 对于熟悉投影矩阵的人来说,这可能是显而易见的,我不得不仔细检查以确认它能正常工作。

事实证明,您可以使用简单的逻辑执行近/远线剪辑。

  1. 将该位置乘以透视矩阵以获得4D向量。
  2. 比较第4个分量与近/远的剪辑距离。
  3. 如果需要的话,剪切段。

这可以通过在计算完整投影之前计算矢量的第四个分量来优化。

这也意味着您不需要在裁剪之后再次重新计算XYZ组件。

例如:这将4D向量乘以4x4矩阵。

pub fn mul_m4v4(m: &[[f64; 4]; 4], v: &[f64; 4]) -> [f64; 4] { 
    [ 
     v[0] * m[0][0] + v[1] * m[1][0] + v[2] * m[2][0] + m[3][0] * v[3], 
     v[0] * m[0][1] + v[1] * m[1][1] + v[2] * m[2][1] + m[3][1] * v[3], 
     v[0] * m[0][2] + v[1] * m[1][2] + v[2] * m[2][2] + m[3][2] * v[3], 
     v[0] * m[0][3] + v[1] * m[1][3] + v[2] * m[2][3] + m[3][3] * v[3], 
    ] 
} 

由于这是一个三维位置,我们可以假设第四个分量是1.0。

pub fn mul_m4v3_as_v4(m: &[[f64; 4]; 4], v: &[f64; 3]) -> [f64; 4] { 
    [ 
     v[0] * m[0][0] + v[1] * m[1][0] + v[2] * m[2][0] + m[3][0], 
     v[0] * m[0][1] + v[1] * m[1][1] + v[2] * m[2][1] + m[3][1], 
     v[0] * m[0][2] + v[1] * m[1][2] + v[2] * m[2][2] + m[3][2], 
     v[0] * m[0][3] + v[1] * m[1][3] + v[2] * m[2][3] + m[3][3], 
    ] 
} 

为了避免完整的计算,分出一个单独的函数来获得第四个组件。

pub fn mul_project_m4_v3_zfac(m: &[[f64; 4]; 4], v: &[f64; 3]) -> [f64; 4] { 
    v[0] * m[0][3] + v[1] * m[1][3] + v[2] * m[2][3] + m[3][3] 
} 

这里是一个commit,它实现了如上所述的限幅。

注意:矩阵是列主要的(像OpenGL)。