CG自学练习一:使用OpenGL绘制Koch Snowflake

In: Computer Graphics|OpenGL

28 2011

这篇文章来源于Standford Univ.的CS148课程的第一周Assignment,作业内容是要求用基本的OpenGL的图元绘制知识来创作一些有趣的图形。

一、Knoch Snowflake介绍

我选择的是绘制鼎鼎有名的Koch Snowflake,它是最早有描述的分形图像之一,因为形状类似雪花且每一边都是基于Koch Curve而得名。从本质上来说,Koch Curve的构建可以用优美的递归形式来描述:

  1. 一条线段平均分成三段,
  2. 基于中间那条线段的位置绘制一个等边三角形,并且指向线段的外侧,
  3. 移除该条线段

而Koch Curve正是通过有限次地不断重复以上三步所得到的曲线,下图展示了递归0-4次时的曲线:

Iteration 0:  
Iteration 1:  
Iteration 2:  
Iteration 3:  
Iteration 4:

……

二、绘制Koch Snowflake

那么应该如何利用OpenGL的基本图元(Primitives)来绘制呢?一开始的时候我设想的是根据预期的迭代次数,找到一个通用公式,从而计算出对应的顶点坐标,然后再用GL_LINE将它们连接起来即可,但是找到这么一个公式比较困难。突然我想到了小时候玩的logo语言,利用代码控制屏幕中小乌龟的位移,它走过的地方就画出一条线,基于Koch曲线如此优美的递归定义,用这种一笔画的方式来绘制,就会非常方便。为了采用这种方法,我们需要定义下列两个绘制函数:

  • draw_line用于从当前位置绘制一条长度为length的线段
  • turn将改变当前画笔的方向angle_in_degrees个角度,根据图形学的惯例,逆时针(counterclockwise)方向为正

这两个方法的实现将会在下文简述

C++语言: 绘制函数
// drawing functions
void draw_line(double length);
void turn(int angle_in_degrees);

有了绘制函数和Koch曲线的递归定义,要画出它来就非常简单了:

void 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 horizontal
turn(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的绘制结果:

三、绘制函数的实现

1. draw_line的实现

为了维护当前“画笔”状态,我们需要两个全局变量:

  • CURRENT_POS用于记录当前“画笔”所在的位置
  • DIRECTION用于记录当前“画笔”的方向

当我们知道了线段的一个端点\mathbf{p}_0=(x_0, y_0) 以及线段的方向\mathbf{d}=(d_x, d_y) ,可以由该线段的长度很轻松地得到线段的另一个端点\mathbf{p}_1=\mathbf{p}+length\cdot{}\mathbf{d} 。将这两个端点放入glBegin()和glEnd()块中即可

2.turn的实现

由于向量本身只表示长度和方向,与起始位置无关,因此要令当前“画笔”的方向向量转过一个角度,可以认为在原地旋转该角度即可,而不需要像其他图形一样需要再考虑与世界坐标系原点来回平移的变换。于是我们可以得到方向向量旋转的变换矩阵为:

至此,一个简单的绘制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

2 Responses to CG自学练习一:使用OpenGL绘制Koch Snowflake

Avatar

zpnec

五月 13th, 2011 at 16:15

直接按照那个递归定义写递归函数也可以做出来,不过你的一笔画思路也很牛X,相当巧妙的说

Avatar

SB

十月 13th, 2011 at 15:52

可以用这个制作视频CG特效吗?
CG动画啊。
我挺想学CG的。

Comment Form

About this blog

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

Photostream

日历

2011 年二月
« 一    
 12345
6789101112
13141516171819
20212223242526
2728  

TwitterWidget

21 小时 ago
@GClover1985 @Hanliinter 没错……他刚刚出现在群里面打了几个点
view tweet
21 小时 ago
刚刚在群里不小心枪了一下 @Hanliinter 大大,还好他没在……
view tweet
at 02/22/2012
3月9号毕业答辩,看来上班时间要往后拖拖了。。
view tweet
at 02/22/2012
@r475 我们据说答辩时间安排也出来了,稍晚些时候会邮件通知。目前最怕的还是抽盲审啊!其实像你们这样必盲的倒也省去许多烦恼了=-=
view tweet
at 02/22/2012
@rebecca_kidult 是电压力锅还是传统的那种用煤气灶烧的高压锅呀?
view tweet
at 02/20/2012
@SafenZhai 谢谢!我还是先好好上班和准备GRE吧><祝再拿到更多的offer呀~~
view tweet
at 02/20/2012
@SafenZhai 嗯。。现在就是研究生、接下来一年的工作和将来想要申请的是三个不同的领域……所以发愁这个-0-不知道工作经验可不可以弥补一下
view tweet
at 02/20/2012
@SafenZhai 申请经验~我也有申请2013 Fall PhD的打算:)
view tweet
at 02/20/2012
@SafenZhai cong!求经验传授
view tweet
at 02/20/2012
@goldengrape 其他设备都好说,像iphone这样在中国可能因为硬件不同而无法得到保修(似乎是连维修都不行)
view tweet
Follow me!

FeedBurner RSS