🧙 Three.js × GLSL 魔法书:动态材质、鼠标涟漪与粒子狂欢

"在像素与三角面之间,有一块布,名曰 Fragment;

在曲面起伏之中,有一道咒语,名曰 Vertex;

若你掌握了它们的语法,你就能让宇宙颤抖。"

------《图形术·着色卷》


🎨 第一章:开场------什么是动态材质?

在 Three.js 的魔法世界中,材质(Material) 是物体的灵魂外衣。

而我们说的"动态材质",指的是:

  • 可随时间、鼠标、交互改变的外观
  • 利用 GLSL(OpenGL Shading Language)在 GPU 上实时计算
  • 创造出 流光、波纹、描边、扭曲等超自然视觉

说白了就是让你的立方体会"呼吸",让地面泛起水波,让鼠标召唤星辉。


🔮 第二章:召唤 ShaderMaterial

我们使用 THREE.ShaderMaterial 这个法术卷轴,来定义你自己的顶点与像素着色器。

php 复制代码
const material = new THREE.ShaderMaterial({
  vertexShader: `...`,    // 顶点着色器
  fragmentShader: `...`,  // 片元着色器
  uniforms: {             // 可供 JS 控制的变量
    uTime: { value: 0 },
    uMouse: { value: new THREE.Vector2() }
  }
});

这就像炼金术的配方------你可以往里面加时间(time)、鼠标(mouse)、贴图(texture)、甚至灵魂(noise)。


💦 第三章:水波术------让地面随鼠标泛起涟漪

"在风的指引下,湖面生出层层涟漪,那是鼠标在引导世界的变化。"

✨ 顶点着色器(vertexShader)

ini 复制代码
uniform float uTime;
uniform vec2 uMouse;
varying vec2 vUv;

void main() {
  vUv = uv;
  
  vec3 pos = position;
  
  float dist = distance(uv, uMouse);
  float ripple = sin(20.0 * dist - uTime * 4.0) * 0.1 / (dist + 0.1);
  
  pos.z += ripple;

  gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
  • uv:二维纹理坐标
  • uMouse:鼠标坐标(范围 0~1)
  • distance:计算每个点离鼠标有多远
  • ripple:水波函数,带着时间流动的 sin 函数

✨ 片元着色器(fragmentShader)

ini 复制代码
varying vec2 vUv;

void main() {
  vec3 color = vec3(vUv, 0.5);
  gl_FragColor = vec4(color, 1.0);
}
  • 渐变背景,先别让画面太复杂。

🖱️ 鼠标控制传入

ini 复制代码
const mouse = new THREE.Vector2();

window.addEventListener('mousemove', (e) => {
  mouse.x = e.clientX / window.innerWidth;
  mouse.y = 1.0 - e.clientY / window.innerHeight; // Y轴倒置
  material.uniforms.uMouse.value.copy(mouse);
});

"你的指尖,点燃了水波的灵魂。"


⏱️ 时间更新

ini 复制代码
function animate(time) {
  material.uniforms.uTime.value = time * 0.001;
  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}

🌈 第四章:流光术与描边术

✨ Fragment Shader 魔改:炫光边缘

scss 复制代码
varying vec2 vUv;
uniform float uTime;

void main() {
  float glow = abs(sin(uTime + vUv.x * 10.0)) * 0.8;
  float edge = smoothstep(0.48, 0.5, abs(vUv.x - 0.5));
  vec3 color = mix(vec3(0.1, 0.1, 0.1), vec3(0.0, 1.0, 1.0), glow * edge);
  gl_FragColor = vec4(color, 1.0);
}
  • glow:闪闪发亮的流光
  • edge:距离中心的边缘检测
  • mix:混合背景和高光

🕳️ 第五章:顶点拉扯术------交互式形变

"当你靠近它,它在逃离你;当你远离它,它在追随你。" ------ 变形元老会·鼠标流派

scss 复制代码
float deform = exp(-10.0 * dist) * sin(uTime * 3.0) * 0.2;
pos.z += deform;

让每个顶点按距离鼠标的远近微微鼓起,结合时间摆动,如同肌肉收缩。


💥 第六章:完整 JS 初始化代码

ini 复制代码
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 100);
camera.position.z = 2;

const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const geometry = new THREE.PlaneGeometry(2, 2, 128, 128);
const uniforms = {
  uTime: { value: 0 },
  uMouse: { value: new THREE.Vector2() }
};

const material = new THREE.ShaderMaterial({
  uniforms,
  vertexShader: `...`, // 👈 填入前面写好的顶点着色器
  fragmentShader: `...`, // 👈 填入片元着色器
  side: THREE.DoubleSide
});

const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

window.addEventListener('mousemove', (e) => {
  uniforms.uMouse.value.set(
    e.clientX / window.innerWidth,
    1.0 - e.clientY / window.innerHeight
  );
});

function animate(time) {
  uniforms.uTime.value = time * 0.001;
  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}

animate();

🔚 第七章:术法背后的秘密

  • sin + distance:构建自然的震动波
  • exp(-d):制造渐隐衰减(如鼓面振动)
  • mix():平滑过渡视觉
  • uniform:将 JS 世界与 GPU 着色世界连接起来

📚 延伸术卷推荐

  • 流动文字/边框光晕 :使用 gl_FragCoord.xy + 时间实现屏幕空间动画
  • 反射高光动画:传入法线贴图与视角方向实现动态高光
  • 步进条纹风格 :用 floor(sin(...)) 实现动态描边与扁平风格

🧙‍♂️ 尾声:愿你成为像素之主

"在每一帧 GPU 的低语中,隐藏着魔法的节奏。

拿起你的 ShaderMaterial,你不是在编码,你在咏唱咒语。"

------ 着色者之歌·序章

相关推荐
我真的叫奥运1 分钟前
def id 重复引发的 svg 复用的一些思考
前端·svg
程序员嘉逸1 分钟前
CSS动画完全指南:从基础过渡到炫酷3D效果,让你的网页动起来!
前端
怪侠欧阳波3 分钟前
Hexo博客部署Cloudflare Pages完整指南
前端·javascript
OpenTiny社区6 分钟前
这可能是2025年最懂前端开发的低代码引擎!
前端·低代码·github
葡萄皮sandy20 分钟前
Web3面试题
前端·web3
掘金安东尼25 分钟前
技术社区已死,博主何去何从?
前端
Fireworkitte34 分钟前
nodejs的npm
前端·npm·node.js
灰海35 分钟前
vscode,cursor,Trae终端不能使用cnpm、npm、pnpm命令解决方案
前端·ide·vue.js·vscode·npm·编辑器
斯~内克36 分钟前
前端包管理工具深度对比:npm、yarn、pnpm 全方位解析
前端·npm·node.js
-睡到自然醒~36 分钟前
完整的 Meteor NPM 集成
前端·npm·node.js