工作中利用好各种图形,是可以做成好看的动态交互,如下动图就是其中的一部分
接下来,将展示常用的图形,以及代码如何实现。后面将附上代码,也可以访问这里查看图形效果
常用图形
新建一个平面 ,设置颜色为黄色,透明度为1,
为了更好的显示取反的效果,平面沿着X轴的宽高都设置为2.
new THREE.PlaneBufferGeometry(2, 2, 20,20)
然后设置着色器的颜色,如下
gl_FragColor =vec4(1,1,0,1);
注意: 下面用到的vPosition 是由vertexShader中传入的position,此处代码就不写了
x
x轴渐变 从圆点向右,由0到1,越来越不透明,vPosition.x的-1到0的部分,透明度按0处理。
gl_FragColor =vec4(1,1,0,vPosition.x);
gl_FragColor =vec4(1,1,0,vPosition.x + vPosition.x); // x 相加,透明度超过1的,按1处理,所以范围只有x的一半
x + x
x 相加,透明度超过1的,按1处理,所以范围只有x的一半
gl_FragColor =vec4(1,1,0,vPosition.x + vPosition.x);
x * x
x*x 得到 x 镜像叠加 x * x == -x * -x;
[-1,0]的部分相乘的结果和[0,1]相乘的结果是一样的,会得到对称的从两边到中间越来越透明,
gl_FragColor =vec4(1,1,0,vPosition.x * vPosition.x);
1.0 - x * x
对 x * x 取反
gl_FragColor =vec4(1,1,0,1.0-vPosition.x * vPosition.x);
y 同 x ,不过透明度是从上到下
gl_FragColor =vec4(1,1,0,vPosition.y); //y 透明度 由0到1
gl_FragColor =vec4(1,1,0,vPosition.y); //y +y 相加,透明度超过1的,按1处理,所以范围只有x的一半
gl_FragColor =vec4(1,1,0,vPosition.y * vPosition.y); // y * y 得到y的镜像叠加,中间透明
gl_FragColor =vec4(1,1,0,1.0-vPosition.y * vPosition.y); // 取反
x + y
gl_FragColor =vec4(1,1,0,(vPosition.x+vPosition.y));
(x + y) + (x + y)
x+y 的基础上范围缩小, 透明度超过1的,按1处理
gl_FragColor =vec4(1,1,0,(vPosition.x+vPosition.y) + (vPosition.x+vPosition.y)); //
(x + y) * (x + y)
相乘, 得到 x + y 的镜像叠加 (x + y)(x + y) = -(x + y)-(x + y)
gl_FragColor =vec4(1,1,0,(vPosition.x+vPosition.y) * (vPosition.x+vPosition.y));
1.0 - (x + y) * (x + y)
对(x + y) * (x + y) 取反
gl_FragColor =vec4(1,1,0,1.0-(vPosition.x+vPosition.y) * (vPosition.x+vPosition.y));
x*y
gl_FragColor =vec4(1,1,0,(vPosition.x*vPosition.y));
x * y + x * y
x*y 的基础上范围缩小, 透明度超过1的,按1处理
gl_FragColor =vec4(1,1,0,(vPosition.x*vPosition.y) + (vPosition.x*vPosition.y));
xy * xy
叠加
gl_FragColor =vec4(1,1,0,(vPosition.x*vPosition.y) * (vPosition.x*vPosition.y));
1.0 - xy * xy
对 xy * xy 取反
gl_FragColor =vec4(1,1,0,1.0-(vPosition.x*vPosition.y) * (vPosition.x*vPosition.y)); // 取反
当加大平面的宽高 new THREE.PlaneBufferGeometry(20, 20, 20,20) ,得到的结果:如下
下面是点到坐标点的距离渐变
radius
[0,1] 透明度由0到1 ,超过1的透明度都按1处理
float distanceToCenter = distance(vPosition.xy,vec2(0.0,0.0)) ; // 半径
gl_FragColor =vec4(1,1,0,distanceToCenter); // 圆圈:[0,1] 透明度由0到1
radius + radius
圆圈缩小: ,半径相加,透明度超过1的,按1处理
float distanceToCenter = distance(vPosition.xy,vec2(0.0,0.0)) ; // 半径
gl_FragColor =vec4(1,1,0,distanceToCenter + distanceToCenter); // 圆圈缩小: ,半径相加,透明度超过1的,按1处理
radius * radius
小数相乘, radius *radius 相乘会小于radius 的值,所以透明度比radius更接近0,透明区域更深
float distanceToCenter = distance(vPosition.xy,vec2(0.0,0.0)) ; // 半径
gl_FragColor =vec4(1,1,0,distanceToCenter * distanceToCenter); // 圆圈:
1.0 - radius * radius
对radius * radius 取反
float distanceToCenter = distance(vPosition.xy,vec2(0.0,0.0)) ; // 半径
gl_FragColor =vec4(1,1,0,1.0-distanceToCenter * distanceToCenter);
扇形
float alpha = 1.0 - step(0.5,distance(vUv,vec2(0.5)));
float angle = atan(vUv.x-0.5,vUv.y-0.5); //范围 [-3.14, 3.14]
float strength = (angle+3.14)/6.28;
gl_FragColor =vec4(strength,strength,strength,alpha);
圆环案例
const size = 50;
planeMesh = new THREE.Mesh(
new THREE.PlaneBufferGeometry(size, size),
new THREE.ShaderMaterial({
side: THREE.DoubleSide,
uniforms: {
uW: { value: 10 },
uTime: { value: 0 },
uTexture1: {
value: textureLoader.load(
'http://127.0.0.1:5500/examples/screenshots/webgl_animation_keyframes.jpg'
),
},
},
vertexShader: `
varying vec3 vPosition;
void main() {
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position,1.0 );
vPosition = position;
}
`,
fragmentShader: `
varying vec3 vPosition;
uniform float uW;
uniform float uTime;
void main(){
float distanceToCenter = distance(vPosition.xy,vec2(0.0,0.0)) ; // distanceToCenter的范围[0,size /2 ]
float radius = (distanceToCenter-uTime); // s的范围是 [-10,40] 透明度小于0的都按0处理,所以10以内的像素都是透明的
float rr = 1.0 - radius * radius; // 两个圆叠加,边缘部分透明渐变,然后取反,就是一条虚的环
float per = rr + uW;// 环加点宽度;
gl_FragColor = mix(vec4(0,0,1,1), vec4(1,1,1,1), per/ uW); // 颜色混合
}`,
})
);
gsap.to(planeMesh.material.uniforms.uTime, {
value: size / 2,
duration: 3,
ease: 'none',
repeat: -1,
yoyo: true,
});
scene.add(planeMesh);
结果如下
点有规律的增大
aIndex : 每个点的索引index
uScale: 缩放比例
// vertexShader:
// 当前点的大小减去当前时间,所有点会同时越来越小,当点小于0的时候,立即将该点目前的大小(负值)加上最大的点值
float size = aIndex - uTime;
// 例如当前是第0个点,随着时间变大,点(负数+uLength)越来越小,
// 例如当前是第10个点,随着时间变大点越来越小,当点成负数后(负数+uLength),会忽然变成最大值,然后再次越来越小,
// 以此类推
if(size < 0.0) {
size = size + uLength;
}
vSize = size * uScale;
// vSize = (size - uLength / 2.0) * uScale; // 设置前二分之一的点为不可见
gl_PointSize = vSize;
改变uTime会看到如下效果:
飞线案例
const m = new THREE.Mesh(
new THREE.PlaneBufferGeometry(20, 20),
new THREE.MeshStandardMaterial({ color: 0xffffff, side: THREE.DoubleSide })
);
m.rotation.x = -Math.PI / 2;
scene.add(m);
const lineCurve = new THREE.CatmullRomCurve3([
new THREE.Vector3(5, 0, 0),
new THREE.Vector3(0, 5, 0),
new THREE.Vector3(-5, 0, 0),
]);
const points = lineCurve.getPoints(500);
const geometry = new THREE.BufferGeometry().setFromPoints(points);
const ver = new Float32Array(points.length);
for (let i = 0; i < points.length; i++) {
ver[i] = i;
}
geometry.setAttribute('aIndex', new THREE.BufferAttribute(ver, 1));
const material = new THREE.ShaderMaterial({
transparent: true,
uniforms: {
uTime: { value: 0 },
uLength: {
value: points.length,
},
uScale: {
value: 0.025,
},
},
vertexShader: `
attribute float aIndex;
uniform float uTime;
uniform float uLength;
uniform float uScale;
varying float vSize;
void main() {
vec4 modelPosition = modelMatrix * vec4( position, 1.0 ); // 顶点坐标
gl_Position = projectionMatrix * viewMatrix * modelPosition;
// 当前点的大小减去当前时间,所有点会同时越来越小,当点小于0的时候,立即将该点目前的大小(负值)加上最大的点值
float size = aIndex - uTime;
// 例如当前是第0个点,随着时间变大,点(负数+uLength)越来越小,
// 例如当前是第10个点,随着时间变大点越来越小,当点成负数后(负数+uLength),会忽然变成最大值,然后再次越来越小,
// 以此类推
if(size < 0.0) {
size = size + uLength;
}
// vSize = (size) * uScale;
vSize = (size - uLength / 2.0) * uScale; // 设置前二分之一的点为不可见
gl_PointSize = vSize;
}
`,
fragmentShader: `
varying float vSize;
uniform float uTime;
uniform float uLength;
uniform float uScale;
void main(){
// 小于或者等于0的点设置透明度为0;
if(vSize <= 0.0){
gl_FragColor = vec4(1,1,0,0);
}else{
// 根据点的大小设置透明度,点越小越透明
float opacity = uLength / 2.0 * uScale;
gl_FragColor = vec4(1,1,0,vSize / opacity);
}
}
`,
});
gsap.to(material.uniforms.uTime, {
value: points.length,
duration: 5,
repeat: -1,
});
// 创建飞线物体
const mesh = new THREE.Points(geometry, material);
scene.add(mesh);
效果如下: