215 lines
7.6 KiB
TypeScript
215 lines
7.6 KiB
TypeScript
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;
|
||
} |