Selaa lähdekoodia

docs(zh): fill missing manual pages (#33021)

DDDDD12138 5 päivää sitten
vanhempi
sitoutus
83d7b8c457

+ 15 - 1
manual/list.json

@@ -339,6 +339,15 @@
 			"相关资源": "zh/useful-links",
 			"WebGL兼容性检查": "zh/webgl-compatibility-check"
 		},
+		"进阶": {
+			"动画系统": "zh/animation-system",
+			"颜色管理": "zh/color-management",
+			"如何创建VR内容": "zh/how-to-create-vr-content",
+			"如何释放对象": "zh/how-to-dispose-of-objects",
+			"如何更新对象": "zh/how-to-update-things",
+			"如何使用后处理": "zh/how-to-use-post-processing",
+			"矩阵变换": "zh/matrix-transformations"
+		},
 		"---": {},
 		"基本": {
 			"基础": "zh/fundamentals",
@@ -356,7 +365,8 @@
 			"阴影": "zh/shadows",
 			"雾": "zh/fog",
 			"渲染目标": "zh/rendertargets",
-			"自定义缓冲几何体": "zh/custom-buffergeometry"
+			"自定义缓冲几何体": "zh/custom-buffergeometry",
+			"物理": "zh/physics"
 		},
 		"技巧": {
 			"按需渲染": "zh/rendering-on-demand",
@@ -390,6 +400,10 @@
 			"体素几何体 (Minecraft)": "zh/voxel-geometry",
 			"来试试做一个游戏吧": "zh/game"
 		},
+		"WebGPU": {
+			"WebGPU渲染器": "zh/webgpurenderer",
+			"后处理": "zh/webgpu-postprocessing"
+		},
 		"WebXR": {
 			"VR - 基础": "zh/webxr-basics",
 			"VR - 用目光进行选择": "zh/webxr-look-to-select",

+ 169 - 0
manual/zh/animation-system.html

@@ -0,0 +1,169 @@
+<!DOCTYPE html><html lang="zh"><head>
+    <meta charset="utf-8">
+    <title>动画系统</title>
+    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+    <meta name="twitter:card" content="summary_large_image">
+    <meta name="twitter:site" content="@threejs">
+    <meta name="twitter:title" content="Three.js - 动画系统">
+    <meta property="og:image" content="https://threejs.org/files/share.png">
+    <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
+    <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">
+
+    <link rel="stylesheet" href="../resources/lesson.css">
+    <link rel="stylesheet" href="../resources/lang.css">
+    <link rel="stylesheet" href="/manual/zh/lang.css">
+<script type="importmap">
+{
+  "imports": {
+    "three": "../../build/three.module.js"
+  }
+}
+</script>
+  </head>
+  <body>
+    <div class="container">
+      <div class="lesson-title">
+        <h1>动画系统</h1>
+      </div>
+      <div class="lesson">
+        <div class="lesson-main">
+ 
+          <h2>概述</h2>
+
+		<p class="desc">
+			在 three.js 的动画系统中,你可以为模型的多种属性制作动画:
+			例如蒙皮绑定模型的骨骼、形态目标(morph targets)、不同材质属性
+			(颜色、不透明度、布尔值)、可见性与变换。动画属性可以淡入、
+			淡出、交叉淡化(crossfade)和变速。即使是同一对象上的多个动画,
+			或不同对象上的多个动画,也可以独立调整权重和时间缩放,
+			并进行同步。<br /><br />
+
+			为了在一个统一系统中实现这些功能,three.js 动画系统在
+			2015 年[link:https://github.com/mrdoob/three.js/issues/6881 发生了彻底重构]
+			(注意甄别过时资料)。当前架构与 Unity / Unreal Engine 4
+			更接近。本页将简要介绍该系统的核心组件,以及它们如何协同工作。
+
+		</p>
+
+		<h3>动画片段(Animation Clips)</h3>
+
+		<p class="desc">
+
+			当你成功导入一个带动画的 3D 对象后(无论它使用骨骼、形态目标,或两者兼有),
+			比如通过 [link:https://github.com/KhronosGroup/glTF-Blender-IO glTF Blender 导出器]
+			从 Blender 导出,再使用 `GLTFLoader` 加载到 three.js 场景中,
+			返回结果中通常会有一个名为 "animations" 的数组字段,
+			其中包含该模型的动画片段(下文会列出支持此能力的加载器)。<br /><br />
+
+			每个 `AnimationClip` 一般表示对象的一种动作数据。以角色模型为例,
+			可以有一个片段表示走路,第二个表示跳跃,第三个表示侧移,等等。
+
+		</p>
+
+		<h3>关键帧轨道(Keyframe Tracks)</h3>
+
+		<p class="desc">
+
+			在 `AnimationClip` 内部,每个被动画驱动的属性都会存储在独立的
+			`KeyframeTrack` 中。假设角色有骨架,那么一条轨道可以记录前臂骨骼
+			随时间变化的位置数据,另一条记录同一骨骼的旋转变化,第三条记录
+			其他骨骼的位置、旋转或缩放,依此类推。也就是说,
+			一个 AnimationClip 通常由大量此类轨道组成。<br /><br />
+
+			如果模型有形态目标(比如一个表示微笑,另一个表示愤怒),
+			每条相关轨道会描述某个形态目标在该片段播放过程中,
+			其影响权重如何随时间变化。
+
+		</p>
+
+		<h3>动画混合器(Animation Mixer)</h3>
+
+		<p class="desc">
+
+			这些存储的数据只是动画基础,真正的播放控制由 `AnimationMixer` 完成。
+			你可以把它理解成不只是一个“播放器”,更像一台真实的混音台:
+			能够同时控制多个动画,并对它们进行混合与融合。
+
+		</p>
+
+		<h3>动画动作(Animation Actions)</h3>
+
+		<p class="desc">
+
+			`AnimationMixer` 本身只有少量通用属性和方法,
+			因为它主要通过动画动作来驱动。通过配置 `AnimationAction`,
+			你可以决定某个 `AnimationClip` 在某个 mixer 上何时播放、暂停或停止,
+			是否循环、循环次数、是否淡入淡出、是否进行时间缩放,
+			以及更多高级控制(如交叉淡化与同步)。
+
+		</p>
+
+		<h3>动画对象组(Animation Object Groups)</h3>
+
+		<p class="desc">
+
+			如果你希望一组对象共享同一套动画状态,
+			可以使用 `AnimationObjectGroup`。
+
+		</p>
+
+		<h3>支持的格式与加载器</h3>
+
+		<p class="desc">
+			请注意,并非所有模型格式都包含动画(例如 OBJ 就不包含),
+			而且只有部分 three.js 加载器支持 `AnimationClip` 序列。
+			下面这些加载器<i>支持</i>这种动画数据:
+		</p>
+
+			<ul>
+				<li>THREE.ObjectLoader</li>
+				<li>THREE.BVHLoader</li>
+				<li>THREE.ColladaLoader</li>
+				<li>THREE.FBXLoader</li>
+				<li>THREE.GLTFLoader</li>
+			</ul>
+
+		<p class="desc">
+			另外,3ds Max 和 Maya 目前还不能直接将多个动画
+			(即不在同一时间轴上的动画)导出到同一个文件中。
+		</p>
+
+		<h2>示例</h2>
+
+<pre class="prettyprint notranslate lang-js" translate="no">
+let mesh;
+
+// 创建 AnimationMixer,并获取 AnimationClip 列表
+const mixer = new THREE.AnimationMixer( mesh );
+const clips = mesh.animations;
+
+// 每帧更新 mixer
+function update () {
+  mixer.update( deltaSeconds );
+}
+
+// 播放指定动画
+const clip = THREE.AnimationClip.findByName( clips, 'dance' );
+const action = mixer.clipAction( clip );
+action.play();
+
+// 播放全部动画
+clips.forEach( function ( clip ) {
+  mixer.clipAction( clip ).play();
+} );
+</pre>
+         
+        </div>
+      </div>
+    </div>
+
+  <script src="../resources/prettify.js"></script>
+  <script src="../resources/lesson.js"></script>
+
+
+
+
+</body></html>
+
+
+

+ 351 - 0
manual/zh/color-management.html

@@ -0,0 +1,351 @@
+<!DOCTYPE html><html lang="zh"><head>
+    <meta charset="utf-8">
+    <title>颜色管理</title>
+    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+    <meta name="twitter:card" content="summary_large_image">
+    <meta name="twitter:site" content="@threejs">
+    <meta name="twitter:title" content="Three.js - 颜色管理">
+    <meta property="og:image" content="https://threejs.org/files/share.png">
+    <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
+    <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">
+
+    <link rel="stylesheet" href="../resources/lesson.css">
+    <link rel="stylesheet" href="../resources/lang.css">
+    <link rel="stylesheet" href="/manual/zh/lang.css">
+<script type="importmap">
+{
+  "imports": {
+    "three": "../../build/three.module.js"
+  }
+}
+</script>
+<style>
+  blockquote {
+    font-size: 0.8em;
+    line-height: 1.5em;
+    margin-left: 0;
+    border-left: 4px solid #cccccc;
+    padding: 1em 2em 1em 2em;
+  }
+
+  blockquote p:first-child {
+    margin-top: 0;
+  }
+
+  blockquote p:last-child {
+    margin-bottom: 0;
+  }
+
+  figure {
+    width: 100%;
+    margin: 1em 0;
+    font-style: italic;
+  }
+
+  figure img {
+    width: 100%;
+  }
+
+  figure.float {
+    float: right;
+    max-width: 30%;
+    margin: 1em;
+  }
+
+  @media all and ( max-width: 640px ) {
+
+    figure.float {
+      float: none;
+      max-width: 100%;
+    }
+
+  }
+</style>
+  </head>
+  <body>
+    <div class="container">
+      <div class="lesson-title">
+        <h1>颜色管理</h1>
+      </div>
+      <div class="lesson">
+        <div class="lesson-main">
+        
+			<h2>什么是色彩空间?</h2>
+
+	<p>
+		每一种色彩空间,都是一组经过权衡的设计选择。它们共同目标是:
+		在满足精度和显示技术限制的前提下,覆盖尽可能大的颜色范围。
+		在创建 3D 资源或把多个 3D 资源组装进同一场景时,
+		理解这些属性及其在不同色彩空间之间的关系非常重要。
+	</p>
+
+	<figure class="float">
+		<img src="../resources/srgb_gamut.png" alt="">
+		<figcaption>
+			参考 CIE 1931 色度图中的 sRGB 颜色与白点(D65)。
+			彩色区域是 sRGB 色域(三维体积)在二维中的投影。
+			来源:<a href="https://en.wikipedia.org/wiki/SRGB" target="_blank" rel="noopener">Wikipedia</a>
+		</figcaption>
+	</figure>
+
+	<ul>
+		<li>
+			<b>色彩原色(Color primaries):</b>原色(如红、绿、蓝)并非绝对值;
+			它们是在有限精度与显示设备能力约束下,从可见光谱中选定的。
+			颜色由各原色的比例来表达。
+		</li>
+		<li>
+			<b>白点(White point):</b>大多数色彩空间都会定义:
+			当原色满足 <i>R = G = B</i> 时呈现“无色(中性)”。
+			白、灰等中性色的视觉效果依赖人眼感知,而感知又与观察环境相关。
+			因此色彩空间会指定一个“白点”以统一基准。
+			sRGB 的白点是 [link:https://en.wikipedia.org/wiki/Illuminant_D65 D65]。
+		</li>
+		<li>
+			<b>传递函数(Transfer functions):</b>在确定色域和颜色模型后,
+			还要定义数值与颜色空间之间的映射(传递函数)。
+			<i>r = 0.5</i> 是表示物理光照比 <i>r = 1.0</i> 少 50%,
+			还是表示人眼感知亮度少 50%?两者并不等价,
+			差异由数学函数来描述。根据目标不同,传递函数可以是
+			<i>线性</i>或<i>非线性</i>。sRGB 使用非线性传递函数。
+			这些函数有时会近似为<i>伽马函数</i>,但“gamma”一词在这里含义模糊,
+			应尽量避免混用。
+		</li>
+	</ul>
+
+	以上三个参数(原色、白点、传递函数)共同定义了一个色彩空间。
+	在此基础上,再补充几个术语会更清晰:
+
+	<ul>
+		<li>
+			<b>颜色模型(Color model):</b>在既定色域中用数字描述颜色的方式,
+			可理解为颜色坐标系。在 three.js 里我们主要使用 RGB 模型,
+			坐标为 <i>r, g, b ∈ [0,1]</i>(闭区间)或
+			<i>r, g, b ∈ [0,+∞)</i>(开域),每一项都表示某个原色所占比例。
+			其他模型(HSL、Lab、LCH)常用于美术调色。
+		</li>
+		<li>
+			<b>色域(Color gamut):</b>当原色与白点确定后,就确定了可见光谱中的一个体积范围,
+			这就是“色域”。不在这个体积内的颜色(超出色域)无法用闭区间 [0,1] 的 RGB 表达。
+			在开域 [0,+∞) 中,色域在数学上可以视为无限。
+		</li>
+	</ul>
+
+	<p>
+		来看两个最常见的色彩空间:`SRGBColorSpace`(sRGB)与
+		`LinearSRGBColorSpace`(Linear-sRGB)。两者原色和白点相同,
+		因此色域一致,也都使用 RGB 模型。它们只在传递函数上不同:
+		Linear-sRGB 相对于物理光强是线性的;sRGB 使用非线性传递函数,
+		更接近人眼感知与常见显示设备的响应特性。
+	</p>
+
+	<p>
+		这个差异非常关键。光照计算和大多数渲染运算通常必须在线性色彩空间中完成。
+		但线性颜色在图像或帧缓冲中的存储效率较低,且直接显示给人眼时观感不正确。
+		因此,输入纹理与最终输出图像通常会使用非线性的 sRGB 色彩空间。
+	</p>
+
+	<blockquote>
+		<p>
+			ℹ️ <i><b>注意:</b>虽然部分现代显示器支持 Display-P3 等更宽色域,
+				但 Web 平台图形 API 仍主要基于 sRGB。
+				当前 three.js 应用通常只会使用 sRGB 与 Linear-sRGB。</i>
+		</p>
+	</blockquote>
+
+	<h2>色彩空间在流程中的角色</h2>
+
+	<p>
+		现代渲染所需的线性工作流通常会涉及不止一种色彩空间,
+		每种色彩空间承担不同职责。线性与非线性色彩空间适用于不同环节,
+		如下所示。
+	</p>
+
+	<h3>输入色彩空间</h3>
+
+	<p>
+		传入 three.js 的颜色(来自取色器、纹理、3D 模型等)都带有各自色彩空间。
+		凡是不在 Linear-sRGB 工作色彩空间中的输入,都需要转换;
+		纹理也必须正确设置 <i>texture.colorSpace</i>。
+		如果在初始化颜色前启用 THREE.ColorManagement,
+		某些转换(如十六进制颜色与 CSS sRGB 颜色)会自动处理:
+	</p>
+
+	<code>
+THREE.ColorManagement.enabled = true;
+	</code>
+
+	<p>
+		THREE.ColorManagement 默认已启用。
+	</p>
+
+	<ul>
+		<li>
+			<b>材质、灯光与着色器:</b>其颜色数据中的 RGB 分量存储在线性的
+			Linear-sRGB 工作空间中。
+		</li>
+		<li>
+			<b>顶点颜色:</b>`BufferAttribute` 中的 RGB 分量也存储在
+			Linear-sRGB 工作空间中。
+		</li>
+		<li>
+			<b>颜色纹理:</b>包含颜色信息的 PNG/JPEG `Texture`
+			(如 `.map`、`.emissiveMap`)应使用闭区间 sRGB,
+			并标注 <i>texture.colorSpace = SRGBColorSpace</i>。
+			OpenEXR 等格式(常用于 `.envMap`、`.lightMap`)则使用 Linear-sRGB,
+			标注为 <i>texture.colorSpace = LinearSRGBColorSpace</i>,
+			并且可能包含开域 [0,+∞) 的值。
+		</li>
+		<li>
+			<b>非颜色纹理:</b>不存储颜色信息的纹理(如 `.normalMap`、`.roughnessMap`)
+			没有对应色彩空间,一般使用默认标注
+			<i>texture.colorSpace = NoColorSpace</i>。
+			在少数场景下,非颜色数据可能因技术原因采用其他非线性编码。
+		</li>
+	</ul>
+
+	<blockquote>
+		<p>
+			⚠️ <i><b>警告:</b>许多 3D 模型格式并未正确或一致地定义色彩空间信息。
+			three.js 虽会尽量处理常见情况,但旧格式仍常出现问题。
+			为获得最佳结果,请优先使用 glTF 2.0(`GLTFLoader`),
+			并尽早在在线查看器中验证资源本身是否正确。</i>
+		</p>
+	</blockquote>
+
+	<h3>工作色彩空间</h3>
+
+	<p>
+		渲染、插值及许多其他计算,必须在开域的线性工作色彩空间中进行,
+		此时 RGB 分量与物理光照强度成比例。在 three.js 中,
+		工作色彩空间是 Linear-sRGB。
+	</p>
+
+	<h3>输出色彩空间</h3>
+
+	<p>
+		输出到显示设备、图片或视频时,通常需要将开域 Linear-sRGB
+		工作空间转换到目标色彩空间。该转换由
+		`WebGLRenderer.outputColorSpace` 定义。
+		使用后处理时,需要 `OutputPass`。
+	</p>
+
+	<ul>
+		<li>
+			<b>显示:</b>写入 WebGL 画布并显示的颜色应使用 sRGB。
+		</li>
+		<li>
+			<b>图像:</b>写入图像时应使用与格式和用途匹配的色彩空间。
+			完整渲染后保存为 PNG/JPEG 的图片通常使用 sRGB。
+			若图像包含自发光、光照贴图或其他不受 [0,1] 限制的数据,
+			通常使用开域 Linear-sRGB,并配合 OpenEXR 等兼容格式。
+		</li>
+	</ul>
+
+	<blockquote>
+		<p>
+			⚠️ <i><b>警告:</b>渲染目标可使用 sRGB 或 Linear-sRGB。
+			sRGB 在有限精度下利用率更高:在闭区间内,sRGB 常用 8-bit 即可,
+			而 Linear-sRGB 可能需要至少 16-bit(half float)。
+			若后续管线阶段还要求 Linear-sRGB 输入,额外转换会带来一定性能开销。</i>
+		</p>
+	</blockquote>
+
+	<p>
+		基于 `ShaderMaterial` 和 `RawShaderMaterial` 的自定义材质需要自行实现输出色彩空间转换。
+		对于 `ShaderMaterial`,通常在片元着色器 `main()` 中加入
+		`colorspace_fragment` shader chunk 即可。
+	</p>
+
+	<h2>使用 THREE.Color 实例</h2>
+
+	<p>
+		读取或修改 `Color` 的方法默认假设数据已经在 three.js 的工作色彩空间
+		(Linear-sRGB)中。RGB 与 HSL 分量都直接对应 `Color` 实例内部数据,
+		不会被隐式转换。你可以显式调用
+		<i>.convertLinearToSRGB()</i> 或 <i>.convertSRGBToLinear()</i> 进行转换。
+	</p>
+
+<pre class="prettyprint notranslate lang-js" translate="no">
+// RGB 分量(不发生转换)。
+color.r = color.g = color.b = 0.5;
+console.log( color.r ); // → 0.5
+
+// 手动转换。
+color.r = 0.5;
+color.convertSRGBToLinear();
+console.log( color.r ); // → 0.214041140
+</pre>
+
+	<p>
+		当设置 <i>ColorManagement.enabled = true</i>(推荐,且默认开启)后,
+		某些转换会自动执行。由于十六进制与 CSS 颜色通常属于 sRGB,
+		`Color` 在 setter 中会把它们从 sRGB 转为 Linear-sRGB;
+		在 getter 返回十六进制或 CSS 值时,则会从 Linear-sRGB 转回 sRGB。
+	</p>
+
+<pre class="prettyprint notranslate lang-js" translate="no">
+// 十六进制转换。
+color.setHex( 0x808080 );
+console.log( color.r ); // → 0.214041140
+console.log( color.getHex() ); // → 0x808080
+
+// CSS 颜色转换。
+color.setStyle( 'rgb( 0.5, 0.5, 0.5 )' );
+console.log( color.r ); // → 0.214041140
+
+// 通过 'colorSpace' 参数覆盖默认转换。
+color.setHex( 0x808080, LinearSRGBColorSpace );
+console.log( color.r ); // → 0.5
+console.log( color.getHex( LinearSRGBColorSpace ) ); // → 0x808080
+console.log( color.getHex( SRGBColorSpace ) ); // → 0xBCBCBC
+</pre>
+
+	<h2>常见错误</h2>
+
+	<p>
+		当某个颜色或纹理配置错误时,它看起来会比预期更亮或更暗。
+		当渲染器输出色彩空间配置错误时,整张场景都可能偏暗
+		(例如遗漏了到 sRGB 的转换)或偏亮(例如后处理中重复转换到 sRGB)。
+		这类问题通常并非全局线性偏差,单纯增减光照并不能真正解决。
+	</p>
+
+	<p>
+		更隐蔽的问题是:当输入和输出色彩空间<i>都</i>设置错误时,
+		整体亮度看似正常,但颜色会在不同光照下异常变化,
+		或明暗层次变得过曝、生硬。两个错误不会相互抵消。
+		务必确保工作色彩空间是线性的(scene referred),
+		输出色彩空间是非线性的(display referred)。
+	</p>
+
+	<h2>延伸阅读</h2>
+
+	<ul>
+		<li>
+			<a href="https://developer.nvidia.com/gpugems/gpugems3/part-iv-image-effects/chapter-24-importance-being-linear" target="_blank" rel="noopener">GPU Gems 3: The Importance of Being Linear</a>, by Larry Gritz and Eugene d'Eon
+		</li>
+		<li>
+			<a href="https://blog.johnnovak.net/2016/09/21/what-every-coder-should-know-about-gamma/" target="_blank" rel="noopener">What every coder should know about gamma</a>, by John Novak
+		</li>
+		<li>
+			<a href="https://hg2dc.com/" target="_blank" rel="noopener">The Hitchhiker's Guide to Digital Color</a>, by Troy Sobotka
+		</li>
+		<li>
+			<a href="https://docs.blender.org/manual/en/latest/render/color_management.html" target="_blank" rel="noopener">Color Management</a>, Blender
+		</li>
+	</ul>
+
+        </div>
+      </div>
+    </div>
+
+  <script src="../resources/prettify.js"></script>
+  <script src="../resources/lesson.js"></script>
+
+
+
+
+</body></html>
+
+
+

+ 109 - 0
manual/zh/how-to-create-vr-content.html

@@ -0,0 +1,109 @@
+<!DOCTYPE html><html lang="zh"><head>
+    <meta charset="utf-8">
+    <title>如何创建 VR 内容</title>
+    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+    <meta name="twitter:card" content="summary_large_image">
+    <meta name="twitter:site" content="@threejs">
+    <meta name="twitter:title" content="Three.js - 如何创建 VR 内容">
+    <meta property="og:image" content="https://threejs.org/files/share.png">
+    <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
+    <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">
+
+    <link rel="stylesheet" href="../resources/lesson.css">
+    <link rel="stylesheet" href="../resources/lang.css">
+    <link rel="stylesheet" href="/manual/zh/lang.css">
+<script type="importmap">
+{
+  "imports": {
+    "three": "../../build/three.module.js"
+  }
+}
+</script>
+  </head>
+  <body>
+    <div class="container">
+      <div class="lesson-title">
+        <h1>如何创建 VR 内容</h1>
+      </div>
+      <div class="lesson">
+        <div class="lesson-main">
+          
+          <p>
+            本指南简要介绍如何使用 three.js 构建一个基于 Web 的 VR 应用,
+            以及其中最基础的组成部分。
+          </p>
+        
+          <h2>工作流程</h2>
+        
+          <p>
+            首先,在项目中引入
+            [link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/webxr/VRButton.js VRButton.js]。
+          </p>
+        
+<pre class="prettyprint notranslate lang-js" translate="no">
+import { VRButton } from 'three/addons/webxr/VRButton.js';
+</pre>
+        
+          <p>
+            *VRButton.createButton()* 会做两件重要的事:它会创建一个用于指示
+            VR 兼容性的按钮;此外,如果用户点击该按钮,它会发起 VR 会话。
+            你只需要在应用中添加下面这行代码。
+          </p>
+        
+<pre class="prettyprint notranslate lang-js" translate="no">
+document.body.appendChild( VRButton.createButton( renderer ) );
+</pre>
+        
+          <p>
+            接下来,需要在 `WebGLRenderer` 实例上启用 XR 渲染。
+          </p>
+        
+<pre class="prettyprint notranslate lang-js" translate="no">
+renderer.xr.enabled = true;
+</pre>
+        
+          <p>
+            最后,要调整动画循环。VR 场景中不再使用常见的
+            *window.requestAnimationFrame()*,而是使用 `renderer.setAnimationLoop()`。
+            最小示例代码如下:
+          </p>
+        
+<pre class="prettyprint notranslate lang-js" translate="no">
+renderer.setAnimationLoop( function () {
+
+  renderer.render( scene, camera );
+
+} );
+</pre>
+        
+          <h2>下一步</h2>
+        
+          <p>
+            可以查看官方 WebXR 示例,了解上述流程在实际项目中的用法。<br /><br />
+        
+            [example:webxr_xr_ballshooter WebXR / XR / ballshooter]<br />
+            [example:webxr_xr_cubes WebXR / XR / cubes]<br />
+            [example:webxr_xr_dragging WebXR / XR / dragging]<br />
+            [example:webxr_xr_paint WebXR / XR / paint]<br />
+            [example:webxr_xr_sculpt WebXR / XR / sculpt]<br />
+            [example:webxr_vr_panorama_depth WebXR / VR / panorama_depth]<br />
+            [example:webxr_vr_panorama WebXR / VR / panorama]<br />
+            [example:webxr_vr_rollercoaster WebXR / VR / rollercoaster]<br />
+            [example:webxr_vr_sandbox WebXR / VR / sandbox]<br />
+            [example:webxr_vr_video WebXR / VR / video]
+          </p>
+
+        </div>
+      </div>
+    </div>
+
+  <script src="../resources/prettify.js"></script>
+  <script src="../resources/lesson.js"></script>
+
+
+
+
+</body></html>
+
+
+

+ 184 - 0
manual/zh/how-to-dispose-of-objects.html

@@ -0,0 +1,184 @@
+<!DOCTYPE html><html lang="zh"><head>
+    <meta charset="utf-8">
+    <title>如何释放对象</title>
+    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+    <meta name="twitter:card" content="summary_large_image">
+    <meta name="twitter:site" content="@threejs">
+    <meta name="twitter:title" content="Three.js - 如何释放对象">
+    <meta property="og:image" content="https://threejs.org/files/share.png">
+    <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
+    <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">
+
+    <link rel="stylesheet" href="../resources/lesson.css">
+    <link rel="stylesheet" href="../resources/lang.css">
+    <link rel="stylesheet" href="/manual/zh/lang.css">
+<script type="importmap">
+{
+  "imports": {
+    "three": "../../build/three.module.js"
+  }
+}
+</script>
+  </head>
+  <body>
+    <div class="container">
+      <div class="lesson-title">
+        <h1>如何释放对象</h1>
+      </div>
+      <div class="lesson">
+        <div class="lesson-main">
+          
+          <p>
+            为了提升性能并避免内存泄漏,及时释放不再使用的对象非常关键。
+            每当你创建一个 *three.js* 实例,都会分配一定内存。同时,*three.js*
+            还会为几何体、材质等对象创建渲染所需的 WebGL 资源(如缓冲区和着色器程序)。
+            这些资源不会自动释放,应用必须通过专用 API 主动清理。
+            本文简要说明这些 API 的使用方式,以及哪些对象需要关注。
+          </p>
+        
+          <h2>几何体</h2>
+        
+          <p>
+            几何体通常由一组顶点属性组成。*three.js* 会为每个属性在内部创建
+            [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLBuffer WebGLBuffer]。
+            这些资源只有在调用 `BufferGeometry.dispose()` 后才会被删除。
+            当几何体不再使用时,应执行该方法释放相关资源。
+          </p>
+        
+          <h2>材质</h2>
+        
+          <p>
+            材质决定对象如何被渲染。*three.js* 会根据材质信息构建着色器程序。
+            着色器程序只有在对应材质被释放后才可能删除。出于性能考虑,
+            *three.js* 会尽量复用已存在的着色器程序,因此只有当相关材质都释放后,
+            着色器程序才会真正销毁。释放材质请调用 `Material.dispose()`。
+          </p>
+        
+          <h2>纹理</h2>
+        
+          <p>
+            释放材质不会影响纹理。纹理需要单独管理,因为一个纹理可能被多个材质共享。
+            每当创建 `Texture`,three.js 会在内部创建
+            [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLTexture WebGLTexture]。
+            与缓冲区一样,它只能通过 `Texture.dispose()` 删除。
+          </p>
+        
+          <p>
+            如果纹理数据源是 `ImageBitmap`,你还需要在应用层调用
+            [link:https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap/close ImageBitmap.close]()
+            来释放 CPU 侧资源。`Texture.dispose()` 无法自动调用该方法,
+            因为 `close()` 后图像位图将不可再用,而引擎无法判断它是否还被其他地方使用。
+          </p>
+        
+          <h2>渲染目标</h2>
+        
+          <p>
+            `WebGLRenderTarget` 不仅会分配
+            [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLTexture WebGLTexture],
+            还会分配 [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLFramebuffer WebGLFramebuffer]
+            和 [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderbuffer WebGLRenderbuffer]
+            来支持自定义渲染输出。这些资源只能通过 `WebGLRenderTarget.dispose()` 释放。
+          </p>
+        
+          <h2>蒙皮网格</h2>
+        
+          <p>
+            蒙皮网格通过骨架(skeleton)表示骨骼层级。若不再需要某个蒙皮网格,
+            可以对其骨架调用 `Skeleton.dispose()` 释放内部资源。
+            注意骨架可能被多个蒙皮网格共享,只有在确认未被其他活动对象使用时再释放。
+          </p>
+        
+          <h2>其他</h2>
+        
+          <p>
+            examples 目录中的其他类(如 controls、后处理 pass)也可能提供 `dispose()`,
+            用于移除内部事件监听器或渲染目标。通常建议查看类的 API / 文档,
+            只要有 `dispose()`,在清理阶段就应调用。
+          </p>
+        
+          <h2>常见问题</h2>
+        
+          <h3>为什么 *three.js* 不能自动释放对象?</h3>
+        
+          <p>
+            这是社区经常提出的问题。核心原因是:*three.js* 无法知道用户创建对象
+            (如几何体、材质)的生命周期与作用域,这属于应用层职责。
+            例如某材质当前帧没被使用,下一帧仍可能需要。
+            因此当应用确认对象可删除时,必须调用对应 `dispose()` 通知引擎。
+          </p>
+        
+          <h3>把 mesh 从场景移除后,几何体和材质会自动释放吗?</h3>
+        
+          <p>
+            不会。你需要显式调用 *dispose()* 释放几何体和材质。
+            同时要注意它们可能被多个 3D 对象共享。
+          </p>
+        
+          <h3>*three.js* 能查看缓存对象数量吗?</h3>
+        
+          <p>
+            可以。查看渲染器的 `renderer.info` 属性即可,它包含显存与渲染流程的统计信息,
+            包括当前内部缓存了多少纹理、几何体、着色器程序等。
+            如果应用出现性能问题,调试该属性有助于快速定位内存泄漏。
+          </p>
+        
+          <h3>纹理图像尚未加载完成时调用 `dispose()` 会怎样?</h3>
+        
+          <p>
+            纹理内部资源只有在图像完全加载后才会分配。
+            若在加载前就调用 `dispose()`,通常不会发生任何事;
+            因为资源尚未创建,也就无需清理。
+          </p>
+        
+          <h3>调用 `dispose()` 后又再次使用该对象,会怎样?</h3>
+        
+          <p>
+            取决于对象类型。对于几何体、材质、纹理、渲染目标和后处理 pass,
+            被删除的内部资源通常可以由引擎重新创建,因此不会直接报运行时错误;
+            但当前帧可能有性能损耗,尤其在需要重新编译着色器时。
+
+            controls 和 renderer 属于例外:调用 `dispose()` 后实例不可继续使用,
+            需要重新创建。
+          </p>
+        
+          <h3>应用里该如何管理 *three.js* 对象?什么时候该释放?</h3>
+        
+          <p>
+            没有唯一标准答案,取决于具体业务场景。需要强调的是,并非任何时候都必须立即释放。
+            例如多关卡游戏,切关通常是做统一清理的好时机:遍历旧场景并释放失效的材质、
+            几何体和纹理。就像上文所说,即使误释放了仍会被使用的对象,
+            一般也不会立刻报错,最坏情况通常是某一帧性能下降。
+          </p>
+        
+          <h3>为什么遍历场景并释放可达资源后,`renderer.info.memory` 仍显示几何体和纹理?</h3>
+        
+          <p>
+            某些情况下,Three.js 会创建一些内部使用的纹理和几何体,
+            它们无法通过遍历场景图直接访问到,因此也无法在遍历时释放。
+            所以即便做了完整场景清理,`renderer.info.memory` 仍可能显示这些对象。
+            这通常不代表泄漏,它们会在后续“清理-重建”循环中被复用。
+
+            常见相关场景包括使用 `material.envMap`、`scene.background`、
+            `scene.environment` 等,会触发引擎创建内部资源。
+          </p>
+        
+          <h2>`dispose()` 用法示例</h2>
+        
+          <p>
+            [example:webgl_test_memory WebGL / test / memory]<br />
+            [example:webgl_test_memory2 WebGL / test / memory2]<br />
+          </p>
+
+        </div>
+      </div>
+    </div>
+
+  <script src="../resources/prettify.js"></script>
+  <script src="../resources/lesson.js"></script>
+
+
+
+
+</body></html>
+
+

+ 281 - 0
manual/zh/how-to-update-things.html

@@ -0,0 +1,281 @@
+<!DOCTYPE html><html lang="zh"><head>
+    <meta charset="utf-8">
+    <title>如何更新对象</title>
+    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+    <meta name="twitter:card" content="summary_large_image">
+    <meta name="twitter:site" content="@threejs">
+    <meta name="twitter:title" content="Three.js - 如何更新对象">
+    <meta property="og:image" content="https://threejs.org/files/share.png">
+    <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
+    <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">
+
+    <link rel="stylesheet" href="../resources/lesson.css">
+    <link rel="stylesheet" href="../resources/lang.css">
+    <link rel="stylesheet" href="/manual/zh/lang.css">
+<script type="importmap">
+{
+  "imports": {
+    "three": "../../build/three.module.js"
+  }
+}
+</script>
+  </head>
+  <body>
+    <div class="container">
+      <div class="lesson-title">
+        <h1>如何更新对象</h1>
+      </div>
+      <div class="lesson">
+        <div class="lesson-main">
+          
+          <div>
+            <p>默认情况下,只要对象被添加到场景中,就会自动更新其矩阵:</p>
+<pre class="prettyprint notranslate lang-js" translate="no">
+const object = new THREE.Object3D();
+scene.add( object );
+</pre>
+            或者,它是某个已加入场景对象的子对象:
+<pre class="prettyprint notranslate lang-js" translate="no">
+const object1 = new THREE.Object3D();
+const object2 = new THREE.Object3D();
+
+object1.add( object2 );
+scene.add( object1 ); // object1 和 object2 都会自动更新它们的矩阵
+</pre>
+          </div>
+      
+          <p>但如果你确定对象是静态的,可以关闭自动更新,仅在需要时手动更新变换矩阵。</p>
+      
+<pre class="prettyprint notranslate lang-js" translate="no">
+object.matrixAutoUpdate = false;
+object.updateMatrix();
+</pre>
+      
+          <h2>BufferGeometry</h2>
+          <div>
+            <p>
+              BufferGeometry 把顶点位置、面索引、法线、颜色、UV 以及自定义属性等信息
+              存在属性缓冲中,也就是
+              [link:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Typed_arrays 类型化数组]。
+              这种结构通常比旧版 Geometry 更快,但使用起来通常更复杂。
+            </p>
+            <p>
+              更新 BufferGeometry 时最重要的一点是:不能调整缓冲区大小
+              (开销很大,基本等同于新建几何体),但可以更新缓冲区已有内容。
+            </p>
+            <p>
+              这意味着如果你知道某个属性会增长(如顶点数增加),
+              必须预先分配足够大的缓冲区来容纳新增数据。
+              同时也意味着 BufferGeometry 必然存在最大容量,
+              无法做到无限高效扩展。
+            </p>
+            <p>
+              下面以“运行时不断延长的线段”为例:
+              先为 500 个顶点分配空间,但起初只绘制 2 个点,
+              通过 `BufferGeometry.drawRange` 控制绘制范围。
+            </p>
+<pre class="prettyprint notranslate lang-js" translate="no">
+const MAX_POINTS = 500;
+
+// 几何体
+const geometry = new THREE.BufferGeometry();
+
+// 属性
+const positions = new Float32Array( MAX_POINTS * 3 ); // 每个点使用 3 个浮点数(x、y、z)
+geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
+
+// 绘制范围
+const drawCount = 2; // 仅绘制前 2 个点
+geometry.setDrawRange( 0, drawCount );
+
+// 材质
+const material = new THREE.LineBasicMaterial( { color: 0xff0000 } );
+
+// 线段
+const line = new THREE.Line( geometry, material );
+scene.add( line );
+</pre>
+             <p>
+              接着按如下方式随机写入线段点位:
+            </p>
+<pre class="prettyprint notranslate lang-js" translate="no">
+const positionAttribute = line.geometry.getAttribute( 'position' );
+
+let x = 0, y = 0, z = 0;
+
+for ( let i = 0; i < positionAttribute.count; i ++ ) {
+
+    positionAttribute.setXYZ( i, x, y, z );
+
+    x += ( Math.random() - 0.5 ) * 30;
+    y += ( Math.random() - 0.5 ) * 30;
+    z += ( Math.random() - 0.5 ) * 30;
+
+}
+</pre>
+            <p>
+              如果要在首次渲染后改变<em>绘制点数量</em>,这样做:
+            </p>
+<pre class="prettyprint notranslate lang-js" translate="no">
+line.geometry.setDrawRange( 0, newValue );
+</pre>
+            <p>
+              如果要在首次渲染后修改位置数据,需要设置 `needsUpdate`:
+            </p>
+<pre class="prettyprint notranslate lang-js" translate="no">
+positionAttribute.needsUpdate = true; // 首次渲染后修改数据时必须设置
+</pre>
+      
+            <p>
+              首次渲染后修改位置数据时,通常还需要重新计算包围体,
+              以保证视锥体裁剪、辅助器等功能正常工作。
+            </p>
+<pre class="prettyprint notranslate lang-js" translate="no">
+line.geometry.computeBoundingBox();
+line.geometry.computeBoundingSphere();
+</pre>
+      
+            <p>
+              [link:https://jsfiddle.net/t4m85pLr/1/ 这个 fiddle 示例]
+              展示了一个动画线段,你可以按需改造。
+            </p>
+      
+            <h3>示例</h3>
+      
+            <p>
+              [example:webgl_custom_attributes WebGL / custom / attributes]<br />
+              [example:webgl_buffergeometry_custom_attributes_particles WebGL / buffergeometry / custom / attributes / particles]
+            </p>
+      
+          </div>
+      
+          <h2>材质</h2>
+          <div>
+            <p>所有 uniforms 都可以自由修改(如颜色、纹理、不透明度等),并会在每帧传入着色器。</p>
+      
+            <p>GL 状态相关参数也可随时修改(如 depthTest、blending、polygonOffset 等)。</p>
+      
+            <p>以下属性在运行时不易修改(尤其材质至少渲染过一次后):</p>
+            <ul>
+              <li>uniform 的数量与类型</li>
+              <li>是否启用以下特性
+                <ul>
+                  <li>texture(纹理)</li>
+                  <li>fog(雾)</li>
+                  <li>vertex colors(顶点色)</li>
+                  <li>morphing(变形)</li>
+                  <li>shadow map(阴影贴图)</li>
+                  <li>alpha test(Alpha 测试)</li>
+                  <li>transparent(透明)</li>
+                </ul>
+              </li>
+            </ul>
+      
+            <p>这些变化会触发重建着色器程序,你需要设置:</p>
+            <code>material.needsUpdate = true</code>
+      
+            <p>注意这一步可能较慢并导致帧率抖动或卡顿(尤其在 Windows 上,DirectX 下编译 shader 往往比 OpenGL 更慢)。</p>
+      
+            <p>为获得更平滑体验,可以通过“占位值”模拟部分开关效果,比如强度为 0 的灯光、纯白纹理或密度为 0 的雾。</p>
+      
+            <p>你可以替换几何体分块所用材质,但无法在运行时改变对象按面材质划分分块的方式。</p>
+      
+            <h3>如果你需要在运行时切换多套材质配置:</h3>
+            <p>若材质/分块数量较少,可提前分块(例如人物:头发/脸/身体/上衣/裤子;汽车:前/侧/顶/玻璃/轮胎/内饰)。</p>
+      
+            <p>若数量很大(例如每个面都可能不同),建议改用属性或纹理驱动每面外观,而非大量分块材质。</p>
+      
+            <h3>示例</h3>
+            <p>
+              [example:webgl_materials_car WebGL / materials / car]<br />
+              [example:webgl_postprocessing_dof WebGL / webgl_postprocessing / dof]
+            </p>
+          </div>
+      
+      
+          <h2>纹理</h2>
+          <div>
+            <p>图像、Canvas、视频和数据纹理若内容有变更,需要设置:</p>
+            <code>
+              texture.needsUpdate = true;
+            </code>
+            <p>渲染目标会自动更新。</p>
+      
+            <h3>示例</h3>
+            <p>
+              [example:webgl_materials_video WebGL / materials / video]<br />
+              [example:webgl_rtt WebGL / rtt]
+            </p>
+      
+          </div>
+      
+          <h2>相机</h2>
+          <div>
+            <p>相机位置和目标会自动更新。如果你要修改以下参数:</p>
+            <ul>
+              <li>
+                fov(视野范围)
+              </li>
+              <li>
+                aspect(宽高比)
+              </li>
+              <li>
+                near(近裁剪面)
+              </li>
+              <li>
+                far(远裁剪面)
+              </li>
+            </ul>
+            <p>
+              则需要重新计算投影矩阵:
+            </p>
+<pre class="prettyprint notranslate lang-js" translate="no">
+camera.aspect = window.innerWidth / window.innerHeight;
+camera.updateProjectionMatrix();
+</pre>
+          </div>
+      
+          <h2>InstancedMesh</h2>
+          <div>
+            <p>
+              `InstancedMesh` 用于在 `three.js` 中便捷地进行实例化渲染。
+              视锥体裁剪、射线检测等功能依赖最新包围体(包围盒和包围球)。
+              由于 `InstancedMesh` 的工作方式,它具有自己的 `boundingBox` 与 `boundingSphere`,
+              会覆盖几何体级别的包围体。
+            </p>
+            <p>
+              与几何体类似,只要底层数据变化就应重算包围体。
+              对 `InstancedMesh` 来说,常见场景是通过 `setMatrixAt()` 修改实例变换矩阵后,
+              再重算包围体。处理方式与几何体相同。
+            </p>
+<pre class="prettyprint notranslate lang-js" translate="no">
+instancedMesh.computeBoundingBox();
+instancedMesh.computeBoundingSphere();
+</pre>
+      
+          </div>
+      
+          <h2>SkinnedMesh</h2>
+          <div>
+            <p>
+              在包围体机制上,`SkinnedMesh` 与 `InstancedMesh` 原则相同:
+              它拥有自己的 `boundingBox` 与 `boundingSphere`,用于正确包裹动画中的网格。
+              当调用 `computeBoundingBox()` 与 `computeBoundingSphere()` 时,
+              会基于当前骨骼变换(即当前动画状态)计算对应包围体。
+            </p>
+          </div>
+
+        </div>
+      </div>
+    </div>
+
+  <script src="../resources/prettify.js"></script>
+  <script src="../resources/lesson.js"></script>
+
+
+
+
+</body></html>
+
+
+

+ 148 - 0
manual/zh/how-to-use-post-processing.html

@@ -0,0 +1,148 @@
+<!DOCTYPE html><html lang="zh"><head>
+    <meta charset="utf-8">
+    <title>如何使用后处理</title>
+    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+    <meta name="twitter:card" content="summary_large_image">
+    <meta name="twitter:site" content="@threejs">
+    <meta name="twitter:title" content="Three.js - 如何使用后处理">
+    <meta property="og:image" content="https://threejs.org/files/share.png">
+    <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
+    <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">
+
+    <link rel="stylesheet" href="../resources/lesson.css">
+    <link rel="stylesheet" href="../resources/lang.css">
+    <link rel="stylesheet" href="/manual/zh/lang.css">
+<script type="importmap">
+{
+  "imports": {
+    "three": "../../build/three.module.js"
+  }
+}
+</script>
+  </head>
+  <body>
+    <div class="container">
+      <div class="lesson-title">
+        <h1>如何使用后处理</h1>
+      </div>
+      <div class="lesson">
+        <div class="lesson-main">
+          
+          <p>
+            许多 three.js 应用会把 3D 对象直接渲染到屏幕上。但在一些场景中,
+            你会希望叠加景深(DOF)、Bloom、胶片颗粒、抗锯齿等视觉效果。后处理(Post Processing)
+            是实现这些效果的常见方案:先把场景渲染到一个渲染目标(显存中的图像缓冲区),
+            再通过一个或多个后处理 pass 对该缓冲区应用滤镜与效果,最后输出到屏幕。
+          </p>
+          <p>
+            three.js 通过 `EffectComposer` 提供了完整的后处理工作流支持。
+          </p>
+      
+          <h2>工作流程</h2>
+      
+          <p>
+            第一步是从 examples 目录导入所需模块。本文默认你使用 three.js 官方
+            [link:https://www.npmjs.com/package/three npm 包]。在本教程的基础示例中,我们需要以下文件。
+          </p>
+      
+<pre class="prettyprint notranslate lang-js" translate="no">
+import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
+import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
+import { GlitchPass } from 'three/addons/postprocessing/GlitchPass.js';
+import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';
+</pre>
+      
+          <p>
+            导入完成后,把 `WebGLRenderer` 实例传入,创建 composer。
+          </p>
+      
+<pre class="prettyprint notranslate lang-js" translate="no">
+const composer = new EffectComposer( renderer );
+</pre>
+      
+          <p>
+            使用 composer 后,需要调整动画循环:不再调用 `WebGLRenderer.render()`,
+            而改为调用 `EffectComposer.render()`。
+          </p>
+      
+<pre class="prettyprint notranslate lang-js" translate="no">
+function animate() {
+
+  requestAnimationFrame( animate );
+
+  composer.render();
+
+}
+</pre>
+      
+          <p>
+            到这里 composer 已准备就绪,可以配置后处理 pass 链。各 pass 按添加顺序依次执行,
+            共同决定最终输出结果。在本例中先执行 `RenderPass`,再执行 `GlitchPass`,
+            最后执行 `OutputPass`。链路中最后一个启用的 pass 会自动渲染到屏幕。
+            配置如下:
+          </p>
+      
+<pre class="prettyprint notranslate lang-js" translate="no">
+const renderPass = new RenderPass( scene, camera );
+composer.addPass( renderPass );
+
+const glitchPass = new GlitchPass();
+composer.addPass( glitchPass );
+
+const outputPass = new OutputPass();
+composer.addPass( outputPass );
+</pre>
+      
+          <p>
+            `RenderPass` 通常放在链路开头,用于提供场景渲染结果给后续步骤。
+            本例中 `GlitchPass` 会基于图像数据施加故障效果。
+            `OutputPass` 一般放在最后,负责 sRGB 色彩空间转换与色调映射(tone mapping)。
+            可参考这个 [link:https://threejs.org/examples/webgl_postprocessing_glitch 在线示例]。
+          </p>
+      
+          <h2>内置 Pass</h2>
+      
+          <p>
+            引擎提供了大量预置后处理 pass,可在
+            [link:https://github.com/mrdoob/three.js/tree/dev/examples/jsm/postprocessing postprocessing]
+            目录中找到。
+          </p>
+      
+          <h2>自定义 Pass</h2>
+      
+          <p>
+            如果你要编写自定义后处理着色器并接入 pass 链,可以使用 `ShaderPass`。
+            在导入相关模块和自定义 shader 后,按下述方式添加 pass:
+          </p>
+      
+<pre class="prettyprint notranslate lang-js" translate="no">
+import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
+import { LuminosityShader } from 'three/addons/shaders/LuminosityShader.js';
+
+// 稍后在你的初始化流程中
+
+const luminosityPass = new ShaderPass( LuminosityShader );
+composer.addPass( luminosityPass );
+</pre>
+      
+          <p>
+            仓库中提供的
+            [link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/shaders/CopyShader.js CopyShader]
+            是编写自定义 shader 的良好起点。`CopyShader` 仅将 `EffectComposer` 的读缓冲内容
+            复制到写缓冲,不附加任何效果。
+          </p>
+
+        </div>
+      </div>
+    </div>
+
+  <script src="../resources/prettify.js"></script>
+  <script src="../resources/lesson.js"></script>
+
+
+
+
+</body></html>
+
+
+

+ 116 - 0
manual/zh/matrix-transformations.html

@@ -0,0 +1,116 @@
+<!DOCTYPE html><html lang="zh"><head>
+    <meta charset="utf-8">
+    <title>矩阵变换</title>
+    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+    <meta name="twitter:card" content="summary_large_image">
+    <meta name="twitter:site" content="@threejs">
+    <meta name="twitter:title" content="Three.js - 矩阵变换">
+    <meta property="og:image" content="https://threejs.org/files/share.png">
+    <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
+    <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">
+
+    <link rel="stylesheet" href="../resources/lesson.css">
+    <link rel="stylesheet" href="../resources/lang.css">
+    <link rel="stylesheet" href="/manual/zh/lang.css">
+<script type="importmap">
+{
+  "imports": {
+    "three": "../../build/three.module.js"
+  }
+}
+</script>
+  </head>
+  <body>
+    <div class="container">
+      <div class="lesson-title">
+        <h1>矩阵变换</h1>
+      </div>
+      <div class="lesson">
+        <div class="lesson-main">
+          
+          <p>
+            Three.js 使用 `matrices`(矩阵)来表示 3D 变换:平移(position)、旋转和缩放。
+            每个 `Object3D` 实例都包含一个 `matrix`,用于存储该对象的位置、旋转与缩放。
+            本页介绍如何更新对象的变换。
+            </p>
+        
+            <h2>便捷属性与 `matrixAutoUpdate`</h2>
+        
+            <p>
+              更新对象变换有两种方式:
+            </p>
+            <ol>
+              <li>
+                修改对象的 `position`、`quaternion`、`scale` 属性,
+                由 three.js 根据这些属性重新计算矩阵:
+<pre class="prettyprint notranslate lang-js" translate="no">
+object.position.copy( start_position );
+object.quaternion.copy( quaternion );
+</pre>
+                默认情况下 `matrixAutoUpdate = true`,矩阵会自动重算。
+                如果对象是静态的,或你希望手动控制重算时机,可将其设为 `false` 以获得更好性能:
+<pre class="prettyprint notranslate lang-js" translate="no">
+object.matrixAutoUpdate = false;
+</pre>
+                修改属性后,再手动更新矩阵:
+<pre class="prettyprint notranslate lang-js" translate="no">
+object.updateMatrix();
+</pre>
+              </li>
+              <li>
+                直接修改对象矩阵。`Matrix4` 提供了多种矩阵修改方法:
+<pre class="prettyprint notranslate lang-js" translate="no">
+object.matrix.setRotationFromQuaternion( quaternion );
+object.matrix.setPosition( start_position );
+object.matrixAutoUpdate = false;
+</pre>
+                注意这种方式下 `matrixAutoUpdate` <em>必须</em>设为 `false`,
+                并且要确保<em>不要</em>调用 `updateMatrix`。
+                调用 `updateMatrix` 会根据 `position`、`scale` 等重新计算矩阵,
+                从而覆盖你手动写入的矩阵内容。
+              </li>
+            </ol>
+        
+            <h2>对象矩阵与世界矩阵</h2>
+            <p>
+            对象的 `matrix` 存储的是相对于父对象的<em>局部</em>变换;
+            若要获取对象在<em>世界坐标</em>中的变换,需要访问对象的世界矩阵。
+            </p>
+            <p>
+            当父对象或子对象变换发生变化时,可以调用 `object.updateMatrixWorld()`,
+            触发子对象世界矩阵更新。
+            </p>
+            <p>
+            也可以通过 `applyMatrix4()` 对对象施加变换。注意:该方法底层依赖
+            `Matrix4.decompose()`,并非所有矩阵都能这样分解。
+            例如父对象存在非均匀缩放时,子对象世界矩阵可能无法正确分解,
+            此时该方法并不适用。
+            </p>
+        
+            <h2>旋转与四元数</h2>
+            <p>
+            Three.js 提供两种 3D 旋转表示:欧拉角与四元数,并支持相互转换。
+            欧拉角会受到“万向节锁(gimbal lock)”问题影响,
+            在某些姿态下会丢失一个自由度(导致无法绕某一轴旋转)。
+            因此,对象旋转在内部<em>始终</em>存储为四元数。
+            </p>
+            <p>
+            旧版本库曾有 `useQuaternion` 属性,设为 false 时会用欧拉角计算对象矩阵。
+            这种做法已废弃。现在应使用 `object.setRotationFromEuler()`,
+            它会同步更新四元数。
+            </p>
+
+        </div>
+      </div>
+    </div>
+
+  <script src="../resources/prettify.js"></script>
+  <script src="../resources/lesson.js"></script>
+
+
+
+
+</body></html>
+
+
+

+ 176 - 0
manual/zh/physics.html

@@ -0,0 +1,176 @@
+<!DOCTYPE html>
+<html lang="zh">
+
+<head>
+    <meta charset="utf-8">
+    <title>物理</title>
+    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+    <meta name="twitter:card" content="summary_large_image">
+    <meta name="twitter:site" content="@threejs">
+    <meta name="twitter:title" content="Three.js - 物理">
+    <meta property="og:image" content="https://threejs.org/files/share.png">
+    <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
+    <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">
+
+    <link rel="stylesheet" href="../resources/lesson.css">
+    <link rel="stylesheet" href="../resources/lang.css">
+        <link rel="stylesheet" href="/manual/zh/lang.css">
+<script type="importmap">
+			{
+				"imports": {
+					"three": "../../build/three.module.js"
+				}
+			}
+		</script>
+</head>
+
+<body>
+    <div class="container">
+        <div class="lesson-title">
+            <h1>物理</h1>
+        </div>
+        <div class="lesson">
+            <div class="lesson-main">
+
+                <p>
+                    物理引擎可以在 3D 场景中模拟重力、碰撞、受力等物理现象。
+                    在常规 three.js 场景中,我们通常直接修改对象位置和旋转;
+                    而在使用物理引擎时,会额外维护一个并行的“物理世界”,
+                    刚体在其中响应力和碰撞。然后每帧把 three.js 网格与物理刚体状态同步,
+                    从而呈现出“真实物理”效果。
+                </p>
+
+                <p>
+                    需要注意的是,物理引擎不一定要每帧更新。为了保持模拟稳定,
+                    通常会采用固定时间步。比如游戏循环运行于 60fps,
+                    物理更新运行于 30fps(1/30 秒),
+                    同时每帧使用物理引擎的最新状态更新 three.js 网格变换(位置、旋转等)。
+                </p>
+
+                <p>
+                    物理模拟尤其适用于游戏、交互可视化,以及任何需要真实对象行为的应用,
+                    例如下落、弹跳、滑动等效果。
+                </p>
+
+                <h2>集成方式</h2>
+
+                <p>
+                    在 three.js 项目中集成物理引擎,主要有三种方式:
+                </p>
+
+                <h3>1. 使用 three.js 物理插件</h3>
+
+                <p>
+                    Three.js 在 <i>examples/jsm/physics</i> 目录中为多个常见物理引擎提供了封装类。
+                    这些插件可简化接入流程,完成物理世界初始化与网格同步。
+                </p>
+
+                <p>
+                    可用插件包括:
+                </p>
+
+                <ul>
+                    <li><b>AmmoPhysics:</b>Ammo.js(Bullet 物理)的封装。</li>
+                    <li><b>JoltPhysics:</b>Jolt Physics 的封装。</li>
+                    <li><b>RapierPhysics:</b>Rapier 的封装。</li>
+                </ul>
+
+                <p>
+                    这些插件屏蔽了大量底层复杂性。对于常规需求,它们是最快的入门路径之一。
+                </p>
+
+                <h4>
+                    示例
+                </h4>
+                <ul>
+                    <li><a href="https://threejs.org/examples/physics_ammo_instancing.html" target="_blank">physics / ammo / instancing</a></li>
+                    <li><a href="https://threejs.org/examples/physics_jolt_instancing.html" target="_blank">physics / jolt / instancing</a></li>
+                    <li><a href="https://threejs.org/examples/physics_rapier_instancing.html" target="_blank">physics / rapier / instancing</a></li>
+                </ul>
+
+                <h3>2. 使用第三方 JS/TS 物理库</h3>
+
+                <p>
+                    许多物理引擎直接由 JavaScript / TypeScript 编写,
+                    与 Web 生态集成较容易。像 <b>cannon-es</b> 这类库因轻量且接入简单而常被采用。
+                </p>
+
+                <p>
+                    使用这类库时,你需要自己创建物理世界和刚体,
+                    并在动画循环中手动把刚体的位置、四元数同步到 three.js 网格。
+                </p>
+
+
+                <h4>
+                    项目
+                </h4>
+                <ul>
+                    <li><b><a href="https://github.com/pmndrs/cannon-es" target="_blank">cannon-es</a></b>:纯 JS/TS 的轻量 3D 物理引擎,MIT 协议。看起来维护已不活跃(最近提交距今较久)。</li>
+                    <li><b><a href="https://github.com/schteppe/cannon.js" target="_blank">cannon.js</a></b>:纯 JavaScript 的轻量 3D 物理引擎,MIT 协议。已基本停止维护。建议优先使用其较新的分支 cannon-es。</li>
+                    <li><b><a href="https://github.com/lo-th/phy" target="_blank">phy</a></b>:面向 three.js 的纯 JavaScript 物理引擎,MIT 协议。当前仍在维护。</li>
+                    <li><b><a href="https://github.com/lo-th/Oimo.js" target="_blank">Oimo.js</a></b>:纯 JavaScript 轻量 3D 物理引擎,已不再维护。作者建议改用 phy。</li>
+                </ul>
+                <p>
+                    另外还有一类“看似 JS/TS、实则调用外部引擎”的方案,例如:
+                </p>
+                <ul>
+                    <li><b><a href="https://github.com/chandlerprall/Physijs" target="_blank">Physijs</a></b>:底层调用 ammo.js,并借助 Web Worker 在独立线程处理物理,MIT 协议。维护不活跃(最近提交距今多年)。</li>
+                    <li><b><a href="https://github.com/enable3d/enable3d" target="_blank">enable3d</a></b>:基于 ammo.js 的 three.js 3D 物理框架,LGPL-3.0 协议。看起来仍在维护。</li>
+                </ul>
+
+                <h3>3. 引入基于 WASM 的引擎</h3>
+
+                <p>
+                    如果你需要更高性能、稳定性和精度(尤其复杂模拟),
+                    可以选择 C++/Rust 等语言编写并编译为 WebAssembly(WASM)的物理引擎。
+                    例如 <b>Ammo.js</b>(Bullet 的移植版)和 <b>Rapier</b> 都属于这一类。
+                </p>
+
+                <p>
+                    这种方式通常功能最完整、性能最好,但接入成本更高,
+                    需要处理 WASM 内存管理及与物理 API 的直接交互。
+                </p>
+
+                <h4>
+                    示例
+                </h4>
+                <ul>
+                    <li><a href="https://threejs.org/examples/physics_ammo_break.html" target="_blank">physics / ammo / break</a></li>
+                    <li><a href="https://threejs.org/examples/physics_ammo_cloth.html" target="_blank">physics / ammo / cloth</a></li>
+                    <li><a href="https://threejs.org/examples/physics_ammo_rope.html" target="_blank">physics / ammo / rope</a></li>
+                    <li><a href="https://threejs.org/examples/physics_ammo_terrain.html" target="_blank">physics / ammo / terrain</a></li>
+                    <li><a href="https://threejs.org/examples/physics_ammo_volume.html" target="_blank">physics / ammo / volume</a></li>
+                </ul>
+
+                <h4>
+                    项目
+                </h4>
+                <ul>
+                    <li><b><a href="https://github.com/jrouwe/JoltPhysics" target="_blank">JoltPhysics</a></b>:面向多核的刚体物理与碰撞检测库,C++ 编写,MIT 协议,活跃维护。已在《Horizon Forbidden West》《Death Stranding 2》等知名作品中得到验证,并获得 Godot 游戏引擎官方支持。</li>
+                    <li><b><a href="https://github.com/NVIDIA-Omniverse/PhysX" target="_blank">PhysX</a></b>:NVIDIA 提供的工业级实时 3D 物理引擎,BSD-3-Clause 协议,稳定且持续维护。</li>
+                    <li><b><a href="https://github.com/dimforge/rapier" target="_blank">Rapier</a></b>:注重性能的 2D/3D 物理引擎,Rust 编写,MIT 协议,活跃维护。</li>
+                    <li><b><a href="https://github.com/bulletphysics/bullet3" target="_blank">Bullet</a></b>:
+                    用于 VR、游戏、视觉特效、机器人、机器学习等场景的实时碰撞检测与多物理模拟库,C++ 编写,ZLIB 协议。维护状态可能不活跃。</li>
+                </ul>
+                <p>
+                    其中一些跨平台 3D 物理引擎已有可直接使用的 WASM 版本,例如:
+                </p>
+                <ul>
+                    <li><b><a href="https://github.com/jrouwe/JoltPhysics.js" target="_blank">JoltPhysics.js</a></b>:使用 Emscripten 将 JoltPhysics 移植到 JavaScript,MIT 协议,当前维护中。</li>
+                    <li><b><a href="https://github.com/fabmax/physx-js-webidl" target="_blank">physx-js-webidl</a></b>:NVIDIA PhysX 的 JavaScript WASM 绑定,MIT 协议,当前维护中。</li>
+                    <li><b><a href="https://github.com/dimforge/rapier.js" target="_blank">Rapier.js</a></b>:Rapier 的官方 JavaScript 绑定,Apache-2.0 协议,活跃维护。</li>
+                    <li><b><a href="https://github.com/kripken/ammo.js" target="_blank">Ammo.js</a></b>:使用 Emscripten 将 Bullet 直接移植到 JavaScript,维护不活跃(最近提交距今多年),采用类似 MIT 的宽松自定义协议。</li>
+                </ul>
+
+            </div>
+        </div>
+    </div>
+
+    <script src="../resources/prettify.js"></script>
+    <script src="../resources/lesson.js"></script>
+
+</body>
+
+</html>
+
+

+ 248 - 0
manual/zh/webgpu-postprocessing.html

@@ -0,0 +1,248 @@
+<!DOCTYPE html><html lang="zh"><head>
+    <meta charset="utf-8">
+    <title>WebGPURenderer 后处理</title>
+    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+    <meta name="twitter:card" content="summary_large_image">
+    <meta name="twitter:site" content="@threejs">
+    <meta name="twitter:title" content="Three.js - WebGPURenderer 后处理">
+    <meta property="og:image" content="https://threejs.org/files/share.png">
+    <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
+    <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">
+
+    <link rel="stylesheet" href="../resources/lesson.css">
+    <link rel="stylesheet" href="../resources/lang.css">
+        <link rel="stylesheet" href="/manual/zh/lang.css">
+<script type="importmap">
+    {
+      "imports": {
+        "three": "../../build/three.module.js"
+      }
+    }
+    </script>
+    </head>
+    <body>
+      <div class="container">
+        <div class="lesson-title">
+          <h1>WebGPURenderer 后处理</h1>
+        </div>
+        <div class="lesson">
+          <div class="lesson-main">
+            
+            <p>
+              `WebGPURenderer` 提供了全新的后处理组件。本文介绍其工作方式和基础用法。
+            </p>
+
+            <h2>概述</h2>
+
+             <p>
+              旧版 `WebGLRenderer` 的后处理在设计上存在一些限制。由于渲染器支持不足,
+              使用 MRT(多渲染目标)较繁琐,同时缺少自动 pass/effect 合并机制,
+              难以优化整体性能。
+            </p>
+
+            <p>
+              新版 `WebGPURenderer` 后处理栈从一开始就面向这些需求设计。
+            </p>
+            <ul>
+              <li>
+                内置完整 MRT 支持。
+              </li>
+              <li>
+                系统会在可能时自动合并效果,减少总渲染 pass 数量。
+              </li>
+              <li>
+                效果链通过节点组合表达,可更灵活地搭建后处理流程。
+              </li>
+            </ul>
+            <p>
+               下面来看如何在 three.js 应用中接入这套后处理系统。
+            </p>
+
+            <h2>基础用法</h2>
+
+            <p>
+              请先阅读 <a href="webgpurenderer">WebGPURenderer</a> 指南并正确配置导入。
+              然后按如下方式创建渲染管线模块实例:
+            </p>
+
+<pre class="prettyprint showlinemods notranslate lang-js" translate="no">
+const renderPipeline = new THREE.RenderPipeline( renderer );
+</pre>
+
+            <p>
+              `RenderPipeline` 用于替代旧的 `EffectComposer`。
+              要确保最终输出来自该模块,需要把动画循环改成如下形式:
+            </p>
+<pre class="prettyprint showlinemods notranslate lang-js" translate="no">
+-  renderer.render( scene, camera );
++  renderPipeline.render();
+</pre>
+
+            <p>
+             大多数后处理流程都会先创建一个所谓的场景 pass(scene pass),也称 beauty pass,
+             作为原始渲染图像,然后再叠加 Bloom、景深、SSR 等效果。
+             先从 TSL 命名空间导入 `pass()` 并创建该 pass。
+            </p>
+<pre class="prettyprint showlinemods notranslate lang-js" translate="no">
+import { pass } from 'three/tsl';
+
+// 在你的初始化流程中
+
+const scenePass = pass( scene, camera );
+</pre>
+            <p>
+             节点系统的核心思想是:把材质或后处理效果表示为节点组合。
+             例如要实现 DotScreen 与 RGB Shift,只需创建对应效果节点并串联。
+            </p>
+
+<pre class="prettyprint showlinemods notranslate lang-js" translate="no">
+import { pass } from 'three/tsl';
++  import { dotScreen } from 'three/addons/tsl/display/DotScreenNode.js';
++  import { rgbShift } from 'three/addons/tsl/display/RGBShiftNode.js';
+
+// 在你的初始化流程中
+
+const scenePass = pass( scene, camera );
+
++  const dotScreenPass = dotScreen( scenePass );
++  const rgbShiftPass = rgbShift( dotScreenPass );
+</pre>
+
+            <p>
+            完成后,把最终节点赋给 `RenderPipeline` 即可。
+            </p>
+<pre class="prettyprint showlinemods notranslate lang-js" translate="no">
+renderPipeline.outputNode = rgbShiftPass;
+</pre>
+
+            <h2>色调映射与色彩空间</h2>
+
+            <p>
+            使用后处理时,色调映射与色彩空间转换会在效果链末尾自动执行。
+            但某些场景你可能希望完全控制执行时机与顺序。
+            例如使用 `FXAANode` 做 FXAA,或用 `Lut3DNode` 做调色时,
+            可以关闭自动处理,并通过 `renderOutput()` 手动应用。
+            </p>
+
+<pre class="prettyprint showlinemods notranslate lang-js" translate="no">
+import { pass, renderOutput } from 'three/tsl';
+import { fxaa } from 'three/addons/tsl/display/FXAANode.js';
+
+// 在你的初始化流程中
+
+const renderPipeline = new THREE.RenderPipeline( renderer );
+renderPipeline.outputColorTransform = false; // 禁用默认输出色彩变换
+
+const scenePass = pass( scene, camera );
+const outputPass = renderOutput( scenePass ); // 在这里应用色调映射和色彩空间转换
+
+// FXAA 必须在 sRGB 色彩空间中计算
+
+const fxaaPass = fxaa( outputPass );
+renderPipeline.outputNode = fxaaPass;
+</pre>
+
+          <p>
+            `renderOutput()` 不是强制的,你也可以按需求自行实现色调映射与色彩空间转换。
+          </p>
+
+          <h2>MRT(多渲染目标)</h2>
+
+          <p>
+            新后处理栈内置 MRT,对高级效果非常关键。MRT 允许你在一次渲染 pass 中产生多个输出。
+            例如使用 TRAA 时,你可以按下述配置准备抗锯齿输入。
+          </p>
+
+<pre class="prettyprint showlinemods notranslate lang-js" translate="no">
+import { pass, mrt, output, velocity } from 'three/tsl';
+
+// 在你的初始化流程中
+
+const scenePass = pass( scene, camera );
+scenePass.setMRT( mrt( {
+  output: output,
+  velocity: velocity
+} ) );
+</pre>
+          <p>
+            传给 `mrt()` 的配置对象用于描述该 pass 的各个输出。
+            本例中我们保存默认输出(场景主图)和速度信息,用于 TRAA。
+            如果还需要深度,一般无需额外作为 MRT 输出配置;
+            在默认输出 pass 中按需请求即可获取。
+            若后续效果需要这些结果,可把它们作为纹理节点读取。
+          </p>
+
+<pre class="prettyprint showlinemods notranslate lang-js" translate="no">
+import { traa } from 'three/addons/tsl/display/TRAANode.js';
+
+// 在你的初始化流程中
+
+const scenePassColor = scenePass.getTextureNode( 'output' );
+const scenePassDepth = scenePass.getTextureNode( 'depth' );
+const scenePassVelocity = scenePass.getTextureNode( 'velocity' );
+
+const traaPass = traa( scenePassColor, scenePassDepth, scenePassVelocity, camera );
+renderPipeline.outputNode = traaPass;
+</pre>
+
+          <p>
+           MRT 配置取决于你的具体方案。你可以使用 `output`、`velocity`、`normalView`、
+           `emissive` 等 TSL 对象,把片元数据写入不同 attachment。
+           在复杂 MRT 流程中,为提升性能并避免显存压力,必须做好数据打包与格式优化。
+           默认 attachment 精度是 RGBA16(Half-Float),并非所有数据都需要这么高。
+           例如下方把 `diffuseColor` 改为 RGBA8,可将带宽和内存占用减半。
+          </p>
+
+<pre class="prettyprint showlinemods notranslate lang-js" translate="no">
+const diffuseTexture = scenePass.getTexture( 'diffuseColor' );
+diffuseTexture.type = THREE.UnsignedByteType;
+</pre> 
+
+          <p>
+            下方 SSR(屏幕空间反射)示例把默认 FP16 法线转换为 RGBA8 颜色,
+            并将金属度/粗糙度打包到单个 attachment。配合 `sample()` TSL 函数可实现自定义解包,
+            本例中会把颜色还原为归一化方向向量。
+          </p>
+
+<pre class="prettyprint showlinemods notranslate lang-js" translate="no">
+scenePass.setMRT( mrt( {
+  output: output,
+  normal: directionToColor( normalView ),
+  metalrough: vec2( metalness, roughness )
+} ) );
+
+// 使用 RGBA8 替代 RGBA16
+
+const normalTexture = scenePass.getTexture( 'normal' );
+normalTexture.type = THREE.UnsignedByteType;
+
+const metalRoughTexture = scenePass.getTexture( 'metalrough' );
+metalRoughTexture.type = THREE.UnsignedByteType;
+
+// 自定义解包。后续效果里请使用得到的 "sceneNormal"
+// 来替代 "scenePassNormal"
+
+const sceneNormal = sample( ( uv ) => {
+
+  return colorToDirection( scenePassNormal.sample( uv ) );
+
+} );
+</pre>
+
+          <p>
+            后续还会继续增强打包/解包能力,提供更多 MRT 数据组织方式。
+            目前建议参考
+            <a href="https://threejs.org/examples/?q=webgpu%20postprocessing" target="_blank">官方示例</a>,
+            了解现有效果和配置模式。
+          </p>
+          </div>
+        </div>
+      </div>
+
+    <script src="../resources/prettify.js"></script>
+    <script src="../resources/lesson.js"></script>
+  </body>
+</html>
+
+
+

+ 182 - 0
manual/zh/webgpurenderer.html

@@ -0,0 +1,182 @@
+<!DOCTYPE html><html lang="zh"><head>
+    <meta charset="utf-8">
+    <title>WebGPU 渲染器</title>
+    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+    <meta name="twitter:card" content="summary_large_image">
+    <meta name="twitter:site" content="@threejs">
+    <meta name="twitter:title" content="Three.js - WebGPU 渲染器">
+    <meta property="og:image" content="https://threejs.org/files/share.png">
+    <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
+    <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">
+
+    <link rel="stylesheet" href="../resources/lesson.css">
+    <link rel="stylesheet" href="../resources/lang.css">
+        <link rel="stylesheet" href="/manual/zh/lang.css">
+<script type="importmap">
+    {
+      "imports": {
+        "three": "../../build/three.module.js"
+      }
+    }
+    </script>
+    </head>
+    <body>
+      <div class="container">
+        <div class="lesson-title">
+          <h1>WebGPU 渲染器</h1>
+        </div>
+        <div class="lesson">
+          <div class="lesson-main">
+            
+            <p>
+              `WebGPURenderer` 是 three.js 的下一代渲染器。本文会简要介绍它的能力和基本使用方式。
+            </p>
+
+            <h2>概述</h2>
+
+            <p>
+              `WebGPURenderer` 被设计为 `WebGLRenderer` 的现代替代方案。
+              它优先使用 WebGPU(现代高性能图形与计算 API),
+              同时也被设计成通用渲染器:若设备/浏览器不支持 WebGPU,
+              会自动回退到 WebGL 2 后端。
+            </p>
+             <p>
+              这个回退机制非常关键:应用可以在支持 WebGPU 的平台获得新能力,
+              同时不牺牲仅支持 WebGL 2 设备的兼容性。
+             </p>
+
+             <p>
+             除了接入 WebGPU,`WebGPURenderer` 还提供了以下特性:
+             <p>
+
+            <ul>
+              <li>
+                内置全新的节点材质系统,开发自定义材质更灵活、更稳健。
+              </li>
+              <li>
+                支持 three.js 着色语言 TSL。你可以用 JavaScript 以跨平台方式编写 shader,
+                并根据后端自动转译为 WGSL 或 GLSL。
+              </li>
+              <li>
+                内置全新后处理栈,支持 MRT(多渲染目标)并可借助节点系统自动合并 pass。
+              </li>
+            </ul>
+
+            下面看看如何在 three.js 应用中集成 `WebGPURenderer`。
+
+            <h2>使用方式</h2>
+
+             <p>
+             `WebGPURenderer` 使用不同构建入口,因此导入方式需要调整:
+            </p>
+            
+<pre class="prettyprint showlinemods notranslate lang-js" translate="no">
+-  import * as THREE from 'three';
++  import * as THREE from 'three/webgpu';
+</pre>
+
+            <p>
+              如果你使用 import map,建议改成如下形式(路径按你的工程结构调整):
+            </p>
+<pre class="prettyprint showlinemods notranslate lang-js" translate="no">
+  &lt;script type="importmap"&gt;
+    {
+      "imports": {
+        "three": "../build/three.webgpu.js",
+        "three/webgpu": "../build/three.webgpu.js",
+        "three/tsl": "../build/three.tsl.js",
+        "three/addons/": "./jsm/"
+      }
+    }
+  &lt;/script&gt;
+</pre>
+
+             <p>
+              创建渲染器实例的方式和 `WebGLRenderer` 类似:
+            </p>
+
+<pre class="prettyprint showlinemods notranslate lang-js" translate="no">
+const renderer = new THREE.WebGPURenderer( { antialias: true } );
+renderer.setPixelRatio( window.devicePixelRatio );
+renderer.setSize( window.innerWidth, window.innerHeight );
+renderer.setAnimationLoop( render );
+document.body.appendChild( renderer.domElement );
+</pre>
+            <p>
+              需要注意,WebGPU 初始化是异步的。因此推荐使用 `setAnimationLoop()`,
+              它能确保首次渲染前完成初始化。
+              如果你坚持使用 `window.requestAnimationFrame()` 或需要在初始化阶段直接使用渲染器,
+              则要额外调用一行初始化代码。
+            </p>
+<pre class="prettyprint showlinemods notranslate lang-js" translate="no">
+const renderer = new THREE.WebGPURenderer( { antialias: true } );
+renderer.setPixelRatio( window.devicePixelRatio );
+renderer.setSize( window.innerWidth, window.innerHeight );
+renderer.setAnimationLoop( render );
+document.body.appendChild( renderer.domElement );
+
++  await renderer.init();
+</pre>
+            <p>
+              `WebGLRenderer` 中常见的方法(如 `clear()`、`setRenderTarget()`、`dispose()`)
+              在 `WebGPURenderer` 中同样可用。完整接口请参考
+              <a href="https://threejs.org/docs/#Renderer" target="_blank">API 文档</a>。
+            </p>
+
+             <p>
+              正如前文所述,`WebGPURenderer` 默认使用 WebGPU,必要时回退 WebGL 2。
+              如果你想在测试中强制 WebGL 2,或出于某些原因禁用 WebGPU,
+              可以使用 `forceWebGL` 参数。
+            </p>
+<pre class="prettyprint showlinemods notranslate lang-js" translate="no">
+-  const renderer = new THREE.WebGPURenderer( { antialias: true } );
++  const renderer = new THREE.WebGPURenderer( { antialias: true, forceWebGL: true } );
+</pre>
+
+            <h2>迁移说明</h2>
+
+            <p>
+              准备迁移到 `WebGPURenderer` 时,需要注意以下几点:
+            </p>
+
+            <ul>
+              <li>
+                `ShaderMaterial`、`RawShaderMaterial` 以及通过 `onBeforeCompile()` 改造内置材质,
+                在 `WebGPURenderer` 中不受支持。相关逻辑需要迁移到节点材质与 TSL。
+              </li>
+              <li>
+                `EffectComposer` 及其传统 pass 在这里不支持,
+                因为 `WebGPURenderer` 提供了新一代后处理栈。
+                类似材质迁移,后处理效果也使用 TSL 编写,并以节点组合表达。
+                常用效果已迁移并提供了性能更好的节点版本,同时新增了 SSGI、SSS、
+                更好的 DoF 等新效果。可查看
+                <a href="https://threejs.org/examples/?q=webgpu%20postprocessing" target="_blank">官方示例</a>。
+              </li>
+              <li>
+                渲染器整体仍属于实验阶段,尽管成熟度近年已明显提升。
+                依据你的应用和场景,仍可能遇到缺失特性,或在某些场景下 `WebGLRenderer` 更快。
+                如遇问题建议在 GitHub 提 issue。`WebGPURenderer` 会持续迭代,
+                建议尽量使用最新版本。
+              </li>
+            </ul>
+
+            <h2>WebGLRenderer 的现状</h2>
+
+            <p>虽然当前研发重点在 `WebGPURenderer`、节点材质和 TSL,
+              `WebGLRenderer` 仍在维护,且依然是纯 WebGL 2 应用的推荐选择。
+              但请注意,项目已不计划为 `WebGLRenderer` 增加大型新特性,这一点从最近的版本说明(release notes)中也可以明显看出。
+              同时我们也在评估为其加入有限的节点材质支持,
+              以便某些项目更平滑地迁移到 `WebGPURenderer`。
+            </p>
+
+          </div>
+        </div>
+      </div>
+
+    <script src="../resources/prettify.js"></script>
+    <script src="../resources/lesson.js"></script>
+  </body>
+</html>
+
+
+

粤ICP备19079148号