import { defineStore } from "pinia"; import { computed, ref } from "vue"; import { MaterialEditor } from "../common/MaterialEditor"; import { Database, PhysicalMaterialRecord, TextureTableRecord } from "webcad_ue4_api"; import { LoadImageFromUrl } from "../helpers/helper.imageLoader"; import { ClampToEdgeWrapping, MirroredRepeatWrapping, RepeatWrapping, Texture } from "three"; import { materialRenderer } from "../common/MaterialRenderer"; import { MaterialIn, MaterialOut } from "../common/MaterialSerializer"; import { GetConfig } from "../lib/libOutputConfig"; import { AsyncDelay } from "../helpers/helper.async"; const sceneSetup = () => { let _editor: MaterialEditor | undefined; let _database: Database | undefined; const _material = ref(new PhysicalMaterialRecord()); const _currGeometry = ref('球'); const _currTexture = ref(); const CurrGeometry = computed({ get: () => _currGeometry.value, set: (val: string) => ChangeGeometry(val) }) const CurrTexture = computed(() => _currTexture.value); const Geometries = ref([]); const Material = computed(() => _material.value); const CurrentShowObject = computed(() => _editor.ShowObject); function Initial(canvas: HTMLElement) { if (_editor) { console.warn("SceneStore has already been initialized"); return; } // 初始化Database _database = new Database(); _database.hm.Enable = false; // 关闭历史记录功能 Material.value.Name = _database.MaterialTable.AllocateName(); // 使用Database为材质分配材质名 _database.MaterialTable.Add(Material.value as PhysicalMaterialRecord); // 为Material配置一个ObjectId,否则其无法被序列化 // Material.value.objectId = new ObjectId(undefined, undefined); _editor = new MaterialEditor(); Geometries.value = Array.from(_editor.Geometrys.keys()); _currGeometry.value = _editor.CurGeometryName; _editor.SetViewer(canvas); _editor.setMaterial((Material.value) as PhysicalMaterialRecord); const view = _editor.Viewer; window.onresize = () => { view.SetSize(canvas.clientWidth, canvas.clientHeight); view.UpdateRender(); } } function Dispose() { Material.value.GoodBye(); _editor?.Dispose(); _editor = undefined; _database.Destroy(); _database = undefined; window.onresize = undefined; } function ChangeGeometry(geoName: string) { _currGeometry.value = geoName; let geo = _editor.Geometrys.get(_currGeometry.value); if (geo) { _editor.ShowMesh.geometry = geo; _editor.Viewer.UpdateRender(); } } function Update() { _editor.Viewer.UpdateRender(); } async function UpdateMaterialAsync() { // TODO: Danger: 如果等待下面这一行,会导致更新卡住(未知问题) Material.value.Update(); // Material.value.Material.needsUpdate = true; await _editor.Update(); Update(); } /** 这是自定义材质更新方法,WebCAD库中的TextureTableRecord.TextureUpdate方法在导出的时候被删除了,所以需要自己实现 */ function UpdateTexture(adjustment?: Partial) { const record = _currTexture.value; const texture = record['texture'] as Texture; texture.wrapS = adjustment?.wrapS ?? record.WrapS; texture.wrapT = adjustment?.wrapT ?? record.WrapT; texture.anisotropy = 16; texture.rotation = adjustment?.rotation ?? record.rotation; texture.repeat.set(adjustment?.repeatX ?? record.repeatX, adjustment?.repeatY ?? record.repeatY); texture.offset.set(adjustment?.moveX ?? record.moveX, adjustment?.moveY ?? record.moveY); texture.needsUpdate = true; Update(); } async function ChangeTextureFromUrlAsync(url?: string) { // 关联贴图 const db = Material.value.Db; // 材质未初始化 if (!db) { console.warn("Material has not been initialized"); return; } // 如果url为空,则保留原有材质中的纹理(修改模式),否则重新实例化纹理对象 let record = Material.value.map?.Object as TextureTableRecord; if (url) { record = new TextureTableRecord(); record.Name = db.TextureTable.AllocateName(); db.TextureTable.Add(record); // 替换map Material.value.map = record.Id; } // 设置Store _currTexture.value = record; const texture = record['texture'] as Texture; if (url) { record.imageUrl = url; texture.image = undefined; } if (!texture.image) { console.warn('Load Image: ', GetConfig().host + '/' + record.imageUrl); const img = await LoadImageFromUrl(GetConfig().host + '/' + record.imageUrl); texture.image = img; } UpdateTexture(); await record.Update(); await AsyncDelay(10); await UpdateMaterialAsync(); } async function SerializeMaterialAsync() { const matJson = MaterialOut(Material.value as PhysicalMaterialRecord); console.log(matJson); return matJson; } async function ImportMaterialAsync(materialJson: string) { const material = MaterialIn(JSON.parse(materialJson)); _material.value = material; _editor.setMaterial(_material.value as PhysicalMaterialRecord); await ChangeTextureFromUrlAsync(); await UpdateMaterialAsync(); } async function GenerateMaterialLogoAsync() { const blob = await materialRenderer.getBlob(Material.value.Material); return blob; // const file = new File([blob], "blob.png", { type: blob.type }); // const formData = new FormData(); // formData.append("file", file); // let data = await Post(ImgsUrl.logo, formData); // let logoPath = ""; // if (data.err_code === RequestStatus.Ok) { // logoPath = data.images.path; // } // return logoPath; } return { CurrGeometry, CurrTexture, Geometries, Material, Initial, Update, UpdateTexture, UpdateMaterialAsync, ChangeTextureFromUrlAsync, SerializeMaterialAsync, ImportMaterialAsync, GenerateMaterialLogoAsync, Dispose, CurrentShowObject, GetEditor: () => _editor }; }; export const useScene = defineStore('scene', sceneSetup); export const useSceneRaw = defineStore('sceneRaw', sceneSetup); // 独立场景,用来静默执行材质序列化 export type TextureAdjustment = { wrapS: number, wrapT: number, rotation: number, repeatX: number, repeatY: number, moveX: number, moveY: number } export interface UploadMaterialRequest { dirId: string; materialName: string; }