赞
踩
效果:
点乘判断是否在扇形内
代码:
- <template>
- <div>
- <el-container>
- <el-main>
- <div class="box-card-left">
- <div id="threejs"></div>
- <div>
- <el-button @click="count" type="primary" plain>计算</el-button>:{{
- res_text
- }}
- </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";
- import TWEEN from "@tweenjs/tween.js";
- import {
- CSS3DObject,
- CSS3DSprite,
- CSS3DRenderer,
- } from "three/examples/jsm/renderers/CSS3DRenderer.js";
- // TextGeometry 是一个附加组件,必须显式导入。 three/examples/jsm/geometries
- import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry.js";
- // FontLoader 是一个附加组件,必须显式导入。
- import { FontLoader } from "three/examples/jsm/loaders/FontLoader.js";
- export default {
- data() {
- return {
- scene: null, // 场景对象
- camera: null, // 相机对象
- group: null, // 组对象
- person: null, // 人对象
- res_text: "",
- deg1: "",
- deg2: "",
- };
- },
- 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(100);
- this.scene.add(axesHelper);
- this.createMesh();
- // 创建箭头对象
- const arrowHelper1 = new this.$three.ArrowHelper(
- new this.$three.Vector3(8, 0, 5).normalize(),
- new this.$three.Vector3(0, 0, 0),
- 5,
- 0xffffff
- );
-
- this.scene.add(arrowHelper1);
- const arrowHelper2 = new this.$three.ArrowHelper(
- new this.$three.Vector3(-1, 0, 5).normalize(),
- new this.$three.Vector3(0, 0, 0),
- 5,
- 0xffffff
- );
-
- this.scene.add(arrowHelper2);
-
- // 创建环境光对象
- 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(-1, 8, -1);
- this.camera.lookAt(0, 0, 0);
- // 创建组对象
- this.group = new this.$three.Group();
- // 创建渲染器对象
- this.renderer = new this.$three.WebGLRenderer();
- this.renderer.setSize(1000, 800);
- // 创建GLTFLoader对象
- const gltfLoader = new GLTFLoader();
- gltfLoader.load("/models/gltf/person2/scene.gltf", (gltf) => {
- this.person = gltf.scene;
- this.group.add(gltf.scene);
- this.scene.add(this.group);
-
- this.drawArc();
- 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);
- });
- });
- },
- createMesh() {
- const geometry = new this.$three.BoxGeometry(2, 2, 2);
- const material = new this.$three.MeshBasicMaterial({ color: 0xffaddd });
- this.mesh = new this.$three.Mesh(geometry, material);
- this.mesh.position.set(-3, 0, 5);
- this.scene.add(this.mesh);
- },
- count() {
- // 从人指向物体的向量
- let b = this.mesh.position.clone().sub(this.person.position.clone());
- // 先计算距离是否大于圆弧半径 5
- // 这里距离去整数了
- if (Math.trunc(b.length()) - 1 > 5) {
- // alert();
- this.res_text = "物体不在扇形内--1";
- } else {
- this.createArc();
- }
- },
- // 生成圆弧
- createArc() {
- // 计算两个箭头之间的角度 -- start
- let a = new this.$three.Vector3(8, 0, 5).normalize(); // 计算后的单位向量
- let b = new this.$three.Vector3(-1, 0, 5).normalize(); // 计算后的单位向量
- let a_dot_b = a.dot(b); // 两个单位向量点乘得到 他们夹角的余弦值
- let cos = Math.acos(a_dot_b); // 反余弦计算得到弧度
- let deg = this.$three.MathUtils.radToDeg(cos); // 弧度转角度
- // 计算两个箭头之间的角度 -- end
-
- // 计算箭头1 和人正前方的单位向量的夹角
- let deg_1 = this.countDeg(8, 0, 5);
- // 计算箭头2 和人正前方的单位向量的夹角
- let deg_2 = this.countDeg(-1, 0, 5);
- // 判断人正前方的单位向量和两个箭头的夹角和(deg_1 + deg_2) 与 两个箭头的夹角(deg)的大小比较;
- // if(deg_1 + deg_2 > deg) 说明人正前方不在两个箭头中间;反之在中间
-
- if (deg_1 + deg_2 > deg) {
- this.res_text = "物体不在扇形内--3";
- } else {
- this.res_text = "物体在扇形内--2";
- }
- },
- countDeg(x, y, z, flag = true) {
- let a = new this.$three.Vector3(x, y, z).normalize(); // 计算后的单位向量
- if (flag) {
- let b = this.person.position.clone().normalize(); // 计算后的单位向量
- let a_dot_b = a.dot(b); // 两个单位向量点乘得到 他们夹角的余弦值
- let cos = Math.acos(a_dot_b); // 反余弦计算得到弧度
- let deg = this.$three.MathUtils.radToDeg(cos); // 弧度转角度
- return deg;
- } else {
- let b = new this.$three.Vector3(1, 0, 0); // 计算后的单位向量
- let a_dot_b = a.dot(b); // 两个单位向量点乘得到 他们夹角的余弦值
- let cos = Math.acos(a_dot_b); // 反余弦计算得到弧度
- let deg = this.$three.MathUtils.radToDeg(cos); // 弧度转角度
- return cos;
- }
- },
- drawArc() {
- // 计算箭头1 和人正前方的单位向量的夹角
- let deg_1 = this.countDeg(8, 0, 5, false);
- // 计算箭头2 和人正前方的单位向量的夹角
- let deg_2 = this.countDeg(-1, 0, 5, false);
- console.log(deg_1, deg_2);
- this.deg1 = deg_1;
- this.deg2 = deg_2;
- // EllipseCurve 的第五个、第六个参数用弧度
- const arcCurve = new this.$three.EllipseCurve( 0, 0, 5, 5, deg_1, deg_2, false,);
- // const arcCurve = new this.$three.EllipseCurve( 0, 0, 5, 5, 0, 2 * Math.PI, false, 0 );
- const points = arcCurve.getPoints(100);
- const geometry = new this.$three.BufferGeometry();
- geometry.setFromPoints(points);
- const material = new this.$three.LineBasicMaterial({ color: 0xffffff });
- const line = new this.$three.Line(geometry, material);
- line.rotateX(Math.PI / 2);
- this.scene.add(line);
- },
- },
- };
- </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>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。