mirror of https://gitee.com/cf-fz/WebCAD.git
!2588 功能:导入fbx资源文件
parent
e9399667f9
commit
dfc5f61b2a
@ -0,0 +1,255 @@
|
|||||||
|
import { Intent } from "@blueprintjs/core";
|
||||||
|
import { MathUtils, Matrix4, Vector3 } from "three";
|
||||||
|
import { app } from "../ApplicationServices/Application";
|
||||||
|
import { FS } from "../Common/FileSystem";
|
||||||
|
import { FBXURL } from "../Common/HostUrl";
|
||||||
|
import { Log, LogType } from "../Common/Log";
|
||||||
|
import { PostJson, RequestStatus } from "../Common/Request";
|
||||||
|
import { UpdateDraw } from "../Common/Status";
|
||||||
|
import { CADFiler } from "../DatabaseServices/CADFiler";
|
||||||
|
import { EntityFbx } from "../DatabaseServices/Entity/EntityFbx";
|
||||||
|
import { TemplateEntityRef } from "../DatabaseServices/Template/ProgramTempate/TemplateEntityRef";
|
||||||
|
import { CommandWrap } from "../Editor/CommandMachine";
|
||||||
|
import { JigUtils } from "../Editor/JigUtils";
|
||||||
|
import { PromptStatus } from "../Editor/PromptResult";
|
||||||
|
import { TempEditor } from "../Editor/TempEditor";
|
||||||
|
import { ParsePlacePos } from "../Editor/TranstrolControl/ParsePlacePos";
|
||||||
|
import { AppToaster, ShowLinesToaster } from "../UI/Components/Toaster";
|
||||||
|
import { TopPanelStore } from "../UI/Store/TopPanelStore";
|
||||||
|
|
||||||
|
export class Command_FBXImport
|
||||||
|
{
|
||||||
|
async exec()
|
||||||
|
{
|
||||||
|
if (TempEditor.EditorIng)
|
||||||
|
{
|
||||||
|
AppToaster.show({
|
||||||
|
message: "当前正处于编辑模式下",
|
||||||
|
timeout: 3000,
|
||||||
|
intent: Intent.WARNING,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FS.ChooseFile({
|
||||||
|
filter: ".fbx",
|
||||||
|
multiple: false,
|
||||||
|
callback: async files =>
|
||||||
|
{
|
||||||
|
let f = files.item(0);
|
||||||
|
await FbxImport(f);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function FbxImport(f: File)
|
||||||
|
{
|
||||||
|
let ext = FS.getFileExtension(f.name);
|
||||||
|
let fbxArr: ArrayBuffer;
|
||||||
|
if (ext === "fbx")
|
||||||
|
fbxArr = await f.arrayBuffer();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AppToaster.show({
|
||||||
|
message: `文件类型错误,不是FBX文件`,
|
||||||
|
intent: Intent.WARNING,
|
||||||
|
timeout: 1000,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cameraFiler = new CADFiler;
|
||||||
|
let fbxEnt = new EntityFbx();
|
||||||
|
let errorMsg = fbxEnt.LoadFBXModelFromArrayBuffer(fbxArr);
|
||||||
|
if (errorMsg)
|
||||||
|
{
|
||||||
|
AppToaster.show({
|
||||||
|
message: errorMsg,
|
||||||
|
timeout: 2000,
|
||||||
|
intent: Intent.DANGER,
|
||||||
|
});
|
||||||
|
Log(errorMsg, LogType.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TempEditor.Start();
|
||||||
|
|
||||||
|
CommandWrap(() =>
|
||||||
|
{
|
||||||
|
app.Database.ModelSpace.Append(fbxEnt);
|
||||||
|
}, "");
|
||||||
|
|
||||||
|
app.Database.hm.lockIndex++;//禁止初始化动作被撤销
|
||||||
|
app.Viewer.CameraCtrl.WriteFile(cameraFiler);
|
||||||
|
|
||||||
|
let isUpLoad = false;
|
||||||
|
|
||||||
|
ShowLinesToaster(
|
||||||
|
["是否上传FBX数据?"],
|
||||||
|
{
|
||||||
|
intent: Intent.PRIMARY,
|
||||||
|
timeout: 0,
|
||||||
|
action:
|
||||||
|
{
|
||||||
|
onClick: () => { isUpLoad = true; },
|
||||||
|
text: "上传",
|
||||||
|
},
|
||||||
|
onDismiss: async () =>
|
||||||
|
{
|
||||||
|
await EndEditor();
|
||||||
|
}
|
||||||
|
}, "upLoad_FBX");
|
||||||
|
|
||||||
|
async function EndEditor()
|
||||||
|
{
|
||||||
|
const hashBuffer = await crypto.subtle.digest("SHA-1", fbxArr);
|
||||||
|
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
||||||
|
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "")).join("");
|
||||||
|
|
||||||
|
const shopId = TopPanelStore.GetInstance().shopId;
|
||||||
|
|
||||||
|
let ent = fbxEnt.Clone();
|
||||||
|
ent.Url = `/${shopId}/${hashHex}`;
|
||||||
|
|
||||||
|
app.Viewer.CameraCtrl.ReadFile(cameraFiler);
|
||||||
|
await app.Editor.ModalManage.EndExecingCmd();
|
||||||
|
TempEditor.End();
|
||||||
|
app.Editor.MaskManage.Clear();
|
||||||
|
|
||||||
|
if (isUpLoad)
|
||||||
|
{
|
||||||
|
const data = await PostJson(FBXURL, { path: `UsrFbxs/${shopId}/${hashHex}` });
|
||||||
|
if (data.err_code != RequestStatus.Ok) return;
|
||||||
|
|
||||||
|
const text = new Uint8Array(fbxArr);
|
||||||
|
const blob = new Blob([text], { type: 'text/plain' });
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('OSSAccessKeyId', data.sign.accessid);
|
||||||
|
formData.append('policy', data.sign.policy);
|
||||||
|
formData.append('success_action_status', '200');
|
||||||
|
formData.append('Signature', data.sign.signature);
|
||||||
|
formData.append('key', `UsrFbxs/${shopId}/${hashHex}`);
|
||||||
|
formData.append('Expires', data.sign.expire);
|
||||||
|
formData.append('file', blob, `${f.name}`);
|
||||||
|
|
||||||
|
let res = await fetch(data.sign.host, {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.status === 200)
|
||||||
|
{
|
||||||
|
AppToaster.show({
|
||||||
|
message: "FBX数据上传成功",
|
||||||
|
timeout: 3000,
|
||||||
|
intent: Intent.SUCCESS
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AppToaster.show({
|
||||||
|
message: "FBX数据上传失败",
|
||||||
|
timeout: 3000,
|
||||||
|
intent: Intent.DANGER,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandWrap(async () =>
|
||||||
|
{
|
||||||
|
JigUtils.Draw(ent);
|
||||||
|
app.Editor.MouseCtrl.EnableMouseUpDoit = true; //响应鼠标抬起就绘制
|
||||||
|
|
||||||
|
let move = new Vector3;
|
||||||
|
let isCopy = false;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
//关闭捕捉
|
||||||
|
let snapBak = app.Editor.GetPointServices.snapServices.SnapModeEnable;
|
||||||
|
app.Editor.GetPointServices.snapServices.SnapModeEnable = 0;
|
||||||
|
|
||||||
|
let ptRes = await app.Editor.GetPoint({
|
||||||
|
Msg: "请点击放置位置(按住Ctrl强制穿透):",
|
||||||
|
Raycast: true,
|
||||||
|
RaycastFilter: { selectFreeze: true },
|
||||||
|
Callback: (p, i) =>
|
||||||
|
{
|
||||||
|
if (i)
|
||||||
|
new ParsePlacePos(ent, i);
|
||||||
|
else
|
||||||
|
ent.Position = p;
|
||||||
|
},
|
||||||
|
KeyWordList: [
|
||||||
|
{ key: "B", msg: "基点" },
|
||||||
|
{ key: "CO", msg: isCopy ? "不复制" : "复制" },
|
||||||
|
{ key: "R", msg: "旋转" },
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
app.Editor.GetPointServices.snapServices.SnapModeEnable = snapBak;
|
||||||
|
app.Editor.MouseCtrl.EnableMouseUpDoit = false;
|
||||||
|
|
||||||
|
if (ptRes.Status === PromptStatus.OK)
|
||||||
|
{
|
||||||
|
if (ptRes.intersection)
|
||||||
|
new ParsePlacePos(ent, ptRes.intersection);
|
||||||
|
else
|
||||||
|
ent.Position = ptRes.Point.add(move);
|
||||||
|
|
||||||
|
app.Database.ModelSpace.Append(ent);
|
||||||
|
|
||||||
|
let tr = new TemplateEntityRef;
|
||||||
|
app.Database.TemplateTable.Append(tr);
|
||||||
|
tr.Objects.push(ent.Id);
|
||||||
|
tr.InitBaseParams();
|
||||||
|
|
||||||
|
if (isCopy)
|
||||||
|
{
|
||||||
|
ent = ent.Clone();
|
||||||
|
JigUtils.Draw(ent);
|
||||||
|
}
|
||||||
|
else return;
|
||||||
|
}
|
||||||
|
else if (ptRes.Status === PromptStatus.Keyword)
|
||||||
|
{
|
||||||
|
if (ptRes.StringResult === "R")
|
||||||
|
{
|
||||||
|
let ocsBack = ent.OCS;
|
||||||
|
let anRes = await app.Editor.GetAngle({
|
||||||
|
Msg: "指定旋转角度",
|
||||||
|
Callback: (newan: number) =>
|
||||||
|
{
|
||||||
|
ent.OCS = new Matrix4().makeRotationZ(MathUtils.degToRad(newan)).setPosition(ent.Position);
|
||||||
|
ent.Update(UpdateDraw.Matrix);
|
||||||
|
},
|
||||||
|
BasePoint: ent.Position,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (anRes.Status === PromptStatus.OK)
|
||||||
|
ent.OCS = new Matrix4().makeRotationZ(MathUtils.degToRad(anRes.Distance)).setPosition(ent.Position);
|
||||||
|
else
|
||||||
|
ent.OCS = ocsBack;
|
||||||
|
|
||||||
|
ent.Update(UpdateDraw.Matrix);
|
||||||
|
}
|
||||||
|
else if (ptRes.StringResult === "B")
|
||||||
|
{
|
||||||
|
let ptRes = await app.Editor.GetPoint({ Msg: "指定基点" });
|
||||||
|
if (ptRes.Status === PromptStatus.OK)
|
||||||
|
move = ent.Position.sub(ptRes.Point);
|
||||||
|
else if (ptRes.Status === PromptStatus.Cancel) return;
|
||||||
|
}
|
||||||
|
else if (ptRes.StringResult === "CO")
|
||||||
|
{
|
||||||
|
isCopy = !isCopy;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}, "fbx插入");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,517 @@
|
|||||||
|
import { Box3, Group, Matrix3, Matrix4, Mesh, MeshPhongMaterial, Object3D, Vector3 } from "three";
|
||||||
|
import { BoxLine } from "../../Add-on/testEntity/BoxLine";
|
||||||
|
import { GenerateCdnUrl } from "../../Add-on/testEntity/GenerateCdnUrl";
|
||||||
|
import { GetDefultFBXMaterial, UE_FBX_LOADER } from "../../Add-on/testEntity/ParseMaterialImage";
|
||||||
|
import { HostApplicationServices } from "../../ApplicationServices/HostApplicationServices";
|
||||||
|
import { ColorMaterial } from "../../Common/ColorPalette";
|
||||||
|
import { DisposeThreeObj, Object3DRemoveAll } from "../../Common/Dispose";
|
||||||
|
import { Log, LogType } from "../../Common/Log";
|
||||||
|
import { UpdateDraw } from "../../Common/Status";
|
||||||
|
import { ObjectSnapMode } from "../../Editor/ObjectSnapMode";
|
||||||
|
import { Box3Ext } from "../../Geometry/Box";
|
||||||
|
import { equalv3 } from "../../Geometry/GeUtils";
|
||||||
|
import { RenderType } from "../../GraphicsSystem/RenderType";
|
||||||
|
import { IndexedDbStore, StoreName } from "../../IndexedDb/IndexedDbStore";
|
||||||
|
import { Factory } from "../CADFactory";
|
||||||
|
import { CADFiler } from "../CADFiler";
|
||||||
|
import { ObjectId } from "../ObjectId";
|
||||||
|
import { PhysicalMaterialRecord } from "../PhysicalMaterialRecord";
|
||||||
|
import { GetBoxGeoBufferGeometry } from "./BoxSolid";
|
||||||
|
import { Entity } from "./Entity";
|
||||||
|
import { GenUVForWorld } from "./GenUVForWorld";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 外部引用的实体,比如glTF
|
||||||
|
*/
|
||||||
|
@Factory
|
||||||
|
export class EntityFbx extends Entity
|
||||||
|
{
|
||||||
|
OnlyRenderType = true;
|
||||||
|
|
||||||
|
private _Size = new Vector3;//原始尺寸
|
||||||
|
private _ScaleSize = new Vector3;//缩放后的尺寸
|
||||||
|
private _Center = new Vector3;//盒子中心
|
||||||
|
|
||||||
|
private _OverWriteMaterial = new Map<number, ObjectId<PhysicalMaterialRecord>>();//section index -> materialId
|
||||||
|
|
||||||
|
constructor(private _url?: string)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
override get IsVisible()
|
||||||
|
{
|
||||||
|
return HostApplicationServices.IsRoomEntityVisible && super.IsVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
get Url() { return this._url; }
|
||||||
|
set Url(url: string)
|
||||||
|
{
|
||||||
|
if (this._url !== url)
|
||||||
|
{
|
||||||
|
this.WriteAllObjectRecord();
|
||||||
|
this._url = url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get CurSize() { return this.ScaleSize.x ? this.ScaleSize.clone() : this._Size.clone(); }
|
||||||
|
|
||||||
|
get ScaleSize() { return this._ScaleSize; }
|
||||||
|
set ScaleSize(size: Vector3)
|
||||||
|
{
|
||||||
|
if (!equalv3(size, this.ScaleSize.x ? this.ScaleSize : this._Size))
|
||||||
|
{
|
||||||
|
this.WriteAllObjectRecord();
|
||||||
|
if (this._ScaleSize.x && equalv3(size, this._Size))
|
||||||
|
this._ScaleSize.set(0, 0, 0);
|
||||||
|
else
|
||||||
|
this._ScaleSize.copy(size);
|
||||||
|
this.Update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get Scale()
|
||||||
|
{
|
||||||
|
if (this._ScaleSize.x && this._Size.x)
|
||||||
|
return this._ScaleSize.clone().divide(this._Size);
|
||||||
|
return new Vector3(1, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
get BoundingBox()
|
||||||
|
{
|
||||||
|
return this.BoundingBoxInOCS.applyMatrix4(this.OCSNoClone);
|
||||||
|
}
|
||||||
|
|
||||||
|
get BoundingBoxInOCS()
|
||||||
|
{
|
||||||
|
let box = new Box3Ext(
|
||||||
|
this._Size.clone().multiplyScalar(-0.5).add(this._Center),
|
||||||
|
this._Size.clone().multiplyScalar(0.5).add(this._Center));
|
||||||
|
|
||||||
|
if (this._ScaleSize.x)
|
||||||
|
{
|
||||||
|
box.applyMatrix4(new Matrix4().makeScale(
|
||||||
|
this._ScaleSize.x / this._Size.x,
|
||||||
|
this._ScaleSize.y / this._Size.y,
|
||||||
|
this._ScaleSize.z / this._Size.z,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return box;
|
||||||
|
}
|
||||||
|
get OverWriteMaterial()
|
||||||
|
{
|
||||||
|
return this._OverWriteMaterial;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetMaterialAtSlot(mtl: ObjectId<PhysicalMaterialRecord>, slotIndex: number)
|
||||||
|
{
|
||||||
|
if (this._OverWriteMaterial.get(slotIndex) !== mtl)
|
||||||
|
{
|
||||||
|
this.WriteAllObjectRecord();
|
||||||
|
this._OverWriteMaterial.set(slotIndex, mtl);
|
||||||
|
this.Update(UpdateDraw.Material);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newObject: Group;
|
||||||
|
|
||||||
|
//通过二进制数组生成fbx模型
|
||||||
|
LoadFBXModelFromArrayBuffer(fbxArray: ArrayBuffer)
|
||||||
|
{
|
||||||
|
let obj: Group;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
obj = UE_FBX_LOADER.parse(fbxArray, UE_FBX_LOADER.path);
|
||||||
|
}
|
||||||
|
catch (error)
|
||||||
|
{
|
||||||
|
return "错误:FBX资源无法解析";
|
||||||
|
}
|
||||||
|
|
||||||
|
this.newObject = obj;
|
||||||
|
this.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
CloneDrawObject(from: this)
|
||||||
|
{
|
||||||
|
for (let [type, obj] of from._CacheDrawObject)
|
||||||
|
{
|
||||||
|
let oldUserDaata = obj.userData;
|
||||||
|
obj.traverse(o => o.userData = {});
|
||||||
|
let newObj = obj.clone();
|
||||||
|
|
||||||
|
newObj.traverse(o =>
|
||||||
|
{
|
||||||
|
if (o instanceof Mesh)
|
||||||
|
{
|
||||||
|
if (Array.isArray(o.material))
|
||||||
|
o.material = [...o.material];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
obj.userData = oldUserDaata;
|
||||||
|
|
||||||
|
newObj.matrix = this._Matrix;
|
||||||
|
newObj.userData = { Entity: this };
|
||||||
|
this._CacheDrawObject.set(type, newObj);
|
||||||
|
}
|
||||||
|
this.NeedUpdateFlag = UpdateDraw.None;
|
||||||
|
}
|
||||||
|
ApplyScaleMatrix(m: Matrix4)
|
||||||
|
{
|
||||||
|
this.WriteAllObjectRecord();
|
||||||
|
let p = this.Position;
|
||||||
|
p.applyMatrix4(m);
|
||||||
|
|
||||||
|
m.extractBasis(Entity._xa, Entity._ya, Entity._za);
|
||||||
|
|
||||||
|
let scaleX = Entity._xa.length();
|
||||||
|
let scaleY = Entity._ya.length();
|
||||||
|
let scaleZ = Entity._za.length();
|
||||||
|
|
||||||
|
if (!this._ScaleSize.x) this._ScaleSize.copy(this._Size);
|
||||||
|
|
||||||
|
this._ScaleSize.x *= scaleX;
|
||||||
|
this._ScaleSize.y *= scaleY;
|
||||||
|
this._ScaleSize.z *= scaleZ;
|
||||||
|
|
||||||
|
Entity._xa.normalize();
|
||||||
|
Entity._ya.normalize();
|
||||||
|
Entity._za.normalize();
|
||||||
|
m = new Matrix4().makeBasis(Entity._xa, Entity._ya, Entity._za);
|
||||||
|
this.ApplyMatrix(m);
|
||||||
|
|
||||||
|
this.Position = p;
|
||||||
|
this.Update();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
InitDrawObject(renderType: RenderType = RenderType.Wireframe)
|
||||||
|
{
|
||||||
|
if (renderType > 100) return;//避免CTRL+P 无法打印(首次开图,同时选墙和窗)
|
||||||
|
if (!this._url && !this.newObject) return;//没有url或newObject,无法初始化
|
||||||
|
|
||||||
|
let dObj = new Object3D();
|
||||||
|
|
||||||
|
const GetMaterial = (m: MeshPhongMaterial, index?: number) =>
|
||||||
|
{
|
||||||
|
let overMtl = this._OverWriteMaterial.get(index);
|
||||||
|
if (overMtl?.Object?.Material)
|
||||||
|
return overMtl.Object.Material;
|
||||||
|
else
|
||||||
|
return GetDefultFBXMaterial();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.newObject)
|
||||||
|
{
|
||||||
|
let gen = new GenUVForWorld;
|
||||||
|
this.newObject.traverse(async o =>
|
||||||
|
{
|
||||||
|
if (o instanceof Mesh)
|
||||||
|
{
|
||||||
|
o.geometry["IsMesh"] = true;
|
||||||
|
|
||||||
|
o.castShadow = true;
|
||||||
|
o.receiveShadow = true;
|
||||||
|
|
||||||
|
if (Array.isArray(o.material))
|
||||||
|
o.material = o.material.map(GetMaterial);
|
||||||
|
else
|
||||||
|
o.material = GetMaterial(o.material);
|
||||||
|
|
||||||
|
gen.GenUV(o);
|
||||||
|
|
||||||
|
this.AsyncUpdated();//保证更新视图
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//缩放尺寸(如果用户指定了这个缩放 我们就缩放它)
|
||||||
|
if (this._ScaleSize.x)
|
||||||
|
this.newObject.scale.copy(this._ScaleSize).divide(this._Size).multiplyScalar(10);
|
||||||
|
else
|
||||||
|
this.newObject.scale.set(10, 10, 10);//UE4缩放10 如果按米为单位的缩放1000
|
||||||
|
|
||||||
|
dObj.add(this.newObject);
|
||||||
|
|
||||||
|
this.newObject.updateMatrix();//保证更新缩放
|
||||||
|
this.newObject.updateMatrixWorld(false);//保证更新位置
|
||||||
|
|
||||||
|
const boundingBox = new Box3().expandByObject(this.newObject);
|
||||||
|
boundingBox.getSize(this._Size);
|
||||||
|
boundingBox.getCenter(this._Center);
|
||||||
|
this.AsyncUpdated();//保证更新视图
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
let previewBoxMesh = new Mesh(GetBoxGeoBufferGeometry(), ColorMaterial.GetBasicMaterialTransparent(7, 0.3));
|
||||||
|
//显示预览盒子,顺便请求模型的原始尺寸,以便我们开图就能有预览效果
|
||||||
|
if (this._Size.x)
|
||||||
|
{
|
||||||
|
previewBoxMesh.scale.copy(this._ScaleSize.x ? this._ScaleSize : this._Size);
|
||||||
|
previewBoxMesh.position.copy(this._Center);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
previewBoxMesh.position.set(0, 0, 150);
|
||||||
|
previewBoxMesh.scale.set(300, 300, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
previewBoxMesh.updateMatrix();
|
||||||
|
previewBoxMesh.updateMatrixWorld(false);//保证更新位置
|
||||||
|
dObj.add(previewBoxMesh);
|
||||||
|
|
||||||
|
IndexedDbStore.CADStore().then(async store =>
|
||||||
|
{
|
||||||
|
let array = await store.Get(StoreName.FBX, this._url) as ArrayBuffer;
|
||||||
|
let needSave = false;
|
||||||
|
if (!array)
|
||||||
|
{
|
||||||
|
needSave = true;
|
||||||
|
|
||||||
|
let fbxurl = GenerateCdnUrl(`/UsrFbxs${this._url}`, false);
|
||||||
|
let res = await fetch(fbxurl);
|
||||||
|
|
||||||
|
if (res.status === 200)
|
||||||
|
array = await res.arrayBuffer();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
let errorMsg = "错误:网络异常或者服务端资源不存在!无法请求到服务器FBX资源:" + this._url;
|
||||||
|
Log(errorMsg, LogType.Error, [this]);
|
||||||
|
//TODO:模型请求失败 是不是应该做点什么 过会重试?
|
||||||
|
reportError(errorMsg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.newObject = UE_FBX_LOADER.parse(array, UE_FBX_LOADER.path);
|
||||||
|
}
|
||||||
|
catch (error)
|
||||||
|
{
|
||||||
|
let errorMsg = "错误:FBX资源无法解析:" + this._url;
|
||||||
|
Log(errorMsg, LogType.Error, [this]);
|
||||||
|
reportError(new Error(errorMsg));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (needSave)
|
||||||
|
store.Put(StoreName.FBX, this.Url, array);
|
||||||
|
|
||||||
|
DisposeThreeObj(dObj);
|
||||||
|
Object3DRemoveAll(dObj);
|
||||||
|
|
||||||
|
let gen = new GenUVForWorld;
|
||||||
|
|
||||||
|
this.newObject.traverse(async o =>
|
||||||
|
{
|
||||||
|
if (o instanceof Mesh)
|
||||||
|
{
|
||||||
|
o.geometry["IsMesh"] = true;
|
||||||
|
|
||||||
|
o.castShadow = true;
|
||||||
|
o.receiveShadow = true;
|
||||||
|
|
||||||
|
if (Array.isArray(o.material))
|
||||||
|
o.material = o.material.map(GetMaterial);
|
||||||
|
else
|
||||||
|
o.material = GetMaterial(o.material);
|
||||||
|
|
||||||
|
gen.GenUV(o);
|
||||||
|
|
||||||
|
this.AsyncUpdated();//保证更新视图
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dObj.add(this.newObject);
|
||||||
|
|
||||||
|
//缩放尺寸(如果用户指定了这个缩放 我们就缩放它)
|
||||||
|
if (this._ScaleSize.x)
|
||||||
|
this.newObject.scale.copy(this._ScaleSize).divide(this._Size).multiplyScalar(10);
|
||||||
|
else
|
||||||
|
this.newObject.scale.set(10, 10, 10);//UE4缩放10 如果按米为单位的缩放1000
|
||||||
|
|
||||||
|
this.newObject.updateMatrix();//保证更新缩放
|
||||||
|
this.newObject.updateMatrixWorld(false);//保证更新位置
|
||||||
|
|
||||||
|
const boundingBox = new Box3().expandByObject(this.newObject);
|
||||||
|
boundingBox.getSize(this._Size);
|
||||||
|
boundingBox.getCenter(this._Center);
|
||||||
|
this.AsyncUpdated();//保证更新视图
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return dObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateDrawObject(type: RenderType, obj: Object3D)
|
||||||
|
{
|
||||||
|
let newObject = obj.children[0];
|
||||||
|
|
||||||
|
//缩放尺寸(如果用户指定了这个缩放 我们就缩放它)
|
||||||
|
if (this._ScaleSize.x && this._Size.x)
|
||||||
|
newObject.scale.copy(this._ScaleSize).divide(this._Size).multiplyScalar(10);
|
||||||
|
else
|
||||||
|
newObject.scale.set(10, 10, 10);//UE4缩放10 如果按米为单位的缩放1000
|
||||||
|
|
||||||
|
newObject.updateMatrix();//保证更新缩放
|
||||||
|
newObject.updateMatrixWorld(false);//保证更新位置
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateDrawObjectMaterial(renderType: RenderType, obj: Object3D)
|
||||||
|
{
|
||||||
|
obj.traverse(o =>
|
||||||
|
{
|
||||||
|
if (o instanceof Mesh)
|
||||||
|
{
|
||||||
|
if (Array.isArray(o.material))
|
||||||
|
{
|
||||||
|
for (let i = 0; i < o.material.length; i++)
|
||||||
|
{
|
||||||
|
let mtl = this._OverWriteMaterial.get(i)?.Object?.Material;
|
||||||
|
if (mtl)
|
||||||
|
{
|
||||||
|
o.material[i] = mtl;
|
||||||
|
if (mtl.transparent)
|
||||||
|
{
|
||||||
|
o.castShadow = false;
|
||||||
|
o.receiveShadow = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
o.material[i] = GetDefultFBXMaterial();
|
||||||
|
this.AsyncUpdated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
let mtl = this._OverWriteMaterial.get(0)?.Object?.Material;
|
||||||
|
if (mtl)
|
||||||
|
o.material = mtl;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
o.material = GetDefultFBXMaterial();
|
||||||
|
this.AsyncUpdated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
GetObjectSnapPoints(
|
||||||
|
snapMode: ObjectSnapMode,
|
||||||
|
pickPoint: Vector3,
|
||||||
|
lastPoint: Vector3,
|
||||||
|
viewXform: Matrix3
|
||||||
|
): Vector3[]
|
||||||
|
{
|
||||||
|
let box = this.BoundingBox;
|
||||||
|
let [x1, y1, z1] = [box.min.x, box.min.y, box.min.z];
|
||||||
|
let [x2, y2, z2] = [box.max.x, box.max.y, box.max.z];
|
||||||
|
switch (snapMode)
|
||||||
|
{
|
||||||
|
case ObjectSnapMode.End:
|
||||||
|
return this.GetGripPoints();
|
||||||
|
case ObjectSnapMode.Mid:
|
||||||
|
let mid = [
|
||||||
|
new Vector3(x1, y1, (z1 + z2) / 2),
|
||||||
|
new Vector3(x1, y2, (z1 + z2) / 2),
|
||||||
|
new Vector3(x2, y2, (z1 + z2) / 2),
|
||||||
|
new Vector3(x2, y1, (z1 + z2) / 2),
|
||||||
|
];
|
||||||
|
let midline = [
|
||||||
|
new Vector3(x1, (y1 + y2) / 2, z1),
|
||||||
|
new Vector3(x2, (y1 + y2) / 2, z1),
|
||||||
|
new Vector3((x1 + x2) / 2, y2, z1),
|
||||||
|
new Vector3((x1 + x2) / 2, y1, z1),
|
||||||
|
];
|
||||||
|
let v = new Vector3(0, 0, z2);
|
||||||
|
let mids: Vector3[] = [];
|
||||||
|
mids.push(...mid, ...midline, ...midline.map(p => p.clone().add(v)));
|
||||||
|
return mids;
|
||||||
|
case ObjectSnapMode.Nea:
|
||||||
|
let lines = BoxLine(this.BoundingBox);
|
||||||
|
let neas: Vector3[] = [];
|
||||||
|
for (let l of lines)
|
||||||
|
neas.push(...l.GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform));
|
||||||
|
return neas;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
MoveGripPoints(indexList: Array<number>, vec: Vector3)
|
||||||
|
{
|
||||||
|
if (indexList.length)
|
||||||
|
{
|
||||||
|
this.WriteAllObjectRecord();
|
||||||
|
this.Position = this.Position.add(vec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#region -------------------------File-------------------------
|
||||||
|
|
||||||
|
//对象从文件中读取数据,初始化自身
|
||||||
|
protected _ReadFile(file: CADFiler)
|
||||||
|
{
|
||||||
|
let ver = file.Read();
|
||||||
|
super._ReadFile(file);
|
||||||
|
this._url = file.Read();
|
||||||
|
|
||||||
|
if (ver > 1)
|
||||||
|
{
|
||||||
|
this._Size.x = file.Read();
|
||||||
|
this._Size.y = file.Read();
|
||||||
|
this._Size.z = file.Read();
|
||||||
|
|
||||||
|
this._Center.x = file.Read();
|
||||||
|
this._Center.y = file.Read();
|
||||||
|
this._Center.z = file.Read();
|
||||||
|
|
||||||
|
this._ScaleSize.x = file.Read();
|
||||||
|
this._ScaleSize.y = file.Read();
|
||||||
|
this._ScaleSize.z = file.Read();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._OverWriteMaterial.clear();
|
||||||
|
if (ver > 2)
|
||||||
|
{
|
||||||
|
let size = file.Read();
|
||||||
|
for (let i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
let index = file.Read();
|
||||||
|
let id = file.ReadHardObjectId() as ObjectId<PhysicalMaterialRecord>;
|
||||||
|
if (id)
|
||||||
|
this._OverWriteMaterial.set(index, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//对象将自身数据写入到文件.
|
||||||
|
WriteFile(file: CADFiler)
|
||||||
|
{
|
||||||
|
file.Write(3);
|
||||||
|
super.WriteFile(file);
|
||||||
|
file.Write(this._url);
|
||||||
|
|
||||||
|
//2
|
||||||
|
file.Write(this._Size.x);
|
||||||
|
file.Write(this._Size.y);
|
||||||
|
file.Write(this._Size.z);
|
||||||
|
|
||||||
|
file.Write(this._Center.x);
|
||||||
|
file.Write(this._Center.y);
|
||||||
|
file.Write(this._Center.z);
|
||||||
|
|
||||||
|
file.Write(this._ScaleSize.x);
|
||||||
|
file.Write(this._ScaleSize.y);
|
||||||
|
file.Write(this._ScaleSize.z);
|
||||||
|
|
||||||
|
//ver3
|
||||||
|
file.Write(this._OverWriteMaterial.size);
|
||||||
|
for (let [index, id] of this._OverWriteMaterial)
|
||||||
|
{
|
||||||
|
file.Write(index);
|
||||||
|
file.WriteHardObjectId(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
}
|
Loading…
Reference in new issue