nitrogen.dishang.threejs.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. import * as THREE from 'three';
  2. import { getTextCanvas, addEnvMap } from '/@/utils/threejs/util';
  3. import * as dat from 'dat.gui';
  4. const gui = new dat.GUI();
  5. gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
  6. class Nitrogen {
  7. model;
  8. modelName = 'nitrogen';
  9. // modelName = 'glass';
  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. constructor(model) {
  18. this.model = model;
  19. this.group.name = this.modelName;
  20. }
  21. addLight() {
  22. const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
  23. directionalLight.position.set(141, 259, 121);
  24. this.group.add(directionalLight);
  25. directionalLight.target = this.group;
  26. // gui.add(directionalLight.position, 'x', -100, 200).onChange(function (value) {
  27. // directionalLight.position.x = Number(value);
  28. // });
  29. // gui.add(directionalLight.position, 'y', -500, 500).onChange(function (value) {
  30. // directionalLight.position.y = Number(value);
  31. // });
  32. // gui.add(directionalLight.position, 'z', -200, 200).onChange(function (value) {
  33. // directionalLight.position.z = Number(value);
  34. // });
  35. const spotLight = new THREE.SpotLight();
  36. spotLight.angle = Math.PI / 4;
  37. spotLight.penumbra = 0;
  38. spotLight.castShadow = true;
  39. spotLight.distance = 0;
  40. spotLight.position.set(-36, 68, 189);
  41. spotLight.target = this.group;
  42. this.group.add(spotLight);
  43. spotLight.shadow.camera.near = 0.5; // default
  44. spotLight.shadow.camera.far = 1000; // default
  45. spotLight.shadow.focus = 1;
  46. spotLight.shadow.bias = -0.000002;
  47. // gui.add(spotLight.position, 'x', -800, 800).onChange(function (value) {
  48. // spotLight.position.x = Number(value);
  49. // });
  50. // gui.add(spotLight.position, 'y', -800, 800).onChange(function (value) {
  51. // spotLight.position.y = Number(value);
  52. // });
  53. // gui.add(spotLight.position, 'z', -800, 800).onChange(function (value) {
  54. // spotLight.position.z = Number(value);
  55. // });
  56. }
  57. // 设置模型位置
  58. setModalPosition() {
  59. this.group?.scale.set(22, 22, 22);
  60. this.group?.position.set(-25, 25, 15);
  61. }
  62. addText(selectData) {
  63. if (!this.group) {
  64. return;
  65. }
  66. const textArr = [
  67. {
  68. text: `龙门式测风装置`,
  69. font: 'normal 32px Arial',
  70. color: '#009900',
  71. strokeStyle: '#002200',
  72. x: 170,
  73. y: 40,
  74. },
  75. {
  76. text: `风量(m3/min):`,
  77. font: 'normal 29px Arial',
  78. color: '#009900',
  79. strokeStyle: '#002200',
  80. x: 2,
  81. y: 115,
  82. },
  83. {
  84. text: `${selectData.m3 ? selectData.m3 : '-'}`,
  85. font: 'normal 29px Arial',
  86. color: '#009900',
  87. strokeStyle: '#002200',
  88. x: 200,
  89. y: 115,
  90. },
  91. {
  92. text: `气源压力(MPa): `,
  93. font: 'normal 29px Arial',
  94. color: '#009900',
  95. strokeStyle: '#002200',
  96. x: 2,
  97. y: 182,
  98. },
  99. {
  100. text: `${selectData.temperature ? selectData.temperature : '-'}`,
  101. font: 'normal 29px Arial',
  102. color: '#009900',
  103. strokeStyle: '#002200',
  104. x: 215,
  105. y: 182,
  106. },
  107. {
  108. text: `Va(m/s):`,
  109. font: 'normal 29px Arial',
  110. color: '#009900',
  111. strokeStyle: '#002200',
  112. x: 2,
  113. y: 245,
  114. },
  115. {
  116. text: `${selectData.va ? selectData.va : '-'}`,
  117. font: 'normal 29px Arial',
  118. color: '#009900',
  119. strokeStyle: '#002200',
  120. x: 130,
  121. y: 246,
  122. },
  123. {
  124. text: `V1(m/s):`,
  125. font: 'normal 28px Arial',
  126. color: '#009900',
  127. strokeStyle: '#002200',
  128. x: 331,
  129. y: 115,
  130. },
  131. {
  132. text: `${selectData.incipientWindSpeed1 ? selectData.incipientWindSpeed1 : '-'}`,
  133. font: 'normal 28px Arial',
  134. color: '#009900',
  135. strokeStyle: '#002200',
  136. x: 455,
  137. y: 115,
  138. },
  139. {
  140. text: `V2(m/s):`,
  141. font: 'normal 28px Arial',
  142. color: '#009900',
  143. strokeStyle: '#002200',
  144. x: 330,
  145. y: 182,
  146. },
  147. {
  148. text: `${selectData.incipientWindSpeed2 ? selectData.incipientWindSpeed2 : '-'}`,
  149. font: 'normal 28px Arial',
  150. color: '#009900',
  151. strokeStyle: '#002200',
  152. x: 452,
  153. y: 182,
  154. },
  155. {
  156. text: `V3(m/s):`,
  157. font: 'normal 28px Arial',
  158. color: '#009900',
  159. strokeStyle: '#002200',
  160. x: 330,
  161. y: 245,
  162. },
  163. {
  164. text: `${selectData.incipientWindSpeed3 ? selectData.incipientWindSpeed3 : '-'}`,
  165. font: 'normal 28px Arial',
  166. color: '#009900',
  167. strokeStyle: '#002200',
  168. x: 452,
  169. y: 245,
  170. },
  171. {
  172. text: `煤炭科学技术研究院有限公司研制`,
  173. font: 'normal 28px Arial',
  174. color: '#009900',
  175. strokeStyle: '#002200',
  176. x: 60,
  177. y: 302,
  178. },
  179. ];
  180. getTextCanvas(560, 346, textArr, '').then((canvas: HTMLCanvasElement) => {
  181. const textMap = new THREE.CanvasTexture(canvas); // 关键一步
  182. const textMaterial = new THREE.MeshBasicMaterial({
  183. map: textMap, // 设置纹理贴图
  184. transparent: true,
  185. side: THREE.DoubleSide, // 这里是双面渲染的意思
  186. });
  187. textMaterial.blending = THREE.CustomBlending;
  188. const monitorPlane = this.group?.getObjectByName('monitorText');
  189. if (monitorPlane) {
  190. monitorPlane.material = textMaterial;
  191. } else {
  192. const planeGeometry = new THREE.PlaneGeometry(560, 346); // 平面3维几何体PlaneGeometry
  193. const planeMesh = new THREE.Mesh(planeGeometry, textMaterial);
  194. planeMesh.name = 'monitorText';
  195. planeMesh.scale.set(0.0022, 0.0022, 0.0022);
  196. planeMesh.position.set(3.25, -0.002, -0.41);
  197. this.group?.add(planeMesh);
  198. }
  199. });
  200. }
  201. /* 提取风门序列帧,初始化前后门动画 */
  202. initAnimation() {}
  203. /* 点击 */
  204. mousedownModel(intersects: THREE.Intersection<THREE.Object3D<THREE.Event>>[]) {
  205. this.isLRAnimation = false;
  206. if (this.animationTimer) {
  207. clearTimeout(this.animationTimer);
  208. this.animationTimer = null;
  209. }
  210. intersects.find((intersect) => {
  211. const mesh = intersect.object;
  212. return false;
  213. });
  214. }
  215. mouseUpModel() {}
  216. // 播放动画
  217. play() {}
  218. /**
  219. * 生序排列模型的子元素
  220. */
  221. sortMeshChildren = (children: THREE.Mesh[]) => {
  222. //生序排列
  223. children.sort((x, y) => {
  224. return x.geometry.attributes.position.count - y.geometry.attributes.position.count;
  225. });
  226. return children;
  227. };
  228. /**
  229. * 设置模型透明
  230. */
  231. transparentModel = (model: THREE.Mesh) => {
  232. const transparentMaterial = new THREE.MeshBasicMaterial({
  233. transparent: true,
  234. opacity: 0,
  235. });
  236. model.material = transparentMaterial;
  237. };
  238. /**
  239. * 处理杯子的纹理和杯子外层透明壳子
  240. */
  241. handleGlassAndWrap = (
  242. objects: THREE.Object3D,
  243. withVolume: THREE.Object3D[],
  244. glassModel: THREE.Mesh,
  245. params: THREE.MeshPhysicalMaterialParameters,
  246. scale: number,
  247. position: THREE.Vector3,
  248. rotation?: THREE.Vector3
  249. ) => {
  250. //辨别杯子和壳 大的是杯子 小的是壳 壳的点比杯子少
  251. const children = glassModel.children as THREE.Mesh[];
  252. this.sortMeshChildren(children);
  253. children.forEach((mesh) => {
  254. mesh.position.copy(position);
  255. mesh.scale.set(scale, scale, scale);
  256. rotation && mesh.rotation.setFromVector3(rotation, 'XYZ');
  257. });
  258. const [transparentWrap, glass] = children;
  259. this.transparentModel(transparentWrap);
  260. glass.material = new THREE.MeshPhysicalMaterial({
  261. side: THREE.DoubleSide,
  262. // specularColor: new Color("#ffffff"),
  263. // color: new Color(0xffa000),
  264. ...params,
  265. });
  266. objects.add(...children);
  267. //只检测壳子 减小开销
  268. withVolume.push(transparentWrap);
  269. };
  270. mountedThree() {
  271. return new Promise((resolve) => {
  272. this.model.setModel([this.modelName]).then(async (gltf) => {
  273. const nitrogenGroup = new THREE.Object3D();
  274. const nitrogenModal = gltf[0].clone();
  275. nitrogenModal.name = 'nitrogenModal0';
  276. nitrogenModal;
  277. const nitrogenModal1 = gltf[0].clone();
  278. nitrogenModal1.name = 'nitrogenModal1';
  279. nitrogenModal1.position.set(0, 0, 1.29);
  280. const texture = await addEnvMap('royal_esplanade_1k', this.model);
  281. const material = new THREE.MeshPhysicalMaterial({
  282. side: THREE.DoubleSide,
  283. // specularColor: new Color("#ffffff"),
  284. // color: new Color(0xffa000),
  285. color: 0xffffff,
  286. //类似透明度
  287. // transmission: 0.5,
  288. opacity: 0,
  289. metalness: 0,
  290. roughness: 0.12,
  291. ior: 1.8,
  292. thickness: 0.39, //透过看物体的模糊程度
  293. specularIntensity: 1.1,
  294. // color: new THREE.Color(0x72531e),
  295. transmission: 1,
  296. // envMap: texture,
  297. });
  298. nitrogenModal.children[0].children[1].material = new THREE.MeshPhysicalMaterial({
  299. side: THREE.DoubleSide,
  300. transparent: true,
  301. opacity: 0.1,
  302. color: 0xffffff,
  303. //类似透明度
  304. // transmission: 0.5,
  305. metalness: 0,
  306. roughness: 0.2,
  307. ior: 1.3,
  308. thickness: 1.2, //透过看物体的模糊程度
  309. specularIntensity: 1,
  310. // color: new THREE.Color(0x72531e),
  311. transmission: 0,
  312. });
  313. gui.add(material, 'metalness', 0, 1).onChange(function (value) {
  314. material.metalness = Number(value);
  315. });
  316. gui.add(material, 'roughness', 0, 1).onChange(function (value) {
  317. material.roughness = Number(value);
  318. });
  319. gui.add(material, 'thickness', 0, 2).onChange(function (value) {
  320. material.thickness = Number(value);
  321. });
  322. gui.add(material, 'specularIntensity', 0, 2).onChange(function (value) {
  323. material.specularIntensity = Number(value);
  324. });
  325. gui.add(material, 'transmission', 0, 1).onChange(function (value) {
  326. material.transmission = Number(value);
  327. });
  328. gui.add(material, 'ior', 0, 3).onChange(function (value) {
  329. material.ior = Number(value);
  330. });
  331. nitrogenModal.children[0].children[0].material = material;
  332. nitrogenGroup.add(nitrogenModal);
  333. nitrogenGroup.add(nitrogenModal1);
  334. this.group = nitrogenGroup;
  335. this.group.name = this.modelName;
  336. // this.handleGlassAndWrap(
  337. // this.group,
  338. // withVolume,
  339. // glass1,
  340. // roughnessParams,
  341. // 10,
  342. // new THREE.Vector3(60, -2.4, -120),
  343. // new THREE.Vector3(1.5, 1, -3)
  344. // );
  345. // this.handleGlassAndWrap(
  346. // objects,
  347. // withVolume,
  348. // glass3,
  349. // { ...roughnessParams, color: new THREE.Color(0x72531e), transmission: 0.7 },
  350. // 5,
  351. // new THREE.Vector3(-42, -2.5, -97)
  352. // );
  353. this.setModalPosition();
  354. this.addLight();
  355. resolve(null);
  356. });
  357. });
  358. }
  359. destroy() {
  360. if (this.group) {
  361. this.model.clearGroup(this.group);
  362. }
  363. this.model = null;
  364. this.group = null;
  365. }
  366. }
  367. export default Nitrogen;