public void TestRelativeAccessor_ParentGet() { var root = RandomTransform(); var child = RandomTransform(root, 2); var AsParent = new TransformExtensions.RelativeAccessor(child.parent); // If the more precise implementation is used, Assert.AreEqual works VeryLooseEqual(TrTransform.FromLocalTransform(child), AsParent[child]); UnityEngine.Object.DestroyImmediate(root.gameObject); }
public void TestRelativeAccessor_UnrelatedGet() { var root = RandomTransform(); var left = RandomTransform(root, 2); var right = RandomTransform(root); var AsRight = new TransformExtensions.RelativeAccessor(right); VeryLooseEqual(TrTransform.FromTransform(right) * AsRight[left], TrTransform.FromTransform(left)); }
// Init unless already initialized. Safe to call zero or multiple times. public void Init() { if (m_bInitialized) { return; } m_bInitialized = true; AsCanvas = new TransformExtensions.RelativeAccessor(transform); }
public void TestRelativeAccessor_AncestorGet() { var root = RandomTransform(); var child = RandomTransform(root, 2); var AsAncestor = new TransformExtensions.RelativeAccessor(child.parent.parent); VeryLooseEqual(TrTransform.FromLocalTransform(child.parent) * TrTransform.FromLocalTransform(child), AsAncestor[child]); UnityEngine.Object.DestroyImmediate(root.gameObject); }
public void TestRelativeAccessor_SameSet() { var root = RandomTransform(); var child = RandomTransform(root, 2); var AsChild = new TransformExtensions.RelativeAccessor(child); try { Assert.That(() => AsChild[child] = RandomTr(), Throws.InvalidOperationException); } finally { UnityEngine.Object.DestroyImmediate(root.gameObject); } }
public void TestRelativeAccessor_ParentSet() { var root = RandomTransform(); var child = RandomTransform(root, 2); var AsParent = new TransformExtensions.RelativeAccessor(child.parent); var xf = RandomTr(); AsParent[child] = xf; VeryLooseEqual(AsParent[child], xf); VeryLooseEqual(TrTransform.FromTransform(child), TrTransform.FromTransform(child.parent) * xf); UnityEngine.Object.DestroyImmediate(root.gameObject); }
// Init unless already initialized. Safe to call zero or multiple times. public void Init() { if (m_bInitialized) { return; } m_bInitialized = true; m_LayerCanvases = new List <CanvasScript>(); AsScene = new TransformExtensions.RelativeAccessor(transform); m_ActiveCanvas = m_MainCanvas; foreach (var c in AllCanvases) { c.Init(); } }
private static void BuildModelsAsModelMeshes( SceneStatePayload payload, IEnumerable <ModelWidget> modelWidgets) { // This is a quadruple-nested loop that's triply flattened into a single IEnumerable. // The structure of the data is is: // 1. There are 1+ Models (which I'll call "prefab" because Model is a loaded term here) // 2. Each "prefab" is used by 1+ ModelWidgets ("instance") // 3. Each ModelWidget, and the "prefab", contains 1+ GameObjects (which has a single Mesh) // 4. Each Mesh has 1+ unity submeshes (almost always exactly 1) // These are converted to ModelMeshPayload // // The resulting ModelMeshPayloads are a mixture of data from all 4 levels, for example // - ModelMeshPayload.model comes from level 1 // - ModelMeshPayload.modelId comes from level 2 // - ModelMeshPayload.xform comes from level 3 // - ModelMeshPayload.pool comes from level 4 // // Orthogonal to this nesting, some data comes from the "prefab" and some from the "instance", // since we don't want to have to convert a mesh into GeometryPool once per instance. // So we iterate level 3 for the Model once, up front; then each ModelWidget level 3 is // a parallel iteration with that Model's pre-computed iteration. foreach (var group in modelWidgets.GroupBy(widget => widget.Model)) { Model prefab = group.Key; // Each element represents a GameObject in the "prefab" List <PrefabGeometry[]> prefabObjs = GetPrefabGameObjs(payload, prefab).ToList(); foreach ((ModelWidget widget, int widgetIndex) in group.WithIndex()) { Matrix4x4 widgetXform = ExportUtils.ChangeBasis(widget.transform, payload); // Acts like our AsScene[], AsCanvas[] accessors var AsWidget = new TransformExtensions.RelativeAccessor(widget.transform); // Verify that it's okay to parallel-iterate over the prefab and instance gameObjs. // It should be, unless one or the other has mucked with their m_MeshChildren. MeshFilter[] instanceObjs = widget.GetMeshes(); if (prefabObjs.Count != instanceObjs.Length) { Debug.LogError($"Bad Model instance: {prefabObjs.Count} {instanceObjs.Length}"); // TODO: check order as well, somehow continue; } // Parallel iterate, taking shared things (GeometryPool, material, name) from the // "prefab" and xforms, unique ids, etc from the "instance". for (int objIndex = 0; objIndex < prefabObjs.Count; ++objIndex) { PrefabGeometry[] prefabSubMeshes = prefabObjs[objIndex]; GameObject instanceObj = instanceObjs[objIndex].gameObject; Matrix4x4 localXform = ExportUtils.ChangeBasis(AsWidget[instanceObj.transform], payload); int objId = payload.idGenerator.GetIdFromInstanceId(instanceObj); Matrix4x4 xform = ExportUtils.ChangeBasis(instanceObj.transform, payload); foreach (PrefabGeometry prefabSubMesh in prefabSubMeshes) { payload.modelMeshes.Add(new ExportUtils.ModelMeshPayload( payload.groupIdMapping.GetId(widget.Group)) { // Copied from "prefab" model = prefabSubMesh.model, geometry = prefabSubMesh.pool, exportableMaterial = prefabSubMesh.exportableMaterial, geometryName = prefabSubMesh.name, // Unique to instance legacyUniqueName = $"{prefabSubMesh.name}_i{objId}", nodeName = $"{prefabSubMesh.name}_{widgetIndex}", parentXform = widgetXform, localXform = localXform, modelId = widgetIndex, xform = xform, }); } } } } }