烧饼的技术乱讲
这篇文章来源于Standford Univ.的CS148课程的第一周Assignment,作业内容是要求用基本的OpenGL的图元绘制知识来创作一些有趣的图形。
我选择的是绘制鼎鼎有名的Koch Snowflake,它是最早有描述的分形图像之一,因为形状类似雪花且每一边都是基于Koch Curve而得名。从本质上来说,Koch Curve的构建可以用优美的递归形式来描述:
而Koch Curve正是通过有限次地不断重复以上三步所得到的曲线,下图展示了递归0-4次时的曲线:
Iteration 0: 
Iteration 1: 
Iteration 2: 
Iteration 3: 
Iteration 4:
……
那么应该如何利用OpenGL的基本图元(Primitives)来绘制呢?一开始的时候我设想的是根据预期的迭代次数,找到一个通用公式,从而计算出对应的顶点坐标,然后再用GL_LINE将它们连接起来即可,但是找到这么一个公式比较困难。突然我想到了小时候玩的logo语言,利用代码控制屏幕中小乌龟的位移,它走过的地方就画出一条线,基于Koch曲线如此优美的递归定义,用这种一笔画的方式来绘制,就会非常方便。为了采用这种方法,我们需要定义下列两个绘制函数:
这两个方法的实现将会在下文简述
C++语言: 绘制函数// drawing functions
void draw_line(double length);
void turn(int angle_in_degrees);
有了绘制函数和Koch曲线的递归定义,要画出它来就非常简单了:
C++语言: 绘制Koch Snowflakevoid koch_curve(unsigned order, double length)
{
if ( 0 == order ) {
draw_line(length);
} else {
order -= 1;
length /= 3;koch_curve(order, length);
turn(60);
koch_curve(order, length);
turn(-120);
koch_curve(order, length);
turn(60);
koch_curve(order, length);
}
}void koch_snowflake(unsigned order, double length_of_side)
{// Assume current direction is horizontalturn(60);
koch_curve(order, length_of_side);
turn(-120);
koch_curve(order, length_of_side);
turn(-120);
koch_curve(order, length_of_side);
}
下图为7阶Koch Snowflake的绘制结果:
为了维护当前“画笔”状态,我们需要两个全局变量:
当我们知道了线段的一个端点
以及线段的方向
,可以由该线段的长度很轻松地得到线段的另一个端点
。将这两个端点放入glBegin()和glEnd()块中即可
由于向量本身只表示长度和方向,与起始位置无关,因此要令当前“画笔”的方向向量转过一个角度,可以认为在原地旋转该角度即可,而不需要像其他图形一样需要再考虑与世界坐标系原点来回平移的变换。于是我们可以得到方向向量旋转的变换矩阵为:
至此,一个简单的绘制Koch Snowflake程序便可以工作良好了。需要注意的是,在这个程序中每一帧都需要对整个图形的坐标进行一次计算,当阶数很大时会占用很多的CPU资源,可以使用Vertex List或者vector来保存已经计算好的坐标再进行绘制。
依照着这个思路,可以很方便的绘制一些优美的图形,如:
[1] Koch Snowflake: http://en.wikipedia.org/wiki/Koch_snowflake
[2] OpenGL Programming Guide: http://www.amazon.com/OpenGL-Programming-Guide-Official-Learning/dp/0321552628/ref=sr_1_1?ie=UTF8&qid=1298881745&sr=8-1
[3] Neils Fabian Helge von Koch’s Snowflake” http://www.efg2.com/Lab/FractalsAndChaos/vonKochCurve.htm
I'm now a graduate student of Computer Applied Technology in Tongji University. I like Computer Graphics, Web 2.0, Magic, Music and am partially a geek. This blog is about C++, algorithm, cg, comments and other things I may get in touch with in the near future. Hope everyone enjoy this little site. Contact me: 4everlove.xu AT gmail.com
2 Responses to CG自学练习一:使用OpenGL绘制Koch Snowflake
zpnec
五月 13th, 2011 at 16:15
直接按照那个递归定义写递归函数也可以做出来,不过你的一笔画思路也很牛X,相当巧妙的说
SB
十月 13th, 2011 at 15:52
可以用这个制作视频CG特效吗?
CG动画啊。
我挺想学CG的。