为了使之前文章的光柱实现渐变发光效果,我们可以利用 THREE.ShaderMaterial
来自定义材质,并通过时间动态改变材质的颜色属性。以下是如何修改和扩展上述代码以实现这一效果:
- 引入必要的模块:确保引入了
ShaderMaterial
,UniformsUtils
,Clock
等必要的模块。 - 定义自定义着色器:编写简单的 vertex 和 fragment 着色器来实现颜色的渐变效果。
- 使用
Clock
来获取时间:用时间来控制颜色的变化。 - 更新渲染函数:在渲染函数中更新着色器的统一变量。
下面是修改后的代码:
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { Group, PlaneGeometry, TextureLoader, ShaderMaterial, UniformsUtils, Clock, Mesh, DoubleSide } from 'three';
export const Pillar = (config?: Partial<{
width: number;
height: number;
lightPillarUrl: string;
color1: number; // 起始颜色
color2: number; // 结束颜色
minScale: number;
maxScale: number;
scaleSpeed: number;
}>) => {
const defaultConfig = {
height: 20,
lightPillarUrl: "./pillarTexture.png",
color1: 0x00ffff,
color2: 0xff00ff,
minScale: 1,
maxScale: 2,
scaleSpeed: 0.01
};
const conf = {
...defaultConfig,
...config
};
const ratios = 255 / 41;
const width = conf.height / ratios;
const group = new Group();
const geometry = new PlaneGeometry(width, conf.height);
geometry.rotateX(Math.PI / 2);
geometry.translate(0, 0, conf.height / 2);
const textureLoader = new TextureLoader();
const uniforms = UniformsUtils.merge([
{
u_time: { value: 1.0 },
u_color1: { value: new THREE.Color(conf.color1) },
u_color2: { value: new THREE.Color(conf.color2) },
u_texture: { value: textureLoader.load(conf.lightPillarUrl) }
}
]);
const vertexShader = `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const fragmentShader = `
uniform sampler2D u_texture;
uniform float u_time;
uniform vec3 u_color1;
uniform vec3 u_color2;
varying vec2 vUv;
void main() {
float mixFactor = abs(sin(u_time));
vec3 color = mix(u_color1, u_color2, mixFactor);
vec4 textureColor = texture2D(u_texture, vUv);
gl_FragColor = vec4(color, textureColor.a);
}
`;
const material = new ShaderMaterial({
uniforms: uniforms,
vertexShader: vertexShader,
fragmentShader: fragmentShader,
transparent: true,
depthWrite: false,
side: DoubleSide
});
const mesh = new Mesh(geometry, material);
const mesh2 = mesh.clone();
mesh2.rotateZ(Math.PI / 2);
group.add(mesh, mesh2);
let currentScale = conf.minScale;
let scalingUp = true;
const clock = new Clock();
const render = () => {
const delta = clock.getDelta();
if (scalingUp) {
currentScale += conf.scaleSpeed;
if (currentScale >= conf.maxScale) {
scalingUp = false;
}
} else {
currentScale -= conf.scaleSpeed;
if (currentScale <= conf.minScale) {
scalingUp = true;
}
}
group.scale.set(currentScale, currentScale, currentScale);
group.rotation.z += 0.01;
// 更新时间
uniforms.u_time.value = clock.elapsedTime;
};
return { mesh: group, render };
};
说明:
- 着色器:
vertexShader
:传递 UV 坐标。fragmentShader
:使用时间来在两种颜色之间进行插值,并应用纹理。
Clock
:- 使用
Clock
对象来获取运行的时间,用于控制颜色渐变。
- 使用
uniforms
:- 定义了一些统一变量,包括时间
u_time
,起始颜色u_color1
,结束颜色u_color2
,以及纹理u_texture
。
- 定义了一些统一变量,包括时间
- 渲染函数:
- 在渲染函数中更新
u_time
统一变量,使得颜色能够随时间渐变。
- 在渲染函数中更新
通过这种方式,光柱将能够实现在两种颜色之间的平滑渐变效果。