http://oos.moxiecode.com/js_webgl/codevember2017/index9.html
效果图:
就是这种有点像彗星拖尾的效果,且这个方向是指向屏幕中央的,当然也可以修改。
代码着色器:
作者@oosmoxiecode,参考的也是 IQ大神 https://www.shadertoy.com/view/4sfGRn
这里直接注释IQ的代码了,都差不多。oos 就是写的可读性更高一些。
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 p = -1.0 + 2.0*fragCoord/iResolution.xy; // 从[0,1]变换到[-1,1]
vec3 col = vec3(0.0);
vec2 d = (vec2(0.0,0.0)-p)/64.0; // 求当前着色位置到屏幕中心的方向向量,这步是关键
float w = 1.0;
vec2 s = p;
// i<10 说明这个过程要叠加10次,越多则效果越强
for( int i=0; i<10; i++ )
{
vec3 res = deform( s ); // 取原texture像素,deform 是扭曲,非必要
col += w*smoothstep( 0.0, 1.0, res );
w *= .98;
s += d;
}
col = col * 3.5 / 64.0;
fragColor = vec4( col, 1.0 );
}
oos 则加了一个限制条件,只有像素颜色值高于某个阈值才拿来做颜色叠加,因此白色的部分会有更强的效果,暗色的就没有:
uniforms: {
"tDiffuse": { type: "t", value: null },
"tMap": { type: "t", value: null },
"steps": { type: "f", value: 100.0 },
"strength": { type: "f", value: 0.95 },
"expo": { type: "f", value: 5.0 },
"threshold": { type: "f", value: 0.7 },
"center": { type: "v2", value: new THREE.Vector2( 0.5, 0.5 ) },
},
"uniform float steps;",
"uniform float strength;",
"uniform float expo;",
"uniform float threshold;",
"uniform sampler2D tDiffuse;",
"uniform sampler2D tMap;",
"uniform vec2 center;",
"varying vec2 vUv;",
"void main() {",
"vec2 s = vUv;",
"vec3 total = vec3(0.0);",
"vec2 d = (center-vUv)/steps;", // 中间往外放射线的效果
"float w = 1.0;",
//"float t = 0.7;",
//"for( int i=0; i<int(steps); i++ ) {",
"for( int i=0; i<40; i++ ) {", // hardcode since the above fails in angle...
"vec3 res = texture2D( tMap, s).xyz;",
"if (res.x > threshold || res.y > threshold || res.z > threshold) {",
//"res = vec3(1.0,1.0,1.0);",
// 越接近白色,放射效果越强
"res *= 5.0;",
"} else {",
"res = vec3(0.0,0.0,0.0);",
"}",
"res = smoothstep(0.0,1.0,res);",
"total += w*res;",
"w *= strength;", // strength < 1, w 逐渐减小
"s += d;", // 沿放射方向,从vUv到屏幕中心
"}",
"total /= steps;",
//"gl_FragColor = vec4( total*expo, 1.0);",
"vec3 dif = texture2D( tDiffuse, vUv).xyz;",
"gl_FragColor = vec4( mix(total*expo, dif*2.0, 0.5), 1.0);",
//"gl_FragColor = vec4( total*expo, 1.0);",
"}"
这个程序的思路可以想象为,每个像素朝着屏幕中心看一段距离(由 for 的次数决定),如果看到的范围内有符合
(res.x > threshold || res.y > threshold || res.z > threshold)
的像素,就拿来作为当前着色像素的一个叠加的颜色。关键是要记住 GPU程序都是处理单个像素的,每次只能为当前着色的像素处理颜色。
很显然 center
不一定是中间位置。利用这个可以更灵活地做效果。