跳轉到內容

分形/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 日編輯了此頁面
華夏公益教科書