[6.837]A0:迭代函数系统(IFS)

任务概述

6.837的第一个作业,实现IFS。目的是熟悉C++的语法特性,并且熟悉使用两个和图像生成和线性代数相关的简单库。通过生成一些奇妙的分形物体来体会图形学的乐趣。
IFS 是一种构造分形的方法,得到的分形通常是自相似(self-similar)的。IFS最经典的例子是绘制一种蕨类植物(Barnsley’s fern),如下图所示,可以看到,每一个子叶片与整个叶片的形状相同。
《[6.837]A0:迭代函数系统(IFS)》
IFS由一个仿射变换(affine transformations)集合所定义,通常定义的仿射变换包括旋转(rotation)、缩放(scale)、平移(translations)、斜切(skew)等等线性变换方法。这些变换不着了自相似的物体形状。IFS可以定义在多个维度上,在这个作业中,我们只需实现二维的变换。形式上来说,IFS由n个仿射变换组成,可以由如下公式表示:
《[6.837]A0:迭代函数系统(IFS)》
每一个变换函数fi一定是收缩的,这意味着两点之间的距离必须减小。IFS的吸引子(attractor)是使得等式A=Ufi(A)成立的物体A,经历了这个集合的变换过程之后,物体A的形状不发生改变,也可以将其看作仿射变换集函数的不动点(fixed-point)。
我们最后将渲染结果输出为图片。通过在一个单位正方形内随机采样点作为输入,通过多次迭代得到不动点,算法伪码描述如下:

for "lots" of random points (x0, y0)
       for k=0 to num_iters 
           pick a random transform fi
           (xk+1, yk+1) = fi(xk, yk)
       display a dot at (xk, yk)

实现细节

1.命令行输入处理

ifs -input fern.txt -points 10000 -iters 10 -size 100 -output fern.tga

上述参数依次为:程序名、IFS数据文件名、随机点个数、迭代次数、图片大小、输出图片名。
2.IFS类

class IFS { 
public:
    //构造函数,使用仿射变换个数初始化
    IFS(int transnum);
    ~IFS();
    //仿射变换的个数
    int m_nNumofTrans;
    //仿射变换矩阵数组
    Matrix* m_matMatsofTrans;
    //每一个仿射变换的选取概率数组
    double* m_darrProbofTrans;
    // 读取IFS输入
    void ReadInput(FILE* filename);
    //绘制IFS图片
    void RenderIFS(Image* img, int pntnum, int iternum);
};

3.选择仿射变换
对于算法的伪码描述,我在RenderIFS函数中给出实现。需要注意的是,对于多个随机输入点,首先要将其归一化,在这里我使用伪随机生成【0,1】区间上的浮点数。将初始点进行迭代,根据n个仿射变换的选取概率来决定究竟每一次迭代的函数。这一段依概率选取的代码也使用伪随机实现:

//以概率p来选择仿射变换j
        int j = 0;
        //初始化区间(a,b]
        double a = 0, b = this->m_darrProbofTrans[j];
        double p = rand()*1.0f / RAND_MAX;
        for (j = 1; j < this->m_nNumofTrans; j++){
            //如果伪随机得到的p落在当前区间内,则跳出循环
            if (p > a&&p <= b){
                break;
            }
            //按照概率更新区间
            a = b;
            b = b + this->m_darrProbofTrans[j];
        }
        //循环结束后j即为最终选取的仿射变换函数fj

4.计算并绘制点
每一次仿射变换都可以通过向量和矩阵的线性乘法得到,在这里我调用了Matrix类下的Transform函数。计算得到的最终点依然位于单位正方形中,将其映射到图片空间的过程,除了x,y轴向上的按比例放大之外,还要将浮点型离散为[0,size-1]的整型,防止数组下标越界。完成后即可通过Image类下的SetPixel函数将最终的点着色。

结果展示

1.Sierpinski Triangle
《[6.837]A0:迭代函数系统(IFS)》

2.Giant-X
《[6.837]A0:迭代函数系统(IFS)》

3.Fern
《[6.837]A0:迭代函数系统(IFS)》

心得体会

对于分形图形的绘制,IFS给出了简洁的设计思路。作为图形学的入门课程,MIT6.837的第一个作业很好的练习了C++的语法特性和线性代数的基本应用。

    原文作者:ZJU_TEDA
    原文地址: https://blog.csdn.net/qq_32096491/article/details/78199058
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞