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; 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( [ ["球", 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; async LoadMetalEnv(): Promise { 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; exrTexture: Texture; async LoadDefaultExr(): Promise { if (this.exrTexture) return this.exrTexture; if (this.exrPromise) return this.exrPromise; this.exrPromise = new Promise((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(); } }