当前位置:   article > 正文

three.js 点乘判断是否在扇形内

three.js 点乘判断是否在扇形内

效果:

点乘判断是否在扇形内

代码:

  1. <template>
  2. <div>
  3. <el-container>
  4. <el-main>
  5. <div class="box-card-left">
  6. <div id="threejs"></div>
  7. <div>
  8. <el-button @click="count" type="primary" plain>计算</el-button>:{{
  9. res_text
  10. }}
  11. </div>
  12. </div>
  13. </el-main>
  14. </el-container>
  15. </div>
  16. </template>
  17. <script>
  18. // 引入轨道控制器扩展库OrbitControls.js
  19. import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
  20. import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
  21. // 效果制作器
  22. import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
  23. // 渲染通道
  24. import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js";
  25. // 发光描边OutlinePass
  26. import { OutlinePass } from "three/examples/jsm/postprocessing/OutlinePass.js";
  27. import {
  28. CSS2DObject,
  29. CSS2DRenderer,
  30. } from "three/examples/jsm/renderers/CSS2DRenderer.js";
  31. import TWEEN from "@tweenjs/tween.js";
  32. import {
  33. CSS3DObject,
  34. CSS3DSprite,
  35. CSS3DRenderer,
  36. } from "three/examples/jsm/renderers/CSS3DRenderer.js";
  37. // TextGeometry 是一个附加组件,必须显式导入。 three/examples/jsm/geometries
  38. import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry.js";
  39. // FontLoader 是一个附加组件,必须显式导入。
  40. import { FontLoader } from "three/examples/jsm/loaders/FontLoader.js";
  41. export default {
  42. data() {
  43. return {
  44. scene: null, // 场景对象
  45. camera: null, // 相机对象
  46. group: null, // 组对象
  47. person: null, // 人对象
  48. res_text: "",
  49. deg1: "",
  50. deg2: "",
  51. };
  52. },
  53. created() {},
  54. mounted() {
  55. this.name = this.$route.query.name;
  56. this.init();
  57. },
  58. methods: {
  59. goBack() {
  60. this.$router.go(-1);
  61. },
  62. /**
  63. * 如何判断物体是在人的前方还是后方
  64. * 思路:借助两个单位向量的点乘结果来判断的;
  65. */
  66. init() {
  67. // 创建场景对象
  68. this.scene = new this.$three.Scene();
  69. // 创建辅助坐标轴对象
  70. const axesHelper = new this.$three.AxesHelper(100);
  71. this.scene.add(axesHelper);
  72. this.createMesh();
  73. // 创建箭头对象
  74. const arrowHelper1 = new this.$three.ArrowHelper(
  75. new this.$three.Vector3(8, 0, 5).normalize(),
  76. new this.$three.Vector3(0, 0, 0),
  77. 5,
  78. 0xffffff
  79. );
  80. this.scene.add(arrowHelper1);
  81. const arrowHelper2 = new this.$three.ArrowHelper(
  82. new this.$three.Vector3(-1, 0, 5).normalize(),
  83. new this.$three.Vector3(0, 0, 0),
  84. 5,
  85. 0xffffff
  86. );
  87. this.scene.add(arrowHelper2);
  88. // 创建环境光对象
  89. const ambientLight = new this.$three.AmbientLight(0xffffff, 10);
  90. this.scene.add(ambientLight);
  91. // 创建相机对象
  92. this.camera = new this.$three.PerspectiveCamera(60, 1, 0.01, 2000);
  93. this.camera.position.set(-1, 8, -1);
  94. this.camera.lookAt(0, 0, 0);
  95. // 创建组对象
  96. this.group = new this.$three.Group();
  97. // 创建渲染器对象
  98. this.renderer = new this.$three.WebGLRenderer();
  99. this.renderer.setSize(1000, 800);
  100. // 创建GLTFLoader对象
  101. const gltfLoader = new GLTFLoader();
  102. gltfLoader.load("/models/gltf/person2/scene.gltf", (gltf) => {
  103. this.person = gltf.scene;
  104. this.group.add(gltf.scene);
  105. this.scene.add(this.group);
  106. this.drawArc();
  107. this.renderer.render(this.scene, this.camera);
  108. window.document
  109. .getElementById("threejs")
  110. .appendChild(this.renderer.domElement);
  111. const controls = new OrbitControls(
  112. this.camera,
  113. this.renderer.domElement
  114. );
  115. controls.addEventListener("change", () => {
  116. this.renderer.render(this.scene, this.camera);
  117. });
  118. });
  119. },
  120. createMesh() {
  121. const geometry = new this.$three.BoxGeometry(2, 2, 2);
  122. const material = new this.$three.MeshBasicMaterial({ color: 0xffaddd });
  123. this.mesh = new this.$three.Mesh(geometry, material);
  124. this.mesh.position.set(-3, 0, 5);
  125. this.scene.add(this.mesh);
  126. },
  127. count() {
  128. // 从人指向物体的向量
  129. let b = this.mesh.position.clone().sub(this.person.position.clone());
  130. // 先计算距离是否大于圆弧半径 5
  131. // 这里距离去整数了
  132. if (Math.trunc(b.length()) - 1 > 5) {
  133. // alert();
  134. this.res_text = "物体不在扇形内--1";
  135. } else {
  136. this.createArc();
  137. }
  138. },
  139. // 生成圆弧
  140. createArc() {
  141. // 计算两个箭头之间的角度 -- start
  142. let a = new this.$three.Vector3(8, 0, 5).normalize(); // 计算后的单位向量
  143. let b = new this.$three.Vector3(-1, 0, 5).normalize(); // 计算后的单位向量
  144. let a_dot_b = a.dot(b); // 两个单位向量点乘得到 他们夹角的余弦值
  145. let cos = Math.acos(a_dot_b); // 反余弦计算得到弧度
  146. let deg = this.$three.MathUtils.radToDeg(cos); // 弧度转角度
  147. // 计算两个箭头之间的角度 -- end
  148. // 计算箭头1 和人正前方的单位向量的夹角
  149. let deg_1 = this.countDeg(8, 0, 5);
  150. // 计算箭头2 和人正前方的单位向量的夹角
  151. let deg_2 = this.countDeg(-1, 0, 5);
  152. // 判断人正前方的单位向量和两个箭头的夹角和(deg_1 + deg_2) 与 两个箭头的夹角(deg)的大小比较;
  153. // if(deg_1 + deg_2 > deg) 说明人正前方不在两个箭头中间;反之在中间
  154. if (deg_1 + deg_2 > deg) {
  155. this.res_text = "物体不在扇形内--3";
  156. } else {
  157. this.res_text = "物体在扇形内--2";
  158. }
  159. },
  160. countDeg(x, y, z, flag = true) {
  161. let a = new this.$three.Vector3(x, y, z).normalize(); // 计算后的单位向量
  162. if (flag) {
  163. let b = this.person.position.clone().normalize(); // 计算后的单位向量
  164. let a_dot_b = a.dot(b); // 两个单位向量点乘得到 他们夹角的余弦值
  165. let cos = Math.acos(a_dot_b); // 反余弦计算得到弧度
  166. let deg = this.$three.MathUtils.radToDeg(cos); // 弧度转角度
  167. return deg;
  168. } else {
  169. let b = new this.$three.Vector3(1, 0, 0); // 计算后的单位向量
  170. let a_dot_b = a.dot(b); // 两个单位向量点乘得到 他们夹角的余弦值
  171. let cos = Math.acos(a_dot_b); // 反余弦计算得到弧度
  172. let deg = this.$three.MathUtils.radToDeg(cos); // 弧度转角度
  173. return cos;
  174. }
  175. },
  176. drawArc() {
  177. // 计算箭头1 和人正前方的单位向量的夹角
  178. let deg_1 = this.countDeg(8, 0, 5, false);
  179. // 计算箭头2 和人正前方的单位向量的夹角
  180. let deg_2 = this.countDeg(-1, 0, 5, false);
  181. console.log(deg_1, deg_2);
  182. this.deg1 = deg_1;
  183. this.deg2 = deg_2;
  184. // EllipseCurve 的第五个、第六个参数用弧度
  185. const arcCurve = new this.$three.EllipseCurve( 0, 0, 5, 5, deg_1, deg_2, false,);
  186. // const arcCurve = new this.$three.EllipseCurve( 0, 0, 5, 5, 0, 2 * Math.PI, false, 0 );
  187. const points = arcCurve.getPoints(100);
  188. const geometry = new this.$three.BufferGeometry();
  189. geometry.setFromPoints(points);
  190. const material = new this.$three.LineBasicMaterial({ color: 0xffffff });
  191. const line = new this.$three.Line(geometry, material);
  192. line.rotateX(Math.PI / 2);
  193. this.scene.add(line);
  194. },
  195. },
  196. };
  197. </script>
  198. <style lang="less" scoped>
  199. .box-card-left {
  200. display: flex;
  201. align-items: flex-start;
  202. flex-direction: row;
  203. width: 100%;
  204. .box-right {
  205. img {
  206. width: 500px;
  207. user-select: none;
  208. }
  209. }
  210. }
  211. </style>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/181497
推荐阅读
相关标签
  

闽ICP备14008679号