beltTun.threejs.base.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. import * as THREE from 'three';
  2. import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
  3. import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
  4. import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js';
  5. import { OutlinePass } from 'three/examples/jsm/postprocessing/OutlinePass.js';
  6. import { FXAAShader } from 'three/examples/jsm/shaders/FXAAShader.js';
  7. import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass.js';
  8. import { GammaCorrectionShader } from 'three/examples/jsm/shaders/GammaCorrectionShader.js';
  9. import { CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
  10. // import * as dat from 'dat.gui';
  11. // const gui = new dat.GUI();
  12. // gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
  13. class BeltFace {
  14. model;
  15. modelName = 'beltTun';
  16. group: THREE.Object3D = new THREE.Object3D();
  17. bloomComposer: EffectComposer | null = null;
  18. finalComposer: EffectComposer | null = null;
  19. outlinePass: OutlinePass | null = null;
  20. positions: THREE.Vector3[][] = [];
  21. msgPositions = [];
  22. bloomLayer = new THREE.Layers();
  23. darkMaterial = new THREE.MeshBasicMaterial({ color: 'black', transparent: true, side: THREE.DoubleSide });
  24. materials = {};
  25. glob = {
  26. ENTIRE_SCENE: 0,
  27. BLOOM_SCENE: 1,
  28. N: 100,
  29. };
  30. locationTexture: THREE.Texture | null = null;
  31. warningLocationTexture: THREE.Texture | null = null;
  32. errorLocationTexture: THREE.Texture | null = null;
  33. playerStartClickTime1 = new Date().getTime();
  34. playerStartClickTime2 = new Date().getTime();
  35. constructor(model) {
  36. this.model = model;
  37. this.group.name = this.modelName;
  38. }
  39. addLight() {
  40. // const _this = this;
  41. const directionalLight = new THREE.DirectionalLight(0xffffff, 3);
  42. directionalLight.position.set(-98, 183, -131);
  43. this.group.add(directionalLight);
  44. directionalLight.target = this.group;
  45. // gui.add(directionalLight.position, 'x', -500, 500).onChange(function (value) {
  46. // directionalLight.position.x = Number(value);
  47. // _this.render();
  48. // });
  49. // gui.add(directionalLight.position, 'y', -500, 500).onChange(function (value) {
  50. // directionalLight.position.y = Number(value);
  51. // _this.render();
  52. // });
  53. // gui.add(directionalLight.position, 'z', -500, 500).onChange(function (value) {
  54. // directionalLight.position.z = Number(value);
  55. // _this.render();
  56. // });
  57. // const pointLight5 = new THREE.PointLight(0xffffff, 0.8, 120);
  58. // pointLight5.position.set(-54, 30, 23.8);
  59. // pointLight5.shadow.bias = 0.05;
  60. // this.group.add(pointLight5);
  61. // const pointLight7 = new THREE.PointLight(0xffffff, 1, 1000);
  62. // pointLight7.position.set(45, 51, -4.1);
  63. // pointLight7.shadow.bias = 0.05;
  64. // this.model.scene.add(pointLight7);
  65. // const spotLight = new THREE.SpotLight();
  66. // spotLight.angle = Math.PI / 2;
  67. // spotLight.penumbra = 0;
  68. // spotLight.castShadow = true;
  69. // spotLight.intensity = 1;
  70. // spotLight.shadow.camera.near = 0.5; // default
  71. // spotLight.shadow.focus = 1.2;
  72. // spotLight.shadow.bias = -0.000002;
  73. // spotLight.position.set(-7.19, 199, -68.1);
  74. // this.group.add(spotLight);
  75. // gui.add(directionalLight.position, 'x', -10, 20).onChange(function (value) {
  76. // directionalLight.position.x = Number(value);
  77. // _this.render();
  78. // });
  79. // gui.add(directionalLight.position, 'y', -50, 50).onChange(function (value) {
  80. // directionalLight.position.y = Number(value);
  81. // _this.render();
  82. // });
  83. // gui.add(directionalLight.position, 'z', -20, 20).onChange(function (value) {
  84. // directionalLight.position.z = Number(value);
  85. // _this.render();
  86. // });
  87. // gui.add(spotLight.position, 'x', -600, 600).onChange(function (value) {
  88. // spotLight.position.x = Number(value);
  89. // _this.render();
  90. // });
  91. // gui.add(spotLight.position, 'y', -600, 800).onChange(function (value) {
  92. // spotLight.position.y = Number(value);
  93. // _this.render();
  94. // });
  95. // gui.add(spotLight.position, 'z', -500, 1000).onChange(function (value) {
  96. // spotLight.position.z = Number(value);
  97. // _this.render();
  98. // });
  99. }
  100. // 设置模型位置
  101. setModalPosition() {
  102. this.group?.scale.set(22, 22, 22);
  103. this.group?.position.set(-15, 25, 15);
  104. }
  105. render() {
  106. // 无发光
  107. if (this.model && this.model.scene.getObjectByName(this.modelName)) {
  108. this.model.renderer?.render(this.model.scene as THREE.Scene, this.model.camera as THREE.PerspectiveCamera);
  109. }
  110. // 有发光
  111. // const _this = this;
  112. // if (this.model && this.model.scene.getObjectByName(this.modelName)) {
  113. // this.group?.traverse((obj) => {
  114. // _this.darkenNonBloomed(obj);
  115. // });
  116. // this.bloomComposer?.render();
  117. // this.group?.traverse((obj) => {
  118. // _this.restoreMaterial(obj);
  119. // });
  120. // this.finalComposer?.render();
  121. // this.model.css3dRender?.render(this.model.scene as THREE.Scene, this.model.camera as THREE.PerspectiveCamera);
  122. // }
  123. }
  124. setRenderPass = () => {
  125. this.bloomLayer.set(this.glob.BLOOM_SCENE);
  126. const params = {
  127. bloomStrength: 2.5,
  128. bloomThreshold: 0,
  129. bloomRadius: 0,
  130. };
  131. const renderScene = new RenderPass(this.model.scene, this.model.camera);
  132. const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85);
  133. bloomPass.strength = params.bloomStrength;
  134. bloomPass.radius = params.bloomRadius;
  135. bloomPass.threshold = params.bloomThreshold;
  136. this.bloomComposer = new EffectComposer(this.model.renderer);
  137. this.bloomComposer.renderToScreen = false;
  138. this.bloomComposer.addPass(renderScene);
  139. this.bloomComposer.addPass(bloomPass);
  140. const finalPass = new ShaderPass(
  141. new THREE.ShaderMaterial({
  142. uniforms: {
  143. baseTexture: { value: null },
  144. bloomTexture: { value: this.bloomComposer.renderTarget2.texture },
  145. },
  146. vertexShader: `
  147. varying vec2 vUv;
  148. void main() {
  149. vUv = uv;
  150. gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
  151. }`,
  152. fragmentShader: `uniform sampler2D baseTexture;
  153. uniform sampler2D bloomTexture;
  154. varying vec2 vUv;
  155. void main() {
  156. gl_FragColor = ( texture2D( baseTexture, vUv ) + vec4( 1.0, 1.0, 1.0, 0.0 ) * texture2D( bloomTexture, vUv ) );
  157. }`,
  158. defines: {},
  159. }),
  160. 'baseTexture'
  161. );
  162. const gammaCorrection = new ShaderPass(GammaCorrectionShader);
  163. finalPass.needsSwap = true;
  164. this.finalComposer = new EffectComposer(this.model.renderer);
  165. this.finalComposer.addPass(renderScene);
  166. this.finalComposer.addPass(gammaCorrection);
  167. this.finalComposer.addPass(finalPass);
  168. const effectFXAA = new ShaderPass(FXAAShader);
  169. effectFXAA.uniforms['resolution'].value.set(1 / window.innerWidth, 1 / window.innerHeight);
  170. this.finalComposer.addPass(effectFXAA);
  171. // this.outlinePass = new OutlinePass(new THREE.Vector2(window.innerWidth, window.innerHeight), this.model.scene, this.model.camera);
  172. // this.finalComposer.addPass(this.outlinePass);
  173. };
  174. getPositions(num = 40) {
  175. const curve1 = new THREE.LineCurve3(new THREE.Vector3(-0.818, 0.002, 0.363), new THREE.Vector3(0.722, 0.002, 0.363)); // 前
  176. const curve2 = new THREE.LineCurve3(new THREE.Vector3(-0.818, 0.002, -0.459), new THREE.Vector3(0.718, -0.002, -0.459)); // 中
  177. const curve3 = new THREE.LineCurve3(new THREE.Vector3(0.345, 0.008, 0.329), new THREE.Vector3(0.345, 0.008, -0.43)); // 后
  178. const len1 = curve1.getLength();
  179. const len2 = curve2.getLength();
  180. const len3 = curve3.getLength();
  181. const unit = (len1 + len2 + len3) / num;
  182. const num1 = Math.floor(len1 / unit);
  183. const num2 = Math.floor(len2 / unit);
  184. const num3 = Math.floor(len3 / unit);
  185. const points1 = curve1.getPoints(num1);
  186. const points2 = curve2.getPoints(num2);
  187. const points3 = curve3.getPoints(num3);
  188. this.positions = [points1, points2, points3];
  189. this.msgPositions = [curve1.getSpacedPoints(10), curve2.getSpacedPoints(10), curve3.getSpacedPoints(10)];
  190. }
  191. drawSpheres = () => {
  192. const _this = this;
  193. const pointLines = new THREE.Object3D();
  194. pointLines.name = 'pointLines';
  195. return new Promise((resolve) => {
  196. new THREE.TextureLoader().load('/model/img/texture-smoke.png', (texture) => {
  197. texture.colorSpace = THREE.SRGBColorSpace;
  198. const material = new THREE.PointsMaterial({
  199. color: '#FFFFFF',
  200. size: 0.03,
  201. map: texture,
  202. transparent: true, // 开启透明度
  203. });
  204. _this.positions.forEach((position, index) => {
  205. const geometry = new THREE.BufferGeometry();
  206. geometry.setFromPoints(position);
  207. const points = new THREE.Points(geometry, material);
  208. points.renderOrder = 0;
  209. index == 0 ? (points.name = 'line_q') : index == 1 ? (points.name = 'line_h') : (points.name = 'line_z');
  210. pointLines.add(points);
  211. points.layers.enable(_this.glob.BLOOM_SCENE);
  212. });
  213. this.group.add(pointLines);
  214. resolve(null);
  215. texture.dispose();
  216. });
  217. });
  218. };
  219. darkenNonBloomed(obj) {
  220. if (obj.isMesh && this.bloomLayer.test(obj.layers) === false) {
  221. const opacity = obj.material.opacity;
  222. this.materials[obj.uuid] = obj.material;
  223. obj.material = this.darkMaterial.clone();
  224. obj.material.opacity = opacity;
  225. }
  226. }
  227. restoreMaterial(obj) {
  228. if (this.materials[obj.uuid]) {
  229. obj.material = this.materials[obj.uuid];
  230. delete this.materials[obj.uuid];
  231. }
  232. }
  233. /* 点击 */
  234. mousedownModel(rayCaster: THREE.Raycaster) {
  235. debugger;
  236. // const outlinePass = this.outlinePass;
  237. // const selectedObjects = [];
  238. // outlinePass.selectedObjects = selectedObjects;
  239. const opticalFiber = this.group.getObjectByName('opticalfiber');
  240. if (opticalFiber) {
  241. const intersects = rayCaster?.intersectObjects([...opticalFiber.children]) as THREE.Intersection[];
  242. // 判断是否点击到视频
  243. // intersects.find((intersect) => {
  244. // const mesh = intersect.object;
  245. // if (mesh.name.startsWith('optical_fiber_')) {
  246. // // outlinePass?.selectedObjects.push(mesh);
  247. // return true;
  248. // }
  249. // return false;
  250. // });
  251. }
  252. this.render();
  253. }
  254. mouseUpModel() {
  255. //
  256. }
  257. mountedThree() {
  258. return new Promise(async (resolve) => {
  259. this.model.renderer.sortObjects = true;
  260. this.model.camera.position.set(0, 3.1, 500);
  261. this.setRenderPass();
  262. this.model.orbitControls.update();
  263. // this.model.orbitControls.addEventListener('change', _this.render.bind(_this));
  264. this.model.setGLTFModel(['laneway']).then(async (gltf) => {
  265. this.group = gltf[0];
  266. this.group.name = this.modelName;
  267. this.group.position.set(-3.5, 0.7, 0);
  268. (this.group as THREE.Group).remove(this.group.getObjectByName('mesh001'));
  269. const optical = this.group.getObjectByName('optical_fiber_');
  270. if (optical) {
  271. optical.renderOrder = 9;
  272. optical.material = new THREE.MeshBasicMaterial({
  273. color: 0x555555,
  274. side: THREE.DoubleSide,
  275. transparent: true,
  276. opacity: 0.15,
  277. });
  278. }
  279. this.getPositions();
  280. this.addLight();
  281. this.drawSpheres();
  282. resolve(null);
  283. });
  284. });
  285. }
  286. destroy() {
  287. this.model.clearGroup(this.group);
  288. this.model = null;
  289. this.group = null;
  290. }
  291. }
  292. export default BeltFace;