!2588 功能:导入fbx资源文件

pull/2588/MERGE
黄诗津 7 months ago committed by ChenX
parent e9399667f9
commit dfc5f61b2a

@ -1,6 +1,7 @@
import { Vector3 } from 'three';
import { app } from '../ApplicationServices/Application';
import { Entity } from '../DatabaseServices/Entity/Entity';
import { EntityFbx } from '../DatabaseServices/Entity/EntityFbx';
import { EntityRef } from '../DatabaseServices/Entity/EntityRef';
import { Line } from '../DatabaseServices/Entity/Line';
import { TemplateRecord } from '../DatabaseServices/Template/TemplateRecord';
@ -35,7 +36,7 @@ export class Entsel implements Command
if (res.Entity instanceof Entity)
if (res.Entity.Template)
dyn.UpdatePrompt(`模版:${res.Entity.Template.Index},${(<TemplateRecord>(res.Entity.Template.Object)).Objects.length}`);
else if (res.Entity instanceof EntityRef)
else if (res.Entity instanceof EntityRef || res.Entity instanceof EntityFbx)
dyn.UpdatePrompt(res.Entity.Url);
else
dyn.UpdatePrompt(res.Entity.ColorIndex.toString());

@ -11,7 +11,6 @@ import { Log } from "../Common/Log";
import { Vector2ApplyMatrix4 } from "../Common/Matrix4Utils";
import { StoreageKeys } from '../Common/StoreageKeys';
import { copyTextToClipboard } from "../Common/Utils";
import { IsMirror } from '../csg/core/math/IsMirrot';
import { CylinderHole } from '../DatabaseServices/3DSolid/CylinderHole';
import { ExtrudeHole } from '../DatabaseServices/3DSolid/ExtrudeHole';
import { RevolveSolid } from '../DatabaseServices/3DSolid/RevolveSolid';
@ -22,6 +21,7 @@ import { Board } from "../DatabaseServices/Entity/Board";
import { Circle } from "../DatabaseServices/Entity/Circle";
import { Curve } from "../DatabaseServices/Entity/Curve";
import { Entity } from "../DatabaseServices/Entity/Entity";
import { EntityFbx } from '../DatabaseServices/Entity/EntityFbx';
import { EntityRef } from '../DatabaseServices/Entity/EntityRef';
import { ExtrudeSolid } from "../DatabaseServices/Entity/Extrude";
import { Line } from '../DatabaseServices/Entity/Line';
@ -55,6 +55,7 @@ import { ModalPosition } from '../UI/Components/Modal/ModalInterface';
import { AppToaster } from '../UI/Components/Toaster';
import { DownPanelStore } from '../UI/Store/DownPanelStore';
import { TopPanelStore } from '../UI/Store/TopPanelStore';
import { IsMirror } from '../csg/core/math/IsMirrot';
import { Hole } from './../DatabaseServices/3DSolid/Hole';
import { CompositeEntity } from './../DatabaseServices/Entity/CompositeEntity';
@ -133,7 +134,7 @@ export class Command_ExportData implements Command
UseSelect: true,
Msg: "请选择需要发送到渲染器的实体:",
Filter: {
filterTypes: [Board, SweepSolid, CompositeEntity, RevolveSolid, EntityRef, Light, Region,
filterTypes: [Board, SweepSolid, CompositeEntity, RevolveSolid, EntityRef, EntityFbx, Light, Region,
RoomWallBase, RoomFlatBase, RoomHolePolyline, BulkheadCeiling
]
},
@ -220,7 +221,7 @@ export function Entitys2Data(ents: Iterable<Entity>): Data
arrayPushArray(d.Entitys, CompositeEntity2Data(e));
else if (e instanceof RevolveSolid)
d.Entitys.push(ConvertRevolve2Data(e));
else if (e instanceof EntityRef)
else if (e instanceof EntityRef || e instanceof EntityFbx)
d.Entitys.push(ConveEntityRef2Data(e));
else if (e instanceof DirectionalLight)
d.Entitys.push(ConverDirectionalLight2Data(e));
@ -397,11 +398,11 @@ function ConveRegion2Data(e: Region)
return reg;
}
function ConveEntityRef2Data(e: EntityRef)
function ConveEntityRef2Data(e: EntityRef | EntityFbx)
{
let ref: any = {};
ref.Id = e.Id?.Index ?? 0;
ref.Type = "Ref";
ref.Type = (e instanceof EntityRef) ? "Ref" : "Fbx";
ref.Url = e.Url;
ref.OCS = e.OCSNoClone.toArray();

@ -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插入");
}
}
}

@ -1,6 +1,7 @@
import { Board } from "../../DatabaseServices/Entity/Board";
import { BoardOpenDir, BoardType } from "../../DatabaseServices/Entity/BoardInterface";
import { Entity } from "../../DatabaseServices/Entity/Entity";
import { EntityFbx } from "../../DatabaseServices/Entity/EntityFbx";
import { EntityRef } from "../../DatabaseServices/Entity/EntityRef";
import { HardwareCompositeEntity } from "../../DatabaseServices/Hardware/HardwareCompositeEntity";
import { HardwareTopline } from "../../DatabaseServices/Hardware/HardwareTopline";
@ -118,6 +119,7 @@ export function IsHouse(en: Entity): boolean
{
if (en instanceof RoomBase ||
en instanceof EntityRef ||
en instanceof EntityFbx ||
(en instanceof HardwareTopline && (en.HardwareOption.name === "地脚线" || en.HardwareOption.name === "吊顶")) ||
en.Template?.Object instanceof TemplateArcWindowRecord ||
(en.Template?.Object as TemplateRecord)?.Parent?.Object instanceof TemplateWindowRecord ||

@ -13,6 +13,7 @@ import { Board } from "../DatabaseServices/Entity/Board";
import { CompositeEntity } from "../DatabaseServices/Entity/CompositeEntity";
import { Curve } from "../DatabaseServices/Entity/Curve";
import { Entity } from "../DatabaseServices/Entity/Entity";
import { EntityFbx } from "../DatabaseServices/Entity/EntityFbx";
import { EntityRef } from "../DatabaseServices/Entity/EntityRef";
import { HardwareCompositeEntity } from "../DatabaseServices/Hardware/HardwareCompositeEntity";
import { Command } from "../Editor/CommandMachine";
@ -23,7 +24,7 @@ import { UpdateEntityDrawTask } from "./UpdateEntityDrawTask";
const NEED_ENTITY = [Curve, AlignedDimension, LineAngularDimension, RadiusDimension];
const CanMirrorEntity = [...NEED_ENTITY, Hole, Board, SweepSolid, CompositeEntity, EntityRef];
const CanMirrorEntity = [...NEED_ENTITY, Hole, Board, SweepSolid, CompositeEntity, EntityRef, EntityFbx];
export class MirrorCommand implements Command
{

@ -6,6 +6,7 @@ import { ExtrudeHole } from "../DatabaseServices/3DSolid/ExtrudeHole";
import { Arc } from "../DatabaseServices/Entity/Arc";
import { Circle } from "../DatabaseServices/Entity/Circle";
import { Entity } from "../DatabaseServices/Entity/Entity";
import { EntityFbx } from "../DatabaseServices/Entity/EntityFbx";
import { EntityRef } from "../DatabaseServices/Entity/EntityRef";
import { ExtrudeSolid } from "../DatabaseServices/Entity/Extrude";
import { Line } from "../DatabaseServices/Entity/Line";
@ -25,7 +26,7 @@ export class Command_Scale implements Command
let ssRes = await app.Editor.GetSelection({
UseSelect: true,
Filter: {
filterTypes: [Arc, Circle, Line, Region, Text, Polyline, EntityRef, ExtrudeSolid, ExtrudeHole]//Ellipse详细请看代码备注
filterTypes: [Arc, Circle, Line, Region, Text, Polyline, EntityRef, EntityFbx, ExtrudeSolid, ExtrudeHole]//Ellipse详细请看代码备注
}
});
if (ssRes.Status != PromptStatus.OK)

@ -7,6 +7,7 @@ import { Intent } from "../../Common/Toaster";
import { CADFiler } from "../../DatabaseServices/CADFiler";
import { Database } from "../../DatabaseServices/Database";
import { Board } from "../../DatabaseServices/Entity/Board";
import { EntityFbx } from "../../DatabaseServices/Entity/EntityFbx";
import { EntityRef } from "../../DatabaseServices/Entity/EntityRef";
import { FileServer } from "../../DatabaseServices/FileServer";
import { HardwareCompositeEntity } from "../../DatabaseServices/Hardware/HardwareCompositeEntity";
@ -38,7 +39,7 @@ export class Command_ShareView implements Command
UseSelect: true,
Filter: {
filterFunction: (obj, ent) =>
!(ent instanceof DirectionalLight || ent instanceof EntityRef ||
!(ent instanceof DirectionalLight || ent instanceof EntityRef || ent instanceof EntityFbx ||
(!store.m_Option.IsExportBoard && (ent instanceof Board)) || (!store.m_Option.IsExportHardware && (ent instanceof HardwareCompositeEntity || ent instanceof HardwareTopline)))//避免拷贝太阳光 太阳光只能有一个
},
});

@ -35,6 +35,33 @@ export function ParseBoxUrl(url: string, box = false): string
return GenerateCdnUrl(`/Paks/paks_cooked2/ue_resource/Content${url}/Mesh_${name}${box ? "_BOX" : ""}.ubox`, true);
}
let defultFBXMaterial: MeshPhysicalMaterial;
export function GetDefultFBXMaterial()
{
if (!defultFBXMaterial)
{
defultFBXMaterial = new MeshPhysicalMaterial({
name: "默认",
side: DoubleSide,
transparent: false,
metalness: 0.2,
opacity: 1,
roughness: 0.2,
bumpScale: 0.0005
});
}
//分开处理,因为有小概率会出现envMap为空的情况
if (!defultFBXMaterial.envMap)
{
HostApplicationServices.LoadDefaultExr().then(exr =>
{
defultFBXMaterial.envMap = exr;
defultFBXMaterial.needsUpdate = true;
});
}
return defultFBXMaterial;
};
export async function ConverMaterial2(m: MeshPhongMaterial, url: string)
{
let name = m.name;
@ -61,6 +88,7 @@ export async function ConverMaterial2(m: MeshPhongMaterial, url: string)
try
{
if (!url) throw ""; //url为空的时候,走默认的材质
let dataString = await (await fetch(GenerateCdnUrl(`/Paks/paks_cooked2/ue_resource/Content${encodeURI(url)}/${name}.json`))).text();
let data = JSON.parse(dataString);

@ -6,6 +6,7 @@ import { HardwareCuttingReactor } from '../Add-on/BoardCutting/HardwareCuttingRe
import { DwgDxfImport } from '../Add-on/DXFLoad';
import { DrillingReactor } from '../Add-on/DrawDrilling/DrillingReactor';
import { AppendUserInfo } from '../Add-on/ExportData';
import { FbxImport } from '../Add-on/FBXLoad';
import { ImportJiajuFile } from '../Add-on/JiaJu/Import/JiaJuImport';
import { ImportKJLData } from '../Add-on/KJL/Import/KJLImport';
import { CommandNames } from '../Common/CommandNames';
@ -372,6 +373,7 @@ export class ApplicationService
let cadfiles: File[] = [];
let jsonFiles: File[] = [];
let xmlFiles: File[] = [];
let fbxFiles: File[] = [];
for (let i = 0; i < e.dataTransfer.files.length; i++)
{
let f = e.dataTransfer.files.item(i);
@ -391,6 +393,11 @@ export class ApplicationService
e.preventDefault();
xmlFiles.push(f);
}
else if (ext === ".FBX")
{
e.preventDefault();
fbxFiles.push(f);
}
}
const exec = async () =>
@ -421,6 +428,11 @@ export class ApplicationService
ImportJiajuFile(xmlFile);
}
}
if (fbxFiles.length > 0)
{
for (let f of fbxFiles)
await FbxImport(f);
}
};
exec();

@ -10,6 +10,7 @@ export enum CommandNames
Group = "GROUP",
DXFImport = "DXF",
DWGImport = "DWG",
FBXImport = "FBX",
Insert = "INSERT",
Line = "LINE", //直线
XLine = "XLINE",

@ -204,3 +204,5 @@ export const PrivateModule = {
GetModuleList: CURRENT_HOST + "/CAD-privateModuleLists",//模型列表
UpdateModule: CURRENT_HOST + "/CAD-privateModuleUpdate"//修改模型信息
};
export const FBXURL = CURRENT_HOST + "/CAD-ossUploadSign";

@ -3,6 +3,7 @@ import { SweepSolid } from "../DatabaseServices/3DSolid/SweepSolid";
import { Board } from "../DatabaseServices/Entity/Board";
import { CompositeEntity } from "../DatabaseServices/Entity/CompositeEntity";
import { Entity } from "../DatabaseServices/Entity/Entity";
import { EntityFbx } from "../DatabaseServices/Entity/EntityFbx";
import { EntityRef } from "../DatabaseServices/Entity/EntityRef";
import { Region } from "../DatabaseServices/Entity/Region";
import { HardwareTopline } from "../DatabaseServices/Hardware/HardwareTopline";
@ -16,6 +17,7 @@ export function IsMeshMaterialEntity(en: Entity): boolean
return (en instanceof Board
|| en instanceof Region
|| en instanceof EntityRef
|| en instanceof EntityFbx
|| en instanceof RevolveSolid
|| en instanceof CompositeEntity || en instanceof SweepSolid || en instanceof HardwareTopline
|| en instanceof RoomWallBase || en instanceof RoomFlatBase

@ -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
}

@ -29,14 +29,14 @@ export class EntityRef extends Entity
{
OnlyRenderType = true;
private _Size = new Vector3;//原始尺寸
private _ScaleSize = new Vector3;//缩放后的尺寸
private _Center = new Vector3;//盒子中心
protected _Size = new Vector3;//原始尺寸
protected _ScaleSize = new Vector3;//缩放后的尺寸
protected _Center = new Vector3;//盒子中心
private _OverWriteMaterial = new Map<number, ObjectId<PhysicalMaterialRecord>>();//section index -> materialId
protected _OverWriteMaterial = new Map<number, ObjectId<PhysicalMaterialRecord>>();//section index -> materialId
// `/Data/ASSETS/DXAA_0001`
constructor(private _url?: string)
constructor(protected _url?: string)
{
super();
}
@ -47,6 +47,14 @@ export class EntityRef extends Entity
}
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(); }
@ -100,6 +108,31 @@ export class EntityRef extends Entity
let oldUserDaata = obj.userData;
obj.traverse(o => o.userData = {});
let newObj = obj.clone();
let mesh1 = [];
let mesh2 = [];
obj.traverse(o =>
{
if (o instanceof Mesh)
mesh1.push(o);
});
newObj.traverse(o =>
{
if (o instanceof Mesh)
{
if (Array.isArray(o.material))
o.material = [...o.material];
mesh2.push(o);
}
});
for (let i = 0; i < mesh1.length; i++)
{
mesh2[i]['__old_material__'] = mesh1[i]['__old_material__'];
}
obj.userData = oldUserDaata;
// obj.userData.IsClone = true;//因为这个实体不需要修改内部的geom 所以我们可以复用她
@ -417,7 +450,7 @@ export class EntityRef extends Entity
if (!converMtl)
{
converMtl = ConverMaterial2(oldMtl, this._url);
this.mtlpromiseCache.set(mtl.name, converMtl);
this.mtlpromiseCache.set(oldMtl.name, converMtl);
}
converMtl.then(mtl =>
{

@ -206,7 +206,6 @@ import { Command_SplitTemplate, Command_SplitTemplateByDir } from "../Add-on/Tem
import { Command_TemplateSearch } from "../Add-on/TemplateSearch";
import { Command_ClosePt } from "../Add-on/closetest";
import { Command_INsTest } from "../Add-on/instest";
import { Fbx } from "../Add-on/loadfbx";
import { Command_PLTest } from "../Add-on/polytest";
import { Command_GroovesModify } from "../Add-on/showModal/GroovesModify";
import { ShowEditorBBS } from "../Add-on/showModal/ShowModal";
@ -221,6 +220,7 @@ import { ApplyModel2ToBoard } from "../Add-on/DrawBoard/ApplyModel2ToBoard";
import { ParseHandle } from "../Add-on/DrawBoard/ParseHandle";
import { ParseHinge } from "../Add-on/DrawBoard/ParseHinge";
import { Command_BoardInfoDimTool } from "../Add-on/DrawDim/BoardInfoDimTool";
import { Command_FBXImport } from "../Add-on/FBXLoad";
import { Command_Show2DPathLine } from "../Add-on/Show2DPathLine/Show2DPathLine";
import { Command_Show2DPathObject } from "../Add-on/Show2DPathLine/Show2DPathObject";
import { TestFb } from "../Add-on/TestFb";
@ -332,6 +332,7 @@ export function registerCommand()
//CAD图纸导入
commandMachine.RegisterCommand(CommandNames.DXFImport, new Command_DWGDXFImport());
commandMachine.RegisterCommand(CommandNames.DWGImport, new Command_DWGDXFImport());
commandMachine.RegisterCommand(CommandNames.FBXImport, new Command_FBXImport());
//帮帮我 出错了
commandMachine.RegisterCommand("999", new Command_999());
@ -420,7 +421,8 @@ export function registerCommand()
commandMachine.RegisterCommand("grip", new DrawGripStretch());
commandMachine.RegisterCommand("fbx", new Fbx());
//暂时关闭这个fbx导入
// commandMachine.RegisterCommand("fbx", new Fbx());
commandMachine.RegisterCommand(CommandNames.HideSelect, new Command_HideSelected());
commandMachine.RegisterCommand(CommandNames.HideUnSelect, new Command_HideUnselected());

@ -2668,6 +2668,16 @@ export const CommandList: ICommand[] = [
// enName: "Import DXF",
chDes: "导入Dwg或者DXF文件",
},
{
typeId: "file",
link: `#`,
defaultCustom: CommandNames.FBXImport,
command: CommandNames.FBXImport,
type: "文件",
chName: "FBX",
// enName: "Import FBX",
chDes: "导入FBX文件",
},
{
icon: IconEnum.SaveToDxf,
typeId: "file",

@ -8,6 +8,7 @@ import { CommandHistoryRecord } from "../../../../DatabaseServices/CommandHistor
import { CreateObjectData } from "../../../../DatabaseServices/CreateObjectData";
import { Board } from "../../../../DatabaseServices/Entity/Board";
import { Entity } from "../../../../DatabaseServices/Entity/Entity";
import { EntityFbx } from "../../../../DatabaseServices/Entity/EntityFbx";
import { EntityRef } from "../../../../DatabaseServices/Entity/EntityRef";
import { RoomBase } from "../../../../DatabaseServices/Room/Entity/RoomBase";
import { commandMachine } from "../../../../Editor/CommandMachine";
@ -127,7 +128,7 @@ export default class ModifyModelStore
this.module_Width = ent.Width;
this.module_Height = ent.Thickness;
}
else if (ent instanceof EntityRef)
else if (ent instanceof EntityRef || ent instanceof EntityFbx)
{
this.name = "[模型]" + ent.Url;
let size = ent.CurSize;
@ -224,7 +225,7 @@ export default class ModifyModelStore
if (ents.length === 1)
{
let ent = ents[0];
if (ent instanceof EntityRef)
if (ent instanceof EntityRef || ent instanceof EntityFbx)
ent.ScaleSize = new Vector3(length, width, height);
else if (ent instanceof Board)
{

@ -3,6 +3,7 @@ import { observer } from 'mobx-react';
import React, { Component } from 'react';
import { app } from '../../../../ApplicationServices/Application';
import { Entity } from '../../../../DatabaseServices/Entity/Entity';
import { EntityFbx } from '../../../../DatabaseServices/Entity/EntityFbx';
import { EntityRef } from '../../../../DatabaseServices/Entity/EntityRef';
import { HardwareTopline } from '../../../../DatabaseServices/Hardware/HardwareTopline';
import { BulkheadCeiling } from '../../../../DatabaseServices/Room/Entity/Ceiling/BulkheadCeiling';
@ -53,20 +54,23 @@ export default class ModuleBaseParams extends Component<ModuleBaseParamsProps, {
</div>
</div>
<Collapse isOpen={ModifyModelStore.isCollapseOpened}>
<div style={{ height: 10, marginTop: 5 }}>
<div style={{ height: 20, marginTop: 5 }}>
<Button
small
minimal
intent='primary'
text='恢复默认'
style={{ fontSize: '12px', display: ents.length === 1 && ents[0] instanceof EntityRef ? "block" : "none" }}
style={{
fontSize: '12px',
display: ents.length === 1 && (ents[0] instanceof EntityRef || ents[0] instanceof EntityFbx) ? "block" : "none"
}}
onClick={async (e: React.MouseEvent) =>
{
e.stopPropagation();
if (!app.Editor.SelectCtrl.SelectSet.SelectEntityList.length) return;
CommandWrap(() =>
{
for (let ent of app.Editor.SelectCtrl.SelectSet.SelectEntityList as EntityRef[])
for (let ent of app.Editor.SelectCtrl.SelectSet.SelectEntityList as EntityRef[] | EntityFbx[])
{
ent.ScaleSize = ZeroVec;
app.Viewer.UpdateRender();

@ -30,6 +30,7 @@ export class TopToolBar extends React.Component<{}, {}>
{ svg: IconEnum.Undo, title: "重做", command: CommandNames.Redo },
{ svg: IconEnum.Open, title: "打开", command: CommandNames.Open },
{ svg: IconEnum.DXF, title: "DXF", command: "DXF" },
{ svg: "", title: "FBX", command: "FBX" },
{ svg: IconEnum.ClearHistoryRecord, title: "清除历史命令", command: "PU" },
];
store.iconList.twoD = [

Loading…
Cancel
Save