threejs 基础概要
threejs 基础概要
点击查看官方文档
下面是翻译的内容(稍作修改)
先了解一下Three.js应用程序的结构。Three.js应用程序需要创建一堆对象并将它们连接在一起。下图表示一个小three.js应用程序的图。
关于上图的注意事项
Renderer 渲染器,将一个场景和一个摄像机传递给渲染器,它就会将摄像机截锥内的3D场景部分作为2D图像呈现给画布。
有一个树状结构的场景图,其中包括各种物体,如Scene对象,多个 Mesh对象,Light对象,Group,Object3D,和Camera对象。一个Scene对象定义了场景图的根,并且包含诸如背景色和雾化度之类的属性。这些对象定义了分层的父/子树状结构,并表示对象出现在何处,以及如何定向。
注意,上图中的Camera相机,占场景图中的一半。这是为了表示在three.js中,与其他对象不同。摄像机不必在场景图中才能正常工作。与其他对象一样,Camera 作为其他对象的子对象,将相对于其父对象移动和定向。
Mesh 网格对象,表示用特定的材质绘制特定的几何图形。Material对象和Geometry对象都可以被多个网格对象使用。例如,要在不同的位置绘制2个蓝色立方体,我们可能需要2个网格对象来表示每个立方体的位置和方向。我们只需要一个Geometry来保存一个立方体的顶点数据,一个Material来指定蓝色。两个网格对象可以引用相同的Geometry对象和相同的Material对象
Geometry 几何对象,表示某些几何形状的顶点数据,例如球体,立方体,平面,狗,猫,人,树,建筑物等。Three.js提供了许多内置的几何图元。同时也可以创建自定义几何图形以及,或者从文件加载几何图形(如***.obj文件)。
Material 表面材质对象,标识绘制几何图形的表面属性,包括要使用的颜色及其光泽程度等。1个Material还可以引用一个或多个Texture对象,这些对象可以用于例如将图像包装到几何图形的表面上。
Texture 纹理对象,通常表示从图像文件加载,从画布生成或从另一个场景渲染的图像。
Light 灯光对象,代表不同类型的灯光。
下面制作一个最小的“Cube”场景,如下所示
首先加载three.js
<script type="module">
// 1.直接使用线上资源
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r115/build/three.module.js';
// 2.直接使用本地 three.js
import *as THREE from "./three.js/build/three.js"
// 3.使用本地 three.module.js
// 本地启服务(http-server等), import 才能访问本地 three.module.js
import *as THREE from "./three.js/build/three.module.js"
</script>
script标签中 type="module" 很重要。这使我们能够使用import关键字来加载three.js。还有其他方法可以加载three.js,但是从r106版本开始,建议使用模块。模块的优点是可以轻松导入所需的其他模块。这使我们不必手动加载它们依赖的额外脚本。
创建canvas标签
<body>
<canvas id="c"></canvas>
</body>
创建render
< script type = "module" >
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r115/build/three.module.js';
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({
canvas
});
...
}
main();
</script>
在查找画布之后,我们创建了一个WebGLRenderer。渲染器负责获取你提供的所有数据并将其呈现到画布上。过去有其他渲染器,比如CSSRenderer, CanvasRenderer,将来可能会有WebGL2Renderer或WebGPURenderer。目前使用WebGLRenderer使用WebGL渲染3D到画布。
注意这里有一些注意的细节。如果你没有传递一个画布到three.js,它会为你创建一个,但你必须把它添加到你的文档。在哪里添加它取决于你的用例,你必须改变你的代码,所以我们发现传递一个画布给three.js感觉更灵活。
我可以将画布放在任何地方,代码会找到它,就好像我有代码可以将画布插入到文档中,如果我的用例发生变化,我可能需要更改代码。
创建Camera
接下来,我们需要一台照相机。下面代码将创建一个PerspectiveCamera(透视相机)。
const fov = 75; // 视场角
const aspect = 2; // canvas 默认的宽高比例 默认 300/150 = 2
const near = 0.1;
const far = 5;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
fov 是 field of view 的缩写,表示视场角。在这种情况下,垂直尺寸为75度。注意,Three.js中的大多数角度都以 弧度 表示,但由于某些原因,透视相机取 度。下图(网上截的图)中的ω,就表示视场角。
aspect 是画布的显示方面。我们将在另一篇文章中详细介绍 ,但默认情况下,画布尺寸为300x150像素,所以宽高比为300/150=2。
near 和 far 表示将要渲染在相机前面的空间范围。该范围之前或之后的任何内容都会被裁剪(不绘制)。
fov、aspect、near、far四个值,定义了一个“视锥”。视锥是3d形状的名称,它的形状像一个金字塔,顶端被切掉。换句话说,将“视锥”这个词视为另一种3D形状,例如球体,立方体,棱镜,视锥。
近平面和远平面的高度由视场确定。两个平面的宽度由视场和外观确定。
定义的视锥内部的所有内容都将被绘制。视锥外面的都不绘制。
相机默认是向下看-Z轴,向上看+Y轴。我们把立方体放在原点,所以我们需要把摄像机从原点往后移一点,这样才能看到任何东西。
camera.position.z = 2;
在上图中,我们可以看到我们的摄像机在z = 2处。它沿着-Z轴向下看。我们的截锥从摄像机前面0.1个单位开始,到摄像机前面5个单位。因为在这个图中,我们是向下看的,视野是受角度影响的。我们的画布的宽度是它的高度的两倍,所以整个视野将比我们指定的75度的垂直视野宽得多。
创建Scene
接下来创建一个scene。three.js中的一个场景,可以看成是一种场景图形式的根。任何你想要让three.js绘制的东西,都需要添加到场景中。
const scene = new THREE.Scene();
创建Geometry
接下来,我们创建一个包含盒子数据的BoxGeometry。
几乎任何我们想要在Three.js中显示的东西,都需要定义构成3D对象的顶点的几何图形。
const boxWidth = 1;
const boxHeight = 1;
const boxDepth = 1;
const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
创建表面Material
然后我们创建一个基本材质并设置它的颜色。颜色可以使用标准的CSS样式6位十六进制颜色值来指定。
const material = new THREE.MeshBasicMaterial({
color: 0x44aa88
})
创建网格Mesh
然后创建一个网格。在three.js中,网格代表了一个几何体(物体的形状)和一个材质(如何绘制物体,闪亮的还是平坦的,什么颜色,应用什么纹理)的组合等。以及该对象在场景中的位置、方向和比例。
const cube = new THREE.Mesh(geometry, material);
将网格添加到场景
scene.add(cube);
渲染场景
然后,我们可以通过调用渲染器的render函数,并将场景和摄像机传递给它,来渲染场景
renderer.render(scene, camera);
开启动画渲染
沿着-Z轴观察的而立方体本身是与轴对齐的,所以我们只能看到一个面。用动画让它旋转,就可以看清3D绘制的效果。
使用浏览器的window.requestAnimationFrame进行渲染。
function render(time) {
time *= 0.001; // 转化一下时间
cube.rotation.x = time; // 绕x轴旋转网格
cube.rotation.y = time; // 绕y轴旋转网格
renderer.render(scene, camera); // renderer渲染
requestAnimationFrame(render);
}
requestAnimationFrame(render);
虽然好了一点,但还是很难看到3d效果。添加一些照明会有帮助,所以让我们添加一盏灯。three.js中有许多种类的light
创建灯光light
const color = 0xFFFFFF; // 光的颜色
const intensity = 1; // 光照强度
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(-1, 2, 4); // 灯的位置
scene.add(light);
定向灯有一个位置和一个目标。两者都默认为0, 0, 0。在本例中,我们将灯光的位置设置为-1, 2, 4,这样它的位置好,就稍微在相机的左边、上面和后面一些。定向灯的目标坐标仍然是(0, 0, 0),所以它会照向原点。
我们还需要换Materail。基本的Material不受光线的影响。让我们把它改成MeshPhongMaterial,它会受到光线的影响。
再创建几个网格Mesh
它现在应该是比较清晰的3D视图了。为了好玩,我们再加两个方块。我们让每个立方体使用相同的几何图形,但制作不同的材质,因此每个立方体可以是不同的颜色。
首先,将创建一个函数,用指定的颜色创建一个新的Material,然后加上指定的Geometry,创建一个Mesh,并将其添加到场景中,并设置其在x轴上的位置。
function makeInstance(geometry, color, x) {
const material = new THREE.MeshPhongMaterial({
color
});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
cube.position.x = x;
return cube;
}
然后我们将使用三种不同的颜色和X轴位置调用三次函数, 将生成的Mesh实例存在一个数组中。
const cubes = [
makeInstance(geometry, 0x44aa88, 0),
makeInstance(geometry, 0x8844aa, -2),
makeInstance(geometry, 0xaa8844, 2),
];
最后在渲染函数中,旋转三个立方体。给每个立方体设置了稍微不同的旋转角度。
function render(time) {
time *= 0.001;
cubes.forEach((cube, ndx) => {
const speed = 1 + ndx * .1;
const rot = time * speed;
cube.rotation.x = rot;
cube.rotation.y = rot;
});
...
}
完整的demo代码
<canvas id="c"></canvas>
<script type="module">
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r115/build/three.module.js';
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({
canvas
});
const scene = new THREE.Scene();
{
const fov = 75;
const aspect = 2;
const near = 0.1;
const far = 5;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.z = 2;
}
{
const color = 0xFFFFFF;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(-1, 2, 4);
}
scene.add(light);
{
const boxWidth = 1;
const boxHeight = 1;
const boxDepth = 1;
const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
}
function makeInstance(geometry, color, x) {
const material = new THREE.MeshPhongMaterial({
color
});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
cube.position.x = x;
return cube;
}
const cubes = [
makeInstance(geometry, 0x44aa88, 0),
makeInstance(geometry, 0x8844aa, -2),
makeInstance(geometry, 0xaa8844, 2),
];
function render(time) {
time *= 0.001;
cubes.forEach((cube, ndx) => {
const speed = 1 + ndx * .1;
const rot = time * speed;
cube.rotation.x = rot;
cube.rotation.y = rot;
});
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
</script>
threejs 基础概要的更多相关文章
- TypeScript进阶开发——ThreeJs基础实例,从入坑到入门
前言 我们前面使用的是自己编写的ts,以及自己手动引入的jquery,由于第三方库采用的是直接引入js,没有d.ts声明文件,开发起来很累,所以一般情况下我们使用npm引入第三方的库,本文记录使用np ...
- Threejs基础学习【修改版】
一. Three.js官网及使用Three.js必备的三个条件 1.Three.js 官网 https://threejs.org/ 2.使用Three.js必备的三个条件(To actually b ...
- ThreeJs 基础入门
本文来自网易云社区 作者:唐钊 Three.js 是一款运行在浏览器中的 3D 引擎,你可以用它在 web 中创建各种三维场景,包括了摄影机.光影.材质等各种对象.使用它可以让我们更加直观的了解 we ...
- python学习笔记--基础概要
1.python的int类型没有大小限制(或者说只受机器内存限制),str类型用单引号或者双引号都行,只要对称就可以了.(注意固定性) 2.使用[]表示存取字符串等序列的某一项(索引从0开始) 3.类 ...
- AngularJS基础概要整理(下)
五.AngularJS Scope(作用域) Scope(作用域)是应用在HTML(视图)和JavaScript(控制器)之间的纽带. Scope是一个对象,有可用的方法和属性. Scope可应用在视 ...
- AngularJS安装配置与基础概要整理(上)
以前整理的,可供参考. 安装: 1.首先要安装node.js和它的npm包管理系统.(nodejs相关待整理) 2.安装grunt .grunt是一个基于任务的Javascript工程命令行构建工具. ...
- JSP基础概要
[版权申明:本文系作者原创,转载请注明出处] 文章出处:http://blog.csdn.net/sdksdk0/article/details/51925232 作者:朱培 ID:sdksdk0 一 ...
- 3 python之基础概要
一: 与用户交互 1 什么事与用户交互 程序等待用户输入一些数据,程序执行完毕之后为用户反馈信息 2 为什么程序要与用户交互 为了让计算机像人一样和用户沟通 3 如何用: 在python3中:inpu ...
- Vue框架基础概要
Vue.js是什么? Vue.js(读音 /vjuː/,类似于 view 的读音)是一套构建用户界面(user interface)的渐进式框架.与其他重量级框架不同的是,Vue 从根本上采用最小成本 ...
随机推荐
- 牛客练习赛70 B.拼凑 (序列自动机)
题意:有一个模板串,有\(T\)个字符串,从字符串中找到某个子串,使得这个子串中的子序列包含模板串,求最短的子串的长度. 题解:找子序列,很容易想到序列自动机,根据序列自动机的原理,我们一定可以确保除 ...
- DCL 数据控制语言
目录 授予权限(GRANT) 回收权限(REVOTE) 授予权限(GRANT) # 语法 mysql> help grant; Name: 'GRANT' Description: Syntax ...
- 数理统计10(习题篇):寻找UMVUE
利用L-S定理,充分完备统计量法是寻找UMVUE的最方便方法,不过实际运用时还需要一些小技巧,比如如何写出充分完备统计量.如何找到无偏估计.如何求条件期望,等等.课本上的例题几乎涵盖了所有这些技巧,我 ...
- python工业互联网应用实战6—任务分解
根据需求定义"任务"是一个完整的业务搬运流程,整个流程涉及到多个机构(设备)分别动作执行多个步骤,所以依据前面的模型设计,需要把任务分解到多个连续的子任务(作业),未来通过顺序串联 ...
- ++i和i++的区别
它们两个的数值变化的区别,我这里就不多说了 这里主要说明两者在效率上的区别 (1)首先如果是自带的数据类型,比如int型,++i和i++,编译器的实现方式是相同的,两者并没有效率上的区别,虽然也有副本 ...
- ZOJ 3494 BCD Code(AC自动机 + 数位DP)题解
题意:每位十进制数都能转化为4位二进制数,比如9是1001,127是 000100100111,现在问你,在L到R(R <= $10^{200}$)范围内,有多少数字的二进制表达式不包含模式串. ...
- console.clear
console.clear Chrome console.clear && console.clear() refs xgqfrms 2012-2020 www.cnblogs.com ...
- 前端 vs 后端
前端 vs 后端 前端与后端: 有什么区别? 前端和后端是计算机行业中最常用的两个术语. 在某种程度上,它们成了流行语. 它们决定了您作为软件开发人员所从事的工作类型,所使用的技术以及所获得的收入. ...
- js & input event & input change event
js & input event & input change event vue & search & input change <input @click=& ...
- Python算法_排序数组(09)
给你一个整数数组 nums,请你将该数组升序排列. 示例 1: 输入:nums = [5,2,3,1]输出:[1,2,3,5] 示例 2: 输入:nums = [5,1,1,2,0,0]输出:[0,0 ...