guodong's blog

master@zhejiang university
   

渲染三角形(Rendering a Triangle)

参考链接 https://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/geometry-of-a-triangle

1、Geometry of a Triangle

首先你得知道三角形法线怎么计算。

然后,按照惯例,左手坐标系中的z轴指向屏幕方向(当x轴指向右侧时)

如图1,A叉乘B和B叉乘A不一样,模相同,但是方向相反。

再如上图,ccw和cw分别指counter-clockwise order和clockwise order。三颜色线表示三轴,ccw,cw表示叉乘的方向,可见得到的结果是反向的。

 

如上图,三颜色为三坐标轴,相机方向沿着z周的负方向,相机可以认为是人眼,人眼射出来的光线(做个比喻,实际上人眼是接受光线)沿着z轴负方向。在左右手坐标系中render不同。

 

为了使render结果相同,需要做一个关于XoY平面的对称变换,这样使得相机的方向仍然和法线的方向相反。

Ray-Triangle Intersection: Geometric Solution

第一步,找到光线和三角形的交点p。

 

光源0,光的方向R,则光的参数等式可以表达为 P = O + tR. 其中t是光源到点p的距离。因此为了找到P,我们需要知道t。平面的法向量,可以通过这个公式来计算:Ax+By+Cz+D=0. 其中,(A,B,C)就是平面的法向量,D是原点到平面的距离,x,y,z是平面上任意一点。于是我们可以计算出t

    \[ \begin{array}{l} P = O + tR\\ Ax + By + Cz + D = 0\\ A * P_x + B * P_y + C * P_z + D = 0\\ A * (O_x + tR_x) + B * (O_y + tR_y) + C * (O_z + tR_z) + D = 0\\ A * O_x + B * O_y + C * O_z + A * tR_x + B * tR_y + C * tR_z + D = 0\\ t * (A * R_x + B * R_y + C * R_z) + A * O_x + B * O_y + C * O_z + D = 0\\ t = -{\dfrac{A * O_x + B * O_y + C * O_z + D}{A * R_x + B * R_y + C * R_z}}\\ t = -{\dfrac{ N(A,B,C) \cdot O + D}{N(A,B,C) \cdot R}} \end{array} \]

当然有两种特殊情况,第一种是当光线和平面平行时,此时没交集。第二种是,当光源在三角形的背后时,此时公式仍然可以计算出t的,但是t时小于0的,此时这种情况也应该忽略。

第二步,p是否在三角形内

我们已经找到了光线和平面的交点P。仍需要判断是否在三角形内。

如上图所示,光线可能和三角形有交点也可能没有,这个判断方法也很简单,称作为inside-outside test。(栅格化时也能用到)。

如图所示,假设向量A已经和x轴对齐,A向量是三角形的一条边,由顶点v0v1确定。第二条边B,由V0V2确定,则,两个向量的叉积表示Z周,也就是三角形的法向量。

    \[ \begin{array}{l} A=(1, 0, 0)\\ B=(1, 1, 0)\\ C_x = A_y B_z - A_z B_y = 0\\ C_y = A_z B_x - A_x B_z = 0\\ C_z = A_x B_y - A_y B_x = 1 * 1 - 0 * 1 = 1\\ C = (0, 0, 1) \end{array} \]

如果B的坐标不是(1,1,0)而是(1,-1,0),此时得到的C‘=(0,0,-1)此时N点成C为负. 这说明当叉积和两条边的叉积同号时,再同一个方向。看图

由此可见,当NC为正时,都是在自己的左侧。然后一圈下来,

 

当点都在人的左侧时,说明这个点就在内部。意思就是说当叉积全部为正(同向)时,这个点就在内部。(逆时针走遍)。另外还有射线法,拓扑法等多种方法来判断是不是在多边形内部,具体可参考 https://blog.csdn.net/gkingzheng/article/details/81836308 这篇文章。

接下来时讨论single-side or double-side, 用兴趣的可以参考原文,这里不讨论。

质心坐标

在CG中,质心坐标尤其重要。质心p(这里指光线和三角形的交点,它的uvw不知道,需要计算)可以通过下面的公式进行计算。P=uA+vB+wC. 其中ABC时三角形的三个顶点,uvw就是质心坐标,它们时标量,切满足u+v+w = 1, uvw都是正数。当uvw是负数或者大于1时,说明点在三角形外。

质心坐标又称为区域坐标( areal coordinates),尽管不是很常用,但也暗示了uvw与局部三角形有关系,看下图

三个子三角形cpa abp bcp,可以通过下面的公式计算质心坐标

    \[ \begin{array}{l} u = {\dfrac{TriangleCAP_{Area}}{TriangleABC_{Area}}}\\ v = {\dfrac{TriangleABP_{Area}}{TriangleABC_{Area}}}\\ w ={\dfrac{TriangleBCP_{Area}}{TriangleABC_{Area}}}\\ \end{array} \]

其中三角形的面积可以通过两个向量的叉积来计算,这样就很容易的计算出质心坐标。

Using Barycentric Coordinates

对于每个顶点,都会储存数据,这叫vertex data。现在我们假设你希望A点是红色,B点是绿色,C点是蓝色。

显然,当光线和三角形交点的是三角形顶点时,直接拿数据就行,最容易。但是当交点在三角形内部或者边上时就比较麻烦。此时可以使用质心作弊爱哦来插值像素数据,这对shading过程,比如交点处的normal非常有用。一个object的Normal可以定义为每个面或者每个顶点basis(也即是face normal 和 vertex normal)。如果被定义为每个顶点,我们可以使用这个插值技巧来模拟一个平滑的shading,当这个三角形在理论上恶认为时平坦的。(由于交点处的normal是由每个点的normal决定,所以要保证每个顶点的normal相同)对于纹理的插值,同样适合。

Optimizing The Computation Of Barycentric Coordinates

上述的计算过程也可以优化,具体表现为,判断点是否在内部时,已经计算过叉积,计算三角形面积时,因为是求面积的比例,所以这里叉积后可以不除以2.

    \[ \begin{array}{l} v  = {\dfrac{triangleABP_{area}}{triangleABC_{area}}}\\  = {\dfrac{||AB \times AP||}{||AB \times AC||}} \end{array} \]

    \[\begin{array}{l}v = {\dfrac{triangleABP_{area}} {triangleABC_{area}}} = {\dfrac{(AB \times AP) \cdot N}{(AB \times AC) \cdot N}} \end{array} \]

First remember that N=AB×ACN=AB×AC. Therefore we can rewrite the above above formula as:

    \[\begin{array}{l} v = {\dfrac{triangleABP_{area}}{triangleABC_{area}}} = {\dfrac{(AB \times AP) \cdot N}{N \cdot N}} \end{array} \]

Möller-Trumbore algorithm

这里一定要看看,由于公式复杂,就不转载了,详情直接点击原链接




上一篇:
下一篇:

头像

guodong

没有评论


你先离开吧:)



发表评论

电子邮件地址不会被公开。 必填项已用*标注