一、实现一个光影墙
1. 根据自定义坐标点,输出一个光影墙
/*** 添加光影墙*/ function addLightWall() {const geometry = new THREE.BufferGeometry();const vertices = new Float32Array([5, 0, 2,3, 0, 5,-2, 0, 5,-4, 0, 2,-4, 5, 2,-2, 5, 5,3, 5, 5,5, 5, 2]);const indices = new Uint16Array([0, 1, 7,1, 6, 7,1, 2, 6,2, 5, 6,2, 3, 5,3, 4, 5])geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));geometry.setIndex(new THREE.BufferAttribute(indices, 1));geometry.setAttribute('aHeight', new THREE.BufferAttribute(new Float32Array(new Array(geometry.getAttribute('position').count).fill(5.0)), 1));const uniforms = {uTime: { value: 0.01 },};setShader(geometry, vertex, frag, [0, 2.5, 0], uniforms) }function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {material = new THREE.ShaderMaterial({vertexShader: vertexShader,fragmentShader: fragmentShader,side: THREE.DoubleSide,uniforms: uniforms,transparent: true,// blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色 });material.depthTest = true;material.depthWrite = false;let planeMesh = new THREE.Mesh(geometry, material);if (isLine) {planeMesh = new THREE.Points(geometry, material);}planeMesh.position.x = position[0];planeMesh.position.y = position[1];planeMesh.position.z = position[2];scene.add(planeMesh); }
2. 圆柱体的光影墙
/*** 添加光影墙*/ function addLightWall() {const geometry = new THREE.CylinderGeometry(3, 3, 5.0, 32, 32, true);geometry.setAttribute('aHeight', new THREE.BufferAttribute(new Float32Array(new Array(geometry.getAttribute('position').count).fill(5.0)), 1));// 生成一个渐变色的光影墙const vertex = `varying vec3 vPosition;varying vec2 vUv;varying float vHeight;attribute float aHeight;void main() {vHeight = aHeight;vUv = uv;vPosition = position;gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}`;const frag = `varying vec3 vPosition;varying vec2 vUv;varying float vHeight;void main() {float d = (vHeight - distance(vPosition, vec3(vPosition.x, -2.5, vPosition.z))) / vHeight;gl_FragColor = vec4(0.0, 1.0, 1.0, d);}`;const uniforms = {uTime: { value: 0.01 },};setShader(geometry, vertex, frag, [0, 2.5, 0], uniforms) }function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {material = new THREE.ShaderMaterial({vertexShader: vertexShader,fragmentShader: fragmentShader,side: THREE.DoubleSide,uniforms: uniforms,transparent: true,// blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色 });material.depthTest = true;material.depthWrite = false;let planeMesh = new THREE.Mesh(geometry, material);if (isLine) {planeMesh = new THREE.Points(geometry, material);}planeMesh.position.x = position[0];planeMesh.position.y = position[1];planeMesh.position.z = position[2];scene.add(planeMesh); }
3. 为圆柱体添加可移动的线圈
/*** 添加光影墙*/ function addLightWall() {const geometry = new THREE.CylinderGeometry(3, 3, 5.0, 32, 32, true);geometry.setAttribute('aHeight', new THREE.BufferAttribute(new Float32Array(new Array(geometry.getAttribute('position').count).fill(5.0)), 1));// 生成一个可以向上移动的墙体线const vertex = `varying vec3 vPosition;varying vec2 vUv;varying float vHeight;attribute float aHeight;void main() {vHeight = aHeight;vUv = uv;vPosition = position;gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}`;const frag = `uniform float uTime;varying vec3 vPosition;varying vec2 vUv;varying float vHeight;void main() {float dis = distance(vPosition, vec3(vPosition.x, -2.5, vPosition.z));float highlightPos = mod(uTime * 5.0, vHeight) - 2.5;float highlightDis = distance(vec3(vPosition.x, highlightPos, vPosition.z), vec3(vPosition.x, -2.5, vPosition.z));float highlightOpa = (vHeight - highlightDis) / vHeight;float opacity = (vHeight - dis) / vHeight;if (abs(dis - highlightDis) < 0.05) {gl_FragColor = vec4(0.04, 0.95, 0.95, highlightOpa + 0.2);} else {gl_FragColor = vec4(0.0, 1.0, 1.0, opacity);}}`;const uniforms = {uTime: { value: 0.01 },};setShader(geometry, vertex, frag, [0, 2.5, 0], uniforms) }function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {material = new THREE.ShaderMaterial({vertexShader: vertexShader,fragmentShader: fragmentShader,side: THREE.DoubleSide,uniforms: uniforms,transparent: true,// blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色 });material.depthTest = true;material.depthWrite = false;let planeMesh = new THREE.Mesh(geometry, material);if (isLine) {planeMesh = new THREE.Points(geometry, material);}planeMesh.position.x = position[0];planeMesh.position.y = position[1];planeMesh.position.z = position[2];scene.add(planeMesh); }
二、实现一个渐变色的波纹圆圈
1. 实现一个固定的渐变色圆圈
原理:
1) UV点的范围是[0, 1],所以各个像素点距离圆心的距离范围是0~0.5,如果乘以2刚好是透明度的范围(0~1),这样就可以实现一个简单的渐变圆
2) 假设厚度为t,那么颜色的透明度的范围是[1, 1-t],而我们实际需要的是[1, 0],可以用图二来表示两个线性关系,可以得到两个方程式
方程式1:y = -x + 1;
方程式2:y = -t + 1;
现在我们知道方程式二中的y的值(像素点到中心的距离distance),通过解方程式就可以得到方程式1中所对应的透明度的值为 (distance - 1) / t + 1;
/*** 添加一个扩散面*/ function addDiffuseCircle() {const geometry = new THREE.CircleGeometry(3, 48);// 绘制一个渐变圈宽度可控的圆弧const vertex = `varying vec2 vUv;void main() {vUv = uv;gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}`;const frag = `uniform float uTime;uniform float uThickness;varying vec2 vUv;void main() {// 使用UV坐标计算各个点到中心点的距离,需要减0.5,将圆心移动到(0.5, 0.5)的位置,半径为0.5,透明度范围为0~1,所以需要乘以2float distance = length(vUv - 0.5) * 2.0;float opacity = (distance - 1.0) / uThickness + 1.0;gl_FragColor = vec4(0.0, 1.0, 1.0, opacity);}`;const uniforms = {uThickness: { value: 0.8, range: [0, 1] }, // 渐变色的厚度uSpeed: { value: 0.5, range: [0, 5] },uTime: { value: 0.01 },};setGui(uniforms);setShader(geometry, vertex, frag, [0,0,0], uniforms); }function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {material = new THREE.ShaderMaterial({vertexShader: vertexShader,fragmentShader: fragmentShader,side: THREE.DoubleSide,uniforms: uniforms,transparent: true,// blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色 });material.depthTest = true;material.depthWrite = false;let planeMesh = new THREE.Mesh(geometry, material);if (isLine) {planeMesh = new THREE.Points(geometry, material);}planeMesh.position.x = position[0];planeMesh.position.y = position[1];planeMesh.position.z = position[2];planeMesh.rotateX(Math.PI / 2);scene.add(planeMesh); }
2. 半径自动缩放的渐变圆
/*** 添加一个扩散面*/ function addDiffuseCircle() {const geometry = new THREE.CircleGeometry(3, 48);// 创建一个大小可控的渐变圆弧const vertex = `varying vec2 vUv;void main() {vUv = uv;gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}`;const frag = `uniform float uTime;uniform float uThickness;uniform float uSpeed;varying vec2 vUv;void main() {// 使用UV坐标计算各个点到中心点的距离,需要减0.5,将圆心移动到(0.5, 0.5)的位置,半径为0.5,透明度范围为0~1,所以需要乘以2// 假设从内像外开始扩散,距离和时间关系是 最内部: 距离0,时间0;最外部:距离1,时间1,如果用1-时间的话,// 所以此时1-时间+距离和样例1中的透明度相同float timeDis = fract(uTime * uSpeed);float distance = length(vUv - 0.5) * 2.0;if (timeDis < distance) {gl_FragColor = vec4(0.0, 0.0, 1.0, 0.0);} else {float opacity = (1.0 - timeDis + distance - 1.0) / uThickness + 1.0;gl_FragColor = vec4(0.0, 1.0, 1.0, opacity);}}`;const uniforms = {uThickness: { value: 0.8, range: [0, 1] }, // 渐变色的厚度uSpeed: { value: 0.5, range: [0, 5] },uTime: { value: 0.01 },};setShader(geometry, vertex, frag, [0,0,0], uniforms); }function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {material = new THREE.ShaderMaterial({vertexShader: vertexShader,fragmentShader: fragmentShader,side: THREE.DoubleSide,uniforms: uniforms,transparent: true,// blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色 });material.depthTest = true;material.depthWrite = false;let planeMesh = new THREE.Mesh(geometry, material);if (isLine) {planeMesh = new THREE.Points(geometry, material);}planeMesh.position.x = position[0];planeMesh.position.y = position[1];planeMesh.position.z = position[2];planeMesh.rotateX(Math.PI / 2);scene.add(planeMesh); }