在之前的文章中我们用一个三维向量表示颜色
vec3 line_color = vec3(1.0,1.0,0.0);
vec3 color = vec3(0.6);
用三维向量表示颜色因为正好它的三个分量可以代表RGBA格式的颜色中的Red(红色)Green(绿色)Blue(蓝色)分量,
我们在最后通常会有一句
gl_FragColor = vec4(color, 1.0);
用一个四位向量来设置颜色并赋值给全局变量gl_FragColor,最后一个参数表示Alpha通道,也就是透明度,这时整个窗口都是背景的颜色为灰色
如果我们以屏幕坐标的x分量来创建颜色,看看发生了什么
vec3 color = vec3(st.x);
下图是执行结果,从中可以看出窗口中从x方向的中线开始向右由黑色渐变为白色,明明我们的坐标范围是[-1,1]怎么左侧全部是黑色,也就是x轴负方向的部分全部是按0计算的,实际上计算机也是这么处理的
我们给屏幕坐标的x求一下绝对值看看什么效果
vec3 color = vec3(abs(st.x));
结果如下,可看到屏幕中的颜色沿x轴方向由白变黑再由黑变白,是因为屏幕x坐标求绝对值后的值从左到右为1.0-0.0-1.0
如果只将R分量设置为x坐标的绝对值
vec3 color = vec3(abs(st.x),0.0,0.0);//背景色
结果是这样,你可以尝试一下单独设置G分量和B分量,或者同时设置RGB看看效果
你同样可以使用一个函数例如正弦函数来改变颜色
vec3 color = vec3(sin(u_time),0.0,0.0);//背景色
运行的效果是颜色慢慢变红然后慢慢变黑不断往复,效果就不贴了,之前是可以上传gif格式图片,不懂为什么现在不支持了,传视频又要先传到某个网站在引入,这么点效果不太值当花时间,望见谅
上面演示的是如何改变背景色,物体形状的颜色改变也是一样,只需要给需要的分量替换为动态的变量
vec3 color = vec3(0.6);//背景色
vec3 shapeColor = vec3(sin(u_time),1.0,0.0);//形状颜色
float pct = sdTriangleRadius(st,vec2(-0.3,0.0),vec2(0.3,0.0),vec2(0.0,0.5),0.05);
color = mix(color,shapeColor,1.0-smoothstep(0.0,0.01,pct));
gl_FragColor = vec4(color, 1.0);
之前处理颜色是使用颜色与形状混合然后赋值给全局变量gl_FragColor,a通道的值设置为1.0,这次借助a通道来完成形状与颜色混合,实现是创建一个函数,有一个inout参数,该参数是一个RGBA颜色,既可以输入也可返回,在函数中创建一个临时图层,将形状写入该图层的a通道,然后使用输入输出颜色进行与该图层通过a通道混合,最后颜色通过自身返回,具体如下
void sdColorBox( in vec2 p,inout vec4 outColor ){
float dist = sdTriangleRadius(p,vec2(-0.3,0.0),vec2(0.3,0.0),vec2(0.0,0.5),0.05);
float pct = 1.0-smoothstep(0.0,0.01,dist);
vec3 shapeColor = vec3(sin(u_time),0.0,1.0);//定义形状颜色
vec4 layer = vec4(shapeColor.rgb, pct);//创建图层并将形状写入a通道
outColor = mix(outColor, layer, layer.a);//图层的a通道与原颜色混合并通过参数返回
}
调用过程,首先准备一个四维向量来表示初始颜色,调用函数后带有颜色的形状被混合到此变量中,这时支付要将该变量赋值给全局变量gl_FragColor即可
vec4 lastColor = vec4(0.6);
sdColorBox(st,lastColor);
gl_FragColor = lastColor;
<body>
<div id="container"></div>
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/build/three.js"></script>
<script>
var container;
var camera, scene, renderer;
var uniforms;
var vertexShader = `
void main() {
gl_Position = vec4( position, 1.0 );
}
`
var fragmentShader = `
#ifdef GL_ES
precision mediump float;
#endif
uniform float u_time;
uniform vec2 u_mouse;
uniform vec2 u_resolution;
float sdTriangleRadius( in vec2 p, in vec2 p0, in vec2 p1, in vec2 p2,float cornerRadius )
{
vec2 e0 = p1-p0, e1 = p2-p1, e2 = p0-p2;
vec2 v0 = p -p0, v1 = p -p1, v2 = p -p2;
vec2 pq0 = v0 - e0*clamp( dot(v0,e0)/dot(e0,e0), 0.0, 1.0 );
vec2 pq1 = v1 - e1*clamp( dot(v1,e1)/dot(e1,e1), 0.0, 1.0 );
vec2 pq2 = v2 - e2*clamp( dot(v2,e2)/dot(e2,e2), 0.0, 1.0 );
float s = sign( e0.x*e2.y - e0.y*e2.x );
vec2 d = min(min(vec2(dot(pq0,pq0), s*(v0.x*e0.y-v0.y*e0.x)),
vec2(dot(pq1,pq1), s*(v1.x*e1.y-v1.y*e1.x))),
vec2(dot(pq2,pq2), s*(v2.x*e2.y-v2.y*e2.x)));
return -sqrt(d.x)*sign(d.y) -cornerRadius;
}
void sdColorTriangle( in vec2 p,inout vec4 outColor ){
float dist = sdTriangleRadius(p,vec2(-0.3,0.0),vec2(0.3,0.0),vec2(0.0,0.5),0.05);
float pct = 1.0-smoothstep(0.0,0.01,dist);
vec3 shapeColor = vec3(sin(u_time),0.0,1.0);//定义形状颜色
vec4 layer = vec4(shapeColor.rgb, pct);//创建图层并将形状写入a通道
outColor = mix(outColor, layer, layer.a);//图层的a通道与原颜色混合并通过参数返回
}
void main( void ) {
//窗口坐标调整为[-1,1],坐标原点在屏幕中心
vec2 st = (gl_FragCoord.xy * 2. - u_resolution) / u_resolution.y;
vec3 color = vec3(0.6);//背景色
vec3 shapeColor = vec3(sin(u_time),1.0,0.0);//形状颜色
float pct = sdTriangleRadius(st,vec2(-0.3,0.0),vec2(0.3,0.0),vec2(0.0,0.5),0.05);
color = mix(color,shapeColor,1.0-smoothstep(0.0,0.01,pct));
gl_FragColor = vec4(color, 1.0);
vec4 lastColor = vec4(0.6);
sdColorTriangle(st,lastColor);
gl_FragColor = lastColor;
}
`
init();
animate();
function init() {
container = document.getElementById('container');
camera = new THREE.Camera();
camera.position.z = 1;
scene = new THREE.Scene();
var geometry = new THREE.PlaneBufferGeometry(2, 2);
uniforms = {
u_time: {
type: "f",
value: 1.0
},
u_resolution: {
type: "v2",
value: new THREE.Vector2()
},
u_mouse: {
type: "v2",
value: new THREE.Vector2()
}
};
var material = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: vertexShader,
fragmentShader: fragmentShader
});
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
renderer = new THREE.WebGLRenderer();
//renderer.setPixelRatio(window.devicePixelRatio);
container.appendChild(renderer.domElement);
onWindowResize();
window.addEventListener('resize', onWindowResize, false);
document.onmousemove = function (e) {
uniforms.u_mouse.value.x = e.pageX
uniforms.u_mouse.value.y = e.pageY
}
}
function onWindowResize(event) {
renderer.setSize(800, 800);
uniforms.u_resolution.value.x = renderer.domElement.width;
uniforms.u_resolution.value.y = renderer.domElement.height;
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
uniforms.u_time.value += 0.02;
renderer.render(scene, camera);
}
</script>
</body>