菜鸟也要学ThreeJs(一)

1,647 阅读5分钟

作为前端开发者,谁不喜欢这样的所见即所得的快乐呢?

构建场景 物理引擎 塑造模型

说起来酷炫,但是实际学起来实在是头大,WegGl的管道着色器基本上写起来和学一门新的语言一样,ThreeJs的话 教程又没那么多,实在是费力。

最近发现了国外大佬的课,分享一下自己的ThreeJs学习路程~

在文章中用到的代码 都会在附在附录上~

接下来就是干货时间:

首先建立HTML文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>03 - Basic Scene</title>
</head>
<body>
    <canvas class="webgl"></canvas>
    <script src="./three.min.js"></script>
    <script src="./script.js"></script>
</body>
</html>

JS文件

// // Canvas
// const canvas = document.querySelector('canvas.webgl')

// // Sizes
// const sizes = {
//     width: 800,
//     height: 600
// }

// // Scene
// const scene = new THREE.Scene()

// // Object
// const cubeGeometry = new THREE.BoxGeometry(1, 1, 1)
// const cubeMaterial = new THREE.MeshBasicMaterial({
//     color: '#ff0000'
// })
// const cubeMesh = new THREE.Mesh(cubeGeometry, cubeMaterial)
// scene.add(cubeMesh)

// // Camera
// const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height)
// camera.position.z = 3
// scene.add(camera)

// // Renderer
// const renderer = new THREE.WebGLRenderer({
//     canvas: canvas
// })
// renderer.setSize(sizes.width, sizes.height)
// renderer.render(scene, camera)


const scene = new THREE.Scene()

const geometry = new THREE.BoxGeometry(1,1,1)
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 })

const mesh = new THREE.Mesh(geometry,material)
scene.add(mesh)

const sizes = {
  width: 800,
  height: 600
}
const camera = new THREE.PerspectiveCamera(75,sizes.width/sizes.height)
camera.position.z = 3
scene.add(camera)

const canvas = document.querySelector('.webgl')

const render = new THREE.WebGLRenderer({
canvas:canvas
})

render.setSize(sizes.width,sizes.height)

render.render(scene,camera)

最后记得再去下载THREEJS文件 并且引入就可以啦!

Three Js 四大要素

1.包含一些对象的场景 Scene

2.一些对象 Object

3.摄像机 Camera

4.渲染器 Render

Scene

const scene = new THREE.Scene()

Object

创建对象,我们需要先创建一个Mesh

Mesh

一个Mesh 是几何(形状)和材料(外观)的组合。

那么我们创建Mesh 对应就需要先创建几何Geomotry ,以及材料Material

const geometry = new THREE.BoxGeometry(1, 1, 1)
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 })

小Tips:

颜色16进制表示 分别表示 R G B 即 红 绿 蓝 ,颜色深度分别从0 到 f

# ff0000

表示为红色

ff => 红色满格

00 => 不要绿色

00 => 不要蓝色

所以如上ff0000就表示纯红色了

创建好geometrymaterial就可以通过THREE.Mesh()来合并生成一个Mesh对象了。

const mesh = new THREE.Mesh(geometry,material)

添加对象

创建Mesh 之后 一定记得像Scen中进行添加,不然Camera是看不到它的

scene.add(mesh)

Camera

1.相机不可见

2.可以设置多个相机,但是render的时候 只能有一个

常规的 我们创建PerspectiveCamera透视相机,可以实现使近处的物体看起来比远处的物体更突出的效果。

设置相机需要像个参数

View 视角

视野是你的视角有多大。如果您使用非常大的角度,您将能够同时看到各个方向,但失真很大,因为结果将绘制在一个小矩形上。如果您使用小角度,则事物看起来会放大。视野(或 fov)以度数表示,对应于垂直视角。在本练习中,我们将使用 75 度角。

小视角:

image-20210608134351009

大视角:

image-20210608134417756

Size 纵横比

在大多数情况下,纵横比是画布的宽度除以其高度。我们暂时没有指定任何宽度或高度,但我们稍后需要。同时,我们将创建一个具有临时值的对象,我们可以重用它。

不要忘记将相机添加到场景中。一切都应该可以在不将相机添加到场景中的情况下工作,但稍后可能会导致错误

相机位置

一定记得设置camera的position 或者 rotation 或者scale

否则 摄像机会处于 整个物体的内部,无法看到任何东西

const camera = new THREE.PerspectiveCamera(75,sizes.width/sizes.height)
camera.position.z = 3
scene.add(camera)

Object

操作ThreeJS 中的 对象 可以帮助我们在后续实现一些动画的效果

之前我们试过position来移动camera的位置,达到不同的视角

后续 我们可以一共有 4 个属性可以转换场景中的对象

  • position (移动物体)

  • scale (调整对象大小)

  • rotation (旋转对象)

  • quaternion (类似旋转对象)

    注意我们改变object的位置,一定要在render.renderer 函数调用之前,否则就不会生效了。

Position

x 是向右的,y轴是向上的,z轴是向后的(forward to camera)

我们可以通过操作Mesh来 变换

因为Mesh 即成雨Object.3D 且 代表着一个具体的模块,即由形状和材质两部分组成。

mesh.position.x = 0.7
mesh.position.y = - 0.6
mesh.position.z = 1

//或者

mesh.position.set(0.7, - 0.6, 1)

Length

Position 设置后 是一个Vector3[3维向量],因此我们可以求的具体的值

mesh.position.length()

这样可以得到一个具体的向量的长度。

同时,如果我们对两个Vectore3 需要知道他们的距离,可以使用distanceTo函数

//当前mesh与相机向量的距离
mesh.position.distanceTo(camera.position)

//与向量(0,1,2)的距离
mesh.positon.distanceTo(new THREE.Vector3(0,1,2))

归一化【标准化】

相当于 将当前向量归一化为标准向量,只需要使用normalize函数即可。

mesh.position.distanceTo(camera.position)
//此时 mesh的length是1

辅助线

/**
 * Axes Helper
 */
const axesHelper = new THREE.AxesHelper(2)
scene.add(axesHelper)

AxesHelper的参数表示辅助线的长度

绿色 - y轴

红色 - x轴

蓝色 - z轴

默认情况下,Camera是对准z轴的,也就是如果我们不移动camera的x , y 那么会看到如下的画面

image-20210609233638336

Scale

按某个方向 缩放

mesh.scale.x = 2
mesh.scale.y = 0.25
mesh.scale.z = 0.5 

mesh.scale.set(2,0.5,0.5)

Rotation

1.旋转

旋转以当前的轴为中心 旋转度数

  • 如果你在 y 轴上旋转,你可以把它想象成一个旋转木马。
  • 如果你在 x 轴上旋转,你可以想象你正在旋转你将要乘坐的汽车的轮子。
  • 如果你在 z 轴上旋转,你可以想象你正在旋转你将要乘坐的飞机前面的螺旋桨。

默认2PI 为一个圆周

mesh.rotation.x = Math.PI * 0.25
mesh.rotation.y = Math.PI * 0.25

但是注意了,在普通的旋转中,无论我们在js中 rotation的顺序如何,都是按照 先x 再y 再z 进行旋转的,然而当我们执行x轴的旋转操作后,此时再执行y轴 就已经和初始的y轴不一致了,因此 我们需要通过加锁来进行设置

object.rotation.reorder('YXZ')
//1.此处XYZ为字符串 2.一定要大写

设置后即表示,按照 先y轴 再x轴 再z轴的顺讯进行旋转。

Look At

Camera.lookat(Vector3)表示 将摄像机指向目标的向量

camera.lookAt(new THREE.Vector3(0, - 1, 0))

即表示将摄像机指向 0 -1 0 的向量位置

当然,我们也可以使用camera.lookAt(mesh.position),此时我们的mesh就会出现在屏幕的正中央。

Group

需要对一个object进行多次变换操作的时候,我们可以通过创建一个group然后,直接移动group即可。