From 979da1a147ff4b7f391a8aa37e17014b429605f8 Mon Sep 17 00:00:00 2001 From: Ammar Askar Date: Sat, 19 Aug 2023 10:44:52 -0400 Subject: [PATCH] Add ability to render multiple scenegraph resources to a single ScenegraphComponent --- .../OpenTS2/Components/ScenegraphComponent.cs | 95 ++++++++++++------- .../Components/SimCharacterComponent.cs | 29 +++--- 2 files changed, 74 insertions(+), 50 deletions(-) diff --git a/Assets/Scripts/OpenTS2/Components/ScenegraphComponent.cs b/Assets/Scripts/OpenTS2/Components/ScenegraphComponent.cs index 2510867..74f322f 100644 --- a/Assets/Scripts/OpenTS2/Components/ScenegraphComponent.cs +++ b/Assets/Scripts/OpenTS2/Components/ScenegraphComponent.cs @@ -25,7 +25,12 @@ namespace OpenTS2.Components /// public static GameObject CreateRootScenegraph(ScenegraphResourceAsset resourceAsset) { - var scenegraph = CreateScenegraphComponent(resourceAsset); + return CreateRootScenegraph(new []{ resourceAsset }); + } + + public static GameObject CreateRootScenegraph(ScenegraphResourceAsset[] resourceAssets) + { + var scenegraph = CreateScenegraphComponent(resourceAssets); var simsTransform = new GameObject(scenegraph.name + "_transform"); // Apply a transformation to convert from the sims coordinate space to unity. @@ -40,37 +45,52 @@ namespace OpenTS2.Components /// Same as `CreateRootScenegraph` except it doesn't apply the transform from sims to unity space. /// public static ScenegraphComponent CreateScenegraphComponent(ScenegraphResourceAsset resourceAsset) + { + return CreateScenegraphComponent(new[] { resourceAsset }); + } + + /// + /// Creates a scenegraph component from a multiple scenegraph resource assets. + /// + public static ScenegraphComponent CreateScenegraphComponent(ScenegraphResourceAsset[] resourceAssets) { var scenegraph = new GameObject("scenegraph", typeof(ScenegraphComponent)); var scenegraphComponent = scenegraph.GetComponent(); - scenegraphComponent.CreateFromScenegraphComponent(resourceAsset.ResourceCollection, resourceAsset.GlobalTGI); + scenegraphComponent.CreateFromScenegraphComponents(resourceAssets.Select(asset => asset.ResourceCollection), + resourceAssets[0].GlobalTGI); return scenegraphComponent; } - public ScenegraphResourceCollection ResourceCollection { get; private set; } private ResourceKey _resourceAssetKey; - private void CreateFromScenegraphComponent(ScenegraphResourceCollection resourceCollection, + private void CreateFromScenegraphComponents(IEnumerable resourceCollections, ResourceKey resourceAssetKey) { _resourceAssetKey = resourceAssetKey; - ResourceCollection = resourceCollection; - var firstResourceNode = ResourceCollection.Blocks.OfType().First(); + foreach (var rCol in resourceCollections) + { + RenderScenegraphResourceCollection(rCol); + } + + BindBonesInMeshes(); + ComputeRelativeBoneAndBlendPaths(); + } + + private void RenderScenegraphResourceCollection(ScenegraphResourceCollection resourceCollection) + { + var firstResourceNode = resourceCollection.Blocks.OfType().First(); name = firstResourceNode.ResourceName; - // Traverse the graph if present and render out any sub-resources. + // Traverse the graph if present and render out any sub-nodes. try { if (firstResourceNode.Tree != null) { - RenderCompositionTree(gameObject, firstResourceNode.Tree); + RenderCompositionTree(gameObject, resourceCollection, firstResourceNode.Tree); } - - BindBonesInMeshes(); - ComputeRelativeBoneAndBlendPaths(); } catch (Exception e) { @@ -165,17 +185,17 @@ namespace OpenTS2.Components renderer.sharedMesh.bindposes = primitive.BindPoses; } - private void RenderCompositionTree(GameObject parent, CompositionTreeNodeBlock tree) + private void RenderCompositionTree(GameObject parent, ScenegraphResourceCollection rCol, CompositionTreeNodeBlock tree) { foreach (var reference in tree.References) { switch (reference) { case InternalReference internalRef: - RenderInternalCompositionTreeChild(parent, internalRef); + RenderInternalCompositionTreeChild(parent, rCol, internalRef); break; case ExternalReference externalRef: - RenderExternalCompositionTreeChild(parent, externalRef); + RenderExternalCompositionTreeChild(parent, rCol, externalRef); break; case NullReference nullRef: throw new ArgumentException("Got null reference in CompositionTree"); @@ -190,7 +210,7 @@ namespace OpenTS2.Components throw new ArgumentException("Got non-internal reference for Extension in resource node"); } - var extension = ResourceCollection.Blocks[internalRef.BlockIndex]; + var extension = rCol.Blocks[internalRef.BlockIndex]; switch (extension) { case DataListExtensionBlock extensionBlock: @@ -205,7 +225,7 @@ namespace OpenTS2.Components } } - private void HandleExtension(GameObject parent, DataListExtensionBlock extension) + private static void HandleExtension(GameObject parent, DataListExtensionBlock extension) { // This is the only extension we care about right now. if (extension.Value.Name != "EffectsList") @@ -243,31 +263,31 @@ namespace OpenTS2.Components } } - private void RenderInternalCompositionTreeChild(GameObject parent, InternalReference reference) + private void RenderInternalCompositionTreeChild(GameObject parent, ScenegraphResourceCollection rCol, InternalReference reference) { - var block = ResourceCollection.Blocks[reference.BlockIndex]; + var block = rCol.Blocks[reference.BlockIndex]; switch (block) { case ShapeRefNodeBlock shapeRef: - RenderShapeRefNode(parent, shapeRef); + RenderShapeRefNode(parent, rCol, shapeRef); break; case TransformNodeBlock transformNode: - RenderTransformNode(parent, transformNode); + RenderTransformNode(parent, rCol, transformNode); break; case ResourceNodeBlock resourceNode: - RenderResourceNode(parent, resourceNode); + RenderResourceNode(parent, rCol, resourceNode); break; case LightRefNodeBlock lightRef: - RenderLightRefNode(parent, lightRef); + RenderLightRefNode(parent, rCol, lightRef); break; default: throw new ArgumentException($"Unsupported block type in render composition tree {block}"); } } - private void RenderExternalCompositionTreeChild(GameObject parent, ExternalReference reference) + private static void RenderExternalCompositionTreeChild(GameObject parent, ScenegraphResourceCollection rCol, ExternalReference reference) { - var resourceKey = ResourceCollection.FileLinks[reference.FileLinksIndex]; + var resourceKey = rCol.FileLinks[reference.FileLinksIndex]; switch (resourceKey.TypeID) { default: @@ -275,7 +295,7 @@ namespace OpenTS2.Components } } - private void RenderTransformNode(GameObject parent, TransformNodeBlock transformNode) + private void RenderTransformNode(GameObject parent, ScenegraphResourceCollection rCol, TransformNodeBlock transformNode) { var transformName = "transform"; @@ -284,8 +304,15 @@ namespace OpenTS2.Components { transformName = transformTag; } + // If we've already rendered this transform node, just use that. Otherwise make a new unity GameObject for it. + if (transformTag != "" && _boneNamesToTransform.TryGetValue(transformName, out var existing)) + { + RenderCompositionTree(existing.gameObject, rCol, transformNode.CompositionTree); + return; + } + var transformObj = new GameObject(transformName, typeof(AssetReferenceComponent)); - RenderCompositionTree(transformObj, transformNode.CompositionTree); + RenderCompositionTree(transformObj, rCol, transformNode.CompositionTree); transformObj.transform.localRotation = transformNode.Rotation; transformObj.transform.position = transformNode.Transform; @@ -295,12 +322,12 @@ namespace OpenTS2.Components _boneNamesToTransform[transformName] = transformObj.transform; } - private void RenderResourceNode(GameObject parent, ResourceNodeBlock resource) + private static void RenderResourceNode(GameObject parent, ScenegraphResourceCollection rCol, ResourceNodeBlock resource) { // TODO: handle non-external resources, maybe merge with the `CreateRootGameObject` code. var resourceRef = resource.ResourceLocation; Debug.Assert(resourceRef is ExternalReference); - var key = ResourceCollection.FileLinks[((ExternalReference)resourceRef).FileLinksIndex]; + var key = rCol.FileLinks[((ExternalReference)resourceRef).FileLinksIndex]; var resourceAsset = ContentProvider.Get().GetAsset(key); if (resourceAsset == null) @@ -312,11 +339,11 @@ namespace OpenTS2.Components resourceObject.transform.SetParent(parent.transform, worldPositionStays:false); } - private void RenderShapeRefNode(GameObject parent, ShapeRefNodeBlock shapeRef) + private void RenderShapeRefNode(GameObject parent, ScenegraphResourceCollection rCol, ShapeRefNodeBlock shapeRef) { var shapeTransform = shapeRef.Renderable.Bounded.Transform; // Render any sub-objects in the transform node. - RenderTransformNode(parent, shapeTransform); + RenderTransformNode(parent, rCol, shapeTransform); // TODO: handle multiple shapes here. if (shapeRef.Shapes.Length == 0) @@ -324,7 +351,7 @@ namespace OpenTS2.Components return; } Debug.Assert(shapeRef.Shapes[0] is ExternalReference); - var shapeKey = ResourceCollection.FileLinks[((ExternalReference) shapeRef.Shapes[0]).FileLinksIndex]; + var shapeKey = rCol.FileLinks[((ExternalReference) shapeRef.Shapes[0]).FileLinksIndex]; if (shapeKey.GroupID == GroupIDs.Local) { @@ -405,14 +432,14 @@ namespace OpenTS2.Components } } - private void RenderLightRefNode(GameObject parent, LightRefNodeBlock lightRef) + private void RenderLightRefNode(GameObject parent, ScenegraphResourceCollection rCol, LightRefNodeBlock lightRef) { var shapeTransform = lightRef.Renderable.Bounded.Transform; // Render any sub-objects in the transform node. - RenderTransformNode(parent, shapeTransform); + RenderTransformNode(parent, rCol, shapeTransform); Debug.Assert(lightRef.Light is ExternalReference); - var lightKey = ResourceCollection.FileLinks[((ExternalReference) lightRef.Light).FileLinksIndex]; + var lightKey = rCol.FileLinks[((ExternalReference) lightRef.Light).FileLinksIndex]; if (lightKey.GroupID == GroupIDs.Local) { diff --git a/Assets/Scripts/OpenTS2/Components/SimCharacterComponent.cs b/Assets/Scripts/OpenTS2/Components/SimCharacterComponent.cs index 7d23087..07a8c3b 100644 --- a/Assets/Scripts/OpenTS2/Components/SimCharacterComponent.cs +++ b/Assets/Scripts/OpenTS2/Components/SimCharacterComponent.cs @@ -15,27 +15,24 @@ namespace OpenTS2.Components public static SimCharacterComponent CreateNakedBaseSim() { const string nakedBodyResourceName = "amBodyNaked_cres"; - var resource = ContentProvider.Get().GetAsset( + var nakedBodyAsset = ContentProvider.Get().GetAsset( new ResourceKey(nakedBodyResourceName, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_CRES)); - var bodyObject = resource.CreateRootGameObject(); - var scenegraph = bodyObject.GetComponentInChildren(); + const string baldHairResourceName = "amHairBald_cres"; + var baldHairAsset = ContentProvider.Get().GetAsset( + new ResourceKey(baldHairResourceName, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_CRES)); + + const string baseFaceResourceName = "amFace_cres"; + var baseFaceAsset = ContentProvider.Get().GetAsset( + new ResourceKey(baseFaceResourceName, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_CRES)); + + var simsObject = + ScenegraphComponent.CreateRootScenegraph(new[] { nakedBodyAsset, baldHairAsset, baseFaceAsset }); + var scenegraph = simsObject.GetComponentInChildren(); var gameObject = new GameObject("sim_character", typeof(SimCharacterComponent)); - bodyObject.transform.parent = gameObject.transform; + simsObject.transform.parent = gameObject.transform; return gameObject.GetComponent(); - - /* - resourceName = "amBodyNaked_cres"; - resource = contentProvider.GetAsset( - new ResourceKey(resourceName, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_CRES)); - var bodyObject = resource.CreateRootGameObject(); - - resourceName = "amHairBald_cres"; - resource = contentProvider.GetAsset( - new ResourceKey(resourceName, GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_CRES)); - var hairObject = resource.CreateRootGameObject(); - */ } } } \ No newline at end of file