From bd43b17aa55d9e1591898d7d418e124d4468dff1 Mon Sep 17 00:00:00 2001 From: Gary Hsu Date: Mon, 13 Oct 2025 17:24:31 -0700 Subject: [PATCH 1/3] Fix KHR_mesh_visibility issue with animation pointers --- .../Extensions/KHR_animation_pointer.data.ts | 13 ++++++++++++- .../glTF/2.0/Extensions/KHR_node_visibility.ts | 3 --- .../glTF/2.0/Extensions/objectModelMapping.ts | 17 +++++++++++++++++ 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_animation_pointer.data.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_animation_pointer.data.ts index 085cff13007..c2d144460ce 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_animation_pointer.data.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_animation_pointer.data.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { Animation } from "core/Animations/animation"; -import type { ICamera, IKHRLightsPunctual_Light, IMaterial } from "../glTFLoaderInterfaces"; +import type { ICamera, IKHRLightsPunctual_Light, IMaterial, INode } from "../glTFLoaderInterfaces"; import type { IAnimatable } from "core/Animations/animatable.interface"; import { AnimationPropertyInfo } from "../glTFLoaderAnimation"; import { Color3 } from "core/Maths/math.color"; @@ -73,6 +73,15 @@ class LightAnimationPropertyInfo extends AnimationPropertyInfo { } } +class MeshAnimationPropertyInfo extends AnimationPropertyInfo { + /** @internal */ + public buildAnimations(target: INode, name: string, fps: number, keys: any[]) { + return target._primitiveBabylonMeshes + ? target._primitiveBabylonMeshes.map((mesh) => ({ babylonAnimatable: mesh, babylonAnimation: this._buildAnimation(name, fps, keys) })) + : []; + } +} + SetInterpolationForKey("/cameras/{}/orthographic/xmag", [ new CameraAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "orthoLeft", getMinusFloat, () => 1), new CameraAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "orthoRight", getNextFloat, () => 1), @@ -326,3 +335,5 @@ SetInterpolationForKey("/extensions/KHR_lights_punctual/lights/{}/spot/outerCone SetInterpolationForKey("/nodes/{}/extensions/EXT_lights_ies/color", [new LightAnimationPropertyInfo(Animation.ANIMATIONTYPE_COLOR3, "diffuse", getColor3, () => 3)]); SetInterpolationForKey("/nodes/{}/extensions/EXT_lights_ies/multiplier", [new LightAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "intensity", getFloat, () => 1)]); + +SetInterpolationForKey("/nodes/{}/extensions/KHR_node_visibility/visible", [new MeshAnimationPropertyInfo(Animation.ANIMATIONTYPE_FLOAT, "isVisible", getFloat, () => 1)]); diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_node_visibility.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_node_visibility.ts index fc57756d63d..33c69dab669 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_node_visibility.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_node_visibility.ts @@ -76,9 +76,6 @@ export class KHR_node_visibility implements IGLTFLoaderExtension { // When the JSON Pointer is used we need to change both the transform node and the primitive meshes to the new value. if (node.extensions?.KHR_node_visibility) { if (node.extensions?.KHR_node_visibility.visible === false) { - if (node._babylonTransformNode) { - (node._babylonTransformNode as AbstractMesh).isVisible = false; - } node._primitiveBabylonMeshes?.forEach((mesh) => { mesh.isVisible = false; }); diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/objectModelMapping.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/objectModelMapping.ts index e47b3443384..b40218fab70 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/objectModelMapping.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/objectModelMapping.ts @@ -51,6 +51,9 @@ export interface IGLTFObjectModelTreeNodesObject; color: IObjectAccessor; }; + KHR_node_visibility?: { + visible: IObjectAccessor; + }; }; }; } @@ -386,6 +389,20 @@ const nodesTree: IGLTFObjectModelTreeNodesObject = { }, }, }, + KHR_node_visibility: { + visible: { + type: "boolean", + get: (node: INode) => { + return node._primitiveBabylonMeshes ? node._primitiveBabylonMeshes[0].isVisible : false; + }, + getTarget: () => undefined, // TODO: what should this return? + set: (value: boolean, node: INode) => { + if (node._primitiveBabylonMeshes) { + node._primitiveBabylonMeshes.forEach((mesh) => (mesh.isVisible = value)); + } + }, + }, + }, }, }, }; From 5eb881877a9ed02d3672a37498994eff4620a9e1 Mon Sep 17 00:00:00 2001 From: Gary Hsu Date: Tue, 14 Oct 2025 16:12:41 -0700 Subject: [PATCH 2/3] Fix issues with node visibility --- packages/dev/core/src/Meshes/abstractMesh.ts | 42 ------------------ packages/dev/core/src/node.ts | 30 +++++++++++++ .../2.0/Extensions/KHR_node_visibility.ts | 33 +++++++------- .../ReferenceImages/gltfNodeVisibility.png | Bin 15463 -> 15705 bytes .../tests/test/visualization/config.json | 2 +- 5 files changed, 49 insertions(+), 58 deletions(-) diff --git a/packages/dev/core/src/Meshes/abstractMesh.ts b/packages/dev/core/src/Meshes/abstractMesh.ts index 470816824b1..8a4e3b1eb1d 100644 --- a/packages/dev/core/src/Meshes/abstractMesh.ts +++ b/packages/dev/core/src/Meshes/abstractMesh.ts @@ -238,12 +238,6 @@ class _InternalAbstractMeshDataInfo { * We use that as a clue to force the material to sideOrientation = null */ public _sideOrientationHint = false; - - /** - * @internal - * if this is set to true, the mesh will be visible only if its parent(s) are also visible - */ - public _inheritVisibility = false; /** * Used in frame graph mode only, to know which meshes to update when in frozen mode */ @@ -558,42 +552,6 @@ export abstract class AbstractMesh extends TransformNode implements IDisposable, */ public alphaIndex = Number.MAX_VALUE; - /** - * If set to true, a mesh will only be visible only if its parent(s) are also visible (default is false) - */ - public get inheritVisibility(): boolean { - return this._internalAbstractMeshDataInfo._inheritVisibility; - } - - public set inheritVisibility(value: boolean) { - this._internalAbstractMeshDataInfo._inheritVisibility = value; - } - - private _isVisible = true; - /** - * Gets or sets a boolean indicating if the mesh is visible (renderable). Default is true - */ - public get isVisible(): boolean { - if (!this._isVisible || !this.inheritVisibility || !this._parentNode) { - return this._isVisible; - } - if (this._isVisible) { - let parent: Nullable = this._parentNode; - while (parent) { - const parentVisible = (parent as AbstractMesh).isVisible; - if (typeof parentVisible !== "undefined") { - return parentVisible; - } - parent = parent.parent; - } - } - return this._isVisible; - } - - public set isVisible(value: boolean) { - this._isVisible = value; - } - /** * Gets or sets a boolean indicating if the mesh can be picked (by scene.pick for instance or through actions). Default is true */ diff --git a/packages/dev/core/src/node.ts b/packages/dev/core/src/node.ts index c0dd5ea5b5f..53f512009ab 100644 --- a/packages/dev/core/src/node.ts +++ b/packages/dev/core/src/node.ts @@ -35,6 +35,8 @@ class _InternalNodeDataInfo { public _isReady = true; public _onEnabledStateChangedObservable = new Observable(); public _onClonedObservable = new Observable(); + public _inheritVisibility = false; + public _isVisible = true; } /** @@ -261,6 +263,34 @@ export class Node implements IBehaviorAware { return this._parentNode; } + /** + * If set to true, this node, when renderable, will only be visible if its parent(s) are also visible. + * @default false + */ + public get inheritVisibility(): boolean { + return this._nodeDataStorage._inheritVisibility; + } + + public set inheritVisibility(value: boolean) { + this._nodeDataStorage._inheritVisibility = value; + } + + /** + * Gets or sets a boolean indicating whether this node is visible, either this node itself when it is renderable or its renderable child nodes when `inheritVisibility` is true. + * @default true + */ + public get isVisible(): boolean { + if (this.inheritVisibility && this._parentNode && !this._parentNode.isVisible) { + return false; + } + + return this._nodeDataStorage._isVisible; + } + + public set isVisible(value: boolean) { + this._nodeDataStorage._isVisible = value; + } + /** * @internal */ diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_node_visibility.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_node_visibility.ts index 33c69dab669..4b76e9babd6 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_node_visibility.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_node_visibility.ts @@ -52,12 +52,13 @@ export class KHR_node_visibility implements IGLTFLoaderExtension { * The name of this extension. */ public readonly name = NAME; + /** * Defines whether this extension is enabled. */ public enabled: boolean; - private _loader: GLTFLoader; + private _loader?: GLTFLoader; /** * @internal @@ -67,25 +68,27 @@ export class KHR_node_visibility implements IGLTFLoaderExtension { this.enabled = loader.isExtensionUsed(NAME); } - // eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-misused-promises - public async onReady(): Promise { - this._loader.gltf.nodes?.forEach((node) => { - node._primitiveBabylonMeshes?.forEach((mesh) => { - mesh.inheritVisibility = true; - }); - // When the JSON Pointer is used we need to change both the transform node and the primitive meshes to the new value. - if (node.extensions?.KHR_node_visibility) { - if (node.extensions?.KHR_node_visibility.visible === false) { - node._primitiveBabylonMeshes?.forEach((mesh) => { - mesh.isVisible = false; - }); + public onReady(): void { + if (!this._loader) { + return; + } + + const nodes = this._loader.gltf.nodes; + if (nodes) { + for (const node of nodes) { + const babylonTransformNode = node._babylonTransformNode; + if (babylonTransformNode) { + babylonTransformNode.inheritVisibility = true; + if (node.extensions && node.extensions.KHR_node_visibility && node.extensions.KHR_node_visibility.visible === false) { + babylonTransformNode.isVisible = false; + } } } - }); + } } public dispose() { - (this._loader as any) = null; + delete this._loader; } } diff --git a/packages/tools/tests/test/visualization/ReferenceImages/gltfNodeVisibility.png b/packages/tools/tests/test/visualization/ReferenceImages/gltfNodeVisibility.png index 2adc8d298e0dd55018c611e84c8e60dedac7da45..fb6f2d259c36e5b16d087f3d376db308453ea017 100644 GIT binary patch literal 15705 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
?sK8-J; z@&8?^<5FJc(5E293UK(|(cxI!4FYO&=MMJhQfHBcXkkgo8$JHD)zyzZ{9_@;*RG)z z_ctDIvLUmCDovPQA?als3XtXa1qJKOv(+^;GP1JNQgw@lhlYl}ef!q@VxkZI1vsaZ z8zR~A`0-^#Po(>~v5)Z|9vQ~rhl8xAc6_?oRa&yJA zH&l21Lgn(P>zoL8a_Rjtsx^{N8hI`rt9~hC_HRo0zpKn~7O=~-_GFLElaZ)*Qp@Pa z4fPAb)gv)fV1;t7dXwa?Nk9+j=H|=r@zry5XKroNC2TXatb*)gf1$3ryza$3>Zx8y-;8+-lw^}BbX@^sc>czUY47!9tiv(qc(iq6^` zP^0xMAN7Z+DLZ@n>BdHF2!^qFH`1OkS#k1%nALO=i4X9K!r&ipDl`#lFB4j|5Irj) zfm^ObKE(30yR(yi?f$66QFeA&-&L0}m%54yd7A)^0>L1evi?|3JBBNc3tql>+`Kt( zPk14TcF@z5KPoIdJS4oJktZuNlYJ=p-Wlo-T5gXYUK}H&wT%I;`}%HV=-1AdwAlaw z?)~|G&`GD=`oe_^H*WMDYX>q+xUGHv{tP4udinF`pPqhDuF$b4(^z%WBA4LTrD%rk zQ$HYf3tdKaot@|F;w3p`Jl;G0K##qg^UtPypd{`YKu7$XCAz1ua2BX;sxFFWd0_zp zV@^gZ@B+BcLNGWf*b@$MP_M!91 zvawr>DMVs>YwOpq zUwNax#Kp1XbO=P&V5K9r`>6tnT7>%gdWpmPajjq+{86v7vvtzj>KhuC7Z;n(IJIuj z61=HDgr5LO1Nl)(ZUVTXYsL4j^PE4wF&JaU#7zA_!M=P$qD>qf(SPXck+1rK`T|abmqf8XbPd2+VRCAlT1SaP&ntMiL2q&k?K4|A~Crst;XUDB$xZt^Jf8! zjEv|J(`9R!n#7Rm0ra)$<(4;lGxUwk%*wN~PfJMT<>kFXubKaMpE<;lxY4 zz;*oF>Z&wITTD!3%`bcZHRCa@$l5`(jWGk#4IN|S;dVuFgM@Oga+_rGowK(Yt9Qr=!c#8tP{Qb){iSf^#y zd#BxsL2R_1OJz?p?qClm=Hxir*=h1b-o?Ytu5)rJFHa(_PxtE8QMY2;?5(Ct91u{= zO(te$#3SncrlE>ls024&hDX%{;JoE4b@n4~zy!g}I`bvr6rf+>{C7?2ll1x=zK<^| zCF@AX;jp{9x}wViZ1(Njmup|yCvr`LwOS{+FgLe#d=b`4etP;HtVAegdSb%X)>fN1 zWo%!X+GK6&w{ok*k%2m3MrUYv82&(amC~h4YO1Qb#uX<-PPina zx{~+x*h-j{`E>L-z&;2K55Me=8%{al;n_24%AMj< zPoko(T)qr(o~Fm&-rinaT|F8Xqnau%eepn+B3E`nK>;AaNLZgg${^DuLNyhjmTjm` zZ0WGgvr6=Q_3qu1IUbliumLH4s*M=-qH?cAo2yrkxGwDtcw1U}URs)8!rdd0gN-fKKP2*xvtgI{ zqoC^qPMs?DUKTok0&VaVKR*t?Ak#kAP@c$|)YKDRn_ADm#4B^-J4c4f?B6vcKd8Jx zY~ic7f1;X73NOA^;-O>meaVz`m-nK``P^(mqEdYhYHwvShlRA8(L3J8?oG{Qy_XF&^r_{=Jq zd(>vbxVAnjNV&k;2X#3!Ba+~{XX$R7`YUFf3b>Cr`r@R5w6rv|6}$Wvn*6Rw+=(NA z4;B_9L&FzW;QQea6crVrd~A-uP=i1yD=S-B0Yuw~98UC}Dy*rgfdNHq!8P4`b?oo$ zWJqRI)W^-#e`72nnl`9%ZHOj?#+y4*Wj0Jp^44t7)0l;Y+yV!#2s$F)BduCEU1O)u z=~lo}lwt2}H~u^?LrzPhAZ@rp5KIO3&zax*<3L7}S(AMgneE;BtjF_5iVd92+z$)| zl>8NzdG=D+SWJ&=KE>VOfTEV2k|j^`QV0C$ePQAk1BZmxdG)n0Wv+-9g>Q2I2;$IS z$RBwh&~#|$9=iZ3(%j)7;~)21$&+2`T#1Jl%=q`0UX+*Ng`l%9TN!dMU%M7x$5U4G zm?q!QL!M6d_s_s$_i4Xr@7|X2#r|OVL+_TNY)~*Qnv|_I zD?s0%)Jf@hTKZ(wq2sQ5+sXoW6U5{;M!PN%Fq{zF)MPZG0&c;EkrYeUt%b*G;X$Kl%)N6aBf?~2l;Oud{1DeJVtQ= z0Ln?H&C38cjy?Pmv4!pXZV*OzsCxXV!w1sb7gU}y|IGP|lk)oRQeM|yfk9v4`V+$q z1TEk3)zhZ?_RLsO%2U6mV;SH0SViako%mm8SA6k0vdFUenP@vhP*r~96Hw&7U*&qrqC zzrRZ&qQ4O>KN$<;`Q?_!Fw(>faLALE4yP>iVa4S z!Cg9`b($f(IzK-j)E2%4WE!PBtacnPl#OK$TwlfHrn)+fpvu$Y;=g7+JQ5q~>+Ni9 z1%!ngzJ6t}KOdoNftqu0a4JZ#ks(-QeTGE?CM&w>jT=e2BnHZgNw=+j=5p|5951g@KlJkH z<#CrHC_QA0IUUcX_dWbF?I491#PuF>GxljZ0D~Z$T#uRSc6LHcA&}I?-F~YJw~MazAhiY3%bh8Sc41*@&(s7laqH@ zJYlv&2wWG@GcaiX_ARc?GL9n`QlQpsQ}pou#Iw#y>1{N$w8hgee61ZqE*a(tPR^6|Pzqsl4j4+-boVMyG}hT`7XTrQtpUbFvE zaQfW2J0gcOO-qgR^cI2{8__Hg`x;LCim9!!E8*5<|bfG5HX3+4F)d%CLXsH7b{V%Q|nPoMr890V%B{{df)iUPDM zNw$EL8Ry%r_{bJ_o9gM|syz~y*EX807vO)8u1r)GI1VTYFhM%x7-ay4K}zlN<1=TF z7V`vxrqd7H|a!Y8;Ax6H8ux{^n7amX?+X z<&PGkO&db&;W$`7id>Orm%e@bwxGaJC`L;|10aLWcbTY}nrHtRVt#JU2^tC>y8AqG zA#m4?nM&H*B{^^3Hrh%c6ha7cUBuADq$F!+H)}*0pb39Izw4T=uI{yKccI=S;;YPSkUM<-{NhARbhKSh zN#VP93PJzzQYd%cbCCM+Aq`|`E`~#Z8iyUaZi-FVFW?7!S%s-11uP&*i0 zYiic7t`-5NgoX1vZ1vNlI+6PNSXrIKh9OEkd9vD8g2Soz1L0+s{hV@b@K=|E-N>R1zMy6*EB85arqOjk!o8PeskQw;Sl_+>nSr z84SO*o8B1;0F%LCSVDPNY0f3o-@A7Y#sX4oSXCE# zvMwb3(=z&;K*)OY2IB*Kyu9DLyP?3wCMU0%nK8>XjW32he*D{~48;o{N?IMxD=7%f z!-*B&u48K2)6~@GR48Op@DHHzREI$#RA(#ODe8dAJ`XG(J|L`)-K%XOaI#^pw3Z`i z!T3$It~y!ZasuV19gL{yOm&!ID`s9>%LWt;rT zll@XtUt>XA#eg6B>11q5W@gy%3T7JCmZz7Oml4}zG}T(Xv%7oJsc>69 z;R?QdQQbC-V;?IWXM5Gx*9Z7PxgR>IsV#^IQ4{w#G_PAh2`0v*n>W|XMyl<8{yLavgs?^cf2fnn~oNqBH?Z`=4 zD7ag_&VNO7$VebMh$DPJD)aSgRa=gD^;ZZ3!@_7B4L^@B;xdaQb*^jIaUR}})R>k0 z3k_11kcGJl%N%$WEKK~oykH`@U%^3HQaBE{`SogyAE4@V}B@I$_VQ)1hGFLwj zD{_|A8M7S@@;|km>1_b4T3eqQWk|%TQw74klTUABFH0z$9?(pb>1b^H)9N-lKR7OI?7|N zEV~m%0G*^t{so!X4%?-*jaG-0`b^+dPmgKQg3H#6OohS*!uvC zMwj#k4jjU5wnyh)x4ug?4HXx@j$$n?_D1lqot{$09fU7S`~2(N-yyM79((ug<7>Tr zBc#flY!rU*zWB|4Kze(YS#N%eN1~kWp-8F*8ylOnh+{PIQBR+48=wr#YCMskrNA6K z`ppA48;9p){8K!iVHgR|!;~9!0pZmi417hywk9Pjgj-TrxV^3E>8Ds}E+y*}nwVa> z;tH~v-sbhVY){w#|EW_|*}AJR>5@KcRn5zs8C^Pa{xIt4`>85t z*%@HrV`@M@-4zWT5i6#o0+4WhpIm~Yc=OF6Sut!pVkTfIf+#zt)~_#{b~{o$jN?Sa zPnxg8(E)A78>Jd#qojTtXluXFPv5t9@6LM^rR0y3Zr~dilbeM7W<&ZveyA=ut4W;i zcJI~D(#lFpd$CwOFpGk@smOeuP3!WBs)!_IZl|BWzG{7(muZ-Xau5$S@3jw)I{}d5 zdGSb0^H4CQ#sdw(auXq9cJnUUmcHS&KLXz7<+;rd)j^xa*Xf&@ZkL@S#+#n6h8=cX zX_e@&Zc_;3c0I7xnE*zT>ZeQoQmj2)U1|x3fjGXhy_K}qN?Z}GM!Pi(uyN)m9$Fe;;(+ZpQ(}w(?;5cM2y?~202&#(>rYM*NlEv|oG=n_Ji$z) z6Y4E<_!#!GJO@Fm=8f;LO(YQDI^s=UrHQLQ6q4w=H^cO-hCOA4g)w^}0al!ushQk_ z=qaYQt)(Th=$S$iNZLXtWk?klJI|LnOg7F~5H7vodkSL!kL`JhUbJ06^qLJ->n06V zAlfcVD28i-=l5?hw5DKc4lxFMTBEf%!%XWTQ$s^#=O;)bFq0z1`sys9TB?px9@ zVSmN-pHg=2?lJ7Nbqx)2>#8Zbw~?Io_rI*{OT#!&4M>s;cGJN@1g(I~^+cTq4Fbe~ zbV!sw7{>u1l|2A~3%*iPQUbI?3wxj-e`jA%<-)US9bzIIf-_-0zM8r^%*ee+qzF~I znbYwx_~T5g0v-EbuV@iUUl%FJ&X#9RY#+yf!;)7iY8MsMs%UL%TjDyd56L9JluY_d zd}7$G7%iFPbXVjs0x)T5X^8tV#{^_w@Ci5s1odUbX|DCW-f>wocRVIGyFr`j_A z@zSnc_qJdA;|If071rveU++QPLPJ9#YCKAN0ODTn@8Gm}dUlMupj0>Nde`fYEkD#H z+1l8wLL{uMt?iaaB>bOgAMra+UvXmO7t;p#7%-4MJ9kK{V-Rn69+CsTxb5A$z8m9a zs50?3vBUdUePq4(kCQoI;-yHOQRg|7K<`q(MpKP}0hmI#2VT2M-&t%AuUe-S6nFqZ zLF+6m?gzm0g(Sm}?HYkbl`8@Xhl>$?lxkGxv5I*gC8bZ$2~E~tKY#v?ripnG6B8dy z8j-4J+9mL`$OQNt@>gL`P%Ev&3UrZba|BrW`P zo0s9`hs(*K3IRhmCC{Ac2DyMh#Bp=pCoWwK-0A=L$1J0-g_l>{J3&zCNjC_EHyIfT z=e?udE@Ji$75VQFQhG*4YUG!J*=@6nBlcfuvGmuB(aCy#gA2^2Qy9ve3EPOWZn~sTz33!~5k=O5K0hq5@TdP@EI%{>u z4wo&LPTv-1k*9;CNzfc_ZEZ!aGkNHNLPT`5r9?c& zSGS$p-*NYPr~fm~17(v8>x&kW8FOK2~Aea}QfLPDwU z+R~37tgd`5h6Zp~O@y*AArGr%#Ndc@+^ zE#z-F4PM$7u#XJNSFeoSMsTVWYVTDt_m6i}*w1Zi7PK6c4UGaj51OD$8c9La`AXrF z`RSq;x^hoN2gcgc`)N{y?qiY%_(NzoNgbe+oRm(2c$co(E&nV&er=_}-!7-)sp=rq zBq!ZJHQP=cKC*Q)nT!fN%NmCFVoufOL5oE$h(SO=0AlaBXB(Kh+GZAYE^%ir3?IAZ z7{Iyy>!jROBP05t^~zN2g z1w#i5`Uh9*(f8*1LxlZ)9ELlUY9m$cxbWU=n+ZLuo-a{IdJ&`>=HjfPriMbR{qkjQ z#Rn79OMmH-Qkb3;Tm$tZk>F!apHr7k5Ly%gP&DODuQ7NX50^4Vn`+soP{kCE!E9dM z7lgkx)}b>Lxpb~xRq-}VZu&Je)O<&9l;I_DKgVg`+r4R~N=j7c{f=7}Y7!y54iQUO zLO=NuV@-q_;6H7PniwMoR(J5q{4R~CU2z95>*;Z`A5TOoBv)>KC@nFjh}}yFxiaPi z9vMX97b8X){S+x_uU~&L&(@9#(Z2%wNjglklmvguoT4RqY|+c;m>{GT-@(iKKF#}# z$xK2wZqLd7*ktBV;npSPzIcJz88FhDE;9|gjqX!8sJC*tNGEK~32)7H_;lO}WH*Xs6KdmfJn)KMV zYv03d#XQE{isN-RSH;ntkvPw?Nh31UPrt$w=_!*426GIlsb?9 zTqI#e#$KFdYnEec_VUJ)cQ`iNAq{>3LFo$geQ;99UF9V2IP*9E!JZK1V$o z1c<`kLbhP8r}>b;QC52V#x9J6B80KVDszZqU~M5KH5K@F!u78f1XHgGzk{tgS5}4z zy^^--7}9YX3^@KL-Ol%p4y*>o#%o9Xc}o))#5NnX6vLbG^N{zmY{R$k<2?$((f{km zdY`^I-^X)nFD_D3P^e#^Ls-{BhiBf4BMhVvIe@GC@6-R?lm8aP|MJt2yS3*|O`6~3 Tr|Ggd&J-#aH5D@zt_S=N_!J7X diff --git a/packages/tools/tests/test/visualization/config.json b/packages/tools/tests/test/visualization/config.json index bf20340c18f..e9cfe0a90f8 100644 --- a/packages/tools/tests/test/visualization/config.json +++ b/packages/tools/tests/test/visualization/config.json @@ -1197,7 +1197,7 @@ }, { "title": "GLTF Node visibility test", - "playgroundId": "#80DN99#3", + "playgroundId": "#80DN99#6", "referenceImage": "gltfNodeVisibility.png" }, { From 8491efecdc3a22d1ef2910ffdd85e48b6960962d Mon Sep 17 00:00:00 2001 From: Gary Hsu Date: Wed, 15 Oct 2025 13:03:44 -0700 Subject: [PATCH 3/3] Update isVisible property and add inheritVisibility property to the inspector v2 --- .../properties/nodes/abstractMeshProperties.tsx | 1 - .../src/components/properties/nodes/nodeProperties.tsx | 9 +++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/dev/inspector-v2/src/components/properties/nodes/abstractMeshProperties.tsx b/packages/dev/inspector-v2/src/components/properties/nodes/abstractMeshProperties.tsx index baceb989db6..c8e7a37cf97 100644 --- a/packages/dev/inspector-v2/src/components/properties/nodes/abstractMeshProperties.tsx +++ b/packages/dev/inspector-v2/src/components/properties/nodes/abstractMeshProperties.tsx @@ -48,7 +48,6 @@ export const AbstractMeshGeneralProperties: FunctionComponent<{ mesh: AbstractMe return ( <> - diff --git a/packages/dev/inspector-v2/src/components/properties/nodes/nodeProperties.tsx b/packages/dev/inspector-v2/src/components/properties/nodes/nodeProperties.tsx index c70462eae01..2f390a8b4f9 100644 --- a/packages/dev/inspector-v2/src/components/properties/nodes/nodeProperties.tsx +++ b/packages/dev/inspector-v2/src/components/properties/nodes/nodeProperties.tsx @@ -7,6 +7,7 @@ import { useObservableState } from "../../../hooks/observableHooks"; import { SwitchPropertyLine } from "shared-ui-components/fluent/hoc/propertyLines/switchPropertyLine"; import type { ISelectionService } from "../../../services/selectionService"; import { LinkToEntityPropertyLine } from "../linkToEntityPropertyLine"; +import { BoundProperty } from "../boundProperty"; export const NodeGeneralProperties: FunctionComponent<{ node: Node; selectionService: ISelectionService }> = (props) => { const { node, selectionService } = props; @@ -18,6 +19,14 @@ export const NodeGeneralProperties: FunctionComponent<{ node: Node; selectionSer <> node.setEnabled(checked)} /> + + ); };