*示例代碼可以直接在ShaderToy中運行。
*我放在這里咯ShaderToy基礎學習中~歡迎交流(ノ>ω<)ノ
先上未抗鋸齒的兩個圓形圖案,可以清楚看清圖案邊緣像素塊,即“鋸齒”。

附代碼:
void mainImage( out vec4 fragColor, in vec2 fragCoord ) { vec2 r = 2.0*vec2(fragCoord.xy - 0.5*iResolution.xy)/iResolution.y; vec2 center1 = vec2(-0.75,0); vec2 center2 = vec2(0.75,0); vec3 bgcol = vec3(1.0,0.5,0.5);//bg color vec3 col1 = vec3(0.4,0.6,0.6);//circle1 vec3 col2 = vec3(0.4,0.2,0.5);//circle2 vec3 pixel; pixel = bgcol; if(length(r-center1)<0.4) pixel = col1; if(length(r-center2)<0.4) pixel = col2; fragColor = vec4(pixel,1.0); }
要消除鋸齒,這里借助幾個GLSL內置函數,下面一個一個做筆記QAQ:
①mix()函數
原型:
//x為下限,y為上限,a為權重 //mix函數返回以a為權重,(x,y)為范圍的線性插值 //返回值計算公式:x ×(1−a)+y×a float mix(float x, float y, float a) vec2 mix(vec2 x, vec2 y, vec2 a) vec3 mix(vec3 x, vec3 y, vec3 a) vec4 mix(vec4 x, vec4 y, vec4 a)
②clamp函數:
原型:
//返回值計算公式: // min(max(x, minVal), maxVal)
//超出下界即等於下界
//超出上界即等於上界
float clamp(float x, float minVal, float maxVal) vec2 clamp(vec2 x, vec2 minVal, vec2 maxVal) vec3 clamp(vec3 x, vec3 minVal, vec3 maxVal) vec4 clamp(vec4 x, vec4 minVal, vec4 maxVal)
③smoothstep函數:
原型:
//在x、y間進行Hermite插值 //等價代碼: // genType t; // t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0); // return t * t * (3.0 - 2.0 * t);
float smoothstep(float edge0, float edge1, float x) vec2 smoothstep(vec2 edge0, vec2 edge1, vec2 x) vec3 smoothstep(vec3 edge0, vec3 edge1, vec3 x) vec4 smoothstep(vec4 edge0, vec4 edge1, vec4 x)
④step函數:
原型:
//step函數返回小於edge的值,否則返回1 float step(float edge, float x) vec2 step(vec2 edge, vec2 x) vec3 step(vec3 edge, vec3 x) vec4 step(vec4 edge, vec4 x)
下面用一個簡單明了的小例子來體現mix等函數的功能:

代碼如下:
void mainImage( out vec4 fragColor, in vec2 fragCoord ) { vec2 p = fragCoord.xy / iResolution.xy; vec3 col1 = vec3(1.0,0.2,0.4); vec3 col2 = vec3(0.4,0.6,1.0); vec3 pixel; float m; //area 1 //展示用作示例的兩種顏色 if(p.x<0.2){ if(p.y<0.5) pixel = col1; else pixel = col2; }
//area 2 //step函數效果 else if(p.x<0.4){ m = step(0.5,p.y); pixel = mix(col1,col2,m); }
//area 3 //根據縱坐標數值線性變化效果 else if(p.x<0.6){ m = p.y; pixel = mix(col1,col2,m); } //area 4 //clamp函數效果 else if(p.x<0.8){ m = clamp(p.y,0.4,0.8);//即將線性變化區間從完整的[0,1]變成[0.4,0.8] pixel = mix(col1,col2,m); }
//area 5 //smoothstep函數效果 else{ m = smoothstep(0.45, 0.55, p.y); pixel = mix(col1,col2,m); }
//區域分界線 for(float i=0.2;i<1.0;i += 0.2){ if(p.x<i&&p.x>i-0.005) pixel = vec3(1.0); } fragColor = vec4((pixel),1.0); }
回到最初的圓形。
用上述函數對原始圓形圖案進行處理,弱化鋸齒:

附代碼:
float linearstep(float edge0, float edge1, float x) { float t = (x - edge0)/(edge1 - edge0); return clamp(t, 0.0, 1.0); } float smootherstep(float edge0, float edge1, float x) { float t = (x - edge0)/(edge1 - edge0); float t1 = t*t*t*(t*(t*6. - 15.) + 10.); return clamp(t1, 0.0, 1.0); } void mainImage( out vec4 fragColor, in vec2 fragCoord ) { vec2 r = 2.0*vec2(fragCoord.xy - 0.5*iResolution.xy)/iResolution.y; vec3 bgcol = vec3(1.0,0.3,0.5);//bg color vec3 col1 = vec3(0.4,0.2,0.5);//circle vec2 center1 = vec2(-1.35,0); vec2 center2 = vec2(-0.45,0); vec2 center3 = vec2(0.45,0); vec2 center4 = vec2(1.35,0); vec3 pixel = bgcol; float m=0.4; pixel = bgcol; //circle 0 //未經任何處理 /* if(r.x<-0.9){ if(length(r-center1)<m){ pixel = col1; } } */ //circle 1 //step處理,等同於未經任何處理的circle 0 if(r.x<-0.9){ m = step(m,length(r-center1)); pixel = mix(col1,bgcol,m); } //circle 2 //linearstep處理 else if(r.x<-0.0){ m = linearstep(m-0.005,m+0.005,length(r-center2)); pixel = mix(col1,bgcol,m); } //circle 3 //smoothstep處理 else if(r.x<0.9){ m = smoothstep(m-0.005,m+0.005,length(r-center3)); pixel = mix(col1,bgcol,m); } //circle 4 //自定義smootherstep處理 else if(r.x<1.8){ m = smootherstep(m-0.005,m+0.005,length(r-center4)); pixel = mix(col1,bgcol,m); } //區域分解線 for(float i=-0.9;i<2.0;i += 0.9){ if(r.x<i&&r.x>i-0.005) pixel = vec3(1.0); } fragColor = vec4(pixel,1.0); }
上圖可能不太明顯,在shadertoy網站運行代碼全屏會更清楚點。事實是從左到右四個圖的圓形鋸齒越來越不明顯。
這里有段代碼蠻有意思的:
float t = (x - edge0)/(edge1 - edge0); return clamp(t, 0.0, 1.0);
第一行代碼的作用是判斷x和edge1之間的關系,結合第二行clamp函數,如果>1說明x>edge1;如果<1則反之。
【over.】
