A0:迭代函數系統(IFS)
任務概述
6.837的第一個作業,實現IFS算法。目的是熟悉C++的語法特性,並且熟悉使用兩個和圖像生成和線性代數相關的簡單庫。通過生成一些奇妙的分形物體來體會圖形學的樂趣。
IFS 是一種構造分形的方法,得到的分形通常是自相似(self-similar)的。IFS最經典的例子是繪製一種蕨類植物(Barnsley’s fern),如下圖所示,可以看到,每一個子葉片與整個葉片的形狀相同。
IFS由一個仿射變換(affine transformations)集合所定義,通常定義的仿射變換包括旋轉(rotation)、縮放(scale)、平移(translations)、斜切(skew)等等線性變換方法。這些變換不着了自相似的物體形狀。IFS可以定義在多個維度上,在這個作業中,我們只需實現二維的變換。
實現細節
本實驗已經提供了matrix.h、vectors.h、image.h、image.cpp、matrix.cpp5個文件
而我們要實現的文件是ifs.h、ifs.cpp、main.cpp
因此本實驗的關鍵是實現ifs類、ifs的輸入和ifs的渲染算法
ifs類的創建
#include "matrix.h"
#include "image.h"
#include "vectors.h"
class IFS {
private:
//仿射變換的個數
int n;
//仿射變換矩陣數組
Matrix* matrix;
//每一個仿射變換的選取概率數組
float* prob;
public:
//構造函數,使用仿射變換個數初始化
IFS():n(0),matrix(nullptr),prob(nullptr){}
//析構函數
~IFS() {
delete[] matrix;
delete[] prob;
}
//讀取IFS輸入
void input(const char* file);
//繪製IFS圖片
void render(Image& image, int num_points, int num_iters);
};
IFS輸入的實現
void IFS::input(const char* file) {
FILE* input = fopen(file, "r");
assert(input != nullptr);//斷言幫助調式解決邏輯bug
//從一個流中執行格式化輸入,fscanf遇到空格和換行時結束,注意空格時也結束
fscanf(input, "%d", &n);//讀取變換的數量
matrix = new Matrix[n];
prob = new float[n];
for (int i=0;i<n;i++)
{
fscanf(input, "%f", &prob[i]);//讀取變換的概率
matrix[i].Read3x3(input);//讀取變換的3x3浮點矩陣
}
fclose(input);//關閉輸入流
}
IFS算法的實現
void IFS::render(Image& image, int num_points, int num_iters) {
int width = image.Width();
int height = image.Height();
for (int i=0;i<num_points;++i){
Vec2f v = Vec2f(rand() * 1.0f / RAND_MAX, rand() * 1.0f / RAND_MAX);
for (int j = 0; j < num_iters; ++j) {
int k = 0;
float sum = 0;
float t = rand() * 1.0f / RAND_MAX;
for (;k<n;++k){
sum += prob[k];
if (sum > t) break;
}
matrix[k].Transform(v);
}
if (v.x() >= 0 && v.x() <= 1 && v.y() >= 0 && v.y() <= 1) {
image.SetPixel(v.x() * width, v.y() * height, Vec3f(0.0, 0.0, 0.0));
}
}
}
這裏我不是很懂這個算法的思想,主要是參考了別人的代碼完成
實驗結果
參考資料
- https://github.com/nycshisan/MIT6_837_Assignments/tree/master/src
- vs2013遇到fopen不安全替換fopen_s的問題
- VS中多級目錄的寫法
- CMAKE的學習
- https://github.com/fuzhanzhan/MIT-CG6.837-2004
- (MIT 6.837)迭代函數系統IFS畫自相似圖形的算法