237 lines
7.7 KiB
TypeScript
237 lines
7.7 KiB
TypeScript
|
|
||
|
import { AmbientLight, BoxBufferGeometry, BufferGeometry, ConeBufferGeometry, CubeRefractionMapping, CubeTextureLoader, Geometry, Mesh, MeshPhysicalMaterial, Object3D, SphereBufferGeometry, sRGBEncoding, Texture, TorusBufferGeometry, TorusKnotBufferGeometry } from 'three';
|
||
|
import { Singleton } from './Singleton';
|
||
|
import { Viewer } from './Viewer';
|
||
|
import { PMREMGenerator3 } from './PMREMGenerator2';
|
||
|
import type { PhysicalMaterialRecord, TextureTableRecord } from 'webcad_ue4_api';
|
||
|
import { MaterialEditorCamerControl } from './MaterialMouseControl';
|
||
|
import { ref } from 'vue';
|
||
|
|
||
|
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
|
||
|
{
|
||
|
Geometrys: Map<string, Geometry | BufferGeometry>;
|
||
|
|
||
|
CurGeometryName = ref("球");
|
||
|
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.CameraCtrl.CameraType = CameraType.PerspectiveCamera;
|
||
|
// this.Viewer.UsePass = false;
|
||
|
this.initScene();
|
||
|
new MaterialEditorCamerControl(this.Viewer);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
this.Canvas.appendChild(this.Viewer.Renderer.domElement);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
SetViewer(canvas: HTMLElement)
|
||
|
{
|
||
|
this.Canvas = canvas;
|
||
|
this.initViewer();
|
||
|
this.CurGeometryName.value = "球";
|
||
|
}
|
||
|
initScene()
|
||
|
{
|
||
|
let scene = this.Viewer.Scene;
|
||
|
this.ShowObject = new Object3D();
|
||
|
let geo = this.Geometrys.get(this.CurGeometryName.value);
|
||
|
this.ShowMesh = new Mesh(geo, this._MeshMaterial);
|
||
|
this.ShowMesh.scale.set(1000, 1000, 1000);
|
||
|
|
||
|
this.ShowObject.add(this.ShowMesh);
|
||
|
scene.add(this.ShowObject);
|
||
|
// let remove = autorun(() =>
|
||
|
// {
|
||
|
// let geo = this.Geometrys.get(this.CurGeometryName.get());
|
||
|
// if (geo)
|
||
|
// {
|
||
|
// this.ShowMesh.geometry = geo;
|
||
|
// this.Viewer.UpdateRender();
|
||
|
// }
|
||
|
// });
|
||
|
// end(this as MaterialEditor, this.dispose, remove);
|
||
|
|
||
|
//环境光
|
||
|
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((res, rej) =>
|
||
|
{
|
||
|
let urls = ['right.webp', 'left.webp', 'top.webp', 'bottom.webp', 'front.webp', 'back.webp'];
|
||
|
new CubeTextureLoader().setPath('https://cdn.cfcad.cn/t/house/')
|
||
|
.load(urls, (t) =>
|
||
|
{
|
||
|
t.encoding = sRGBEncoding;
|
||
|
t.mapping = CubeRefractionMapping;
|
||
|
|
||
|
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.Scene.background = new Color(255,0,0);
|
||
|
|
||
|
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 = ['right.webp', 'left.webp', 'top.webp', 'bottom.webp', 'front.webp', 'back.webp'];
|
||
|
new CubeTextureLoader().setPath('https://cdn.cfcad.cn/t/house_gray/')
|
||
|
.load(urls, (t) =>
|
||
|
{
|
||
|
t.encoding = sRGBEncoding;
|
||
|
t.mapping = CubeRefractionMapping;
|
||
|
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;
|
||
|
if (this.Material.map && this.Material.map.Object && this.Material.useMap)
|
||
|
{
|
||
|
let texture = this.Material.map.Object as TextureTableRecord;
|
||
|
await textureRenderUpdate(texture);
|
||
|
}
|
||
|
if (this.Material.bumpMap && this.Material.bumpMap.Object)
|
||
|
{
|
||
|
let texture = this.Material.bumpMap.Object as TextureTableRecord;
|
||
|
await textureRenderUpdate(texture);
|
||
|
}
|
||
|
if (this.Material.roughnessMap && this.Material.roughnessMap.Object)
|
||
|
{
|
||
|
let texture = this.Material.roughnessMap.Object as TextureTableRecord;
|
||
|
await textureRenderUpdate(texture);
|
||
|
}
|
||
|
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();
|
||
|
}
|
||
|
}
|