From d64ac05ffeb5083491b71d489ecbef607221440e Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Mon, 27 Apr 2026 00:13:08 +0200 Subject: [PATCH] Refactor model instance rendering and selection logic in ViewportHost --- src/viewport-three/viewport-host.ts | 139 ++++++++++++++++++++-------- 1 file changed, 99 insertions(+), 40 deletions(-) diff --git a/src/viewport-three/viewport-host.ts b/src/viewport-three/viewport-host.ts index 960d42f5..d270d0d5 100644 --- a/src/viewport-three/viewport-host.ts +++ b/src/viewport-three/viewport-host.ts @@ -6048,6 +6048,23 @@ export class ViewportHost { ) { this.clearModelInstances(); + const displayedModelInstances = this.getDisplayedModelInstances(document); + + for (const modelInstance of displayedModelInstances) { + if (!modelInstance.enabled || !modelInstance.visible) { + continue; + } + + this.addModelInstanceRenderGroup( + modelInstance, + isModelInstanceSelected(selection, modelInstance.id) + ); + } + + this.applyShadowState(); + } + + private getDisplayedModelInstances(document: SceneDocument): ModelInstance[] { const runtimeModelInstances = this.currentSimulationScene?.modelInstances ?? null; const authoredModelInstancesById = new Map( @@ -6079,49 +6096,91 @@ export class ViewportHost { animationAutoplay: runtimeModelInstance.animationAutoplay }); }) ?? getModelInstances(document.modelInstances); + } - for (const modelInstance of displayedModelInstances) { - if (!modelInstance.enabled || !modelInstance.visible) { - continue; - } - - const selected = isModelInstanceSelected(selection, modelInstance.id); - const asset = this.projectAssets[modelInstance.assetId]; - const loadedAsset = this.loadedModelAssets[modelInstance.assetId]; - const renderGroup = createModelInstanceRenderGroup( - modelInstance, - asset, - loadedAsset, - selected, - undefined, - this.displayMode === "wireframe" ? "wireframe" : "normal" - ); - applyRendererRenderCategoryFromMaterial(renderGroup); - - if (asset?.kind === "model" && modelInstance.collision.visible) { - try { - const generatedCollider = buildGeneratedModelCollider( - modelInstance, - asset, - loadedAsset - ); - - if (generatedCollider !== null) { - const colliderDebugGroup = - createModelColliderDebugGroup(generatedCollider); - applyRendererRenderCategory(colliderDebugGroup, "overlay"); - renderGroup.add(colliderDebugGroup); - } - } catch { - // Validation surfaces unsupported collider modes; the viewport keeps rendering the model. - } - } - - this.modelGroup.add(renderGroup); - this.modelRenderObjects.set(modelInstance.id, renderGroup); + private getDisplayedModelInstanceById( + modelInstanceId: string + ): ModelInstance | null { + if (this.currentDocument === null) { + return null; } - this.applyShadowState(); + return ( + this.getDisplayedModelInstances(this.currentDocument).find( + (modelInstance) => modelInstance.id === modelInstanceId + ) ?? null + ); + } + + private addModelInstanceRenderGroup( + modelInstance: ModelInstance, + selected: boolean + ) { + const asset = this.projectAssets[modelInstance.assetId]; + const loadedAsset = this.loadedModelAssets[modelInstance.assetId]; + const renderGroup = createModelInstanceRenderGroup( + modelInstance, + asset, + loadedAsset, + selected, + undefined, + this.displayMode === "wireframe" ? "wireframe" : "normal" + ); + applyRendererRenderCategoryFromMaterial(renderGroup); + + if (asset?.kind === "model" && modelInstance.collision.visible) { + try { + const generatedCollider = buildGeneratedModelCollider( + modelInstance, + asset, + loadedAsset + ); + + if (generatedCollider !== null) { + const colliderDebugGroup = + createModelColliderDebugGroup(generatedCollider); + applyRendererRenderCategory(colliderDebugGroup, "overlay"); + renderGroup.add(colliderDebugGroup); + } + } catch { + // Validation surfaces unsupported collider modes; the viewport keeps rendering the model. + } + } + + this.modelGroup.add(renderGroup); + this.modelRenderObjects.set(modelInstance.id, renderGroup); + } + + private refreshModelInstanceSelectionPresentationForId( + modelInstanceId: string + ) { + const renderGroup = this.modelRenderObjects.get(modelInstanceId); + + if (renderGroup === undefined) { + return; + } + + const modelInstance = this.getDisplayedModelInstanceById(modelInstanceId); + + if (modelInstance === null) { + return; + } + + syncModelInstanceSelectionShell( + renderGroup, + this.projectAssets[modelInstance.assetId], + isModelInstanceSelected(this.currentSelection, modelInstanceId) + ); + applyRendererRenderCategoryFromMaterial(renderGroup); + applyAdvancedRenderingRenderableShadowFlags( + renderGroup, + this.currentWorld !== null && + (this.currentSimulationScene?.world ?? this.currentWorld) + .advancedRendering.enabled && + (this.currentSimulationScene?.world ?? this.currentWorld) + .advancedRendering.shadows.enabled && + this.displayMode === "normal" + ); } private createEntityRenderObjects(