当前位置:   article > 正文

vue + threejs 给3D模型添加label标签(dom的方式)_three.js模型头上标签

three.js模型头上标签

 webGL.js封装的代码。

  1. const THREE = window.THREE;
  2. // webGL对象配置
  3. export const webglOBJ = {
  4. renderDom: null,
  5. Scene: null, // 场景
  6. camera: null, // 摄像头
  7. renderer: null, // 渲染器
  8. senceAdd (objList = []) {
  9. objList.forEach(v => {
  10. webglOBJ.Scene.add(v);
  11. });
  12. },
  13. // 创建场景
  14. createSence (renderDom) {
  15. this.renderDom = renderDom;
  16. webglOBJ.Scene = new THREE.Scene();
  17. return webglOBJ.Scene;
  18. },
  19. // 创建摄像机
  20. createCamera ({innerWidth, innerHeight, position} = {}) {
  21. const { width, height } = this.renderDom.getBoundingClientRect();
  22. let camera = new THREE.PerspectiveCamera(45, 1, 0.1, 1000);
  23. camera.position.x = -50;
  24. camera.position.y = 30;
  25. camera.position.z = 50;
  26. camera.lookAt(webglOBJ.Scene.position); // 视角
  27. webglOBJ.camera = camera; // 视角
  28. return webglOBJ.camera;
  29. },
  30. createRenderer () {
  31. let renderer = new THREE.WebGLRenderer();
  32. const {width, height} = this.renderDom.getBoundingClientRect();
  33. renderer.setSize(width, height);
  34. renderer.setClearColor(new THREE.Color(0xcccccc));
  35. renderer.shadowMap.enabled = true;
  36. this.renderDom.appendChild(renderer.domElement);
  37. webglOBJ.renderer = renderer;
  38. return webglOBJ.renderer;
  39. },
  40. createPlane (textureLoaderUrl, textureNormalUrl) {
  41. let planeGeometry = new THREE.PlaneGeometry(60, 60, 1, 1); // 平面网格
  42. let textureLoader = new THREE.TextureLoader();
  43. let texture = textureLoader.load(textureLoaderUrl);
  44. let textureNormal = textureLoader.load(textureNormalUrl);
  45. // 加载高光贴图
  46. let planeMaterial = new THREE.MeshPhongMaterial({
  47. // specular: 0xff0000,//高光部分的颜色
  48. shininess: 30, //高光部分的亮度,默认30
  49. map: texture, // 普通纹理贴图
  50. roughness: 0.3,
  51. lightMap: textureNormal,
  52. // normalMap: textureNormal, //法线贴图
  53. bumpScale: 3
  54. }); // 材质对象Material
  55. // let planeMaterial = new THREE.MeshLambertMaterial({color: 0xcccccc});
  56. let plane = new THREE.Mesh(planeGeometry, planeMaterial);
  57. plane.rotation.x = -0.5 * Math.PI;
  58. plane.position.x = 0;
  59. plane.name = '平面物体ID=' + 1;
  60. plane.position.y = 0;
  61. plane.position.z = 0;
  62. plane.receiveShadow = true;
  63. return plane;
  64. },
  65. createBoxGeometry (textureLoaderUrl, {x, y, z}) {
  66. // 创建立方体
  67. let textureLoader = new THREE.TextureLoader();
  68. let textureNormal = textureLoader.load(textureLoaderUrl);
  69. let boxGeometry = new THREE.BoxGeometry(10, 10, 10, 200);
  70. let texture1 = textureLoader.load(textureLoaderUrl);
  71. let boxGeometryMaterial = new THREE.MeshLambertMaterial({
  72. // specular: 0xff0000,//高光部分的颜色
  73. shininess: 10, //高光部分的亮度,默认30
  74. normalScale: new THREE.Vector2(2.2, 2.2),
  75. map: texture1, // 普通纹理贴图
  76. normalMap: textureNormal, //法线贴图
  77. bumpMap: textureNormal,
  78. bumpScale: 0.3
  79. });
  80. let box = new THREE.Mesh(boxGeometry, boxGeometryMaterial);
  81. box.name = '正方物体ID=' + 2;
  82. box.position.x = x;
  83. box.position.y = y;
  84. box.position.z = z;
  85. box.castShadow = true;
  86. return box;
  87. },
  88. // 点光源
  89. createSpotLight () {
  90. // 点光源
  91. let spotLight = new THREE.SpotLight(0xffffff);
  92. spotLight.position.set(-60, 40, -20);
  93. spotLight.castShadow = true;
  94. return spotLight;
  95. },
  96. // 平行光
  97. createDirectionalLight (target) {
  98. // 平行光
  99. let directionalLight = new THREE.DirectionalLight(0xffffff, 1);
  100. // 设置光源的方向:通过光源position属性和目标指向对象的position属性计算
  101. directionalLight.position.set(-90, 80, -20);
  102. // 方向光指向对象网格模型mesh2,可以不设置,默认的位置是0,0,0
  103. // directionalLight.target = target;
  104. return directionalLight;
  105. },
  106. // 环境光
  107. createAmbient (color = 0x444444) {
  108. let ambient = new THREE.AmbientLight(color);
  109. // ambient.castShadow = true;
  110. return ambient;
  111. },
  112. createDatGui () {
  113. let gui = {
  114. bump: 0.03,
  115. animation: false,
  116. };
  117. let datGui = new dat.GUI();
  118. //将设置属性添加到gui当中,gui.add(对象,属性,最小值,最大值)
  119. datGui.add(gui, "bump", -1, 1).onChange(function (e) {
  120. box.material.bumpScale = e;
  121. });
  122. datGui.add(gui, "animation");
  123. return datGui;
  124. },
  125. // 创建控制轴
  126. createControls () {
  127. let controls = new THREE.OrbitControls(webglOBJ.camera, webglOBJ.renderDom);
  128. return controls;
  129. },
  130. // 创建帮助
  131. createAxisHelper () {
  132. let axisHelper = new THREE.AxisHelper(250);
  133. return axisHelper;
  134. },
  135. // 初始化webGL对象
  136. webglRender (Scene, camera) {
  137. webglOBJ.renderer.render(Scene, camera);
  138. window.requestAnimationFrame(webglOBJ.webglRender);
  139. }
  140. };
  141. /**
  142. * 添加标签:dom方式
  143. * @param {*} targePosition :需要传递当前标签的位置
  144. * @param {*} targetId :标签对应的dom的唯一ID,暂且用时间戳代替,避免重复
  145. * @param {*} innerHTML :标签对应html
  146. */
  147. export function labelTag (camera, targePosition, targetId, innerHTML, webGLdom) {
  148. const { width, height } = webGLdom.getBoundingClientRect();
  149. let worldVector = new THREE.Vector3(targePosition.x, targePosition.y, targePosition.z);
  150. let vector = worldVector.project(camera);
  151. let halfWidth = width / 2,
  152. halfHeight = height / 2;
  153. let x = Math.round(vector.x * halfWidth + halfWidth);
  154. let y = Math.round(-vector.y * halfHeight + halfHeight);
  155. /**
  156. * 更新立方体元素位置
  157. */
  158. let div = document.getElementById(targetId);
  159. div.style.left = x + 'px';
  160. div.style.top = y + 'px';
  161. // div.innerHTML = `uuid:${innerHTML.uuid}`;
  162. }

vue中引用: 

  1. <template>
  2. <div>
  3. <div class="three-box_wrapper"></div>
  4. <div :id="`sign${idx + 1}`" style="position: absolute;" v-for="(v, idx) in labels" :key="idx">
  5. <div class="sign" :uuid="v.uuid">
  6. <div class="name">我是标签1</div>
  7. <div class="data">数据: {{v.uuid}}</div>
  8. </div>
  9. </div>
  10. </div>
  11. </template>
  12. <script>
  13. import {webglOBJ, labelTag} from '@/utils/webGL/webGL.js';
  14. export default {
  15. name: 'threeBox',
  16. data () {
  17. return {
  18. labels: []
  19. };
  20. },
  21. mounted () {
  22. this.int();
  23. },
  24. methods: {
  25. createLabel () {
  26. },
  27. int () {
  28. const imgBG = require('./img.jpg');
  29. const webGLdom = document.querySelector('.three-box_wrapper');
  30. const sence = webglOBJ.createSence(webGLdom);
  31. const camera = webglOBJ.createCamera();
  32. const renderer = webglOBJ.createRenderer();
  33. const plane = webglOBJ.createPlane(imgBG, imgBG);
  34. const boxGeometry = webglOBJ.createBoxGeometry(imgBG, {x: 10, y: 5, z: 10});
  35. const boxGeometry1 = webglOBJ.createBoxGeometry(imgBG, {x: -10, y: 5, z: 10});
  36. const spotLight = webglOBJ.createSpotLight();
  37. const directionalLight = webglOBJ.createDirectionalLight(boxGeometry);
  38. const ambient = webglOBJ.createAmbient();
  39. const datGui = webglOBJ.createDatGui();
  40. const controls = webglOBJ.createControls();
  41. const axisHelper = webglOBJ.createAxisHelper();
  42. // 将对象添加到场景中去
  43. webglOBJ.senceAdd([plane, boxGeometry, boxGeometry1, spotLight, directionalLight, ambient, datGui, controls, axisHelper]);
  44. // webglOBJ.webglRender(sence, camera, renderer);
  45. console.log(sence, 'sence');
  46. const vm = this;
  47. function render(html) {
  48. vm.labels = sence.children.filter(v => v.type == 'Mesh');
  49. vm.$nextTick(() => {
  50. sence.children.forEach((val, idx) => {
  51. if (val.type == 'Mesh') {
  52. const {x, y, z} = val.position;
  53. labelTag(camera, {x, y, z}, `sign${idx + 1}`, val, webGLdom);
  54. }
  55. });
  56. });
  57. renderer.render(sence, camera);
  58. requestAnimationFrame(render);
  59. };
  60. render();
  61. // 监听点击事件查看点击的元素
  62. let raycaster = new THREE.Raycaster();
  63. let mouse = new THREE.Vector2();
  64. // 点击了哪个模型
  65. function clickEvent() {
  66. if (event.target.tagName == 'CANVAS') {
  67. mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  68. mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
  69. sence.updateMatrixWorld(true);
  70. // 通过鼠标点的位置和当前相机的矩阵计算出raycaster
  71. raycaster.setFromCamera(mouse, camera);
  72. // 获取raycaster直线和所有模型相交的数组集合
  73. let intersects = raycaster.intersectObjects(sence.children, true);
  74. if (intersects[0]) {
  75. console.log(intersects[0]);
  76. }
  77. }
  78. }
  79. window.addEventListener('click', clickEvent, false);
  80. }
  81. }
  82. };
  83. </script>
  84. <style lang="scss" scoped>
  85. .three-box_wrapper {
  86. position: relative;
  87. width: 100%;
  88. height: 800px;
  89. border: 1px solid #ccc;
  90. }
  91. div[id *= "sign"] {
  92. width: 250px;
  93. height: 100px;
  94. background: rgba(0, 0, 0, .65);
  95. .sign{
  96. div {
  97. color: #fff;
  98. text-align: left;
  99. padding: 0 5px;
  100. }
  101. }
  102. }
  103. </style>

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

闽ICP备14008679号