vue create my-project // my-project是项目名称
npm install three --force
我是先给盒子一个固定的宽高和边框,看的时候比较方便,
<template>
<div ref="container" id="container"></div>
</template>
<script>
export default {
name: 'ThreeJs',
data() {
return {};
},
};
</script>
<style scoped>
#container {
width: 400px;
height: 400px;
border: 1px solid red;
}
</style>
在Base.js中创建一个类,并且在构造器中获取传入的dom,然后挂载到Vue上,这段代码写在Base.js中
export class ThreeBox {
dom = null; // 挂载的 DOM
// 构造器函数
constructor(dom) {
// 挂载
this.dom = dom
}
}
<script>
import { ThreeBox } from './js/Base';
export default {
name: 'ThreeJs',
data() {
return {
ThreeBox: null,
};
},
mounted() {
this.ThreeBox = new ThreeBox(this.$refs.container);
},
};
</script>```
import { WebGLRenderer } from 'three'
在构造函数里面创建
import { WebGLRenderer } from 'three'
dom.appendChild(renderer.domElement)
设置的和 dom 节点一样大小一样就可以
renderer.setSize(dom.offsetWidth, dom.offsetHeight, true)
因为之前已经引入了渲染器的工具类,直接在后面加场景工具类就可以
import { WebGLRenderer,Scene } from 'three'
let scene = new Scene() // 实例化场景
this.scene = scene
到目前为止,Base.js里面的全部代码如下:
import { WebGLRenderer,Scene } from 'three'
export class ThreeBox {
dom = null; // 挂载的 DOM
// 构造器函数
constructor(dom) {
// 挂载
// 创建渲染器
let renderer = new WebGLRenderer({
antialias: true, // 开启抗锯齿
})
renderer.setSize(dom.offsetWidth, dom.offsetHeight, true)
dom.appendChild(renderer.domElement) // 将渲染器挂载到dom
let scene = new Scene() // 实例化场景
this.scene = scene
this.dom = dom
}
}
import { WebGLRenderer,Scene,PerspectiveCamera,Vector3 } from 'three'
let camera = new PerspectiveCamera(45, dom.offsetWidth / dom.offsetHeight, 1, 1000)
简单介绍一些四个参数是什么意思
1、视野角度(FOV)-视野角度是无论在什么时候,在显示器上所能看到的场景 的范围,单位是角度(与弧度区分开)
2、长宽比(aspect ratio)-用一个物体的宽除以它的高所得来的值
3、近截面(near)-当物体某些部分比摄像机的远截面远或者比近截面近的时候,该这些部分将不会被渲染到场景中
4、远截面(far)-当物体某些部分比摄像机的远截面远或者比近截面近的时候,该这些部分将不会被渲染到场景中
camera.position.set(50, 50, 50) // 设置相机位置
camera.lookAt(new Vector3(0, 0, 0)) // 设置相机看先中心点
camera.up = new Vector3(0, 1, 0) // 设置相机自身的方向
补充个小知识:
renderer.render(scene, camera) // 渲染器渲染场景和相机
到此刻,场景是黑色的,因为场景没有东西
避免Base.js文件中代码可读性强,所以我们新建一个js文件,用来存放基础模型,我这里创建的是Modal.js
BoxGeometry:几何体,
Mesh:网格
MeshStandardMaterial :材质
import { BoxGeometry, Mesh, MeshStandardMaterial } from "three"
创建模型数组的目的是,后期使用的时候,可以获取到全部的模型,比如立方体球体等,后期添加的模型添加到这个数组中去的时候,组件中可以一次性获取到所有的模型
export const allModal = [] //抛出所有基础模型
可以使用抛出的方式,也可以添加到模型数组中去,单独抛出的话组件可以单独使用这一个立方体模型
// 创建立方体
export const box = new Mesh(
new BoxGeometry(20, 20, 20), // 设置立方体的大小 (x 长度, y 高度 ,z 长度)
new MeshStandardMaterial({ // 设置材质
color: 'rgb(36, 172, 242)', // 设置材质的颜色
})
)
allModal.push(box) // 添加到模型数组
注意:写在构造函数外面
/**
* 向场景中添加模型
* @param {...any} moadl 模型列表
*/
addModal(...moadl) {
moadl.forEach(elem => {
this.scene.add(elem) // 场景添加模型
})
}
在组件ThreeJs中,引入和调用
import { allModal } from './js/Modal';
this.ThreeBox.addModal(...allModal);
因为光线也有多种,方便Base.js代码的可读性,将添加光线的代码单独使用一个JS编写,我这里新建了一个Light.js文件来编写
import { AmbientLight } from "three"
这里和模型数组一样,光线有多种,其他组件引用的时候可以引用全部光线
export const allLights = []
设置自然光的颜色,强度等
export const ambientLight = new AmbientLight('rgb(255,255,255)', 0.8)
// 同时添加到光线数组中去
allLights.push(ambientLight)
// 两个参数第一个为光线的颜色,第二个为光线的强度
在ThreeJs组件中,引入并添加光线
import {allLights} from './js/Light'
this.ThreeBox.addModal(...allLights);
threejs 的渲染器,初始化渲染器完成之后就只渲染了一次就不管了,所以后边我们再修改场景修改模型的时候,并没有给我们渲染,需要添加一段渲染代码,threejs 就会一直帮我们逐帧渲染页面效果,这段代码加在构造器的最后面
let animate = () => {
renderer.render(scene, camera) // 渲染器渲染场景和相机
requestAnimationFrame(animate);
}
animate()
这里发一下构造器,避免写露或者写错地方
constructor(dom) {
// 挂载
// 创建渲染器
let renderer = new WebGLRenderer({
antialias: true, // 开启抗锯齿
})
renderer.setSize(dom.offsetWidth, dom.offsetHeight, true)
dom.appendChild(renderer.domElement) // 将渲染器挂载到dom
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) // 设置相机自身的方向
renderer.render(scene, camera) // 渲染器渲染场景和相机
this.scene = scene
this.dom = dom
let animate = () => {
renderer.render(scene, camera) // 渲染器渲染场景和相机
requestAnimationFrame(animate);
}
animate()
}
写到这里效果可以就可以看到了,能看到背景为黑色,因为没有设置,默认就是黑色的,
我们可以给他设置其他的颜色
renderer.setClearColor('rgb(253, 218, 1)')
这个时候可以看到页面是静止的,鼠标无法进行操作,如果想要鼠标可以进行操作,我们需要添加一个工具类(OrbitControls,它叫做轨道控制器),
在base.js中引入和实例化
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
轨道控制器鼠标按键功能,是可以设置的,需要先添加鼠标工具类
import { WebGLRenderer,Scene,PerspectiveCamera,Vector3,MOUSE } from 'three'
一般情况下,鼠标左键是有其他功能的,所以一般不添加功能,这里为了操作方便,所以给鼠标左键也添加了旋转的功能
let orbitControls = new OrbitControls(camera, renderer.domElement)
orbitControls.mouseButtons = { // 设置鼠标功能键(轨道控制器)
LEFT: MOUSE.ROTATE, // 左键旋转
MIDDLE: MOUSE.DOLLY, // 中键缩放
RIGHT: MOUSE.ROTATE // 右键旋转
}
写到这里,我们会发现一个问题,就是这个立方体的每一面的光都是一样,因为我们使用了环境光,环境光的特点就是它在模型的每一个面上光照强度都是一样的,不会衰减,所以说我们看到的模型,他每个面放光是一样的,根本看不出立体感,所以我们需要添加点光源,从一个点射出一束光向四周扩散,光强度不一样的话,立体感就能看的很清楚了。
在Light.js文件中引入并创建点光源
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(ambientLight,pointLight)
四个参数分别是:
1、color(可选参数)-十六进制光照颜色,默认白色
2、intensity(可选参数)-光照强度
3、distance-表示光源到光照强度为0的位置,当设置为0时,光照永远不会消失
4、decay-沿着光照距离的衰退量
写到这里,立方体的效果也出来了,鼠标也能操作了,我这个背景色比较深,看的可能不是很清楚,你们使用的时候可以适当调节立方体的颜色和背景的颜色,看的就比较明显了