跳转到内容

分形/shadertoy

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

Shadertoy [1][2]

与 Shadertoy 相关的 GLSL ES 部分

Preprocessor: # #define #undef #if #ifdef #ifndef #else #elif #endif #error #pragma #extension #version #line
Operators: () + - ! * / % << >> < > <= >= == != && ||
Comments: // /* */
Types: void bool int float vec2 vec3 vec4 bvec2 bvec3 bvec4 ivec2 ivec3 ivec4 mat2 mat3 mat4 sampler2D
Function Parameter Qualifiers: [none], in, out, inout
Global Variable Qualifiers: const
Vector Components: .xyzw .rgba .stpq
Flow Control: if else for return break continue
Output: vec4 gl_FragColor
Input: vec4 gl_FragCoord

主要有四种类型:[3]

  • float
  • int
  • bool
  • sampler
vec2, vec3, vec4			2D, 3D and 4D floating point vector
ivec2, ivec3, ivec4			2D, 3D and 4D integer vector
bvec2, bvec3, bvec4			2D, 3D and 4D boolean vectors
\\ matrix types:
mat2, mat3, mat4			2x2, 3x3, 4x4 floating point matrix
\\
sampler1D, sampler2D, sampler3D		1D, 2D and 3D texture
samplerCube				Cube Map texture
sampler1Dshadow, sampler2Dshadow	1D and 2D depth-component texture

内置函数

[编辑 | 编辑源代码]
type radians (type degrees)
type degrees (type radians)
type sin (type angle)
type cos (type angle)
type tan (type angle)
type asin (type x)
type acos (type x)
type atan (type y, type x)
type atan (type y_over_x)
type pow (type x, type y)
type exp (type x)
type log (type x)
type exp2 (type x)
type log2 (type x)
type sqrt (type x)
type inversesqrt (type x)
type abs (type x)
type sign (type x)
type floor (type x)
type ceil (type x)
type fract (type x)
type mod (type x, float y)
type mod (type x, type y)
type min (type x, type y)
type min (type x, float y)
type max (type x, type y)
type max (type x, float y)
type clamp (type x, type minV, type maxV)
type clamp (type x, float minV, float maxV)
type mix (type x, type y, type a)
type mix (type x, type y, float a)
type step (type edge, type x)
type step (float edge, type x)
type smoothstep (type a, type b, type x)
type smoothstep (float a, float b, type x)
mat matrixCompMult (mat x, mat y)
float length (type x)
float distance (type p0, type p1)
float dot (type x, type y)
vec3 cross (vec3 x, vec3 y)
type normalize (type x)
type faceforward (type N, type I, type Nref)
type reflect (type I, type N)
type refract (type I, type N,float eta)
bvec lessThan(vec x, vec y)
bvec lessThan(ivec x, ivec y)
bvec lessThanEqual(vec x, vec y)
bvec lessThanEqual(ivec x, ivec y)
bvec greaterThan(vec x, vec y)
bvec greaterThan(ivec x, ivec y)
bvec greaterThanEqual(vec x, vec y)
bvec greaterThanEqual(ivec x, ivec y)
bvec equal(vec x, vec y)
bvec equal(ivec x, ivec y)
bvec equal(bvec x, bvec y)
bvec notEqual(vec x, vec y)
bvec notEqual(ivec x, ivec y)
bvec notEqual(bvec x, bvec y)
bool any(bvec x)
bool all(bvec x)
bvec not(bvec x)
vec4 texture2D(sampler2D sampler, vec2 coord )
vec4 texture2D(sampler2D sampler, vec2 coord, float bias)
vec4 textureCube(samplerCube sampler, vec3 coord)
vec4 texture2DProj(sampler2D sampler, vec3 coord )
vec4 texture2DProj(sampler2D sampler, vec3 coord, float bias)
vec4 texture2DProj(sampler2D sampler, vec4 coord)
vec4 texture2DProj(sampler2D sampler, vec4 coord, float bias)
type dFdx( type x ), dFdy( type x )
type fwidth( type p )

将 Shadertoy 着色器转换为

  • GLSL Sandbox 代码[4]

着色器描述

[编辑 | 编辑源代码]

"着色器是在 GPU 中执行的程序。一个着色器实际上包含两个程序:顶点着色器和片段(或像素)着色器。" [5]

着色器是一个“单个程序,作用于单个像素,但 Shadertoy 和 WebGL 将其(同时)运行在视窗中的每个像素上……这要归功于 GPU 加速的强大功能” [6]

Shadertoy 着色器的类型

  • 图像着色器
  • 声音着色器
  • VR 着色器

mainImage 函数

[编辑 | 编辑源代码]

图像着色器实现 mainImage() 函数,以便通过计算每个像素的颜色来生成过程图像。

预期此函数对每个像素调用一次,并且主机应用程序负责提供正确的输入并从中获取输出颜色并将其分配给屏幕像素。

原型是

void mainImage( out vec4 fragColor, in vec2 fragCoord );

"uniform 用于从着色器外部获取值,并将其输入到着色器中……uniform 可以是向量、浮点数、浮点数组、整数和整数数组。" [7]

可以使用以下 **uniform 变量**(Shadertoy 特定输入)为着色器提供不同类型的每帧静态信息

类型 名称 描述
uniform vec3 iResolution 视窗分辨率。iResolution 的宽度/高度分别设置为 x 和 y。z 是像素纵横比,通常为 1.0
uniform float iGlobalTime 当前时间(以秒为单位)
uniform float iChannelTime[4] 通道时间(如果为视频或音频),以秒为单位
uniform vec3 iChannelResolution0..3 每个通道的输入纹理分辨率
uniform vec4 iMouse xy = 当前像素坐标(如果 LMB 已按下)。zw = 点击像素
uniform sampler2D iChannel{i} 输入纹理 i 的采样器
uniform vec4 iDate 年、月、日、时间(以秒为单位),分别存储在 .xyzw 中
uniform float iSampleRate 声音采样率(通常为 44100)

类型

  • 像素
    • x 从 0 到宽度
    • y 从 0 到高度
  • 归一化:从 0.0 到 1.0
  • 世界:任意范围

mainImage() 函数的输入变量是 **fragCoord**(= GLSL 中的 gl_FragCoord)

它包含当前像素位置(坐标)(以像素为单位),着色器需要为此计算颜色。我们可以访问它的 x 和 y 值

**坐标**以像素单位表示

分辨率通过 iResolution uniform 传递到着色器(参见上表)。

要**归一化**坐标(归一化设备坐标 = NDC),请执行以下操作

// Converting (x,y) to range [0,1]
float x = gl_FragCoord.x / iResolution.x; // 
float y = gl_FragCoord.y / iResolution.y;

"现在我们的 x 和 y 在 0..1 范围内,我们不再关心(屏幕)分辨率、宽度或长度。" [8]

**纵横比**[9]

x *= iResolution.x / iResolution.y;

"对于图像着色器,常规的 gl_FragColor 用作输出通道。目前不是强制性的,但建议将 alpha 通道保留为 1.0;"

第一个图像着色器

[编辑 | 编辑源代码]
// This shader computes the same color ( red = 1.0,0.0,0.0 ) for every pixel
// static image 
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// color = r,g,b,a 
	// every value is in range [0.0, 1.0]
	fragColor = vec4(1.0,0.0,0.0,1.0);
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    float r = fragCoord.x / iResolution.x;
    float g = fragCoord.y / iResolution.y;
    float b = fragCoord.x / iResolution.y;
    fragColor = vec4(r,g,b,1.0);
}

水平红色渐变

// based on the code by Omar Shehata
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    float x = fragCoord.x; //We obtain our coordinates for the current pixel
    x = x / iResolution.x; //We divide the coordinates by the screen size
    // Now x is 0 for the leftmost pixel, and 1 for the rightmost pixel
    //Set its red component to the normalized x value = red gradient from left to right 
    fragColor = vec4(x, 0.0,  0.0, 1.0);
}

垂直绿色渐变

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    float y = fragCoord.y; //We obtain our coordinates for the current pixel
    y = y / iResolution.y; //We divide the coordinates by the screen size
    // Now y is 0 for the bottom pixel, and 1 for the up  pixel
    //Set its red component to the normalized x value
    fragColor = vec4( 0.0, y, 0.0, 1.0);
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    
    float x = fragCoord.x/iResolution.x; // 0.0 < x < 1.0
    float y = fragCoord.y/iResolution.y; // 
    
    
    fragColor = vec4(0.0,1.0,0.0,1.0); // green = background
    
    if( x > 0.5 && y > 0.5) {fragColor = vec4(1.0,0.0,0.0,1.0);} // red = upper right
    if( x < 0.5 && y < 0.5) {fragColor = vec4(0.0,0.0,1.0,1.0);} // blue = lower left
}
// https://www.shadertoy.com/view/MssXWn
// bu Lukas Pukenis http://www.letsdive.in/2014/05/11/glsl-basics/
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {			
	float thicknessH = 0.01;
	float thicknessV = 0.01;
	
	float y = fragCoord.y / iResolution.y;
	float x = fragCoord.x / iResolution.x;

	float diffY = abs(0.5 - y);
	float diffX = abs(0.5 - x);
	
	if ( diffY < thicknessH || diffX < thicknessV) {
		fragColor = vec4(1.0, 0.0, 0.0, 1.0 );
	} else {
		fragColor = vec4(0.0, 0.0, 0.0, 1.0 );
	}
		
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{   
    float x = fragCoord.x/iResolution.x; // 0.0 < x < 1.0
    float y = fragCoord.y/iResolution.y; // 
    vec2 center = vec2(0.5, 0.5); // center of the image
    
    fragColor = vec4(0.0,1.0,0.0,1.0); // green = background
    if( abs(center.x - x) < 0.2 && abs(center.y - y) < 0.2) {fragColor = vec4(1.0,0.0,0.0,1.0);} // red rectangle in center of image 
}

正方形

[编辑 | 编辑源代码]
void mainImage( out vec4 fragColor, in vec2 fragCoord )
    
     
{   float ratio = iResolution.x / iResolution.y; // aspect ratio of the window : https://github.com/mattdesl/lwjgl-basics/wiki/ShaderLesson3
    float x = ratio*fragCoord.x/iResolution.x; // 0.0 < x < 1.0*ratio
    float y = fragCoord.y/iResolution.y; //  0.0 < y < 1.0
    vec2 center = vec2(ratio*0.5, 0.5); // center of the image 
 
    fragColor = vec4(0.0,1.0,0.0,1.0); // green = background
    if( abs(center.x - x) < 0.2 && abs(center.y - y) < 0.2) {fragColor = vec4(1.0,0.0,0.0,1.0);} // red rectangle in center of image 
}

使用像素坐标 的圆形 

// https://www.shadertoy.com/view/Mdf3Df
// circle using pixel coordinate
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	
    // the center of the texture
    vec2 center = vec2(iResolution.x/2.0,iResolution.y/2.0); 
	
    // current pixel location
    vec2 loc = fragCoord.xy;
	
    // how far we are from the center
    float radius=length(loc-center);
	
    
    if (radius<100.0)
        fragColor = vec4(1,0,0,1); // if we are within our circle, paint it red
    else
        fragColor = vec4(0,0,0,1); // black background
}

使用世界坐标中心/半径平面描述 的圆形

vec2 center = vec2(0.0,0.0); // center of the image in world units
float radius = 2.0; // Radius is defined as "the difference in imaginary coordinate between the center and the top of the axis-aligned view rectangle".

vec2 GiveCoordinate(vec2 center, float radius, vec2 fragCoord, vec3 iResolution)
{
  // from pixel to world coordinate   
  // start with pixel coordinate : now point=(0,0) is left bottom and point=(iResolution.x, iResolution.y) is right top   
  float x = (fragCoord.x -  iResolution.x/2.0)/ (iResolution.y/2.0);
  float y = (fragCoord.y -  iResolution.y/2.0)/ (iResolution.y/2.0);
  vec2 c = vec2(center.x + radius*x, center.y + radius*y) ;  
  return c ; // now coordinate are measured in world units : from 0.0 t 1.0
}

vec3 GiveColor ( vec2 c, vec2 circle_center, float circle_radius)
{
    vec3 color = vec3(1.0, 0.0, 035); // background 
    // draws a circle centered at circle_center 
    if ( length(circle_center-c)< circle_radius) {color = vec3(0.0, 0.0, 0.0);}
    return color;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord)
{   
    vec2 c =  GiveCoordinate(center, radius, fragCoord, iResolution);
    vec3 color = GiveColor(c, vec2(0.0, 0.9), 1.5);     
    fragColor = vec4(color,1.0); //   
}

Julia 集

[编辑 | 编辑源代码]

Julia 集 

  • 整数逃逸时间和用于外部的水平集方法
  • 内部的纯色(红色)
// based on the code by gltracy
// https://www.shadertoy.com/view/XsS3Rm

const int i_max = 2055;
vec2 c = vec2( -0.12256, 0.74486);
float er2 = 4.0; // er= er*er escape radius

vec2 complex_square( vec2 v ) {
	return vec2(
		v.x * v.x - v.y * v.y,
		v.x * v.y * 2.0
	);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    
    // compute coordinate 
	vec2 z = fragCoord.xy - iResolution.xy * 0.5;
	z *= 2.5 / min( iResolution.x, iResolution.y );
	

	
	
	float scale = 0.1;

	int count = 0;
	
    
    // iterations 
	for ( int i = 0 ; i < i_max; i++ ) {
        
		z = c + complex_square( z );
		count = i;
        if ( dot(z,z) > er2 ) {  break; }
	}
	
    // color 
    if (count == i_max-1) {fragColor = vec4(1.0, 0.0,0.0,1.0);} // filled-in Julia set = red
    else  fragColor = vec4(1.0- float( count ) * scale ); // exterior 
}

轨道陷阱

[编辑 | 编辑源代码]

轨道陷阱,抛物线棋盘格

// https://www.shadertoy.com/view/4dy3RR
// Orbit trapped julia by maeln
#define MAXITER 128

vec2 cmul(vec2 i1, vec2 i2) 
{
    return vec2(i1.x*i2.x - i1.y*i2.y, i1.y*i2.x + i1.x*i2.y);
}

vec3 julia(vec2 z, vec2 c)
{
    int i = 0;
    vec2 zi = z;
    
    float trap1 = 10e5;
    float trap2 = 10e5;
    
    for(int n=0; n < MAXITER; ++n)
    {
        if(dot(zi,zi) > 4.0)
            break;
        i++;
        zi = cmul(zi,zi) + c;
		
        // Orbit trap
        trap1 = min(trap1, sqrt(zi.x*zi.y));
        trap2 = min(trap2, sqrt(zi.y*zi.y));
    }
    
    return vec3(i,trap1,trap2);
}

vec4 gen_color(vec3 iter)
{
    float t1 = 1.0+log(iter.y)/8.0;
    float t2 = 1.0+log(iter.z)/16.0;
    float t3 = t1/t2;
    
    //vec3 comp = vec3(t1,t1,t1);
    vec3 red = vec3(0.9,0.2,0.1);
    vec3 black = vec3(1.0,1.0,1.0);
    vec3 blue = vec3(0.1,0.2,0.9);
    vec3 comp = mix(blue,black,vec3(t2));
    comp = mix(red,comp,vec3(t1));
    
    return vec4(comp, 1.0);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 z = 2.*(2.*fragCoord.xy - iResolution.xy) / iResolution.x;
    // Display the julia fractal for C = (-0.8, [0.0;0.3]).
    vec3 iter = julia(z, vec2(cos(iTime/5.0), mix(0.0, 0.3, sin(iTime))));
	fragColor = gen_color(iter);
}


动力学

[编辑 | 编辑源代码]

二次一维多项式 fc(z)=z²+c 的动力学

// Created by inigo quilez - iq/2013
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
// 
//-----------------https://www.shadertoy.com/view/MdX3zN-------------------------------------------
//
// Dynamics for quadratic 1D polynomials fc(z)=z²+c
//
// * Orange: the Fatou set Kc. 
// * Black: the Julia set Jc.
// * Checkerboard distortion: the Boettcher map phi(z). 
// * Checkerboard shadowing: the gradient of the Green's function, log|phi(z)|
// * Blue: the two fixed points. 
// * Green, the period 2 fixed points.
// * White: c
// * Yellow: the Koening coordinates
//
// Some theory:
//
// * c (white) belongs to Kc (orange), for these are all connected Julia sets. 
//
// * When both fixed points (blue) are in Jc but not in Kc, or in other words, when both points
//   are repeling (derivative of fc(z) is bigger than one), c does not belong to the Mandelbrot 
//   set's main cardioid, but to bulbs of higher period. In that case Kc (orange) is made of several 
//   branches (as many as the period of the bul)
//
// * When one of the two fixed points (blue dots) is inside Kc, meanins it is attractive (derivative
//   of fc(z) < 1), then c belongs to the main cardiod of the Mandelbrot set, and Kc is a single piece 
//   shape.
//
// * When the period 2 fixed points are always repelling (belong to Jc, not to Kc) except for the sets 
//   that have c belonging to the period-2 bulb of the Mandelbrot set. In those cases, the green dots
//   become attrative and sit inside the orange area Kc.
// 
// * The Koening coordinates can only been seen when c belongs to the main cariod of the Madelbrot set
//
//------------------------------------------------------------

// complex number operations
vec2 cadd( vec2 a, float s ) { return vec2( a.x+s, a.y ); }
vec2 cmul( vec2 a, vec2 b )  { return vec2( a.x*b.x - a.y*b.y, a.x*b.y + a.y*b.x ); }
vec2 cdiv( vec2 a, vec2 b )  { float d = dot(b,b); return vec2( dot(a,b), a.y*b.x - a.x*b.y ) / d; }
vec2 csqrt( vec2 z ) { float m = length(z); return sqrt( 0.5*vec2(m+z.x, m-z.x) ) * vec2( 1.0, sign(z.y) ); }
vec2 conj( vec2 z ) { return vec2(z.x,-z.y); }
vec2 cpow( vec2 z, float n ) { float r = length( z ); float a = atan( z.y, z.x ); return pow( r, n )*vec2( cos(a*n), sin(a*n) ); }

//------------------------------------------------------------

float argument( in vec2 p )
{
	float f = atan( p.y, p.x );
	if( f<0.0 ) f += 6.2831;
	f = f/6.2831;
	return f;
}

float grid( in vec2 p )
{
	vec2 q = 16.0*p;
	vec2 r = fract( q );
    float fx = smoothstep( 0.05, 0.06, r.x ) - smoothstep( 0.94, 0.95, r.x );
    float fy = smoothstep( 0.05, 0.06, r.y ) - smoothstep( 0.94, 0.95, r.y );
		
    return 0.5 + 0.5*mod( floor(q.x)+floor(q.y), 2.0 );
}

float cross( vec2 a, vec2 b )
{
    return a.x*b.y - a.y*b.x;
}

bool isInTriangle( in vec2 p, in vec2 a, in vec2 b, in vec2 c )
{
    vec3 di = vec3( cross( b - a, p - a ), 
				    cross( c - b, p - b ), 
				    cross( a - c, p - c ) );
			
    return all(greaterThan(di,vec3(0.0)));
}

float distanceToSegment( vec2 a, vec2 b, vec2 p )
{
	vec2 pa = p - a;
	vec2 ba = b - a;
	float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
	
	return length( pa - ba*h );
}

vec3 circle( vec3 bcol, vec3 col, in vec2 a, in vec2 b )
{
	float rr = 0.04;
	
	vec3 res = mix( bcol, col, 1.0 - smoothstep( rr-0.01, rr, length(a-b) ) );
	
	float f = smoothstep( rr-0.01, rr, length(a-b) ) - smoothstep( rr, rr+0.01, length(a-b) );
		
	return mix( res, vec3(0.0), f );
}

//------------------------------------------------------------

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	vec2 uv = fragCoord.xy/iResolution.xy;
	
	vec2 p = -1.0 + 2.0*uv;
	p.x *= iResolution.x/iResolution.y;
	
	float at = mod( (iTime+.5)/5.0, 8.0 );

	vec2 c =    vec2(-0.800, 0.100);
	c = mix( c, vec2( 0.280,-0.490), smoothstep(0.0,0.1,at) );
	c = mix( c, vec2(-0.500,-0.500), smoothstep(1.0,1.1,at) );
	c = mix( c, vec2(-0.160, 0.657), smoothstep(2.0,2.1,at) );
	c = mix( c, vec2(-0.650, 0.100), smoothstep(3.0,3.1,at) );
	c = mix( c, vec2(-0.114, 0.650), smoothstep(4.0,4.1,at) );
	c = mix( c, vec2(-0.731, 0.166), smoothstep(5.0,5.1,at) );
	c = mix( c, vec2(-0.100,-0.660), smoothstep(6.0,6.1,at) );
    c = mix( c, vec2(-0.800, 0.100), smoothstep(7.0,7.1,at) );
	
	// get the 2 fixed points
	vec2 one = vec2( 1.0, 0.0 );

    vec2 fix1_1 = 0.5*( one + csqrt( one - 4.0*c ) );
    vec2 fix1_2 = 0.5*( one - csqrt( one - 4.0*c ) );
	vec2 fix2_1 = -(csqrt(-4.0*c-3.0*one)+one)/2.0;
	vec2 fix2_2 =  (csqrt(-4.0*c-3.0*one)-one)/2.0;
	vec2 fix2_3 = -(csqrt( one-4.0*c)-one)/2.0;
	vec2 fix2_4 =  (csqrt( one-4.0*c)+one)/2.0;

		
	vec2 z = p;
	vec2 dz = vec2( 1.0, 0.0 );

	vec2 ph = z;
	vec2 gr = vec2( log(length(z)), atan(z.y,z.x) );
	float t = 0.0;

	for( int i=0; i<512; i++ )
	{
		if( dot(z,z)>10000.0 ) continue;

        t += 1.0;

        // derivative
        dz = 2.0*cmul( z, dz );

        // point
        z = cmul(z,z) + c;

        vec2 a = cdiv(z,z-c);
        float s = pow( 0.5, t );

        // phi
        ph = cmul( ph, cpow(a, s) );
		
        // green
        gr.x += log(length(a)) * s;
        float aa = atan(a.y,a.x);
        if( isInTriangle( z, vec2(0.0), fix1_2, c ) )
        {
            aa -= sign(aa)*2.0*3.14159;
        }
        gr.y += aa * s;
	}
	
	
	vec3 col = vec3(1.0,0.65,0.10);
	
	if( t<511.0 )
	{
        float s = pow( 0.5, t );
        vec2  phib = cpow( z, s );
        float phiR = length( phib );
        float greenR = log(length(z)) * s;
        float greenI = argument(z*s);
        float d = log( length(z) ) * length(z) / length(dz);
        vec2  gradG = -conj(cmul( dz, conj(z) ));
        float n = t/50.0;
        float sn = -log2(abs(greenR))/50.0;
	
        col = vec3( 0.6 + 0.4*dot(normalize(-gradG),vec2(0.707)) );

        col *= vec3( grid( ph ) );
        col *= vec3(1.0)*clamp(d*50.0,0.0,1.0);
	}
	else
	{
		z = p;

		float t = 0.0;
		for( int i=0; i<200; i++ )
		{
			if( length(z-fix1_2)>0.001 )
			{
			z = cmul(z,z) + c;
			t += 1.0;
			}
		}
		vec2 fix = fix1_2;
		if( length(2.0*fix1_1)<1.0 ) fix=fix1_1;
		if( length(2.0*fix)<1.0 )
		{
		    vec2 ph = cdiv( z - fix, cpow(2.0*fix,t) );
		    float g = log(length(ph));
		    float l = 1.0 - 0.1*smoothstep( 0.7, 0.71, sin(48.0*g) );
		    col += 0.1*(abs(g));
		    ph = 1.0*vec2( length(ph), atan(ph.y,ph.x)/3.14 );
			col *= l;
		}
		
	}

	// color depending of attractive/repulsive fixed point
	col = circle( col, vec3(1.0,1.0,1.0), p, c );

	vec3 col2 = vec3(0.0,1.0,0.0);
	col = circle( col, col2, p, fix2_1 );
	col = circle( col, col2, p, fix2_2 );
	col = circle( col, col2, p, fix2_3 );
	col = circle( col, col2, p, fix2_4 );

	vec3 col1 = vec3(0.0,0.7,1.0);
	col = circle( col, col1, p, fix1_1 );
	col = circle( col, col1, p, fix1_2 );

	fragColor = vec4( col, 1.0 );
}

曼德勃罗集

[编辑 | 编辑源代码]

布尔逃逸时间

[编辑 | 编辑源代码]

曼德勃罗集 

  • 布尔逃逸时间方法
    • 外部的纯色 background_color = vec3(1.0, 0.0, 035);
  • 内部的纯色 mandel_color = vec3(0.0, 0.0, 0.0);

使用 的平面描述

简短版本

[编辑 | 编辑源代码]
// https://www.shadertoy.com/view/4sVGWz
// Simple_Mandelbrot by Created by r1nat in 2016-Jan-29

//Based on explanation http://www.hiddendimension.com/fractalmath/Divergent_Fractals_Main.html
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 c = fragCoord.xy / iResolution.xy;
    //scaling real axis to [-2.5, 1.5] and  imaginary axis to  [-1.5, 1.5]
    c = c * vec2(4,3) - vec2(2.5, 1.5); 

    vec2 z = vec2(0);
    fragColor = vec4(0);
    
    for (int i=0;i<100;i++)
    {
        if (z.x * z.x + z.y * z.y >= 4.) 
        {
            fragColor = vec4(1);
            break;
        }
        
       z = vec2(z.x*z.x - z.y*z.y, 2.*z.x*z.y) + c;
    }
}


长版本

[编辑 | 编辑源代码]
// image parameters in world coordinate 
vec2 center = vec2(-0.75,0.0); // center of the image in world units : http://mightymandel.mathr.co.uk/gallery.html
float radius = 1.25; // Radius is defined as "the difference in imaginary coordinate between the center and the top of the axis-aligned view rectangle".

// escape time algorithm
 float er2 = 40.0; // square of escape radius :  er2 = er*er  so er = 2.0  
 #define imax 1000

// rgb colors 
vec3 background_color = vec3(1.0, 0.0, 035);
vec3 mandel_color = vec3(0.0, 0.0, 0.0);

// compute pixel coordinate in world units 
vec2 GiveCoordinate(vec2 center, float radius, vec2 fragCoord, vec3 iResolution)
{
  // from pixel to world coordinate   
  // start with pixel coordinate : now point=(0,0) is left bottom and point=(iResolution.x, iResolution.y) is right top   
  float x = (fragCoord.x -  iResolution.x/2.0)/ (iResolution.y/2.0);
  float y = (fragCoord.y -  iResolution.y/2.0)/ (iResolution.y/2.0);
  vec2 c = vec2(center.x + radius*x, center.y + radius*y) ;  
  return c ; // now coordinate are measured in world units : from 0.0 t 1.0
}
 
// square of vector ( = complex number) 
vec2 complex_square( vec2 v ) {
	return vec2(
		v.x * v.x - v.y * v.y,
		v.x * v.y * 2.0
	);
}

bool CheckIfIsInsideMandelbrot(vec2 c)
{
    int count=0;
    vec2 z = vec2(0.0, 0.0); // initial value is a critical point 
    
    // iterations 
    for ( int i = 0 ; i < imax; i++ ) {
 	z = c + complex_square( z ); // z = fc(z) = z^2+c
	count = i;
        if ( dot(z,z) > er2 ) {  break; } 
	}
    if (count==imax-1) 
         {return true;}
         else return false;
}

vec3 GiveColor ( vec2 c )
{
    bool IsInside =  CheckIfIsInsideMandelbrot(c); 
     
    if ( IsInside) {return mandel_color; }
    else return background_color;
}
 
void mainImage( out vec4 fragColor, in vec2 fragCoord)
{   
    vec2 c =  GiveCoordinate(center, radius, fragCoord, iResolution);
    vec3 color = GiveColor(c);     
    fragColor = vec4(color,1.0); //   
}

曼德勃罗集 

使用 的平面描述

结果在这里

// image parameters in world coordinate 
//vec2 center = vec2(-0.75,0.0); // center of the image in world units : http://mightymandel.mathr.co.uk/gallery.html
//float radius = 1.25; // Radius is defined as "the difference in imaginary coordinate between the center and the top of the axis-aligned view rectangle".
 vec2 center = vec2(-0.771139525,-0.115216065);
 float radius = 0.001;

// escape time algorithm
 float er2 = 4.0; // square of escape radius :  er2 = er*er  so er = 2.0  
 #define imax 500

// compute pixel coordinate in world units 
vec2 GiveCoordinate(vec2 center, float radius, vec2 fragCoord, vec3 iResolution)
{
  // from pixel to world coordinate   
  // start with pixel coordinate : now point=(0,0) is left bottom and point=(iResolution.x, iResolution.y) is right top   
  float x = (fragCoord.x -  iResolution.x/2.0)/ (iResolution.y/2.0);
  float y = (fragCoord.y -  iResolution.y/2.0)/ (iResolution.y/2.0);
  vec2 c = vec2(center.x + radius*x, center.y + radius*y) ;  
  return c ; // now coordinate are measured in world units : from 0.0 t 1.0
}
 
// based on the code by gltracy https://www.shadertoy.com/view/XsS3Rm
// square of vector ( = complex number) 
vec2 complex_square( vec2 v ) {
	return vec2(
		v.x * v.x - v.y * v.y,
		v.x * v.y * 2.0	);
}

// based on the code by gltracy https://www.shadertoy.com/view/XsS3Rm
int GiveLevel(vec2 c)
{
    int final_i = 0; // level
    vec2 z = vec2(0.0, 0.0); // initial value is a critical point 
    
  // iterations 
	for ( int i = 0 ; i < imax; i++ ) {
 
		z = c + complex_square( z ); // z = fc(z) = z^2+c
		final_i = i;
        if ( dot(z,z) > er2 ) {  break; } 
	}
  return final_i;          
    
}

vec3 GiveColor ( int i)
{
    
    vec3 color;
    
    if ( i < imax ) 
     // level set method  = LSM/M 
     // based on https://www.weheartswift.com/fractals-xcode-6/ by Silviu Pop 
     {  color.r = sin(float(i) / 3.0); // exterior of Mandelbrot set
        color.g = cos(float(i) / 6.0);
        color.b = cos(float(i) / 12.0 + 3.14 / 4.0);
    } 
    else color= vec3(0.0, 0.0, 0.0); // interior of mandelbrot set
    
    return color;
}
 
void mainImage( out vec4 fragColor, in vec2 fragCoord)
{   
    vec2 c =  GiveCoordinate(center, radius, fragCoord, iResolution);
    int level = GiveLevel(c );
    vec3 color = GiveColor(level);     
    fragColor = vec4(color,1.0); //   
}

二进制分解

[编辑 | 编辑源代码]
// image parameters in world coordinate 
vec2 center = vec2(-0.75,0.0); // center of the image in world units : http://mightymandel.mathr.co.uk/gallery.html
float radius = 1.5; // Radius is defined as "the difference in imaginary coordinate between the center and the top of the axis-aligned view rectangle".

// escape time algorithm
 float er2 = 100000.0; // square of escape radius :  er2 = er*er  so er = 1000.0;  
 #define imax 1000

// rgba colors 
vec4 up_color = vec4(1.0, 1.0, 1.0, 1.0);// target set up
vec4 down_color = vec4(0.0, 0.0, 0.0, 1.0); // target set down
vec4 mandel_color = vec4(0.0, 0.0, 0.0, 1.0); // inside

// compute pixel coordinate in world units 
vec2 GiveCoordinate(vec2 center, float radius, vec2 fragCoord, vec3 iResolution)
{
  // from pixel to world coordinate   
  // start with pixel coordinate : now point=(0,0) is left bottom and point=(iResolution.x, iResolution.y) is right top   
  float x = (fragCoord.x -  iResolution.x/2.0)/ (iResolution.y/2.0);
  float y = (fragCoord.y -  iResolution.y/2.0)/ (iResolution.y/2.0);
  vec2 c = vec2(center.x + radius*x, center.y + radius*y) ;  
  return c ; // now coordinate are measured in world units : from 0.0 t 1.0
}
 
// square of vector ( = complex number) 
vec2 complex_square( vec2 v ) {
	return vec2(
		v.x * v.x - v.y * v.y,
		v.x * v.y * 2.0
	);
}

int CheckType(vec2 c)
{
    int count=0;
    vec2 z = vec2(0.0, 0.0); // initial value is a critical point 
    
    // iterations 
    for ( int i = 0 ; i < imax; i++ ) {
 	z = c + complex_square( z ); // z = fc(z) = z^2+c
	count = i;
        if ( dot(z,z) > er2 ) {  break; } 
	}
    if (count==imax-1) 
         {return 0;}
         else 
              if (z.x>0.0) return 1; 
                         else return 2;
}

vec4 GiveColor ( vec2 c )
{
    int colorType =  CheckType(c); 
     
    if ( colorType==0) {return mandel_color; }
    if (colorType==1) return up_color;
    return down_color;
}
 
void mainImage( out vec4 fragColor, in vec2 fragCoord)
{   
    vec2 c =  GiveCoordinate(center, radius, fragCoord, iResolution);
    fragColor = GiveColor(c);     
       
}

平滑着色

[编辑 | 编辑源代码]
//see http://linas.org/art-gallery/escape/escape.html for more info on normalizing the Mandelbrot escape
// Smooth Mandelbrot Created by Justaway in 2015-Jan-2
// https://www.shadertoy.com/view/ltXGDN

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    float e=100.0;
	vec2 c = vec2(
        (fragCoord.x-iResolution.x/2.0)/iResolution.y,
        (fragCoord.y-iResolution.y/2.0)/iResolution.y);
    c*=2.5;
    int ic=0;
    vec2 tz;
    vec2 z=vec2(0.0);
    for(int i=0;i<32;i++){
        if(length(z)<e){
            tz=z;
            z.x=tz.x*tz.x-z.y*tz.y+c.x;
            z.y=2.0*tz.x*tz.y+c.y;
            ic++;
        }
    }
    float m=float(ic)-(log(log(length(z))))/log(2.0);
    fragColor=vec4(abs(sin(m/5.0)));
}


// Mandelbrot set zoom, with smooth coloring (Douady-Hubbard) by iq]
// https://www.shadertoy.com/view/lllGWH 
// Created by inigo quilez - iq/2015
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.

void mainImage( out vec4 f, in vec2 p )
{
    float n = 0.;
    vec2 c = vec2(-.745,.186) + 3. * (p.xy/iResolution.y-.5)*pow(.01,1.+cos(.2*iGlobalTime)), z=c*n;
    
    for( int i=0; i<128; i++ )
    {
        z = vec2( z.x*z.x - z.y*z.y, 2.*z.x*z.y ) + c;

        if( dot(z,z)>1e4 ) break;

        n++;
    }
    
    f = .5 + .5*cos( vec4(3,4,11,0) + .05*(n - log2(log2(dot(z,z)))) );
}

展开的卡迪奥曲线

[编辑 | 编辑源代码]
// https://www.shadertoy.com/view/ldfSW4
// The trees are breathing Created by jld in 2014-May-24

#define M_PI 3.14159265358979323846
#define N 53

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	vec2 rth = fragCoord.xy / iResolution.xy * 2.0 * M_PI;
	rth.y *= iResolution.y / iResolution.x;
	rth.x += (iTime / 60.0) * 2.0 * M_PI;
	vec2 z0 = (1.0 + rth.y) * vec2(cos(rth.x), sin(rth.x)) / 2.0;
	vec2 z1 = vec2(1.0, 0.0) - z0;
	vec2 c = vec2(z0.x * z1.x - z0.y * z1.y, z0.x * z1.y + z0.y * z1.x);
	vec2 a = c;
	float g = 1.0;
	float thresh = 10.0 + 6.0 ;
	vec3 color = vec3(1.0, 1.0, 1.0);

	// color += (1.0 + cos (iTime)) * vec3(0.0, 0.007, 0.01) * clamp(z1.x - z0.x, -2.0, 3.0);
	
	for (int i = 0; i < N; ++i) {
		if (dot(a, a) > thresh) {
			break;
		}
		g *= 0.9;
	    a = vec2(a.x * a.x - a.y * a.y, 2.0 * a.x * a.y) + c;
	}

	fragColor = vec4(g * color, 1.0);
}
// https://www.shadertoy.com/view/4st3Wn 
// Filled Mandelbrot created by Kramin in 2015-Dec-1
#define AA 2

#define maxIteration 300
#define CX -0.75
#define CY 0.0
#define INVZOOM 2.5
#define T 20.0

float getColourValue(float mu, float s, float m, float e)
{
    if (mu<s) {
        return 0.0;
    } else if (mu<m) {
        return (mu - s)/(m-s);
    } else if (mu<e) {
        return 1.0 - (mu - m)/(e-m);
    }
    return 0.0;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    float modtime = iTime*1.5; //controls the slight pulsating
    float sinsq1 = max(0.0,sin(modtime)); sinsq1 = sinsq1*sinsq1;
    float sinsq2 = max(0.0,sin(modtime+0.75)); sinsq2 = sinsq2*sinsq2;
    float sinsq3 = max(0.0,sin(modtime+1.5)); sinsq3 = sinsq3*sinsq3;
    float sinsq4 = max(0.0,sin(modtime+2.25)); sinsq4 = sinsq4*sinsq4;
    float izoom = INVZOOM;
    vec3 colour = vec3(0.0,0.0,0.0);
#if AA>1
    for( int m=0; m<AA; m++ )
    for( int n=0; n<AA; n++ )
    {
    vec2 c = vec2(CX,CY) + (fragCoord+vec2(float(m),float(n))/float(AA)-iResolution.xy/2.0)*izoom/iResolution.y;
    float w = float(AA*m+n);
#else
    vec2 c = vec2(CX,CY) + (fragCoord-iResolution.xy/2.0)*izoom/iResolution.y;
#endif
	vec2 z = c;
	float iteration = float(maxIteration);
	
	float zlen = length(z);
	float minz = zlen;
	int minziter = 0;
	
	for (int i = 0; i<maxIteration; i++) {
        if (zlen > 3000.0) {
            iteration = float(i);
            break;
        }
        
		if (zlen < minz){
		  minziter = i;
		  minz = zlen;
		}
		
		// do z = z^2 + c
		z = mat2(z,-z.y,z.x)*z + c;
		
		zlen = length(z);
	}
    
	if (iteration < float(maxIteration)){
		//smooth colouring
		float mu = float(iteration) - log(log(length(vec2(z))))/0.6931471805599453; //log(2.0) = 0.6931471805599453
    	mu = max(mu,0.0);
		//transform to between 0 and 1
		//mu/(mu+constant) goes to 1 as mu goes to infinity and to 0 as mu goes to 0.
		//This transformation is much better than a simple mu = mu/maxIteration because it 
		//is independent of maxIteration
		mu=mu/(mu+T);
		
		//colour.x += getColourValue(mu,0.5,1.0,1.0) + getColourValue(mu,0.0,0.5,1.0)*0.9 + getColourValue(mu,-1.0,-0.5,0.5)*0.3;
		//colour.y += getColourValue(mu,0.5,1.0,1.0) + getColourValue(mu,0.0,0.5,1.0)*0.1 + getColourValue(mu,-1.0,-0.5,0.5)*0.0;
		//colour.z += getColourValue(mu,0.5,1.0,1.0) + getColourValue(mu,0.0,0.5,1.0)*0.1 + getColourValue(mu,-1.0,-0.5,0.5)*0.4;
        colour += getColourValue(mu,0.5+0.05*(-0.5*sinsq2+0.5),1.0,1.0) + (0.2*sinsq2+0.8)*getColourValue(mu,0.0,0.5,1.0)*vec3(0.867,0.282,0.078) + (0.2*sinsq1+0.8)*getColourValue(mu,-1.0,-0.5,0.5)*vec3(0.302,0.114,0.208);
	}
	else {
	  float mu = float(minziter);
	  mu = (0.5+0.25*(-0.2*sinsq4+0.8))*10.0/(mu+10.0)+0.25*(-0.2*sinsq3+0.8)*sqrt(minz);//sqrt(minz) adds a little gradient to the interior 
	  //colour.x += getColourValue(mu,0.0,0.7,1.0)*0.1 + getColourValue(mu,0.0,0.4,0.7)*0.0 + getColourValue(mu,0.0,0.1,0.5);
	  //colour.y += getColourValue(mu,0.0,0.7,1.0)*0.0 + getColourValue(mu,0.0,0.4,0.7)*0.6 + getColourValue(mu,0.0,0.1,0.5);
	  //colour.z += getColourValue(mu,0.0,0.7,1.0)*0.2 + getColourValue(mu,0.0,0.4,0.7)*0.8 + getColourValue(mu,0.0,0.1,0.5);
      colour += getColourValue(mu,0.0,0.7,1.0)*vec3(0.302,0.114,0.208) + getColourValue(mu,0.0,0.4,0.7)*vec3(0.867,0.282,0.078) + getColourValue(mu,0.0,0.1,0.5);
	}
#if AA>1
    }
    colour /= float(AA*AA);
#endif
  fragColor = vec4( colour.x, colour.y, colour.z, 1.0 );
}

参考资料

[编辑 | 编辑源代码]
  1. Shardertoy
  2. Omar Shehata 在 2015 年 4 月 15 日撰写的《图形着色器编码入门指南》
  3. NeHe : GLSL 入门
  4. 转换 ShaderToy 着色器
  5. Xor 的着色器基础
  6. Michael Mara 撰写的《面向非图形程序员的 Shadertoy 入门指南》
  7. Xor 的模糊着色器 #5 第 2 部分
  8. Lukas Pukenis 撰写的 Glsl 基础
  9. Matt DesLauriers 撰写的着色器教程,于 2014 年 7 月 12 日编辑了此页面
华夏公益教科书