当前位置: 首页 > news >正文

Three.js 人物虚化教程

人物虚化 ·人物虚化· ▶ 在线运行案例

  • 案例合集:三维可视化功能案例(threehub.cn)
  • 开源仓库github地址:https://github.com/z2586300277/three-cesium-examples
  • 400个案例代码:网盘链接

你将学到什么

  • onBeforeCompile 注入 GLSL 改造内置材质
  • OrbitControls 相机轨道交互
  • Canvas 动态纹理贴图
  • FBXLoader 加载 FBX 城市/角色模型
  • 骨骼动画与 AnimationMixer
  • requestAnimationFrame渲染循环与resize自适应

效果说明

本案例演示人物虚化效果:用 Canvas 2D 绘制内容并实时映射为 Three.js 纹理;核心用到 onBeforeCompile、OrbitControls、Canvas。建议先打开文首在线案例查看动态画面,再对照下方源码逐步理解。

核心概念

  • Scene / Camera / WebGLRenderer构成最小渲染闭环;大场景可开logarithmicDepthBuffer缓解 Z-fighting。
  • onBeforeCompile在 Three 拼好内置 shader 后替换#include片段,适合在 PBR 材质上叠加大屏特效。
  • OrbitControls提供轨道旋转/缩放;开启enableDamping后需在 animate 中controls.update()
  • CanvasTexture每帧或按需把 2D Canvas 内容上传 GPU,适合动态文字、图表、视频帧贴图。

实现步骤

  • 搭建 Scene、PerspectiveCamera、WebGLRenderer,挂载 canvas 并处理resize
  • 异步加载模型 / 3D Tiles / GeoJSON 等资源并加入 scene 或 entities
  • 定义 uniforms / onBeforeCompile 或 ShaderMaterial,编写 GLSL 与材质参数
  • 创建 OrbitControls(及 Raycaster 等交互控件,若源码包含)
  • requestAnimationFrame循环中更新状态并 render(Cesium 为viewer.render或自动渲染)
  • 代码要点

    import * as THREE from "three";

    import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader.js"; import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; import { GUI } from "dat.gui";

    const modelUrl = "https://ylfq.github.io/model/walk.fbx";

    const canvas = document.createElement("canvas"); canvas.style.width = "100vw !important"; canvas.style.height = "100vh !important"; document.body.appendChild(canvas);

    const renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true, alpha: true }); renderer.setClearColor(0x333333, 0); renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFShadowMap;

    const scene = new THREE.Scene();

    const loader_fbx = new FBXLoader();

    const modelMaterialUniforms = { blur: 0.85, blockSize: 12.0, };

    const model = await loader_fbx.loadAsync(modelUrl); model.traverse((obj) => { if (obj instanceof THREE.Mesh) { obj.castShadow = true; obj.receiveShadow = true;

    /* @type {THREE.MeshPhongMaterial}/ const m = obj.material; m.onBeforeCompile = (shader) => { shader.uniforms.blur = { get value() { return modelMaterialUniforms.blur; }, }; shader.uniforms.blockSize = { get value() { return modelMaterialUniforms.blockSize; }, };

    shader.fragmentShader = shader.fragmentShader.replace( /glsl/void main() {, /glsl/// 虚化阈值 uniform float blur; // 虚化区块大小 uniform float blockSize;

    // 虚化矩阵,自定义区块内的虚化顺序,当像素对应的虚化矩阵值小于blur时,该像素不进行渲染 const mat4 blurMatrix = mat4( 0.1, 0.5, 0.7, 0.3, 0.6, 0.6, 0.9, 0.8, 0.8, 1.0, 0.2, 0.6, 0.3, 0.7, 0.5, 0.4 ); void main() { ivec2 xyInBlur = ivec2(fract(gl_FragCoord.xy / blockSize) * 4.0); if (blurMatrix[xyInBlur.y][xyInBlur.x] <= blur) discard;); }; } }); const mixer = new THREE.AnimationMixer(model); const action = mixer.clipAction(model.animations[0]); action.setLoop(THREE.LoopRepeat); action.play();

    const light_ambient = new THREE.AmbientLight(0xffffff, 0.7);

    const light_directional = new THREE.DirectionalLight(0xffffff, 0.8); light_directional.position.set(200, 200, 200); light_directional.castShadow = true; light_directional.shadow.camera.left = -100; light_directional.shadow.camera.right = 100; light_directional.shadow.camera.top = 100; light_directional.shadow.camera.bottom = -100; light_directional.shadow.camera.near = 1; light_directional.shadow.camera.far = 1000; light_directional.shadow.mapSize.width = 1024; light_directional.shadow.mapSize.height = 1024;

    scene.add(model, light_ambient, light_directional);

    const camera = new THREE.PerspectiveCamera(90, 1, 0.1, 1000); camera.position.set(0, 0, 140);

    const controls = new OrbitControls(camera, canvas); controls.enableDamping = true;

    const timer = new THREE.Timer();

    const tick = (delta, elapsed) => { controls.update(delta);

    // 更新动画并限制模型不进行移动 mixer.update(delta * 0.9); model.children[2].children[0].position.set(0, 0, 0); };

    const render = () => { renderer.render(scene, camera); };

    const ani = () => { const elapsed = timer.getElapsed(); const delta = timer.getDelta();

    timer.update();

    tick(delta, elapsed); render();

    requestAnimationFrame(ani); };

    const data = { get blur() { return modelMaterialUniforms.blur; }, set blur(v) { modelMaterialUniforms.blur = v; },

    get blockSize() { return modelMaterialUniforms.blockSize; }, set blockSize(v) { modelMaterialUniforms.blockSize = v; }, }; const gui = new GUI(); gui.add(data, "blur", 0, 1, 0.001).name("虚化强度"); gui.add(data, "blockSize", 2.0, 20.0, 4.0).name("虚化区块大小");

    new ResizeObserver(() => { const rect = document.body.getBoundingClientRect(); const w = rect.width; const h = rect.height; const a = w / h; const dpr = window.devicePixelRatio * 1.25;

    renderer.setSize(w, h, false); renderer.setPixelRatio(dpr);

    camera.aspect = a; camera.updateProjectionMatrix(); }).observe(document.body);

    ani();

    完整源码:GitHub

    小结

    • 本文提供人物虚化完整 Three.js 源码与在线 Demo,建议先运行案例再改 uniform/参数做二次实验
    • 更多 Three.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库
http://www.jsqmd.com/news/1109435/

相关文章:

  • 三相异步电机原理,星三角降压启动原理
  • 基于PIC微控制器的智能RGB灯带系统设计与实现
  • 开源通用漏洞扫描器Sirius Scan:从架构解析到CI/CD集成的实战指南
  • 中国车牌生成器:3分钟学会批量生成合规车牌图片的终极指南
  • 污水池加盖膜材怎么选更划算?全生命周期成本对比与选型建议
  • 6DoF运动追踪:IIM-42652 IMU与PIC32微控制器实战
  • 深度学习优化算法深度解析:从SGD到Sophia的进化之路
  • Sqribble文档流水线:规则驱动的确定性排版系统
  • 传音TEX AI团队AI消除算法技术成果入选ECCV 2026
  • 基于74HC32与PIC18F97J60的2x2矩阵键盘设计
  • QMcDump:终极QQ音乐加密文件解码工具完整指南
  • 米联客F31-4EV(B) Linux开机测试完整流程(零基础手把手)
  • 基于TPAFE0808和MK51DN512的多通道信号采集系统设计
  • NVIDIA A5000与STM32L442KC构建安全边缘计算方案
  • 低成本条码采集系统设计与实现:基于LV30和PIC18F4550
  • League Akari 1.5.0:英雄联盟LCU工具箱完整使用教程,快速提升游戏效率
  • 基于Si4732与PIC18F2525的高保真收音机设计
  • AI工具如何解决本科毕业论文写作三大痛点
  • 工业级房价预测实战:可解释回归建模全流程复盘
  • STM32G431KB与LV3296嵌入式数据采集系统设计
  • 中国车牌生成器:快速生成逼真车牌图像的终极解决方案
  • 基于PIC18F2620的RGB灯带控制系统设计与实现
  • 告别平台限制:3分钟学会用qmcdump解锁QQ音乐加密文件
  • 基于Si4731与STM32的数字收音机设计与实现
  • RPG Maker游戏解密终极指南:3步轻松提取加密资源
  • STM32与Si4731打造低成本可编程收音机系统
  • MuleSoft+LLM企业级AI编排:打通系统孤岛与语义断层
  • STM32F765ZI与BMI270的6DoF IMU开发指南
  • 2026海南省黄金回收白银回收铂金回收旧料回收怎么选?五家高实价铂金白银线下门店测评清单 + 联系方式
  • PIC18F86J16实现DC-DC降压电源设计与优化