material-editor/src/common/MaterialEditor.ts

217 lines
6.9 KiB
TypeScript

import { AmbientLight, BoxBufferGeometry, BufferGeometry, Color, ConeBufferGeometry, CubeRefractionMapping, CubeTextureLoader, FrontSide, Geometry, LinearEncoding, Mesh, MeshPhysicalMaterial, Object3D, SphereBufferGeometry, sRGBEncoding, Texture, TextureLoader, TorusBufferGeometry, TorusKnotBufferGeometry, Vector3 } from 'three';
import { Singleton } from './Singleton';
import { Viewer } from './Viewer';
import { PMREMGenerator3 } from './PMREMGenerator2';
import type { PhysicalMaterialRecord, TextureTableRecord } from 'webcad_ue4_api';
import { MaterialEditorCameraControl } from './MaterialMouseControl';
import { GetConfig } from '../lib/libOutputConfig';
async function textureRenderUpdate(textureRecord:TextureTableRecord){
const texture = textureRecord['texture'] as Texture;
texture.wrapS = textureRecord.WrapS;
texture.wrapT = textureRecord.WrapT;
texture.anisotropy = 16;
texture.rotation = textureRecord.rotation;
texture.repeat.set(textureRecord.repeatX, textureRecord.repeatY);
texture.offset.set(textureRecord.moveX, textureRecord.moveY);
texture.needsUpdate = true;
// for (let f of this.waits)
// f();
// this.waits.length = 0;
//
// this.AsyncUpdated();
}
/**
* 材质编辑器
*/
export class MaterialEditor extends Singleton
{
private _pointerLocked = false;
Geometrys: Map<string, Geometry | BufferGeometry>;
CurGeometryName = "球";
Canvas: HTMLElement;
ShowObject: Object3D;
ShowMesh: Mesh;
Viewer: Viewer;
private _MeshMaterial: MeshPhysicalMaterial = new MeshPhysicalMaterial({});
//构造
private constructor()
{
super();
this.initGeometrys();
this.LoadDefaultExr();
this.LoadMetalEnv();
}
initGeometrys()
{
this.Geometrys = new Map<string, Geometry | BufferGeometry>(
[
["球", new SphereBufferGeometry(1000, 32, 32)],
["圆环", new TorusBufferGeometry(0.8 * 1e3, 0.4 * 1e3, 32, 64)],
["立方体", new BoxBufferGeometry(1e3, 1e3, 1e3, 1, 1, 1)],
["环面纽结", new TorusKnotBufferGeometry(0.7 * 1e3, 0.3 * 1e3, 128, 64)],
["圆锥体", new ConeBufferGeometry(1 * 1e3, 2 * 1e3, 32)],
// ["球(多面)", new SphereBufferGeometry(1 * 1e3, 64, 64)],
// ["立方体(多面)", new BoxBufferGeometry(1 * 1e3, 1 * 1e3, 1 * 1e3, 128, 128, 128)]
]
);
}
initViewer()
{
if (!this.Viewer)
{
this.Viewer = new Viewer(this.Canvas);
// this.Viewer.PreViewer.Cursor.CursorObject.visible = false;
// this.Viewer.UsePass = false;
this.initScene();
new MaterialEditorCameraControl(this.Viewer, this.ShowObject.position);
this.Viewer.ZoomAll();
// 初始化相机位置到观察物体的正后方
// CameraUpdate中的Rotate参数类型并非标准的欧拉角。。。
this.Viewer.RotateAround(new Vector3(0, -90 * 8, 0), this.ShowObject.position);
this.Viewer.Pan(new Vector3(0, 0, -1500));
this.Viewer.UpdateRender();
this.Viewer.Fov = 90;
}
}
SetViewer(canvas: HTMLElement)
{
this.Canvas = canvas;
this.initViewer();
this.CurGeometryName = "球";
}
initScene()
{
let scene = this.Viewer.Scene;
this.ShowObject = new Object3D();
let geo = this.Geometrys.get(this.CurGeometryName);
this.ShowMesh = new Mesh(geo, this._MeshMaterial);
this.ShowMesh.scale.set(1000, 1000, 1000);
this.ShowObject.add(this.ShowMesh);
scene.add(this.ShowObject);
//环境光
let ambient = new AmbientLight();
ambient.intensity = 0.7;
scene.add(ambient);
}
metaTexture: Texture;
metaPromise: Promise<Texture>;
async LoadMetalEnv(): Promise<Texture>
{
if (this.metaTexture) return this.metaTexture;
if (this.metaPromise) return this.metaPromise;
return new Promise(async (res, rej) =>
{
let urls = [...GetConfig().envTextureSrc];
new CubeTextureLoader()
.load(urls, (t) =>
{
t.encoding = sRGBEncoding;
t.mapping = CubeRefractionMapping;
t.encoding = LinearEncoding;
let pmremGenerator = new PMREMGenerator3(this.Viewer.Renderer);
let ldrCubeRenderTarget = pmremGenerator.fromCubemap(t);
this.metaTexture = ldrCubeRenderTarget.texture;
res(this.metaTexture);
this.Viewer.Scene.background = this.metaTexture;
this.Viewer.UpdateRender();
});
});
}
exrPromise: Promise<Texture>;
exrTexture: Texture;
async LoadDefaultExr(): Promise<Texture>
{
if (this.exrTexture) return this.exrTexture;
if (this.exrPromise) return this.exrPromise;
this.exrPromise = new Promise<Texture>((res, rej) =>
{
let urls = [...GetConfig().grayEnvTextureSrc];
new CubeTextureLoader()
.load(urls, (t) =>
{
t.encoding = sRGBEncoding;
t.mapping = CubeRefractionMapping;
t.encoding = LinearEncoding;
let pmremGenerator = new PMREMGenerator3(this.Viewer.Renderer);
let target = pmremGenerator.fromCubemap(t);
this.exrTexture = target.texture;
res(this.exrTexture);
this.Viewer.UpdateRender();
});
});
return this.exrPromise;
}
private Material: PhysicalMaterialRecord;
setMaterial(mat: PhysicalMaterialRecord)
{
this.Material = mat;
this._MeshMaterial.copy(mat.Material);
let mtl = this._MeshMaterial;
if (mtl.metalness > 0.8)
this.LoadMetalEnv().then(env =>
{
mtl.envMap = env;
mtl.needsUpdate = true;
});
else
this.LoadDefaultExr().then(exr =>
{
mtl.envMap = exr;
mtl.needsUpdate = true;
});
this.Update();
}
dispose()
{
}
async Update()
{
let mat = this.ShowMesh.material as MeshPhysicalMaterial;
mat.needsUpdate = true;
this._MeshMaterial.copy(this.Material.Material);
let mtl = this._MeshMaterial;
if (mtl.metalness > 0.8)
this.LoadMetalEnv().then(env =>
{
mtl.envMap = env;
mtl.needsUpdate = true;
});
else
this.LoadDefaultExr().then(exr =>
{
mtl.envMap = exr;
mtl.needsUpdate = true;
});
this.Viewer.UpdateRender();
}
}