244 lines
6.4 KiB
TypeScript
244 lines
6.4 KiB
TypeScript
|
||
import { Mesh, MeshBasicMaterial, Raycaster, Scene, Vector3, WebGLRenderer, WebGLRendererParameters } from "three";
|
||
import { boardMaterial, CameraControls, PointPick, selectMaterial } from ".";
|
||
import { CameraUpdate } from "./CameraUpdate";
|
||
import { ColorMaterial } from "./ColorPalette";
|
||
import { cZeroVec, GetBox, GetBoxArr } from "./GeUtils";
|
||
import { PlaneExt } from "./PlaneExt";
|
||
|
||
export class ViewerSettings
|
||
{
|
||
boardMaterial: MeshBasicMaterial = boardMaterial;
|
||
selectMaterial: MeshBasicMaterial = selectMaterial;
|
||
selectByPointCallback: (meshId: number) => void = () => { };
|
||
}
|
||
|
||
export class Viewer
|
||
{
|
||
m_LookTarget: any;
|
||
m_Camera: CameraUpdate = new CameraUpdate();
|
||
m_CameraCtrl: CameraControls;
|
||
m_bNeedUpdate: boolean = true;
|
||
m_Render: WebGLRenderer;//渲染器 //暂时只用这个类型
|
||
m_DomEl: HTMLElement; //画布容器
|
||
|
||
_Height: number;
|
||
_Width: number;
|
||
|
||
m_Scene: Scene = new Scene();
|
||
|
||
_Settings = new ViewerSettings();
|
||
/**
|
||
*
|
||
* @param {HTMLElement} canvasContainer 可以传入一个div或者一个画布
|
||
* @memberof Viewer
|
||
*/
|
||
constructor(canvasContainer: HTMLElement, setupAction: (settings: ViewerSettings) => void = null)
|
||
{
|
||
if (setupAction)
|
||
{
|
||
setupAction(this._Settings);
|
||
}
|
||
|
||
this.m_DomEl = canvasContainer;
|
||
this.initRender(canvasContainer);
|
||
this.OnSize();
|
||
this.StartRender();
|
||
this.m_CameraCtrl = new CameraControls(this);
|
||
window.addEventListener("resize", () =>
|
||
{
|
||
this.OnSize();
|
||
});
|
||
|
||
this.m_Render.domElement.addEventListener("mousemove", (e: MouseEvent) =>
|
||
{
|
||
this.SelectByPoint(e.offsetX, e.offsetY);
|
||
})
|
||
}
|
||
|
||
//初始化render
|
||
initRender(canvasContainer: HTMLElement)
|
||
{
|
||
let params: WebGLRendererParameters = {
|
||
antialias: true,//antialias:true/false是否开启反锯齿
|
||
precision: "highp",//precision:highp/mediump/lowp着色精度选择
|
||
alpha: true//alpha:true/false是否可以设置背景色透明
|
||
};
|
||
if (canvasContainer instanceof HTMLCanvasElement)
|
||
{
|
||
params.canvas = canvasContainer;
|
||
this.m_Render = new WebGLRenderer(params);
|
||
}
|
||
else
|
||
{
|
||
this.m_Render = new WebGLRenderer(params);
|
||
//加到画布
|
||
canvasContainer.appendChild(this.m_Render.domElement);
|
||
}
|
||
|
||
this.m_Render.autoClear = true;
|
||
|
||
//如果设置,那么它希望所有的纹理和颜色都是预乘的伽玛。默认值为false。
|
||
// this.m_Render.gammaInput = true;
|
||
// this.m_Render.gammaOutput = true;
|
||
// this.m_Render.shadowMap.enabled = true;
|
||
// this.m_Render.toneMapping = ReinhardToneMapping;
|
||
//设置设备像素比。 这通常用于HiDPI设备,以防止模糊输出画布。
|
||
this.m_Render.setPixelRatio(window.devicePixelRatio);
|
||
this.m_Render.physicallyCorrectLights = true;
|
||
//this.m_Render.toneMappingExposure = Math.pow(1, 5.0); // to allow for very bright scenes.
|
||
|
||
//设置它的背景色为黑色
|
||
this.m_Render.setClearColor(0xffffff, 1);
|
||
|
||
|
||
this.OnSize();
|
||
}
|
||
|
||
OnSize = (width?, height?) =>
|
||
{
|
||
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.m_Render.setSize(this._Width, this._Height);
|
||
this.m_Camera.SetSize(this._Width, this._Height);
|
||
}
|
||
|
||
StartRender = () =>
|
||
{
|
||
requestAnimationFrame(this.StartRender);
|
||
if (this.m_Scene != null && this.m_bNeedUpdate)
|
||
{
|
||
this.Render();
|
||
this.m_bNeedUpdate = false;
|
||
}
|
||
}
|
||
Render()
|
||
{
|
||
this.m_Render.render(this.m_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.m_Render.renderLists.get(this.m_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.m_bNeedUpdate = true;
|
||
}
|
||
Pan(mouseMove: Vector3)
|
||
{
|
||
this.m_Camera.Pan(mouseMove);
|
||
this.m_bNeedUpdate = true;
|
||
}
|
||
Zoom(scale: number, center?: Vector3)
|
||
{
|
||
this.m_Camera.Zoom(scale, center);
|
||
this.m_bNeedUpdate = true;
|
||
}
|
||
ZoomAll()
|
||
{
|
||
this.m_Camera.ZoomExtensBox3(GetBox(this.m_Scene, true));
|
||
this.m_bNeedUpdate = true;
|
||
}
|
||
|
||
ViewToTop()
|
||
{
|
||
this.m_Camera.LookAt(new Vector3(0, 0, -1));
|
||
this.m_bNeedUpdate = true;
|
||
}
|
||
ViewToFront()
|
||
{
|
||
this.m_Camera.LookAt(new Vector3(0, 1, 0));
|
||
this.m_bNeedUpdate = true;
|
||
}
|
||
ViewToSwiso()
|
||
{
|
||
this.m_Camera.LookAt(new Vector3(1, 1, -1));
|
||
this.m_bNeedUpdate = true;
|
||
}
|
||
|
||
oldMesh: Mesh;
|
||
SelectByPoint(x: number, y: number)
|
||
{
|
||
let mesh = PointPick(this, x, y);
|
||
if (this.oldMesh)
|
||
this.oldMesh.material = this._Settings.boardMaterial;
|
||
if (mesh && mesh.material !== ColorMaterial.GetBasicMaterial(1))
|
||
{
|
||
this.oldMesh = mesh;
|
||
mesh.material = this._Settings.selectMaterial;
|
||
if (this._Settings.selectByPointCallback)
|
||
{
|
||
this._Settings.selectByPointCallback(mesh.id);
|
||
}
|
||
}
|
||
this.m_bNeedUpdate = true;
|
||
}
|
||
SelectBlock(blockMeshMap: Map<number, number>, dataID: number)
|
||
{
|
||
if (blockMeshMap.has(dataID))
|
||
{
|
||
let meshId = blockMeshMap.get(dataID);
|
||
if (this.oldMesh)
|
||
this.oldMesh.material = this._Settings.boardMaterial;
|
||
this.m_Scene.children.forEach(obj =>
|
||
{
|
||
if (obj instanceof Mesh)
|
||
{
|
||
if (obj.id == meshId)
|
||
{
|
||
this.oldMesh = obj;
|
||
obj.material = this._Settings.selectMaterial;
|
||
this.m_bNeedUpdate = true;
|
||
}
|
||
}
|
||
|
||
})
|
||
}
|
||
}
|
||
}
|