123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- import * as THREE from "three";
- import {
- AxesHelper,
- BoxGeometry,
- Mesh,
- MeshLambertMaterial,
- PerspectiveCamera,
- Vector2,
- } from "three";
- import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
- import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer";
- import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass";
- import { OutlinePass } from "three/examples/jsm/postprocessing/OutlinePass";
- import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader";
- export default class ThreeHelper {
- width: number = 0;
- height: number = 0;
- group: THREE.Group;
- geometry: THREE.BoxGeometry;
- material: THREE.MeshLambertMaterial;
- mesh: THREE.Mesh;
- camera: THREE.PerspectiveCamera;
- axesHelper: THREE.AxesHelper;
- scene: THREE.Scene;
- light: THREE.PointLight;
- renderer: THREE.WebGLRenderer | null = null;
- constructor() {
- this.group = new THREE.Group();
- this.geometry = new BoxGeometry(60, 90, 80);
- this.material = new MeshLambertMaterial({
- color: 0x009900,
- transparent: true,
- opacity: 0.5,
- });
- this.mesh = new Mesh(this.geometry, this.material);
- this.group.add(this.mesh);
- this.camera = this.creatCamera();
- this.axesHelper = new AxesHelper(400);
- this.light = this.creatLight();
- this.scene = new THREE.Scene();
- this.scene.add(this.group);
- this.scene.add(this.axesHelper);
- this.scene.add(this.light);
- }
- creatLight = () => {
- const light = new THREE.PointLight(0xffffff, 1.0);
- light.intensity = 300.0; //光照强度
- light.decay = 0.0; //设置光源不随距离衰减
- light.position.set(1000, 1000, 1000);
- return light;
- };
- creatRenderer = (dom: HTMLElement) => {
- this.width = dom.clientWidth;
- this.height = dom.clientHeight;
- const renderer: THREE.WebGLRenderer = new THREE.WebGLRenderer({
- antialias: true,
- });
- renderer.setSize(this.width, this.height);
- renderer.setClearColor(0x000000, 0.4);
- this.renderer = renderer;
- // 改变相机观察目标
- this.camera.aspect = this.width / this.height;
- this.camera.updateProjectionMatrix();
- // 注意相机控件OrbitControls会影响lookAt设置,注意手动设置OrbitControls的目标参数
- const controls = new OrbitControls(this.camera, this.renderer.domElement);
- // controls.target = mesh.position;
- // controls.update();
- controls.addEventListener("change", () => {
- this.renderer!.render(this.scene, this.camera);
- });
- // console.log(this.renderer, dom);
- dom.appendChild(renderer.domElement);
- this.renderer.render(this.scene, this.camera);
- };
- loadFBX = (src: string, finish: () => void) => {
- const loader = new FBXLoader();
- loader.load(
- src,
- (fbx) => {
- console.log("loadFBX", fbx);
- this.group.add(fbx);
- this.renderer!.render(this.scene, this.camera);
- finish();
- },
- (event) => {
- console.log(
- "loadFBX" + (event.loaded / event.total) * 100 + "% loaded"
- );
- },
- (error) => {
- console.log("loadFBX", error);
- finish();
- }
- );
- };
- addOutline = (
- width: number = this.width,
- height: number = this.height,
- model?: THREE.Object3D
- ) => {
- const composer = new EffectComposer(this.renderer!);
- const renderPass = new RenderPass(this.scene, this.camera);
- const outlinePass = new OutlinePass(
- new Vector2(width, height),
- this.scene,
- this.camera
- );
- //模型描边颜色,默认白色
- outlinePass.visibleEdgeColor.set(0xffff00);
- //高亮发光描边厚度
- outlinePass.edgeThickness = 4;
- //高亮描边发光强度
- outlinePass.edgeStrength = 6;
- //模型闪烁频率控制,默认0不闪烁
- outlinePass.pulsePeriod = 2;
- composer.addPass(renderPass);
- composer.addPass(outlinePass);
- // composer.render();
- const that = this;
- this.renderer!.domElement.addEventListener("click", function (event) {
- // .offsetY、.offsetX以canvas画布左上角为坐标原点,单位px
- const px = event.offsetX;
- const py = event.offsetY;
- //屏幕坐标px、py转WebGL标准设备坐标x、y
- //width、height表示canvas画布宽高度
- const x = (px / width) * 2 - 1;
- const y = -(py / height) * 2 + 1;
- //创建一个射线投射器`Raycaster`
- const raycaster = new THREE.Raycaster();
- //.setFromCamera()计算射线投射器`Raycaster`的射线属性.ray
- // 形象点说就是在点击位置创建一条射线,射线穿过的模型代表选中
- raycaster.setFromCamera(new THREE.Vector2(x, y), that.camera);
- //.intersectObjects([mesh1, mesh2, mesh3])对参数中的网格模型对象进行射线交叉计算
- // 未选中对象返回空数组[],选中一个对象,数组1个元素,选中两个对象,数组两个元素
- const toAddModelArray = [];
- if (model) {
- toAddModelArray.push(model);
- }
- const intersects = raycaster.intersectObjects([
- that.mesh,
- ...toAddModelArray,
- ]);
- console.log("射线器返回的对象", intersects);
- // intersects.length大于0说明,说明选中了模型
- if (intersects.length > 0) {
- outlinePass.selectedObjects = [intersects[0].object];
- composer.render();
- }
- });
- };
- resizeRender = (dom: HTMLElement) => {
- this.width = dom.clientWidth;
- this.height = dom.clientHeight;
- this.renderer!.setSize(this.width, this.height);
- this.camera.aspect = this.width / this.height;
- this.camera.updateProjectionMatrix();
- this.renderer!.render(this.scene, this.camera);
- };
- private creatCamera = () => {
- const camera = new PerspectiveCamera(
- 75,
- window.innerWidth / window.innerHeight,
- 0.1,
- 3000
- );
- camera.position.set(1000, 1000, 1000);
- camera.lookAt(0, 0, 0);
- return camera;
- };
- }
|