From 74d17baf5adff754945f2fbe99c55796b3ab101d Mon Sep 17 00:00:00 2001 From: Jakub-Krakowiak Date: Thu, 27 Jul 2023 15:08:20 +0200 Subject: [PATCH 01/10] Added heightmap and trees --- .../Scripts/LowLevelWrappers/RGLMeshObject.cs | 26 +++++- Assets/RGLUnityPlugin/Scripts/SceneManager.cs | 83 +++++++++++++++++ .../Scripts/Utilities/TerrainUtilities.cs | 88 +++++++++++++++++++ .../Utilities/TerrainUtilities.cs.meta | 3 + 4 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs create mode 100644 Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs.meta diff --git a/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs index 91d6a47a9..f6776d29f 100644 --- a/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs +++ b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs @@ -17,7 +17,8 @@ using UnityEngine.Assertions; // Experimental is necessary for gathering GraphicsFormat of the texture. using UnityEngine.Experimental.Rendering; -using Unity.Collections; +using System.Collections.Generic; +using Unity.VisualScripting; namespace RGLUnityPlugin { @@ -59,7 +60,7 @@ public RGLObject(string identifier, RGLMesh rglMesh, Func getLocalToW DestroyFromRGL(); } - public void DestroyFromRGL() + public virtual void DestroyFromRGL() { if (rglEntityPtr != IntPtr.Zero) { @@ -153,6 +154,27 @@ public void SetIntensityTexture(RGLTexture texture) } } + public class RGLTerrainObject : RGLObject + { + public List TerrainSubObjects; + + public RGLTerrainObject(string identifier, RGLMesh rglMesh, Func getLocalToWorld, GameObject representedGO) + : base(identifier, rglMesh, getLocalToWorld, representedGO) + { + TerrainSubObjects = new List(); + } + + public override void DestroyFromRGL() + { + foreach (var terrainSubObject in TerrainSubObjects) + { + terrainSubObject.DestroyFromRGL(); + } + + base.DestroyFromRGL(); + } + } + /// /// RGL counterpart of Unity Mesh. /// Contains information about RGL mesh. diff --git a/Assets/RGLUnityPlugin/Scripts/SceneManager.cs b/Assets/RGLUnityPlugin/Scripts/SceneManager.cs index fe4b92f65..83535efe4 100644 --- a/Assets/RGLUnityPlugin/Scripts/SceneManager.cs +++ b/Assets/RGLUnityPlugin/Scripts/SceneManager.cs @@ -145,6 +145,11 @@ public void DoUpdate() var toAddGOs = new HashSet(thisFrameGOs); toAddGOs.ExceptWith(lastFrameGameObjects); RGLObject[] toAdd = IntoRGLObjects(toAddGOs).ToArray(); + RGLObject[] toAddTerrain = IntoRGLTerrain(toAddGOs).ToArray(); + if (toAddTerrain.Length != 0) + { + toAdd = toAdd.Concat(toAddTerrain).ToArray(); + } // Removed var toRemoveGOs = new HashSet(lastFrameGameObjects); @@ -178,6 +183,15 @@ public void DoUpdate() { sharedMeshesUsageCount[rglObject.RglMesh.Identifier] -= 1; } + + var terrainObject = rglObject as RGLTerrainObject; + if (terrainObject != null) + { + foreach (var terrainSubObject in terrainObject.TerrainSubObjects) + { + sharedMeshesUsageCount[terrainSubObject.RglMesh.Identifier] -= 1; + } + } updateSemanticDict(rglObject); rglObject.DestroyFromRGL(); @@ -331,6 +345,13 @@ private static IEnumerable IntoRGLObjectsUsingCollider(IEnumerable IntoRGLObjectsUsingMeshes(IEnumerable IntoRGLTerrain(IEnumerable gameObjects) + { + foreach (var gameObject in gameObjects) + { + if (gameObject.TryGetComponent(out var terrain)) + { + yield return TerrainToRGLObject(terrain); + } + } + } + private static RGLObject ColliderToRGLObject(Collider collider) { var mesh = ColliderUtilities.GetMeshForCollider(collider); @@ -454,6 +486,57 @@ private static RGLObject MeshFilterToRGLObject(MeshFilter meshFilter) gameObject); } + private static RGLObject TerrainToRGLObject(Terrain terrain) + { + var mesh = TerrainUtilities.GetTerrainMesh(terrain); + string meshId = $"r#{mesh.GetInstanceID()}"; + if (!sharedMeshes.ContainsKey(meshId)) + { + RGLMesh rglMesh = new RGLMesh(meshId, mesh); + sharedMeshes.Add(meshId, rglMesh); + sharedMeshesUsageCount.Add(meshId, 0); + } + + var terrainData = terrain.terrainData; + var terrainGO = terrain.gameObject; + var terrainRGLObject = new RGLTerrainObject($"{terrainGO.name}#{terrainGO.GetInstanceID()}", + sharedMeshes[meshId], + () => terrain.transform.localToWorldMatrix, + terrainGO); + + for (var i = 0; i < terrainData.treeInstanceCount; i++) + { + var treeMesh = TerrainUtilities.GetTreeMesh(terrain, i); + string treeMeshId = $"r#{treeMesh.GetInstanceID()}"; + if (!treeMesh.isReadable) + { + Debug.LogWarning($"Tree mesh of prefab: '" + + $"{terrainData.treePrototypes[terrainData.treeInstances[i].prototypeIndex].prefab.name}' " + + $"is not readable, skipping tree {i}, please set the model's 'Read/Write Enabled' attribute to true"); + continue; + } + if (!sharedMeshes.ContainsKey(treeMeshId)) + { + RGLMesh rglMesh = new RGLMesh(treeMeshId, treeMesh); + sharedMeshes.Add(treeMeshId, rglMesh); + sharedMeshesUsageCount.Add(treeMeshId, 1); + } + else + { + sharedMeshesUsageCount[treeMeshId]++; + } + + var tree = new RGLObject($"{terrainGO.name}#{terrainGO.GetInstanceID()}#{i}", + sharedMeshes[treeMeshId], + () => terrain.transform.localToWorldMatrix * TerrainUtilities.GetTreePose(terrain, i), + terrainGO); + tree.UpdateTransform(); + terrainRGLObject.TerrainSubObjects.Add(tree); + } + + return terrainRGLObject; + } + /// /// Some prefabs have LOD Group component (Level Of Detail) /// which implies using different renders based on the distance from the camera. diff --git a/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs b/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs new file mode 100644 index 000000000..ad0c03d83 --- /dev/null +++ b/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs @@ -0,0 +1,88 @@ + +using UnityEngine.Rendering; +using UnityEngine; +using System; + +namespace RGLUnityPlugin +{ + public class TerrainUtilities + { + public static Mesh GetTerrainMesh(Terrain terrain) + { + var terrainData = terrain.terrainData; + var resolution = terrainData.heightmapResolution; + var heights = terrainData.GetHeights(0, 0, resolution, resolution); + var scale = terrainData.heightmapScale; + var vertices = new Vector3[resolution * resolution]; + + for (var i = 0; i < resolution; i++) + { + for (var j = 0; j < resolution; j++) + { + vertices[i * resolution + j].x = i * scale.x; + vertices[i * resolution + j].y = heights[j, i] * scale.y; + vertices[i * resolution + j].z = j * scale.z; + } + } + + var quadResolution = resolution - 1; + var triangles = new int[quadResolution * quadResolution * 2 * 3]; + + for (var i = 0; i < quadResolution; i++) + { + for (var j = 0; j < quadResolution; j++) + { + var sampleBase = i * resolution + j; + var quadBase = 6 * (i * quadResolution + j); + + // first triangle of quad + triangles[quadBase] = sampleBase; + triangles[quadBase + 1] = sampleBase + resolution; + triangles[quadBase + 2] = sampleBase + resolution + 1; + + // second triangle of quad + triangles[quadBase + 3] = sampleBase; + triangles[quadBase + 4] = sampleBase + 1; + triangles[quadBase + 5] = sampleBase + resolution + 1; + } + } + + var mesh = new Mesh(); + mesh.indexFormat = IndexFormat.UInt32; + mesh.vertices = vertices; + mesh.triangles = triangles; + + return mesh; + } + + public static Mesh GetTreeMesh(Terrain terrain, int treeIndex) + { + var terrainData = terrain.terrainData; + var treeInstance = terrainData.treeInstances[treeIndex]; + var treePrototype = terrainData.treePrototypes[treeInstance.prototypeIndex]; + return treePrototype.prefab.GetComponent().sharedMesh; + } + + public static Matrix4x4 GetTreePose(Terrain terrain, int treeIndex) + { + var terrainPosition = terrain.transform.position; + var terrainData = terrain.terrainData; + var resolution = terrainData.heightmapResolution; + var heightmapScale = terrainData.heightmapScale; + var treeInstance = terrainData.treeInstances[treeIndex]; + var treePosition = treeInstance.position; + + var translation = new Vector3(treePosition.x, 0, treePosition.z); + translation.x *= heightmapScale.x * (resolution - 1); + translation.z *= heightmapScale.z * (resolution - 1); + var samplePose = new Vector3(terrainPosition.x + translation.x, 0, terrainPosition.z + translation.z); + translation.y = terrain.SampleHeight(samplePose); + + var rotation = Quaternion.AngleAxis((float)(treeInstance.rotation / Math.PI * 180), Vector3.up); + + var scale = new Vector3(treeInstance.widthScale, treeInstance.heightScale, treeInstance.widthScale); + + return Matrix4x4.TRS(translation, rotation, scale); + } + } +} \ No newline at end of file diff --git a/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs.meta b/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs.meta new file mode 100644 index 000000000..0c582e395 --- /dev/null +++ b/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1719548a6c3b4d6b90c6162fec245261 +timeCreated: 1690364114 \ No newline at end of file From 7c94e52147b29b10fcd353a19b3088005f1e37e2 Mon Sep 17 00:00:00 2001 From: Jakub-Krakowiak Date: Fri, 4 Aug 2023 12:40:46 +0200 Subject: [PATCH 02/10] code cleanup and added comments --- Assets/RGLUnityPlugin/Scripts/SceneManager.cs | 12 ++++ .../Scripts/Utilities/TerrainUtilities.cs | 71 +++++++++++-------- 2 files changed, 53 insertions(+), 30 deletions(-) diff --git a/Assets/RGLUnityPlugin/Scripts/SceneManager.cs b/Assets/RGLUnityPlugin/Scripts/SceneManager.cs index 83535efe4..0e27a459a 100644 --- a/Assets/RGLUnityPlugin/Scripts/SceneManager.cs +++ b/Assets/RGLUnityPlugin/Scripts/SceneManager.cs @@ -486,6 +486,14 @@ private static RGLObject MeshFilterToRGLObject(MeshFilter meshFilter) gameObject); } + /// + /// This function adds the Terrain game object with a mesh based on the heightmap of the terrain as well as + /// all trees of the terrain game object as separate instances in RGL. + /// Tree transforms are updated only once per simulation, since the terrain object is static (Cannot be moved) + /// while simulation is running. + /// This function relies on the tree prefabs having a LOD (Level Of Detail) component and + /// a mesh renderer of LOD0 having a mesh filter. + /// private static RGLObject TerrainToRGLObject(Terrain terrain) { var mesh = TerrainUtilities.GetTerrainMesh(terrain); @@ -507,6 +515,10 @@ private static RGLObject TerrainToRGLObject(Terrain terrain) for (var i = 0; i < terrainData.treeInstanceCount; i++) { var treeMesh = TerrainUtilities.GetTreeMesh(terrain, i); + if (treeMesh is null) + { + continue; + } string treeMeshId = $"r#{treeMesh.GetInstanceID()}"; if (!treeMesh.isReadable) { diff --git a/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs b/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs index ad0c03d83..ee171e515 100644 --- a/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs +++ b/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs @@ -1,7 +1,6 @@ using UnityEngine.Rendering; using UnityEngine; -using System; namespace RGLUnityPlugin { @@ -15,52 +14,64 @@ public static Mesh GetTerrainMesh(Terrain terrain) var scale = terrainData.heightmapScale; var vertices = new Vector3[resolution * resolution]; - for (var i = 0; i < resolution; i++) + for (var x = 0; x < resolution; x++) { - for (var j = 0; j < resolution; j++) + for (var z = 0; z < resolution; z++) { - vertices[i * resolution + j].x = i * scale.x; - vertices[i * resolution + j].y = heights[j, i] * scale.y; - vertices[i * resolution + j].z = j * scale.z; + vertices[x * resolution + z].x = x * scale.x; + vertices[x * resolution + z].y = heights[z, x] * scale.y; + vertices[x * resolution + z].z = z * scale.z; } } - var quadResolution = resolution - 1; - var triangles = new int[quadResolution * quadResolution * 2 * 3]; + var squareResolution = resolution - 1; + // there are 2 triangles per square, so 6 indices + var triangles = new int[squareResolution * squareResolution * 2 * 3]; - for (var i = 0; i < quadResolution; i++) + for (var x = 0; x < squareResolution; x++) { - for (var j = 0; j < quadResolution; j++) + for (var z = 0; z < squareResolution; z++) { - var sampleBase = i * resolution + j; - var quadBase = 6 * (i * quadResolution + j); + var sampleBase = x * resolution + z; + var squareBase = 6 * (x * squareResolution + z); - // first triangle of quad - triangles[quadBase] = sampleBase; - triangles[quadBase + 1] = sampleBase + resolution; - triangles[quadBase + 2] = sampleBase + resolution + 1; + // first triangle of square + triangles[squareBase] = sampleBase; + triangles[squareBase + 1] = sampleBase + resolution; + triangles[squareBase + 2] = sampleBase + resolution + 1; - // second triangle of quad - triangles[quadBase + 3] = sampleBase; - triangles[quadBase + 4] = sampleBase + 1; - triangles[quadBase + 5] = sampleBase + resolution + 1; + // second triangle of square + triangles[squareBase + 3] = sampleBase; + triangles[squareBase + 4] = sampleBase + 1; + triangles[squareBase + 5] = sampleBase + 1 + resolution; } } - var mesh = new Mesh(); - mesh.indexFormat = IndexFormat.UInt32; - mesh.vertices = vertices; - mesh.triangles = triangles; + var heightmapMesh = new Mesh(); + heightmapMesh.indexFormat = IndexFormat.UInt32; + heightmapMesh.vertices = vertices; + heightmapMesh.triangles = triangles; - return mesh; + return heightmapMesh; } public static Mesh GetTreeMesh(Terrain terrain, int treeIndex) { var terrainData = terrain.terrainData; - var treeInstance = terrainData.treeInstances[treeIndex]; - var treePrototype = terrainData.treePrototypes[treeInstance.prototypeIndex]; - return treePrototype.prefab.GetComponent().sharedMesh; + var treeInstance = terrainData.GetTreeInstance(treeIndex); + var treePrefab = terrainData.treePrototypes[treeInstance.prototypeIndex].prefab; + if (treePrefab.TryGetComponent(out LODGroup lodGroup)) + { + if (lodGroup.GetLODs()[0].renderers[0].TryGetComponent(out MeshFilter meshFilter)) + { + return meshFilter.sharedMesh; + } + + Debug.LogWarning($"Tree[{treeIndex}] of terrain {terrain}'s LODGroup component has no MeshFilter component, it will be ignored by LIDAR"); + return null; + } + Debug.LogWarning($"Tree[{treeIndex}] of terrain {terrain} has no LODGroup component, it will be ignored by LIDAR"); + return null; } public static Matrix4x4 GetTreePose(Terrain terrain, int treeIndex) @@ -78,11 +89,11 @@ public static Matrix4x4 GetTreePose(Terrain terrain, int treeIndex) var samplePose = new Vector3(terrainPosition.x + translation.x, 0, terrainPosition.z + translation.z); translation.y = terrain.SampleHeight(samplePose); - var rotation = Quaternion.AngleAxis((float)(treeInstance.rotation / Math.PI * 180), Vector3.up); + var rotation = Quaternion.AngleAxis(treeInstance.rotation * Mathf.Rad2Deg, Vector3.up); var scale = new Vector3(treeInstance.widthScale, treeInstance.heightScale, treeInstance.widthScale); return Matrix4x4.TRS(translation, rotation, scale); } } -} \ No newline at end of file +} From 6fb59c74a9c5c7d05d31fca3a69d071231e29897 Mon Sep 17 00:00:00 2001 From: Jakub-Krakowiak Date: Fri, 4 Aug 2023 13:08:11 +0200 Subject: [PATCH 03/10] fixed 'using' and comments --- .../RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs | 1 - Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs index f6776d29f..4bb1fe362 100644 --- a/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs +++ b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs @@ -18,7 +18,6 @@ // Experimental is necessary for gathering GraphicsFormat of the texture. using UnityEngine.Experimental.Rendering; using System.Collections.Generic; -using Unity.VisualScripting; namespace RGLUnityPlugin { diff --git a/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs b/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs index ee171e515..da3adfb31 100644 --- a/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs +++ b/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs @@ -67,10 +67,10 @@ public static Mesh GetTreeMesh(Terrain terrain, int treeIndex) return meshFilter.sharedMesh; } - Debug.LogWarning($"Tree[{treeIndex}] of terrain {terrain}'s LODGroup component has no MeshFilter component, it will be ignored by LIDAR"); + Debug.LogWarning($"Tree[{treeIndex}] of terrain {terrain}'s LODGroup component has no MeshFilter component, it will be ignored by RGL"); return null; } - Debug.LogWarning($"Tree[{treeIndex}] of terrain {terrain} has no LODGroup component, it will be ignored by LIDAR"); + Debug.LogWarning($"Tree[{treeIndex}] of terrain {terrain} has no LODGroup component, it will be ignored by RGL"); return null; } From dfaea3c774757f45c4d9bcb2bfc0e51fba3f8444 Mon Sep 17 00:00:00 2001 From: Jakub-Krakowiak Date: Tue, 22 Aug 2023 15:33:20 +0200 Subject: [PATCH 04/10] Added holes, texture and vu support toterrain mesh, major refactor of RGLObject class and SceneManager --- .../Scripts/LowLevelWrappers/RGLMeshObject.cs | 293 ++++++++++++++--- .../RGLUnityPlugin/Scripts/RGLMeshManager.cs | 53 +++ .../Scripts/RGLMeshManager.cs.meta | 3 + .../Scripts/RGLTextureManager.cs | 52 +++ .../Scripts/RGLTextureManager.cs.meta | 3 + Assets/RGLUnityPlugin/Scripts/SceneManager.cs | 304 ++---------------- .../Scripts/Utilities/TerrainUtilities.cs | 100 ++++-- 7 files changed, 461 insertions(+), 347 deletions(-) create mode 100644 Assets/RGLUnityPlugin/Scripts/RGLMeshManager.cs create mode 100644 Assets/RGLUnityPlugin/Scripts/RGLMeshManager.cs.meta create mode 100644 Assets/RGLUnityPlugin/Scripts/RGLTextureManager.cs create mode 100644 Assets/RGLUnityPlugin/Scripts/RGLTextureManager.cs.meta diff --git a/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs index 4bb1fe362..90235dc3b 100644 --- a/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs +++ b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs @@ -21,30 +21,48 @@ namespace RGLUnityPlugin { + + internal interface IRGLObject + { + GameObject RepresentedGO { get; } + int? CategoryId { get; } + string CategoryName { get; } + + void Update(); + + void DestroyInRGL(); + } + /// /// RGL counterpart of Unity GameObjects. /// Contains information about RGL entity and RGLMesh. /// - public class RGLObject + public abstract class RGLObject : IRGLObject { - public string Identifier; - public RGLMesh RglMesh; - public RGLTexture Texture; - public Func GetLocalToWorld; - public GameObject RepresentedGO; - public int? categoryId; - public string categoryName; + private string Identifier; + private RGLMesh RglMesh; + private RGLTexture RglTexture; + + public GameObject RepresentedGO { get; } + public int? CategoryId { get; private set; } + public string CategoryName { get; private set; } private IntPtr rglEntityPtr; + private bool transformInitialized; - public RGLObject(string identifier, RGLMesh rglMesh, Func getLocalToWorld, GameObject representedGO) + protected abstract RGLMesh GetRGLMeshFrom(T meshSource); + + protected RGLObject(string identifier, GameObject representedGO, T meshSource) { Identifier = identifier; - RglMesh = rglMesh; - GetLocalToWorld = getLocalToWorld; RepresentedGO = representedGO; - + RglMesh = GetRGLMeshFrom(meshSource); + if (RglMesh == null) + { + return; + } UploadToRGL(); + SetIntensityTexture(); var semanticCategory = RepresentedGO.GetComponentInParent(); if (semanticCategory != null) @@ -56,20 +74,50 @@ public RGLObject(string identifier, RGLMesh rglMesh, Func getLocalToW ~RGLObject() { - DestroyFromRGL(); + DestroyInRGL(); } - public virtual void DestroyFromRGL() + public virtual void DestroyInRGL() { if (rglEntityPtr != IntPtr.Zero) { RGLNativeAPI.CheckErr(RGLNativeAPI.rgl_entity_destroy(rglEntityPtr)); rglEntityPtr = IntPtr.Zero; + if (RglMesh is RGLSkinnedMesh) + { + RglMesh.DestroyFromRGL(); + } + else + { + RGLMeshManager.UnregisterRGLMeshInstance(RglMesh.Identifier); + } + RglMesh = null; + if (RglTexture != null) + { + RGLTextureManager.UnregisterRGLTextureInstance(RglTexture.Identifier); + RglTexture = null; + } + } + } + + public void Update() + { + UpdateTransform(); + if (RglMesh is RGLSkinnedMesh rglSkinnedMesh) + { + rglSkinnedMesh.UpdateSkinnedMesh(); } } - public void UpdateTransform() + protected abstract Matrix4x4 GetLocalToWorld(); + + protected virtual void UpdateTransform() { + if (rglEntityPtr == IntPtr.Zero || (transformInitialized && RepresentedGO.isStatic)) + { + return; + } + Matrix4x4 m = GetLocalToWorld(); float[] matrix3x4 = { @@ -85,6 +133,11 @@ public void UpdateTransform() RGLNativeAPI.rgl_entity_set_pose(rglEntityPtr, (IntPtr) pMatrix3x4)); } } + + if (!transformInitialized) + { + transformInitialized = true; + } } public override int GetHashCode() @@ -94,10 +147,10 @@ public override int GetHashCode() public override bool Equals(object obj) { - return obj is RGLObject rglObject && Identifier.Equals(rglObject.Identifier); + return obj is RGLObject rglObject && Identifier.Equals(rglObject.Identifier); } - protected void UploadToRGL() + private void UploadToRGL() { // Mesh should be uploaded. Assert.IsFalse(RglMesh.rglMeshPtr == IntPtr.Zero); @@ -124,53 +177,197 @@ private void UpdateSemanticCategory(SemanticCategory semanticCategory) return; } - categoryId = semanticCategory.CategoryId; - categoryName = semanticCategory.gameObject.name; - RGLNativeAPI.CheckErr(RGLNativeAPI.rgl_entity_set_id(rglEntityPtr, categoryId.Value)); + CategoryId = semanticCategory.CategoryId; + CategoryName = semanticCategory.gameObject.name; + RGLNativeAPI.CheckErr(RGLNativeAPI.rgl_entity_set_id(rglEntityPtr, CategoryId.Value)); } - public void SetIntensityTexture(RGLTexture texture) + private void SetIntensityTexture() { - unsafe + var intensityTextureComponent = RepresentedGO.GetComponent(); + + if( intensityTextureComponent == null || intensityTextureComponent.texture == null) { - try - { - RGLNativeAPI.CheckErr( - RGLNativeAPI.rgl_entity_set_intensity_texture(rglEntityPtr, texture.rglTexturePtr)); - Texture = texture; - } - catch (RGLException) - { - Debug.LogError($"Cannot assign texture: {texture.Identifier}, to entity: {Identifier}"); - throw; - } + return; + } - // Mesh should be uploaded before assigning UVs. - Assert.IsFalse(RglMesh.rglMeshPtr == IntPtr.Zero); + RglTexture = RGLTextureManager.RegisterRGLTextureInstance(intensityTextureComponent.texture); + try + { + RGLNativeAPI.CheckErr( + RGLNativeAPI.rgl_entity_set_intensity_texture(rglEntityPtr, RglTexture.rglTexturePtr)); + } + catch (RGLException) + { + Debug.LogError($"Cannot assign texture: {RglTexture.Identifier}, to entity: {Identifier}"); + throw; + } + + // Mesh should be uploaded before assigning UVs. + Assert.IsFalse(RglMesh.rglMeshPtr == IntPtr.Zero); + + RglMesh.UploadUVs(); + } + } + + public class RGLMeshObject : RGLObject + { + private readonly Func getLocalToWorld; + + public RGLMeshObject(string identifier, GameObject representedGO, Mesh mesh, Func getLocalToWorld) : + base(identifier, representedGO, mesh) + { + this.getLocalToWorld = getLocalToWorld; + } - RglMesh.UploadUVs(); + protected override RGLMesh GetRGLMeshFrom(Mesh mesh) + { + return RGLMeshManager.RegisterRGLMeshInstance(mesh); + } + + protected override Matrix4x4 GetLocalToWorld() + { + return getLocalToWorld(); + } + } + + public class RGLMeshRendererObject : RGLObject + { + private readonly Transform rendererTransform; + + public RGLMeshRendererObject(MeshRenderer meshRenderer) : + base( + $"{meshRenderer.gameObject.name}#{meshRenderer.gameObject.GetInstanceID()}", + meshRenderer.gameObject, + meshRenderer + ) + { + rendererTransform = meshRenderer.transform; + } + + protected override RGLMesh GetRGLMeshFrom(MeshRenderer meshRenderer) + { + var meshFilter = meshRenderer.GetComponent(); + if (meshFilter.sharedMesh == null) + { + Debug.LogWarning($"Shared mesh of {meshRenderer.gameObject} is null, skipping"); + return null; } + + return RGLMeshManager.RegisterRGLMeshInstance(meshFilter.sharedMesh); + } + + protected override Matrix4x4 GetLocalToWorld() + { + return rendererTransform.localToWorldMatrix; + } + } + + public class RGLSkinnedMeshRendererObject : RGLObject + { + private readonly Transform skinnedMeshRendererTransform; + + public RGLSkinnedMeshRendererObject(SkinnedMeshRenderer skinnedMeshRenderer) : + base( + $"{skinnedMeshRenderer.gameObject.name}#{skinnedMeshRenderer.gameObject.GetInstanceID()}", + skinnedMeshRenderer.gameObject, + skinnedMeshRenderer + ) + { + skinnedMeshRendererTransform = skinnedMeshRenderer.transform; + } + + protected override RGLMesh GetRGLMeshFrom(SkinnedMeshRenderer skinnedMeshRenderer) + { + return new RGLSkinnedMesh(skinnedMeshRenderer.gameObject.GetInstanceID(), skinnedMeshRenderer); + } + + protected override Matrix4x4 GetLocalToWorld() + { + return skinnedMeshRendererTransform.localToWorldMatrix; } } - public class RGLTerrainObject : RGLObject + public class RGLColliderObject : RGLObject { - public List TerrainSubObjects; + private readonly Collider collider; - public RGLTerrainObject(string identifier, RGLMesh rglMesh, Func getLocalToWorld, GameObject representedGO) - : base(identifier, rglMesh, getLocalToWorld, representedGO) + public RGLColliderObject(Collider collider) : + base($"{collider.gameObject.name}#{collider.gameObject.GetInstanceID()}", + collider.gameObject, + collider + ) { - TerrainSubObjects = new List(); + this.collider = collider; + } + + protected override RGLMesh GetRGLMeshFrom(Collider collider) + { + return RGLMeshManager.RegisterRGLMeshInstance(ColliderUtilities.GetMeshForCollider(collider)); + } + + protected override Matrix4x4 GetLocalToWorld() + { + return collider.transform.localToWorldMatrix * ColliderUtilities.GetColliderTransformMatrix(collider); + } + } + + public class RGLTerrainObject : RGLObject + { + private readonly List terrainSubObjects; + private readonly Transform terrainTransform; + + public RGLTerrainObject(Terrain terrain) : + base($"{terrain.gameObject.name}#{terrain.gameObject.GetInstanceID()}", terrain.gameObject, terrain) + { + terrainTransform = terrain.transform; + terrainSubObjects = new List(); + var terrainData = terrain.terrainData; + for (var i = 0; i < terrainData.treeInstanceCount; i++) + { + var treeMesh = TerrainUtilities.GetTreeMesh(terrain, i); + if (treeMesh is null) + { + continue; + } + // we need to make a copy of the index because lambda captures use reference semantics for all captured variables + var treeIndex = i; + var tree = new RGLMeshObject($"{RepresentedGO.name}#{RepresentedGO.GetInstanceID()}#{treeIndex}", + RepresentedGO, + treeMesh, + () => terrain.transform.localToWorldMatrix * TerrainUtilities.GetTreePose(terrain, treeIndex)); + terrainSubObjects.Add(tree); + } + } + + protected override Matrix4x4 GetLocalToWorld() + { + return terrainTransform.localToWorldMatrix; } - public override void DestroyFromRGL() + public override void DestroyInRGL() + { + foreach (var terrainSubObject in terrainSubObjects) + { + terrainSubObject.DestroyInRGL(); + } + + base.DestroyInRGL(); + } + + protected override void UpdateTransform() { - foreach (var terrainSubObject in TerrainSubObjects) + foreach (var terrainSubObject in terrainSubObjects) { - terrainSubObject.DestroyFromRGL(); + terrainSubObject.Update(); } - base.DestroyFromRGL(); + base.UpdateTransform(); + } + + protected override RGLMesh GetRGLMeshFrom(Terrain terrain) + { + return RGLMeshManager.RegisterRGLMeshInstance(TerrainUtilities.GetTerrainMesh(terrain)); } } @@ -181,12 +378,12 @@ public override void DestroyFromRGL() /// public class RGLMesh { - public string Identifier; + public int Identifier; public Mesh Mesh; public IntPtr rglMeshPtr = IntPtr.Zero; - public RGLMesh(string identifier, Mesh mesh) + public RGLMesh(int identifier, Mesh mesh) { Identifier = identifier; Mesh = mesh; @@ -287,7 +484,7 @@ public class RGLSkinnedMesh : RGLMesh { public SkinnedMeshRenderer SkinnedMeshRenderer; - public RGLSkinnedMesh(string identifier, SkinnedMeshRenderer smr) + public RGLSkinnedMesh(int identifier, SkinnedMeshRenderer smr) { Identifier = identifier; Mesh = new Mesh(); diff --git a/Assets/RGLUnityPlugin/Scripts/RGLMeshManager.cs b/Assets/RGLUnityPlugin/Scripts/RGLMeshManager.cs new file mode 100644 index 000000000..0587d3a73 --- /dev/null +++ b/Assets/RGLUnityPlugin/Scripts/RGLMeshManager.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace RGLUnityPlugin +{ + public class RGLMeshManager + { + private static Dictionary sharedMeshes = new Dictionary(); // + private static Dictionary sharedMeshesUsageCount = new Dictionary(); // + + public static RGLMesh RegisterRGLMeshInstance(Mesh unityMesh) + { + var meshId = unityMesh.GetInstanceID(); + if (!sharedMeshes.ContainsKey(meshId)) + { + var rglMesh = new RGLMesh(meshId, unityMesh); + sharedMeshes.Add(meshId, rglMesh); + sharedMeshesUsageCount.Add(meshId, 1); + } + else + { + sharedMeshesUsageCount[meshId]++; + } + + return sharedMeshes[meshId]; + } + + public static void UnregisterRGLMeshInstance(int meshId) + { + if (sharedMeshes[meshId] is null) + { + Debug.LogWarning($"Trying to unregister absent in RGLMeshManager mesh of id: {meshId}, ignoring request"); + return; + } + + sharedMeshesUsageCount[meshId]--; + if (sharedMeshesUsageCount[meshId] == 0) + { + sharedMeshes[meshId].DestroyFromRGL(); + sharedMeshes.Remove(meshId); + sharedMeshesUsageCount.Remove(meshId); + } + } + + public static void ClearAllMeshes() + { + foreach (var mesh in sharedMeshes) + { + mesh.Value.DestroyFromRGL(); + } + } + } +} \ No newline at end of file diff --git a/Assets/RGLUnityPlugin/Scripts/RGLMeshManager.cs.meta b/Assets/RGLUnityPlugin/Scripts/RGLMeshManager.cs.meta new file mode 100644 index 000000000..518a28ba0 --- /dev/null +++ b/Assets/RGLUnityPlugin/Scripts/RGLMeshManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bedd83a891b64af4859250467981ae5d +timeCreated: 1691588628 \ No newline at end of file diff --git a/Assets/RGLUnityPlugin/Scripts/RGLTextureManager.cs b/Assets/RGLUnityPlugin/Scripts/RGLTextureManager.cs new file mode 100644 index 000000000..ceb728de3 --- /dev/null +++ b/Assets/RGLUnityPlugin/Scripts/RGLTextureManager.cs @@ -0,0 +1,52 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace RGLUnityPlugin +{ + public class RGLTextureManager + { + private static Dictionary sharedTextures = new Dictionary(); // + private static Dictionary sharedTexturesUsageCount = new Dictionary(); // + + public static RGLTexture RegisterRGLTextureInstance(Texture2D texture) + { + var textureID = texture.GetInstanceID(); + + if(!sharedTextures.ContainsKey(textureID)) + { + var rglTextureToAdd = new RGLTexture(texture, textureID); + sharedTextures.Add(textureID, rglTextureToAdd); + sharedTexturesUsageCount.Add(textureID, 0); + } + + sharedTexturesUsageCount[textureID] += 1; + + return sharedTextures[textureID]; + } + + public static void UnregisterRGLTextureInstance(int textureId) + { + if (sharedTextures[textureId] is null) + { + Debug.LogWarning($"Trying to unregister absent in RGLTextureManager texture of id: {textureId}, ignoring request"); + return; + } + + sharedTexturesUsageCount[textureId]--; + if (sharedTexturesUsageCount[textureId] == 0) + { + sharedTextures[textureId].DestroyFromRGL(); + sharedTextures.Remove(textureId); + sharedTextures.Remove(textureId); + } + } + + public static void ClearAllTextures() + { + foreach (var mesh in sharedTextures) + { + mesh.Value.DestroyFromRGL(); + } + } + } +} diff --git a/Assets/RGLUnityPlugin/Scripts/RGLTextureManager.cs.meta b/Assets/RGLUnityPlugin/Scripts/RGLTextureManager.cs.meta new file mode 100644 index 000000000..a72cba859 --- /dev/null +++ b/Assets/RGLUnityPlugin/Scripts/RGLTextureManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c848f96e811948f49d9a5e411b9ccb3e +timeCreated: 1692014679 \ No newline at end of file diff --git a/Assets/RGLUnityPlugin/Scripts/SceneManager.cs b/Assets/RGLUnityPlugin/Scripts/SceneManager.cs index 0e27a459a..403fe3283 100644 --- a/Assets/RGLUnityPlugin/Scripts/SceneManager.cs +++ b/Assets/RGLUnityPlugin/Scripts/SceneManager.cs @@ -53,35 +53,29 @@ public enum MeshSource private string semanticCategoryDictionaryFile; // Getting meshes strategies - private delegate IEnumerable IntoRGLObjectsStrategy(IEnumerable gameObjects); + private delegate IEnumerable IntoRGLObjectsStrategy(IEnumerable gameObjects); private IntoRGLObjectsStrategy IntoRGLObjects; // Keeping track of the scene objects private HashSet lastFrameGameObjects = new HashSet(); - private readonly Dictionary uploadedRGLObjects = new Dictionary(); + private readonly Dictionary uploadedRGLObjects = new Dictionary(); // This dictionary keeps tracks of identifier -> instance id of objects that were removed (e.g. temporary NPCs) // This is needed to include them in the instance id dictionary yaml saved at the end of simulation. // Since categoryId can be changed in the runtime, this is filled only on object removal / simulation end. - private Dictionary semanticDict = new Dictionary(); - - private static Dictionary sharedMeshes = new Dictionary(); // - private static Dictionary sharedMeshesUsageCount = new Dictionary(); // - - private static Dictionary sharedTextures = new Dictionary(); // - private static Dictionary sharedTexturesUsageCount = new Dictionary(); // + private readonly Dictionary semanticDict = new Dictionary(); public static ITimeSource TimeSource { get; set; } = new UnityTimeSource(); private int lastUpdateFrame = -1; - void OnDisable() + private void OnDisable() { Clear(); } - void OnValidate() + private void OnValidate() { UpdateMeshSource(); } @@ -98,7 +92,7 @@ private void UpdateMeshSource() { IntoRGLObjectsStrategy UpdatedIntoRGLObjects = meshSource switch { - MeshSource.OnlyColliders => IntoRGLObjectsUsingCollider, + MeshSource.OnlyColliders => IntoRGLObjectsUsingColliders, MeshSource.RegularMeshesAndCollidersInsteadOfSkinned => IntoRGLObjectsHybrid, MeshSource.RegularMeshesAndSkinnedMeshes => IntoRGLObjectsUsingMeshes, _ => throw new ArgumentOutOfRangeException() @@ -144,8 +138,8 @@ public void DoUpdate() // Added var toAddGOs = new HashSet(thisFrameGOs); toAddGOs.ExceptWith(lastFrameGameObjects); - RGLObject[] toAdd = IntoRGLObjects(toAddGOs).ToArray(); - RGLObject[] toAddTerrain = IntoRGLTerrain(toAddGOs).ToArray(); + var toAdd = IntoRGLObjects(toAddGOs).ToArray(); + var toAddTerrain = IntoRGLTerrainObjects(toAddGOs).ToArray(); if (toAddTerrain.Length != 0) { toAdd = toAdd.Concat(toAddTerrain).ToArray(); @@ -155,104 +149,38 @@ public void DoUpdate() var toRemoveGOs = new HashSet(lastFrameGameObjects); toRemoveGOs.ExceptWith(thisFrameGOs); toRemoveGOs.IntersectWith(uploadedRGLObjects.Keys); - RGLObject[] toRemove = toRemoveGOs.Select((o) => uploadedRGLObjects[o]).ToArray(); - - // Skinned - RGLObject[] newToSkin = toAdd.Where(o => o.RglMesh is RGLSkinnedMesh).ToArray(); - RGLObject[] existingToSkin = uploadedRGLObjects.Values - .Where(o => o.RglMesh is RGLSkinnedMesh) - .Except(toRemove).ToArray(); - RGLObject[] toSkin = existingToSkin.Concat(newToSkin).ToArray(); + var toRemove = toRemoveGOs.Select((o) => uploadedRGLObjects[o]).ToArray(); lastFrameGameObjects = thisFrameGOs; Profiler.EndSample(); - Profiler.BeginSample("Add new textures"); - AddTextures(toAdd); - Profiler.EndSample(); - Profiler.BeginSample("Remove despawned objects"); foreach (var rglObject in toRemove) { - if(rglObject.Texture != null) - { - sharedTexturesUsageCount[rglObject.Texture.Identifier] -=1; - } - - if (!(rglObject.RglMesh is RGLSkinnedMesh)) - { - sharedMeshesUsageCount[rglObject.RglMesh.Identifier] -= 1; - } - - var terrainObject = rglObject as RGLTerrainObject; - if (terrainObject != null) - { - foreach (var terrainSubObject in terrainObject.TerrainSubObjects) - { - sharedMeshesUsageCount[terrainSubObject.RglMesh.Identifier] -= 1; - } - } - - updateSemanticDict(rglObject); - rglObject.DestroyFromRGL(); + rglObject.DestroyInRGL(); uploadedRGLObjects.Remove(rglObject.RepresentedGO); } - - Profiler.EndSample(); - - // TODO: this can be parallelized and moved to Update() - Profiler.BeginSample("Update skinned meshes"); - foreach (var rglObject in toSkin) - { - var skinnedMesh = rglObject.RglMesh as RGLSkinnedMesh; - Assert.IsNotNull(skinnedMesh); - skinnedMesh.UpdateSkinnedMesh(); - } - Profiler.EndSample(); - + Profiler.BeginSample("Mark spawned objects as updated"); foreach (var rglObject in toAdd) { // Game Objects must not have duplicate representations. // Occasionally, this assertion may fail due to disabled Read/Write setting of the prefab's mesh. Assert.IsFalse(uploadedRGLObjects.ContainsKey(rglObject.RepresentedGO)); - - if (!(rglObject.RglMesh is RGLSkinnedMesh)) sharedMeshesUsageCount[rglObject.RglMesh.Identifier] += 1; + uploadedRGLObjects.Add(rglObject.RepresentedGO, rglObject); } - Profiler.EndSample(); // TODO(prybicki): This part can take up to 8ms on Shinjuku scene, two ideas to optimize it soon: // - Implement batch update in RGL // - Use Transform.hasChanged to filter out some objects - Profiler.BeginSample("Update transforms"); + Profiler.BeginSample("Update transforms and skinned meshes"); foreach (var gameRGLObject in uploadedRGLObjects) { - gameRGLObject.Value.UpdateTransform(); - } - - Profiler.EndSample(); - - Profiler.BeginSample("Destroy unused meshes"); - foreach (var meshUsageCounter in sharedMeshesUsageCount.Where(x => x.Value < 1).ToList()) - { - sharedMeshes[meshUsageCounter.Key].DestroyFromRGL(); - sharedMeshes.Remove(meshUsageCounter.Key); - sharedMeshesUsageCount.Remove(meshUsageCounter.Key); + gameRGLObject.Value.Update(); } - - Profiler.EndSample(); - - Profiler.BeginSample("Destroy unused textures"); - foreach(var textureUsageCounter in sharedTexturesUsageCount.Where(x =>x.Value < 1).ToList()) - { - sharedTextures[textureUsageCounter.Key].DestroyFromRGL(); - sharedTextures.Remove(textureUsageCounter.Key); - sharedTexturesUsageCount.Remove(textureUsageCounter.Key); - } - Profiler.EndSample(); } @@ -267,39 +195,25 @@ private void SynchronizeSceneTime() private void Clear() { - if (!lastFrameGameObjects.Any() && !uploadedRGLObjects.Any() && !sharedMeshes.Any()) return; - - foreach (var rglMesh in sharedMeshes) - { - rglMesh.Value.DestroyFromRGL(); - } + if (!lastFrameGameObjects.Any() && !uploadedRGLObjects.Any()) return; foreach (var rglObject in uploadedRGLObjects) { - rglObject.Value.DestroyFromRGL(); - } - - foreach ( var rglTexture in sharedTextures) - { - rglTexture.Value.DestroyFromRGL(); + rglObject.Value.DestroyInRGL(); } uploadedRGLObjects.Clear(); lastFrameGameObjects.Clear(); - sharedMeshes.Clear(); - sharedMeshesUsageCount.Clear(); - sharedTextures.Clear(); - sharedMeshesUsageCount.Clear(); Debug.Log("RGLSceneManager: cleared"); } - private void updateSemanticDict(RGLObject rglObject) + private void updateSemanticDict(IRGLObject rglObject) { - if (rglObject.categoryId.HasValue) + if (rglObject.CategoryId.HasValue) { - if (!semanticDict.ContainsKey(rglObject.categoryName)) + if (!semanticDict.ContainsKey(rglObject.CategoryName)) { - semanticDict.Add(rglObject.categoryName, rglObject.categoryId.Value); + semanticDict.Add(rglObject.CategoryName, rglObject.CategoryId.Value); } } } @@ -325,7 +239,7 @@ private void OnApplicationQuit() /// Yields a collection of RGL objects based on active colliders found in provided game objects. /// This function ignores whether gameObject is active, if filtering is needed, it should be done earlier. /// - private static IEnumerable IntoRGLObjectsUsingCollider(IEnumerable gameObjects) + private static IEnumerable IntoRGLObjectsUsingColliders(IEnumerable gameObjects) { foreach (var gameObject in gameObjects) { @@ -348,11 +262,11 @@ private static IEnumerable IntoRGLObjectsUsingCollider(IEnumerable IntoRGLObjectsUsingCollider(IEnumerable - private static IEnumerable IntoRGLObjectsHybrid(IEnumerable gameObjects) + private static IEnumerable IntoRGLObjectsHybrid(IEnumerable gameObjects) { var collidersToYield = new HashSet(); foreach (var renderer in GetUniqueRenderersInGameObjects(gameObjects)) @@ -383,19 +297,13 @@ private static IEnumerable IntoRGLObjectsHybrid(IEnumerable(); - if (mf.sharedMesh == null) - { - Debug.LogWarning($"Shared mesh of {mr.gameObject} is null, skipping"); - continue; - } - yield return MeshFilterToRGLObject(mf); + yield return new RGLMeshRendererObject(mr); } } foreach (var collider in collidersToYield) { - yield return ColliderToRGLObject(collider); + yield return new RGLColliderObject(collider); } } @@ -404,20 +312,13 @@ private static IEnumerable IntoRGLObjectsHybrid(IEnumerable - private static IEnumerable IntoRGLObjectsUsingMeshes(IEnumerable gameObjects) + private static IEnumerable IntoRGLObjectsUsingMeshes(IEnumerable gameObjects) { foreach (var renderer in GetUniqueRenderersInGameObjects(gameObjects)) { - var go = renderer.gameObject; if (renderer is MeshRenderer mr) { - var mf = mr.GetComponent(); - if (mf.sharedMesh == null) - { - Debug.LogWarning($"Shared mesh of {mr.gameObject} is null, skipping"); - continue; - } - yield return MeshFilterToRGLObject(mf); + yield return new RGLMeshRendererObject(mr); } if (renderer is SkinnedMeshRenderer smr) @@ -427,128 +328,23 @@ private static IEnumerable IntoRGLObjectsUsingMeshes(IEnumerable smr.transform.localToWorldMatrix, - go); + + yield return new RGLSkinnedMeshRendererObject(smr); } } } - private static IEnumerable IntoRGLTerrain(IEnumerable gameObjects) + private static IEnumerable IntoRGLTerrainObjects(IEnumerable gameObjects) { foreach (var gameObject in gameObjects) { if (gameObject.TryGetComponent(out var terrain)) { - yield return TerrainToRGLObject(terrain); + yield return new RGLTerrainObject(terrain); } } } - private static RGLObject ColliderToRGLObject(Collider collider) - { - var mesh = ColliderUtilities.GetMeshForCollider(collider); - string meshId = $"r#{mesh.GetInstanceID()}"; - if (!sharedMeshes.ContainsKey(meshId)) - { - RGLMesh rglMesh = new RGLMesh(meshId, mesh); - sharedMeshes.Add(meshId, rglMesh); - sharedMeshesUsageCount.Add(meshId, 0); - } - - var gameObject = collider.gameObject; - return new RGLObject($"{gameObject.name}#{gameObject.GetInstanceID()}", - sharedMeshes[meshId], - () => collider.transform.localToWorldMatrix * - ColliderUtilities.GetColliderTransformMatrix(collider), - gameObject); - } - - private static RGLObject MeshFilterToRGLObject(MeshFilter meshFilter) - { - var mesh = meshFilter.sharedMesh; - string meshId = $"r#{mesh.GetInstanceID()}"; - if (!sharedMeshes.ContainsKey(meshId)) - { - RGLMesh rglMesh = new RGLMesh(meshId, mesh); - sharedMeshes.Add(meshId, rglMesh); - sharedMeshesUsageCount.Add(meshId, 0); - } - - var gameObject = meshFilter.gameObject; - return new RGLObject($"{gameObject.name}#{gameObject.GetInstanceID()}", - sharedMeshes[meshId], - () => gameObject.transform.localToWorldMatrix, - gameObject); - } - - /// - /// This function adds the Terrain game object with a mesh based on the heightmap of the terrain as well as - /// all trees of the terrain game object as separate instances in RGL. - /// Tree transforms are updated only once per simulation, since the terrain object is static (Cannot be moved) - /// while simulation is running. - /// This function relies on the tree prefabs having a LOD (Level Of Detail) component and - /// a mesh renderer of LOD0 having a mesh filter. - /// - private static RGLObject TerrainToRGLObject(Terrain terrain) - { - var mesh = TerrainUtilities.GetTerrainMesh(terrain); - string meshId = $"r#{mesh.GetInstanceID()}"; - if (!sharedMeshes.ContainsKey(meshId)) - { - RGLMesh rglMesh = new RGLMesh(meshId, mesh); - sharedMeshes.Add(meshId, rglMesh); - sharedMeshesUsageCount.Add(meshId, 0); - } - - var terrainData = terrain.terrainData; - var terrainGO = terrain.gameObject; - var terrainRGLObject = new RGLTerrainObject($"{terrainGO.name}#{terrainGO.GetInstanceID()}", - sharedMeshes[meshId], - () => terrain.transform.localToWorldMatrix, - terrainGO); - - for (var i = 0; i < terrainData.treeInstanceCount; i++) - { - var treeMesh = TerrainUtilities.GetTreeMesh(terrain, i); - if (treeMesh is null) - { - continue; - } - string treeMeshId = $"r#{treeMesh.GetInstanceID()}"; - if (!treeMesh.isReadable) - { - Debug.LogWarning($"Tree mesh of prefab: '" + - $"{terrainData.treePrototypes[terrainData.treeInstances[i].prototypeIndex].prefab.name}' " + - $"is not readable, skipping tree {i}, please set the model's 'Read/Write Enabled' attribute to true"); - continue; - } - if (!sharedMeshes.ContainsKey(treeMeshId)) - { - RGLMesh rglMesh = new RGLMesh(treeMeshId, treeMesh); - sharedMeshes.Add(treeMeshId, rglMesh); - sharedMeshesUsageCount.Add(treeMeshId, 1); - } - else - { - sharedMeshesUsageCount[treeMeshId]++; - } - - var tree = new RGLObject($"{terrainGO.name}#{terrainGO.GetInstanceID()}#{i}", - sharedMeshes[treeMeshId], - () => terrain.transform.localToWorldMatrix * TerrainUtilities.GetTreePose(terrain, i), - terrainGO); - tree.UpdateTransform(); - terrainRGLObject.TerrainSubObjects.Add(tree); - } - - return terrainRGLObject; - } - /// /// Some prefabs have LOD Group component (Level Of Detail) /// which implies using different renders based on the distance from the camera. @@ -606,42 +402,6 @@ private static IEnumerable GetUniqueRenderersInGameObjects(IEnumerable foreach (var smr in smrs) yield return smr; foreach (var mr in mrs) yield return mr; } - - /// - /// Searches through new rglObjects for ones containing IntensityTexture component. - /// If present, check if the found texture was already sent to RGL. - /// If not, send it and write its identifier to sharedTextures dictionary. - /// After that assign rglTexture to the proper rglObject. - /// - private static void AddTextures(IEnumerable rglObjects) - { - foreach (var rglObject in rglObjects) - { - var intensityTextureComponent = rglObject.RepresentedGO.GetComponent(); - - if( intensityTextureComponent == null) - { - continue; - } - - if( intensityTextureComponent.texture == null) - { - continue; - } - - int textureID = intensityTextureComponent.texture.GetInstanceID(); - - if(!sharedTextures.ContainsKey(textureID)) - { - var rglTextureToAdd = new RGLTexture(intensityTextureComponent.texture, textureID); - sharedTextures.Add(textureID, rglTextureToAdd); - sharedTexturesUsageCount.Add(textureID, 0); - } - - rglObject.SetIntensityTexture(sharedTextures[textureID]); - sharedTexturesUsageCount[textureID] += 1; - } - } private static bool IsNotActiveOrParentHasLidar(GameObject gameObject) { diff --git a/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs b/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs index da3adfb31..12ee145c8 100644 --- a/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs +++ b/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs @@ -1,4 +1,3 @@ - using UnityEngine.Rendering; using UnityEngine; @@ -9,48 +8,88 @@ public class TerrainUtilities public static Mesh GetTerrainMesh(Terrain terrain) { var terrainData = terrain.terrainData; - var resolution = terrainData.heightmapResolution; - var heights = terrainData.GetHeights(0, 0, resolution, resolution); + var heightmapResolution = terrainData.heightmapResolution; + var holesResolution = terrainData.holesResolution; + var correctHolesResolution = holesResolution == heightmapResolution - 1; + var heights = terrainData.GetHeights(0, 0, heightmapResolution, heightmapResolution); + var solidSurfaceTiles = terrainData.GetHoles(0, 0, holesResolution, holesResolution); var scale = terrainData.heightmapScale; - var vertices = new Vector3[resolution * resolution]; + var vertices = new Vector3[heightmapResolution * heightmapResolution]; + + if (!correctHolesResolution) + { + Debug.LogWarning($"Terrain {terrain.GetInstanceID()} holes resolution is incorrect, holes will be ignored by RGL"); + } + + for (var z = 0; z < heightmapResolution; z++) + { + for (var x = 0; x < heightmapResolution; x++) + { + vertices[x * heightmapResolution + z].x = x * scale.x; + vertices[x * heightmapResolution + z].y = heights[z, x] * scale.y; + vertices[x * heightmapResolution + z].z = z * scale.z; + } + } - for (var x = 0; x < resolution; x++) + // this is the number of squares alongside each axis of the terrain + // e.g. if you have a 3x3 grid of points you can fill the space between them using a 2x2 square grid + var tileResolution = heightmapResolution - 1; + + + // count solid terrain tiles (not holes) + var tileCount = 0; + foreach (var solidSurface in solidSurfaceTiles) { - for (var z = 0; z < resolution; z++) + if (solidSurface) { - vertices[x * resolution + z].x = x * scale.x; - vertices[x * resolution + z].y = heights[z, x] * scale.y; - vertices[x * resolution + z].z = z * scale.z; + tileCount++; } } - var squareResolution = resolution - 1; - // there are 2 triangles per square, so 6 indices - var triangles = new int[squareResolution * squareResolution * 2 * 3]; + if (!correctHolesResolution) + { + tileCount = tileResolution * tileResolution; + } - for (var x = 0; x < squareResolution; x++) + // there are 2 triangles per square tile, so 6 indices + var triangles = new int[tileCount * 2 * 3]; + + var trianglesIndex = 0; + for (var z = 0; z < tileResolution; z++) { - for (var z = 0; z < squareResolution; z++) + for (var x = 0; x < tileResolution; x++) { - var sampleBase = x * resolution + z; - var squareBase = 6 * (x * squareResolution + z); - // first triangle of square - triangles[squareBase] = sampleBase; - triangles[squareBase + 1] = sampleBase + resolution; - triangles[squareBase + 2] = sampleBase + resolution + 1; + if (correctHolesResolution && !solidSurfaceTiles[z, x]) + { + continue; + } - // second triangle of square - triangles[squareBase + 3] = sampleBase; - triangles[squareBase + 4] = sampleBase + 1; - triangles[squareBase + 5] = sampleBase + 1 + resolution; + var sampleBase = x * heightmapResolution + z; + + // first triangle of tile + triangles[trianglesIndex++] = sampleBase; + triangles[trianglesIndex++] = sampleBase + heightmapResolution; + triangles[trianglesIndex++] = sampleBase + heightmapResolution + 1; + + // second triangle of tile + triangles[trianglesIndex++] = sampleBase; + triangles[trianglesIndex++] = sampleBase + 1; + triangles[trianglesIndex++] = sampleBase + 1 + heightmapResolution; } } - + + var uv = new Vector2[vertices.Length]; + for (var i = 0; i < vertices.Length; i++) + { + uv[i] = new Vector2(vertices[i].x / (tileResolution * scale.x), vertices[i].z / (tileResolution * scale.z)); + } + var heightmapMesh = new Mesh(); heightmapMesh.indexFormat = IndexFormat.UInt32; heightmapMesh.vertices = vertices; heightmapMesh.triangles = triangles; + heightmapMesh.uv = uv; return heightmapMesh; } @@ -67,10 +106,17 @@ public static Mesh GetTreeMesh(Terrain terrain, int treeIndex) return meshFilter.sharedMesh; } - Debug.LogWarning($"Tree[{treeIndex}] of terrain {terrain}'s LODGroup component has no MeshFilter component, it will be ignored by RGL"); + Debug.LogWarning($"Tree[{treeIndex}] \"{treePrefab.name}\" of terrain {terrain.GetInstanceID()} has LODGroup component with no MeshFilter component, it will be ignored by RGL"); return null; } - Debug.LogWarning($"Tree[{treeIndex}] of terrain {terrain} has no LODGroup component, it will be ignored by RGL"); + else if (treePrefab.TryGetComponent(out MeshFilter meshFilter)) + { + Debug.LogWarning($"Tree[{treeIndex}] \"{treePrefab.name}\" of terrain {terrain.GetInstanceID()} has no LODGroup component, but it has a MeshFilter component. " + + $"The tree's rotation and scale is not going o match those in the Unity Editor, " + + $"since Unity Editor has a bug and does not rotate or scale trees without LODGroup components"); + return meshFilter.sharedMesh; + } + Debug.LogWarning($"Tree[{treeIndex}] \"{treePrefab.name}\" of terrain {terrain.GetInstanceID()} has no LODGroup or MeshFilter component, it will be ignored by RGL"); return null; } From 8c5b3571e2dea9943d07024d842ff08d967cb3eb Mon Sep 17 00:00:00 2001 From: Jakub-Krakowiak Date: Tue, 22 Aug 2023 16:35:58 +0200 Subject: [PATCH 05/10] removed isStatic check on transform update --- .../Scripts/LowLevelWrappers/RGLMeshObject.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs index 90235dc3b..5839823c9 100644 --- a/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs +++ b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs @@ -48,7 +48,6 @@ public abstract class RGLObject : IRGLObject public string CategoryName { get; private set; } private IntPtr rglEntityPtr; - private bool transformInitialized; protected abstract RGLMesh GetRGLMeshFrom(T meshSource); @@ -113,7 +112,7 @@ public void Update() protected virtual void UpdateTransform() { - if (rglEntityPtr == IntPtr.Zero || (transformInitialized && RepresentedGO.isStatic)) + if (rglEntityPtr == IntPtr.Zero) { return; } @@ -133,11 +132,6 @@ protected virtual void UpdateTransform() RGLNativeAPI.rgl_entity_set_pose(rglEntityPtr, (IntPtr) pMatrix3x4)); } } - - if (!transformInitialized) - { - transformInitialized = true; - } } public override int GetHashCode() From 31a05cb6b7d538f5bcab7737cd339b416913c01b Mon Sep 17 00:00:00 2001 From: Jakub-Krakowiak Date: Wed, 23 Aug 2023 16:29:59 +0200 Subject: [PATCH 06/10] minor structural fixes --- .../Scripts/LowLevelWrappers/RGLMeshObject.cs | 92 ++++++++++++------- .../RGLUnityPlugin/Scripts/RGLMeshManager.cs | 3 +- .../Scripts/RGLTextureManager.cs | 3 +- Assets/RGLUnityPlugin/Scripts/SceneManager.cs | 4 +- 4 files changed, 65 insertions(+), 37 deletions(-) diff --git a/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs index 5839823c9..31be80c3b 100644 --- a/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs +++ b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs @@ -39,9 +39,9 @@ internal interface IRGLObject /// public abstract class RGLObject : IRGLObject { - private string Identifier; - private RGLMesh RglMesh; - private RGLTexture RglTexture; + private readonly string identifier; + private RGLMesh rglMesh; + private RGLTexture rglTexture; public GameObject RepresentedGO { get; } public int? CategoryId { get; private set; } @@ -53,10 +53,10 @@ public abstract class RGLObject : IRGLObject protected RGLObject(string identifier, GameObject representedGO, T meshSource) { - Identifier = identifier; + this.identifier = identifier; RepresentedGO = representedGO; - RglMesh = GetRGLMeshFrom(meshSource); - if (RglMesh == null) + rglMesh = GetRGLMeshFrom(meshSource); + if (rglMesh == null) { return; } @@ -76,33 +76,32 @@ protected RGLObject(string identifier, GameObject representedGO, T meshSource) DestroyInRGL(); } + protected abstract void DestroyRGLMesh(RGLMesh rglMesh); + public virtual void DestroyInRGL() { - if (rglEntityPtr != IntPtr.Zero) + if (rglEntityPtr == IntPtr.Zero) { - RGLNativeAPI.CheckErr(RGLNativeAPI.rgl_entity_destroy(rglEntityPtr)); - rglEntityPtr = IntPtr.Zero; - if (RglMesh is RGLSkinnedMesh) - { - RglMesh.DestroyFromRGL(); - } - else - { - RGLMeshManager.UnregisterRGLMeshInstance(RglMesh.Identifier); - } - RglMesh = null; - if (RglTexture != null) - { - RGLTextureManager.UnregisterRGLTextureInstance(RglTexture.Identifier); - RglTexture = null; - } + return; + } + + RGLNativeAPI.CheckErr(RGLNativeAPI.rgl_entity_destroy(rglEntityPtr)); + rglEntityPtr = IntPtr.Zero; + + DestroyRGLMesh(rglMesh); + rglMesh = null; + + if (rglTexture != null) + { + RGLTextureManager.UnregisterRGLTextureInstance(rglTexture); + rglTexture = null; } } public void Update() { UpdateTransform(); - if (RglMesh is RGLSkinnedMesh rglSkinnedMesh) + if (rglMesh is RGLSkinnedMesh rglSkinnedMesh) { rglSkinnedMesh.UpdateSkinnedMesh(); } @@ -136,25 +135,25 @@ protected virtual void UpdateTransform() public override int GetHashCode() { - return Identifier.GetHashCode(); + return identifier.GetHashCode(); } public override bool Equals(object obj) { - return obj is RGLObject rglObject && Identifier.Equals(rglObject.Identifier); + return obj is RGLObject rglObject && identifier.Equals(rglObject.identifier); } private void UploadToRGL() { // Mesh should be uploaded. - Assert.IsFalse(RglMesh.rglMeshPtr == IntPtr.Zero); + Assert.IsFalse(rglMesh.rglMeshPtr == IntPtr.Zero); unsafe { try { RGLNativeAPI.CheckErr( - RGLNativeAPI.rgl_entity_create(out rglEntityPtr, IntPtr.Zero, RglMesh.rglMeshPtr)); + RGLNativeAPI.rgl_entity_create(out rglEntityPtr, IntPtr.Zero, rglMesh.rglMeshPtr)); } catch (RGLException) { @@ -185,22 +184,22 @@ private void SetIntensityTexture() return; } - RglTexture = RGLTextureManager.RegisterRGLTextureInstance(intensityTextureComponent.texture); + rglTexture = RGLTextureManager.RegisterRGLTextureInstance(intensityTextureComponent.texture); try { RGLNativeAPI.CheckErr( - RGLNativeAPI.rgl_entity_set_intensity_texture(rglEntityPtr, RglTexture.rglTexturePtr)); + RGLNativeAPI.rgl_entity_set_intensity_texture(rglEntityPtr, rglTexture.rglTexturePtr)); } catch (RGLException) { - Debug.LogError($"Cannot assign texture: {RglTexture.Identifier}, to entity: {Identifier}"); + Debug.LogError($"Cannot assign texture: {rglTexture.Identifier}, to entity: {identifier}"); throw; } // Mesh should be uploaded before assigning UVs. - Assert.IsFalse(RglMesh.rglMeshPtr == IntPtr.Zero); + Assert.IsFalse(rglMesh.rglMeshPtr == IntPtr.Zero); - RglMesh.UploadUVs(); + rglMesh.UploadUVs(); } } @@ -223,6 +222,11 @@ protected override Matrix4x4 GetLocalToWorld() { return getLocalToWorld(); } + + protected override void DestroyRGLMesh(RGLMesh rglMesh) + { + RGLMeshManager.UnregisterRGLMeshInstance(rglMesh); + } } public class RGLMeshRendererObject : RGLObject @@ -255,6 +259,11 @@ protected override Matrix4x4 GetLocalToWorld() { return rendererTransform.localToWorldMatrix; } + + protected override void DestroyRGLMesh(RGLMesh rglMesh) + { + RGLMeshManager.UnregisterRGLMeshInstance(rglMesh); + } } public class RGLSkinnedMeshRendererObject : RGLObject @@ -280,6 +289,11 @@ protected override Matrix4x4 GetLocalToWorld() { return skinnedMeshRendererTransform.localToWorldMatrix; } + + protected override void DestroyRGLMesh(RGLMesh rglMesh) + { + rglMesh.DestroyFromRGL(); + } } public class RGLColliderObject : RGLObject @@ -304,6 +318,11 @@ protected override Matrix4x4 GetLocalToWorld() { return collider.transform.localToWorldMatrix * ColliderUtilities.GetColliderTransformMatrix(collider); } + + protected override void DestroyRGLMesh(RGLMesh rglMesh) + { + RGLMeshManager.UnregisterRGLMeshInstance(rglMesh); + } } public class RGLTerrainObject : RGLObject @@ -361,7 +380,12 @@ protected override void UpdateTransform() protected override RGLMesh GetRGLMeshFrom(Terrain terrain) { - return RGLMeshManager.RegisterRGLMeshInstance(TerrainUtilities.GetTerrainMesh(terrain)); + return new RGLMesh(terrain.gameObject.GetInstanceID(), TerrainUtilities.GetTerrainMesh(terrain)); + } + + protected override void DestroyRGLMesh(RGLMesh rglMesh) + { + rglMesh.DestroyFromRGL(); } } diff --git a/Assets/RGLUnityPlugin/Scripts/RGLMeshManager.cs b/Assets/RGLUnityPlugin/Scripts/RGLMeshManager.cs index 0587d3a73..c1fcd9be9 100644 --- a/Assets/RGLUnityPlugin/Scripts/RGLMeshManager.cs +++ b/Assets/RGLUnityPlugin/Scripts/RGLMeshManager.cs @@ -25,8 +25,9 @@ public static RGLMesh RegisterRGLMeshInstance(Mesh unityMesh) return sharedMeshes[meshId]; } - public static void UnregisterRGLMeshInstance(int meshId) + public static void UnregisterRGLMeshInstance(RGLMesh rglMesh) { + var meshId = rglMesh.Identifier; if (sharedMeshes[meshId] is null) { Debug.LogWarning($"Trying to unregister absent in RGLMeshManager mesh of id: {meshId}, ignoring request"); diff --git a/Assets/RGLUnityPlugin/Scripts/RGLTextureManager.cs b/Assets/RGLUnityPlugin/Scripts/RGLTextureManager.cs index ceb728de3..99a25532c 100644 --- a/Assets/RGLUnityPlugin/Scripts/RGLTextureManager.cs +++ b/Assets/RGLUnityPlugin/Scripts/RGLTextureManager.cs @@ -24,8 +24,9 @@ public static RGLTexture RegisterRGLTextureInstance(Texture2D texture) return sharedTextures[textureID]; } - public static void UnregisterRGLTextureInstance(int textureId) + public static void UnregisterRGLTextureInstance(RGLTexture rglTexture) { + var textureId = rglTexture.Identifier; if (sharedTextures[textureId] is null) { Debug.LogWarning($"Trying to unregister absent in RGLTextureManager texture of id: {textureId}, ignoring request"); diff --git a/Assets/RGLUnityPlugin/Scripts/SceneManager.cs b/Assets/RGLUnityPlugin/Scripts/SceneManager.cs index 403fe3283..61de555b9 100644 --- a/Assets/RGLUnityPlugin/Scripts/SceneManager.cs +++ b/Assets/RGLUnityPlugin/Scripts/SceneManager.cs @@ -201,7 +201,9 @@ private void Clear() { rglObject.Value.DestroyInRGL(); } - + + RGLMeshManager.ClearAllMeshes(); + RGLTextureManager.ClearAllTextures(); uploadedRGLObjects.Clear(); lastFrameGameObjects.Clear(); Debug.Log("RGLSceneManager: cleared"); From 2991ab1de6915e3377ee6323d9206cfc9bcea9c2 Mon Sep 17 00:00:00 2001 From: Jakub-Krakowiak Date: Wed, 23 Aug 2023 20:45:17 +0200 Subject: [PATCH 07/10] made a fix to enable all mr and smr from trees in RGL --- .../Scripts/LowLevelWrappers/RGLMeshObject.cs | 75 +++++++---------- Assets/RGLUnityPlugin/Scripts/SceneManager.cs | 62 +------------- .../Scripts/Utilities/RendererUtilities.cs | 82 +++++++++++++++++++ .../Utilities/RendererUtilities.cs.meta | 3 + .../Scripts/Utilities/TerrainUtilities.cs | 50 +++++------ 5 files changed, 143 insertions(+), 129 deletions(-) create mode 100644 Assets/RGLUnityPlugin/Scripts/Utilities/RendererUtilities.cs create mode 100644 Assets/RGLUnityPlugin/Scripts/Utilities/RendererUtilities.cs.meta diff --git a/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs index 31be80c3b..1eb9e353a 100644 --- a/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs +++ b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs @@ -203,37 +203,12 @@ private void SetIntensityTexture() } } - public class RGLMeshObject : RGLObject - { - private readonly Func getLocalToWorld; - - public RGLMeshObject(string identifier, GameObject representedGO, Mesh mesh, Func getLocalToWorld) : - base(identifier, representedGO, mesh) - { - this.getLocalToWorld = getLocalToWorld; - } - - protected override RGLMesh GetRGLMeshFrom(Mesh mesh) - { - return RGLMeshManager.RegisterRGLMeshInstance(mesh); - } - - protected override Matrix4x4 GetLocalToWorld() - { - return getLocalToWorld(); - } - - protected override void DestroyRGLMesh(RGLMesh rglMesh) - { - RGLMeshManager.UnregisterRGLMeshInstance(rglMesh); - } - } - public class RGLMeshRendererObject : RGLObject { private readonly Transform rendererTransform; + private readonly Func getLocalToWorld; - public RGLMeshRendererObject(MeshRenderer meshRenderer) : + public RGLMeshRendererObject(MeshRenderer meshRenderer, Func getLocalToWorld = null): base( $"{meshRenderer.gameObject.name}#{meshRenderer.gameObject.GetInstanceID()}", meshRenderer.gameObject, @@ -241,6 +216,7 @@ public RGLMeshRendererObject(MeshRenderer meshRenderer) : ) { rendererTransform = meshRenderer.transform; + this.getLocalToWorld = getLocalToWorld; } protected override RGLMesh GetRGLMeshFrom(MeshRenderer meshRenderer) @@ -257,7 +233,7 @@ protected override RGLMesh GetRGLMeshFrom(MeshRenderer meshRenderer) protected override Matrix4x4 GetLocalToWorld() { - return rendererTransform.localToWorldMatrix; + return getLocalToWorld != null ? getLocalToWorld() : rendererTransform.localToWorldMatrix; } protected override void DestroyRGLMesh(RGLMesh rglMesh) @@ -269,8 +245,9 @@ protected override void DestroyRGLMesh(RGLMesh rglMesh) public class RGLSkinnedMeshRendererObject : RGLObject { private readonly Transform skinnedMeshRendererTransform; + private readonly Func getLocalToWorld; - public RGLSkinnedMeshRendererObject(SkinnedMeshRenderer skinnedMeshRenderer) : + public RGLSkinnedMeshRendererObject(SkinnedMeshRenderer skinnedMeshRenderer, Func getLocalToWorld = null) : base( $"{skinnedMeshRenderer.gameObject.name}#{skinnedMeshRenderer.gameObject.GetInstanceID()}", skinnedMeshRenderer.gameObject, @@ -278,6 +255,7 @@ public RGLSkinnedMeshRendererObject(SkinnedMeshRenderer skinnedMeshRenderer) : ) { skinnedMeshRendererTransform = skinnedMeshRenderer.transform; + this.getLocalToWorld = getLocalToWorld; } protected override RGLMesh GetRGLMeshFrom(SkinnedMeshRenderer skinnedMeshRenderer) @@ -287,7 +265,7 @@ protected override RGLMesh GetRGLMeshFrom(SkinnedMeshRenderer skinnedMeshRendere protected override Matrix4x4 GetLocalToWorld() { - return skinnedMeshRendererTransform.localToWorldMatrix; + return getLocalToWorld != null ? getLocalToWorld() : skinnedMeshRendererTransform.localToWorldMatrix; } protected override void DestroyRGLMesh(RGLMesh rglMesh) @@ -327,29 +305,38 @@ protected override void DestroyRGLMesh(RGLMesh rglMesh) public class RGLTerrainObject : RGLObject { - private readonly List terrainSubObjects; + private readonly List terrainSubObjects; private readonly Transform terrainTransform; public RGLTerrainObject(Terrain terrain) : base($"{terrain.gameObject.name}#{terrain.gameObject.GetInstanceID()}", terrain.gameObject, terrain) { terrainTransform = terrain.transform; - terrainSubObjects = new List(); - var terrainData = terrain.terrainData; - for (var i = 0; i < terrainData.treeInstanceCount; i++) + terrainSubObjects = new List(); + var treePrototypes = terrain.terrainData.treePrototypes; + + for (var i = 0; i < treePrototypes.Length; i++) { - var treeMesh = TerrainUtilities.GetTreeMesh(terrain, i); - if (treeMesh is null) + var gameObjects = RendererUtilities.GetAllGameObjectsOfPrefab(treePrototypes[i].prefab); + var renderers = RendererUtilities.GetUniqueRenderersInGameObjects(gameObjects); + foreach (var renderer in renderers) { - continue; + var treeIndex = i; + if (renderer is SkinnedMeshRenderer smr) + { + terrainSubObjects.Add(new RGLSkinnedMeshRendererObject(smr,() => + terrain.transform.localToWorldMatrix * + TerrainUtilities.GetTreePose(terrain, treeIndex) * + smr.localToWorldMatrix)); + } + if (renderer is MeshRenderer mr) + { + terrainSubObjects.Add(new RGLMeshRendererObject(mr,() => + terrain.transform.localToWorldMatrix * + TerrainUtilities.GetTreePose(terrain, treeIndex) * + mr.localToWorldMatrix)); + } } - // we need to make a copy of the index because lambda captures use reference semantics for all captured variables - var treeIndex = i; - var tree = new RGLMeshObject($"{RepresentedGO.name}#{RepresentedGO.GetInstanceID()}#{treeIndex}", - RepresentedGO, - treeMesh, - () => terrain.transform.localToWorldMatrix * TerrainUtilities.GetTreePose(terrain, treeIndex)); - terrainSubObjects.Add(tree); } } diff --git a/Assets/RGLUnityPlugin/Scripts/SceneManager.cs b/Assets/RGLUnityPlugin/Scripts/SceneManager.cs index 61de555b9..2a6483618 100644 --- a/Assets/RGLUnityPlugin/Scripts/SceneManager.cs +++ b/Assets/RGLUnityPlugin/Scripts/SceneManager.cs @@ -282,7 +282,7 @@ private static IEnumerable IntoRGLObjectsUsingColliders(IEnumerable< private static IEnumerable IntoRGLObjectsHybrid(IEnumerable gameObjects) { var collidersToYield = new HashSet(); - foreach (var renderer in GetUniqueRenderersInGameObjects(gameObjects)) + foreach (var renderer in RendererUtilities.GetUniqueRenderersInGameObjects(gameObjects)) { if (renderer is SkinnedMeshRenderer smr) { @@ -316,7 +316,7 @@ private static IEnumerable IntoRGLObjectsHybrid(IEnumerable private static IEnumerable IntoRGLObjectsUsingMeshes(IEnumerable gameObjects) { - foreach (var renderer in GetUniqueRenderersInGameObjects(gameObjects)) + foreach (var renderer in RendererUtilities.GetUniqueRenderersInGameObjects(gameObjects)) { if (renderer is MeshRenderer mr) { @@ -346,64 +346,6 @@ private static IEnumerable IntoRGLTerrainObjects(IEnumerable - /// Some prefabs have LOD Group component (Level Of Detail) - /// which implies using different renders based on the distance from the camera. - /// For raytracing purposes, the best available LOD is used (index: 0). - /// Some prefabs may not use LOD and use mesh renderers directly. - /// This function takes the aforementioned into account to output exactly one Renderer per game object. - /// It is guaranteed that yielded meshes are enabled and are not attached to a disabled LOD. - /// - private static IEnumerable GetUniqueRenderersInGameObjects(IEnumerable gameObjects) - { - var lodGroups = new HashSet(); - var smrs = new HashSet(); - var mrs = new HashSet(); - - foreach (var gameObject in gameObjects) - { - if (gameObject.TryGetComponent(out var lodGroup)) - { - lodGroups.Add(lodGroup); - } - - if (gameObject.TryGetComponent(out var smr) && smr.enabled) - { - smrs.Add(smr); - } - - bool hasMeshRenderer = gameObject.TryGetComponent(out var mr) && mr.enabled; - bool hasMeshFilter = gameObject.TryGetComponent(out _); // Mesh filter can't be disabled - if (hasMeshRenderer && hasMeshFilter) - { - mrs.Add(mr); - } - } - - foreach (var lodGroup in lodGroups) - { - for (int lodIndex = 0; lodIndex < lodGroup.lodCount; ++lodIndex) - { - var lod = lodGroup.GetLODs()[lodIndex]; - foreach (var renderer in lod.renderers) - { - // In theory it is possible that the renderer-containing game object is not a descendant of the LoD - // therefore we need to additionally check if renderer.gameObject.activeInHierarchy - if (lodGroup.enabled && lodIndex == 0 && renderer.enabled && renderer.gameObject.activeInHierarchy) - { - yield return renderer; - } - - smrs.Remove(renderer as SkinnedMeshRenderer); - mrs.Remove(renderer as MeshRenderer); - } - } - } - - foreach (var smr in smrs) yield return smr; - foreach (var mr in mrs) yield return mr; - } private static bool IsNotActiveOrParentHasLidar(GameObject gameObject) { diff --git a/Assets/RGLUnityPlugin/Scripts/Utilities/RendererUtilities.cs b/Assets/RGLUnityPlugin/Scripts/Utilities/RendererUtilities.cs new file mode 100644 index 000000000..4927ba91e --- /dev/null +++ b/Assets/RGLUnityPlugin/Scripts/Utilities/RendererUtilities.cs @@ -0,0 +1,82 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace RGLUnityPlugin +{ + public class RendererUtilities + { + /// + /// Some prefabs have LOD Group component (Level Of Detail) + /// which implies using different renders based on the distance from the camera. + /// For raytracing purposes, the best available LOD is used (index: 0). + /// Some prefabs may not use LOD and use mesh renderers directly. + /// This function takes the aforementioned into account to output exactly one Renderer per game object. + /// It is guaranteed that yielded meshes are enabled and are not attached to a disabled LOD. + /// + public static IEnumerable GetUniqueRenderersInGameObjects(IEnumerable gameObjects) + { + var lodGroups = new HashSet(); + var smrs = new HashSet(); + var mrs = new HashSet(); + + foreach (var gameObject in gameObjects) + { + if (gameObject.TryGetComponent(out var lodGroup)) + { + lodGroups.Add(lodGroup); + } + + if (gameObject.TryGetComponent(out var smr) && smr.enabled) + { + smrs.Add(smr); + } + + bool hasMeshRenderer = gameObject.TryGetComponent(out var mr) && mr.enabled; + bool hasMeshFilter = gameObject.TryGetComponent(out _); // Mesh filter can't be disabled + if (hasMeshRenderer && hasMeshFilter) + { + mrs.Add(mr); + } + } + + foreach (var lodGroup in lodGroups) + { + for (int lodIndex = 0; lodIndex < lodGroup.lodCount; ++lodIndex) + { + var lod = lodGroup.GetLODs()[lodIndex]; + foreach (var renderer in lod.renderers) + { + // In theory it is possible that the renderer-containing game object is not a descendant of the LoD + // therefore we need to additionally check if renderer.gameObject.activeInHierarchy + if (lodGroup.enabled && lodIndex == 0 && renderer.enabled && renderer.gameObject.activeInHierarchy) + { + yield return renderer; + } + + smrs.Remove(renderer as SkinnedMeshRenderer); + mrs.Remove(renderer as MeshRenderer); + } + } + } + + foreach (var smr in smrs) yield return smr; + foreach (var mr in mrs) yield return mr; + } + + public static List GetAllGameObjectsOfPrefab(GameObject prefab) + { + var result = new List(); + GetAllGameObjectsOfPrefabHelper(prefab.transform, result); + return result; + } + + private static void GetAllGameObjectsOfPrefabHelper(Transform transform, List result) + { + result.Add(transform.gameObject); + for (var i = 0; i < transform.childCount; i++) + { + GetAllGameObjectsOfPrefabHelper(transform.GetChild(i), result); + } + } + } +} \ No newline at end of file diff --git a/Assets/RGLUnityPlugin/Scripts/Utilities/RendererUtilities.cs.meta b/Assets/RGLUnityPlugin/Scripts/Utilities/RendererUtilities.cs.meta new file mode 100644 index 000000000..b2ae9fc62 --- /dev/null +++ b/Assets/RGLUnityPlugin/Scripts/Utilities/RendererUtilities.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bd4a0894cf624bb8bd2fa980960b70e7 +timeCreated: 1692802128 \ No newline at end of file diff --git a/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs b/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs index 12ee145c8..6523bc354 100644 --- a/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs +++ b/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using UnityEngine.Rendering; using UnityEngine; @@ -94,31 +95,30 @@ public static Mesh GetTerrainMesh(Terrain terrain) return heightmapMesh; } - public static Mesh GetTreeMesh(Terrain terrain, int treeIndex) - { - var terrainData = terrain.terrainData; - var treeInstance = terrainData.GetTreeInstance(treeIndex); - var treePrefab = terrainData.treePrototypes[treeInstance.prototypeIndex].prefab; - if (treePrefab.TryGetComponent(out LODGroup lodGroup)) - { - if (lodGroup.GetLODs()[0].renderers[0].TryGetComponent(out MeshFilter meshFilter)) - { - return meshFilter.sharedMesh; - } - - Debug.LogWarning($"Tree[{treeIndex}] \"{treePrefab.name}\" of terrain {terrain.GetInstanceID()} has LODGroup component with no MeshFilter component, it will be ignored by RGL"); - return null; - } - else if (treePrefab.TryGetComponent(out MeshFilter meshFilter)) - { - Debug.LogWarning($"Tree[{treeIndex}] \"{treePrefab.name}\" of terrain {terrain.GetInstanceID()} has no LODGroup component, but it has a MeshFilter component. " + - $"The tree's rotation and scale is not going o match those in the Unity Editor, " + - $"since Unity Editor has a bug and does not rotate or scale trees without LODGroup components"); - return meshFilter.sharedMesh; - } - Debug.LogWarning($"Tree[{treeIndex}] \"{treePrefab.name}\" of terrain {terrain.GetInstanceID()} has no LODGroup or MeshFilter component, it will be ignored by RGL"); - return null; - } + // public static Mesh GetTreeMesh(Terrain terrain, int treeIndex) + // { + // var terrainData = terrain.terrainData; + // + // if (treePrefab.TryGetComponent(out LODGroup lodGroup)) + // { + // if (lodGroup.GetLODs()[0].renderers[0].TryGetComponent(out MeshFilter meshFilter)) + // { + // return meshFilter.sharedMesh; + // } + // + // Debug.LogWarning($"Tree[{treeIndex}] \"{treePrefab.name}\" of terrain {terrain.GetInstanceID()} has LODGroup component with no MeshFilter component, it will be ignored by RGL"); + // return null; + // } + // else if (treePrefab.TryGetComponent(out MeshFilter meshFilter)) + // { + // Debug.LogWarning($"Tree[{treeIndex}] \"{treePrefab.name}\" of terrain {terrain.GetInstanceID()} has no LODGroup component, but it has a MeshFilter component. " + + // $"The tree's rotation and scale is not going o match those in the Unity Editor, " + + // $"since Unity Editor has a bug and does not rotate or scale trees without LODGroup components"); + // return meshFilter.sharedMesh; + // } + // Debug.LogWarning($"Tree[{treeIndex}] \"{treePrefab.name}\" of terrain {terrain.GetInstanceID()} has no LODGroup or MeshFilter component, it will be ignored by RGL"); + // return null; + // } public static Matrix4x4 GetTreePose(Terrain terrain, int treeIndex) { From 5537cf3514c4d12d5e19258e898665a0e06d45c6 Mon Sep 17 00:00:00 2001 From: Mateusz Szczygielski Date: Thu, 24 Aug 2023 16:26:45 +0200 Subject: [PATCH 08/10] Fix terrain tree handling --- .../Scripts/LowLevelWrappers/RGLMeshObject.cs | 41 +++++++--- Assets/RGLUnityPlugin/Scripts/SceneManager.cs | 64 ++++++++++++++- .../Scripts/Utilities/RendererUtilities.cs | 82 ------------------- .../Utilities/RendererUtilities.cs.meta | 3 - .../Scripts/Utilities/TerrainUtilities.cs | 59 +++++-------- 5 files changed, 109 insertions(+), 140 deletions(-) delete mode 100644 Assets/RGLUnityPlugin/Scripts/Utilities/RendererUtilities.cs delete mode 100644 Assets/RGLUnityPlugin/Scripts/Utilities/RendererUtilities.cs.meta diff --git a/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs index 1eb9e353a..4670d4417 100644 --- a/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs +++ b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs @@ -315,31 +315,46 @@ public RGLTerrainObject(Terrain terrain) : terrainSubObjects = new List(); var treePrototypes = terrain.terrainData.treePrototypes; + List[] treePrototypesRenderes = new List[treePrototypes.Length]; + bool[] treePrototypesHasLODGroup = new bool[treePrototypes.Length]; + for (var i = 0; i < treePrototypes.Length; i++) { - var gameObjects = RendererUtilities.GetAllGameObjectsOfPrefab(treePrototypes[i].prefab); - var renderers = RendererUtilities.GetUniqueRenderersInGameObjects(gameObjects); - foreach (var renderer in renderers) + treePrototypesRenderes[i] = new List(); + var treePrefab = treePrototypes[i].prefab; + if (treePrefab.TryGetComponent(out var lodGroup)) { - var treeIndex = i; - if (renderer is SkinnedMeshRenderer smr) + var lod = lodGroup.GetLODs()[0]; + foreach (var renderer in lod.renderers) { - terrainSubObjects.Add(new RGLSkinnedMeshRendererObject(smr,() => - terrain.transform.localToWorldMatrix * - TerrainUtilities.GetTreePose(terrain, treeIndex) * - smr.localToWorldMatrix)); + if (renderer.gameObject.TryGetComponent(out _)) + { + treePrototypesRenderes[i].Add(renderer); + } } + treePrototypesHasLODGroup[i] = true; + } else if (treePrefab.TryGetComponent(out var mr) && treePrefab.TryGetComponent(out _)) + { + treePrototypesRenderes[i].Add(mr); + treePrototypesHasLODGroup[i] = false; + } + } + + for (var treeIdx = 0; treeIdx < terrain.terrainData.treeInstanceCount; treeIdx++) + { + int prototypeIdx = terrain.terrainData.GetTreeInstance(treeIdx).prototypeIndex; + foreach (var renderer in treePrototypesRenderes[prototypeIdx]) + { + var treePose = TerrainUtilities.GetTreePose(terrain, treeIdx, treePrototypesHasLODGroup[prototypeIdx]); if (renderer is MeshRenderer mr) { terrainSubObjects.Add(new RGLMeshRendererObject(mr,() => - terrain.transform.localToWorldMatrix * - TerrainUtilities.GetTreePose(terrain, treeIndex) * - mr.localToWorldMatrix)); + terrain.transform.localToWorldMatrix * treePose * mr.localToWorldMatrix)); } } } } - + protected override Matrix4x4 GetLocalToWorld() { return terrainTransform.localToWorldMatrix; diff --git a/Assets/RGLUnityPlugin/Scripts/SceneManager.cs b/Assets/RGLUnityPlugin/Scripts/SceneManager.cs index 2a6483618..66de63eac 100644 --- a/Assets/RGLUnityPlugin/Scripts/SceneManager.cs +++ b/Assets/RGLUnityPlugin/Scripts/SceneManager.cs @@ -282,7 +282,7 @@ private static IEnumerable IntoRGLObjectsUsingColliders(IEnumerable< private static IEnumerable IntoRGLObjectsHybrid(IEnumerable gameObjects) { var collidersToYield = new HashSet(); - foreach (var renderer in RendererUtilities.GetUniqueRenderersInGameObjects(gameObjects)) + foreach (var renderer in GetUniqueRenderersInGameObjects(gameObjects)) { if (renderer is SkinnedMeshRenderer smr) { @@ -316,7 +316,7 @@ private static IEnumerable IntoRGLObjectsHybrid(IEnumerable private static IEnumerable IntoRGLObjectsUsingMeshes(IEnumerable gameObjects) { - foreach (var renderer in RendererUtilities.GetUniqueRenderersInGameObjects(gameObjects)) + foreach (var renderer in GetUniqueRenderersInGameObjects(gameObjects)) { if (renderer is MeshRenderer mr) { @@ -346,7 +346,65 @@ private static IEnumerable IntoRGLTerrainObjects(IEnumerable + /// Some prefabs have LOD Group component (Level Of Detail) + /// which implies using different renders based on the distance from the camera. + /// For raytracing purposes, the best available LOD is used (index: 0). + /// Some prefabs may not use LOD and use mesh renderers directly. + /// This function takes the aforementioned into account to output exactly one Renderer per game object. + /// It is guaranteed that yielded meshes are enabled and are not attached to a disabled LOD. + /// + private static IEnumerable GetUniqueRenderersInGameObjects(IEnumerable gameObjects) + { + var lodGroups = new HashSet(); + var smrs = new HashSet(); + var mrs = new HashSet(); + + foreach (var gameObject in gameObjects) + { + if (gameObject.TryGetComponent(out var lodGroup)) + { + lodGroups.Add(lodGroup); + } + + if (gameObject.TryGetComponent(out var smr) && smr.enabled) + { + smrs.Add(smr); + } + + bool hasMeshRenderer = gameObject.TryGetComponent(out var mr) && mr.enabled; + bool hasMeshFilter = gameObject.TryGetComponent(out _); // Mesh filter can't be disabled + if (hasMeshRenderer && hasMeshFilter) + { + mrs.Add(mr); + } + } + + foreach (var lodGroup in lodGroups) + { + for (int lodIndex = 0; lodIndex < lodGroup.lodCount; ++lodIndex) + { + var lod = lodGroup.GetLODs()[lodIndex]; + foreach (var renderer in lod.renderers) + { + // In theory it is possible that the renderer-containing game object is not a descendant of the LoD + // therefore we need to additionally check if renderer.gameObject.activeInHierarchy + if (lodGroup.enabled && lodIndex == 0 && renderer.enabled && renderer.gameObject.activeInHierarchy) + { + yield return renderer; + } + + smrs.Remove(renderer as SkinnedMeshRenderer); + mrs.Remove(renderer as MeshRenderer); + } + } + } + + foreach (var smr in smrs) yield return smr; + foreach (var mr in mrs) yield return mr; + } + private static bool IsNotActiveOrParentHasLidar(GameObject gameObject) { return !gameObject.activeInHierarchy || gameObject.GetComponentsInParent().Length != 0; diff --git a/Assets/RGLUnityPlugin/Scripts/Utilities/RendererUtilities.cs b/Assets/RGLUnityPlugin/Scripts/Utilities/RendererUtilities.cs deleted file mode 100644 index 4927ba91e..000000000 --- a/Assets/RGLUnityPlugin/Scripts/Utilities/RendererUtilities.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -namespace RGLUnityPlugin -{ - public class RendererUtilities - { - /// - /// Some prefabs have LOD Group component (Level Of Detail) - /// which implies using different renders based on the distance from the camera. - /// For raytracing purposes, the best available LOD is used (index: 0). - /// Some prefabs may not use LOD and use mesh renderers directly. - /// This function takes the aforementioned into account to output exactly one Renderer per game object. - /// It is guaranteed that yielded meshes are enabled and are not attached to a disabled LOD. - /// - public static IEnumerable GetUniqueRenderersInGameObjects(IEnumerable gameObjects) - { - var lodGroups = new HashSet(); - var smrs = new HashSet(); - var mrs = new HashSet(); - - foreach (var gameObject in gameObjects) - { - if (gameObject.TryGetComponent(out var lodGroup)) - { - lodGroups.Add(lodGroup); - } - - if (gameObject.TryGetComponent(out var smr) && smr.enabled) - { - smrs.Add(smr); - } - - bool hasMeshRenderer = gameObject.TryGetComponent(out var mr) && mr.enabled; - bool hasMeshFilter = gameObject.TryGetComponent(out _); // Mesh filter can't be disabled - if (hasMeshRenderer && hasMeshFilter) - { - mrs.Add(mr); - } - } - - foreach (var lodGroup in lodGroups) - { - for (int lodIndex = 0; lodIndex < lodGroup.lodCount; ++lodIndex) - { - var lod = lodGroup.GetLODs()[lodIndex]; - foreach (var renderer in lod.renderers) - { - // In theory it is possible that the renderer-containing game object is not a descendant of the LoD - // therefore we need to additionally check if renderer.gameObject.activeInHierarchy - if (lodGroup.enabled && lodIndex == 0 && renderer.enabled && renderer.gameObject.activeInHierarchy) - { - yield return renderer; - } - - smrs.Remove(renderer as SkinnedMeshRenderer); - mrs.Remove(renderer as MeshRenderer); - } - } - } - - foreach (var smr in smrs) yield return smr; - foreach (var mr in mrs) yield return mr; - } - - public static List GetAllGameObjectsOfPrefab(GameObject prefab) - { - var result = new List(); - GetAllGameObjectsOfPrefabHelper(prefab.transform, result); - return result; - } - - private static void GetAllGameObjectsOfPrefabHelper(Transform transform, List result) - { - result.Add(transform.gameObject); - for (var i = 0; i < transform.childCount; i++) - { - GetAllGameObjectsOfPrefabHelper(transform.GetChild(i), result); - } - } - } -} \ No newline at end of file diff --git a/Assets/RGLUnityPlugin/Scripts/Utilities/RendererUtilities.cs.meta b/Assets/RGLUnityPlugin/Scripts/Utilities/RendererUtilities.cs.meta deleted file mode 100644 index b2ae9fc62..000000000 --- a/Assets/RGLUnityPlugin/Scripts/Utilities/RendererUtilities.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: bd4a0894cf624bb8bd2fa980960b70e7 -timeCreated: 1692802128 \ No newline at end of file diff --git a/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs b/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs index 6523bc354..580653935 100644 --- a/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs +++ b/Assets/RGLUnityPlugin/Scripts/Utilities/TerrainUtilities.cs @@ -16,7 +16,7 @@ public static Mesh GetTerrainMesh(Terrain terrain) var solidSurfaceTiles = terrainData.GetHoles(0, 0, holesResolution, holesResolution); var scale = terrainData.heightmapScale; var vertices = new Vector3[heightmapResolution * heightmapResolution]; - + if (!correctHolesResolution) { Debug.LogWarning($"Terrain {terrain.GetInstanceID()} holes resolution is incorrect, holes will be ignored by RGL"); @@ -35,8 +35,7 @@ public static Mesh GetTerrainMesh(Terrain terrain) // this is the number of squares alongside each axis of the terrain // e.g. if you have a 3x3 grid of points you can fill the space between them using a 2x2 square grid var tileResolution = heightmapResolution - 1; - - + // count solid terrain tiles (not holes) var tileCount = 0; foreach (var solidSurface in solidSurfaceTiles) @@ -51,7 +50,7 @@ public static Mesh GetTerrainMesh(Terrain terrain) { tileCount = tileResolution * tileResolution; } - + // there are 2 triangles per square tile, so 6 indices var triangles = new int[tileCount * 2 * 3]; @@ -60,32 +59,31 @@ public static Mesh GetTerrainMesh(Terrain terrain) { for (var x = 0; x < tileResolution; x++) { - if (correctHolesResolution && !solidSurfaceTiles[z, x]) { continue; } - + var sampleBase = x * heightmapResolution + z; - + // first triangle of tile triangles[trianglesIndex++] = sampleBase; triangles[trianglesIndex++] = sampleBase + heightmapResolution; triangles[trianglesIndex++] = sampleBase + heightmapResolution + 1; - + // second triangle of tile triangles[trianglesIndex++] = sampleBase; triangles[trianglesIndex++] = sampleBase + 1; triangles[trianglesIndex++] = sampleBase + 1 + heightmapResolution; } } - + var uv = new Vector2[vertices.Length]; for (var i = 0; i < vertices.Length; i++) { uv[i] = new Vector2(vertices[i].x / (tileResolution * scale.x), vertices[i].z / (tileResolution * scale.z)); } - + var heightmapMesh = new Mesh(); heightmapMesh.indexFormat = IndexFormat.UInt32; heightmapMesh.vertices = vertices; @@ -95,38 +93,13 @@ public static Mesh GetTerrainMesh(Terrain terrain) return heightmapMesh; } - // public static Mesh GetTreeMesh(Terrain terrain, int treeIndex) - // { - // var terrainData = terrain.terrainData; - // - // if (treePrefab.TryGetComponent(out LODGroup lodGroup)) - // { - // if (lodGroup.GetLODs()[0].renderers[0].TryGetComponent(out MeshFilter meshFilter)) - // { - // return meshFilter.sharedMesh; - // } - // - // Debug.LogWarning($"Tree[{treeIndex}] \"{treePrefab.name}\" of terrain {terrain.GetInstanceID()} has LODGroup component with no MeshFilter component, it will be ignored by RGL"); - // return null; - // } - // else if (treePrefab.TryGetComponent(out MeshFilter meshFilter)) - // { - // Debug.LogWarning($"Tree[{treeIndex}] \"{treePrefab.name}\" of terrain {terrain.GetInstanceID()} has no LODGroup component, but it has a MeshFilter component. " + - // $"The tree's rotation and scale is not going o match those in the Unity Editor, " + - // $"since Unity Editor has a bug and does not rotate or scale trees without LODGroup components"); - // return meshFilter.sharedMesh; - // } - // Debug.LogWarning($"Tree[{treeIndex}] \"{treePrefab.name}\" of terrain {terrain.GetInstanceID()} has no LODGroup or MeshFilter component, it will be ignored by RGL"); - // return null; - // } - - public static Matrix4x4 GetTreePose(Terrain terrain, int treeIndex) + public static Matrix4x4 GetTreePose(Terrain terrain, int treeIndex, bool applyRotationAndScale) { var terrainPosition = terrain.transform.position; var terrainData = terrain.terrainData; var resolution = terrainData.heightmapResolution; var heightmapScale = terrainData.heightmapScale; - var treeInstance = terrainData.treeInstances[treeIndex]; + var treeInstance = terrainData.GetTreeInstance(treeIndex); var treePosition = treeInstance.position; var translation = new Vector3(treePosition.x, 0, treePosition.z); @@ -135,9 +108,17 @@ public static Matrix4x4 GetTreePose(Terrain terrain, int treeIndex) var samplePose = new Vector3(terrainPosition.x + translation.x, 0, terrainPosition.z + translation.z); translation.y = terrain.SampleHeight(samplePose); - var rotation = Quaternion.AngleAxis(treeInstance.rotation * Mathf.Rad2Deg, Vector3.up); + var rotation = Quaternion.identity; + if (applyRotationAndScale) + { + rotation = Quaternion.AngleAxis(treeInstance.rotation * Mathf.Rad2Deg, Vector3.up); + } - var scale = new Vector3(treeInstance.widthScale, treeInstance.heightScale, treeInstance.widthScale); + var scale = Vector3.one; + if (applyRotationAndScale) + { + scale = new Vector3(treeInstance.widthScale, treeInstance.heightScale, treeInstance.widthScale); + } return Matrix4x4.TRS(translation, rotation, scale); } From 972606e6cc8e2dc1feed622748b1b3cce4922a2c Mon Sep 17 00:00:00 2001 From: Mateusz Szczygielski Date: Thu, 24 Aug 2023 17:35:54 +0200 Subject: [PATCH 09/10] Review changes --- .../Scripts/LowLevelWrappers/RGLMeshObject.cs | 113 +++++++++--------- .../RGLMeshSharingManager.cs} | 10 +- .../RGLMeshSharingManager.cs.meta | 11 ++ .../RGLTextureManager.cs | 10 +- .../RGLTextureManager.cs.meta | 11 ++ .../Scripts/RGLMeshManager.cs.meta | 3 - .../Scripts/RGLTextureManager.cs.meta | 3 - Assets/RGLUnityPlugin/Scripts/SceneManager.cs | 4 +- 8 files changed, 91 insertions(+), 74 deletions(-) rename Assets/RGLUnityPlugin/Scripts/{RGLMeshManager.cs => LowLevelWrappers/RGLMeshSharingManager.cs} (86%) create mode 100644 Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshSharingManager.cs.meta rename Assets/RGLUnityPlugin/Scripts/{ => LowLevelWrappers}/RGLTextureManager.cs (86%) create mode 100644 Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLTextureManager.cs.meta delete mode 100644 Assets/RGLUnityPlugin/Scripts/RGLMeshManager.cs.meta delete mode 100644 Assets/RGLUnityPlugin/Scripts/RGLTextureManager.cs.meta diff --git a/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs index 4670d4417..e052bd18a 100644 --- a/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs +++ b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs @@ -40,17 +40,21 @@ internal interface IRGLObject public abstract class RGLObject : IRGLObject { private readonly string identifier; - private RGLMesh rglMesh; private RGLTexture rglTexture; - + private IntPtr rglEntityPtr; + + protected RGLMesh rglMesh; + public GameObject RepresentedGO { get; } public int? CategoryId { get; private set; } public string CategoryName { get; private set; } - private IntPtr rglEntityPtr; - + // There are different stratiegies for obtaining a RGLMesh so we have to also destroy it differently. protected abstract RGLMesh GetRGLMeshFrom(T meshSource); - + protected abstract void DestroyRGLMesh(); + + protected abstract Matrix4x4 GetLocalToWorld(); + protected RGLObject(string identifier, GameObject representedGO, T meshSource) { this.identifier = identifier; @@ -58,7 +62,7 @@ protected RGLObject(string identifier, GameObject representedGO, T meshSource) rglMesh = GetRGLMeshFrom(meshSource); if (rglMesh == null) { - return; + throw new RGLException($"Could not create RGLMesh from gameobject '{representedGO.name}'."); } UploadToRGL(); SetIntensityTexture(); @@ -76,24 +80,22 @@ protected RGLObject(string identifier, GameObject representedGO, T meshSource) DestroyInRGL(); } - protected abstract void DestroyRGLMesh(RGLMesh rglMesh); - public virtual void DestroyInRGL() { if (rglEntityPtr == IntPtr.Zero) { return; } - + RGLNativeAPI.CheckErr(RGLNativeAPI.rgl_entity_destroy(rglEntityPtr)); rglEntityPtr = IntPtr.Zero; - DestroyRGLMesh(rglMesh); + DestroyRGLMesh(); rglMesh = null; - + if (rglTexture != null) { - RGLTextureManager.UnregisterRGLTextureInstance(rglTexture); + RGLTextureSharingManager.UnregisterRGLTextureInstance(rglTexture); rglTexture = null; } } @@ -107,15 +109,10 @@ public void Update() } } - protected abstract Matrix4x4 GetLocalToWorld(); - protected virtual void UpdateTransform() { - if (rglEntityPtr == IntPtr.Zero) - { - return; - } - + Assert.IsFalse(rglEntityPtr == IntPtr.Zero); + Matrix4x4 m = GetLocalToWorld(); float[] matrix3x4 = { @@ -184,7 +181,7 @@ private void SetIntensityTexture() return; } - rglTexture = RGLTextureManager.RegisterRGLTextureInstance(intensityTextureComponent.texture); + rglTexture = RGLTextureSharingManager.RegisterRGLTextureInstance(intensityTextureComponent.texture); try { RGLNativeAPI.CheckErr( @@ -205,18 +202,18 @@ private void SetIntensityTexture() public class RGLMeshRendererObject : RGLObject { - private readonly Transform rendererTransform; private readonly Func getLocalToWorld; - public RGLMeshRendererObject(MeshRenderer meshRenderer, Func getLocalToWorld = null): + // By default localToWorld is taken from MeshRenderer, but developer can override it by passing overrideGetLocalToWorld. + public RGLMeshRendererObject(MeshRenderer meshRenderer, Func overrideGetLocalToWorld = null): base( $"{meshRenderer.gameObject.name}#{meshRenderer.gameObject.GetInstanceID()}", meshRenderer.gameObject, meshRenderer ) { - rendererTransform = meshRenderer.transform; - this.getLocalToWorld = getLocalToWorld; + var rendererTransfrom = meshRenderer.transform; + getLocalToWorld = overrideGetLocalToWorld != null ? overrideGetLocalToWorld : () => rendererTransfrom.localToWorldMatrix; } protected override RGLMesh GetRGLMeshFrom(MeshRenderer meshRenderer) @@ -224,30 +221,29 @@ protected override RGLMesh GetRGLMeshFrom(MeshRenderer meshRenderer) var meshFilter = meshRenderer.GetComponent(); if (meshFilter.sharedMesh == null) { - Debug.LogWarning($"Shared mesh of {meshRenderer.gameObject} is null, skipping"); + Debug.LogWarning($"Shared mesh of {meshRenderer.gameObject.name} is null, skipping"); return null; } - return RGLMeshManager.RegisterRGLMeshInstance(meshFilter.sharedMesh); + return RGLMeshSharingManager.RegisterRGLMeshInstance(meshFilter.sharedMesh); } protected override Matrix4x4 GetLocalToWorld() { - return getLocalToWorld != null ? getLocalToWorld() : rendererTransform.localToWorldMatrix; + return getLocalToWorld(); } - protected override void DestroyRGLMesh(RGLMesh rglMesh) + protected override void DestroyRGLMesh() { - RGLMeshManager.UnregisterRGLMeshInstance(rglMesh); + RGLMeshSharingManager.UnregisterRGLMeshInstance(rglMesh); } } public class RGLSkinnedMeshRendererObject : RGLObject { private readonly Transform skinnedMeshRendererTransform; - private readonly Func getLocalToWorld; - public RGLSkinnedMeshRendererObject(SkinnedMeshRenderer skinnedMeshRenderer, Func getLocalToWorld = null) : + public RGLSkinnedMeshRendererObject(SkinnedMeshRenderer skinnedMeshRenderer) : base( $"{skinnedMeshRenderer.gameObject.name}#{skinnedMeshRenderer.gameObject.GetInstanceID()}", skinnedMeshRenderer.gameObject, @@ -255,22 +251,22 @@ public RGLSkinnedMeshRendererObject(SkinnedMeshRenderer skinnedMeshRenderer, Fun ) { skinnedMeshRendererTransform = skinnedMeshRenderer.transform; - this.getLocalToWorld = getLocalToWorld; } protected override RGLMesh GetRGLMeshFrom(SkinnedMeshRenderer skinnedMeshRenderer) { + // Skinned meshes cannot be shared by using RGLMeshSharingManager return new RGLSkinnedMesh(skinnedMeshRenderer.gameObject.GetInstanceID(), skinnedMeshRenderer); } protected override Matrix4x4 GetLocalToWorld() { - return getLocalToWorld != null ? getLocalToWorld() : skinnedMeshRendererTransform.localToWorldMatrix; + return skinnedMeshRendererTransform.localToWorldMatrix; } - protected override void DestroyRGLMesh(RGLMesh rglMesh) + protected override void DestroyRGLMesh() { - rglMesh.DestroyFromRGL(); + rglMesh.DestroyInRGL(); } } @@ -289,7 +285,7 @@ public RGLColliderObject(Collider collider) : protected override RGLMesh GetRGLMeshFrom(Collider collider) { - return RGLMeshManager.RegisterRGLMeshInstance(ColliderUtilities.GetMeshForCollider(collider)); + return RGLMeshSharingManager.RegisterRGLMeshInstance(ColliderUtilities.GetMeshForCollider(collider)); } protected override Matrix4x4 GetLocalToWorld() @@ -297,9 +293,9 @@ protected override Matrix4x4 GetLocalToWorld() return collider.transform.localToWorldMatrix * ColliderUtilities.GetColliderTransformMatrix(collider); } - protected override void DestroyRGLMesh(RGLMesh rglMesh) + protected override void DestroyRGLMesh() { - RGLMeshManager.UnregisterRGLMeshInstance(rglMesh); + RGLMeshSharingManager.UnregisterRGLMeshInstance(rglMesh); } } @@ -324,6 +320,11 @@ public RGLTerrainObject(Terrain terrain) : var treePrefab = treePrototypes[i].prefab; if (treePrefab.TryGetComponent(out var lodGroup)) { + if (lodGroup.GetLODs().Length == 0) + { + Debug.LogWarning($"No LOD levels in LODGroup of tree prototype {treePrefab.name}"); + continue; + } var lod = lodGroup.GetLODs()[0]; foreach (var renderer in lod.renderers) { @@ -340,12 +341,12 @@ public RGLTerrainObject(Terrain terrain) : } } - for (var treeIdx = 0; treeIdx < terrain.terrainData.treeInstanceCount; treeIdx++) + for (var treeIndex = 0; treeIndex < terrain.terrainData.treeInstanceCount; treeIndex++) { - int prototypeIdx = terrain.terrainData.GetTreeInstance(treeIdx).prototypeIndex; - foreach (var renderer in treePrototypesRenderes[prototypeIdx]) + int prototypeIndex = terrain.terrainData.GetTreeInstance(treeIndex).prototypeIndex; + foreach (var renderer in treePrototypesRenderes[prototypeIndex]) { - var treePose = TerrainUtilities.GetTreePose(terrain, treeIdx, treePrototypesHasLODGroup[prototypeIdx]); + var treePose = TerrainUtilities.GetTreePose(terrain, treeIndex, treePrototypesHasLODGroup[prototypeIndex]); if (renderer is MeshRenderer mr) { terrainSubObjects.Add(new RGLMeshRendererObject(mr,() => @@ -376,7 +377,7 @@ protected override void UpdateTransform() { terrainSubObject.Update(); } - + base.UpdateTransform(); } @@ -385,9 +386,9 @@ protected override RGLMesh GetRGLMeshFrom(Terrain terrain) return new RGLMesh(terrain.gameObject.GetInstanceID(), TerrainUtilities.GetTerrainMesh(terrain)); } - protected override void DestroyRGLMesh(RGLMesh rglMesh) + protected override void DestroyRGLMesh() { - rglMesh.DestroyFromRGL(); + rglMesh.DestroyInRGL(); } } @@ -413,10 +414,10 @@ public RGLMesh(int identifier, Mesh mesh) ~RGLMesh() { - DestroyFromRGL(); + DestroyInRGL(); } - public void DestroyFromRGL() + public void DestroyInRGL() { if (rglMeshPtr != IntPtr.Zero) { @@ -438,7 +439,7 @@ protected void UploadToRGL() if (!verticesOK || !indicesOK) { throw new NotSupportedException( - $"Could not get mesh data with mesh identifier {Identifier}. The mesh may be not readable or empty."); + $"Could not get mesh data from Mesh '{Mesh.name}'. The mesh may be not readable or empty."); } unsafe @@ -471,7 +472,7 @@ public void UploadUVs() if(!uvOK) { - Debug.LogWarning($"Could not assign UVs to mesh: {Identifier}. Mash has no UV, or UV are empty."); + Debug.LogWarning($"Could not assign UVs to mesh: '{Mesh.name}'. Mesh has no UV, or UV are empty."); } else { @@ -488,7 +489,7 @@ public void UploadUVs() } catch (RGLException) { - Debug.LogWarning($"Could not assign UVs to mesh: {Identifier}."); + Debug.LogWarning($"Could not assign UVs to mesh: '{Mesh.name}'."); throw; } } @@ -553,10 +554,10 @@ public RGLTexture(Texture2D texture, int identifier) ~RGLTexture() { - DestroyFromRGL(); + DestroyInRGL(); } - public void DestroyFromRGL() + public void DestroyInRGL() { if (rglTexturePtr != IntPtr.Zero) { @@ -573,13 +574,13 @@ protected void UploadToRGL() if (!resolutionOK) { throw new NotSupportedException( - $"Could not get texture data. Resolution seems to be broken."); + $"Could not get texture data from Texture '{Texture.name}'. Resolution seems to be broken."); } if (!graphicsFormatOK) { throw new NotSupportedException( - $"Could not get texture data. Texture format has to be equal to R8_UNorm."); + $"Could not get texture data from Texture '{Texture.name}'. Texture format has to be equal to R8_UNorm."); } unsafe @@ -602,10 +603,10 @@ protected void UploadToRGL() RGLNativeAPI.rgl_texture_destroy(rglTexturePtr); rglTexturePtr = IntPtr.Zero; } - throw; + throw; } } - } + } } } } \ No newline at end of file diff --git a/Assets/RGLUnityPlugin/Scripts/RGLMeshManager.cs b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshSharingManager.cs similarity index 86% rename from Assets/RGLUnityPlugin/Scripts/RGLMeshManager.cs rename to Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshSharingManager.cs index c1fcd9be9..136a1c596 100644 --- a/Assets/RGLUnityPlugin/Scripts/RGLMeshManager.cs +++ b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshSharingManager.cs @@ -3,7 +3,7 @@ namespace RGLUnityPlugin { - public class RGLMeshManager + public class RGLMeshSharingManager { private static Dictionary sharedMeshes = new Dictionary(); // private static Dictionary sharedMeshesUsageCount = new Dictionary(); // @@ -30,24 +30,24 @@ public static void UnregisterRGLMeshInstance(RGLMesh rglMesh) var meshId = rglMesh.Identifier; if (sharedMeshes[meshId] is null) { - Debug.LogWarning($"Trying to unregister absent in RGLMeshManager mesh of id: {meshId}, ignoring request"); + Debug.LogWarning($"Trying to unregister absent in RGLMeshSharingManager mesh of id: {meshId}, ignoring request"); return; } sharedMeshesUsageCount[meshId]--; if (sharedMeshesUsageCount[meshId] == 0) { - sharedMeshes[meshId].DestroyFromRGL(); + sharedMeshes[meshId].DestroyInRGL(); sharedMeshes.Remove(meshId); sharedMeshesUsageCount.Remove(meshId); } } - public static void ClearAllMeshes() + public static void Clear() { foreach (var mesh in sharedMeshes) { - mesh.Value.DestroyFromRGL(); + mesh.Value.DestroyInRGL(); } } } diff --git a/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshSharingManager.cs.meta b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshSharingManager.cs.meta new file mode 100644 index 000000000..1aa510c44 --- /dev/null +++ b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshSharingManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f3925eb4ce66baa129634b42f2ff2c6f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RGLUnityPlugin/Scripts/RGLTextureManager.cs b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLTextureManager.cs similarity index 86% rename from Assets/RGLUnityPlugin/Scripts/RGLTextureManager.cs rename to Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLTextureManager.cs index 99a25532c..f876a1804 100644 --- a/Assets/RGLUnityPlugin/Scripts/RGLTextureManager.cs +++ b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLTextureManager.cs @@ -3,7 +3,7 @@ namespace RGLUnityPlugin { - public class RGLTextureManager + public class RGLTextureSharingManager { private static Dictionary sharedTextures = new Dictionary(); // private static Dictionary sharedTexturesUsageCount = new Dictionary(); // @@ -29,24 +29,24 @@ public static void UnregisterRGLTextureInstance(RGLTexture rglTexture) var textureId = rglTexture.Identifier; if (sharedTextures[textureId] is null) { - Debug.LogWarning($"Trying to unregister absent in RGLTextureManager texture of id: {textureId}, ignoring request"); + Debug.LogWarning($"Trying to unregister absent in RGLTextureSharingManager texture of id: {textureId}, ignoring request"); return; } sharedTexturesUsageCount[textureId]--; if (sharedTexturesUsageCount[textureId] == 0) { - sharedTextures[textureId].DestroyFromRGL(); + sharedTextures[textureId].DestroyInRGL(); sharedTextures.Remove(textureId); sharedTextures.Remove(textureId); } } - public static void ClearAllTextures() + public static void Clear() { foreach (var mesh in sharedTextures) { - mesh.Value.DestroyFromRGL(); + mesh.Value.DestroyInRGL(); } } } diff --git a/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLTextureManager.cs.meta b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLTextureManager.cs.meta new file mode 100644 index 000000000..2d0afa663 --- /dev/null +++ b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLTextureManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 91c9c04927411d5dcb8a4505e5e1e81b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RGLUnityPlugin/Scripts/RGLMeshManager.cs.meta b/Assets/RGLUnityPlugin/Scripts/RGLMeshManager.cs.meta deleted file mode 100644 index 518a28ba0..000000000 --- a/Assets/RGLUnityPlugin/Scripts/RGLMeshManager.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: bedd83a891b64af4859250467981ae5d -timeCreated: 1691588628 \ No newline at end of file diff --git a/Assets/RGLUnityPlugin/Scripts/RGLTextureManager.cs.meta b/Assets/RGLUnityPlugin/Scripts/RGLTextureManager.cs.meta deleted file mode 100644 index a72cba859..000000000 --- a/Assets/RGLUnityPlugin/Scripts/RGLTextureManager.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: c848f96e811948f49d9a5e411b9ccb3e -timeCreated: 1692014679 \ No newline at end of file diff --git a/Assets/RGLUnityPlugin/Scripts/SceneManager.cs b/Assets/RGLUnityPlugin/Scripts/SceneManager.cs index 66de63eac..24e697a9e 100644 --- a/Assets/RGLUnityPlugin/Scripts/SceneManager.cs +++ b/Assets/RGLUnityPlugin/Scripts/SceneManager.cs @@ -202,8 +202,8 @@ private void Clear() rglObject.Value.DestroyInRGL(); } - RGLMeshManager.ClearAllMeshes(); - RGLTextureManager.ClearAllTextures(); + RGLMeshSharingManager.Clear(); + RGLTextureSharingManager.Clear(); uploadedRGLObjects.Clear(); lastFrameGameObjects.Clear(); Debug.Log("RGLSceneManager: cleared"); From 21bc4ced6d4864ee412db842747b09d7a8c6cadc Mon Sep 17 00:00:00 2001 From: Jakub-Krakowiak Date: Thu, 24 Aug 2023 19:10:45 +0200 Subject: [PATCH 10/10] fixed RGLMesh and RGLTexture member variables visibility and names, fixed some typos --- .../Scripts/LowLevelWrappers/RGLMeshObject.cs | 86 +++++++++---------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs index e052bd18a..3c1866db5 100644 --- a/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs +++ b/Assets/RGLUnityPlugin/Scripts/LowLevelWrappers/RGLMeshObject.cs @@ -143,14 +143,14 @@ public override bool Equals(object obj) private void UploadToRGL() { // Mesh should be uploaded. - Assert.IsFalse(rglMesh.rglMeshPtr == IntPtr.Zero); + Assert.IsFalse(rglMesh.RGLMeshPtr == IntPtr.Zero); unsafe { try { RGLNativeAPI.CheckErr( - RGLNativeAPI.rgl_entity_create(out rglEntityPtr, IntPtr.Zero, rglMesh.rglMeshPtr)); + RGLNativeAPI.rgl_entity_create(out rglEntityPtr, IntPtr.Zero, rglMesh.RGLMeshPtr)); } catch (RGLException) { @@ -185,16 +185,16 @@ private void SetIntensityTexture() try { RGLNativeAPI.CheckErr( - RGLNativeAPI.rgl_entity_set_intensity_texture(rglEntityPtr, rglTexture.rglTexturePtr)); + RGLNativeAPI.rgl_entity_set_intensity_texture(rglEntityPtr, rglTexture.RGLTexturePtr)); } catch (RGLException) { - Debug.LogError($"Cannot assign texture: {rglTexture.Identifier}, to entity: {identifier}"); + Debug.LogError($"Cannot assign texture: {rglTexture.Texture.name}, to entity: {RepresentedGO.name}"); throw; } // Mesh should be uploaded before assigning UVs. - Assert.IsFalse(rglMesh.rglMeshPtr == IntPtr.Zero); + Assert.IsFalse(rglMesh.RGLMeshPtr == IntPtr.Zero); rglMesh.UploadUVs(); } @@ -212,8 +212,8 @@ public RGLMeshRendererObject(MeshRenderer meshRenderer, Func override meshRenderer ) { - var rendererTransfrom = meshRenderer.transform; - getLocalToWorld = overrideGetLocalToWorld != null ? overrideGetLocalToWorld : () => rendererTransfrom.localToWorldMatrix; + var rendererTransform = meshRenderer.transform; + getLocalToWorld = overrideGetLocalToWorld != null ? overrideGetLocalToWorld : () => rendererTransform.localToWorldMatrix; } protected override RGLMesh GetRGLMeshFrom(MeshRenderer meshRenderer) @@ -311,12 +311,12 @@ public RGLTerrainObject(Terrain terrain) : terrainSubObjects = new List(); var treePrototypes = terrain.terrainData.treePrototypes; - List[] treePrototypesRenderes = new List[treePrototypes.Length]; - bool[] treePrototypesHasLODGroup = new bool[treePrototypes.Length]; + var treePrototypesRenderers = new List[treePrototypes.Length]; + var treePrototypeHasLODGroup = new bool[treePrototypes.Length]; for (var i = 0; i < treePrototypes.Length; i++) { - treePrototypesRenderes[i] = new List(); + treePrototypesRenderers[i] = new List(); var treePrefab = treePrototypes[i].prefab; if (treePrefab.TryGetComponent(out var lodGroup)) { @@ -330,23 +330,23 @@ public RGLTerrainObject(Terrain terrain) : { if (renderer.gameObject.TryGetComponent(out _)) { - treePrototypesRenderes[i].Add(renderer); + treePrototypesRenderers[i].Add(renderer); } } - treePrototypesHasLODGroup[i] = true; + treePrototypeHasLODGroup[i] = true; } else if (treePrefab.TryGetComponent(out var mr) && treePrefab.TryGetComponent(out _)) { - treePrototypesRenderes[i].Add(mr); - treePrototypesHasLODGroup[i] = false; + treePrototypesRenderers[i].Add(mr); + treePrototypeHasLODGroup[i] = false; } } for (var treeIndex = 0; treeIndex < terrain.terrainData.treeInstanceCount; treeIndex++) { - int prototypeIndex = terrain.terrainData.GetTreeInstance(treeIndex).prototypeIndex; - foreach (var renderer in treePrototypesRenderes[prototypeIndex]) + var prototypeIndex = terrain.terrainData.GetTreeInstance(treeIndex).prototypeIndex; + foreach (var renderer in treePrototypesRenderers[prototypeIndex]) { - var treePose = TerrainUtilities.GetTreePose(terrain, treeIndex, treePrototypesHasLODGroup[prototypeIndex]); + var treePose = TerrainUtilities.GetTreePose(terrain, treeIndex, treePrototypeHasLODGroup[prototypeIndex]); if (renderer is MeshRenderer mr) { terrainSubObjects.Add(new RGLMeshRendererObject(mr,() => @@ -400,9 +400,9 @@ protected override void DestroyRGLMesh() public class RGLMesh { public int Identifier; - public Mesh Mesh; + protected Mesh Mesh; - public IntPtr rglMeshPtr = IntPtr.Zero; + public IntPtr RGLMeshPtr = IntPtr.Zero; public RGLMesh(int identifier, Mesh mesh) { @@ -419,10 +419,10 @@ public RGLMesh(int identifier, Mesh mesh) public void DestroyInRGL() { - if (rglMeshPtr != IntPtr.Zero) + if (RGLMeshPtr != IntPtr.Zero) { - RGLNativeAPI.CheckErr(RGLNativeAPI.rgl_mesh_destroy(rglMeshPtr)); - rglMeshPtr = IntPtr.Zero; + RGLNativeAPI.CheckErr(RGLNativeAPI.rgl_mesh_destroy(RGLMeshPtr)); + RGLMeshPtr = IntPtr.Zero; } } @@ -451,13 +451,13 @@ protected void UploadToRGL() try { RGLNativeAPI.CheckErr( - RGLNativeAPI.rgl_mesh_create(out rglMeshPtr, + RGLNativeAPI.rgl_mesh_create(out RGLMeshPtr, (IntPtr) pVertices, vertices.Length, (IntPtr) pIndices, indices.Length / 3)); } catch (RGLException) { - if (rglMeshPtr != IntPtr.Zero) RGLNativeAPI.rgl_mesh_destroy(rglMeshPtr); + if (RGLMeshPtr != IntPtr.Zero) RGLNativeAPI.rgl_mesh_destroy(RGLMeshPtr); throw; } } @@ -477,13 +477,13 @@ public void UploadUVs() else { unsafe - { + { fixed(Vector2* pUVs = UVs) { try { RGLNativeAPI.CheckErr( - RGLNativeAPI.rgl_mesh_set_texture_coords(rglMeshPtr, + RGLNativeAPI.rgl_mesh_set_texture_coords(RGLMeshPtr, (IntPtr)pUVs, UVs.Length)); } @@ -493,7 +493,7 @@ public void UploadUVs() throw; } } - } + } } } } @@ -503,20 +503,20 @@ public void UploadUVs() /// public class RGLSkinnedMesh : RGLMesh { - public SkinnedMeshRenderer SkinnedMeshRenderer; + private readonly SkinnedMeshRenderer skinnedMeshRenderer; public RGLSkinnedMesh(int identifier, SkinnedMeshRenderer smr) { Identifier = identifier; Mesh = new Mesh(); - SkinnedMeshRenderer = smr; - SkinnedMeshRenderer.BakeMesh(Mesh, true); + skinnedMeshRenderer = smr; + skinnedMeshRenderer.BakeMesh(Mesh, true); UploadToRGL(); } public void UpdateSkinnedMesh() { - SkinnedMeshRenderer.BakeMesh(Mesh, true); + skinnedMeshRenderer.BakeMesh(Mesh, true); unsafe { // Accessing .vertices perform a CPU copy! @@ -527,7 +527,7 @@ public void UpdateSkinnedMesh() fixed (Vector3* pVertices = Mesh.vertices) { RGLNativeAPI.CheckErr( - RGLNativeAPI.rgl_mesh_update_vertices(rglMeshPtr, (IntPtr) pVertices, Mesh.vertices.Length)); + RGLNativeAPI.rgl_mesh_update_vertices(RGLMeshPtr, (IntPtr) pVertices, Mesh.vertices.Length)); } } } @@ -539,9 +539,9 @@ public void UpdateSkinnedMesh() /// public class RGLTexture { - public int Identifier; - public Texture2D Texture; - public IntPtr rglTexturePtr = IntPtr.Zero; + public readonly int Identifier; + public readonly Texture2D Texture; + public IntPtr RGLTexturePtr = IntPtr.Zero; public RGLTexture(){} @@ -559,10 +559,10 @@ public RGLTexture(Texture2D texture, int identifier) public void DestroyInRGL() { - if (rglTexturePtr != IntPtr.Zero) + if (RGLTexturePtr != IntPtr.Zero) { - RGLNativeAPI.CheckErr(RGLNativeAPI.rgl_texture_destroy(rglTexturePtr)); - rglTexturePtr = IntPtr.Zero; + RGLNativeAPI.CheckErr(RGLNativeAPI.rgl_texture_destroy(RGLTexturePtr)); + RGLTexturePtr = IntPtr.Zero; } } @@ -591,21 +591,21 @@ protected void UploadToRGL() { RGLNativeAPI.CheckErr( RGLNativeAPI.rgl_texture_create( - out rglTexturePtr, + out RGLTexturePtr, (IntPtr) textureDataPtr, Texture.width, Texture.height)); } catch (RGLException) { - if (rglTexturePtr != IntPtr.Zero) + if (RGLTexturePtr != IntPtr.Zero) { - RGLNativeAPI.rgl_texture_destroy(rglTexturePtr); - rglTexturePtr = IntPtr.Zero; + RGLNativeAPI.rgl_texture_destroy(RGLTexturePtr); + RGLTexturePtr = IntPtr.Zero; } throw; } - } + } } } }