diff --git a/manual/list.json b/manual/list.json index 6c284e86f09545..1d134f0017c699 100644 --- a/manual/list.json +++ b/manual/list.json @@ -326,6 +326,19 @@ } }, "zh": { + "入门": { + "安装": "zh/installation", + "创建场景": "zh/creating-a-scene", + "创建文本": "zh/creating-text", + "绘制线条": "zh/drawing-lines", + "常见问题": "zh/faq", + "库和插件": "zh/libraries-and-plugins", + "加载3D模型": "zh/loading-3d-models", + "Uniform类型": "zh/uniform-types", + "相关资源": "zh/useful-links", + "WebGL兼容性检查": "zh/webgl-compatibility-check" + }, + "---": {}, "基本": { "基础": "zh/fundamentals", "响应式设计": "zh/responsive", diff --git a/manual/zh/creating-a-scene.html b/manual/zh/creating-a-scene.html new file mode 100644 index 00000000000000..67b88405373797 --- /dev/null +++ b/manual/zh/creating-a-scene.html @@ -0,0 +1,179 @@ +
+ +本节的目标是简要介绍 three.js。我们将从搭建一个包含旋转立方体的场景开始。页面底部提供了可运行的示例,如果你遇到困难可以参考。
+ ++ 如果你还没有阅读过安装指南,请先阅读它。我们假设你已经搭建好了相同的项目结构(包括 index.html 和 main.js),安装了 three.js,并且正在使用构建工具,或使用本地服务器并配合 CDN 与 import maps。 +
+ +要使用 three.js 显示任何内容,我们需要三样东西:场景(scene)、相机(camera)和渲染器(renderer),这样我们才能通过相机来渲染场景。
+ +main.js —
+ ++import * as THREE from 'three'; + +const scene = new THREE.Scene(); +const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); + +const renderer = new THREE.WebGLRenderer(); +renderer.setSize( window.innerWidth, window.innerHeight ); +document.body.appendChild( renderer.domElement ); ++ +
让我们花点时间解释一下这里发生了什么。我们现在已经设置好了场景、相机和渲染器。
+ +three.js 中有几种不同的相机。目前,我们先使用 `PerspectiveCamera`(透视相机)。
+ +第一个参数是`视野范围`(field of view)。FOV 是指在任意时刻显示器上能看到的场景范围,值以角度为单位。
+ +第二个参数是`宽高比`(aspect ratio)。几乎总是应该使用元素的宽度除以高度,否则会出现类似在宽屏电视上播放老电影的效果——画面看起来会被压扁。
+ +接下来的两个参数是近裁剪面(`near`)和远裁剪面(`far`)。也就是说,距离相机比 `far` 更远或比 `near` 更近的物体将不会被渲染。你现在不必担心这个,但在实际应用中可能需要调整这些值以获得更好的性能。
+ +接下来是渲染器。除了创建渲染器实例之外,我们还需要设置渲染尺寸。通常建议用应用需要填满的区域宽高——在这里就是浏览器窗口的宽度和高度。对于性能要求较高的应用,你也可以给 `setSize` 传入较小的值,例如 `window.innerWidth/2` 和 `window.innerHeight/2`,这会使应用以四分之一的尺寸进行渲染。
+ +如果你希望保持应用的显示尺寸不变,但以较低的分辨率渲染,可以在调用 `setSize` 时将第三个参数 `updateStyle` 设为 false。例如,假设你的 <canvas> 宽高均为 100%,调用 `setSize(window.innerWidth/2, window.innerHeight/2, false)` 将以一半的分辨率渲染应用。
+ +最后,我们将 `renderer` 元素添加到 HTML 文档中。这是一个 <canvas> 元素,渲染器用它来向我们展示场景。
+ +"听起来不错,但你说好的立方体呢?" 现在就来添加它。
+ +
+const geometry = new THREE.BoxGeometry( 1, 1, 1 );
+const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
+const cube = new THREE.Mesh( geometry, material );
+scene.add( cube );
+
+camera.position.z = 5;
+
+
+ 要创建一个立方体,我们需要一个 `BoxGeometry`(立方体几何体)。这个对象包含了立方体的所有顶点(`vertices`)和面(`faces`)。我们以后会进一步探索这些内容。
+ +除了几何体,我们还需要一个材质来为它着色。Three.js 提供了多种材质,这里我们先使用 `MeshBasicMaterial`。所有材质都接受一个属性对象。为了简单起见,我们只提供一个颜色属性 `0x00ff00`,即绿色。颜色的工作方式与 CSS 或 Photoshop 中的十六进制颜色(`hex colors`)相同。
+ +我们需要的第三样东西是 `Mesh`(网格)。网格是一个接受几何体并将材质应用于其上的对象,然后我们可以将它插入场景中并自由移动。
+ +默认情况下,当我们调用 `scene.add()` 时,添加的对象会被放置在坐标 `(0,0,0)` 处。这会导致相机和立方体重叠在一起。为了避免这种情况,我们只需将相机稍微向外移动一些。
+ +如果你将上面的代码复制到之前创建的 main.js 文件中,你会发现什么都看不到。这是因为我们还没有真正进行渲染。为此,我们需要一个所谓的渲染循环或动画循环。
+ +
+function animate( time ) {
+ renderer.render( scene, camera );
+}
+renderer.setAnimationLoop( animate );
+
+
+ 这会创建一个循环,让渲染器在每次屏幕刷新时绘制场景(在普通屏幕上这意味着每秒 60 次)。如果你是浏览器游戏开发的新手,可能会问"为什么不直接用 setInterval?"当然可以,但 `WebGLRenderer` 内部使用的 `requestAnimationFrame` 有很多优势。其中最重要的一点是,当用户切换到其他浏览器标签页时它会自动暂停,从而不会浪费宝贵的处理资源和电池寿命。
+ +如果你将上面所有的代码都插入到文件中,你应该能看到一个绿色的立方体。让我们给它添加旋转,使它更有趣一些。
+ +在 `animate` 函数中的 `renderer.render` 调用之前添加以下代码:
+ ++cube.rotation.x = time / 2000; +cube.rotation.y = time / 1000; ++ +
这段代码会在每一帧执行(通常每秒 60 次),让立方体产生流畅的旋转动画。基本上,在应用运行期间你想要移动或改变的任何东西都需要通过动画循环来实现。当然,你可以在其中调用其他函数,这样就不会让 `animate` 函数变得过于冗长。
+ +恭喜!你已经完成了你的第一个 three.js 应用。虽然很简单,但万事总要有个开始。
+ +完整代码如下,也可以作为可编辑的 [link:https://jsfiddle.net/zycqb61k/ 在线示例] 查看。试着修改代码来加深理解。
+ +index.html —
+ +
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>My first three.js app</title>
+ <style>
+ body { margin: 0; }
+ </style>
+ </head>
+ <body>
+ <script type="module" src="/main.js"></script>
+ </body>
+</html>
+
+
+ main.js —
+ +
+import * as THREE from 'three';
+
+const scene = new THREE.Scene();
+const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
+
+const renderer = new THREE.WebGLRenderer();
+renderer.setSize( window.innerWidth, window.innerHeight );
+renderer.setAnimationLoop( animate );
+document.body.appendChild( renderer.domElement );
+
+const geometry = new THREE.BoxGeometry( 1, 1, 1 );
+const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
+const cube = new THREE.Mesh( geometry, material );
+scene.add( cube );
+
+camera.position.z = 5;
+
+function animate( time ) {
+
+ cube.rotation.x = time / 2000;
+ cube.rotation.y = time / 1000;
+
+ renderer.render( scene, camera );
+
+}
+
+
+ + 在 three.js 应用中,你经常需要用到文本——下面是几种实现方式。 +
++ 使用 HTML 通常是添加文本最简单、最快捷的方式。大多数 three.js 示例中的描述性叠加层都采用了这种方法。 +
+你可以向某个元素添加内容,例如:
++<div id="info">Description</div> ++
+ 然后使用 CSS 将其绝对定位,并通过 z-index 使其显示在所有其他元素之上,尤其是在 three.js 全屏运行时。 +
+ +
+#info {
+ position: absolute;
+ top: 10px;
+ width: 100%;
+ text-align: center;
+ z-index: 100;
+ display:block;
+}
+
+
+ + 使用这些渲染器可以将包含在 DOM 元素中的高质量文本绘制到 three.js 场景中。 + 这与方法 1 类似,但元素能更紧密、更动态地融入场景。 +
+如果你希望在 three.js 场景中的平面上轻松绘制文本,可以使用此方法。
+如果你更喜欢使用 3D 建模应用来制作模型,然后导入到 three.js 中,可以使用此方法。
++ 如果你更倾向于完全在 THREE.js 中工作,或者需要创建程序化、动态的 3D 文本几何体, + 可以创建一个网格,其几何体是 THREE.TextGeometry 的实例: +
+
+ new THREE.TextGeometry( text, parameters );
+
+ 不过要使其正常工作,TextGeometry 的 `font` 参数需要设置为一个 THREE.Font 实例。 + + 请参阅 `TextGeometry` 页面,了解如何设置字体、各参数的说明,以及 THREE.js 发行版自带的 JSON 字体列表。 +
+ +
+ [example:webgl_geometry_text WebGL / geometry / text]
+ [example:webgl_shadowmap WebGL / shadowmap]
+
+ 如果 Typeface 不可用,或你想使用其中没有的字体,可参考一个教程, + 其中包含用于 Blender 的 Python 脚本,可将文本导出为 Three.js 的 JSON 格式: + [link:http://www.jaanga.com/2012/03/blender-to-threejs-create-3d-text-with.html] +
+ ++ BMFonts(位图字体)允许将字形批量合并到单个 BufferGeometry 中。BMFont 渲染支持自动换行、字母间距、字距调整、带标准导数的有符号距离场、多通道有符号距离场、多纹理字体等。 + 参阅 [link:https://github.com/felixmariotto/three-mesh-ui three-mesh-ui] 或 [link:https://github.com/Jam3/three-bmfont-text three-bmfont-text]。 +
++ 现成的字体可以在 [link:https://github.com/etiennepinchon/aframe-fonts A-Frame Fonts] 等项目中找到, + 你也可以从任何 .TTF 字体创建自己的位图字体,并优化为仅包含项目所需的字符。 +
++ 一些有用的工具: +
++ [link:https://www.npmjs.com/package/troika-three-text troika-three-text] 该包使用与 BMFonts 类似的技术渲染高质量抗锯齿文本,但可以直接使用任何 .TTF 或 .WOFF 字体文件,无需离线预生成字形纹理。它还提供了以下功能: +
++ 假设你想绘制一条线或一个圆,而不是线框 `Mesh`。 + 首先我们需要设置渲染器、场景和相机(参见"创建场景"页面)。 +
+ +以下是我们将使用的代码:
++const renderer = new THREE.WebGLRenderer(); +renderer.setSize( window.innerWidth, window.innerHeight ); +document.body.appendChild( renderer.domElement ); + +const camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 500 ); +camera.position.set( 0, 0, 100 ); +camera.lookAt( 0, 0, 0 ); + +const scene = new THREE.Scene(); ++
接下来我们需要定义一个材质。对于线条,需要使用 `LineBasicMaterial` 或 `LineDashedMaterial`。
+
+// 创建一个蓝色的 LineBasicMaterial
+const material = new THREE.LineBasicMaterial( { color: 0x0000ff } );
+
+
+ + 有了材质之后,我们还需要一个带有顶点的几何体: +
+ ++const points = []; +points.push( new THREE.Vector3( - 10, 0, 0 ) ); +points.push( new THREE.Vector3( 0, 10, 0 ) ); +points.push( new THREE.Vector3( 10, 0, 0 ) ); + +const geometry = new THREE.BufferGeometry().setFromPoints( points ); ++ +
注意,线条是在每对相邻顶点之间绘制的,而不会连接首尾两个顶点(即线条不是闭合的)。
+ +现在我们有了两条线段的顶点和一个材质,可以将它们组合成一条线:
++const line = new THREE.Line( geometry, material ); ++
剩下的就是将其添加到场景中并调用 `renderer.render()`。
+ ++scene.add( line ); +renderer.render( scene, camera ); ++ +
现在你应该能看到一个由两条蓝色线段组成的向上箭头。
+ ++ 推荐使用 glTF(GL Transmission Format)格式来导入和导出资源。由于 glTF 专注于运行时资源传输,它体积紧凑、加载速度快。 +
++ three.js 也提供了许多其他常见格式的加载器,如 FBX、Collada 和 OBJ 等。尽管如此,你应该始终优先在项目中建立基于 glTF 的工作流。 +
+<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">+ +
这些标签用于控制移动端浏览器的视口大小和缩放比例(在移动端,页面内容的渲染尺寸可能与可见视口不同)。
+ +[link:https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariWebContent/UsingtheViewport/UsingtheViewport.html Safari: Using the Viewport]
+ +[link:https://developer.mozilla.org/zh-CN/docs/Web/HTML/Viewport_meta_tag MDN: 使用 viewport meta 标签]
++ 我们希望所有物体无论距离相机多远,在窗口缩放时都保持相同的显示大小。 + + 解决这个问题的关键公式是给定距离下的可见高度: + +
visible_height = 2 * Math.tan( ( Math.PI / 180 ) * camera.fov / 2 ) * distance_from_camera;+ 如果我们将窗口高度增加一定百分比,那么我们希望所有距离下的可见高度也增加相同的百分比。 + + 这无法通过改变相机位置来实现,而需要改变相机的视野范围(field-of-view)。 + [link:http://jsfiddle.net/Q4Jpu/ 示例]。 + + +
+ 这可能是由于面剔除(face culling)导致的。每个面都有一个朝向,决定了哪一侧是正面、哪一侧是背面。默认情况下,剔除会移除背面。 + 要检查是否是这个问题,可以将材质的 side 属性设置为 THREE.DoubleSide。 +
material.side = THREE.DoubleSide+ + +
+ 出于性能考虑,three.js 在大多数情况下不会验证输入。确保所有输入有效是你的应用的责任。 +
+ ++ 由于 three.js 是为 Web 构建的,它依赖于浏览器和 DOM API,而这些在 Node.js 中并不总是存在。部分问题可以通过使用 + [link:https://github.com/stackgl/headless-gl headless-gl] 和 [link:https://github.com/rstacruz/jsdom-global jsdom-global] 等 shim(兼容层)来解决, + 或者用自定义替代方案替换 `TextureLoader` 等组件。其他 DOM API 可能与使用它们的代码深度耦合,更难处理。我们欢迎简洁且易于维护的 Pull Request 来改善 Node.js 支持,但建议先提交 issue 讨论你的改进方案。 +
+ ++ 每个 three.js 项目至少需要一个 HTML 文件来定义网页,以及一个 JavaScript 文件来运行你的 three.js 代码。下面的结构和命名方式并非强制要求,但为了保持一致性,本指南将始终使用这种方式。 +
+ +
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>My first three.js app</title>
+ <style>
+ body { margin: 0; }
+ </style>
+ </head>
+ <body>
+ <script type="module" src="/main.js"></script>
+ </body>
+</html>
+
+ +import * as THREE from 'three'; + +... ++
+ 现在我们已经搭建好了基本的项目结构,接下来需要一种方式在本地运行项目并通过浏览器访问它。安装和本地开发可以通过 npm 和构建工具来完成,也可以通过从 CDN 导入 three.js 来实现。下面将分别介绍这两种方式。 +
+ ++ 从 [link:https://www.npmjs.com/ npm 包注册表] 安装并使用 [link:https://eloquentjavascript.net/10_modules.html#h_zWTXAU93DC 构建工具] 对大多数用户来说是推荐的方式——你的项目依赖越多,就越可能遇到静态托管难以解决的问题。使用构建工具时,导入本地 JavaScript 文件和 npm 包无需 import map 即可直接使用。 +
+ + ++ 在项目文件夹中打开 [link:https://www.joshwcomeau.com/javascript/terminal-for-js-devs/ 终端],安装 three.js 和构建工具 [link:https://vitejs.dev/ Vite]。Vite 仅在开发过程中使用,不会成为最终网页的一部分。如果你更喜欢使用其他构建工具也没问题——我们支持任何能导入 [link:https://eloquentjavascript.net/10_modules.html#h_zWTXAU93DC ES Modules] 的现代构建工具。 +
++# three.js +npm install --save three + +# vite +npm install --save-dev vite ++ +
npx vite+ +
+ 页面将是空白的——你已经准备好创建一个场景了。 +
+ ++ 如果你想在继续之前了解更多关于这些工具的信息,请参阅: +
+ ++ 稍后,当你准备部署 Web 应用时,只需让 Vite 执行生产构建——npx vite build。应用使用的所有内容都会被编译、优化并复制到 dist/ 文件夹中。该文件夹的内容即可直接托管到你的网站上。 +
+ +不使用构建工具进行安装需要对上述项目结构做一些修改。
+ ++ 我们在 main.js 中从 'three'(一个 npm 包)导入了代码,但浏览器并不知道这意味着什么。在 index.html 中,我们需要添加一个 [link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap import map] 来定义从哪里获取该包。将以下代码放在 <head></head> 标签内,样式之后。 +
+
+<script type="importmap">
+{
+ "imports": {
+ "three": "https://cdn.jsdelivr.net/npm/three@<version>/build/three.module.js",
+ "three/addons/": "https://cdn.jsdelivr.net/npm/three@<version>/examples/jsm/"
+ }
+}
+</script>
+
+ + 别忘了将 <version> 替换为 three.js 的实际版本号,例如 "v0.149.0"。最新版本可以在 [link:https://www.npmjs.com/package/three?activeTab=versions npm 版本列表] 中找到。 +
++ 我们还需要运行一个本地服务器来将这些文件托管到浏览器可以访问的 URL 上。虽然技术上可以双击 HTML 文件在浏览器中打开,但出于安全原因,我们后续要实现的重要功能在以这种方式打开页面时无法正常工作。 +
++ 安装 [link:https://nodejs.org/ Node.js],然后在项目目录中运行 [link:https://www.npmjs.com/package/serve serve] 来启动本地服务器: +
+npx serve .+
+ 页面将是空白的——你已经准备好 [link:#manual/introduction/Creating-a-scene 创建一个场景] 了。 +
+ ++ 还有许多其他本地静态服务器可供选择——有些使用 Node.js 以外的语言,有些是桌面应用程序。它们的工作方式基本相同,下面列出了一些替代方案。 +
+ +命令行本地服务器从终端窗口运行。可能需要先安装相应的编程语言。
+ +图形界面本地服务器以应用程序窗口的形式在你的计算机上运行,可能带有用户界面。
+ +一些代码编辑器提供插件,可按需启动简单服务器。
+ ++ 当你准备部署 Web 应用时,只需将源文件推送到你的网站托管服务商——无需构建或编译任何内容。这种方式的缺点是,你需要小心地确保 import map 与应用所需的所有依赖(以及依赖的依赖!)同步更新。如果托管这些依赖的 CDN 暂时宕机,你的网站也会停止工作。 +
+ ++ 重要提示:所有依赖都应从同一版本的 three.js 和同一个 CDN 导入。混合使用不同来源的文件可能导致代码被重复引入,甚至以意想不到的方式破坏应用。 +
+ ++ three.js 开箱即用地包含了 3D 引擎的基础功能。其他 three.js 组件——如控制器、加载器和后期处理效果——属于 [link:https://github.com/mrdoob/three.js/tree/dev/examples/jsm addons/] 目录的一部分。附加组件不需要单独安装,但需要单独导入。 +
+ ++ 下面的示例展示了如何导入 three.js 以及 `OrbitControls` 和 `GLTFLoader` 附加组件。在必要时,每个附加组件的文档或示例中也会提到这一点。 +
+ +
+import * as THREE from 'three';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
+import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
+
+const controls = new OrbitControls( camera, renderer.domElement );
+const loader = new GLTFLoader();
+
+
+ + 也有一些优秀的第三方项目可用于 three.js。这些需要单独安装——请参阅库和插件。 +
+ ++ 你现在已经准备好创建一个场景了。 +
+ ++ 这里列出由外部开发、与 three.js 兼容的库和插件。此列表及相关包由社区维护,不能保证是最新的。如需更新该列表,请提交 PR! +
+ ++ 除了 [link:https://github.com/mrdoob/three.js/tree/dev/examples/jsm/postprocessing three.js 官方后处理效果]之外,外部库还提供对一些额外效果和框架的支持。 +
+ ++ 除了 [link:https://github.com/mrdoob/three.js/tree/dev/examples/jsm/loaders three.js 官方加载器]之外,外部库还提供对一些额外格式的支持。 +
+ ++ 3D 模型有数百种文件格式,每种格式都有不同的用途、各异的特性和不同的复杂度。虽然 + + three.js 提供了许多加载器,但选择正确的格式和工作流可以节省大量时间,避免后续的麻烦。某些格式难以使用、不适合实时场景,或者目前尚未完全支持。 +
+ ++ 本指南提供了适用于大多数用户的推荐工作流,以及在遇到问题时的排查建议。 +
+ ++ 如果你是第一次搭建本地服务器,请先阅读安装页面。正确托管文件可以避免许多查看 3D 模型时的常见错误。 +
+ ++ 我们推荐尽可能使用 glTF(GL Transmission Format)格式。该格式的 .GLB 和 .GLTF 两种版本都得到了良好支持。由于 glTF 专注于运行时资源交付,它体积紧凑、加载速度快。支持的特性包括网格、材质、纹理、蒙皮、骨骼、变形目标、动画、灯光和相机。 +
+ ++ 公共领域的 glTF 文件可以在 + + Sketchfab 等网站上找到,许多工具也支持 glTF 导出: +
+ ++ 如果你常用的工具不支持 glTF,可以考虑向作者请求添加 glTF 导出功能,或者在 + glTF 路线图讨论帖中发帖。 +
+ ++ 当 glTF 不可用时,也可以使用 FBX、OBJ 或 COLLADA 等常见格式,它们同样可用且持续维护中。 +
+ ++ three.js 默认只包含少数加载器(如 `ObjectLoader`),其他加载器需要单独添加到你的应用中。 +
+ +
+import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
+
+
+ + 导入加载器后,就可以向场景中添加模型了。不同加载器的语法各不相同——使用其他格式时,请查阅对应加载器的示例和文档。对于 glTF,使用全局脚本的方式如下: +
+ +
+const loader = new GLTFLoader();
+
+loader.load( 'path/to/model.glb', function ( gltf ) {
+
+ scene.add( gltf.scene );
+
+}, undefined, function ( error ) {
+
+ console.error( error );
+
+} );
+
+
+ + 你花了好几个小时精心制作了一个模型,将它加载到网页中,结果——天哪!😭 它变形了、颜色不对,或者完全看不到。请按以下步骤排查: +
+ ++ 如果你已经完成了上述排查步骤,模型仍然无法正常工作,正确的求助方式能帮你更快找到解决方案。在 + three.js 论坛上发帖提问,并尽可能附上你的模型(或具有相同问题的简化模型),提供你手头的所有格式。请包含足够的信息以便他人快速复现问题——最好提供一个在线演示。 +
+ ++ 每个 uniform 都必须有一个 `value` 属性。其值的类型必须与 GLSL 代码中 uniform 变量的类型相对应,具体的 GLSL 基本类型对应关系见下表。Uniform 结构体和数组同样受支持。基本类型的 GLSL 数组必须指定为对应 THREE 对象的数组,或者包含所有对象数据的扁平数组。换言之,GLSL 基本类型本身不应再嵌套一层数组。此规则不具有传递性。例如,一个由 `vec2` 数组组成的数组,每个子数组包含五个向量,则必须是一个数组的数组,其中每个元素可以是五个 `Vector2` 对象或十个 `number`。 +
+ +| GLSL 类型 | +JavaScript 类型 | +
|---|---|
| int | +Number | +
| uint | +Number | +
| float | +Number | +
| bool | +Boolean | +
| bool | +Number | +
| vec2 | +Vector2 | +
| vec2 | +Float32Array (*) | +
| vec2 | +Array (*) | +
| vec3 | +Vector3 | +
| vec3 | +Color | +
| vec3 | +Float32Array (*) | +
| vec3 | +Array (*) | +
| vec4 | +Vector4 | +
| vec4 | +Quaternion | +
| vec4 | +Float32Array (*) | +
| vec4 | +Array (*) | +
| mat2 | +Float32Array (*) | +
| mat2 | +Array (*) | +
| mat3 | +Matrix3 | +
| mat3 | +Float32Array (*) | +
| mat3 | +Array (*) | +
| mat4 | +Matrix4 | +
| mat4 | +Float32Array (*) | +
| mat4 | +Array (*) | +
| ivec2, bvec2 | +Float32Array (*) | +
| ivec2, bvec2 | +Array (*) | +
| ivec3, bvec3 | +Int32Array (*) | +
| ivec3, bvec3 | +Array (*) | +
| ivec4, bvec4 | +Int32Array (*) | +
| ivec4, bvec4 | +Array (*) | +
| sampler2D | +Texture | +
| samplerCube | +CubeTexture | +
+ (*) 对于相同 GLSL 类型的(最内层)数组(维度)同样适用,其中包含数组中所有向量或矩阵的分量。 +
+ ++ 有时你可能希望在着色器代码中将 uniform 组织为 `struct`(结构体)。必须使用以下方式,`three.js` 才能正确处理结构化的 uniform 数据。 +
+
+uniforms = {
+ data: {
+ value: {
+ position: new Vector3(),
+ direction: new Vector3( 0, 0, 1 )
+ }
+ }
+};
+
+ 此定义可以映射到以下 GLSL 代码:
+
+struct Data {
+ vec3 position;
+ vec3 direction;
+};
+uniform Data data;
+
+
+ + 也可以在数组中管理 `structs`。此用法的语法如下: +
+
+const entry1 = {
+ position: new Vector3(),
+ direction: new Vector3( 0, 0, 1 )
+};
+const entry2 = {
+ position: new Vector3( 1, 1, 1 ),
+ direction: new Vector3( 0, 1, 0 )
+};
+
+uniforms = {
+ data: {
+ value: [ entry1, entry2 ]
+ }
+};
+
+ 此定义可以映射到以下 GLSL 代码:
+
+struct Data {
+ vec3 position;
+ vec3 direction;
+};
+uniform Data data[ 2 ];
+
+
+
+ 以下是一些在学习 three.js 时可能对你有用的链接合集。
+ 如果你想在此添加内容,或者认为以下某个链接已经过时或失效,请点击右下角的"编辑"按钮进行修改!
+
+ 另外请注意,由于 three.js 处于快速开发中,其中许多链接可能包含过时的信息——如果某些内容未按预期工作,或与这些链接中描述的不一致,请检查浏览器控制台中的警告或错误,同时查阅相关文档页面。
+
+ Three.js 官方使用[link:https://discourse.threejs.org/ 论坛]和 [link:http://stackoverflow.com/tags/three.js/info Stack Overflow] 来处理帮助请求。如果你需要帮助,请前往这些平台。请不要在 GitHub 上提交 issue 来寻求帮助。 +
+ ++ 这些链接出于历史原因保留——你可能仍然会觉得它们有用,但请注意其中的信息可能涉及非常旧的 three.js 版本。 +
+ ++ 尽管这个问题越来越少见,但某些设备或浏览器可能仍然不支持 WebGL 2。以下方法可以检测是否支持 WebGL 2,并在不支持时向用户显示提示信息。请导入 WebGL 支持检测模块,并在渲染任何内容之前运行以下代码。 +
+ +
+import WebGL from 'three/addons/capabilities/WebGL.js';
+
+if ( WebGL.isWebGL2Available() ) {
+
+ // 在此处调用初始化函数或执行其他初始化操作
+ animate();
+
+} else {
+
+ const warning = WebGL.getWebGL2ErrorMessage();
+ document.getElementById( 'container' ).appendChild( warning );
+
+}
+
+
+