169 lines
5.2 KiB
TypeScript
169 lines
5.2 KiB
TypeScript
|
import { Raycaster, Scene, Vector3, WebGLRenderer, type WebGLRendererParameters } from "three";
|
|||
|
import { cZeroVec, GetBox, GetBoxArr } from "./GeUtils";
|
|||
|
import { PlaneExt } from "./PlaneExt";
|
|||
|
import { CameraUpdate } from "webcad_ue4_api";
|
|||
|
import { CameraControls } from "./CameraControls";
|
|||
|
|
|||
|
export class Viewer {
|
|||
|
m_LookTarget: any;
|
|||
|
m_Camera: CameraUpdate = new CameraUpdate();
|
|||
|
CameraCtrl: CameraControls;
|
|||
|
protected NeedUpdate: boolean = true;
|
|||
|
Renderer: WebGLRenderer;//渲染器 //暂时只用这个类型
|
|||
|
m_DomEl: HTMLElement; //画布容器
|
|||
|
|
|||
|
_Height: number = 0;
|
|||
|
_Width: number = 0;
|
|||
|
|
|||
|
_Scene: Scene = new Scene();
|
|||
|
|
|||
|
get Scene() {
|
|||
|
return this._Scene;
|
|||
|
}
|
|||
|
|
|||
|
UpdateRender()
|
|||
|
{
|
|||
|
this.NeedUpdate = true;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
*
|
|||
|
* @param {HTMLElement} canvasContainer 可以传入一个div或者一个画布
|
|||
|
* @memberof Viewer
|
|||
|
*/
|
|||
|
constructor(canvasContainer: HTMLElement) {
|
|||
|
|
|||
|
this.m_DomEl = canvasContainer;
|
|||
|
this.initRender(canvasContainer);
|
|||
|
this.OnSize();
|
|||
|
this.StartRender();
|
|||
|
this.CameraCtrl = new CameraControls(this);
|
|||
|
window.addEventListener("resize", () => {
|
|||
|
this.OnSize();
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
//初始化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();
|
|||
|
}
|
|||
|
|
|||
|
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.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;
|
|||
|
}
|
|||
|
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;
|
|||
|
}
|
|||
|
}
|