nitrogen.dishang.threejs.ts 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. import * as THREE from 'three';
  2. import { getTextCanvas, addEnvMap, setModalCenter } from '/@/utils/threejs/util';
  3. import { CSS3DSprite } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
  4. // import * as dat from 'dat.gui';
  5. // const gui = new dat.GUI();
  6. // gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
  7. class Nitrogen {
  8. model;
  9. modelName = 'nitrogen';
  10. group: THREE.Object3D = new THREE.Object3D();
  11. animationTimer;
  12. isLRAnimation = true;
  13. direction = 1;
  14. playerStartClickTime1 = new Date().getTime();
  15. playerStartClickTime2 = new Date().getTime();
  16. deviceRunState = '';
  17. nitrogenNum = 0;
  18. constructor(model) {
  19. this.model = model;
  20. this.group.name = this.modelName;
  21. }
  22. addLight() {
  23. const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
  24. directionalLight.position.set(32, -1, 60);
  25. this.group.add(directionalLight);
  26. directionalLight.target = this.group;
  27. // gui.add(directionalLight.position, 'x', -500, 500)
  28. // gui.add(directionalLight.position, 'y', -500, 500)
  29. // gui.add(directionalLight.position, 'z', -200, 200)
  30. const spotLight = new THREE.SpotLight();
  31. spotLight.angle = Math.PI / 4;
  32. spotLight.penumbra = 0;
  33. spotLight.castShadow = true;
  34. spotLight.distance = 0;
  35. spotLight.position.set(-88, 85, -88);
  36. spotLight.target = this.group;
  37. this.group.add(spotLight);
  38. spotLight.shadow.camera.near = 0.5; // default
  39. spotLight.shadow.camera.far = 1000; // default
  40. spotLight.shadow.focus = 1;
  41. spotLight.shadow.bias = -0.000002;
  42. // gui.add(spotLight.position, 'x', -800, 800).onChange(function (value) {
  43. // spotLight.position.x = Number(value);
  44. // });
  45. // gui.add(spotLight.position, 'y', -800, 800).onChange(function (value) {
  46. // spotLight.position.y = Number(value);
  47. // });
  48. // gui.add(spotLight.position, 'z', -800, 800).onChange(function (value) {
  49. // spotLight.position.z = Number(value);
  50. // });
  51. }
  52. // 设置模型位置
  53. setModalPosition() {
  54. if (this.nitrogenNum == 4) {
  55. this.group.position.set(0, -17, 3);
  56. this.group?.scale.set(24.0, 24.0, 24.0);
  57. }
  58. if (this.nitrogenNum == 3) {
  59. this.group.position.set(0, -1, 3);
  60. this.group?.scale.set(24.0, 24.0, 24.0);
  61. }
  62. if (this.nitrogenNum == 2) {
  63. this.group.position.set(0, 0.42, 1.21);
  64. this.group?.scale.set(24.0, 24.0, 24.0);
  65. }
  66. if (this.nitrogenNum == 1) {
  67. this.group.position.set(0, 8, 3.0);
  68. this.group?.scale.set(24.0, 24.0, 24.0);
  69. }
  70. }
  71. /* 提取风门序列帧,初始化前后门动画 */
  72. initAnimation() {}
  73. /* 点击 */
  74. mousedownModel(intersects: THREE.Intersection<THREE.Object3D<THREE.Event>>[]) {
  75. this.isLRAnimation = false;
  76. if (this.animationTimer) {
  77. clearTimeout(this.animationTimer);
  78. this.animationTimer = null;
  79. }
  80. intersects.find((intersect) => {
  81. const mesh = intersect.object;
  82. return false;
  83. });
  84. }
  85. mouseUpModel() {}
  86. // 播放动画
  87. play() {}
  88. /**
  89. * 生序排列模型的子元素
  90. */
  91. sortMeshChildren = (children: THREE.Mesh[]) => {
  92. //生序排列
  93. children.sort((x, y) => {
  94. return x.geometry.attributes.position.count - y.geometry.attributes.position.count;
  95. });
  96. return children;
  97. };
  98. /**
  99. * 设置模型透明
  100. */
  101. transparentModel = (model: THREE.Mesh) => {
  102. const transparentMaterial = new THREE.MeshBasicMaterial({
  103. transparent: true,
  104. opacity: 0,
  105. });
  106. model.material = transparentMaterial;
  107. };
  108. addCssText = () => {
  109. if (this.nitrogenNum > 0) {
  110. for (let i = 0; i < this.nitrogenNum; i++) {
  111. const nitrogenModal = this.group.getObjectByName('nitrogenModal' + i) as THREE.Object3D;
  112. if (!nitrogenModal.getObjectByName('monitorNitrogenText')) {
  113. const element = document.getElementById('nitrogenMonitor' + (i + 1)) as HTMLElement;
  114. element.style.top = '0px';
  115. element.style.left = '0px';
  116. const nitrogenMonitorCSS3D = new CSS3DSprite(element);
  117. nitrogenMonitorCSS3D.name = 'monitorNitrogenText';
  118. nitrogenMonitorCSS3D.scale.set(0.003, 0.003, 0.003);
  119. if (i == 0) nitrogenMonitorCSS3D.position.set(-0.89, 0.31, 0);
  120. if (i == 1) nitrogenMonitorCSS3D.position.set(-0.89, 0.31, 0.04);
  121. if (i == 2) nitrogenMonitorCSS3D.position.set(-0.89, 0.31, 0.08);
  122. if (i == 3) nitrogenMonitorCSS3D.position.set(-0.89, 0.31, 0.12);
  123. nitrogenModal.add(nitrogenMonitorCSS3D);
  124. }
  125. }
  126. }
  127. };
  128. /**
  129. * 处理杯子的纹理和杯子外层透明壳子
  130. */
  131. handleGlassAndWrap = (
  132. objects: THREE.Object3D,
  133. withVolume: THREE.Object3D[],
  134. glassModel: THREE.Mesh,
  135. params: THREE.MeshPhysicalMaterialParameters,
  136. scale: number,
  137. position: THREE.Vector3,
  138. rotation?: THREE.Vector3
  139. ) => {
  140. //辨别杯子和壳 大的是杯子 小的是壳 壳的点比杯子少
  141. const children = glassModel.children as THREE.Mesh[];
  142. this.sortMeshChildren(children);
  143. children.forEach((mesh) => {
  144. mesh.position.copy(position);
  145. mesh.scale.set(scale, scale, scale);
  146. rotation && mesh.rotation.setFromVector3(rotation, 'XYZ');
  147. });
  148. const [transparentWrap, glass] = children;
  149. this.transparentModel(transparentWrap);
  150. glass.material = new THREE.MeshPhysicalMaterial({
  151. side: THREE.DoubleSide,
  152. // specularColor: new Color("#ffffff"),
  153. // color: new Color(0xffa000),
  154. ...params,
  155. });
  156. objects.add(...children);
  157. //只检测壳子 减小开销
  158. withVolume.push(transparentWrap);
  159. };
  160. mountedThree(nitrogenNum) {
  161. this.nitrogenNum = nitrogenNum;
  162. return new Promise((resolve) => {
  163. if (nitrogenNum < 1) {
  164. resolve(null);
  165. return;
  166. }
  167. this.model.setGLTFModel([this.modelName]).then(async (gltf) => {
  168. const nitrogenGroup = new THREE.Object3D();
  169. const flag = nitrogenNum % 2 == 0 ? 0 : 1;
  170. for (let i = 0; i < nitrogenNum; i++) {
  171. const nitrogenModal = gltf[0].clone();
  172. nitrogenModal.name = 'nitrogenModal' + i;
  173. const c = Math.floor(nitrogenNum / 2);
  174. if (flag) {
  175. nitrogenModal.position.set(0, 0, 1.355 * (c - i));
  176. } else {
  177. nitrogenModal.position.set(0, 0, (c - i - 0.5) * 1.355);
  178. }
  179. nitrogenGroup.add(nitrogenModal);
  180. }
  181. this.group = nitrogenGroup;
  182. this.group.name = this.modelName;
  183. setModalCenter(this.group);
  184. this.addCssText();
  185. this.setModalPosition();
  186. this.addLight();
  187. resolve(null);
  188. });
  189. });
  190. }
  191. destroy() {
  192. if (this.group) {
  193. this.model.clearGroup(this.group);
  194. }
  195. this.model = null;
  196. this.group = null;
  197. }
  198. }
  199. export default Nitrogen;