mirror of
https://github.com/misskey-dev/misskey.git
synced 2026-06-25 17:10:43 +00:00
wip
This commit is contained in:
parent
ac2c6b93ce
commit
124079f80a
30 changed files with 121 additions and 22 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -243,7 +243,12 @@ class ModelManager {
|
|||
|
||||
const excludeMeshes = [...this.bakeExcludeMeshes, ...this.root.getChildMeshes().filter(m => SYSTEM_MESH_NAMES.some(s => m.name.includes(s)))];
|
||||
|
||||
const childMeshes = this.root.getChildMeshes().filter(m => !excludeMeshes.some(x => x === m) && m.isVisible);
|
||||
const childMeshes = this.root.getChildMeshes().filter(m => !excludeMeshes.some(x => x === m) && m.isVisible && !m.isDisposed());
|
||||
|
||||
if (childMeshes.length <= 1) {
|
||||
this.bakedCallback?.([...childMeshes, ...excludeMeshes]);
|
||||
return;
|
||||
}
|
||||
|
||||
const _toMerge = [] as BABYLON.Mesh[];
|
||||
for (const mesh of childMeshes) {
|
||||
|
|
@ -301,7 +306,12 @@ class ModelManager {
|
|||
toMerge.push(newMesh);
|
||||
}
|
||||
|
||||
const merged = BABYLON.Mesh.MergeMeshes(toMerge, true, true, undefined, false, true);
|
||||
if (toMerge.length === 0) {
|
||||
this.bakedCallback?.([...childMeshes, ...excludeMeshes]);
|
||||
return;
|
||||
}
|
||||
|
||||
const merged = BABYLON.Mesh.MergeMeshes(toMerge, true, false, undefined, false, true);
|
||||
merged.parent = this.root;
|
||||
merged.material.freeze();
|
||||
if (merged.material instanceof BABYLON.MultiMaterial) {
|
||||
|
|
@ -333,6 +343,44 @@ class ModelManager {
|
|||
}
|
||||
}
|
||||
|
||||
function mergeMeshes(meshes: BABYLON.Mesh[], root: BABYLON.Mesh, hasTexture: boolean) {
|
||||
const excludeMeshes = root.getChildMeshes().filter(m => SYSTEM_MESH_NAMES.some(s => m.name.includes(s)));
|
||||
|
||||
const childMeshes = root.getChildMeshes().filter(m => !excludeMeshes.some(x => x === m) && m.isVisible && !m.isDisposed());
|
||||
|
||||
const toMerge = [] as BABYLON.Mesh[];
|
||||
for (const mesh of childMeshes) {
|
||||
if (mesh instanceof BABYLON.InstancedMesh) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mesh.hasInstances) continue;
|
||||
|
||||
if (mesh instanceof BABYLON.Mesh) {
|
||||
toMerge.push(mesh);
|
||||
}
|
||||
}
|
||||
|
||||
for (const mesh of toMerge) {
|
||||
if (hasTexture) {
|
||||
if (mesh.getVerticesData(BABYLON.VertexBuffer.UVKind) == null) {
|
||||
const vertexCount = mesh.getTotalVertices();
|
||||
const uvs = new Array(vertexCount * 2).fill(0);
|
||||
mesh.setVerticesData(BABYLON.VertexBuffer.UVKind, uvs, false, 2);
|
||||
}
|
||||
if (mesh.getVerticesData(BABYLON.VertexBuffer.UV2Kind) == null) {
|
||||
const vertexCount = mesh.getTotalVertices();
|
||||
const uvs = new Array(vertexCount * 2).fill(0);
|
||||
mesh.setVerticesData(BABYLON.VertexBuffer.UV2Kind, uvs, false, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const merged = BABYLON.Mesh.MergeMeshes(toMerge, true, false, undefined, false, true);
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
export type ObjectDef<OpSc extends OptionsSchema = OptionsSchema> = {
|
||||
id: string;
|
||||
name: string;
|
||||
|
|
@ -344,6 +392,7 @@ export type ObjectDef<OpSc extends OptionsSchema = OptionsSchema> = {
|
|||
placement: 'top' | 'side' | 'bottom' | 'wall' | 'ceiling' | 'floor';
|
||||
hasCollisions?: boolean;
|
||||
hasTexture?: boolean;
|
||||
canPreMeshesMerging?: boolean;
|
||||
//groupingMeshes: string[]; // multi-materialなメッシュは複数のメッシュに分割されるが、それだと不便な場合に追加の親メッシュでグルーピングするための指定
|
||||
isChair?: boolean;
|
||||
treatLoaderResult?: (loaderResult: BABYLON.AssetContainer) => void;
|
||||
|
|
@ -833,13 +882,13 @@ export class RoomEngine extends EventEmitter<RoomEngineEvents> {
|
|||
|
||||
// TODO: __PICK__考慮
|
||||
const pickingInfo = this.scene.pick(this.scene.pointerX, this.scene.pointerY,
|
||||
(m) => m.metadata?.objectId != null && this.objectEntities.has(m.metadata.objectId));
|
||||
(m) => m.name.includes('__PICK__') || (m.isVisible && m.isEnabled() && m.metadata?.objectId != null && this.objectEntities.has(m.metadata.objectId)));
|
||||
|
||||
if (pickingInfo.pickedMesh != null) {
|
||||
const oid = pickingInfo.pickedMesh.metadata.objectId;
|
||||
if (oid != null && this.objectEntities.has(oid)) {
|
||||
const o = this.objectEntities.get(oid)!;
|
||||
const boundingInfo = getMeshesBoundingBox(o.rootMesh.getChildMeshes().filter(m => m.isEnabled() && m.isVisible));
|
||||
const boundingInfo = getMeshesBoundingBox(o.rootMesh.getChildMeshes().filter(m => m.isEnabled() && m.isVisible && !m.isDisposed()));
|
||||
this.selectObject(oid);
|
||||
|
||||
{ // camera animation
|
||||
|
|
@ -1169,6 +1218,19 @@ export class RoomEngine extends EventEmitter<RoomEngineEvents> {
|
|||
}
|
||||
}
|
||||
|
||||
if (def.canPreMeshesMerging) {
|
||||
const merged = mergeMeshes(loaderResult.meshes, subRoot, def.hasTexture);
|
||||
merged.setParent(subRoot);
|
||||
merged.name = 'preMerged';
|
||||
|
||||
// TODO: 再帰的にする
|
||||
for (const m of loaderResult.transformNodes) {
|
||||
if (m.getChildren().length === 0) {
|
||||
m.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (BAKE_TRANSFORM) {
|
||||
subRoot.scaling = new BABYLON.Vector3(1, 1, 1);
|
||||
subRoot.rotationQuaternion = null;
|
||||
|
|
@ -1330,7 +1392,7 @@ export class RoomEngine extends EventEmitter<RoomEngineEvents> {
|
|||
root.rotation = args.rotation.clone();
|
||||
root.metadata = metadata;
|
||||
|
||||
const model = new ModelManager(BAKE_TRANSFORM ? root : subRoot, loaderResult.meshes.filter(m => m.name !== '__root__'), def.hasTexture, (meshes) => {
|
||||
const model = new ModelManager(BAKE_TRANSFORM ? root : subRoot, loaderResult.meshes.filter(m => !m.isDisposed() && m.name !== '__root__'), def.hasTexture, (meshes) => {
|
||||
if (this.selected?.objectId === args.id) {
|
||||
this.highlightMeshes(meshes);
|
||||
}
|
||||
|
|
@ -2082,6 +2144,20 @@ export class RoomObjectPreviewEngine {
|
|||
const filePath = def.path != null ? `/client-assets/room/objects/${def.path}.glb` : `/client-assets/room/objects/${camelToKebab(args.type)}/${camelToKebab(args.type)}.glb`;
|
||||
const loaderResult = await BABYLON.LoadAssetContainerAsync(filePath, this.scene);
|
||||
|
||||
// 不要なUVを掃除
|
||||
if (!def.hasTexture) {
|
||||
for (const m of loaderResult.meshes) {
|
||||
if (m.geometry != null) {
|
||||
m.geometry.removeVerticesData(BABYLON.VertexBuffer.UVKind);
|
||||
m.geometry.removeVerticesData(BABYLON.VertexBuffer.UV2Kind);
|
||||
m.geometry.removeVerticesData(BABYLON.VertexBuffer.UV3Kind);
|
||||
m.geometry.removeVerticesData(BABYLON.VertexBuffer.UV4Kind);
|
||||
m.geometry.removeVerticesData(BABYLON.VertexBuffer.UV5Kind);
|
||||
m.geometry.removeVerticesData(BABYLON.VertexBuffer.UV6Kind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// babylonによって自動で追加される右手系変換用ノード
|
||||
const subRoot = loaderResult.meshes[0];
|
||||
subRoot.scaling = subRoot.scaling.scale(WORLD_SCALE);// cmをmに
|
||||
|
|
@ -2090,7 +2166,7 @@ export class RoomObjectPreviewEngine {
|
|||
|
||||
root.addChild(subRoot);
|
||||
|
||||
const model = new ModelManager(subRoot, loaderResult.meshes.filter(m => m !== subRoot), def.hasTexture, (meshes) => {
|
||||
const model = new ModelManager(subRoot, loaderResult.meshes.filter(m => !m.isDisposed() && m !== subRoot), def.hasTexture, (meshes) => {
|
||||
for (const m of meshes) {
|
||||
const mesh = m;
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export const aircon = defineObject({
|
|||
},
|
||||
placement: 'wall',
|
||||
hasCollisions: false,
|
||||
canPreMeshesMerging: true,
|
||||
createInstance: () => {
|
||||
return {
|
||||
interactions: {},
|
||||
|
|
|
|||
|
|
@ -28,12 +28,10 @@ export const aromaReedDiffuser = defineObject({
|
|||
placement: 'top',
|
||||
hasCollisions: false,
|
||||
hasTexture: true,
|
||||
canPreMeshesMerging: true,
|
||||
createInstance: ({ options, model }) => {
|
||||
const bottleMesh = model.findMesh('__X_BOTTLE__');
|
||||
const bottleMaterial = bottleMesh.material as BABYLON.PBRMaterial;
|
||||
|
||||
const oilMesh = model.findMesh('__X_OIL__');
|
||||
const oilMaterial = oilMesh.material as BABYLON.PBRMaterial;
|
||||
const bottleMaterial = model.findMaterial('__X_BOTTLE__');
|
||||
const oilMaterial = model.findMaterial('__X_OIL__');
|
||||
|
||||
const applyBottleColor = () => {
|
||||
const [r, g, b] = options.bottleColor;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ export const banknote = defineObject({
|
|||
placement: 'top',
|
||||
hasCollisions: false,
|
||||
hasTexture: true,
|
||||
canPreMeshesMerging: true,
|
||||
createInstance: () => {
|
||||
return {
|
||||
interactions: {},
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ export const beamLamp = defineObject({
|
|||
},
|
||||
placement: 'top',
|
||||
hasCollisions: false,
|
||||
canPreMeshesMerging: true,
|
||||
createInstance: ({ room, root, scene }) => {
|
||||
return {
|
||||
onInited: () => {
|
||||
|
|
|
|||
|
|
@ -23,9 +23,9 @@ export const cactusS = defineObject({
|
|||
placement: 'top',
|
||||
hasCollisions: false,
|
||||
hasTexture: true,
|
||||
canPreMeshesMerging: true,
|
||||
createInstance: ({ options, model }) => {
|
||||
const potMesh = model.findMesh('__X_POT__');
|
||||
const potMaterial = potMesh.material as BABYLON.PBRMaterial;
|
||||
const potMaterial = model.findMaterial('__X_POT__');
|
||||
|
||||
const applyPotColor = () => {
|
||||
const [r, g, b] = options.potColor;
|
||||
|
|
|
|||
|
|
@ -28,12 +28,10 @@ export const chair = defineObject({
|
|||
placement: 'floor',
|
||||
hasCollisions: true,
|
||||
isChair: true,
|
||||
canPreMeshesMerging: true,
|
||||
createInstance: ({ model, options }) => {
|
||||
const primaryMesh = model.findMesh('__X_PRIMARY__');
|
||||
const primaryMaterial = primaryMesh.material as BABYLON.PBRMaterial;
|
||||
|
||||
const secondaryMesh = model.findMesh('__X_SECONDARY__');
|
||||
const secondaryMaterial = secondaryMesh.material as BABYLON.PBRMaterial;
|
||||
const primaryMaterial = model.findMaterial('__X_PRIMARY__');
|
||||
const secondaryMaterial = model.findMaterial('__X_SECONDARY__');
|
||||
|
||||
const applyPrimaryColor = () => {
|
||||
const [r, g, b] = options.primaryColor;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ export const coffeeCup = defineObject({
|
|||
placement: 'top',
|
||||
hasCollisions: false,
|
||||
hasTexture: true,
|
||||
canPreMeshesMerging: true,
|
||||
createInstance: () => {
|
||||
return {
|
||||
interactions: {},
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ export const cupNoodle = defineObject({
|
|||
placement: 'top',
|
||||
hasCollisions: false,
|
||||
hasTexture: true,
|
||||
canPreMeshesMerging: true,
|
||||
createInstance: ({ scene, root }) => {
|
||||
let yugeDispose: (() => void) | null = null;
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export const custardPudding = defineObject({
|
|||
},
|
||||
placement: 'top',
|
||||
hasCollisions: false,
|
||||
canPreMeshesMerging: true,
|
||||
createInstance: () => {
|
||||
return {
|
||||
interactions: {},
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ export const desktopPc = defineObject({
|
|||
},
|
||||
placement: 'top',
|
||||
hasCollisions: true,
|
||||
canPreMeshesMerging: true,
|
||||
createInstance: ({ options, model, root, scene, room }) => {
|
||||
const light1 = new BABYLON.SpotLight('', new BABYLON.Vector3(0, cm(10), cm(22)), new BABYLON.Vector3(0, 0, 1), Math.PI / 1, 2, scene, room?.lightContainer != null);
|
||||
light1.parent = root;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ export const djMixer = defineObject({
|
|||
placement: 'top',
|
||||
hasCollisions: false,
|
||||
hasTexture: true,
|
||||
canPreMeshesMerging: true,
|
||||
createInstance: () => {
|
||||
return {
|
||||
interactions: {},
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ export const facialTissue = defineObject({
|
|||
placement: 'top',
|
||||
hasCollisions: false,
|
||||
hasTexture: true,
|
||||
canPreMeshesMerging: true,
|
||||
createInstance: () => {
|
||||
return {
|
||||
interactions: {},
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ export const hangingTShirt = defineObject({
|
|||
placement: 'side',
|
||||
hasCollisions: false,
|
||||
hasTexture: true,
|
||||
canPreMeshesMerging: true,
|
||||
createInstance: () => {
|
||||
return {
|
||||
interactions: {},
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export const keyboard = defineObject({
|
|||
},
|
||||
placement: 'top',
|
||||
hasCollisions: false,
|
||||
canPreMeshesMerging: true,
|
||||
createInstance: () => {
|
||||
return {
|
||||
interactions: {},
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export const letterCase = defineObject({
|
|||
default: {},
|
||||
},
|
||||
placement: 'top',
|
||||
canPreMeshesMerging: true,
|
||||
createInstance: () => {
|
||||
return {
|
||||
interactions: {},
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export const miPlate = defineObject({
|
|||
},
|
||||
placement: 'top',
|
||||
hasCollisions: false,
|
||||
canPreMeshesMerging: true,
|
||||
createInstance: () => {
|
||||
return {
|
||||
interactions: {},
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export const miPlateDisplayed = defineObject({
|
|||
},
|
||||
placement: 'top',
|
||||
hasCollisions: false,
|
||||
canPreMeshesMerging: true,
|
||||
createInstance: () => {
|
||||
return {
|
||||
interactions: {},
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ export const pachira = defineObject({
|
|||
placement: 'top',
|
||||
hasCollisions: true,
|
||||
hasTexture: true,
|
||||
canPreMeshesMerging: true,
|
||||
createInstance: () => {
|
||||
return {
|
||||
interactions: {},
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ export const piano = defineObject({
|
|||
},
|
||||
placement: 'floor',
|
||||
hasCollisions: true,
|
||||
canPreMeshesMerging: true,
|
||||
createInstance: ({ options, model }) => {
|
||||
const bodyMaterial = model.findMaterial('__X_BODY__');
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export const pizza = defineObject({
|
|||
},
|
||||
placement: 'top',
|
||||
hasCollisions: false,
|
||||
canPreMeshesMerging: true,
|
||||
createInstance: () => {
|
||||
return {
|
||||
interactions: {},
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ export const plant = defineObject({
|
|||
placement: 'top',
|
||||
hasCollisions: false,
|
||||
hasTexture: true,
|
||||
canPreMeshesMerging: true,
|
||||
createInstance: () => {
|
||||
return {
|
||||
interactions: {},
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ export const tabletopCalendar = defineObject({
|
|||
placement: 'top',
|
||||
hasCollisions: false,
|
||||
hasTexture: true,
|
||||
canPreMeshesMerging: true,
|
||||
createInstance: () => {
|
||||
return {
|
||||
interactions: {},
|
||||
|
|
|
|||
|
|
@ -417,18 +417,26 @@ export function createPlaneUvMapper(mesh: BABYLON.Mesh) {
|
|||
};
|
||||
}
|
||||
|
||||
export function findMaterial(rootMesh: BABYLON.AbstractMesh, keyword: string): BABYLON.PBRMaterial {
|
||||
export function findMaterial(rootMesh: BABYLON.AbstractMesh, keyword: string, allowMultiMaterial = false): BABYLON.PBRMaterial {
|
||||
for (const m of rootMesh.getChildMeshes()) {
|
||||
if (m.material == null) continue;
|
||||
if (m.material.name.includes(keyword)) {
|
||||
return m.material as BABYLON.PBRMaterial;
|
||||
} else if ((m.material as BABYLON.MultiMaterial).subMaterials != null) {
|
||||
if (m.material instanceof BABYLON.MultiMaterial) {
|
||||
if (allowMultiMaterial && m.material.name.includes(keyword)) {
|
||||
return m.material as BABYLON.MultiMaterial;
|
||||
}
|
||||
|
||||
if ((m.material as BABYLON.MultiMaterial).subMaterials == null) continue;
|
||||
|
||||
for (const sm of (m.material as BABYLON.MultiMaterial).subMaterials) {
|
||||
if (sm == null) continue;
|
||||
if (sm.name.includes(keyword)) {
|
||||
return sm as BABYLON.PBRMaterial;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (m.material.name.includes(keyword)) {
|
||||
return m.material as BABYLON.PBRMaterial;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new Error(`Material with keyword "${keyword}" not found`);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue