ThreeModel.vue 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. <template>
  2. <div class="three-model" @click="clickEvent">
  3. <loading ref="pageLoading"></loading>
  4. </div>
  5. </template>
  6. <script>
  7. import loading from '@com/coms/loading/loading.vue';
  8. import * as THREE from "three";
  9. import { GLTFLoader } from "@node/three/examples/jsm/loaders/GLTFLoader.js";
  10. import { OrbitControls } from "@node/three/examples/jsm/controls/OrbitControls.js";
  11. let camera, scene, renderer, controls;
  12. let mixers = [];
  13. let clock = new THREE.Clock();
  14. let fanAnimates = [];
  15. export default {
  16. // 名称
  17. name: "ThreeModel",
  18. // 使用组件
  19. components: {
  20. loading
  21. },
  22. // 传入参数
  23. props: {},
  24. // 自定义事件
  25. emits: {
  26. when: null,
  27. },
  28. // 数据
  29. data() {
  30. return {
  31. // 场景
  32. initScene: function () {
  33. scene = new THREE.Scene();
  34. // scene.background = new THREE.Color(0xa0a0a0);
  35. },
  36. // 相机
  37. initCamera: function () {
  38. camera = new THREE.PerspectiveCamera(45, this.$el.scrollWidth / this.$el.scrollHeight, 0.1, 10000);
  39. camera.position.set(50, 60, 50);
  40. },
  41. // 坐标轴
  42. initAxesHelper: function () {
  43. const axesHelper = new THREE.AxesHelper(150);
  44. scene.add(axesHelper);
  45. axesHelper.position.set(0, 0, 0);
  46. },
  47. // 渲染器
  48. initRender: function () {
  49. renderer = new THREE.WebGLRenderer({antialias: true, alpha: true});
  50. // renderer.setClearAlpha(0);
  51. renderer.setSize(this.$el.scrollWidth, this.$el.scrollHeight);
  52. this.$el.append(renderer.domElement);
  53. },
  54. // 灯光
  55. initLight: function () {
  56. // let light = new THREE.PointLight(0xffffff, 2);
  57. let light = new THREE.AmbientLight(0xffffff, 4);
  58. // light.position.set(50, 50, 50);
  59. scene.add(light);
  60. },
  61. // 控制器
  62. initControls: function () {
  63. controls = new OrbitControls(camera, renderer.domElement);
  64. },
  65. // 初始化一个风机动画
  66. initFanAnimate: function (fan1, fan2, fan3) {
  67. let fanAnimateObj = {
  68. speed: 0.05,
  69. fan1: fan1,
  70. fan2: fan2,
  71. fan3: fan3,
  72. };
  73. let fanAnimateFunction = function () {
  74. fanAnimateObj.fan1.rotateZ(fanAnimateObj.speed);
  75. fanAnimateObj.fan2.rotateZ(fanAnimateObj.speed);
  76. fanAnimateObj.fan3.rotateZ(fanAnimateObj.speed);
  77. fanAnimateObj.animateId = window.requestAnimationFrame(fanAnimateFunction);
  78. }
  79. fanAnimateObj.stop = function () {
  80. window.cancelAnimationFrame(fanAnimateObj.animateId);
  81. };
  82. fanAnimateObj.start = function () {
  83. fanAnimateFunction();
  84. };
  85. fanAnimateFunction();
  86. fanAnimates.push(fanAnimateObj);
  87. return fanAnimateObj;
  88. },
  89. // 清空风机动画
  90. clearFanAnimate: function () {
  91. while (fanAnimates.length > 0) {
  92. let fanAnimateObj = fanAnimates.shift();
  93. fanAnimateObj.stop();
  94. }
  95. },
  96. // 内容
  97. initContent: function () {
  98. // 加载3D地面
  99. let loaderGround = new GLTFLoader();/*实例化加载器*/
  100. loaderGround.load("static/3d/group/ng.gltf", (gltf) => {
  101. gltf.scene.position.set(5, 10, 0);
  102. scene.add(gltf.scene);
  103. // 找到一个大风扇的 Object3D
  104. let fanBig1_1 = gltf.scene.children[0].getObjectByName("Box707");
  105. let fanBig1_2 = gltf.scene.children[0].getObjectByName("Box708");
  106. let fanBig1_3 = gltf.scene.children[0].getObjectByName("Box709");
  107. let fanBig2_1 = gltf.scene.children[0].getObjectByName("Box719");
  108. let fanBig2_2 = gltf.scene.children[0].getObjectByName("Box720");
  109. let fanBig2_3 = gltf.scene.children[0].getObjectByName("Box721");
  110. let fanBig3_1 = gltf.scene.children[0].getObjectByName("Box699");
  111. let fanBig3_2 = gltf.scene.children[0].getObjectByName("Box701");
  112. let fanBig3_3 = gltf.scene.children[0].getObjectByName("Box702");
  113. this.initFanAnimate(fanBig1_1, fanBig1_2, fanBig1_3);
  114. this.initFanAnimate(fanBig2_1, fanBig2_2, fanBig2_3);
  115. this.initFanAnimate(fanBig3_1, fanBig3_2, fanBig3_3);
  116. let mixer = new THREE.AnimationMixer(gltf.scene.children[0]);
  117. mixer.clipAction(gltf.animations[0]).setDuration(3).play();
  118. mixers.push(mixer);
  119. console.log(gltf)
  120. }, (xhr) => {
  121. if (xhr.loaded == xhr.total) {
  122. this.$emit("when");
  123. setTimeout(() => {
  124. this.$refs.pageLoading.hide();
  125. }, 3000);
  126. }
  127. }, function (error) {
  128. console.error('load error!'+error.getWebGLErrorMessage());
  129. })
  130. },
  131. // 创建一个圆柱
  132. initCylinderGeometry: function () {
  133. let geometry = new THREE.CylinderGeometry(4, 4, 4, 64);
  134. let materials = [
  135. //圆柱侧面材质,使用纹理贴图
  136. new THREE.MeshBasicMaterial({
  137. color: 0xffff00,
  138. side: THREE.DoubleSide,
  139. transparent: true
  140. }),
  141. //圆柱顶材质
  142. new THREE.MeshBasicMaterial({
  143. transparent: true,
  144. opacity: 0,
  145. side: THREE.DoubleSide
  146. }),
  147. //圆柱底材质
  148. new THREE.MeshBasicMaterial({
  149. transparent: true,
  150. opacity: 0,
  151. side: THREE.DoubleSide
  152. })
  153. ];
  154. let cylinder = new THREE.Mesh(geometry, materials);
  155. scene.add(cylinder);
  156. },
  157. // 点击事件
  158. clickEvent: function (event) {
  159. event.preventDefault();
  160. let vector = new THREE.Vector3(
  161. (event.clientX / window.innerWidth) * 2 - 1,
  162. -(event.clientY / window.innerHeight) * 2 + 1,
  163. 0.5
  164. );
  165. vector = vector.unproject(camera);
  166. let raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
  167. let intersects = raycaster.intersectObjects(scene.children,true);
  168. console.log(intersects)
  169. // this.initCylinderGeometry();
  170. },
  171. // 初始化
  172. initThree: function () {
  173. this.initScene();
  174. // this.initAxesHelper();
  175. this.initCamera();
  176. this.initRender();
  177. this.initLight();
  178. this.initControls();
  179. this.initContent();
  180. renderer.setAnimationLoop(this.animate);
  181. },
  182. // 动画
  183. animate: function () {
  184. var delta = clock.getDelta();
  185. for ( var i = 0; i < mixers.length; i ++ ) { // 重复播放动画
  186. mixers[ i ].update( delta );
  187. }
  188. renderer.render(scene, camera);
  189. },
  190. };
  191. },
  192. // 函数
  193. methods: {},
  194. // 生命周期钩子
  195. beforeCreate() {
  196. // 创建前
  197. },
  198. created() {
  199. // 创建后
  200. },
  201. beforeMount() {
  202. // 渲染前
  203. },
  204. mounted() {
  205. // 渲染后
  206. this.initThree();
  207. },
  208. beforeUpdate() {
  209. // 数据更新前
  210. },
  211. updated() {
  212. // 数据更新后
  213. },
  214. beforeUnmount() {
  215. // 销毁前
  216. renderer.setAnimationLoop(null);
  217. camera = null;
  218. scene = null;
  219. renderer = null;
  220. },
  221. };
  222. </script>
  223. <style lang="less" scoped>
  224. .three-model {
  225. }
  226. </style>