import { Raycaster, Scene, Vector3, WebGLRenderer, type Vector, type WebGLRendererParameters } from "three"; import { cZeroVec, GetBox, GetBoxArr } from "./GeUtils"; import { PlaneExt } from "./PlaneExt"; import { CameraType, CameraUpdate } from "webcad_ue4_api"; export class Viewer { m_LookTarget: any; m_Camera: CameraUpdate = new CameraUpdate(); protected NeedUpdate: boolean = true; Renderer: WebGLRenderer;//渲染器 //暂时只用这个类型 m_DomEl: HTMLElement; //画布容器 _Height: number = 0; _Width: number = 0; _Scene: Scene = new Scene(); get Scene() { return this._Scene; } get Fov() { return this.m_Camera.Fov; } set Fov(val: number) { this.m_Camera.Fov = val; this.NeedUpdate = true; } UpdateRender() { this.NeedUpdate = true; } /** * * @param {HTMLElement} canvasContainer 可以传入一个div或者一个画布 * @memberof Viewer */ constructor(canvasContainer: HTMLElement) { this.m_DomEl = canvasContainer; this.initRender(canvasContainer); this.OnSize(); this.StartRender(); window.addEventListener("resize", () => { this.OnSize(); }); this.InitCamera(); } //初始化render initRender(canvasContainer: HTMLElement) { let params: WebGLRendererParameters = { antialias: true,//antialias:true/false是否开启反锯齿 precision: "highp",//precision:highp/mediump/lowp着色精度选择 alpha: true//alpha:true/false是否可以设置背景色透明 }; this.Renderer = new WebGLRenderer(params); //加到画布 canvasContainer.appendChild(this.Renderer.domElement); this.Renderer.autoClear = true; //如果设置,那么它希望所有的纹理和颜色都是预乘的伽玛。默认值为false。 // this.Renderer.gammaInput = true; // this.Renderer.gammaOutput = true; // this.Renderer.shadowMap.enabled = true; // this.Renderer.toneMapping = ReinhardToneMapping; //设置设备像素比。 这通常用于HiDPI设备,以防止模糊输出画布。 this.Renderer.setPixelRatio(window.devicePixelRatio); this.Renderer.physicallyCorrectLights = true; //this.Renderer.toneMappingExposure = Math.pow(1, 5.0); // to allow for very bright scenes. //设置它的背景色为黑色 this.Renderer.setClearColor(0xffffff, 1); this.OnSize(); } InitCamera() { this.m_Camera.CameraType = CameraType.PerspectiveCamera; this.m_Camera.Near = 0.001; this.m_Camera.Camera.far = 1000000000; } OnSize = (width?: number, height?: number) => { this._Width = width ? width : this.m_DomEl.clientWidth; this._Height = height ? height : this.m_DomEl.clientHeight; //校验.成为2的倍数 避免外轮廓错误. if (this._Width % 2 == 1) this._Width -= 1; if (this._Height % 2 == 1) this._Height -= 1; this.Renderer.setSize(this._Width, this._Height); this.m_Camera.SetSize(this._Width, this._Height); }; StartRender = () => { requestAnimationFrame(this.StartRender); if (this._Scene != null && this.NeedUpdate) { this.Render(); this.m_Camera.Update(); this.NeedUpdate = false; } }; Render() { this.Renderer.render(this._Scene, this.m_Camera.Camera); } ScreenToWorld(pt: Vector3, planVec?: Vector3) { //变换和求交点 let plan = new PlaneExt(planVec || new Vector3(0, 0, 1)); let raycaster = new Raycaster(); // 射线从相机射线向屏幕点位置 raycaster.setFromCamera( { x: (pt.x / this._Width) * 2 - 1, y: - (pt.y / this._Height) * 2 + 1 } , this.m_Camera.Camera ); plan.intersectRay(raycaster.ray, pt, true); } WorldToScreen(pt: Vector3) { let widthHalf = this._Width * 0.5; let heightHalf = this._Height * 0.5; pt.project(this.m_Camera.Camera); pt.x = (pt.x * widthHalf) + widthHalf; pt.y = - (pt.y * heightHalf) + heightHalf; } /** * 更新视角观测目标(物体中心) * * @memberof Viewer */ UpdateLockTarget() { let renderList = this.Renderer.renderLists.get(this._Scene, this.m_Camera.Camera); let box = GetBoxArr(renderList.opaque.map(o => o.object)); if (box) this.m_LookTarget = box.getCenter(new Vector3()); else this.m_LookTarget = cZeroVec; } Rotate(mouseMove: Vector3) { this.m_Camera.Rotate(mouseMove, this.m_LookTarget); this.NeedUpdate = true; } RotateAround(movement: Vector3, center: Vector3) { this.m_Camera.Rotate(movement, center); this.NeedUpdate = true; } Pan(mouseMove: Vector3) { this.m_Camera.Pan(mouseMove); this.NeedUpdate = true; } Zoom(scale: number, center?: Vector3) { this.m_Camera.Zoom(scale, center); this.NeedUpdate = true; } ZoomAll() { this.m_Camera.ZoomExtentsBox3(GetBox(this._Scene, true)); this.NeedUpdate = true; } ViewToTop() { this.m_Camera.LookAt(new Vector3(0, 0, -1)); this.NeedUpdate = true; } ViewToFront() { this.m_Camera.LookAt(new Vector3(0, 1, 0)); this.NeedUpdate = true; } ViewToSwiso() { this.m_Camera.LookAt(new Vector3(1, 1, -1)); this.NeedUpdate = true; } }