Files
material-editor/src/stores/sceneStore.ts

215 lines
7.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<PhysicalMaterialRecord>(new PhysicalMaterialRecord());
const _currGeometry = ref<string>('球');
const _currTexture = ref<TextureTableRecord>();
const CurrGeometry = computed({
get: () => _currGeometry.value,
set: (val: string) => ChangeGeometry(val)
})
const CurrTexture = computed<TextureTableRecord>(() => _currTexture.value);
const Geometries = ref<string[]>([]);
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<TextureAdjustment>) {
const record = _currTexture.value;
if (adjustment) {
// 将用户修改的纹理配置项同步写回 TextureTableRecord确保序列化时数据不丢失
if (adjustment.wrapS !== undefined) record.WrapS = adjustment.wrapS;
if (adjustment.wrapT !== undefined) record.WrapT = adjustment.wrapT;
if (adjustment.rotation !== undefined) record.rotation = adjustment.rotation;
if (adjustment.repeatX !== undefined) record.repeatX = adjustment.repeatX;
if (adjustment.repeatY !== undefined) record.repeatY = adjustment.repeatY;
if (adjustment.moveX !== undefined) record.moveX = adjustment.moveX;
if (adjustment.moveY !== undefined) record.moveY = adjustment.moveY;
}
const texture = record['texture'] as Texture;
texture.wrapS = record.WrapS;
texture.wrapT = record.WrapT;
texture.anisotropy = 16;
texture.rotation = record.rotation;
texture.repeat.set(record.repeatX, record.repeatY);
texture.offset.set(record.moveX, 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;
}