效果:请关注抖音
代码:
<template><div><el-container><el-main><div class="box-card-left"><div id="threejs" style="border: 1px solid red;position: relative;"></div></div></el-main></el-container></div>
</template>
<script>
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
// 效果制作器
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
// 渲染通道
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js";
// 发光描边OutlinePass
import { OutlinePass } from "three/examples/jsm/postprocessing/OutlinePass.js";
import { CSS2DObject, CSS2DRenderer } from "three/examples/jsm/renderers/CSS2DRenderer.js";export default {data() {return {name: "",scene: null,camera: null,renderer: null,css2DRenderer: null,effectComposer: null,mesh: null,geometry: null,group: null,material: null,texture: null,position: null,outlinePass: null,canvasWidth: 1000,canvasHeight: 800,color: [],meshArr: [],};},created() {},mounted() {this.name = this.$route.query.name;this.init();},methods: {goBack() {this.$router.go(-1);},init() {// 思路:有六个模型,分别代表人的头,身体,左右手臂,左右腿;当点击某一个模型时,高亮,并且显示标签名称this.scene = new this.$three.Scene();const axesHelper = new this.$three.AxesHelper(300);this.scene.add(axesHelper);this.group = new this.$three.Group();this.group.translateY(150);this.creatMesh_tou();this.creatMesh_body();this.creatMesh_hand();this.creatMesh_foot();this.scene.add(this.group);// 创建相机对象this.camera = new this.$three.PerspectiveCamera(60,1,0.01,2000);this.camera.position.set(300,300,300);this.camera.lookAt(0,0,0);// 创建渲染器对象this.renderer = new this.$three.WebGLRenderer();this.renderer.setSize(this.canvasWidth, this.canvasHeight);this.renderer.render(this.scene, this.camera);window.document.getElementById("threejs").appendChild(this.renderer.domElement);// this.css2DRenderer = new CSS2DRenderer();this.css2DRenderer.setSize(this.canvasWidth, this.canvasHeight);this.css2DRenderer.render(this.scene, this.camera);this.css2DRenderer.domElement.style.position = "absolute";this.css2DRenderer.domElement.style.top = 0;this.css2DRenderer.domElement.style.pointerEvents = 'none';window.document.getElementById("threejs").appendChild(this.css2DRenderer.domElement);// 创建空间轨道控制器对象const controls = new OrbitControls(this.camera, this.renderer.domElement);controls.addEventListener("change", () => {this.renderer.render(this.scene, this.camera);})this.rayCasterFn();this.effectComposerFn();},renderFun() {// 调用后处理对象的render方法进行渲染,this.effectComposer.render();this.css2DRenderer.render(this.scene, this.camera);window.requestAnimationFrame(this.renderFun);},rayCasterFn() {// 画布添加事件监听document.getElementById("threejs").addEventListener("click", e => {this.scene.traverse(one => {if(one.isCSS2DObject) {this.scene.remove(one);}})// 坐标转换const p_x = e.offsetX;const p_y = e.offsetY;const x = (p_x / this.canvasWidth) * 2 - 1;const y = -(p_y / this.canvasHeight) * 2 + 1;// 创建射线拾取器对象const raycaster = new this.$three.Raycaster();// 射线计算raycaster.setFromCamera(new this.$three.Vector2(x, y), this.camera);// 射线交叉计算const intersects = raycaster.intersectObjects(this.group.children);if(intersects.length > 0) {let obj = intersects[0].object;this.outlinePass.selectedObjects = [obj];let dom = this.createDiv(obj.name);let css2_obj = new CSS2DObject(dom);const wp = new this.$three.Vector3();obj.getWorldPosition(wp)css2_obj.position.set(wp.x, wp.y, wp.z);this.scene.add(css2_obj);this.renderFun();} else {this.outlinePass.selectedObjects = [];}})},effectComposerFn() {// 创建后处理对象this.effectComposer = new EffectComposer(this.renderer);// 创建后处理通道const renderPass = new RenderPass(this.scene, this.camera);this.effectComposer.addPass(renderPass);// 创建发光描边对象this.outlinePass = new OutlinePass(new this.$three.Vector2(this.canvasWidth, this.canvasHeight), this.scene, this.camera);this.outlinePass.edgeStrength = 20;this.outlinePass.edgeThickness = 5;this.outlinePass.visibleEdgeColor.set(0xffaadd);this.outlinePass.pulsePeriod = 2;this.effectComposer.addPass(this.outlinePass);},createDiv(name) {let dom = document.createElement("div");dom.style.padding = '5px 10px';dom.style.border = '1px solid skyblue';dom.style.color = 'red';dom.style.background = '#2FF885';dom.style.borderRadius = '15px';dom.innerHTML = name;// dom.innerHTML = "龙年大吉";return dom;},creatMesh_tou() {const geometry = new this.$three.SphereGeometry(30,64,64);const material = new this.$three.MeshBasicMaterial({color: 0xdfdf});const mesh = new this.$three.Mesh(geometry, material);mesh.name = "头";this.group.add(mesh);},creatMesh_body() {const geometry = new this.$three.BoxGeometry(50,100,80);const material = new this.$three.MeshBasicMaterial({color: 0xdaafdf});const mesh = new this.$three.Mesh(geometry, material);mesh.translateY(-80);mesh.name = "身体";this.group.add(mesh);},creatMesh_hand() {const geometry = new this.$three.BoxGeometry(10,10,120);const material = new this.$three.MeshBasicMaterial({color: 0x11afdf});const mesh = new this.$three.Mesh(geometry, material);mesh.translateY(-60);mesh.translateZ(-100);mesh.name = "右手";this.group.add(mesh);const mesh2 = mesh.clone();mesh2.translateZ(200);mesh2.name = "左手";this.group.add(mesh2);},creatMesh_foot() {const geometry = new this.$three.BoxGeometry(10,190,10);const material = new this.$three.MeshBasicMaterial({color: 0xD63DF0});const mesh = new this.$three.Mesh(geometry, material);mesh.translateY(-220);mesh.translateZ(-30);mesh.name = "右腿";this.group.add(mesh);const mesh2 = mesh.clone();mesh2.translateZ(60);mesh2.name = "左腿";this.group.add(mesh2);},},
};
</script>
//
<style lang="less" scoped>
.box-card-left {display: flex;align-items: flex-start;flex-direction: row;position: relative;width: 100%;.box-right {img{width:500px;user-select: none;}}
}
</style>