效果:
代碼:
<template><div><el-container><el-main><div class="box-card-left"><div id="threejs"></div><div style="padding: 10px;text-align: left;">叉乘判斷物體在人左前、右前還是左后,右后方向<div style="margin: 10px;"><el-button @click="judge">開始判斷</el-button><div v-for="(item,index) in this.positon_arr" :key="index" style="line-height: 28px;">{{ item }}</div></div></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 {CSS3DSprite,CSS3DRenderer,
} from "three/examples/jsm/renderers/CSS3DRenderer.js";
export default {data() {return {scene: null, // 場景對象camera: null, // 相機對象group: null, // 組對象person: null, // 人對象renderer: null, // 渲染器對象css3DRenderer: null, // 渲染器對象a: new this.$three.Vector3(0, 0, 1),// b: new this.$three.Vector3(30, 0, 30),meshPosition:[],positon_arr:[],};},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(10);this.scene.add(axesHelper);// 創建環境光對象const ambientLight = new this.$three.AmbientLight(0xffffff, 10);this.scene.add(ambientLight);// 創建相機對象this.camera = new this.$three.PerspectiveCamera(60,1,0.01,2000);this.camera.position.set(-4,5,-5);this.camera.lookAt(0,0,0);this.css3DRenderer = new CSS3DRenderer();this.css3DRenderer.setSize(1000,800);this.css3DRenderer.render(this.scene, this.camera);this.css3DRenderer.domElement.style.position = 'absolute';this.css3DRenderer.domElement.style.top = 0;this.css3DRenderer.domElement.style.pointerEvents = 'none';this.css3DRenderer.render(this.scene, this.camera);window.document.getElementById("threejs").appendChild(this.css3DRenderer.domElement);this.createMesh(0xffaadd, new this.$three.Vector3(3,0,3), '球1');this.createMesh(0xddcc11, new this.$three.Vector3(-3,0,3), '球2');this.createMesh(0x1199dd, new this.$three.Vector3(3,0,-3), '球3');this.createMesh(0xbbaadd, new this.$three.Vector3(-3,0,-3), '球4');this.createArrow(this.a);// 創建渲染器對象this.renderer = new this.$three.WebGLRenderer();this.renderer.setSize(1000,800);// 創建gltfLoader加載器對象const gltfLoader = new GLTFLoader();gltfLoader.load("/models/gltf/person2/scene.gltf", gltf => {console.log(gltf);gltf.scene.children[0].scale.set(2,2,2);this.scene.add(gltf.scene);this.renderer.render(this.scene, this.camera);window.document.getElementById("threejs").appendChild(this.renderer.domElement);const controls = new OrbitControls(this.camera, this.renderer.domElement);controls.addEventListener("change", () => {this.renderer.render(this.scene, this.camera);})this.renderFun();})},// 創建箭頭用于顯示人前方的單位向量 this.acreateArrow(dir, l=2, color=0xffffff) {let arrow = new this.$three.ArrowHelper(dir, new this.$three.Vector3(0,0,0), l, color);this.scene.add(arrow);},// 創建模型的方法createMesh(color, position, name) {// 創建球緩沖幾何體const geometry = new this.$three.SphereGeometry(1,32,16);// 創建材質對象const material = new this.$three.MeshBasicMaterial({color: color});const mesh = new this.$three.Mesh(geometry, material);mesh.name = name;mesh.position.set(position.x, position.y, position.z);this.meshPosition.push({name: name, position: mesh.position});let dom = this.createDom(name);mesh.add(dom);this.scene.add(mesh);this.createArrow(mesh.position, mesh.position.length()*0.7,color);},createDom(name) {let dom = document.createElement("div");dom.innerText = name;let css3DObject = new CSS3DSprite(dom);css3DObject.scale.set(0.03,0.03,0.03);return css3DObject;},renderFun() {this.css3DRenderer.render(this.scene, this.camera);requestAnimationFrame(this.renderFun); // 一定要設置這一句,否則,不渲染},/*** 人前方的單位向量a 與 物體到原點的向量m 叉乘后,* 可以通過叉乘結果的y值判斷物體是在人左側還是右側* */judge() {if(this.meshPosition) {this.positon_arr = [];this.meshPosition.forEach(item => {let c = this.a.clone().cross(item.position);let p_str = "";if(c.y > 0) {p_str += item.name +"在人左";p_str += this.dotDeg(item.position);} else {p_str += item.name +"在人右";p_str += this.dotDeg(item.position);}this.positon_arr.push(p_str);})}},// 點乘判斷兩個向量的夾角dotDeg(meshPosition) {let c = this.a.clone().dot(meshPosition.clone().normalize());let cos = Math.acos(c);let deg = this.$three.MathUtils.radToDeg(cos);console.log(deg);let pos = "";if(deg > 0 && deg < 90) {pos = "前";} else if (deg == 90) {pos = "平行";} else {pos = "后";}return pos;}},
};
</script>
<style lang="less" scoped>
.box-card-left {display: flex;align-items: flex-start;flex-direction: row;width: 100%;.box-right {img {width: 500px;user-select: none;}}
}
</style>
?