- 三.js教程
- Three.js - 主页
- Three.js - 简介
- Three.js - 安装
- Three.js - Hello Cube 应用程序
- Three.js - 渲染器和响应能力
- Three.js - 响应式设计
- Three.js - 调试和统计
- Three.js - 相机
- Three.js - 控件
- Three.js - 光与影
- Three.js - 几何
- Three.js - 材料
- Three.js - 纹理
- Three.js - 画线
- Three.js - 动画
- Three.js - 创建文本
- Three.js - 加载 3D 模型
- Three.js - 库和插件
- Three.js 有用资源
- Three.js - 快速指南
- Three.js - 有用的资源
- Three.js - 讨论
Three.js - 快速指南
Three.js - 简介
所有现代浏览器都变得更强大并且更容易直接使用 JavaScript 进行访问。他们采用了 WebGL(Web 图形库),这是一种 JavaScript API,允许您使用 GPU(图形处理单元)的功能在任何兼容的 Web 浏览器中渲染高性能交互式 3D 和 2D 图形。
但 WebGL 是一个非常低级的系统,只能绘制点、正方形和直线等基本对象。然而,直接从 JavaScript 进行 WebGL 编程是一个非常复杂且冗长的过程。您需要了解 WebGL 的内部细节并学习复杂的着色器语言才能充分利用 WebGL。Three.js来了,让您的生活变得轻松。
什么是 Three.js?
Three.js 是一个开源、轻量级、跨浏览器、通用 JavaScript 库。Three.js 在后台使用 WebGL,因此您可以使用它在浏览器中的 HTML <canvas> 元素上渲染图形。由于 Three.js 使用 JavaScript,因此您可以与其他网页元素进行交互,添加动画和交互,甚至创建具有某些逻辑的游戏。
为什么使用 Three.js?
以下功能使 Three.js 成为一个优秀的库。
您只需使用 JavaScript 即可创建复杂的 3D 图形。
您可以在浏览器内创建虚拟现实 (VR) 和增强现实 (AR) 场景。
由于它使用WebGL,因此它具有跨浏览器支持。许多浏览器都支持它。
您可以添加各种材质、纹理和动画 3D 对象。
您还可以从其他 3D 建模软件加载和处理对象。
只需几行 JavaScript 和简单的逻辑,您就可以创建任何内容,从高性能交互式 3D 模型到逼真的实时场景。
这些是使用 Three.js 创建的一些优秀网站−
你可以在Three.js的官方网站上找到很多其他的例子
浏览器支持
桌面和移动设备上的所有现代浏览器目前都支持 WebGL。您唯一需要注意的浏览器是移动 Opera Mini 浏览器。对于 IE 10 及更早版本,有 IEWebGL 插件,您可以从https://github.com/iewebgl/iewebgl./您可以在此处找到有关 WebGL 浏览器支持的详细信息。
一旦您了解了 Three.js 是什么,您就可以继续阅读下一章,了解如何设置项目以开始使用 Three.js。
Three.js - 安装
有多种方法可以将 Three.js 包含在您的项目中。您可以使用以下任意方法来开始使用 Three.js。然后打开您最喜欢的代码编辑器并开始。
下载完整的 Three.js 项目
将完整的 Three.js 项目下载到您的系统中。您可以在此处或从GitHub下载。解压 Three.js-master.zip 文件并查看 build 文件夹内部。你可以找到两个三.js,三.min.js,这只是一个缩小版本。将这两个文件中的任何一个添加到您的项目文件夹中,并将它们链接到您的 HTML 文件。现在您可以在项目中使用 Three.js 了。
注意- 我们建议使用缩小版本,因为它加载速度更快。
将以下 <script> 标记插入到 HTML 的 <head> 元素中,其中包含 Threejs.min.js 文件的路径。
<script src='/path/to/threejs.min.js'></script>
使用 CDN 链接
您可以从 CDN(内容交付网络)链接文件,CDN 是一个专门用于托管文件的远程站点,以便您可以在线使用它们。您可以使用这些网站中的任何一个 -
将以下任意 <script> 标记插入 HTML 的 <head> 元素中。
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r127/three.min.js"></script>
或者
<script src="https://cdn.jsdelivr.net/npm/three@0.127.0/build/three.min.js"></script>
安装Three.js包
Three.js 也可以作为NPM 上的包提供。如果您的计算机上安装了 Node.js,则可以使用 npm 或yarn 安装它。
npm install three
或者
yarn add three
然后,您可以将 Three.js 从 Three.module.js 文件导入到您的 JavaScript 文件中
import * as THREE from 'three'
您可以将 Three.js 与任何 JavaScript 框架(如 React、Angular、Vue)一起使用。
完成项目设置后,让我们开始创建。
Three.js - Hello Cube 应用程序
与任何其他编程语言一样,让我们通过创建“Hellocube!”来开始学习 Three.js。应用程序。
超文本标记语言
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1" /> <meta charset="UTF-8" /> <title>Three.js - Hello cube</title> <style> /* Our CSS goes here */ </style> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r127/three.min.js"></script> </head> <body> <div id="threejs-container"> <!-- Our output to be rendered here → </div> <script type="module"> // our JavaScript code goes here </script> </body> </html>
正如您所看到的,它只是一个带有 Three.js CDN 的简单 HTML 文件。
CSS
<style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; } html, body { height: 100vh; width: 100vw; } #threejs-container{ position: block; width: 100%; height: 100%; } </style>
上面的CSS只是HTML页面的基本样式。Threejs-容器占据了整个屏幕。
JavaScript
这就是我们的 Three.js 应用程序发挥作用的地方。下面的代码在屏幕中间渲染一个立方体。所有这些代码都将进入 HTML 中的空 <script> 标记。
const width = window.innerWidth const height = window.innerHeight // Scene const scene = new THREE.Scene() scene.background = new THREE.Color('#00b140') // Camera const fov = 45 // AKA Field of View const aspect = window.innerWidth / window.innerHeight const near = 0.1 // the near clipping plane const far = 100 // the far clipping plane const camera = new PerspectiveCamera(fov, aspect, near, far) camera.position.set(0, 0, 10) // Renderer const renderer = new THREE.WebGLRenderer() renderer.setSize(window.innerWidth, window.innerHeight) renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) // Creating a cube const geometry = new THREE.BoxGeometry(2, 2, 2) const material = new THREE.MeshBasicMaterial({ wireframe: true }) const cube = new THREE.Mesh(geometry, material) scene.add(cube) // Rendering the scene const container = document.querySelector('#threejs-container') container.append(renderer.domElement) renderer.render(scene, camera)
让我们一次一步地讨论代码,然后您可以在接下来的章节中获得有关每个元素的更多信息。我们需要做的第一件事是创建场景、相机和渲染器。这些是构成每个 Three.js 应用程序的基本组件。
现场
const scene = new THREE.Scene() scene.background = new THREE.Color('#262626')
场景作为我们在屏幕上看到的所有内容的容器,如果没有 THREE.Scene 对象,Three.js 就无法渲染任何内容。背景颜色是深灰色,这样我们就可以看到立方体。
相机
const camera = new PerspectiveCamera(fov, aspect, near, far) camera.position.set(0, 0, 10)
相机对象定义了渲染场景时我们将看到的内容。相机的类型不多,但类型不同,但在本例中,您将使用 PerspectiveCamera,它与我们的眼睛观察世界的方式相匹配。
渲染器
const renderer = new THREE.WebGLRenderer() renderer.setSize(window.innerWidth, window.innerHeight)
渲染器对象负责根据相机计算场景在浏览器中的外观。渲染器有不同类型,但我们主要使用 WebGLRenderer,因为大多数浏览器都支持 WebGL。
除了创建渲染器实例之外,我们还需要设置渲染应用程序的大小。最好使用我们想要用我们的应用程序 The Cube 填充的区域的宽度和高度 - 在本例中是浏览器窗口的宽度和高度。
立方体
const geometry = new THREE.BoxGeometry(2, 2, 2) const material = new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe: true, }) const cube = new THREE.Mesh(geometry, material) scene.add(cube)
上面的代码在屏幕中央创建了一个简单的立方体。我们可以使用 THREE.Mesh 制作任何物体。网格需要两个对象:几何体和材质。网格的几何形状定义了其形状,材料决定了对象的表面属性。
要创建立方体,我们需要 BoxGeometry 和颜色为 0xffffff 的主要材质 (MeshBasicMaterial)。如果将wireframe属性设置为true,它会告诉Three.js向我们显示一个线框而不是一个实体对象。
渲染场景
const container = document.querySelector('#threejs-container') container.append(renderer.domElement) renderer.render(scene, camera)
例子
最后但并非最不重要的一点是,我们将渲染器元素添加到 HTML 文档中。渲染器使用 <canvas> 元素向我们显示场景。在这种情况下,渲染器将 <canvas> 元素附加到 HTML 中的引用容器。
你好-cube-app.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Three.js – Hello cube</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: -applesystem, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } html, body { height: 100vh; overflow: hidden; width: 100vw; } #threejs-container { position: block; width: 100%; height: 100%; } </style> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> </head> <body> <div id="threejs-container"></div> <script type="module"> // Hello Cube App // Your first Three.js application // sizes const width = window.innerWidth const height = window.innerHeight // scene const scene = new THREE.Scene() scene.background = new THREE.Color(0x262626) // camera const camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 100) camera.position.set(0, 0, 10) // cube const geometry = new THREE.BoxGeometry(2, 2, 2) const material = new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe: true }) const cube = new THREE.Mesh(geometry, material) scene.add(cube) // renderer const renderer = new THREE.WebGL1Renderer() renderer.setSize(width, height) renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) // rendering the scene const container = document.querySelector('#threejs-container') container.append(renderer.domElement) renderer.render(scene, camera) </script> </body> </html>
输出
如果一切正常,输出看起来像这样。尝试一下代码以更好地理解它的工作原理。
您现在已经完成了第一个 Three.js 应用程序的创建。让我们继续为应用程序添加更多美感。
Three.js - 渲染器和响应能力
场景的基本功能
您知道场景是相机、灯光和我们要在屏幕上渲染的对象的容器。让我们看一下 Scene 对象的一些基本功能 -
添加对象
函数 add(object) 用于将对象添加到场景中。
const scene = THREE.Scene() scene.add(cube) // adds the cube scene.add(sphere) // adds a sphere
移除对象
函数remove(object)从场景中删除一个对象。
scene.remove(cube) // removes the last added cube scene.remove(sphere) // removes a sphere
孩子们
在 scene.children 中返回场景中所有对象的数组,包括相机和灯光。
console.log(scene.children) // outputs all the objects in the scene console.log(scene.children.length) // outputs number of elements on the scene
注意- 我们可以使用名称属性为任何对象命名。名称对于调试目的很方便,但也可以直接访问场景中的对象。
查看以下示例。
场景.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Three.js – The scene <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: -applesystem, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } html, body { height: 100vh; width: 100vw; background-color: #262626; overflow: hidden; } #btn-conatiner { position: absolute; top: 0; left: 0; height: 10vh; width: 100%; } @media screen and (max-width:600px){ #btn-container{ display: flex; flex-direction: column; } } .btn { padding: 5px 15px; margin: 5px 15px; font-weight: bold; text-transform: uppercase; } .add { color: green; } .rem { color: red; } #threejs-container { position: block; width: 100%; height: 100%; } </style> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.js"></script> </head> <body> <div id="btn-conatiner"> <button class="btn add">Add Cube</button> <button class="btn rem">Remove Cube</button> </div> <div id="threejs-container"></div> <script type="module"> // Experimenting with different methods of scene // add, remove, children, getElementById // sizes let width = window.innerWidth let height = window.innerHeight const gui = new dat.GUI() // scene const scene = new THREE.Scene() scene.background = new THREE.Color(0x262626) // lights const ambientLight = new THREE.AmbientLight(0xffffff, 0.5) scene.add(ambientLight) const light = new THREE.PointLight(0xffffff, 0.5) light.position.set(-10, 10, -10) // for shadow light.castShadow = true light.shadow.mapSize.width = 1024 light.shadow.mapSize.height = 1024 light.shadow.camera.near = 0.1 light.shadow.camera.far = 1000 scene.add(light) // camera const camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000) camera.position.set(0, 10, 40) camera.lookAt(0, 0, 0) gui.add(camera.position, 'z', 10, 200, 1).name('camera-z') // plane const planeGeometry = new THREE.PlaneGeometry(100, 100) const plane = new THREE.Mesh( planeGeometry, new THREE.MeshPhongMaterial({ color: 0xffffff, side: THREE.DoubleSide }) ) plane.rotateX(Math.PI / 2) plane.position.y = -1.75 plane.receiveShadow = true scene.add(plane) // scene.add function addCube() { const cubeSize = Math.ceil(Math.random() * 3) const cubeGeometry = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize)const cubeMaterial = new THREE.MeshLambertMaterial({ color: Math.random() * 0xffffff }) const cube = new THREE.Mesh(cubeGeometry, cubeMaterial) cube.castShadow = true cube.name = 'cube-' + scene.children.length cube.position.x = -30 + Math.round(Math.random() * 50) cube.position.y = Math.round(Math.random() * 5) cube.position.z = -20 + Math.round(Math.random() * 50) scene.add(cube) } const add = document.querySelector('.add') add.addEventListener('click', () => { addCube() console.log('cube added') }) // scene.remove function removeCube() { const allChildren = scene.children const lastObject = allChildren[allChildren.length - 1] if (lastObject.name) { scene.remove(lastObject) } } const remove = document.querySelector('.rem') remove.addEventListener('click', () => { removeCube() console.log('cube removed') }) // scene.children console.log(scene.children) // responsivenesswindow.addEventListener('resize', () => { width = window.innerWidth height = window.innerHeight camera.aspect = width / height camera.updateProjectionMatrix() renderer.setSize(window.innerWidth, window.innerHeight) renderer.render(scene, camera) }) // renderer const renderer = new THREE.WebGL1Renderer() renderer.setSize(width, height) renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) // animation function animate() { requestAnimationFrame(animate) renderer.render(scene, camera) } // rendering the scene const container = document.querySelector('#threejs-container') container.append(renderer.domElement) renderer.render(scene, camera) animate() </script> </body> </html>
打开控制台查看场景中的元素。
使用名称属性
函数 scene.getObjectByName(name) 直接从场景中按特定名称返回对象。
您还可以添加另一个参数 - 递归。
scene.getObjectByName(name, recursive)
如果将递归参数设置为 true,Three.js 将搜索完整的对象树以查找具有指定名称的事物。
为场景添加雾
此属性允许您设置场景的雾。雾呈现出薄雾,遮盖了远处的物体。
scene.fog = new THREE.Fog(0xffffff, 0.015, 100)
这行代码定义了白雾(0xffffff)。您可以使用前面的两个属性来调整雾的显示方式。0.015 值设置近属性,100 值设置远属性。利用这些属性,您可以确定雾开始的位置以及雾变得更浓的速度。
对于 THREE.Fog 对象,雾会线性增加。还有一种不同的方式来设置场景的雾气;为此,请使用以下定义 -
scene.fog = new THREE.FogExp2(0xffffff, 0.01)
这次,我们不指定远近,只指定颜色(0xffffff)和雾的密度(0.01)。最好对这些属性进行一些试验以获得您想要的效果。
使用覆盖材质属性
overrideMaterial 属性强制场景中的所有对象使用相同的材质。
scene.overrideMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff })
这里,场景中的所有物体采用相同的材质,即MeshLambertMaterial。
注意- THREE.Scene 是一种有时也称为Scenegraph 的结构。场景图是一种可以保存图形场景所有必要信息的结构。在 Three.js 中,这意味着 THREE.Scene 包含渲染所需的所有对象、灯光和其他对象。
渲染器
渲染器使用相机和场景中的信息在屏幕上绘制输出,即 <canvas> 元素。
在 Hello 立方体应用程序中,我们使用了 WebGLRenderer。还可以使用其他一些渲染器,但 WebGLRenderer 是迄今为止最强大的可用渲染器,并且通常是您唯一需要的渲染器。
注意- 有一个基于 canvas 的渲染器、一个基于 CSS 的渲染器和一个基于 SVG 的渲染器。尽管它们可以工作并且可以渲染简单的场景,但我不建议使用它们。它们的开发并不积极,非常消耗 CPU,并且缺乏良好的材质支持和阴影等功能。
Three.js - 响应式设计
在调整屏幕大小时,您可以观察到场景没有响应。使网页响应通常是指页面在不同尺寸的显示器(从台式机、平板电脑到手机)上显示良好。在本章中,您可以了解如何解决 Three.js 应用程序的一些基本问题。
当浏览器尺寸改变时自动调整输出大小
当您调整浏览器大小时,我们必须通知 Three.js 以了解 <canvas> 元素应该有多宽。对于相机,我们需要更新纵横比属性,该属性保存屏幕的纵横比,对于渲染器,我们需要更改其大小。
window.addEventListener('resize', () => { // update display width and height width = window.innerWidth height = window.innerHeight // update camera aspect camera.aspect = width / height camera.updateProjectionMatrix() // update renderer renderer.setSize(width, height) renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) renderer.render(scene, camera) })
例子
上面的代码为您的 Three.js 项目提供了响应能力。
调整浏览器大小.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Three.js – Resizing browser</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: -applesystem, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } html, body { height: 100vh; width: 100vw; } #threejs-container { position: block; width: 100%; height: 100%; } </style> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.js"></script> </head> <body> <div id="threejs-container"></div> <script type="module"> // Adding responsiveness for Three.js // sizes let width = window.innerWidth let height = window.innerHeight const gui = new dat.GUI() // scene const scene = new THREE.Scene() scene.background = new THREE.Color(0x262626) // camera const camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 100) camera.position.set(0, 0, 10) // cube const geometry = new THREE.BoxGeometry(2, 2, 2) const material = new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe: true }) const cube = new THREE.Mesh(geometry, material) scene.add(cube) // responsiveness window.addEventListener('resize', () => { width = window.innerWidth height = window.innerHeight camera.aspect = width / height camera.updateProjectionMatrix() renderer.setSize(window.innerWidth, window.innerHeight) renderer.render(scene, camera) }) // renderer const renderer = new THREE.WebGL1Renderer() renderer.setSize(width, height) renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) // animation function animate() { requestAnimationFrame(animate) cube.rotation.x += 0.005 cube.rotation.y += 0.01 renderer.render(scene, camera) } // rendering the scene const container = document.querySelector('#threejs-container') container.append(renderer.domElement) renderer.render(scene, camera) animate() </script> </body> </html>
输出
当您执行代码时,它将产生以下输出 -
现在,调整浏览器的大小。由于响应式设计,该对象始终会重新定位在浏览器的中心。
抗锯齿
锯齿效应是指边缘和对象(使用像素渲染)上出现锯齿状边缘或“锯齿”(也称为阶梯线)。
例子
抗锯齿.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Three.js - Anti-aliasing</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: -applesystem, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } html, body { height: 100vh; width: 100vw; } #threejs-container { position: block; width: 100%; height: 100%; } </style> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.js"></script> </head> <body> <div id="threejs-container"></div> <script type="module"> // Adding anti-aliasing to Three.js app for removing jaggies // sizes let width = window.innerWidth let height = window.innerHeight const gui = new dat.GUI() // scene const scene = new THREE.Scene() scene.background = new THREE.Color(0x262626) // camera const camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 100) camera.position.set(0, 0, 10) // cube const geometry = new THREE.BoxGeometry(2, 2, 2) const material = new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe: true }) const cube = new THREE.Mesh(geometry, material) scene.add(cube) // responsiveness window.addEventListener('resize', () => { width = window.innerWidth height = window.innerHeight camera.aspect = width / height camera.updateProjectionMatrix() renderer.setSize(window.innerWidth, window.innerHeight) renderer.render(scene, camera) }) // renderer - anti-aliasing const renderer = new THREE.WebGLRenderer({ antialias: true }) renderer.physicallyCorrectLights = true renderer.setSize(width, height) renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) // animation function animate() { requestAnimationFrame(animate) cube.rotation.x += 0.005 cube.rotation.y += 0.01 renderer.render(scene, camera) } // rendering the scene const container = document.querySelector('#threejs-container') container.append(renderer.domElement) renderer.render(scene, camera) animate() </script> </body> </html>
输出
我们的 Hello 立方体应用程序中的别名如下所示。
我们可以通过将 WebGLRenderer 的 antialias 属性设置为 true 来打开抗锯齿功能。默认情况下,它是错误的。在这里,我们将抗锯齿参数设置为 true -
const renderer = new WebGLRenderer({ antialias: true }) renderer.physicallyCorrectLights = true
抗锯齿后,它看起来很平滑,没有锯齿,如下图所示。
physicalCorrectLights 属性告诉 Three.js 是否使用物理上正确的光照模式。默认为 false。将其设置为 true 有助于增加对象的细节。
Three.js - 调试和统计
使用Dat.GUI
不断尝试变量的值(例如立方体的位置)是很困难的。在这种情况下,假设直到你得到你喜欢的东西。这是一个缓慢而艰巨的过程。幸运的是,已经有一个很好的解决方案可以与 Three.js、dat.GUI 完美集成。它允许您创建一个可以更改代码中变量的基本用户界面组件。
安装
要在您的项目中使用 dat.GUI,请在此处下载并将 <script> 标记添加到 HTML 文件中。
<script type='text/javascript' src='path/to/dat.gui.min.js'></script>
或者您可以使用 CDN,在 HTML 中添加以下 <script> 标记。
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.js"></script>
如果您在节点应用程序中使用 Three.js,请安装 npm 包 - dat.GUI 并将其导入您的 JavaScript 文件中。
npm install dat.gui
或者
yarn add dat.gui import * as dat from 'dat.gui'
用法
首先,您应该初始化对象本身。它创建一个小部件并将其显示在屏幕右上角。
const gui = new dat.GUI()
然后,您可以添加要控制的参数和变量。例如,下面的代码是控制立方体的y位置。
gui.add(cube.position, 'y')
例子
尝试添加其他位置变量。请参阅此工作代码示例。
立方体.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Three.js - Position GUI</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: -applesystem, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } html, body { height: 100vh; width: 100vw; } #threejs-container { position: block; width: 100%; height: 100%; } </style> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.js"></script> </head> <body> <div id="threejs-container"></div> <script type="module"> // Adding UI to debug and experimenting different values // UI const gui = new dat.GUI() // sizes let width = window.innerWidth let height = window.innerHeight // scene const scene = new THREE.Scene() scene.background = new THREE.Color(0x262626) // camera const camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 100) camera.position.set(0, 0, 10) // cube const geometry = new THREE.BoxGeometry(2, 2, 2) const material = new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe: true }) gui.add(material, 'wireframe') const cube = new THREE.Mesh(geometry, material) scene.add(cube) gui.add(cube.position, 'x') gui.add(cube.position, 'y') gui.add(cube.position, 'z') // responsiveness window.addEventListener('resize', () => { width = window.innerWidth height = window.innerHeight camera.aspect = width / height camera.updateProjectionMatrix() renderer.setSize(window.innerWidth, window.innerHeight) renderer.render(scene, camera) }) // renderer const renderer = new THREE.WebGL1Renderer() renderer.setSize(width, height) renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) // animation function animate() { requestAnimationFrame(animate) cube.rotation.x += 0.005 cube.rotation.y += 0.01 renderer.render(scene, camera) } // rendering the scene const container = document.querySelector('#threejs-container') container.append(renderer.domElement) renderer.render(scene, camera) animate() </script> </body> </html>
输出
您可以使用 name 属性自定义显示的标签。要更改变量行上的标签,请使用 .name("your label")。
gui.add(cube.position, 'y').name('cube-y')
您可以设置最小/最大限制以及获取滑块的步骤。以下行允许值从 1 到 10,每次将值增加 1。
gui.add(cube.position, 'y').min(1).max(10).step(1) // or gui.add(cube.position, 'y', 1, 10, 1)
如果有许多同名的变量,您可能会发现很难区分它们。在这种情况下,您可以为每个对象添加文件夹。与对象相关的所有变量都位于一个文件夹中。
// creating a folder const cube1 = gui.addFolder('Cube 1') cube1.add(redCube.position, 'y').min(1).max(10).step(1) cube1.add(redCube.position, 'x').min(1).max(10).step(1) cube1.add(redCube.position, 'z').min(1).max(10).step(1) // another folder const cube2 = gui.addFolder('Cube 2') cube2.add(greenCube.position, 'y').min(1).max(10).step(1) cube2.add(greenCube.position, 'x').min(1).max(10).step(1) cube2.add(greenCube.position, 'z').min(1).max(10).step(1)
例子
现在,检查以下示例。
gui-folders.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Three.js - More variables</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: -applesystem, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } html, body { height: 100vh; width: 100vw; } #threejs-container { position: block; width: 100%; height: 100%; } </style> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.js"></script> </head> <body> <div id="threejs-container"></div> <script type="module"> // Adding folders to distinguish between variables // controls const gui = new dat.GUI() // sizes let width = window.innerWidth let height = window.innerHeight // scene const scene = new THREE.Scene() scene.background = new THREE.Color(0x262626) // camera const camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 100) camera.position.set(0, 0, 10) const camFolder = gui.addFolder('Camera') camFolder.add(camera.position, 'z').min(10).max(60).step(10) // cube const geometry = new THREE.BoxGeometry(2, 2, 2) const material = new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe: true }) const cubeColor = { color: 0xffffff } const materialFolder = gui.addFolder('Material') materialFolder.add(material, 'wireframe') materialFolder.addColor(cubeColor, 'color').onChange(() => { // callback material.color.set(cubeColor.color) }) materialFolder.open() const cube = new THREE.Mesh(geometry, material) scene.add(cube) const cubeFolder = gui.addFolder('Cube') // for position const posFolder = cubeFolder.addFolder('position') posFolder.add(cube.position, 'x', 0, 5, 0.1) posFolder.add(cube.position, 'y', 0, 5, 0.1) posFolder.add(cube.position, 'z', 0, 5, 0.1) posFolder.open() // for scale const scaleFolder = cubeFolder.addFolder('Scale') scaleFolder.add(cube.scale, 'x', 0, 5, 0.1).name('Width') scaleFolder.add(cube.scale, 'y', 0, 5, 0.1).name('Height') scaleFolder.add(cube.scale, 'z', 0, 5, 0.1).name('Depth') scaleFolder.open() cubeFolder.open() // responsiveness window.addEventListener('resize', () => { width = window.innerWidth height = window.innerHeight camera.aspect = width / height camera.updateProjectionMatrix() renderer.setSize(window.innerWidth, window.innerHeight) renderer.render(scene, camera) }) // renderer const renderer = new THREE.WebGL1Renderer() renderer.setSize(width, height) renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) // animation function animate() { requestAnimationFrame(animate) cube.rotation.x += 0.005 cube.rotation.y += 0.01 renderer.render(scene, camera) } // rendering the scene const container = document.querySelector('#threejs-container') container.append(renderer.domElement) renderer.render(scene, camera) animate() </script> </body> </html>
输出
您还可以添加一些回调函数。一旦值改变就会触发onChange。
gui.add(cube.position, 'y').onChange(function () { // refresh based on the new value of y console.log(cube.position.y) })
让我们看一下使用 dat.gui 和回调更改颜色的另一个示例。
// parameter const cubeColor = { color: 0xff0000, } gui.addColor(cubeColor, 'color').onChange(() => { // callback cube.color.set(cubeColor.color) })
当cubeColor的颜色改变时,上面的回调onChange通知Three.js改变立方体的颜色。
从现在开始我们将经常使用这个 dat.gui。通过尝试“Hello Cube!”确保您习惯了它。应用程序。
统计- 统计在大规模应用中发挥着重要作用。
Three.js - 相机
相机类型
Three.js 中有两种类型的相机。
先生编号 | 相机及描述 |
---|---|
1 | Three.js 中有不同的相机。最常见的相机也是我们一直使用的相机是 PerspectiveCamera。 |
2 | 第二个最常见的相机是正交相机。它指定一个具有左、右、上、下、近和远设置的框。它以二维方式表示三维物体。 |
让相机跟随物体
在动画函数中,我们使用camera.lookAt函数将相机指向对象的位置函数。我们在渲染的每一帧中都执行此操作。看起来相机完全跟随物体的位置。
function animate() { const object = scene.getObjectByName('sphere') renderer.render(scene, camera) camera.lookAt(object.position) requestAnimationFrame(render) }
Three.js - 控件
您可以使用摄像机控制在场景中移动摄像机。Three.js 有许多摄像机控件,您可以使用它们来控制整个场景中的摄像机。您必须从GitHub单独获取控件。Three.js 库不包含这些。
先生编号 | 控制和说明 |
---|---|
1 |
轨道控制允许摄像机围绕场景中心旋转。 |
2 |
TrackballControls 与 Orbit 控件类似。然而,它不保持恒定的相机向上矢量。 |
3 |
这些是类似飞行模拟器的控件。使用键盘和鼠标移动和驾驶。 |
4 |
PointerLockControls 实现内置浏览器 Pointer Lock API。 |
在本章中,我们看到了最有用的控件。一些开发人员正在为 Three.js 创建更有用的控件。您可以在这里看到一些其他控件,它们有详细的文档记录并且易于使用。
Three.js - 光与影
灯光使对象可见,类似地,在 Three.js 中,THREE.Light 照亮场景并使某些东西可见。并非所有材质都会受到光照的影响。MeshBasicMaterial 和 MeshNormalMaterial 是自发光的,因此它们不需要照明即可在场景中可见。但是,大多数其他材质(MeshLambertMaterial、MeshPhongMaterial、MeshStandardMaterial、MeshPhysicalMaterial 和 MeshToonMaterial)都可以。我们将在后续章节中讨论更多材料。在本章中,我们将重点介绍 Three.js 中不同类型的灯光。
每种光都具有颜色和强度属性。
color - (可选)灯光的十六进制颜色。默认值为 0xffffff(白色)。
强度- (可选)光强度/强度的数值。默认值为 1。
投射阴影
来自特定方向的光可以投射阴影。首先,我们应该让场景准备好投射阴影。
步骤 - 1
我们应该首先告诉渲染器我们要启用阴影。投射阴影是一项昂贵的操作。WebGLRenderer 仅支持此功能。它使用阴影映射,这是一种特定于 WebGL 的技术,直接在 GPU 上执行。
renderer.shadowMapEnabled = true
上面的代码行告诉渲染器在场景中投射阴影。
注意- Three.js 默认情况下使用阴影贴图。阴影贴图适用于投射阴影的光。场景渲染所有标记为从光的角度投射阴影的对象。
如果阴影的边缘看起来有点块状,则意味着阴影贴图太小。要增加阴影贴图大小,您可以为灯光定义shadowMapHeight 和shadowMapWidht 属性。或者,您也可以尝试更改WebGLRenderer的shadowMapType属性。您可以将其设置为 THREE.BasicShadowMap、THREE.PCFShadowMap 或 THREE.PCFSoftShadowMap。
// to antialias the shadow renderer.shadowMapType = THREE.PCFSoftShadowMap // or directionalLight.shadowMapWidth = 2048 directionalLight.shadowMapHeight = 2048
步骤 - 2
您应该配置对象来投射阴影。您可以告知 Three.js 哪些对象可以投射阴影以及哪些对象可以接收阴影。
object.castShadow = true object.recieveShadow = true
步骤 - 3
上述所有步骤对于每个灯都是相同的。下一步是设置与阴影相关的属性。
light.castShadow = true light.shadow.camera.near = 10 light.shadow.camera.far = 100 light.shadow.camera.left = -50 light.shadow.camera.right = 50 light.shadow.camera.top = 50 light.shadow.camera.bottom = -50
第一个属性castShadow告诉Three.js这个光投射阴影。由于投射阴影是一项昂贵的操作,因此我们需要定义阴影可以出现的区域。您可以使用shadow.camera.near、shadow.camera.far 和shadow.camera.left 等属性来完成此操作。利用上述属性,我们创建了一个类似盒子的区域,Three.js 在此渲染阴影。
例子
在此示例中探索更多内容。
定向.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Three.js - Directional Light</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: -applesystem, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } html, body { height: 100vh; width: 100vw; } #threejs-container { position: block; width: 100%; height: 100%; } </style> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.js"></script> </head> <body> <div id="container"></div> <script type="module"> // Adding directional light to the scene // The lights falls from the light only in one direction. // You can see the position of light using helpers provided in Three.j s for debugging purposes // GUI const gui = new dat.GUI() // sizes let width = window.innerWidth let height = window.innerHeight // scene const scene = new THREE.Scene() scene.background = new THREE.Color(0x262626) // camera const camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000) camera.position.set(0, 0, 10) const camFolder = gui.addFolder('Camera') camFolder.add(camera.position, 'z', 10, 80, 1) camFolder.open() // lights const ambientLight = new THREE.AmbientLight(0xffffff, 0.5) scene.add(ambientLight) const light = new THREE.DirectionalLight() light.position.set(2.5, 2, 2) light.castShadow = true light.shadow.mapSize.width = 512 light.shadow.mapSize.height = 512 light.shadow.camera.near = 0.5 light.shadow.camera.far = 100 scene.add(light) const helper = new THREE.DirectionalLightHelper(light) scene.add(helper) // light controls const lightColor = { color: light.color.getHex() } const lightFolder = gui.addFolder('Directional Light') lightFolder.addColor(lightColor, 'color').onChange(() => { light.color.set(lightColor.color) }) lightFolder.add(light, 'intensity', 0, 1, 0.01) lightFolder.open() const directionalLightFolder = gui.addFolder('Position of Light') directionalLightFolder.add(light.position, 'x', -10, 10, 0.1) directionalLightFolder.add(light.position, 'y', -10, 10, 0.1) directionalLightFolder.add(light.position, 'z', -10, 10, 0.1) directionalLightFolder.open() // plane const planeGeometry = new THREE.PlaneGeometry(100, 20) const plane = new THREE.Mesh(planeGeometry, new THREE.MeshPhongMateria l({ color: 0xffffff })) plane.rotateX(-Math.PI / 2) plane.position.y = -1.75 plane.receiveShadow = true scene.add(plane) // cube const geometry = new THREE.BoxGeometry(2, 2, 2) const material = new THREE.MeshStandardMaterial({ color: 0x87ceeb }) const materialFolder = gui.addFolder('Material') materialFolder.add(material, 'wireframe') materialFolder.open() const cube = new THREE.Mesh(geometry, material) cube.position.set(0, 0.5, 0) cube.castShadow = true cube.receiveShadow = true scene.add(cube) // responsiveness window.addEventListener('resize', () => { width = window.innerWidth height = window.innerHeight camera.aspect = width / height camera.updateProjectionMatrix() renderer.setSize(window.innerWidth, window.innerHeight) renderer.render(scene, camera) }) // renderer const renderer = new THREE.WebGL1Renderer() renderer.setSize(window.innerWidth, window.innerHeight) renderer.shadowMap.enabled = true renderer.shadowMap.type = THREE.PCFSoftShadowMap renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) // animation function animate() { requestAnimationFrame(animate) cube.rotation.x += 0.005 cube.rotation.y += 0.01 renderer.render(scene, camera) } // rendering the scene const container = document.querySelector('#container') container.append(renderer.domElement) renderer.render(scene, camera) animate() </script> </body> </html>
输出
先生编号 | 灯光及说明 |
---|---|
1 |
它是最基本的光,均匀地照亮整个场景。 |
2 |
定向光来自特定点并从远处直接发射到目标。 |
3 |
它是另一种来自圆锥体特定方向的光。 |
4 |
点光源是从一个点向各个方向发射光的光源。 |
5 |
它是一种用于创造自然光的特殊灯。 |
Three.js - 几何
几何图形用于在 Three.js 中创建和定义形状。Three.js 有许多类型的内置几何图形,包括 2D 和 3D。
在本章中,我们将讨论基本的内置几何图形。我们将首先查看 2D 几何图形,然后,我们将探索所有可用的基本 3D 几何图形。
先生编号 | 几何形状和描述 |
---|---|
1 |
THREE.PlaneGeometry 创建一个简单的 2D 矩形。 |
2 |
THREE.CircleGeometry 创建一个简单的 2D 圆。 |
3 |
THREE.RingGeometry 创建一个中心有孔的 D 盘。 |
4 |
THREE.BoxGeometry 创建一个具有指定尺寸的简单 3D 框。 |
5 |
THREE.SphereGeometry 创建 3D 球体几何形状。 |
6 |
要在 Three.js 中创建圆柱体,您可以使用 Three.CylinderGeometry。 |
7 |
您可以使用 THREE.ConeGeometry 创建圆锥体。它与 CylinderGeometry 非常相似,不同之处在于它只允许您设置半径而不是 radiusTop 和 radiusBottom。 |
8 |
环面是一种管状形状,看起来像甜甜圈。您可以使用 THREE.TorusGeometry 在 Three.js 中创建圆环。 |
9 |
环面结是一种特殊的结,看起来像一根绕自身缠绕几圈的管子。 |
10 |
多面体是仅具有平面和直边的几何形状。 |
在此处了解有关几何形状的更多信息
Three.js - 材料
材料就像物体的皮肤。它定义了几何体的外观。Three.js 提供了许多工作材料。我们应该根据自己的需要来选择材料的类型。在本章中,我们将讨论 Three.js 中最常用的材料。
先生编号 | 材料及描述 |
---|---|
1 |
它是 Three.js 中非常基本的材料。 |
2 |
它使用距相机的距离来确定如何以灰度级为网格着色。 |
3 |
该材质使用面部法线向量的 x/y/z 值的大小来计算和设置面部显示颜色的红色/绿色/蓝色值。 |
4 |
您可以使用这种材料创建暗淡、无光泽的表面。 |
5 |
此材质类似于 MeshLambertMaterial,但可以创建更有光泽的表面。 |
6 |
|