资讯动态

three.js AnaglyphEffect 红绿分色3D渲染实战:API 参数、完整示例与离轴立体投影原理

发布时间:2026/9/7 3:35:59 来源:尧图企业网站定制
three.js AnaglyphEffect 红绿分色3D渲染实战API 参数、完整示例与离轴立体投影原理【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js本文围绕 three.js 官方文档 AnaglyphEffect 展开讲清楚这个红绿分色Anaglyph3D 效果类的全部 API——构造函数、eyeSep/planeDistance参数、render/setSize/dispose方法——并给出官方示例 webgl_effects_anaglyph.html 的完整可运行代码。读完并对照源码 examples/jsm/effects/AnaglyphEffect.js 后你能在不依赖 XR 设备的情况下让普通显示器呈现具有真实深度感的立体画面并理解其背后物理正确的离轴立体投影off-axis stereo projection是如何通过frameCorners()实现的。一、AnaglyphEffect 是什么适用什么渲染器Anaglyph红绿分色是一种经典立体视觉方案用红色滤过左眼图像、青色滤过右眼图像两张图叠加后佩戴红青 3D 眼镜的人眼会分别只看到一侧的画面大脑融合后产生深度感。three.js 的AnaglyphEffect类文档定义为A class that creates an anaglyph effect using physically-correct off-axis stereo projection使用物理正确的离轴立体投影创建红绿分色效果的类。它有两个关键特性离轴投影而非平行投影双眼相机各自偏转、对准同一个虚拟屏幕平面避免传统平行投影criss-cross/parallel导致的梯形失真与视差不适零视差平面Zero Parallax Plane在指定距离处放置虚拟屏幕位于该距离的物体看起来恰好贴在屏幕表面更近的物体凸出屏幕更远的物体凹入屏幕。渲染器限制文档明确要求AnaglyphEffect只能与WebGLRenderer配合使用。若项目使用WebGPURenderer请改用节点式实现 AnaglyphPassNode下文第七节给出对照说明。二、导入与构造AnaglyphEffect是一个 addon附加组件必须显式导入不能通过import * as THREE from three直接获得import { AnaglyphEffect } from three/addons/effects/AnaglyphEffect.js;构造函数new AnaglyphEffect( renderer, width 512, height 512 )参数类型说明默认值rendererWebGLRenderer渲染器实例效果内部所有双通道渲染都通过它完成必填widthnumber效果的宽度物理像素physical pixels512heightnumber效果的高度物理像素physical pixels512注意构造函数接收的是物理像素而setSize()接收的是逻辑像素源码内部会乘以renderer.getPixelRatio()两者单位不要混淆。默认 512×512 只是一个保底值实际项目中几乎总是紧接着调用setSize()覆盖。构造时还会初始化三组 GPU 资源可以从源码 AnaglyphEffect.js#L51-L157 看到两张离屏渲染目标_renderTargetL/_renderTargetRWebGLRenderTargetRGBAFormatminFilter 为LinearFilter、magFilter 为NearestFilter分别缓存左眼、右眼渲染结果一组 Dubois 红青色度矩阵见第五节一个FullScreenQuad合成四边形挂载负责左右眼画面红青混合的ShaderMaterial。三、核心属性eyeSep 与 planeDistance这两个属性决定了立体效果的生理参数和深度基准是调参的主要入口。.eyeSep : number默认0.064瞳距interpupillary distanceIPD即双眼分开的距离单位为世界单位。典型人类瞳距约 0.064 米64mm源码注释见 AnaglyphEffect.js#L67-L74。调整方式取决于场景的比例尺如果你的场景以米为单位建模直接保留0.064如果场景比例不同例如 1 个单位 1 厘米应改为6.4。瞳距过大或过小都会改变物体的相对深度强度——瞳距越大视差越强立体感越夸张但也越容易视觉疲劳。.planeDistance : number默认0.5观察者到虚拟屏幕平面的距离世界单位即零视差发生的位置。文档对其行为的描述是Objects at this distance appear at the screen surface. Objects closer appear in front of the screen (negative parallax). Objects further appear behind the screen (positive parallax).The screen dimensions are derived from the cameras FOV and aspect ratio at this distance, ensuring the stereo view matches the cameras field of view.翻译过来位于该距离的物体 → 看起来贴在屏幕表面零视差更近的物体 → 凸出屏幕前方负视差更远的物体 → 凹入屏幕后方正视差。同时虚拟屏幕的宽高会由相机 FOV 与长宽比在该距离上推导出来源码中halfHeight planeDistance * tan(fov/2)halfWidth halfHeight * aspect见 AnaglyphEffect.js#L206-L207保证立体视场的视场角与你原本的相机完全一致不会因开启立体效果而放大或缩小画面。调参经验官方示例中把planeDistance设为3正好等于相机到场景中心的距离让画面中心区域落在屏幕深度上示例注释Match camera distance to origin for zero parallax at scene center见 webgl_effects_anaglyph.html#L101-L105。一个实用的做法是把planeDistance设为你想让画面看起来平的那一层内容到相机的距离。四、完整可运行示例以下代码整理自官方示例 webgl_effects_anaglyph.html用 import map 方式引用本地构建产物可直接放入项目使用!DOCTYPE html html langen head meta charsetutf-8 meta nameviewport contentwidthdevice-width, user-scalableno /head body script typeimportmap { imports: { three: ../build/three.module.js, three/addons/: ./jsm/ } } /script script typemodule import * as THREE from three; import { AnaglyphEffect } from three/addons/effects/AnaglyphEffect.js; let container, camera, scene, renderer, effect; const spheres []; let mouseX 0, mouseY 0; let windowHalfX window.innerWidth / 2; let windowHalfY window.innerHeight / 2; document.addEventListener( mousemove, ( event ) { mouseX ( event.clientX - windowHalfX ) / 100; mouseY ( event.clientY - windowHalfY ) / 100; } ); function init() { container document.createElement( div ); document.body.appendChild( container ); // 透视相机FOV 60近裁剪面 0.01相机位于 z3 camera new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.01, 100 ); camera.position.z 3; scene new THREE.Scene(); // 500 个球体用于展示立体深度 const geometry new THREE.SphereGeometry( 0.1, 32, 16 ); const material new THREE.MeshBasicMaterial( { color: 0xffffff } ); for ( let i 0; i 500; i ) { const mesh new THREE.Mesh( geometry, material ); mesh.position.set( Math.random() * 10 - 5, Math.random() * 10 - 5, Math.random() * 10 - 5 ); const s Math.random() * 3 1; mesh.scale.setScalar( s ); scene.add( mesh ); spheres.push( mesh ); } renderer new THREE.WebGLRenderer(); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setAnimationLoop( animate ); container.appendChild( renderer.domElement ); // 1) 构造效果只传 renderer尺寸随后由 setSize 指定 const width window.innerWidth || 2; const height window.innerHeight || 2; effect new AnaglyphEffect( renderer ); effect.setSize( width, height ); // 2) 配置立体参数 effect.eyeSep 0.064; // 瞳距 64mm场景以米为单位 effect.planeDistance 3; // 与相机到场景中心的距离一致 → 场景中心零视差 window.addEventListener( resize, onWindowResize ); } function onWindowResize() { windowHalfX window.innerWidth / 2; windowHalfY window.innerHeight / 2; camera.aspect window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); // 3) 窗口变化时同步调整效果尺寸 effect.setSize( window.innerWidth, window.innerHeight ); } function animate() { render(); } function render() { const timer 0.0001 * Date.now(); camera.position.x ( mouseX - camera.position.x ) * .05; camera.position.y ( - mouseY - camera.position.y ) * .05; camera.lookAt( scene.position ); for ( let i 0; i spheres.length; i ) { spheres[ i ].position.x 5 * Math.cos( timer i ); spheres[ i ].position.y 5 * Math.sin( timer i * 1.1 ); } // 4) 关键用 effect.render 替代 renderer.render effect.render( scene, camera ); } init(); /script /body /html四个要点回顾new AnaglyphEffect( renderer )构造effect.setSize( width, height )指定逻辑像素尺寸按场景比例设置eyeSep与planeDistance渲染循环中调用effect.render( scene, camera )而不是renderer.render( scene, camera )——这是文档对render方法的明确定义this method should be called instead of the default WebGLRenderer#render。五、源码级原理一次 effect.render 内部发生了什么render( scene, camera )的完整实现在 AnaglyphEffect.js#L183-L254可以拆成四步1. 从相机世界矩阵提取坐标轴并计算双眼位置camera.matrixWorld.extractBasis( _right, _up, _forward ); const halfSep this.eyeSep / 2; _eyeL.copy( camera.position ).addScaledVector( _right, - halfSep ); // 左眼 _eyeR.copy( camera.position ).addScaledVector( _right, halfSep ); // 右眼注意眼睛的偏移方向来自相机的世界坐标右轴而非全局 X 轴——即使相机翻转、倾斜左右眼的相对位置依然正确。2. 推导虚拟屏幕四角用 frameCorners 构建离轴投影_screenCenter.copy( camera.position ).addScaledVector( _forward, - this.planeDistance ); const halfHeight this.planeDistance * Math.tan( MathUtils.DEG2RAD * camera.fov / 2 ); const halfWidth halfHeight * camera.aspect; // …由 _screenCenter ± halfWidth*_right ± halfHeight*_up 算出屏幕三个角点 frameCorners( _cameraL, _screenBottomLeft, _screenBottomRight, _screenTopLeft, true );frameCorners来自 CameraUtils.js#L34-L80它是整套立体方案的核心以屏幕三corner点为基准构造离轴投影矩阵off-axis frustum——projectionMatrix中第三、六列(rl)/(r-l)、(tb)/(t-b)的偏移项使左眼相机的视锥中心指向屏幕、右眼相机的视锥中心指向同一点两个视锥精确共面shared plane这正是物理正确的来源屏幕上任意一点对双眼而言都在同一条视线交点上从而保证零视差平面上没有视差误差同时把相机四元数旋转到使焦平面贴合屏幕平面最后一个参数estimateViewFrustum true会为相机估算一个保守的 FOVto make frustum tall/wide enough to encompass it——用于修正离轴视锥下的视锥剔除frustum culling避免画面边缘物体被错误剔除。调用之后效果内部手动compose了matrixWorld并求逆matrixWorldInverseAnaglyphEffect.js#L227-L236因为离轴矩阵已经手工写入projectionMatrix绕过了常规的updateProjectionMatrix()流程——frameCorners的注释也明确提醒do not call updateProjectionMatrix() after this。3. 双通道渲染左右眼各渲染一次完整场景到独立渲染目标renderer.setRenderTarget( _renderTargetL ); renderer.clear(); renderer.render( scene, _cameraL ); renderer.setRenderTarget( _renderTargetR ); renderer.clear(); renderer.render( scene, _cameraR );因此开启 AnaglyphEffect 后每帧的渲染负载约为原来的 2 倍再加一次全屏合成这是性能上必须知晓的代价对大型场景可考虑降低离屏目标分辨率。4. 红青色度矩阵合成合成着色器从两张离屏纹理采样后执行vec3 color clamp( colorMatrixLeft * colorL.rgb colorMatrixRight * colorR.rgb, 0., 1. ); gl_FragColor vec4( color, max( colorL.a, colorR.a ) ); #include tonemapping_fragment #include colorspace_fragment所用的色度矩阵是 Dubois 最小二乘优化的红青矩阵源码注释标注了出处见 AnaglyphEffect.js#L53-L65// 左眼[ 0.4561, -0.0400822, -0.0152161; // 0.500484, -0.0378246, -0.0205971; // 0.176381, -0.0157589, -0.00546856 ] // 右眼[ -0.0434706, 0.378476, -0.0721527; // -0.0879388, 0.73364, -0.112961; // -0.00155529, -0.0184503, 1.2264 ]相比最朴素的左眼只留红、右眼只留青绿蓝做法Dubois 矩阵通过跨通道混合在色度上做了全局最小二乘拟合能保留更多原场景颜色信息、减少鬼影retinal rivalry。合成末尾的两个#include保证合成结果同样经过 tone mapping 与色彩空间转换与主渲染管线保持一致。六、setSize 与 dispose生命周期管理.setSize( width, height )setSize( width, height ) // 逻辑像素源码实现AnaglyphEffect.js#L165-L174做了三件事renderer.setSize( width, height ); const pixelRatio renderer.getPixelRatio(); _renderTargetL.setSize( width * pixelRatio, height * pixelRatio ); _renderTargetR.setSize( width * pixelRatio, height * pixelRatio );即同步调整画布尺寸并按当前pixelRatio把左右眼离屏目标放大到对应物理分辨率。窗口 resize 时必须调用它同时记得更新camera.aspect并camera.updateProjectionMatrix()否则屏幕尺寸与立体视场的长宽比推导会不一致画面会拉伸或裁剪错误。.dispose()effect.dispose();释放两张WebGLRenderTarget、合成ShaderMaterial和FullScreenQuadAnaglyphEffect.js#L260-L268。在 SPA 页面切换、场景销毁或热重载时调用避免 GPU 资源泄漏。七、WebGPU 对照AnaglyphPassNode文档明确指出使用WebGPURenderer时应改用 AnaglyphPassNode。两者共享同一套frameCorners离轴投影算法updateStereoCamera中的屏幕四角推导与 WebGL 版逐行对应见 AnaglyphPassNode.js#L447-L502但节点版把合成逻辑搬进 TSLthree Shadertoy Language节点管线且提供了远比AnaglyphEffect更丰富的色度算法import { anaglyphPass, AnaglyphAlgorithm, AnaglyphColorMode } from three/addons/tsl/display/AnaglyphPassNode.js; const pass anaglyphPass( scene, camera ); pass.algorithm AnaglyphAlgorithm.DUBOIS; // 默认即 dubois pass.colorMode AnaglyphColorMode.RED_CYAN; // 默认 redCyan pass.eyeSep 0.064; pass.planeDistance 3;其中AnaglyphAlgorithm提供TRUE、GREY、COLOUR、HALF_COLOUR、DUBOIS、OPTIMISED、COMPROMISE七种分色算法AnaglyphColorMode提供RED_CYAN、MAGENTA_CYAN、MAGENTA_GREEN三种配色矩阵表完整定义见 AnaglyphPassNode.js#L114-L270注释中各算法的来源论文也一一标注。AnaglyphEffect则固定使用 Dubois 红青矩阵不可切换——如果你的产品需要灰度模式减少眩晕或Magenta/Cyan 配色WebGPU 管线是更灵活的选择。八、使用要点小结要点说明渲染器仅限WebGLRendererWebGPURenderer用AnaglyphPassNode渲染调用用effect.render( scene, camera )替代renderer.render(...)eyeSep世界单位瞳距默认0.064对应米制场景 64mm按场景比例尺换算planeDistance默认0.5建议设为希望呈现为平面的内容层到相机的距离官方示例取相机到场景中心的3尺寸构造参数是物理像素setSize是逻辑像素内部按pixelRatio换算窗口 resize 必须同步更新相机 aspect 与setSize性能每帧 左眼全场景 右眼全场景 全屏合成约为 2 倍场景渲染开销资源场景销毁时调用effect.dispose()释放离屏目标与合成材质通过AnaglyphEffectthree.js 把一个需要自己处理双相机、离轴矩阵与色度矩阵的问题收敛成了三行代码构造、setSize、render而frameCorners带来的零视差平面保证使它在普通显示器上也能得到几何上正确的红青立体效果需要更多分色算法或 WebGPU 管线时切换到AnaglyphPassNode即可无缝复用同一套立体相机算法。【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价