news 2026/7/8 13:29:53

Three.js 图片抖动教程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Three.js 图片抖动教程

图片抖动 ·Image Shake· ▶ 在线运行案例

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

你将学到什么

  • ShaderMaterial 自定义着色器实现核心视觉效果
  • THREE.Points 粒子点渲染
  • Canvas 动态纹理贴图
  • BufferGeometry 自定义顶点/索引数据
  • requestAnimationFrame渲染循环与resize自适应

效果说明

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

核心概念

  • Scene / Camera / WebGLRenderer构成最小渲染闭环;大场景可开logarithmicDepthBuffer缓解 Z-fighting。
  • ShaderMaterial通过uniforms+ 自定义 GLSL 控制逐像素/逐点效果;透明粒子常配合depthTest: false
  • THREE.Points将每个顶点渲染为可控大小的粒子;可用自定义 attribute(如u_index)驱动片元/顶点动画。
  • CanvasTexture每帧或按需把 2D Canvas 内容上传 GPU,适合动态文字、图表、视频帧贴图。

实现步骤

  • 搭建 Scene、PerspectiveCamera、WebGLRenderer,挂载 canvas 并处理resize
  • 定义 uniforms / onBeforeCompile 或 ShaderMaterial,编写 GLSL 与材质参数
  • requestAnimationFrame循环中更新状态并 render(Cesium 为viewer.render或自动渲染)
  • 代码要点

    import * as THREE from 'three';

    import { TrackballControls } from 'three/examples/jsm/controls/TrackballControls.js';

    var container; var camera, scene, renderer; var controls;

    var shaderUniforms, shaderAttributes;

    var particles = []; var particleSystem;

    var imageWidth = 640; var imageHeight = 400; var imageData = null;

    var animationTime = 0; var animationDelta = 0.005;

    init(); // tick();

    function init() { createScene(); createControls(); createPixelData();

    window.addEventListener('resize', onWindowResize, false); }

    function createScene() { container = document.getElementById('box');

    scene = new THREE.Scene();

    camera = new THREE.PerspectiveCamera(20, window.innerWidth / window.innerHeight, 1, 10000); camera.position.z = 3000; camera.lookAt(scene.position)

    renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setClearColor(0x000000, 1);

    container.appendChild(renderer.domElement);

    scene.add(new THREE.AxesHelper(1000)); scene.add(new THREE.AmbientLight(0xffffff, 3)); }

    function createControls() { controls = new TrackballControls(camera, renderer.domElement);

    controls.rotateSpeed = 1.0; controls.zoomSpeed = 1.2; controls.panSpeed = 0.8;

    controls.noZoom = false; controls.noPan = true;

    controls.staticMoving = true; controls.dynamicDampingFactor = 0.3; }

    function createPixelData() { var image = document.createElement("img"); var canvas = document.createElement("canvas"); var context = canvas.getContext("2d"); image.crossOrigin = "Anonymous"; image.onload = function() { canvas.width = image.width; canvas.height = image.height; imageWidth = image.width; imageHeight = image.height; context.fillStyle = context.createPattern(image, 'no-repeat'); context.fillRect(0, 0, imageWidth, imageHeight); imageData = context.getImageData(0, 0, imageWidth, imageHeight).data;

    createPaticles(); tick(); }; image.src = HOST + 'files/author/z2586300277.png' }

    function createPaticles() { var colors = []; var weights = [0.2126, 0.7152, 0.0722]; var c = 0;

    var geometry, material; var x, y; var zRange = 400;

    geometry = new THREE.BufferGeometry(); var positions = []; var colors = [];

    x = imageWidth * -0.5; y = imageHeight * 0.5;

    shaderUniforms = { amplitude: { type: "f", value: 0.5 }, vertexColor: { type: "c", value: [] } };

    var shaderMaterial = new THREE.ShaderMaterial({ uniforms: shaderUniforms, vertexShader:uniform float amplitude; attribute vec3 customColor; varying vec3 vColor; void main() { vColor = customColor; vec4 pos = vec4(position, 1.0); pos.z *= amplitude; vec4 mvPosition = modelViewMatrix * pos; gl_PointSize = 2.0 * ( 300.0 / -mvPosition.z ); gl_Position = projectionMatrix * mvPosition; }, fragmentShader:varying vec3 vColor; void main() { gl_FragColor = vec4( vColor, 1.0 ); }, vertexColors: true }); var positions = []; var colors = []; for (var i = 0; i < imageHeight; i++) { for (var j = 0; j < imageWidth; j++) { var color = new THREE.Color(); color.setRGB(imageData[c] / 255, imageData[c + 1] / 255, imageData[c + 2] / 255); var weight = color.r * weights[0] + color.g * weights[1] + color.b * weights[2];

    var vertex = new THREE.Vector3(); vertex.x = x; vertex.y = y; vertex.z = (zRange-0.5) + (zRangeweight); positions.push(vertex.x, vertex.y, vertex.z); colors.push(color.r, color.g, color.b); c += 4; x++; } x = imageWidth * -0.5; y--; } var geometry = new THREE.BufferGeometry(); geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); geometry.setAttribute('customColor', new THREE.Float32BufferAttribute(colors, 3)); particleSystem = new THREE.Points(geometry, shaderMaterial); scene.add(particleSystem); }

    function tick() { requestAnimationFrame(tick); update(); render(); }

    function update() { shaderUniforms.amplitude.value = Math.sin(animationTime); animationTime += animationDelta; controls.update(); }

    function render() { renderer.render(scene, camera); }

    function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); }

    完整源码:GitHub

    小结

    • 本文提供图片抖动完整 Three.js 源码与在线 Demo,建议先运行案例再改 uniform/参数做二次实验
    • 更多 Three.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/8 13:22:10

数据产业服务分类(47)——框架设计——分类维度

数据产业服务分类存在多种维度&#xff0c;通过一种维度对数据产业服务进行分类是不可能的。因此在数据产业服务分类设计之前需要明确分类的维度及其作用。分类维度的选择&#xff0c;是由使用者&#xff0c;及其使用目的所决定的。服务分类应该与服务清单类似&#xff0c;其用…

作者头像 李华
网站建设 2026/7/8 13:18:03

海量数据渲染瓶颈的终极解决方案:高性能表格组件深度解析

海量数据渲染瓶颈的终极解决方案&#xff1a;高性能表格组件深度解析 【免费下载链接】umy-ui A desktop component library based on Vue 2.0 prepared for developers 项目地址: https://gitcode.com/gh_mirrors/umy/umy-ui 在现代企业级应用中&#xff0c;数据可视化…

作者头像 李华