答案 0 :(得分:0)
在更深的缩放中,不仅轮廓比基本图像更紧密(“风景”上升得更快),而且所使用的调色板具有较小的过渡。基本图像中使用的调色板在相邻轮廓之间的颜色值上有较大的阶梯,从深蓝色到黄色仅需9阶梯。
如果仅在从一个轮廓到下一个轮廓的三个基色之一中使用单个值步长,您仍然可以辨别出差异,但差异不那么明显,显得更加平滑。我将使用预先计算的查找表来完成此操作。
答案 1 :(得分:0)
尝试使用计算的调色板而不是纹理
例如,这是我的:
更高的详细信息需要更高的迭代计数
那么您获得了多少次迭代?如果我应用#1 并使用n=200
迭代,则:
我明白了:
或多或少与您的情况类似(除了长宽比,但仍不确定我们有相同的设置...)。迭代次数不仅会影响细节计数,还会影响结果的整体亮度,因此请注意不要使用过多或过少。
缩放
开始缩放后,详细信息将开始出现在更深的位置...这是n=2000
,并从右侧缩放了第三份副本...
如您所见,有很多细节在上一张图像中不可见
进一步的改进
您可以使用非线性比例从迭代到颜色进行映射。因此再次进行相同的缩放,但是使用t=pow(t,0.5);
作为颜色的参数...
您可以看到结果看起来更好(更平滑)...
我能想到的最后一件事是实现某种HDR ...,因此,用较小的n
计算第一个基础图像,然后对其进行检查并找到细节较低(几乎没有颜色变化)的区域并重新渲染它们具有较高的n
,直到没有此类区域为止。对于每个n
,您可以稍微调整参数去线性化函数...
您还可以找到整个结果的min和max参数,并仅从覆盖该光谱的整个光谱范围内计算颜色,例如:
l = 400 + 300*(i-imin)/(imax-imin)
其中l
是色谱图[nm]
中的波长,i
是最终迭代,而imin,imax
是整个图像的最小值和最大值。我无法轻松尝试,因为我需要将GLSL渲染重写为两遍渲染器。
您可以做的另一件事是使用直方图代替min max ...但这也是多遍技术...
[Edit1]匹配
此外,在与外来图像进行比较时,请确保它们使用相同的图像集...否则,您将桔子与苹果进行比较。当我仔细观察它的明显点时,我得到了相同的集合,但x ...的比例不同,并且视图放大了分形的特定点。经过一些调整后,我发现最匹配的是:
[Edit2]直方图
修改我的代码以支持多遍渲染后,我可以应用直方图方法...所以
将Mandelbrot渲染为纹理
但是代替颜色呈现迭代索引...
计算渲染内容的直方图
找到要重新着色的索引范围
直方图将包含许多像素数为零或较小的条目...然后会有一组较高的值(这是您要查找的范围),之后将再次为较小或零的值...最重要的是,最后一个值可能包含大量像素(即黑色空白区域),并且可能存在一个或多个非常高的值,这些值过于独立于主要组。如果我将80%的光谱色用于主要组/范围,将10%用于其之前的索引,将10%用于其之后的索引,则结果如下:
以下是修改后的GLSL代码,其缩放比例,缩放比例已缩放,并可在单次/多遍渲染之间切换:
// Vertex
#version 420 core
layout(location=0) in vec2 pos; // glVertex2f <-1,+1>
out smooth vec2 p; // texture end point <0,1>
void main()
{
p=pos;
gl_Position=vec4(pos,0.0,1.0);
}
// Fragment
#version 420 core
#define multi_pass
uniform vec2 p0=vec2(0.0,0.0); // mouse position <-1,+1>
uniform float zoom=1.000; // zoom [-]
uniform int n=4000; // iterations [-]
in smooth vec2 p;
out vec4 col;
#ifdef multi_pass
vec3 spectral_color(float l) // RGB <0,1> <- lambda l <400,700> [nm]
{
float t; vec3 c=vec3(0.0,0.0,0.0);
if ((l>=400.0)&&(l<410.0)) { t=(l-400.0)/(410.0-400.0); c.r= +(0.33*t)-(0.20*t*t); }
else if ((l>=410.0)&&(l<475.0)) { t=(l-410.0)/(475.0-410.0); c.r=0.14 -(0.13*t*t); }
else if ((l>=545.0)&&(l<595.0)) { t=(l-545.0)/(595.0-545.0); c.r= +(1.98*t)-( t*t); }
else if ((l>=595.0)&&(l<650.0)) { t=(l-595.0)/(650.0-595.0); c.r=0.98+(0.06*t)-(0.40*t*t); }
else if ((l>=650.0)&&(l<700.0)) { t=(l-650.0)/(700.0-650.0); c.r=0.65-(0.84*t)+(0.20*t*t); }
if ((l>=415.0)&&(l<475.0)) { t=(l-415.0)/(475.0-415.0); c.g= +(0.80*t*t); }
else if ((l>=475.0)&&(l<590.0)) { t=(l-475.0)/(590.0-475.0); c.g=0.8 +(0.76*t)-(0.80*t*t); }
else if ((l>=585.0)&&(l<639.0)) { t=(l-585.0)/(639.0-585.0); c.g=0.84-(0.84*t) ; }
if ((l>=400.0)&&(l<475.0)) { t=(l-400.0)/(475.0-400.0); c.b= +(2.20*t)-(1.50*t*t); }
else if ((l>=475.0)&&(l<560.0)) { t=(l-475.0)/(560.0-475.0); c.b=0.7 -( t)+(0.30*t*t); }
return c;
}
#endif
void main()
{
int i,j;
vec2 pp;
float x,y,q,xx,yy;
pp=(p/zoom)-p0; // y (-1.0, 1.0)
pp.x-=0.5; // x (-1.5, 0.5)
for (x=0.0,y=0.0,xx=0.0,yy=0.0,i=0;(i<n)&&(xx+yy<4.0);i++)
{
q=xx-yy+pp.x;
y=(2.0*x*y)+pp.y;
x=q;
xx=x*x;
yy=y*y;
}
#ifndef multi_pass
// RGB
q=float(i)/float(n);
q=pow(q,0.2);
col=vec4(spectral_color(400.0+(300.0*q)),1.0);
#else
// i
float r,g,b;
r= i &255; r/=255.0;
g=(i>> 8)&255; g/=255.0;
b=(i>>16)&255; b/=255.0;
col=vec4(r,g,b,255);
#endif
}
已拍摄图片
n=4095; // max iterations
zoom=1763.0; // zoom [-]
p0.x=0.1483064; // center position
p0.y=0.3742866;
第二遍渲染如下:
// globals
const int N=4095; // this is the max count of iterations
OpenGLtexture txr;
// helper functions
DWORD spectral_color(float l) // RGB <0,1> <- lambda l <400,700> [nm]
{
float t; float r,g,b; DWORD c,x; r=0.0; g=0.0; b=0.0;
if ((l>=400.0)&&(l<410.0)) { t=(l-400.0)/(410.0-400.0); r= +(0.33*t)-(0.20*t*t); }
else if ((l>=410.0)&&(l<475.0)) { t=(l-410.0)/(475.0-410.0); r=0.14 -(0.13*t*t); }
else if ((l>=545.0)&&(l<595.0)) { t=(l-545.0)/(595.0-545.0); r= +(1.98*t)-( t*t); }
else if ((l>=595.0)&&(l<650.0)) { t=(l-595.0)/(650.0-595.0); r=0.98+(0.06*t)-(0.40*t*t); }
else if ((l>=650.0)&&(l<700.0)) { t=(l-650.0)/(700.0-650.0); r=0.65-(0.84*t)+(0.20*t*t); }
if ((l>=415.0)&&(l<475.0)) { t=(l-415.0)/(475.0-415.0); g= +(0.80*t*t); }
else if ((l>=475.0)&&(l<590.0)) { t=(l-475.0)/(590.0-475.0); g=0.8 +(0.76*t)-(0.80*t*t); }
else if ((l>=585.0)&&(l<639.0)) { t=(l-585.0)/(639.0-585.0); g=0.84-(0.84*t) ; }
if ((l>=400.0)&&(l<475.0)) { t=(l-400.0)/(475.0-400.0); b= +(2.20*t)-(1.50*t*t); }
else if ((l>=475.0)&&(l<560.0)) { t=(l-475.0)/(560.0-475.0); b=0.7 -( t)+(0.30*t*t); }
r*=255.0; g*=255.0; b*=255.0;
x=r; c =x;
x=g; c|=x<<8;
x=b; c|=x<<16;
return c;
}
...
// [multipass] this is executed after the shader renders its stuff
int hist[N+1],sz=txr.xs*txr.ys,i,i0,i1,a0,a1;
float t;
// get rendered image
glReadPixels(0,0,txr.xs,txr.ys,GL_RGBA,GL_UNSIGNED_BYTE,txr.txr);
// compute histogram
for (i=0;i<N;i++) hist[i]=0;
for (i=0;i<sz;i++) hist[txr.txr[i]&0x00FFFFFF]++;
// find the major used range
a0=txr.xs/4;
a1=txr.xs*4;
for (i0= 0;(i0<N)&&((hist[i0]<a0)||(hist[i0]>a1));i0++);
for (i1=N-1;(i1>0)&&((hist[i1]<a0)||(hist[i1]>a1));i1--);
// recolor it
for (i=0;i<sz;i++)
{
a0=txr.txr[i]&0x00FFFFFF;
if (a0<i0) t=(0.1*divide(a0 ,i0 ));
else if (a0>i1) t=(0.1*divide(a0-i1,N -i1))+0.9;
else t=(0.8*divide(a0-i0,i1-i0))+0.1;
txr.txr[i]=spectral_color(400.0+(300.0*t));
}
// render it back
scr.cls();
txr.bind();
glColor3f(1.0,1.0,1.0);
glBegin(GL_QUADS);
glTexCoord2f(0.0,1.0); glVertex2f(-1.0,+1.0);
glTexCoord2f(0.0,0.0); glVertex2f(-1.0,-1.0);
glTexCoord2f(1.0,0.0); glVertex2f(+1.0,-1.0);
glTexCoord2f(1.0,1.0); glVertex2f(+1.0,+1.0);
glEnd();
txr.unbind();
glDisable(GL_TEXTURE_2D);
我知道它使用了很多我没有分享的东西,但是直方图的用法很简单,足以将其移植到您的需求中...
所以现在只需要找到n
和位置/缩放的正确组合即可。
[Edit3]但是,即使这还不够
然后您可以实施小数转义有关更多信息,请参见: