GLSL 动画动作万能规律表

先记住 2 个核心根基:

  1. 所有流动 / 摆动 / 起伏 90% 只用:sin(正弦)cos(余弦)
  2. 所有位置偏移+ - * /
  3. 时间统一变量:uTime(全局动画时间)

一、先记万能基础公式

1. 正弦万能波动(最常用!90% 动画靠它)

js 复制代码
// 基础格式 
sin( 自变量 ) 

// 让结果范围变成 0 ~ 1(颜色/透明度/强度必用) 
sin(x) * 0.5 + 0.5

值域

  • sin(x) → 范围 -1 ~ 1
  • sin(x)*0.5+0.5 → 范围 0 ~ 1

2. 控制 4 个参数,随便改动作

js 复制代码
sin( 频率 * 坐标 + 速度 * 时间 )
  • 频率:数字越大,波动越密、越快
  • 时间:uTime,控制整体动起来
  • 速度:控制快慢
修改内容 写法 效果
波纹更密集 坐标 * 大数 纹路变多、紧凑
波纹更稀疏 坐标 * 小数 纹路变少、宽松
动画变快 uTime * 2.0 运动加速
动画变慢 uTime * 0.3 运动舒缓
正向运动 + uTime 正向流动
反向运动 - uTime 反向流动

二、按「想要什么效果」直接对应公式

1. 左右横向流动(最常用:流光、飘带、流云)

需求:画面从左往右缓缓流动

js 复制代码
// uv.x 横向坐标 
float flow = sin(uv.x * 5.0 + uTime);
  • uv.x * 5:波纹疏密
  • +uTime:向右流动
  • 改成 -uTime:向左流动

2. 上下竖向流动

js 复制代码
float flow = sin(uv.y * 5.0 + uTime);

3. 整体明暗闪烁 / 呼吸灯

需求:颜色一亮一暗慢慢呼吸

js 复制代码
// 只跟时间有关,跟坐标无关 
float breath = sin(uTime) * 0.5 + 0.5; 
col *= breath;

4. 波浪起伏(水面、飘动旗帜)

需求:一排高低起伏波浪

js 复制代码
// 水平波浪 
float wave = sin(uv.x * 8.0 + uTime * 2.0); 
// 用这个值去偏移位置/偏移颜色

5. 环形扩散波纹(圆心往外扩散水纹)

需求:中心点一圈一圈散开

js 复制代码
float len = length(uv - 0.5); // 到中心距离 
float ring = sin(len * 15.0 - uTime * 3.0);
  • -uTime = 向外扩散
  • +uTime = 向内收缩

6. 旋转动画(整体旋转、漩涡)

需求:图案转圈

js 复制代码
float angle = atan(uv.y, uv.x); // 获取角度 
float rotate = sin(angle * 6.0 + uTime);

7. 随机闪烁星星(无规律闪动)

需求:星星各自乱闪

js 复制代码
float r = rand(uv); // 随机值 
float twinkle = sin(uTime + r * 10.0) * 0.5 + 0.5;

8. 快慢变速控制

  • 动得慢:uTime * 0.3
  • 正常速度:uTime * 1.0
  • 动得快:uTime * 2.5

9. 条纹移动(科技网格线)

js 复制代码
float line = fract(uv.x * 10.0 + uTime); 
float grid = smoothstep(0.0, 0.1, line);

10. 画面轻微扰动(星云/云雾柔化)

js 复制代码
uv.x += sin(uv.y * 3.0 + uTime * 0.2) * 0.1; 
uv.y += cos(uv.x * 3.0 + uTime * 0.15) * 0.15;

11. 屏幕边缘渐变淡化(所有背景通用美化)

js 复制代码
float fade = 1.0 - length(uv - 0.5); 
color *= fade;

三、最简搭配口诀(背会直接写)

  1. 想左右动 → 用 uv.x + uTime
  2. 想上下动 → 用 uv.y + uTime
  3. 想转圈扩散 → 用 length /atan + uTime
  4. 想呼吸明暗 → 只用纯 uTime
  5. 想疏密变化 → 乘大数
  6. 想快慢变化 → 乘时间系数
  7. *想 0~1 可用颜色 → 统一 0.5+0.5

四、三角函数通用进阶用法(快速增加画面复杂度)

1. GLSL 仅需掌握 3 个核心函数

js 复制代码
sin(x) // 主力:波动、流动、起伏、闪烁 
cos(x) // 辅助:和sin相位错位,搭配做出错位动感 
atan(y,x) // 专用:计算角度,实现旋转、漩涡、环形动画

tan 极少使用,日常开发可直接忽略

2. 双层叠加公式(告别机械单调动画)

核心逻辑:不同方向、不同速度、正负错位叠加,模拟自然运动

js 复制代码
// 横向波动 
float w1 = sin(uv.x * 6.0 + uTime * 1.0); 
// 纵向反向波动 
float w2 = sin(uv.y * 4.0 - uTime * 1.2); 
// 加权混合 
float allWave = w1 * 0.6 + w2 * 0.4;

3. 多方向叠加万能模板(一键提升复杂度)

横向 + 纵向 + 斜向三维叠加,轻松做出高级流动效果

js 复制代码
// 横向 
float a = sin(uv.x * 5.0 + uTime); 
// 纵向 
float b = sin(uv.y * 6.0 - uTime); 
// 斜向 
float c = sin((uv.x + uv.y) * 4.0 + uTime); 
// 均匀混合 
float finalEffect = (a + b + c) / 3.0;

5. 四类高阶效果极简公式

  1. 自然海浪
js 复制代码
float w1 = sin(uv.x*6. + uTime); 
float w2 = sin(uv.y*4. - uTime*1.2); 
float wave = w1*.6 + w2*.4;
  1. 扩散水纹
js 复制代码
float d = length(uv-.5); 
float ring = sin(d*12. - uTime*3.);
  1. 旋转螺旋
js 复制代码
float a = atan(uv.y,uv.x); 
float r = sin(a*8. - uTime*2.);
  1. 柔性流云
js 复制代码
uv += vec2(sin(uv.y*2.5+uTime*0.2),cos(uv.x*2.5+uTime*0.15))*0.12;

五、速记口诀

  • 想波动,用 sin
  • 想自然,叠两层
  • 想扩散,用 length
  • 想旋转,用 atan想
  • 复杂,叠方向
  • 调疏密改系数,调快慢改时间

六、一些例子

1. 星云流动渐变背景

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>星云流动背景</title>
<style>body{margin:0;overflow:hidden;}</style>
</head>
<body>
<script type="module">
import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.160/build/three.module.js'

const scene = new THREE.Scene()
const camera = new THREE.OrthographicCamera(-1,1,1,-1,0,10)
camera.position.z = 1

const renderer = new THREE.WebGLRenderer({antialias:true})
renderer.setSize(innerWidth,innerHeight)
renderer.setPixelRatio(Math.min(devicePixelRatio,1.5))
document.body.appendChild(renderer.domElement)

const vertexShader = `
varying vec2 vUv;
void main(){
    vUv = uv;
    gl_Position = vec4(position,1.0);
}
`

const fragmentShader = `
uniform float uTime;
varying vec2 vUv;

void main(){
    vec2 uv = vUv;
    uv.x += sin(uv.y*3.0 + uTime*0.2)*0.1;
    uv.y += cos(uv.x*3.0 + uTime*0.15)*0.1;

    vec3 col1 = vec3(0.1,0.2,0.6);
    vec3 col2 = vec3(0.2,0.5,0.9);
    vec3 col3 = vec3(0.0,0.1,0.3);

    float mix1 = sin(uv.x*4.0 + uTime*0.3)*0.5+0.5;
    float mix2 = cos(uv.y*4.0 - uTime*0.2)*0.5+0.5;

    vec3 finalCol = mix(col1,col2,mix1);
    finalCol = mix(finalCol,col3,mix2*0.5);
    gl_FragColor = vec4(finalCol,1.0);
}
`

const shaderMat = new THREE.ShaderMaterial({
    vertexShader,
    fragmentShader,
    uniforms:{
        uTime:{value:0}
    }
})

const plane = new THREE.Mesh(new THREE.PlaneGeometry(2,2), shaderMat)
scene.add(plane)

window.addEventListener('resize',()=>{
    renderer.setSize(innerWidth,innerHeight)
})

const clock = new THREE.Clock()
function animate(){
    requestAnimationFrame(animate)
    shaderMat.uniforms.uTime.value = clock.getElapsedTime()
    renderer.render(scene,camera)
}
animate()
</script>
</body>
</html>

2. 中心动态波纹水纹

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>中心波纹水纹</title>
<style>body{margin:0;overflow:hidden;}</style>
</head>
<body>
<script type="module">
import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.160/build/three.module.js'

const scene = new THREE.Scene()
const camera = new THREE.OrthographicCamera(-1,1,1,-1,0,10)
camera.position.z = 1

const renderer = new THREE.WebGLRenderer({antialias:true})
renderer.setSize(innerWidth,innerHeight)
renderer.setPixelRatio(Math.min(devicePixelRatio,1.5))
document.body.appendChild(renderer.domElement)

const vertexShader = `
varying vec2 vUv;
void main(){
    vUv = uv;
    gl_Position = vec4(position,1.0);
}
`

const fragmentShader = `
uniform float uTime;
varying vec2 vUv;

void main(){
    vec2 uv = vUv - 0.5;
    float len = length(uv);
    float wave = sin(len*12.0 - uTime*2.5) * 0.15;
    float wave2 = sin(len*8.0 + uTime*1.8) * 0.1;
    
    vec3 base = vec3(0.15,0.45,0.75);
    vec3 color = base + vec3(wave+wave2);
    color *= 1.0 - len*0.8;
    gl_FragColor = vec4(color,1.0);
}
`

const shaderMat = new THREE.ShaderMaterial({
    vertexShader,
    fragmentShader,
    uniforms:{
        uTime:{value:0}
    }
})

const plane = new THREE.Mesh(new THREE.PlaneGeometry(2,2), shaderMat)
scene.add(plane)

window.addEventListener('resize',()=>{
    renderer.setSize(innerWidth,innerHeight)
})

const clock = new THREE.Clock()
function animate(){
    requestAnimationFrame(animate)
    shaderMat.uniforms.uTime.value = clock.getElapsedTime()
    renderer.render(scene,camera)
}
animate()
</script>
</body>
</html>

3. 科技流动网格线条

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>科技流动网格</title>
<style>body{margin:0;overflow:hidden;}</style>
</head>
<body>
<script type="module">
import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.160/build/three.module.js'

const scene = new THREE.Scene()
const camera = new THREE.OrthographicCamera(-1,1,1,-1,0,10)
camera.position.z = 1

const renderer = new THREE.WebGLRenderer({antialias:true})
renderer.setSize(innerWidth,innerHeight)
renderer.setPixelRatio(Math.min(devicePixelRatio,1.5))
document.body.appendChild(renderer.domElement)

const vertexShader = `
varying vec2 vUv;
void main(){
    vUv = uv;
    gl_Position = vec4(position,1.0);
}
`

const fragmentShader = `
uniform float uTime;
varying vec2 vUv;

void main(){
    vec2 uv = vUv * 10.0;
    float lineX = smoothstep(0.0,0.08,fract(uv.x + uTime*0.5));
    float lineY = smoothstep(0.0,0.08,fract(uv.y - uTime*0.3));

    float grid = max(lineX,lineY);
    vec3 lineCol = vec3(0.2,0.7,1.0);
    vec3 bg = vec3(0.02,0.05,0.12);
    vec3 res = mix(bg,lineCol,grid*0.6);
    gl_FragColor = vec4(res,1.0);
}
`

const shaderMat = new THREE.ShaderMaterial({
    vertexShader,
    fragmentShader,
    uniforms:{
        uTime:{value:0}
    }
})

const plane = new THREE.Mesh(new THREE.PlaneGeometry(2,2), shaderMat)
scene.add(plane)

window.addEventListener('resize',()=>{
    renderer.setSize(innerWidth,innerHeight)
})

const clock = new THREE.Clock()
function animate(){
    requestAnimationFrame(animate)
    shaderMat.uniforms.uTime.value = clock.getElapsedTime()
    renderer.render(scene,camera)
}
animate()
</script>
</body>
</html>

4. 极简闪烁星空背景

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>闪烁星空</title>
<style>body{margin:0;overflow:hidden;}</style>
</head>
<body>
<script type="module">
import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.160/build/three.module.js'

const scene = new THREE.Scene()
const camera = new THREE.OrthographicCamera(-1,1,1,-1,0,10)
camera.position.z = 1

const renderer = new THREE.WebGLRenderer({antialias:true})
renderer.setSize(innerWidth,innerHeight)
renderer.setPixelRatio(Math.min(devicePixelRatio,1.5))
document.body.appendChild(renderer.domElement)

const vertexShader = `
varying vec2 vUv;
void main(){
    vUv = uv;
    gl_Position = vec4(position,1.0);
}
`

const fragmentShader = `
uniform float uTime;
varying vec2 vUv;

float rand(vec2 p){
    return fract(sin(dot(p,vec2(12.9898,78.233)))*43758.5453);
}

void main(){
    vec2 uv = vUv * 25.0;
    vec2 id = floor(uv);
    float r = rand(id);
    float twinkle = sin(uTime*2.0 + r*10.0)*0.4+0.6;
    float star = smoothstep(0.85,1.0,r) * twinkle;

    vec3 bg = vec3(0.01,0.02,0.06);
    vec3 starCol = vec3(1.0,1.0,1.0);
    vec3 col = bg + starCol*star;
    gl_FragColor = vec4(col,1.0);
}
`

const shaderMat = new THREE.ShaderMaterial({
    vertexShader,
    fragmentShader,
    uniforms:{
        uTime:{value:0}
    }
})

const plane = new THREE.Mesh(new THREE.PlaneGeometry(2,2), shaderMat)
scene.add(plane)

window.addEventListener('resize',()=>{
    renderer.setSize(innerWidth,innerHeight)
})

const clock = new THREE.Clock()
function animate(){
    requestAnimationFrame(animate)
    shaderMat.uniforms.uTime.value = clock.getElapsedTime()
    renderer.render(scene,camera)
}
animate()
</script>
</body>
</html>
相关推荐
小飞侠是个胖子11 小时前
底层博弈:在高阶 WebGL 开发中平衡视觉极限与渲染性能
webgl
郝学胜-神的一滴11 小时前
中级OpenGL教程 006:高光反射原理与 Shader 实现
c++·unity·godot·图形渲染·three.js·opengl·unreal
李剑一1 天前
520了,程序员就得有点儿独特的浪漫
前端·three.js
贵州数擎科技有限公司1 天前
分形金字塔的 Ray Marching 实现
webgl·three.js
谢小飞1 天前
Three.js三球轮播沉浸式落地页开发
前端·three.js
贵州数擎科技有限公司2 天前
雨滴特效的 Three.js 实现
前端·three.js
:mnong4 天前
PlayCanvas 开源 WebGL/WebGPU 3D 创作平台分析
3d·开源·webgl
Strayer7 天前
在地图上实现管网拓扑批量移动、旋转与缩放(参考图片的实现方式)
gis·webgl·数据可视化
Strayer7 天前
WebGL 地图上做精准编辑?这套分层方案搞定管网拖拽 / 连接
gis·webgl