
three.js 后处理 KaleidoShader 完全指南基于 ShaderPass 实现径向万花筒反射特效【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js本指南以 three.js 仓库中的 KaleidoShader 模块文档 为核心结合其完整源码实现examples/jsm/shaders/KaleidoShader.js展开。你将理解这个ShaderMaterial~Shader对象的三个 uniform 参数tDiffuse、sides、angle的含义掌握其片段着色器中“极坐标 取模折叠 镜像”的核心算法并学会把它接入EffectComposer/ShaderPass后处理管线为任意 3D 场景一键添加旋转、对称的万花筒滤镜。一、KaleidoShader 是什么KaleidoShader 是一个屏幕空间后处理着色器post-processing shader实现“围绕画面中心点的径向反射”Radial reflection around center point即经典万花筒效果整幅画面沿圆心的多个扇区反复折叠、镜像形成对称的放射状图案。根据文档与源码注释该着色器由 Toby Schachman 编写的 Pixel Shaders 在线编辑器示例移植而来属于ShaderMaterial~Shader类型的纯常量对象constant它只描述一份可复用的着色器定义uniforms vertex/fragment 代码自身不持有任何渲染状态由使用者通常是ShaderPass将它实例化为真正的ShaderMaterial后投入渲染。在 three.js 中它被归类为addon附加模块不在核心包three的默认导出内必须显式导入。二、导入方式addon 显式导入KaleidoShader 不随three核心模块自动加载需要从 addons 路径显式导入import { KaleidoShader } from three/addons/shaders/KaleidoShader.js;这一点与文档中“Addon 必须显式导入”的说明一致。从源码结构看KaleidoShader通过 examples/jsm/Addons.js 中的export * from ./shaders/KaleidoShader.js统一对外暴露因此只要使用three/addons/...这种入口写法等价于examples/jsm/...即可正常解析。三、Shader 对象结构与 Uniform 属性KaleidoShader是一个结构标准的 shader 对象源码位于 examples/jsm/shaders/KaleidoShader.js包含四个字段字段内容说明nameKaleidoShader着色器名称用于调试与材质命名uniformstDiffuse/sides/angle着色器统一变量声明及默认值vertexShader全屏四边形顶点程序透传 UV计算gl_PositionfragmentShader万花筒折叠算法核心效果所在三个 uniform 的默认值及含义如下字段说明直接来自文档与源码uniform类型默认值含义tDiffusesampler2Dnull输入纹理即上一 Pass 渲染出的场景缓冲sidesfloat6.0反射扇形分割数量anglefloat0.0初始角度单位弧度radians其中tDiffuse在源码中初始为null实际使用时由后处理框架见下文ShaderPass说明在每个渲染帧自动绑定为 readBuffer 的纹理无需手动赋值sides与angle则直接暴露给使用者实时调节。四、着色器实现原理一步步拆解片段算法4.1 顶点着色器标准全屏 Passvarying vec2 vUv; void main() { vUv uv; gl_Position projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); }顶点程序源码 KaleidoShader.js#L30-L39不做任何几何变换仅把网格 UV 传给片元阶段——这是所有全屏后处理 shader 的标准模板。4.2 片段着色器极坐标折叠与镜像uniform sampler2D tDiffuse; uniform float sides; uniform float angle; varying vec2 vUv; void main() { vec2 p vUv - 0.5; float r length(p); float a atan(p.y, p.x) angle; float tau 2. * 3.1416 ; a mod(a, tau/sides); a abs(a - tau/sides/2.) ; p r * vec2(cos(a), sin(a)); vec4 color texture2D(tDiffuse, p 0.5); gl_FragColor color; }这段代码源码 KaleidoShader.js#L49-L60每一步的作用可以这样理解坐标系平移p vUv - 0.5把 UV 原点从左上角移到画面中心使万花筒以画面中心为对称轴。直角坐标转极坐标r length(p)取像素到中心的距离a atan(p.y, p.x) angle取像素极角并叠加初始旋转角angle。扇形取模折叠a mod(a, tau / sides)把任意角度折进宽度为2π / sides的单个扇形区间注意tau用2. * 3.1416近似圆周率。扇形中线镜像a abs(a - tau / sides / 2.)沿扇形中线再做一次绝对值镜像。这一步让图案在扇形内形成左右对称的回折。重采样用折叠后的角度重建采样点p r * vec2(cos(a), sin(a))再平移回纹理坐标p 0.5采样tDiffuse输出到gl_FragColor。从数学上可以推导像素到中心的径向距离r被原样保留只有角度被重映射到[0, τ/(2·sides)]区间由于角度的折叠在每个扇形内会出现两次取值升/降沿同一来源像素会沿圆周被复制为2 × sides个镜像扇区。因此sides越大图案扇区越多、越细碎sides建议使用正整数否则扇形宽度无法整数等分圆周会在首尾相接处产生不连续的接缝由于采样坐标p 0.5可能超出[0,1]纹理范围画面四角到中心的距离约为0.707边缘表现受纹理环绕模式影响。五、把 KaleidoShader 接入 EffectComposer 后处理管线5.1 前置概念ShaderPass 如何消费 shader 对象KaleidoShader这样的对象不能直接丢给渲染器它需要被实例化为材质。three.js 提供了ShaderPassexamples/jsm/postprocessing/ShaderPass.js其构造函数见 ShaderPass.js#L56-L76会自动完成三件事用UniformsUtils.clone( shader.uniforms )克隆 uniforms避免多个 Pass 共享同一份状态依据name、defines、uniforms、vertexShader、fragmentShader构造一个ShaderMaterial在每次render()见 ShaderPass.js#L95-L101时自动把readBuffer.texture写入uniforms[tDiffuse]。其中第二步的默认纹理 uniform 名正是tDiffuse构造函数参数textureID tDiffuse这解释了 KaleidoShader 为何把场景输入纹理命名为tDiffuse。5.2 最小可运行示例下面以仓库中经典的后处理示例 examples/webgl_postprocessing.html 的导入与组装模式为蓝本演示如何把 KaleidoShader 挂进合成器import * as THREE from three; import { EffectComposer } from three/addons/postprocessing/EffectComposer.js; import { RenderPass } from three/addons/postprocessing/RenderPass.js; import { ShaderPass } from three/addons/postprocessing/ShaderPass.js; import { OutputPass } from three/addons/postprocessing/OutputPass.js; import { KaleidoShader } from three/addons/shaders/KaleidoShader.js;初始化渲染器与场景后按“场景渲染 → 特效 Pass → 输出”的顺序组装const renderer new THREE.WebGLRenderer(); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); const composer new EffectComposer( renderer ); composer.addPass( new RenderPass( scene, camera ) ); // 万花筒后处理 Pass const kaleidoPass new ShaderPass( KaleidoShader ); kaleidoPass.uniforms[ sides ].value 6; // 扇区数量 kaleidoPass.uniforms[ angle ].value 0; // 初始弧度 composer.addPass( kaleidoPass ); // 色彩/色调映射输出建议始终作为最后一环 composer.addPass( new OutputPass() );在动画循环中更新sides与angle即可驱动万花筒旋转与形变function animate() { requestAnimationFrame( animate ); // 让图案持续旋转角度单位是弧度 kaleidoPass.uniforms[ angle ].value 0.005; // 也可以让扇区数随时间呼吸式变化建议取整避免接缝断裂 // kaleidoPass.uniforms[ sides ].value 3 Math.floor( 4 * Math.abs( Math.sin( clock.getElapsedTime() ) ) ); composer.render(); }注意ShaderPass内部克隆了 uniforms因此动态调节必须通过kaleidoPass.uniforms[ ... ].value修改正如 webgl_postprocessing.html 中对DotScreenShader、RGBShiftShader的处理方式而不是改动KaleidoShader原对象。5.3 与其他 Pass 串联KaleidoShader 只负责几何折叠、不做色彩管理把它放在链中任何位置都能工作。推荐的串联方式与 examples/webgl_postprocessing.html 一致RenderPass渲染场景 → 若干ShaderPass特效 → 最后一个OutputPass负责 sRGB 色彩空间转换与色调映射输出。若跳过OutputPass在部分渲染器配置下画面色彩可能偏暗或偏灰。六、使用前提、边界与注意事项导入前提KaleidoShader位于three/addons/shaders/命名空间仅支持 ES Moduleimport方式显式引用仓库中通过 examples/jsm/Addons.js 统一 re-export如果使用构建工具确保打包器能解析three/addons/...别名。效果范围该 shader 是纯 2D 屏幕空间变换不感知 3D 几何只对当前帧整幅画面做中心径向折叠场景内容变化相机运动、物体动画都会实时反映在万花筒内部。参数取值sides以float声明但应取正整数否则 2π 圆周无法被整数分割而产生接缝angle单位是弧度做匀速旋转时直接逐帧累加即可。uniform 绑定tDiffuse初始为null不要手动赋值——ShaderPass会在每次渲染时用 readBuffer 纹理覆盖它。渲染前提该后处理需要EffectComposer对应的 WebGL 渲染环境片段着色器沿用texture2D/gl_FragColor的 GLSL 1.00 风格书写与仓库examples/jsm/shaders/下其余后处理着色器保持一致。七、延伸阅读源码与相关资源模块 API 文档本文依据的主文档docs/pages/module-KaleidoShader.html.md及其生成的 HTML 页面 docs/pages/module-KaleidoShader.html完整实现examples/jsm/shaders/KaleidoShader.jsaddons 汇总入口examples/jsm/Addons.js后处理 Pass 载体examples/jsm/postprocessing/ShaderPass.js组装范式参考examples/webgl_postprocessing.html若想自己改造可在examples/jsm/shaders/KaleidoShader.js的片段着色器基础上替换步骤 4镜像为其他映射例如加入径向缩放r、改为六边形/三角形晶格折叠等从而衍生出风格迥异的对称滤镜。仓库的完整 addons shader 集合位于 examples/jsm/shaders适合横向对比学习。【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考