首页 > 代码库 > 高咯德着色
高咯德着色
引言
在前面,我们已经讲解了多个光照模型的方程,有了那些模型,读者就能够自己做出比较好看的Demo了,如果想要更加精确,高级,好看的效果,读者就需要自己去学习有关全局光照系统的方法。使用全局光照系统,需要掌握有关辐射着色的理论,这种理论难度很高,需要读者有足够的数学和物理理论知识,由于我自己在这方面也不是很了解,所以就不再讲述这种更加精确的光照模型了。如果将来,我学会了这样的知识,会在博客中与大家一起分享的。期待吧!!!
在前面,我们都是在顶点着色器中进行光照计算的,读者可能想知道,为什么我们只是计算出了顶点的颜色,最后,整个三角形都具有了颜色了???这样的功能是通过着色方法来实现的。所谓的着色方式,就是对某些量,在某一个参考维度上进行插值计算,然后得到最后的结果。在下面将会向大家一一展示我自己目前掌握的几种简单的着色方法。
着色方法
一般来说,在固定流水线中,一般支持如下的几种着色方式:
- 固定着色(Pure shading, Constant shading)
- 恒定着色(Flat shading)
- 高洛德着色(Gouraud Shading)
固定着色,指的是,通过人为的,而不是通过光照计算来得到模型中多边形的颜色,然后使用这个颜色,来填充整个三角形。这种方式,简单,高效,但是,效果却很不理想,基本上已经不使用了。
恒定着色,说的是通过光照计算,计算出每一个多边形的最终颜色,而不是通过人工指定,来给出每个多边形的颜色,这样的方法,使得物体整体看上去比较的逼真了。使用这样的着色方法,对那些棱角分明的物体,比如立方体,长方体,这样的物体进行着色,效果会很好,但是如果,要使用这样的方法对比较圆润的物体,比如球体进行着色,就会发现,效果很差。所以,恒定着色,一般也不用来使用,只有在某些性能要求上,才会使用恒定着色方法来对棱角分明的物体进行着色。
高洛德着色,是最常用的着色方法,也是我们前面几个Demo中使用的着色方法。下面,我们将详细的讲解高洛德着色方法。
高洛德着色
Gouraud Shading 是法国计算机科学家Henri Gouraud发明的。这种着色方法,能够产生出很平滑的3D图形效果,大部分的3D游戏都采用了这种着色方式来对物体进行着色。它的原理是通过光照计算,计算出三角形三个顶点的颜色值,然后使用插值方法,对三角形中所有的像素进行插值计算,最后得到整个三角形的颜色值。如果读者对这个文字描述,不是很清楚的话,那么看下下图:
上图中,左边的图是一个纯红的三角形,而右边的三角形,看上去五颜六色。可是,如果读者细心观看的话,就会发现,它的顶点颜色实际上分别是红色,绿色,和蓝色。那它是通过怎么样的方式,最后形成这个样子的了?
实际上,实现这样功能的方法很简单。只要通过简单的线性插值计算,就可以得到了。
我们先来假设A点颜色为Ac(255,0,0), Bc(0,255,0), Cc(0,0,255)。读者应该对这种RGB表示方法很熟悉,所以不再解释。
我们有了三角形三个顶点的颜色之后,我们自然也应该有这三个顶点的坐标关系,如A(xa,ya), B(xb,yb), C(xc,yc)。
好了,有了这些数据之后,我们就可以计算插值了。
首先,在进行插值计算之前,读者需要明白一件事,在计算机中,像素图都是使用一个一个的像素来构成图的。你看上去的直线,也是通过一个接着一个的点来绘制完成的。而在计算机中,由于视频缓存的内存,看上去就像是一个2D的矩阵,所以,在里面绘制横向的直线,或者纵向的直线是非常容易,也是十分精确的,而要绘制斜线,却不是那么容易的事情。只要读者自己在任何绘图软件中,将一条绘制的斜线放大到一定程度,读者就会发现,斜的直线,实际上并不是那么的“直”。
好了,说了这么多,意思就是,我们在计算机中,绘制横直线和纵直线要比绘制任意直线容易的多,也精确的多,而绘制横直线比绘制纵直线,更加的容易点,所以,在三角形填充算法中,一般都是使用横向的扫描线,进行绘制。也就是说,只要我们获得了这条横向扫描线的左右端点的位置和颜色值,绘制这条直线就变的容易的多。事实上也的确是这样的,但是有个问题,我们只是知道直线左右端点的位置和颜色而已,两个端点之间的颜色该怎么计算出来了?读者,如果你这么想,就明确了问题的关键部分了。我们解决这里的问题,就是通过插值计算而来。
假设我们有一条横向的直线,端点和颜色分别是S(xs,ys) , SC(sr,sg,sb), E(xe,ye) EC(er,eg,eb)
我们计算这两个端点之间的步长:
x_step = xe - xs ;
有了步长之后,我们就可以使用这两个端点的颜色值来对计算每一个颜色分量上的步进值:
r_step = (er - sr) / x_step ;
g_step = (eg - sg) / x_step ;
b_step = (eb - sb) / x_step ;
在有了每一个颜色分量的步进值之后,我们就可以按照,从s(起点)到e(终点),以每个像素为单位进行插值了,即:
r_new = sr + r_step * (x_new - xs) ;
g_new = sg + g_step * (x_new - xs) ;
b_new = sb + b_step * (x_new - xs) ;
这样,在这条直线上的x_new坐标处,像素颜色就为(r_new,g_new,b_new)了。如此反复执行,整条直线就使用端点的两种颜色插值计算出来了。
好了,我们掌握了对一条扫描线进行插值的方法之后,就可以来对三角形进行插值计算了。我们拥有三角形的三个顶点A,B,C和他们对应的颜色值Ac, Bc, Cc。
绘制三角形的算法有很多种,一般都是使用扫描线的方式,从上到下,绘制所有的扫描线。在我的博客中讲述了一种绘制三角形的方法,读者可以到这里来阅读了解。
知道了如何对三角形进行填充之后,我们需要确定的就是每一条扫描线左右两个端点的位置和颜色,然后使用直线插值算法来对颜色进行插值,最后就能够完整的绘制出整个插值的三角形了。
那么如果获取每一条扫描线的左右端点的颜色了?同样的,我们也是使用插值的方法来进行。
我们绘制扫描线,是按照从上到下的方式绘制扫描线的。所以,我们以两个端点的Y坐标为参考来计算颜色直线端点的步长值,即:
yleft_step = ya - yb ;
yright_step = ya - yc ;
在有了三角形左右两边的y轴步长之后,我们就可以来计算左右两边各个颜色分量的步进值了:
r_step_left = (ar - br) / yleft_step ;
g_step_left = (ag - bg) / yleft_step ;
b_step_left = (ab - bb) / yleft_step ;
r_step_right = (ar - cr) / yright_step ;
g_step_right = (ag - cg) / yright_step ;
b_step_right = (ab - cb) / yright_step ;
好了,有了左右两边的步进值之后,我们就可以计算每条扫面线的左右端点的颜色了,然后就可以用直线插值来进行绘制,最后整个三角形就被绘制出来了。
Gouraud着色,就是使用这样的方法来进行三角形的绘制,所以,我们在Shader中,计算了顶点的颜色之后,它就会被插值,然后到像素着色器中绘制正确的像素颜色,从而达到很平滑的效果。
上面描述的几种着色方式,在我自己编写的软件3D图形渲染流水线中都支持,读者可以从这里看到一些截图效果。
除了上面介绍的Gouraud着色之外,还有一种着色方法,它的效果比Gouraud着色效果更加的好,更加的逼真,这个将会在下篇文章中讲解它的原理,以及如何使用Shader来实现它。
好了,今天到这里就结束了,下次再见!!!
高咯德着色