# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)

时间:2022-11-28 12:59:08

一篇文章了解 threejs 在 vue 项目中的基本使用

Three.js 是一个跨浏览器的脚本,使用 JavaScript 函数库或 API 来在网页浏览器中创建和展示动画的三维计算机图形。为啥突然想写这么一篇文章的主要原因其实是前几天有个人需要我帮忙写一个简单的 demo,花了几个小时之后觉得基本上 threejs 基本的使用效果都实现了,之前就看过 threejs 的东西,但是一直没有时间静下心来整理汇总一下,所以说呢,今天时间比较充足,就稍微的记录一下。当然了,我也没有深入的学习使用,学习的时间很短,所以说也谈不上经验的分享,就算是一个简单的学习记录吧,浅看则以,切勿尽信。

threejs 相关资料

其实相对来说 threejs 的学习成本比较高的,需要掌握的知识相对来说会稍微杂一些,但是简单的入门倒是很简单,现在网上的资料还是很多的,无论是博客还是视频都是比较充足的,然后接下来的博文内容,就简单的介绍一些在 vue2 项目中 threejs 的基本使用。

threejs 介绍

threejs 是运行在浏览器中的 3D 引擎,是JavaScript编写的WebGL第三方库。提供了非常多的3D显示功能。开发者可以用它创建各种三维场景,包括了摄影机、光影、材质等各种对象。可以在它的主页上看到许多精彩的演示。不过,这款引擎还处在比较不成熟的开发阶段,其不够丰富的 API 以及匮乏的文档增加了初学者的学习难度(尤其是文档的匮乏)。

前言

在讲解 threejs 的时候,我们通过一个基本的简单的案例,来实现一个小的效果,然后把常用的 API、工具、功能稍微说一下哈!

这个案例我是使用 vue2 + 脚手架工具创建的项目,采用 javascript 开发。再次之前需要先准备一个 vue 的空项目,好在我们不需要使用网络请求,直接默认创建一个 vue2 的项目即可,不需要过多的配置。

安装 threejs

安装 threejs 的方式也很简单,直接使用 npm 工具就可以安装到项目里面使用:

npm install --save three

在终端输入命令然后回车等待执行完成就可以了!

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)

安装完成之后,就可以看到 package.json 文件中已经包含了我们刚刚安装的 three 依赖。

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)


同时,在 node_modules 文件夹下,也出现了 three 相关的包依赖。

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)

这样,我们就成功将 threejs 相关的依赖添加到我们的项目,就可以继续进行后续 threejs 相关功能的开发了。

初始化项目

这个步骤就不多说了,直接使用 cli3 以上的版本创建一个 vue2 的项目,然年修改一下组件内容,创建一个 div 标签铺满整个浏览器页面就可以了。

<template>
<div class="three-canvas" ref="threeTarget"></div>
</template>

<script>
export default {
name: 'HelloWorld',
}
</script>

<style scoped>
.three-canvas {
width: 100%;
height: 100%;
overflow: hidden;
background-color: #d6eaff;
}
</style>

大体效果就是下面的样子,当然了这个无所谓了。

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)

然后我们在这个组件中实现 threejs 效果,效果呢,挂载到我们创建的 ​​<div class="three-canvas" ref="threeTarget"></div>​​ 标签上面渲染。

为了保证项目代码稍微的有点规范性,我们创建一个 ​​TEngine.js​​​ 文件,在当前组件引入,然后呢,所有与 threejs 初始化、操作等代码都是 ​​TEngine.js​​ 文件中实现。

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)

创建渲染器 WebGLRenderer

接下来我们在 TEngine.js 文件中初始化一个 threejs ,首先第一步,我们需要有一个 dom 挂载我们创建的 threejs ,啥叫挂载呢,简单点说就是我创建的 3D 模型显示在哪里,我们之前初始化项目不是创建一个全屏的 div 吗?然后我们就把 3D 模型放在这个 div 上面显示。

第一步,我们现在 TEngine.js 中创建并交出一个 ThreeEngine 类,然后这个类,在组件中实例化就可以了,前面说了,需要一个 dom 节点挂载模型,那么我们首先得接收一个 dom 节点吧?所以说在构造器函数里面获取到传入的 dom 节点,然后挂载。

export class ThreeEngine {
dom = null; // 挂载的 DOM
// 构造器函数
constructor(dom) {
this.dom = dom
}
}

然后我们就可以在组件中实例化这个类了。注意,需要在 mounted 生命周期钩子中实例化吧?不能在 created 生命周期钩子中,为啥,因为 mounted 才是 dom 都渲染完成吧,好:

<script>
import { ThreeEngine } from './js/TEngine'
export default {
name: 'HelloWorld',
data() {
return {
ThreeEngine: null,
};
},
mounted() {
this.ThreeEngine = new ThreeEngine(this.$refs.threeTarget)
}
}
</script>

OK,这样子第一步就完成了,但是呢页面没效果,因为我们刚刚开始,完全没有任何的 threejs 的操作。

接下来,就是 threejs 相关的操作了哈,都在 ThreeEngine 类的构造器函数中实现。

【引导】首先你想,我们想在一个 div 上面展示 3D 模型的东西,是不是首先得有一个东西把这个 3D 模型转换成我们浏览器可以展示的画面放在我们传递进来 div 上展示啊,这个帮助我们把 模型 展示到 div 上的东西就可以简单的理解成​​渲染器​​。举一个例子:老师说我们准备换一个新教室,老师想看一下新教室的布局,但是自己有事过不去,怎么办?找个同学小明帮忙过去看一下就可以了吧,怎么让老师亲眼看到?对,视频通话,小明拿手机拍摄,然后老师在手机上就可以看到这个新教室的布局了吧,那这个小明就是渲染器。所以第一步,找一个小明。

老师的渲染器是小明,而 threejs 的渲染器就是 WebGLRenderer。WebGLRenderer是 three 中提供的一个工具类,我们在使用之前需要先引入他,使用也很简单。

import { WebGLRenderer } from 'three'

首先创建一个渲染器:

let renderer = new WebGLRenderer()  // 创建渲染器

创建完成之后,我们需要把这个渲染器挂载到 dom 上面,这样,渲染器渲染的效果就可以展示在 div 上面,就是学生和老师打视频电话,才可以让老师在自己的手机看到新教室布局。

dom.appendChild(renderer.domElement)  // 将渲染器挂载到dom

问题来了,我们告诉渲染器说:你把 threejs 的效果展示在 div 上面。可以渲染器有点蒙蔽还,就是我要渲染多大啊?这个 div 有高宽,我是渲染在这个 div 的那个部分呢?所以说还需要设置一下渲染器的大小吧?我们一般设置的和 dom 节点一样大小就可以。

renderer.setSize(dom.offsetWidth, dom.offsetHeight, true)

这样我们的渲染器初始化的全部代码就完成了!

import { WebGLRenderer } from 'three'

export class ThreeEngine {

dom = null; // 挂载的 DOM

constructor(dom) {

// 创建渲染器
let renderer = new WebGLRenderer({
antialias: true, // 开启抗锯齿
})
dom.appendChild(renderer.domElement) // 将渲染器挂载到dom
renderer.setSize(dom.offsetWidth, dom.offsetHeight, true)

this.dom = dom
}

}

我们看一下页面效果。

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)

非常好,和没有初始化之前一模一样,为啥。

【引导】还是老师想看新教室,渲染器小明有了,但是小明拿手机拍啥啊?新教室对吧?但是我们只是找到了小明,交代给小明说你去渲染给我看,但是并没有告诉小明去看啥,这里让小明看的东西叫做​​场景​​,我们需要告诉小明看什么场景才可以。所以说下一步,找一个场景。

创建场景 Scene

threejs 中的场景是 Scene,同样这个也是 threejs 提供的工具类,使用的话也需要引入,创建一样简单。

import { WebGLRenderer, Scene } from 'three'

创建场景直接 new 就可以。

let scene = new Scene()  // 实例化场景
this.scene = scene

就这两行代码初始完场景了,然后到此为止,所有的代码就是下面这样的。

import { WebGLRenderer, Scene } from 'three'
export class ThreeEngine {
dom = null; // 挂载的 DOM
scene = null; // 场景
constructor(dom) {
// 创建渲染器
let renderer = new WebGLRenderer({
antialias: true, // 开启抗锯齿
})
dom.appendChild(renderer.domElement) // 将渲染器挂载到dom
renderer.setSize(dom.offsetWidth, dom.offsetHeight, true)
let scene = new Scene() // 实例化场景
this.dom = dom
this.scene = scene
}
}

我们看一下效果:

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)

我勒个去!还是怎么东西没有,我之前一模一样。这又是为啥!

【引导】还是老师让小明看新教室,渲染器小明有了,场景也有了。但是小明拿着手机懵了,为啥懵了,小明到了新教室,他不知道怎么给老师看新教室,我们想法是啥,小明拿手机打视频给老师看,但是小明不知道啊!我们得给小明一个有摄像机的手机才可以。继续,小明有相机了,但是小明比较笨,他不知道从那个角度拍给老师看(尽管小明笨,但不许换掉小明),所以说我们还得告诉小明拍摄的位置,也就是说从哪个角度拍摄吧。

创建相机并设置位置 PerspectiveCamera

threejs 中的相机是 PerspectiveCamera,他同样是 three 提供的工具类,我们需要引入,然后在实例化。

import { WebGLRenderer, Scene, PerspectiveCamera } from 'three'

怎么创建相机有几个步骤,首先实例化一个相机;然后需要设置相机的位置,就是从哪里拍;再然后设置相机拍摄的位置,就是拍具体哪里;最后可以设置相机角度,就是歪着拍还是竖着拍;

首先是初始化相机

// 实例化相机
let camera = new PerspectiveCamera(45, dom.offsetWidth / dom.offsetHeight, 1, 1000)

这里传了几个参数,分别是啥意思稍微说一下。

  • 第一个参数 ​​45​​ 是 摄像机视锥体垂直视野角度,人眼看东西就差不多60度左右嘛,不可能看到头后面的东西,这里也是这个意思,一般就设置 45。
  • 第二个参数 ​​dom.offsetWidth / dom.offsetHeight​​ 是摄像机视锥体长宽比,我们就设置是我们 div 容器的长宽比就可以,如果不这样设置,可能会变形。因为我们看到的要和相机看到的一样大小,不然会被拉伸。
  • 第三个参数 ​​1​​ 是摄像机视锥体近端面
  • 第四个参数 ​​1000​​ 摄像机视锥体远端面

然后是设置相机位置,就是相机都放在哪里。

camera.position.set(50, 50, 50) // 设置相机位置

我们把相机放在 three 坐标 50 50 50 的位置。

然后是设置相机看向哪里,这里我们让相机看向原点。

camera.lookAt(new Vector3(0, 0, 0))  // 设置相机看先中心点

我们还可以设置相机自身的方向。

camera.up = new Vector3(0, 1, 0)  // 设置相机自身的方向

这里我们稍微补充一点知识点,因为没有图形学基础的话可能不好理解,首先说一点,threejs 坐标系是向右为 x 轴正方向,垂直屏幕向外为 z 轴的正方向,向上为 y 轴正方向。

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)


所以说设置相机的位置和看向原点就理解了哈,然后渲染器默认加载完成后他的中心就是(0,0,0)原点,分别对应 (x,y,z)。


camera.up 是用来设置相机自身的方向设置 y = 1 表示 y 轴的正方向为相机向上的方向,可能没说明白,就是相机向上移动就是向 three 坐标系 y 轴的正方向移动。

到这里,我们初始化相机的部分就完成了,然后我们到此位置所有代码:

import { WebGLRenderer, Scene, PerspectiveCamera, Vector3 } from 'three'
export class ThreeEngine {
dom = null; // 挂载的 DOM
scene = null; // 场景
constructor(dom) {
// 创建渲染器
let renderer = new WebGLRenderer({
antialias: true, // 开启抗锯齿
})
dom.appendChild(renderer.domElement) // 将渲染器挂载到dom
renderer.setSize(dom.offsetWidth, dom.offsetHeight, true)
let scene = new Scene() // 实例化场景
// 实例化相机
let camera = new PerspectiveCamera(45, dom.offsetWidth / dom.offsetHeight, 1, 1000)
camera.position.set(50, 50, 50) // 设置相机位置
camera.lookAt(new Vector3(0, 0, 0)) // 设置相机看先中心点
camera.up = new Vector3(0, 1, 0) // 设置相机自身方向
this.dom = dom
this.scene = scene
}
}

然后我们保存代码,看一下页面效果。

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)

非常好,还是那个样子,啥都没有。

为啥呢?再来引导一波!

【引导】我们初始化了渲染器,找到小明了;初始化了场景,让小明去了新教室;相机准备好了,小明掏出手机对准了目标。但是没有视频啊!老师啥也看不到。所以我们接下来需要把这个相机和场景绑定到渲染器里面。

绑定很简单,只需要在初始化相机之后呢,把场景和相机绑进渲染器,让渲染器渲染就可以了:

renderer.render(scene, camera)  // 渲染器渲染场景和相机

OK,现在在看一下效果。

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)


全部变黑了是吧?这就是成功了,为啥是黑的呢,因为现在这个场景没有东西,如果有东西的话就可以展示出来了吧。

添加模型 Mesh

现在我们创建一个立方体放进场景里面去,我们就可以看到一个模型了吧?好的,现在开始!

为了保证我们项目代码的结构,我们创建一个 TBaseObject.js 文件,用来存放基础的模型,然后这个文件中我们创建一个立方体模型,并返回出来。

我们就简单点,先声明一个数组抛出,然后数组里面是创建的模型,这样外面使用这个文件的时候,导入就可以获取模型的列表了。

export const allBaseObject = []  // 返回所有基础模型

然后创建一个立方体模型,当然也可以抛出去,也可以往数组里面添加一下,这样的话我们既可以单独使用这个立方体,也可以获取全部模型。

创建一个简单的立方体很简单,Mesh 是 three 提供的基于以三角形为polygon mesh(多边形网格)的物体的类,我们可以通过他创建一个立方体。

// 创建立方体
export const box = new Mesh(
new BoxGeometry(20, 20, 20), // 设置立方体的大小 (x 长度, y 高度 ,z 长度)
new MeshStandardMaterial({ // 设置材质
color: 'rgb(36, 172, 242)', // 设置材质的颜色
})
)

allBaseObject.push(stage) // 添加到模型数组

小地方说一下哈,设置模型大小肯定需要的,这个模型多宽、多高、多长。那材质是啥意思,就是我们这个立方体的样式,比如颜色,光泽等属性,当然如果是实际模型可能还有贴图之类的。简单理解就是什么样子的。

当然,中间使用的类也需要引入一下。

import { BoxGeometry, Mesh, MeshStandardMaterial } from "three"

好,创建完成做一个事情,就是我们需要在 three 中把这个立方体添加进三维场景中,我们在 TEngine.js 文件中创建一个方法,用来向场景中添加模型。

/**
* 向场景中添加模型
* @param {...any} object 模型列表
*/
addObject(...object) {
object.forEach(elem => {
this.scene.add(elem) // 场景添加模型
})
}

然后我们在组件中把获取模型列表,然后呢,把模型添加到场景中。

import { allBaseObject } from './js/TBaseObject'

再 threejs 初始化完成后,调用我们写的方法,把模型列表添加到场景。

this.ThreeEngine.addObject(...allBaseObject)  // 添加基础模型

代码我最后会全部提交到 gitee,到时候如果需要可以看一下。

这样我们在看一下效果:

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)


哇偶,还是黑色的。为啥呢,在引导一波!

【引导】小明开视频了,但是老师眼前一黑,为啥?没开灯呗!其实 threejs 还是很真实的,他里面集成了光线的设置,如果没有光线,就和实际生活一样,完全就是漆黑的一篇,真棒!那么接下来,我们给场景添加一个“自然光”。

光线添加

嗯,现实生活中光线有很多了,比如说房间一盏灯,点亮之后就是一个点光源向四周发散光,在比如聚光,各大晚会的聚光灯照在一个人身上这种。threejs 中也存在这种光源,我们先编写一个最简单的光线,叫 “自然光”。

注意一点,我们创建的很多东西如果想展示出来都需要添加到场景才可以,比如我们创建的立方体、现在要创建的自然光,以及后边说的光线辅助啥的都需要添加进场景才可以看到,那么我们写这个光线的时候和立方体一样,创建一个 TLights.js 文件,把光源创建出来,然后引入到组件然后添加进场景进行展示。

创建光线其实很简单:

import { AmbientLight } from "three"


/**
* 光线
*/
export const allLights = []

// 添加环境光(自然光),设置自然光的颜色,设置自然光的强度(0 最暗, 1 最强)
export const ambientLight = new AmbientLight('rgb(255,255,255)', 0.8)

allLights.push(ambientLight)

threejs 中的自然光是 AmbientLight ,使用之前需要引入,引入完成实例化的时候需要传递两个参数:

  • 第一个参数是光线的颜色。
  • 第二个参数是光线的强度。0最暗,1最亮。

然后我们同样也是在 组件 中引入光线,然后将光线添加到场景。

this.ThreeEngine.addObject(...allLights)  // 添加光线

这样,光线就被我们添加到场景了,我们再来看一下效果。

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)


啊? 还是黑色的!这又是怎么回事啊!!!!!

【说明】我们知道,页面是有刷新率的,比如 60hz 表示屏幕一秒钟渲染60个页面,我们的眼睛有延时,页面切换的太快,所以说我们看到的就是一个视频效果,但是 threejs 的渲染器,在初始化渲染器完成之后就只渲染了一次就不管了,所以说后边我们再修改场景修改模型的时候,并没有给我们渲染,所以说我们需要自己写代码然他渲染,怎么写呢,官网其实说的也很明白,一段代码加上就 OK 了。

接下来,我们在 构造器函数 最后加上这段代码,threejs 就会一直帮我们逐帧渲染页面效果。

// 逐帧渲染threejs
let animate = () => {
renderer.render(scene, camera) // 渲染器渲染场景和相机
requestAnimationFrame(animate);
}
animate()

我们现在再来看效果:

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)

终于,我们的立方体加载出来了。如果我们不设置正方体的位置,默认模型初始化加载在原点位置。

我们看到渲染器背景是黑色的,这是因为我们没有设置,他默认就是黑色的,我们可以给渲染器设置其他的颜色,在渲染器绑定完相机和场景之后:

renderer.setClearColor('rgb(239, 70, 1)')  // 设置渲染器的颜色

他就可以被设置成我们想设置的任意颜色。

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)


好了,这就是最基本的使用。

轨道控制器 OrbitControls

上面我们说完了基本的初始化渲染器、相机、场景、添加模型、设置光线之后,我们发现一个问题啊,就是这个页面是静态的,我们之前看百度地图或者是其他 cesium 创建场景之后,鼠标可以拖动,放大缩小,但是现在我们编写的案例还不可以,接下来我们实现这个功能。

要想实现鼠标操控,需要使用 threejs 的另一个工具类,那就是 OrbitControls,它叫做轨道控制器。

怎么使用呢?首先需要引入进项目,主要,这个工具类不是 three 中提供的,而是在它提供的案例里面,我们需要单独引入。

import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

引入完成,需要初始化轨道控制器。

let orbitControls = new OrbitControls(camera, renderer.domElement)

OK,初始化完成再去看效果,我们的案例就可以鼠标旋转缩放了。

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)


这就是 轨道控制器 的基本使用。使用方式也很简单:

  • 鼠标左键按下拖拽:围绕视图中心点旋转。
  • 鼠标中键滚动:缩小放大,实际是相机靠近和远离。
  • 鼠标右键按下拖拽:移动场景。

【拓展】

再稍微拓展一个轨道控制器的地方,就是我们的轨道控制器鼠标按键功能,是可以设置的,因为我们后面可能介绍鼠标点击事件,所以说鼠标左键按下事件可能有冲突,所以说我们重新设置一下,中键功能不变,旋转改为右键操作,左键什么功能都没有。

let orbitControls = new OrbitControls(camera, renderer.domElement)
orbitControls.mouseButtons = { // 设置鼠标功能键(轨道控制器)
LEFT: null, // 左键无功能
MIDDLE: MOUSE.DOLLY, // 中键缩放
RIGHT: MOUSE.ROTATE // 右键旋转
}

里面使用了 MOUSE,这是 three 提供的,我们得引入一下:

import { WebGLRenderer, Scene, PerspectiveCamera, Vector3, MOUSE } from 'three'

这样设置之后,我们鼠标按键的功能就发生了变化,可以试一下。

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)


OK,发现鼠标功能确实实现了。但是有没有发现一个很大的问题啊?就是根本看不出立方体的感觉来,你说他是立方体,我还就说他是一个多边形不停的变换呢!

确实是这样哈!正经的立方体他是有轮廓显示的,类似于下面:

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)

但是现在没有为啥。稍微解释一下,为了看见这个立方体,我们使用了环境光,环境光有一个特点,啥特点呢,就是说,他在模型的每一个面上光照强度都是一样的,不会衰减,所以说我们看到的模型,他每个面放光是一样的,根本看不出立体感。如果想要立体感怎么办?很简单哈,换一种光线,不使用环境光了,我们使用一个点光源,从一个点射出一束光向四周扩散,这样的话,照在模型上,因为距离不一样,光照强度就不一样,立体感就出来了。

添加点光源 PointLight

我们之前在 TLights.js 文件创建了一个环境光,现在我们再创建一个点光源 PointLight,添加到场景中去。因为之前封装好了,我们只需要创建完点光源,然后把点光源放进光源数组就可以了吧。

创建点光源使用的是 PointLight,这个工具类同样是 three 中提供的,我们需要引入一下子。

import { AmbientLight, PointLight } from "three"

然后就是创建点光源,创建点光源和创建环境光有点不一样,因为他就像一个灯泡,需要有颜色、强度、能照射多远、光照衰减值,最后还有位置:

// 点光源
export const pointLight = new PointLight(
'rgb(255,255,255)',
0.5,
600,
0.2
)
pointLight.position.set(0, 100, 200) // 设置点光源位置 (x,y,z)

allLights.push(pointLight) // 将点光源添加到光源列表抛出

PointLight 有四个参数:

  • color - (可选参数)) 十六进制光照颜色。默认 0xffffff (白色)。
  • intensity - (可选参数) 光照强度。 缺省值 1。
  • distance - 这个距离表示从光源到光照强度为0的位置。 当设置为0时,光永远不会消失,默认0。
  • decay - 沿着光照距离的衰退量。默认 1。

OK,现在我们再来看一下添加完点光源之后,模型效果:

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)


非常好,模型的立体感已经出来了。

模型部分拓展

我们既然说完了光线,其实还有很多中光线,可以去官网查看相关使用。

接下来我们稍微拓展一点儿东西哈,就是我们之前创建模型是使用的下面的代码:

// 创建立方体
export const box = new Mesh(
new BoxGeometry(20, 20, 20), // 设置立方体的大小
new MeshStandardMaterial({ // 设置材质
color: 'rgb(36, 172, 242)', // 设置材质的颜色
})
)

我们可以向这个模型添加数据的,比如我们设置个 name,我这个立方体叫做 “box” 可以吧。只需要这样写就可以配置他的 name 属性。

export const box = new Mesh(
new BoxGeometry(20, 20, 20), // 设置立方体的大小
new MeshStandardMaterial({ // 设置材质
color: 'rgb(36, 172, 242)', // 设置材质的颜色
})
)
box.name = 'box'

除了 name 之外还可以设置他的位置。

box.position.set(5, 5, 5)  // 设置模型位置 (x,y,z)

当然,位置信息也可以单独设置。

box.position.x = 5
box.position.y = 5
box.position.z = 5

单独设置每个坐标轴的位置也是可以的。

在实际开发的时候,比如我们有一个模型,我们需要给这个模型绑定一些数据,点击弹窗显示或者是鼠标悬浮显示的时候获取到这些数据,怎么绑定数据呢?其实我们可以直接设置,比如:

box.sheshimoxingshuju = {
name: 'box',
user: '我是ed.'
}

当然,threejs 提供了一个参数 ​​userData​​ 用来存放用户数据,建议放到那里面,默认我们都放到 uerData 里面,这样是为了以后多人开发,不至于每个人创建一个属性最后乱套了都。

export const box = new Mesh(
new BoxGeometry(20, 20, 20), // 设置立方体的大小
new MeshStandardMaterial({ // 设置材质
color: 'rgb(36, 172, 242)', // 设置材质的颜色
})
)
box.name = 'box' // 设置模型 name
box.position.set(5, 5, 5) // 设置模型位置
box.position.x = 5
box.position.y = 5
box.position.z = 5


box.sheshimoxingshuju = {
name: 'box',
user: '我是ed.'
}

box.userData = {
name: '我是ed.'
}

怎么确定我们都设置成功了?我们打印一下就可以了。

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)

我们直接打印一下 box 就可以看到我们配置的都是生效了的,都存进去了的。为啥突然想说这个,主要是想说一下 name 设置的,因为后边可能要根据模型的 name 从场景中获取模型,所以说一下模型的 name 怎么设置。我们去掉测试多余的代码哈。

然后再说一下模型的材质问题

还是这段代码:

export const box = new Mesh(
new BoxGeometry(20, 20, 20), // 设置立方体的大小
new MeshStandardMaterial({ // 设置材质
color: 'rgb(36, 172, 242)', // 设置材质的颜色
})
)

关于材质,我们只设置了一个颜色对吧!页面效果也显示出来了,然后是蓝色的很精致的小盒子,他除了颜色还可以设置其他的属性,比如:粗糙度 roughness

roughness 粗糙度是啥意思,就比如说我们生活里面,木头的粗糙度就很高,玻璃的粗糙度就很低。

roughness 上怎么提现粗糙度呢,roughness 的取值范围是 0 到 1。当 roughness 为 0 时,表示粗糙度最低,就越光滑;当 roughness 为 1 时,表示粗糙度最高,越粗糙。

比如我们给这个正方体设置一个粗糙度为 0 ,也就是最光滑。

export const box = new Mesh(
new BoxGeometry(20, 20, 20), // 设置立方体的大小
new MeshStandardMaterial({ // 设置材质
color: 'rgb(36, 172, 242)', // 设置材质的颜色\
roughness: 0 // 粗糙度(0 最光滑,1 最粗糙)
})
)

我们怎么看效果,这也是为啥我在这里说粗糙度而不是在添加模型说的原因,我们在场景添加了一个点光源,可以理解成就是一个灯吧!如果一个物体,他表面光滑到一个程度之后他会反光的!我就把正方体的粗糙度调到最低,也就是最光滑的时候,他肯定会反光吧,那我们调节模型,看他有没有反光的时候。看效果:

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)


找到反光的点了,是吧!但是如果我们粗糙度调到最高,是绝对不可能反光的,这里我们就不看了,有兴趣的可以自己看一下。

除了粗糙度,在说一个吧,就是 金属度 metalness

我们在生活中见过铁吧!见过不锈钢吧!见过铝合金吧!那种金属质感很酷吧?就算是相同的颜色,塑料和金属你一眼就分个大概吧!

metalness 就是用来设置模型金属质感的,他的取值也是从 0 到 1,当 metalness 为 0 表示金属质感最少,最不像金属;metalness 为 1 表示金属质感最强,最像金属。

我们在给模型添加一个金属质感。

export const box = new Mesh(
new BoxGeometry(20, 20, 20), // 设置立方体的大小
new MeshStandardMaterial({ // 设置材质
color: 'rgb(36, 172, 242)', // 设置材质的颜色
metalness: 0.5, // 金属度 (1 最像金属,0 最不想金属)
roughness: 0 // 粗糙度(0 最光滑,1 最粗糙)
})
)

我这里金属质感设置的 0.5,为啥,现实生活中有没有一个感觉,就是一个金属块,表面越光滑,金属感越强,他的颜色就越暗,暗的发黑。

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)

看,我设置完金属度之后,模型不如之前亮了,但是没有看出金属质感啊?别急,我移动一下,照样让他返回看一下,金属质感立马就出来了。

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)


怎么样!厉害吧!啊哈哈哈哈!

好了,关于这个小的拓展部分就到这里吧!完成!

添加辅助线

这一部分说一些辅助工具,我们添加模型啥的,包括模型的定位,都是凭感觉,不知道各个轴的方向,也不知道原点位置,所以说能不能让原点位置和坐标轴可视化?

答案是肯定的, threejs 为我们提供了辅助线,用来可是画坐标轴。接下来就实现一下坐标轴的可视化操作。

首先我们还是和模型、光线一样,创建一个辅助文件 THelper.js ,在这个 js 文件中创建辅助线,然后抛出,在组件中接受,最后添加在场景里面,我们就可以看到坐标轴辅助线了。

首先坐标轴辅助线是 AxesHelper,这个工具类是 three 提供的,所以说我们需要单独引入一下。

import { AxesHelper } from 'three'

引入完成就可以使用来了。接下来创建辅助:

import { AxesHelper, GridHelper } from 'three'

export const allHelper = []

// 坐标辅助
export const axesHelper = new AxesHelper(500) // 创建坐标辅助 (500 为辅助线的长度)

allHelper.push(axesHelper) // 添加到辅助列表

还是,在组件中引入,然后就可以添加到场景里面去了。

import { allHelper } from './js/THelper'

添加到场景:

this.ThreeEngine.addObject(...allHelper)   // 添加辅助

这样辅助线就添加到场景中去了,我们可以看一下效果。

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)

这里的 红色线就是 x 轴,蓝色线就是 z 轴,绿色线就是 z 轴。

除了坐标辅助线,我们还可以添加地面网格线 GridHelper

import { AxesHelper, GridHelper } from 'three'

export const allHelper = []

// 坐标辅助
export const axesHelper = new AxesHelper(500) // 创建坐标辅助

// 创建地面网格辅助
export const gridHelper = new GridHelper(100, 10, 'red', 'rgb(222, 225, 230)')

allHelper.push(axesHelper, gridHelper)

网格辅助线一共需要配置四个参数:

  • size -- 坐标格尺寸. 默认为 10. 这就是网格组成的大正方形最大是多少
  • divisions -- 坐标格细分次数. 默认为 10. 组成的最大的正方向平均分多少份
  • colorCenterLine -- 中线颜色. 值可以为 Color 类型, 16进制 和 CSS 颜色名. 默认为 0x444444。这个是指网格和坐标的 x轴 z 轴重合线的颜色。
  • colorGrid -- 坐标格网格线颜色. 值可以为 Color 类型, 16进制 和 CSS 颜色名. 默认为 0x888888

我们看一下效果:

# 一篇文章了解 threejs 在 vue 项目中的基本使用(未完结)


这样,地面网格线也出来了。

【版权声明】本博文著作权归作者所有,任何形式的转载都请联系作者获取授权并注明出处!
【重要说明】博文仅作为本人的学习记录,论点和观点仅代表个人而不代表技术的真理,目的是自我学习和有幸成为可以向他人分享的经验,因此有错误会虚心接受改正,但不代表此刻博文无误! 【Gitee地址】我是????????. :​​https://gitee.com/wjw1014​