threeVehicleModel.vue 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. <template>
  2. <div>
  3. <div id="containerThreeVehicleModel"></div>
  4. </div>
  5. </template>
  6. <script>
  7. import * as THREE from "three";
  8. import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
  9. import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
  10. import {
  11. showFullScreenLoading,
  12. tryHideFullScreenLoading,
  13. } from "../../../axios/filter";
  14. import { mapState } from "vuex";
  15. export default {
  16. name: "threeVehicleModel", // 动力学配置中的threeJS
  17. data() {
  18. return {
  19. publicPath: process.env.BASE_URL,
  20. scene: null,
  21. camera: null,
  22. renderer: null,
  23. light: null,
  24. geometryName: null,
  25. controls: null,
  26. mesh: null,
  27. cube: null,
  28. container: null,
  29. car: null,
  30. cubeTexture: null,
  31. raf: null,
  32. // scale: 2, // 物体加载换算倍数
  33. };
  34. },
  35. computed: {
  36. ...mapState(["scale", "scaleRate"]),
  37. },
  38. props: {
  39. carModel: {
  40. type: String,
  41. default: "",
  42. },
  43. },
  44. watch: {
  45. carModel(newVal, oldVal) {
  46. if (newVal != oldVal) {
  47. this.initCar(newVal);
  48. }
  49. },
  50. },
  51. methods: {
  52. // 场景
  53. initScene() {
  54. this.scene = new THREE.Scene();
  55. const gridHelper = new THREE.GridHelper(1000, 100);
  56. gridHelper.material.opacity = 0.25;
  57. gridHelper.material.transparent = true;
  58. this.scene.add(gridHelper);
  59. },
  60. // 相机
  61. initCamera() {
  62. this.camera = new THREE.PerspectiveCamera(
  63. 75,
  64. this.container.clientWidth / this.container.clientHeight,
  65. 0.1,
  66. 1000
  67. );
  68. this.camera.position.set(200, 200, 200);
  69. this.scene.add(this.camera);
  70. },
  71. // 渲染器
  72. initRenderer() {
  73. this.renderer = new THREE.WebGLRenderer({
  74. antialias: true,
  75. alpha: true,
  76. });
  77. this.renderer.setSize(
  78. this.container.clientWidth,
  79. this.container.clientHeight
  80. );
  81. this.renderer.setClearColor("#272727");
  82. this.container.appendChild(this.renderer.domElement);
  83. },
  84. // 初始化灯光
  85. initLight() {
  86. var hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444);
  87. hemiLight.position.set(0, 20, 0);
  88. this.scene.add(hemiLight);
  89. // 环境光会均匀的照亮场景中的所有物体
  90. const light = new THREE.AmbientLight(0x5c5c5c, 0.4); // soft white light
  91. this.scene.add(light);
  92. // 平行光是沿着特定方向发射的光
  93. const dirLight = new THREE.DirectionalLight(0xffffff, 0.5);
  94. this.scene.add(dirLight);
  95. },
  96. // 初始化车模型
  97. initCar(model) {
  98. if (this.car) {
  99. this.scene.remove(this.car);
  100. this.removeObj(this.car);
  101. this.car = null;
  102. }
  103. if (!model) return;
  104. if (!model.includes(".glb")) return;
  105. let that = this;
  106. let loader = new GLTFLoader();
  107. showFullScreenLoading();
  108. loader.load(
  109. model,
  110. function (obj) {
  111. tryHideFullScreenLoading();
  112. obj.scene.rotation.set(
  113. (-90 * Math.PI) / 180,
  114. 0,
  115. (-180 * Math.PI) / 180
  116. );
  117. let s = 0;
  118. if (model.includes("928.glb")) {
  119. s = that.scale / that.scaleRate;
  120. } else {
  121. s = that.scale;
  122. }
  123. let scale = 30 * s;
  124. obj.scene.scale.set(scale, scale, scale);
  125. that.scene.add(obj.scene);
  126. that.car = obj.scene;
  127. },
  128. (xhr) => {
  129. // console.log((xhr.loaded / xhr.total) * 100 + "% loaded");
  130. },
  131. (error) => {
  132. tryHideFullScreenLoading();
  133. console.error(error);
  134. }
  135. );
  136. },
  137. // 初始化
  138. init() {
  139. this.initScene();
  140. this.initCamera();
  141. this.initRenderer();
  142. this.initLight();
  143. this.controls = new OrbitControls(
  144. this.camera,
  145. this.renderer.domElement
  146. ); //创建控件对象
  147. this.controls.minDistance = 30;
  148. this.controls.maxDistance = 600;
  149. this.controls.update();
  150. },
  151. animate() {
  152. this.raf = requestAnimationFrame(this.animate);
  153. this.renderer.render(this.scene, this.camera);
  154. this.controls.update();
  155. },
  156. onWindowResize() {
  157. this.camera.aspect =
  158. this.container.clientWidth / this.container.clientHeight;
  159. this.camera.updateProjectionMatrix();
  160. this.renderer.setSize(
  161. this.container.clientWidth,
  162. this.container.clientHeight
  163. );
  164. },
  165. go() {
  166. this.container = document.getElementById(
  167. "containerThreeVehicleModel"
  168. );
  169. this.init();
  170. this.animate();
  171. window.addEventListener("resize", this.onWindowResize);
  172. },
  173. removeScene() {
  174. this.clearScene();
  175. },
  176. clearCache(item) {
  177. if (item.geometry && item.geometry.dispose) item.geometry.dispose();
  178. if (item.material && item.material.dispose) item.material.dispose();
  179. },
  180. clearScene() {
  181. this.removeObj(this.scene);
  182. },
  183. removeObj(obj) {
  184. let arr = obj.children.filter((x) => x);
  185. arr.forEach((item) => {
  186. if (item.children.length) {
  187. this.removeObj(item);
  188. } else {
  189. this.clearCache(item);
  190. item.clear();
  191. }
  192. }),
  193. obj.clear();
  194. arr = null;
  195. },
  196. },
  197. mounted() {
  198. this.go();
  199. },
  200. destroyed() {
  201. window.removeEventListener("resize", this.onWindowResize);
  202. cancelAnimationFrame(this.raf);
  203. if (this.renderer) {
  204. this.renderer.renderLists.dispose();
  205. this.renderer.dispose();
  206. this.renderer.forceContextLoss();
  207. this.renderer.domElement = null;
  208. this.renderer.content = null;
  209. this.renderer = null;
  210. }
  211. if (this.controls) {
  212. this.controls.dispose();
  213. this.controls = null;
  214. }
  215. this.clearScene();
  216. this.scene = null;
  217. this.camera = null;
  218. this.light = null;
  219. this.geometryName = null;
  220. this.mesh = null;
  221. this.cube = null;
  222. this.container = null;
  223. this.car = null;
  224. this.cubeTexture = null;
  225. this.raf = null;
  226. THREE.Cache.clear();
  227. },
  228. };
  229. </script>
  230. <style lang="less" scoped>
  231. #containerThreeVehicleModel {
  232. width: 100%;
  233. height: calc(100vh - 180px);
  234. }
  235. </style>