ThreeHelper.ts 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. import * as THREE from "three";
  2. import {
  3. AxesHelper,
  4. BoxGeometry,
  5. Mesh,
  6. MeshLambertMaterial,
  7. PerspectiveCamera,
  8. Vector2,
  9. } from "three";
  10. import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
  11. import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer";
  12. import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass";
  13. import { OutlinePass } from "three/examples/jsm/postprocessing/OutlinePass";
  14. import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader";
  15. export default class ThreeHelper {
  16. width: number = 0;
  17. height: number = 0;
  18. group: THREE.Group;
  19. geometry: THREE.BoxGeometry;
  20. material: THREE.MeshLambertMaterial;
  21. mesh: THREE.Mesh;
  22. camera: THREE.PerspectiveCamera;
  23. axesHelper: THREE.AxesHelper;
  24. scene: THREE.Scene;
  25. light: THREE.PointLight;
  26. renderer: THREE.WebGLRenderer | null = null;
  27. constructor() {
  28. this.group = new THREE.Group();
  29. this.geometry = new BoxGeometry(60, 90, 80);
  30. this.material = new MeshLambertMaterial({
  31. color: 0x009900,
  32. transparent: true,
  33. opacity: 0.5,
  34. });
  35. this.mesh = new Mesh(this.geometry, this.material);
  36. this.group.add(this.mesh);
  37. this.camera = this.creatCamera();
  38. this.axesHelper = new AxesHelper(400);
  39. this.light = this.creatLight();
  40. this.scene = new THREE.Scene();
  41. this.scene.add(this.group);
  42. this.scene.add(this.axesHelper);
  43. this.scene.add(this.light);
  44. }
  45. creatLight = () => {
  46. const light = new THREE.PointLight(0xffffff, 1.0);
  47. light.intensity = 300.0; //光照强度
  48. light.decay = 0.0; //设置光源不随距离衰减
  49. light.position.set(1000, 1000, 1000);
  50. return light;
  51. };
  52. creatRenderer = (dom: HTMLElement) => {
  53. this.width = dom.clientWidth;
  54. this.height = dom.clientHeight;
  55. const renderer: THREE.WebGLRenderer = new THREE.WebGLRenderer({
  56. antialias: true,
  57. });
  58. renderer.setSize(this.width, this.height);
  59. renderer.setClearColor(0x000000, 0.4);
  60. this.renderer = renderer;
  61. // 改变相机观察目标
  62. this.camera.aspect = this.width / this.height;
  63. this.camera.updateProjectionMatrix();
  64. // 注意相机控件OrbitControls会影响lookAt设置,注意手动设置OrbitControls的目标参数
  65. const controls = new OrbitControls(this.camera, this.renderer.domElement);
  66. // controls.target = mesh.position;
  67. // controls.update();
  68. controls.addEventListener("change", () => {
  69. this.renderer!.render(this.scene, this.camera);
  70. });
  71. // console.log(this.renderer, dom);
  72. dom.appendChild(renderer.domElement);
  73. this.renderer.render(this.scene, this.camera);
  74. };
  75. loadFBX = (src: string, finish: () => void) => {
  76. const loader = new FBXLoader();
  77. loader.load(
  78. src,
  79. (fbx) => {
  80. console.log("loadFBX", fbx);
  81. this.group.add(fbx);
  82. this.renderer!.render(this.scene, this.camera);
  83. finish();
  84. },
  85. (event) => {
  86. console.log(
  87. "loadFBX" + (event.loaded / event.total) * 100 + "% loaded"
  88. );
  89. },
  90. (error) => {
  91. console.log("loadFBX", error);
  92. finish();
  93. }
  94. );
  95. };
  96. addOutline = (
  97. width: number = this.width,
  98. height: number = this.height,
  99. model?: THREE.Object3D
  100. ) => {
  101. const composer = new EffectComposer(this.renderer!);
  102. const renderPass = new RenderPass(this.scene, this.camera);
  103. const outlinePass = new OutlinePass(
  104. new Vector2(width, height),
  105. this.scene,
  106. this.camera
  107. );
  108. //模型描边颜色,默认白色
  109. outlinePass.visibleEdgeColor.set(0xffff00);
  110. //高亮发光描边厚度
  111. outlinePass.edgeThickness = 4;
  112. //高亮描边发光强度
  113. outlinePass.edgeStrength = 6;
  114. //模型闪烁频率控制,默认0不闪烁
  115. outlinePass.pulsePeriod = 2;
  116. composer.addPass(renderPass);
  117. composer.addPass(outlinePass);
  118. // composer.render();
  119. const that = this;
  120. this.renderer!.domElement.addEventListener("click", function (event) {
  121. // .offsetY、.offsetX以canvas画布左上角为坐标原点,单位px
  122. const px = event.offsetX;
  123. const py = event.offsetY;
  124. //屏幕坐标px、py转WebGL标准设备坐标x、y
  125. //width、height表示canvas画布宽高度
  126. const x = (px / width) * 2 - 1;
  127. const y = -(py / height) * 2 + 1;
  128. //创建一个射线投射器`Raycaster`
  129. const raycaster = new THREE.Raycaster();
  130. //.setFromCamera()计算射线投射器`Raycaster`的射线属性.ray
  131. // 形象点说就是在点击位置创建一条射线,射线穿过的模型代表选中
  132. raycaster.setFromCamera(new THREE.Vector2(x, y), that.camera);
  133. //.intersectObjects([mesh1, mesh2, mesh3])对参数中的网格模型对象进行射线交叉计算
  134. // 未选中对象返回空数组[],选中一个对象,数组1个元素,选中两个对象,数组两个元素
  135. const toAddModelArray = [];
  136. if (model) {
  137. toAddModelArray.push(model);
  138. }
  139. const intersects = raycaster.intersectObjects([
  140. that.mesh,
  141. ...toAddModelArray,
  142. ]);
  143. console.log("射线器返回的对象", intersects);
  144. // intersects.length大于0说明,说明选中了模型
  145. if (intersects.length > 0) {
  146. outlinePass.selectedObjects = [intersects[0].object];
  147. composer.render();
  148. }
  149. });
  150. };
  151. resizeRender = (dom: HTMLElement) => {
  152. this.width = dom.clientWidth;
  153. this.height = dom.clientHeight;
  154. this.renderer!.setSize(this.width, this.height);
  155. this.camera.aspect = this.width / this.height;
  156. this.camera.updateProjectionMatrix();
  157. this.renderer!.render(this.scene, this.camera);
  158. };
  159. private creatCamera = () => {
  160. const camera = new PerspectiveCamera(
  161. 75,
  162. window.innerWidth / window.innerHeight,
  163. 0.1,
  164. 3000
  165. );
  166. camera.position.set(1000, 1000, 1000);
  167. camera.lookAt(0, 0, 0);
  168. return camera;
  169. };
  170. }