three.js 叉乘判断物体在人前左,前右,后左、后右

news2024/9/21 10:37:10

效果:

代码:

<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.a
    createArrow(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>

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1480357.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Flutter修改了函数申明后hotload会失效

文章目录 问题描述问题原因解决方法 问题描述 在 Flutter 开发中&#xff0c;如果修改了函数的声明&#xff0c;Hot Reload 功能通常不能正常使用&#xff0c;需要重新编译。 问题原因 Hot Reload 功能的工作原理是通过注入新的 Dart 代码来更新运行中的应用程序。当您修改函…

从零学算法289

289.根据 百度百科 &#xff0c; 生命游戏 &#xff0c;简称为 生命 &#xff0c;是英国数学家约翰何顿康威在 1970 年发明的细胞自动机。 给定一个包含 m n 个格子的面板&#xff0c;每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态&#xff1a; 1 即为 活细胞 …

全面评估2023年最受欢迎的 3 类型原型设计工具

与其他设计工具相比&#xff0c;原型设计工具往往强调快速设计&#xff0c;界面建设和交互设计可以通过预设的组件、模板等内容快速完成。这可以在短时间内呈现和表达这个想法。 在原型设计工具市场上&#xff0c;有遥遥领先的基准产品、积累的新兴产品、没有创新的模仿产品、…

Tomcat布署及优化-----JDK和Tomcat

1.Tomcat简介 Tomcat 是 Java 语言开发的&#xff0c;Tomcat 服务器是一个免费的开放源代码的 Web 应用服务器&#xff0c;Tomcat 属于轻量级应用服务器&#xff0c;在中小型系统和并发访问用户不是很多的场合下被普遍使用&#xff0c;是开发和调试 JSP 程序的首选。一般来说&…

Springboot项目集成短信验证码(超简单)

操作流程 注册验证码平台创建验证码模版开始集成&#xff08;无需引入第三方库&#xff09; 注册并登陆中昱维信验证码平台 获取AppID和AppKey。 创建验证码模版 创建验证码模版&#xff0c;获取验证码模版id 开始集成 创建controller import org.springframework.web.bi…

YOLOv8涨点技巧,添加SE注意力机制提升目标检测效果

目录 论文地址 摘要 SE结构图 代码实现 Squeeze Excitation SE-Inception and SE-ResNet yaml文件编写 完整代码分享 总结 论文地址 http://openaccess.thecvf.com/content_cvpr_2018/papers/Hu_Squeeze-and-Excitation_Networks_CVPR_2018_paper.pdf 摘要 卷积神…

day06_菜单管理(查询菜单,添加菜单,添加子菜单,修改菜单,删除菜单,角色分配菜单,查询菜单,保存菜单,动态菜单)

文章目录 1 菜单管理1.1 表结构介绍1.2 查询菜单1.2.1 需求说明1.2.2 页面制作1.2.3 后端接口SysMenuSysMenuControllerSysMenuServiceMenuHelperSysMenuMapperSysMenuMapper.xml 1.2.4 前端对接sysMenu.jssysMenu.vue 1.3 添加菜单1.3.1 需求说明1.3.3 页面制作1.3.3 后端接口…

续上一篇---Jetson Xavier NX 开发板Yolov4 环境搭建和摄像头实时检测教程

1.已成功安装完CUDA&#xff0c;OpenCV&#xff0c;cuDNN&#xff0c;配置如下&#xff1a; 2.下载yolov4 自行去GitHub下载&#xff0c;然后再导入NX中&#xff0c;这样比较快且不容易出错。 https://github.com/AlexeyAB/darknet.git 3.配置 下载好包后解压缩&#xff0c;进…

一个完整的Flutter项目的基本构成

目录 1.页面跳转2.本地数据库和读取2.1 在pubspec.yaml中添加数据库框架依赖2.2 创建db.dart 初始化数据库并创建表2.3 安装JsonToDart插件2.4 创建实体类 user_bean.dart2.5 增删改查&#xff1a; 3.网络请求数据解析UI渲染 本篇主要总结下一个完整的Flutter项目有哪些基本构成…

C语言第三十三弹---动态内存管理(上)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 动态内存管理 1、为什么要有动态内存分配 2、malloc和free 2.1、malloc 2.2、free 3、calloc和realloc 3.1、calloc 3.2、realloc 4、常见的动态内存的错…

【单片机学习的准备】

文章目录 前言一、找一个视频是二、画图软件三、装keil5 仿真protues总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 项目需要&#xff1a; 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、找一个视频是 https://www.b…

mariadb数据库——安装,创建数据库

MariaDB是一个流行的开源关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它是MySQL的一个分支。 安装 apt -y install mariadb-servervi /etc/mysql/mariadb.conf.d/50-server.cnf character-set-server utf8mb4 collation-server utf8mb4_general_c…

让AI给你写代码,初体验(三)- AI加上格式化对话,实现对单个文件的修改/保存

上一篇中&#xff0c;AI生成web应用初步解决了简单web应用生成&#xff0c;但是存在两方面的问题 1&#xff09; 无法向AI提供增量需求&#xff0c;特别是一个对话结束之后&#xff0c;只能把全部需求&#xff08;包括新需求&#xff09;再描述一遍 2&#xff09; 无法用AI对存…

深入学习NumPy库在数据分析中的应用场景

在数据科学与机器学习领域&#xff0c;NumPy&#xff08;Numerical Python&#xff09;是一个经常被提及的重要工具。它是Python语言中一个非常强大的库&#xff0c;提供了高性能的多维数组对象以及用于处理这些数组的工具。NumPy不仅仅是一个用于数值计算的库&#xff0c;它还…

Redis第6讲——主从复制模式详解

Redis的读写性能很高&#xff0c;但在面对大规模数据和高发访问的挑战时&#xff0c;单节点的Redis可能无法满足需求&#xff0c;这就引出了Redis集群的概念。本节先介绍一下Redis高可用方案之一的主从复制模式&#xff0c;虽说现在基本不会用这种模式&#xff0c;但是无论是哨…

Web自动化测试平台开发---Automated_platform

一、项目简介 历时一个假期&#xff0c;Automated_platform 第一版完工&#xff0c;是一款基于po模式的自动化测试平台,采用后端技术为DjangoceleryRabbitMQmysql 配置mysql数据库&#xff0c;进行数据迁移后&#xff0c;运行项目后&#xff0c;即可成功访问http://127.0.0.1:8…

单调栈的理解

单调栈的理解 核心代码场景思考 完整代码 单调栈&#xff1a; 单调递增或 单调递减的栈 核心代码 while (!s.empty()&&s.peek()<nums[i]){s.pop(); } s.push(nums[i]);将要放入的元素&#xff0c;与栈内元素依个比较&#xff0c;小于的都出栈&#xff0c;最后将要…

List 集合遍历过程中删除元素避坑指南。

文章目录 1. 遍历2. 遍历过程中删除元素2.1 for 简单循环正向遍历方式2.2 for 简单循环反向遍历方式2.3 foreach 方式遍历删除2.4 Iterator的remove()方法2.5 <font color green> removeIf() &#xff08;推荐&#xff09;<green>2.6 Strem 方式 作为一名后端开发…

Executable and Linkable Format(ELF)

File layout ELF文件有两种视图。程序头表&#xff08;Program Header&#xff09;显示在运行时使用的段&#xff08;Segments&#xff09;&#xff0c;而节头表&#xff08;Section Header&#xff09;则列出了二进制文件的所有节&#xff08;Sections&#xff09;的集合。程…

SCT2633STER:4.5V-60V Vin,3A,高效降压DCDC转换器

•宽输入范围&#xff1a;4.5V-60V •高达3A的连续输出电流 •1.221V1%反馈参考电压 •集成220mΩ高压侧MOSFET •低静态电流为300uA •轻负载下的脉冲跳过模式&#xff08;PSM&#xff09; •最小接通时间100ns •内置12ms软启动时间 •简易内部补偿 •固定频率500KH…