背景:在一个vue文件里使用两个gltf模型,并且两个模型直接不存在绑定及依赖关系,即相互独立。
目的:点击单个模型,则该模型变色。另一模型不发生任何变化。
思路处理:按方法来进行一步步导入和处理。
- 初始化顺序
init() {
this.createScene() 创建场景,可以理解为三维世界,用来展示三维物体
this.loadGLTF() 加载GLTF模型,三维世界已经建好,那么我们就把三维物体放到三维世界里
this.createLight() 创建光源,首先光会产生能见度,没有光线自然会出现那种特别暗或者是一片黑的情况,
第二就是光线能够更好的展示出三维图形的立体感
this.createCamera() 创建相机,相机就是我们的视角,从哪去看这个三维物体
this.createRender() 创建渲染器,到目前为止还都是代码,想让这些理论代码显示到网页上就需要渲染器来工作了。
this.createControls() 创建控件对象,没有它,我们是无法用鼠标来控制模型旋转之类的操作的,
this.render() 渲染,一切准备就绪,渲染器开始工作
},
完整代码:
<template>
<div>
<div id="container"></div>
</div>
</template>
<script>
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
// 引入渲染器通道RenderPass
import { OutlinePass } from "three/addons/postprocessing/OutlinePass.js";
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import * as Three from "three";
var scene,mesh,model1,model2; //这两个变量不要在data(){ }中定义问题即可解决。
export default {
data() {
return {
// publicPath: process.env.BASE_URL,
// mesh: null,
camera: null,
// scene: null,
renderer: null,
controls: null
}
},
mounted() {
this.init()
window.addEventListener("click", this.onClick, false);
},
methods: {
//事件函数
onClick(event) {
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
// 计算鼠标或触摸点的位置
const threeModel = document.getElementById("container");
const width = threeModel.offsetWidth;
const height = threeModel.offsetHeight;
let getClientRect = threeModel.getBoundingClientRect();
mouse.x = ((event.clientX - getClientRect .left) / width) * 2 - 1;
mouse.y = -((event.clientY - getClientRect .top) / height) * 2 + 1;
console.log(event.clientX)
// 更新射线 注意——> this.camera 是相机 定义到data里的
raycaster.setFromCamera(mouse, this.camera);
// 计算与所有对象的交点
const intersects = raycaster.intersectObjects(scene.children, true);
if (intersects.length > 0) {
// 处理点击事件
// intersects[0] 包含了第一个
// 交点
const clickedObject = intersects[0].object;
//通过点击到该模型用名字匹配
if (clickedObject.name === clickedObject.name) {
// 创建后处理对象,这里我将该对象称作 效果制作器
mesh = new EffectComposer(this.renderer);
// 创建渲染器通道
const renderPass = new RenderPass(scene, this.camera);
mesh.addPass(renderPass);
// 创建发光描边对象,model2可选,具体根据gltf导入时所确定的名称,对应修改
const outlinePass = new OutlinePass(new Three.Vector2(1000, 800), model2, this.camera);
// 设置发光描边颜色
outlinePass.visibleEdgeColor.set(0x7CFC00);
// 设置发光描边厚度
outlinePass.edgeThickness = 5;
// 设置发光描边强度
outlinePass.edgeStrength = 7;
// 设置闪烁频率
outlinePass.pulsePeriod = 2;
const obj = [];
scene.traverse(item => {
if(item.isMesh) {
obj.push(item);
}
})
outlinePass.selectedObjects = obj;
mesh.addPass(outlinePass);
this.renderFun();
}
}
},
// 初始化
init() {
this.createScene() // 创建场景
this.loadGLTF() // 加载GLTF模型
this.createLight() // 创建光源
this.createCamera() // 创建相机
this.createRender() // 创建渲染器
this.createControls() // 创建控件对象
this.render() // 渲染
},
//技术来自 http://www.webgl3d.cn/pages/637c91/
// 1.创建三维场景
createScene() {
scene = new THREE.Scene()
},
// 加载GLTF模型对象,(别的模型需要单独修改)
loadGLTF() {
const loader = new GLTFLoader()
loader.load(`../gy.gltf`,
gltf1 => {
model1=gltf1.scene//用于全局控制变色时的具体对象,变色时选择model1则代表该模型变色
// 解决模型为黑色的问题
gltf1.scene.traverse(function(child) {//遍历对象,给其上色
if (child.isMesh) {
child.material.emissive = child.material.color;//emissive自发光属性,color默认值是白色
child.material.emissiveMap = child.material.map;//emissiveMap自发光贴图属性
}
});
gltf1.scene.children[0].scale.set(10, 10, 10)//调整模型整体大小用的,三个数值保持一致即可
scene.add(model1)
})
loader.load(`../gy.gltf`,
gltf2 => {
model2=gltf2.scene//用于全局控制变色时的具体对象,变色时选择model2则代表该模型变色
// 解决模型为黑色的问题
gltf2.scene.traverse(function(child) {//遍历对象,给其上色
if (child.isMesh) {
child.material.emissive = child.material.color;//emissive自发光属性,color默认值是白色
child.material.emissiveMap = child.material.map;//emissiveMap自发光贴图属性
}
});
gltf2.scene.children[0].scale.set(10, 10, 10)
gltf2.scene.children[0].position.x=150//平行横向
gltf2.scene.children[0].position.y=150//平行前后
gltf2.scene.children[0].position.z=150//平行前后
scene.add(model2)
})
},
// 创建光源
createLight() {
// 环境光
const ambientLight = new THREE.AmbientLight(0xffffff, 0.1) // 创建环境光
scene.add(ambientLight) // 将环境光添加到场景
// 创建聚光灯
const spotLight = new THREE.SpotLight(0xffffff)
spotLight.position.set(150, 150, 150)
spotLight.castShadow = true
scene.add(spotLight)
},
// 创建相机
createCamera() {
//先设计坐标系
const width = 300 // 窗口宽度
const height = 150 // 窗口高度
const k = width / height // 窗口宽高比
//设计相机
// PerspectiveCamera( fov, aspect, near, far )
this.camera = new THREE.PerspectiveCamera(75, k, 0.1, 1000)//
this.camera.position.set(150, 150, 150) // 设置相机位置,主要控制页面显示中的起始大小
this.camera.lookAt(new THREE.Vector3(10, 40, 0)) // 设置相机方向
//把相机加到三维场景中
scene.add(this.camera)
},
// 创建渲染器
createRender() {
const element = document.getElementById('container')
//创建WebGL渲染器
this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
this.renderer.setSize(element.clientWidth, element.clientHeight) // 设置渲染区域尺寸
this.renderer.shadowMap.enabled = true // 显示阴影
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap//设置阴影效果
this.renderer.setClearColor(null, 1) // 设置背景颜色,null就是透明色
//three.js执行渲染命令会输出一个canvas画布(HTML元素),你可以插入到web页面中
element.appendChild(this.renderer.domElement)
},
//开始渲染
render() {
if (mesh) {
//加z轴方向旋转弧度,每次旋转0.006个弧度
mesh.rotation.z += 0.006
}
//把三维场景,和照相机开始渲染
this.renderer.render(scene, this.camera)
//页面刷新,自动重新渲染话
requestAnimationFrame(this.render)
this.camera.updateMatrixWorld()
},
renderFun() {
mesh.render();
window.requestAnimationFrame(this.renderFun);
},
// 创建控件对象
createControls() {
this.controls = new OrbitControls(this.camera, this.renderer.domElement)
}
}
}
</script>
<style>
#container {
position: absolute;
width: 30%;
height: 40%;
}
</style>