mirror of
https://github.com/misskey-dev/misskey.git
synced 2026-05-13 14:05:35 +02:00
wip
This commit is contained in:
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`);
|
||||
|
||||
Reference in New Issue
Block a user