跳至内容

分形/复平面上的迭代/斜率

来自维基教科书,开放世界中的开放书籍

这是一种将 2D 图像转换为 3D 图像的算法

"每个像素迭代三个点,然后用于创建三维曲面。垂直于该曲面的向量用作 z 变量,并传递给着色例程。当使用斜率公式进行光照着色时,结果类似于从上方和侧面照亮的分形曲面。" Kerry Mitchell[1]

差异

  • 阴影浮雕或阴影山体:通过考虑光源角和阴影,从表面栅格创建阴影浮雕。
  • 斜率 = 识别栅格每个像元的斜率(梯度或陡峭度)。


直线的斜率

[编辑 | 编辑源代码]
斜率:

在数学中,直线的斜率梯度是一个描述直线方向陡峭程度的数字。[3] 斜率通常用字母m表示;关于为什么用字母m表示斜率没有明确的答案。

y = mx + b

经过两点:(x1,y1) 和 (x2,y2) 的直线的斜率是

直线的斜率m与其倾斜角θ的关系由正切函数给出

应用于

[编辑 | 编辑源代码]
  • 曼德勃罗集[4]
  • 朱利亚集
  • 牛顿法 [5]
  • 克莱因群分形[6]
  • 奇异吸引子 [7]
  • 由 Damien Jones 在 dmj.ufm 和 standard.ufm 中提供的 Ultrafractal 公式



hue = fmod(1 + carg(de) / (2 * pi), 1); //  slope of complex number de

由 nickspiker 提供的 Matlab 代码

%for each pixel do the stuff below
c=somethingreal+somethingimaginary;
z=0;
d=1;
while (real(z)^2+imaginary(z)^2)<realbignumber
z=z^2+c;
d=2*z*d+1;%derivative step and I think the plus one comes from the derivative of c, not totally sure on that one
endwhile
slope=sign(z/d)%values are strange because of where we abruptly end the step but the sign is clean

%then this is what I do for the shading bit
%you can look at the real and imaginary parts of slope before you do the steps below to better understand what's going on
sunangle=45;
brightness=slope*e^(i*sunangle*pi/180);%this rotates the sign by the angle above
brightness=real(brightness)/2+.5;


%Mandelbrot rendering algorithms utilizing interior and exterior slope finding steps copyright 2020 Nick Spiker [email protected]

maxn=2^32;
steps=2^5;%anti aliasing steps
mns=2^8;%max newton steps
dpi=90;
bleed=0;%change to 6 when final render, 3 per side
width=42;
height=48;
zoom=3;
center=-.75;
rotation=90;
alias=2^-6;
tiles=3;
starttile=1;
preview=false;

if preview
    dpi=30;
    tiles=1;
    bleed=0;
end

rez=[(width+bleed).*dpi,(height+bleed).*dpi];
zoom=zoom./height.*(height+bleed);
localrez=ceil(rez./tiles);%finds closest multiple equal to or greater than rez
localrezb=localrez+2;
pixelsize=zoom./rez(2);
tlx=-zoom./rez(2).*rez(1)./2;
tly=zoom./2;
localzoom=localrezb(2).*pixelsize;

tic;
for tiley=floor((starttile-1)./tiles)+1:tiles
    for tilex=mod(starttile-1,tiles)+1:tiles
        tn=toc;
        starttile=1;
        localcenter=tlx+pixelsize.*localrez(1).*(tilex-.5)+(tly-pixelsize.*localrez(2).*(tiley-.5)).*i;
        localcenter=center+localcenter.*exp(1i*rotation*pi/180);
       
        xlim = [(pixelsize-localzoom./localrezb(2).*localrezb(1))./2,(localzoom./localrezb(2).*localrezb(1)-pixelsize)./2];
        ylim = [(localzoom-pixelsize)./2,(pixelsize-localzoom)./2];
       
        x=linspace(xlim(1),xlim(2),localrezb(1));
        y=linspace(ylim(1),ylim(2),localrezb(2));
        [xGrid,yGrid]=meshgrid(x,y);
       
        cleanc=xGrid+1i*yGrid;
        cleanc=cleanc*exp(1i*rotation*pi/180)+localcenter;
       
        stackalpha=zeros(localrezb(2),localrezb(1),3);
        stackimage=zeros(localrezb(2),localrezb(1),3);
        stackalias=true(localrezb(2),localrezb(1));
        aliasstep=alias;
       
        for step=1 :steps
            tm=toc;
            aliasstep=aliasstep+alias;
            totalpixels=sum(sum(stackalias));
            if totalpixels==0
                break
            end
            c=(cleanc(stackalias)+rand(totalpixels,1).*(cleanc(1,1)-cleanc(1,2))+rand(totalpixels,1).*(cleanc(1,1)-cleanc(2,1)));
            ac=abs(c);
            acs=ac.*ac;
            acs=acs.*acs;
            acs=acs.*acs;
            cr=real(c);
            ci=imag(c);
            inside=false(totalpixels,1);
            a=zeros(totalpixels,1);
            frame=cat(3,a,a,a);
            dr=a;
            di=a;
            er=a;
            ei=a;
            slope=a;
            maxcount=1;
            parfor p=1:totalpixels%parfor
                insidep=false;
                %orbitcount=1;
                crp=cr(p);
                cip=ci(p);
                zr=crp;
                zi=cip;
                ap=maxn;
                drp=0;
                dip=0;
                dsp=0;
                erp=0;
                eip=0;
                esp=0;
                srp=1;
                sip=0;
                osr=1;
                osi=0;
                %orbit=0;
                zsmallest=realmax;
                for n=1:maxn
                   
                    srpt=2.*(srp.*zr-sip.*zi);
                    sip=2.*(srp.*zi+sip.*zr);
                    srp=srpt+1;
                   
                   
                    zrs=zr.*zr;
                    zis=zi.*zi;
                    zs=zrs+zis;
                    ns=n.*n;
                    if zs>4
                        llzs=log(log(zs));
                        taper=(llzs-0.326634259978281)./6.238324625039508;
                        taper=1-taper.*taper;
                        taper=taper.*taper;
                        taper=taper.*taper.*taper.*ns;
                        zsq=taper./sqrt(zs);
                        esp=esp+taper;
                        erp=erp+zr.*zsq;
                        eip=eip+zi.*zsq;
                       
                        zsi=ns./zs;
                        dsp=dsp+zsi;
                        drp=drp+zr.*zsi;
                        dip=dip+zi.*zsi;
                       
                        if zs>1.340780792994260e+154
                            ap=n-(llzs-5.174750624576761).*1.442695040888963;
                            break
                        end
                       
                        durt=2.*(zr.*osr-zi.*osi)+1;
                        osi=2.*(osr.*zi+osi.*zr);
                        osr=durt;
                       
                        zi=2.*zr.*zi+cip;
                        zr=zrs-zis+crp;
                    else
                        taper=ns;
                        zsq=taper./sqrt(zs);
                        esp=esp+taper;
                        erp=erp+zr.*zsq;
                        eip=eip+zi.*zsq;
                        zsi=ns./zs;
                        dsp=dsp+zsi;
                        drp=drp+zr.*zsi;
                        dip=dip+zi.*zsi;
                        if zsmallest>zs
                            adcs=zs./zsmallest;
                            zsmallest=zs;
                            if adcs<.25
                                period=n;
                                wr=zr;
                                wi=zi;
                                for l=1:mns
                                    ur=wr;
                                    ui=wi;
                                    dur=1;
                                    dui=0;
                                    for m=1:period
                                       
                                        %du=2*du*u
                                        durt=2.*(dur.*ur-dui.*ui);
                                        dui=2.*(dur.*ui+dui.*ur);
                                        dur=durt;
                                       
                                        %u=u*u+c
                                        uis=ui.*ui;
                                        ui=2.*ur.*ui+cip;
                                        ur=ur.*ur-uis+crp;
                                       
                                    end
                                   
                                    %nw=w-(u-w)/(du-1)
                                    nwr=ur-wr;
                                    nwi=ui-wi;
                                    duro=dur-1;
                                    durt=duro.*duro+dui.*dui;
                                    nwrt=(nwr.*duro+nwi.*dui)./durt;
                                    nwi=(nwi.*duro-nwr.*dui)./durt;
                                    nwr=nwrt;
                                    ns=nwr.*nwr+nwi.*nwi;
                                    wr=wr-nwr;
                                    wi=wi-nwi;
                                   
                                    if ns<2^-32
                                        if dur.*dur+dui.*dui<1
                                            drp=dur;
                                            dip=dui;
                                            erp=wr;
                                            eip=wi;
                                            insidep=true;
                                            ap=m;
                                            break
                                        end
                                    end
                                end
                                if insidep
                                    break
                                end
                            end
                        end
                       
                        durt=2.*(zr.*osr-zi.*osi)+1;
                        osi=2.*(osr.*zi+osi.*zr);
                        osr=durt;
                       
                        zi=2.*zr.*zi+cip;
                        zr=zrs-zis+crp;
                       
                    end
                    if insidep
                        break
                    end
                end
               
                maxcount=max(maxcount,n);
                if insidep
                    inside(p)=true;
                    dr(p)=drp;
                    di(p)=dip;
                    er(p)=erp;
                    ei(p)=eip;
                   
                    cca=crp+cip.*i;
                    ccc=cca;
                    for l=1:mns
                        zzz=ccc;
                        ddd=1;
                        for z=2:period
                            ddd=2.*ddd.*zzz+1;
                            zzz=zzz.*zzz+ccc;
                        end
                        ddd=ccc-zzz./ddd+2^-256.*i;
                        if ddd==ccc
                            ccc=ddd;
                            break
                        end
                        ccc=ddd;
                    end
                    slope(p)=ccc-cca;
                else
                    dsp=1./dsp;
                    esp=1./esp;
                    dr(p)=drp.*dsp;
                    di(p)=dip.*dsp;
                    er(p)=erp.*esp;
                    ei(p)=eip.*esp;
                    slope(p)=sign((osr+osi.*i)./(zr+zi.*i));
                end
                a(p)=ap;
            end
           
            tm=toc-tm;
            hrs=floor(tm/(60*60));
            mnt=floor((tm-hrs*60*60)/60);
            snd=tm-hrs*60*60-mnt*60;
            ['Tile ',num2str(tilex+tiley.*tiles-tiles),' of ',num2str(tiles.^2),', ',sprintf(['%0',num2str(floor(log10(tiles))+1),'.0f'],tiley),'x',sprintf(['%0',num2str(floor(log10(tiles))+1),'.0f'],tilex),', Step ',num2str(step),', ',num2str(hrs),' hours, ',num2str(mnt),' minutes, ',num2str(snd),' seconds per step, Max N=2^',num2str(log2(maxcount)),' alias%',num2str(totalpixels./(localrezb(1).*localrezb(2)).*100)]
           
            ia=a(inside);%interior period count
            oa=a(not(inside));%exterior iteration count
           
            d=dr+di.*i;
            ic=d(inside);%interior coordinate,
            ea=d(not(inside));%exterior average
           
            e=er+ei.*i;
            iw=e(inside);%interior W
            ef=e(not(inside));%Exterior flames
           
            is=slope(inside);
           
            inside3=cat(3,inside,inside,inside);
            stackalias3=cat(3,stackalias,stackalias,stackalias);
           
            %start color
            interiorrotationoffset=1.5;
            exteriorrotationoffset=pi./4;
            squarerotation=-.05;
            squarebrightness=.7;
            fresnelbrightness=.125;
            reflectionrotation=.1;
            reflectionoffset=1/4;
            reflectioncurve=1/16;
            reflectionwavies=1/8;
            reflectionbrightness=0.125;
            shaderotation=-pi./5;
            slopescale=.5;
           
            aic=abs(ic);
            isreflect=sign(is).*aic;
            shading=real(isreflect.*exp(shaderotation.*i))./3+.75;
            iss=isreflect.*exp(i.*squarerotation);
            cc=exp(i.*(angle(iw)+1./aic+interiorrotationoffset)).*aic;
            waves=real(exp(i.*(angle(is)+1./aic)).*aic);
            o=real(cc.*exp(i*120*pi/180));
            p=real(cc);
            q=real(cc.*exp(i*270*pi/180));
            cc=cat(3,o,p,q);
            cc=cc./2+.5;
            aic=aic.*aic;
            iss=iss.*aic;
            aic=aic.*aic;
            aics=aic.*aic;
            aic=aics+fresnelbrightness;
            aics=aics.*aics;
           
            shading=1-(1-aics).*shading;
           
            cc=1-cc.*(1-shading);
            issr=real(iss);
            issi=imag(iss);
            cc=1-cc.*(1-(and(and(issr>.3,issr<.7),and(issi>0.1,issi<.4)).*squarebrightness+(real(isreflect.*exp(reflectionrotation.*i))>(reflectionoffset-aics.*reflectioncurve+waves.*reflectionwavies)).*reflectionbrightness).*aic);
           
            frame(inside3)=cc;
           
            outsideslope=slope(not(inside));
            outsideslope=0.5-real(outsideslope.*exp(exteriorrotationoffset.*i))./2;
           
            oc=erf(12./oa);
            %cc=abs(ef).*exp(i.*(angle(ef)+oa.*16.*oa));
            cc=ef;
            o=real(cc.*exp(i*120*pi/180));
            p=real(cc);
            q=real(cc.*exp(i*270*pi/180));
            cc=cat(3,o,p,q);
            cc=cc./2+.5;
            oc3=5./oa;
            oc3=1-oc3;
            oc3=1-cat(3,oc3,oc3,oc3).*(1-cc)./2;
            cc=oc3.*oc.*(outsideslope.*slopescale+(1-slopescale));
            frame(not(inside3))=cc;
           
            if preview
                stackimage(stackalias3)=reshape(frame,size(frame,1).*size(frame,2).*size(frame,3),1);
                imshow(stackimage)
                return
                %else
                %frame=frame./2+.25;%declip for post
            end
            %end color
           
            stackimage(stackalias3)=stackimage(stackalias3)+reshape(frame,size(frame,1).*size(frame,2).*size(frame,3),1);
            stackalpha=stackalpha+stackalias3;
            frame=stackimage./stackalpha;
           
            if step~=steps
                if step==1
                    stackdiff=false(localrezb(2),localrezb(1));
                else
                    previousframe=abs(frame-previousframe);
                    stackdiff=previousframe(:,:,1)+previousframe(:,:,2)+previousframe(:,:,3)+stackdiff./stackalpha(:,:,2);
                end
                r=frame(:,:,1);
                g=frame(:,:,2);
                b=frame(:,:,3);
                r=ordfilt2(r,1,ones(3,3),'symmetric');
                g=ordfilt2(g,1,ones(3,3),'symmetric');
                b=ordfilt2(b,1,ones(3,3),'symmetric');
                mn=cat(3,r,g,b);
                r=frame(:,:,1);
                g=frame(:,:,2);
                b=frame(:,:,3);
                r=ordfilt2(r,9,ones(3,3),'symmetric');
                g=ordfilt2(g,9,ones(3,3),'symmetric');
                b=ordfilt2(b,9,ones(3,3),'symmetric');
                mx=cat(3,r,g,b);
                mx=mx-mn;
                mx=mx(:,:,1).*2+mx(:,:,2).*3+mx(:,:,3);
                stackalias=or(mx>aliasstep,stackdiff>alias);
            end
            previousframe=frame;
           
        end
        imwrite(uint16(frame(2:localrez(2)+1,2:localrez(1)+1,:).*2^16),['Z ',sprintf(['%0',num2str(floor(log10(tiles))+1),'.0f'],tiley),'x',sprintf(['%0',num2str(floor(log10(tiles))+1),'.0f'],tilex),'.tif'])
       
        tm=toc-tn;
        hrs=floor(tm/(60*60));
        mnt=floor((tm-hrs*60*60)/60);
        snd=tm-hrs*60*60-mnt*60;
        ['Tile ',num2str(tilex+tiley.*tiles-tiles),' of ',num2str(tiles.^2),', ',sprintf(['%0',num2str(floor(log10(tiles))+1),'.0f'],tiley),'x',sprintf(['%0',num2str(floor(log10(tiles))+1),'.0f'],tilex),', ',num2str(hrs),' hours, ',num2str(mnt),' minutes, ',num2str(snd),' seconds per tile.']
       
       
    end
end
clear('a','a3','afull','aliasstep','ang','b','c','ca','cavg','cavgi','cavgr','cavgs','ci','cleanc','count','cr','cscale','fcs','frame','g','gby','gbys','gc','gm','go','grg','grgs','gs','hrs','inside','inside3','insidef','lcolor','lmag','localcenter','localrezb','loop','loopi','loopr','loops','maxn','mn','mnt','mx','n','o','outside','p','pixelsize','previousframe','r','snd','stackalias','stackalpha','stackdiff','stackimage','step','tic1','tilex','tiley','tlx','tly','tm','totalpixels','waitstepcheck','x','xGrid','xlim','y','yGrid','ylim','zi','zr');
try
    finalimage=zeros(localrez(2).*tiles,localrez(1).*tiles,3,'uint16');
    for tiley=1:tiles
        for tilex=1:tiles
            ['Z ',sprintf(['%0',num2str(floor(log10(tiles))+1),'.0f'],tiley),'x',sprintf(['%0',num2str(floor(log10(tiles))+1),'.0f'],tilex)]
            finalimage((tiley-1).*localrez(2)+1:(tiley).*localrez(2),(tilex-1).*localrez(1)+1:(tilex).*localrez(1),:)=imread(['Z ',sprintf(['%0',num2str(floor(log10(tiles))+1),'.0f'],tiley),'x',sprintf(['%0',num2str(floor(log10(tiles))+1),'.0f'],tilex),'.tif']);
        end
    end
    imwrite(finalimage,'out.tif');
catch
    finalimage=zeros(localrez(2),localrez(1).*tiles,3,'uint16');
    for tiley=1:tiles
        for tilex=1:tiles
            ['Z ',sprintf(['%0',num2str(floor(log10(tiles))+1),'.0f'],tiley),'x',sprintf(['%0',num2str(floor(log10(tiles))+1),'.0f'],tilex)]
            finalimage(:,(tilex-1).*localrez(1)+1:(tilex).*localrez(1),:)=imread(['Z ',sprintf(['%0',num2str(floor(log10(tiles))+1),'.0f'],tiley),'x',sprintf(['%0',num2str(floor(log10(tiles))+1),'.0f'],tilex),'.tif']);
        end
        imwrite(finalimage,['F ',sprintf(['%0',num2str(floor(log10(tiles))+1),'.0f'],tiley),'.tif']);
    end
end

由 LionHeart 提供的 C++ 代码[8]

/*
    FWDDIFF.CPP a module for determining the slope using forward differencing calculations of fractals.
   
    Written in Microsoft Visual 'C++' by Paul de Leeuw.

     https://github.com/hrkalona/Fractal-Zoomer/blob/master/src/fractalzoomer/core/ThreadDraw.java#L3640
     https://github.com/hrkalona/Fractal-Zoomer/blob/master/src/fractalzoomer/main/app_settings/BumpMapSettings.java
*/

#include	"slope.h"

/**************************************************************************
    Calculate functions
**************************************************************************/

void	CSlope::DoSlopeFwdDiffFn(Complex *z, Complex *q)
    {
    Complex	sqr, temp;
    Complex	t = { 1.0, 0.0 };
    double	real_imag;
    int		k;
    int		degree = (int)param[5];
    int		degree1, degree2;

//    PaletteStart = (int)param[4];

    switch (subtype)
	{
	case 0:					// Mandelbrot
	    sqr.x = z->x * z->x;
	    sqr.y = z->y * z->y;
	    real_imag = z->x * z->y;
	    z->x = q->x + sqr.x - sqr.y;
	    z->y = q->y + real_imag + real_imag;
	    break;
// other cases removed
	}
    }

/**************************************************************************
    Get the gradients in the x and y directions
**************************************************************************/

double	CSlope::getGradientX(double *wpixels, int index, int width)
    {
    int x = index % width;
    double it = *(wpixels + index);

    if (x == 0) {
	return (*(wpixels + index + 1) - it) * 2;
	}
    else if (x == width - 1) {
	return (it - *(wpixels + index - 1)) * 2;
	}
    else {
	double diffL = it - *(wpixels + index - 1);
	double diffR = it - *(wpixels + index + 1);
	return diffL * diffR >= 0 ? 0 : diffL - diffR;
	}
    }

double	CSlope::getGradientY(double *wpixels, int index, int width, int height)
    {
    int y = index / width;
    double it = *(wpixels + index);

    if (y == 0) {
	return (it - *(wpixels + index + width)) * 2;
	}
    else if (y == height - 1) {
	return (*(wpixels + index - width) - it) * 2;
	}
    else {
	double diffU = it - *(wpixels + index - width);
	double diffD = it - *(wpixels + index + width);
	return diffD * diffU >= 0 ? 0 : diffD - diffU;
	}
    }

/**************************************************************************
   Brightness Scaling
**************************************************************************/

int	CSlope::changeBrightnessOfColorScaling(int rgb, double delta)
    {
    int	    new_color = 0;
    double	bump_transfer_factor = param[0];		// future add to dialogue box

//    double mul = getBumpCoef(delta);
    double  mul = (1.5 / (fabs(delta * bump_transfer_factor) + 1.5));

    if (delta > 0) {
	rgb ^= 0xFFFFFF;
	int r = rgb & 0xFF0000;
	int g = rgb & 0x00FF00;
	int b = rgb & 0x0000FF;
	int ret = (int)(r * mul + 0.5) & 0xFF0000 | (int)(g * mul + 0.5) & 0x00FF00 | (int)(b * mul + 0.5);
	new_color = 0xff000000 | (ret ^ 0xFFFFFF);
	}
    else {
	int r = rgb & 0xFF0000;
	int g = rgb & 0x00FF00;
	int b = rgb & 0x0000FF;
	new_color = 0xff000000 | (int)(r * mul + 0.5) & 0xFF0000 | (int)(g * mul + 0.5) & 0x00FF00 | (int)(b * mul + 0.5);
	}

    return new_color;
    }

/**************************************************************************
	Slope Fractal
**************************************************************************/

int	CSlope::RunSlopeFwdDiff(HWND hwndIn, void(*plot)(WORD, WORD, DWORD), int user_data(HWND hwnd), char* StatusBarInfo, bool *ThreadComplete, int subtypeIn, int NumThreadsIn, int threadIn, Complex j, double mandel_width, double hor, double vert, double xgap, double ygap,
    double rqlim, long threshold, double paramIn[], CTrueCol *TrueCol, CDib *Dib, double *SlopeDataPtr, BYTE juliaflag)
    {
    Complex	z = 0.0;			// initial value for iteration Z0
    Complex	c, q;
    BigComplex	cBig, zBig, qBig;
    BigDouble	BigTemp, BigTemp1;

    double	log_zn, nu;
    int		lastChecked = -1;

    int		x, y, i;
    DWORD	index;
    double	iterations;

    thread = threadIn;
    NumThreads = NumThreadsIn;
    subtype = subtypeIn;
    hwnd = hwndIn;
    for (i = 0; i < NUMSLOPEDERIVPARAM; i++)
	param[i] = paramIn[i];

    if (NumThreads == 0)
	StripWidth = xdots;
    else
	StripWidth = xdots / NumThreads;
    StripStart = StripWidth * thread;
    *ThreadComplete = false;

    for (y = 0; y < ydots; y++)
	{
	if (BigNumFlag)
	    cBig.y = BigVert + BigWidth - Big_ygap * y;
	else
	    c.y = vert + mandel_width - y * ygap;
	double progress = (double)y / ydots;
	if (int(progress * 100) != lastChecked)
	    {
	    lastChecked = int(progress * 10);
	    sprintf(StatusBarInfo, "Progess (%d%%), %d Threads", int(progress * 100), NumThreads);
	    }
	for (x = StripStart; x < StripStart + StripWidth; x++)
	    {
	    if (user_data(hwnd) < 0)	// trap user input
		return -1;

	    c.x = hor + x * xgap;
	       {
	        if (juliaflag)
	            {
	            q = j;
	            z = c;
	            }
	        else
	            {
	            q = c;
	            z = 0.0;
	            }
	        }
	    iterations = 0.0;
	    for (;;)
		{
		iterations++;
		if (iterations >= threshold)
		    break;
		DoSlopeFwdDiffFn(&z, &q);
		if ((z.x * z.x + z.y * z.y) >= rqlim)
		    break;
		}
	    if (iterations < threshold)
		{
		if (BigNumFlag)
		    {
		    // sqrt of inner term removed using log simplification rules.
		    BigTemp = zBig.x * zBig.x + zBig.y * zBig.y;
		    BigTemp1 = BigTemp.BigLog();
		    log_zn = mpfr_get_d(BigTemp1.x, MPFR_RNDN) / 2;
		    nu = log(log_zn / log(2.0)) / log(2.0);
		    }
		else
		    {
		    // sqrt of inner term removed using log simplification rules.
		    log_zn = log(z.x * z.x + z.y * z.y) / 2;
		    nu = log(log_zn / log(2.0)) / log(2.0);
		    }
		iterations = iterations + 1 - nu;
		}
	    index = ((DWORD)y * (DWORD)width) + (DWORD)x;
	    if (x >= 0 && x < xdots - 1 && y >= 0 && y < ydots - 1)
		*(SlopeDataPtr + index) = iterations;
	    plot(x, y, (long)iterations);
	    }
	}
    *ThreadComplete = true;
    return 0;
    }

/**************************************************************************
	Slope Fractal
**************************************************************************/

int	CSlope::RenderSlope(long threshold, double paramIn[], CTrueCol *TrueCol, CDib *Dib, double *SlopeDataPtr)

    {
    double	dotp, gradAbs, gradCorr, cosAngle, sizeCorr, smoothGrad, lightAngleRadians, lightx, lighty;
   
    for (int i = 0; i < NUMPARAM; i++)
	param[i] = paramIn[i];

    double	bumpMappingDepth = param[3];		// future add to dialogue box
    double	bumpMappingStrength = param[4];		// future add to dialogue box
    double	lightDirectionDegrees = param[2];	// future add to dialogue box
    int		PaletteStart = (int)param[1];

    double	iterations;
    int		lastChecked = -1;
    DWORD	index;
    int		x, y;
    double	gradx, grady;
    unsigned char r, g, b;
    RGBTRIPLE	colour;
    int		modified;

    lastChecked = -1;

    sizeCorr = 0.0;
    lightx = 0.0;
    lighty = 0.0;

    gradCorr = pow(2, (bumpMappingStrength - DEFAULT_BUMP_MAPPING_STRENGTH) * 0.05);
    sizeCorr = ydots / pow(2, (MAX_BUMP_MAPPING_DEPTH - bumpMappingDepth) * 0.16);
    lightAngleRadians = lightDirectionDegrees * PI / 180.0;
    lightx = cos(lightAngleRadians) * gradCorr;
    lighty = sin(lightAngleRadians) * gradCorr;

    for (y = 0; y < ydots; y++)
	{
	for (x = 0; x < xdots; x++)
	    {
	    index = ((DWORD)y * (DWORD)width) + (DWORD)x;
	    if (SlopeDataPtr)
		iterations = *(SlopeDataPtr + index);
	    else
		return 0;			// oops, we don't actually have forward differencing

	    if (iterations >= threshold)
		{				//  interior of Mandelbrot set = inside_color
		colour.rgbtRed = (BYTE)TrueCol->InsideRed;		// M_waves
		colour.rgbtGreen = (BYTE)TrueCol->InsideGreen;
		colour.rgbtBlue = (BYTE)TrueCol->InsideBlue;
		}
	    else
		{
		// modified = rgbs[index];
		if (iterations < PaletteStart)
		    modified = 0x00FFFFFF;
		else
		    modified = 0xFF000000 | ((DWORD)*(TrueCol->PalettePtr + (BYTE)(((long)iterations) % 256) * 3 + 0) << 16) | ((DWORD)*(TrueCol->PalettePtr + (BYTE)(((long)iterations) % 256) * 3 + 1) << 8) | *(TrueCol->PalettePtr + (BYTE)(((long)iterations) % 256) * 3 + 2);
		gradx = getGradientX(SlopeDataPtr, index, xdots);
		grady = getGradientY(SlopeDataPtr, index, xdots, ydots);
		dotp = gradx * lightx + grady * lighty;
//		int	original_color = modified;		// not sure what this is for
		if (dotp != 0)
		    {
		    gradAbs = sqrt(gradx * gradx + grady * grady);
		    cosAngle = dotp / gradAbs;
		    smoothGrad = -2.3562 / (gradAbs * sizeCorr + 1.5) + 1.57;
		    //smoothGrad = Math.atan(gradAbs * sizeCorr);
		    modified = changeBrightnessOfColorScaling(modified, cosAngle * smoothGrad);
		    }
		r = (modified >> 16) & 0xFF;
		g = (modified >> 8) & 0xFF;
		b = modified & 0xFF;
		colour.rgbtRed = r;
		colour.rgbtGreen = g;
		colour.rgbtBlue = b;
		}
	    outRGBpoint(Dib, x, y, colour);
	    }
	}
    return 0;
    }

由 Softology 提供的 OpenGLSL 代码着色器中的斜率光照[9]

#version 400

//the following uniform values are set by Visions of Chaos prior to shader execution
uniform vec2 resolution;
uniform vec3 palette[256];
uniform double xmin;
uniform double xmax;
uniform double ymin;
uniform double ymax;
uniform double bailout;
uniform int maxiters;
uniform int samplepixels;

double sqrsamplepixels=double(samplepixels*samplepixels);
double bailout_squared=double(bailout*bailout);
double magnitude,r1,r2,g1,g2,b1,b2,r,g,b,tweenval;
float realiters;
vec4 finalcol,col;
int superx,supery;
double stepx=(xmax-xmin)/resolution.x/double(samplepixels);
double stepy=(ymax-ymin)/resolution.y/double(samplepixels);
int index,colval,colval2;
dvec2 z,c,dc,der,u,v,ctwo;
double h2,angle,pi,t;

//------------------------------------------------------------
// complex number operations
dvec2 cadd( dvec2 a, dvec2 b ) { return dvec2( a.x+b.x, a.y+b.y ); }
dvec2 csub( dvec2 a, dvec2 b ) { return dvec2( a.x-b.x, a.y-b.y ); }
dvec2 cmul( dvec2 a, dvec2 b )  { return dvec2( a.x*b.x - a.y*b.y, a.x*b.y + a.y*b.x ); }
dvec2 cdiv( dvec2 a, dvec2 b )  { double d = dot(b,b); return dvec2( dot(a,b), a.y*b.x - a.x*b.y ) / d; }
dvec2 csqr( dvec2 a ) { return dvec2(a.x*a.x-a.y*a.y, 2.0*a.x*a.y ); }
dvec2 csqrt( dvec2 z ) { double m = length(z); return sqrt( 0.5*dvec2(m+z.x, m-z.x) ) * dvec2( 1.0, sign(z.y) ); }
dvec2 conj( dvec2 z ) { return dvec2(z.x,-z.y); }
dvec2 cabs( dvec2 c) { return dvec2(sqrt(c.x * c.x + c.y * c.y)); }
//------------------------------------------------------------

void main(void)
{
	finalcol=vec4(0,0,0,0);
	pi=3.14159265359;
	h2=1.5; // height factor of the incoming light
	angle=45; // incoming direction of light
	v=dvec2(exp(float(1.0*angle*2*pi/360)),0.0); // unit 2D vector in this direction
	ctwo=dvec2(2.0,0.0);

	for (supery=0;supery<samplepixels;supery++)
	{
		for (superx=0;superx<samplepixels;superx++)
		{
			c.x = xmin+gl_FragCoord.x/resolution.x*(xmax-xmin)+(stepx*double(superx));
			c.y = ymin+gl_FragCoord.y/resolution.y*(ymax-ymin)+(stepy*double(supery));
			int i;
			z = dvec2(0.0,0.0);
			dc = dvec2(1.0,0.0);
			der = dc;
			for(i=0; i<maxiters; i++)
			{
				//START OF FRACTAL FORMULA
				z=cadd(csqr(z),c);
				//END OF FRACTAL FORMULA
				
				magnitude=(z.x * z.x + z.y * z.y);
				if(magnitude>bailout_squared) break;
				
				// der = der*2*z + dc
				der = cadd(cmul(der,cmul(ctwo,z)),dc);
			}

			if (i==maxiters) {
				col=vec4(0.0,0.0,0.0,1.0);
			} else {
				//CPM smooth colors
				//note that double precision does not support log so it needs to be cast as float
				realiters=float(i+1-((log(log(sqrt(float(magnitude))))/log(2.0))));
				colval=int(mod(realiters,255));
				colval2=int(mod(colval+1,255));
				tweenval=realiters-int(realiters);
				r1=palette[colval].r;
				g1=palette[colval].g;
				b1=palette[colval].b;
				r2=palette[colval2].r;
				g2=palette[colval2].g;
				b2=palette[colval2].b;
				r=r1+((r2-r1)*tweenval);
				g=g1+((g2-g1)*tweenval);
				b=b1+((b2-b1)*tweenval);

				u = cdiv(z,der);
    			        u = cdiv(u,cabs(u)); // normal vector: (u.re,u.im,1)
    			        t = u.x*v.x + u.y*v.y + h2; // dot product with the incoming light
    			        t = t/(1+h2); // rescale so that t does not get bigger than 1
    			        if (t<0) { t=0; }
				
				//p.color = linear_interpolation(black,white,t)
				t=1.0-t;
				r=r*t;
				g=g*t;
				b=b*t;

				col=vec4(r,g,b,1.0);
			}

			finalcol+=col;
		}
	}
	gl_FragColor = vec4(finalcol/double(sqrsamplepixels));
}
  • Ultrafractal[10]
  • 方向性 DE,可用于斜率着色

与... 比较

[编辑 | 编辑源代码]

参考文献

[编辑 | 编辑源代码]
  1. kerrymitchellart : uf1-5
  2. Eamonn O'Brien-Strain 的《探索曼德勃罗集》
  3. Clapham, C.; Nicholson, J. (2009). "牛津简明数学词典,梯度" (PDF). Addison-Wesley. p. 348. 从 原文 (PDF) 存档于 2013 年 10 月 29 日. 检索于 2013 年 9 月 1 日.
  4. hiddendimension 斜率教程 2
  5. hiddendimension 斜率教程 3
  6. hiddendimension 教程:斜率教程 9
  7. hiddendimension 斜率教程 7
  8. fractalforums.org : 在分形中渲染斜率的算法
  9. fractalforums.org : 在分形中渲染斜率的算法
  10. ultrafractal 标准公式 : 斜率
华夏公益教科书