引入外部文件
-
引入需要的插件
-
- 控制器(可以操作模型)
-
- 对加载出来的物体进行鼠标的操作,放大、缩小、旋转、平移
- 模型加载器
-
- 可以用不同的模型加载器加载不同文件类型的模型
- 这次使用的是GLTFLoader.js,用来加载gltf模型
-
- 以扩展的形式,将加载的js代
- 可以在模型的基础上,进行多其他效果的渲染(如分块着色等)
import * as THREE from 'three';
// 引入控制器
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js';
// 引入模型加载器
import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader';
-
相机
-
- 一般使用透视投影相机(PerspectiveCamera)
-
- 基本等同于人的眼睛
- 离的远的物体会显得比较小,近处的物体会比较大
- 还有一种叫正交投影相机(OrthographicCamera)
const aspect = this.width / this.height;
// 创建一个透视投影相机
// 视景体竖直方向上的张角45度
// aspect等于width/height,是照相机水平方向和竖直方向长度的比值,通常设为canvas的横纵比例
// 照相机到视景体最近的距离 1
// 照相机到视景体最远的距离 1000
this.camera = new THREE.PerspectiveCamera(45, aspect, 1, 1000);
// 照相机放的位置
this.camera.position.z = 15;
-
控制器
-
- 轨道控制器可以使得相机围绕目标进行轨道运动
this.controls = new OrbitControls(this.camera, this.canvas);
// 你能够垂直旋转的角度的下限
// 范围是0到Math.PI,默认值为0,0的话可以看到顶部
this.controls.minPolarAngle = 0;
// 你能够垂直旋转的角度的上限,范围是0到Math.PI,其默认值为Math.PI
// Math.PI的话可以看到底部
this.controls.maxPolarAngle = Math.PI;
// 滑动效果是否流畅
this.controls.smooth = true;
// 平滑滑动的速度
this.controls.smoothspeed = 0.95;
// 相机以自动围绕目标旋转
this.controls.autoRotate = true;
// 围绕目标旋转的速度,默认值为2.0,相当于钟表每旋转一周需要30秒
this.controls.autoRotateSpeed = 1;
// 够将相机向外移动的最大距离(相机越远物体越小)
this.controls.maxDistance = 50;
// 够将相机向外移动的最小距离
this.controls.minDistance = 12;
// 如果.autoRotate被启用,你必须在你的动画循环里调用.update()
this.controls.update();
完整代码如下
/**
* @version 1.0.1
* @author yangf
*/
// 引入three
import * as THREE from 'three';
// 引入控制器
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js';
// 引入模型加载器
import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader';
export default {
name: 'page-demo',
data() {
return {
canvas: null,
scene: null,
camera: null,
renderer: null,
width: 0,
height: 0,
activeIndex: 0,
meshList: [],
meshColorList: []
};
},
mounted() {
// 初始化
this.init();
// 加载模型
this.loadModel();
// 更新模型
this.update();
},
methods: {
// 初始化
init() {
// 获取要加载模型的容器,并且创建canvas
this.initEL();
this.initSence();
this.initLight();
this.initCamera();
this.initRenderer();
this.render();
this.initControls();
this.root.appendChild(this.canvas);
},
// 获取渲染dom节点
initEL() {
this.root = document.getElementById('content');
this.canvas = document.createElement('canvas');
this.width = this.root.offsetWidth;
this.height = this.root.offsetHeight;
},
// 初始化场景
initSence() {
this.scene = new THREE.Scene();
},
// 初始化光源
initLight() {
// 环境光(颜色会添加到整个场景和所有对象的当前颜色上)
// 参数为颜色和光照强度
const ambient = new THREE.AmbientLight(0xffffff, 0.9);
this.scene.add(ambient);
// 点光源(光线来自同一点,且辐射方向四面八方,如蜡烛发出的光)
// const point = new THREE.PointLight(0x0655fd, 0.1, 100);
// 平行光
// const directional = new THREE.DirectionalLight(0xffffff, 0.5);
// this.scene.add(point);
// this.scene.add(directional);
},
// 初始化相机
initCamera() {
const aspect = this.width / this.height;
// 创建一个透视投影相机
// 视景体竖直方向上的张角45度
// aspect等于width/height,是照相机水平方向和竖直方向长度的比值,通常设为canvas的横纵比例
// 照相机到视景体最近的距离 1
// 照相机到视景体最远的距离 1000
this.camera = new THREE.PerspectiveCamera(45, aspect, 1, 1000);
// 照相机放的位置
this.camera.position.z = 15;
},
// 初始化渲染
initRenderer() {
// 创建渲染器
this.renderer = new THREE.WebGLRenderer({antialias: true});
// 设置渲染器为容器高宽大小
this.renderer.setSize(this.width, this.height);
// 设置渲染器的容器颜色
this.renderer.setClearColor(0xeeeeee, 1);
// 渲染器给canvas,为了在 HTML 创建的容器中添加渲染器的 DOM 元素
this.canvas = this.renderer.domElement;
},
// 初始化控制器
initControls() {
this.controls = new OrbitControls(this.camera, this.canvas);
// 你能够垂直旋转的角度的下限
// 范围是0到Math.PI,默认值为0,0的话可以看到顶部
this.controls.minPolarAngle = 0;
// 你能够垂直旋转的角度的上限,范围是0到Math.PI,其默认值为Math.PI
// Math.PI的话可以看到底部
this.controls.maxPolarAngle = Math.PI;
// 滑动效果是否流畅
this.controls.smooth = true;
// 平滑滑动的速度
this.controls.smoothspeed = 0.95;
// 相机以自动围绕目标旋转
this.controls.autoRotate = true;
// 围绕目标旋转的速度,默认值为2.0,相当于钟表每旋转一周需要30秒
this.controls.autoRotateSpeed = 60;
// 够将相机向外移动的最大距离(相机越远物体越小)
this.controls.maxDistance = 30;
// 够将相机向外移动的最小距离
this.controls.minDistance = 10;
},
// 加载模型
loadModel() {
this.loader = new GLTFLoader();
this.loader.load('static/cat_dispenser/scene.gltf', (model) => {
let index = 1;
// 将每个模块存起来
model.scene.traverse((child) => {
if (child instanceof THREE.Mesh) {
child.name = `模块${index}`;
index++;
this.meshList.push(child);
this.meshColorList.push(child.material);
// child.material.map = null;
}
});
this.scene.add(model.scene);
this.renderer.render(this.scene, this.camera);
});
},
// 渲染
render() {
this.renderer.render(this.scene, this.camera);
},
// 更新模型
update() {
// 帧循环
requestAnimationFrame(() => this.update());
// 如果.autoRotate被启用,你必须在你的动画循环里调用.update()
// 自动动
// this.controls.update();
this.render();
},
// 点击添加和去除材质
chickChangeMaterial(item, index) {
this.$set(this.meshList[index], 'active', !item.active);
// 选择出模型
const rgb = 'rgb(255,0,0)'.replace(/[rgb]|[(]|[)]|\s/g, '').split(',');
this.meshList[index].material = this.setTexture(rgb);
},
// 设置材质
setTexture(rgb) {
// 定义一张纹理(可以理解为布)
const size = 200 * 200;
const data = new Uint8Array(3 * size);
for (let i = 0; i < size; i++) {
const stride = i * 3;
data[stride] = rgb[0];
data[stride + 1] = rgb[1];
data[stride + 2] = rgb[2];
}
// 创建一个纹理
const texture = new THREE.DataTexture(data, 100, 100, THREE.RGBFormat);
// 将纹理作为材质返回
return new THREE.MeshPhongMaterial({map: texture});
}
}
};
// html代码
<!--
* @name:
* @author: yangf
* @description:
* @createTime: Do not edit
* @UpdateTime: Do not edit
-->
<template>
<div class="fd-page-content">
<button class="fd-mb20" @click="clickGoto('/index')">返回</button>
<div id="content" class="canvas"></div>
<button @click="chickChangeMaterial(item,index)"
:class="['fd-ctrl-btn',{active:item.active}]"
v-for="(item, index) in meshList" :key="index"
>{{item.name}}</button>
</div>
</template>
<script src="./index.js"></script>
<style scoped>
.fd-ctrl-btn {
margin: 50px 10px;
background: #5cadff !important;
border-color: #5cadff !important;
}
.fd-ctrl-btn.active {
background: #a1a7ad !important;
border-color: #a1a7ad !important;
}
</style>
里面使用的3D模型地址:sketchfab.com/3d-models/c…