分形特效



以下是2003年我在看分形算法之后写的一个关于IFS(迭代函数系)类分形实现程序,ifs是分形中最为简单的一类,用途很广。该类利用信息的自相似特性,可以描述很多自然界中存在的食物,如海岸,山脉,树木,楼宇,其数学抽象为仿射坐标变换,旋转,扭曲,平移三种效果的迭加。
特别的,对于二维图像只要事先给定a,b,c,d,e,f系数,就可以确定五花八门的图像了。
x(n+1) = a*x(n) + b*y(n) + c
y(n+1) = d*x(n) + e*y(n) + f


对于其应用印象最深的应该是Maya paint effect screensaver (其算法没有看到,只是根据界面做了一些简单推测). 刚开始接触这个分形系统的时候,我觉得非常神奇,每个mel文件对应一个分形图案,每个图案也非常漂亮,而且绘制非常迅速。开始,我把神奇归结到了那些mel脚本里面,而且差点就去学习mel编程了,很快发现,情况并非如此,因为所有的mel文件中并没有实质上的可执行的语句,只是大量的常数定义,当把多个mel文件打开的时候,发现其关键字全部相同,这才明白,这些数据只是给出了绘制这些分形图形,并进行渲染所需要的参数,真正生成图形的算法应该是在二进制文件里面,其最巧妙的地方就是对一种分形算法重复利用,太阳花,菊花,蒲公英,竹子,杂草均使用一个分形系统,在做渲染的时候,则提取事先定义好的二维图形贴片进行贴图,就生成了各种各样的绚丽图案。






void CIfsDlg::OnFile()
{
    while(nValidate == 2) {
        nShouldStop = 1;
        Sleep(10);
    }
    flag = 0;
    XMax = 0; YMax = 0;
    XMin = 0; YMin = 0;


    CFileDialog dlg(TRUE, NULL,    NULL,
        OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
        "ifs文件 (*.ifs)|*.ifs||");


    if(dlg.DoModal() == IDOK) {
        CString str;
        nNum = 0;
        CStdioFile file(dlg.GetFileName(), CFile::modeRead);
        if(! file.ReadString(str)) return;
        nNum = atoi(str);
        for(int i=0; i<nNum; i++) {
            if(! file.ReadString(str)) return;
            sscanf(str, "%f %f %f %f %f %f %f",
                &a[i][0], &a[i][1], &a[i][2], &a[i][3],
                &a[i][4], &a[i][5], &a[i][6]);
        }
        file.Close();
        p_sum = 0.f;
        for(i=0; i<nNum; i++) {
            p_sum += a[i][6];
            p_cum[i] = int(p_sum*RAND_MAX+.5);
        }
    }
    OnButton1();
}


void CIfsDlg::OnButton1()
{
    DWORD id;


    while(nValidate == 2) {
        nShouldStop = 1;
        Sleep(10);
    }


    nShouldStop = 0;


    CreateThread(NULL, 0, PaintIfs, this, NULL, &id);
}




void CIfsDlg::OnSize(UINT nType, int cx, int cy)
{
    CDialog::OnSize(nType, cx, cy);


    if(m_Ifs) {
        nShouldStop = 1;
        if(m_FullScreen) {
            XS = cx;
            YS = cy;
        }
        else
        {
            m_Ifs.SetWindowPos(NULL, 0, 0, cx-130,cy-30, SWP_NOZORDER|SWP_NOMOVE);
            XS = cx-140;
            YS = cy-40;
        }
        flag = 0;
        XMax = 0; YMax = 0;
        XMin = 0; YMin = 0;
        OnButton1();
    }
}


DWORD WINAPI CIfsDlg::PaintIfs(LPVOID lpvThreadParm)
{
    CIfsDlg * dlg = (CIfsDlg *) lpvThreadParm;
    dlg->nValidate = 2;
    CDC *dc1;
    if(dlg->m_FullScreen){
        dc1 = dlg->GetWindowDC();
        //dc1 = GetDesktopWindow()->GetDC();
    }
    else
    {
        dc1 = dlg->m_Ifs.GetDC();
    }


    int i, temp, k;


    RECT rec = {0,0,dlg->XS+10,dlg->YS+10};
    dc1->FillRect(&rec, &CBrush(RGB(0, 0, 0)));
    COLORREF col = RGB(
        dlg->MyRand(128)+128,
        dlg->MyRand(128)+128,
        dlg->MyRand(128)+128);
    for(;;)
    {
        if(dlg->m_FullScreen && (dlg->MyRand(1000)== 0))
        {
            dlg->nValidate = 0;
            dlg->ReadFile();
            dc1->DeleteDC();
            return 0;
        }
        Sleep(5);
        for(i=0; i<256; i++)
        {
            temp = dlg->MyRand();


            for(k=0; k<dlg->nNum-1; k++)
            {
                if(temp<dlg->p_cum[k]) break;
            }
            dlg->newx = (dlg->a[k][0]*dlg->x+dlg->a[k][1]*dlg->y+dlg->a[k][4]);
            dlg->y = (dlg->a[k][2]*dlg->x+dlg->a[k][3]*dlg->y+dlg->a[k][5]);
            dlg->x = dlg->newx;


            if(dlg->flag == 0 && i>16)
            {
                dlg->XMax = max(dlg->x, dlg->XMax); dlg->XMin = min(dlg->x, dlg->XMin);
                dlg->YMax = max(dlg->y, dlg->YMax); dlg->YMin = min(dlg->y, dlg->YMin);
            }
            else if(dlg->flag == 1)
            {
                dlg->px = dlg->x*dlg->xscale + dlg->xoffset;
                dlg->py = dlg->y*dlg->yscale + dlg->yoffset;
                if((dlg->px >=0 ) && (dlg->px <= dlg->XS + 10)
                    && (dlg->py >= 0) && (dlg->py <= dlg->YS+10))
                {
                    dc1->SetPixel(dlg->px+2, dlg->YS - dlg->py+10, col);
                }
                if(dlg->nShouldStop) {
                    dlg->nValidate = 0;
                    dc1->DeleteDC();
                    return 1;
                }
            }
        }


        if(dlg->flag == 0)
        {
            dlg->xscale = dlg->XS/(dlg->XMax-dlg->XMin);
            dlg->yscale = min(dlg->YS/(dlg->YMax-dlg->YMin), dlg->xscale);
            if(dlg->yscale < dlg->xscale) dlg->xscale = dlg->yscale;
            dlg->xoffset = dlg->XS/2 - (dlg->XMax+dlg->XMin)*dlg->xscale/2-1;
            dlg->yoffset = dlg->YS/2 - (dlg->YMax+dlg->YMin)*dlg->yscale/2-1;
            dlg->flag = 1;
        }
    }


    dc1->DeleteDC();
    dlg->nValidate = 0;
    return 0;
}


void CIfsDlg::ReadFile()
{
    while(nValidate == 2) {
        nShouldStop = 1;
        Sleep(10);
    }
    flag = 0;
    XMax = 0; YMax = 0;
    XMin = 0; YMin = 0;


    CString str;
    nNum = 0;
    char *fileName[]={"circle.ifs","fern.ifs","ktree.ifs","mleaf.ifs","sierpink.ifs","tree.ifs"};
    int n = rand();


    int i;
/*  str = ""; 
    char ch[8] = {0};
    for(i=0; i<100; i++) 
    {
        sprintf(ch, "%d ", MyRand());
        str += ch;
        if(!(i%10)) str += "\r\n";
    }
    MessageBox(str);
*/
    n=MyRand(6);
    char *p = *(fileName+n);
    CStdioFile file(p, CFile::modeRead);
    if(! file.ReadString(str)) return;
    nNum = atoi(str);
    for(i=0; i<nNum; i++) {
        if(! file.ReadString(str)) return;
        sscanf(str, "%f %f %f %f %f %f %f",
            &a[i][0], &a[i][1], &a[i][2], &a[i][3],
            &a[i][4], &a[i][5], &a[i][6]);
    }
    file.Close();
    p_sum = 0.f;
    for(i=0; i<nNum; i++) {
        p_sum += a[i][6];
        p_cum[i] = int(p_sum*RAND_MAX+.5);
    }


    OnButton1();
}


int CIfsDlg::MyRand(int nMax)
{
    LARGE_INTEGER litmp;
    LONGLONG QPart1;
    QueryPerformanceCounter(&litmp);
    QPart1 = litmp.QuadPart;
    QPart1 &= 0x7fff;
    QPart1 = QPart1*QPart1;


    int n2 = QPart1&0xff;


    QPart1 >>= 8;
    int n1 = QPart1 & 0x7fff;
    n1 = n1*nMax/0x7fff;
    if(n1>=nMax) n1 = nMax-1;


    return n1;
}





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值