diff --git a/CHANGELOG.md b/CHANGELOG.md index 5692b6e..6783850 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,20 @@ uid: changelog # Changelog +## [1.2.0] - 2024-03-22 -## [1.2.0-pre.12] - 2024-02-13 +### Changed + +* fixed the issue with LOD objects being culled when the camera is static + +### Fixed + +* Entities Graphics should now never run out of space in the NewChunks buffer. +* A null reference exception thrown in some cases when using MeshRenderers with missing materials and/or meshes +## [1.2.0-pre.12] - 2024-02-13 + ### Added * `RenderMeshUnmanaged` an unmanaged IComponentData using the new UnityObjRef for big performance gains in baking! diff --git a/Unity.Entities.Graphics/EntitiesGraphicsCulling.cs b/Unity.Entities.Graphics/EntitiesGraphicsCulling.cs index b983e95..6163813 100644 --- a/Unity.Entities.Graphics/EntitiesGraphicsCulling.cs +++ b/Unity.Entities.Graphics/EntitiesGraphicsCulling.cs @@ -141,91 +141,85 @@ public void Execute(in ArchetypeChunk archetypeChunk, int unfilteredChunkIndex, int diff = (int)chunkCullingData.MovementGraceFixed16 - CameraMoveDistanceFixed16; chunkCullingData.MovementGraceFixed16 = (ushort)math.max(0, diff); - var graceExpired = chunkCullingData.MovementGraceFixed16 == 0; - var forceLodChanged = forceLowLOD != chunkCullingData.ForceLowLODPrevious; - - if (graceExpired || forceLodChanged || DistanceScaleChanged) - { - chunkEntityLodEnabled.Enabled[0] = 0; - chunkEntityLodEnabled.Enabled[1] = 0; + chunkEntityLodEnabled.Enabled[0] = 0; + chunkEntityLodEnabled.Enabled[1] = 0; #if UNITY_EDITOR - stats.LodChunksTested++; + stats.LodChunksTested++; #endif - var chunk = chunkHeader.ArchetypeChunk; + var chunk = chunkHeader.ArchetypeChunk; - var rootLODRanges = chunk.GetNativeArray(ref RootLODRanges); - var rootLODReferencePoints = chunk.GetNativeArray(ref RootLODReferencePoints); - var lodRanges = chunk.GetNativeArray(ref LODRanges); - var lodReferencePoints = chunk.GetNativeArray(ref LODReferencePoints); + var rootLODRanges = chunk.GetNativeArray(ref RootLODRanges); + var rootLODReferencePoints = chunk.GetNativeArray(ref RootLODReferencePoints); + var lodRanges = chunk.GetNativeArray(ref LODRanges); + var lodReferencePoints = chunk.GetNativeArray(ref LODReferencePoints); - float graceDistance = float.MaxValue; + float graceDistance = float.MaxValue; - for (int i = 0; i < chunkInstanceCount; i++) - { - var rootLODRange = rootLODRanges[i]; - var rootLODReferencePoint = rootLODReferencePoints[i]; + for (int i = 0; i < chunkInstanceCount; i++) + { + var rootLODRange = rootLODRanges[i]; + var rootLODReferencePoint = rootLODReferencePoints[i]; - var rootLodDistance = - math.select( - DistanceScale * - math.length(LODParams.cameraPos - rootLODReferencePoint.Value), - DistanceScale, isOrtho); + var rootLodDistance = + math.select( + DistanceScale * + math.length(LODParams.cameraPos - rootLODReferencePoint.Value), + DistanceScale, isOrtho); - float rootMinDist = math.select(rootLODRange.LOD.MinDist, 0.0f, forceLowLOD == 1); - float rootMaxDist = rootLODRange.LOD.MaxDist; + float rootMinDist = math.select(rootLODRange.LOD.MinDist, 0.0f, forceLowLOD == 1); + float rootMaxDist = rootLODRange.LOD.MaxDist; - graceDistance = math.min(math.abs(rootLodDistance - rootMinDist), graceDistance); - graceDistance = math.min(math.abs(rootLodDistance - rootMaxDist), graceDistance); + graceDistance = math.min(math.abs(rootLodDistance - rootMinDist), graceDistance); + graceDistance = math.min(math.abs(rootLodDistance - rootMaxDist), graceDistance); - var rootLodIntersect = (rootLodDistance < rootMaxDist) && (rootLodDistance >= rootMinDist); + var rootLodIntersect = (rootLodDistance < rootMaxDist) && (rootLodDistance >= rootMinDist); - if (rootLodIntersect) + if (rootLodIntersect) + { + var lodRange = lodRanges[i]; + if (lodRange.LODMask < MaximumLODLevelMask) + { + continue; + } + if (lodRange.LODMask == MaximumLODLevelMask) { - var lodRange = lodRanges[i]; - if (lodRange.LODMask < MaximumLODLevelMask) - { - continue; - } - if (lodRange.LODMask == MaximumLODLevelMask) - { // Expand maximum LOD range to cover all higher LODs - lodRange.MinDist = 0.0f; - } - var lodReferencePoint = lodReferencePoints[i]; - - var instanceDistance = - math.select( - DistanceScale * - math.length(LODParams.cameraPos - - lodReferencePoint.Value), DistanceScale, + lodRange.MinDist = 0.0f; + } + var lodReferencePoint = lodReferencePoints[i]; + + var instanceDistance = + math.select( + DistanceScale * + math.length(LODParams.cameraPos - lodReferencePoint.Value), DistanceScale, isOrtho); - var instanceLodIntersect = - (instanceDistance < lodRange.MaxDist) && - (instanceDistance >= lodRange.MinDist); - - graceDistance = math.min(math.abs(instanceDistance - lodRange.MinDist), - graceDistance); - graceDistance = math.min(math.abs(instanceDistance - lodRange.MaxDist), - graceDistance); - - if (instanceLodIntersect) - { - var index = i; - var wordIndex = index >> 6; - var bitIndex = index & 0x3f; - var lodWord = chunkEntityLodEnabled.Enabled[wordIndex]; - - lodWord |= 1UL << bitIndex; - chunkEntityLodEnabled.Enabled[wordIndex] = lodWord; - } + var instanceLodIntersect = + (instanceDistance < lodRange.MaxDist) && + (instanceDistance >= lodRange.MinDist); + + graceDistance = math.min(math.abs(instanceDistance - lodRange.MinDist), + graceDistance); + graceDistance = math.min(math.abs(instanceDistance - lodRange.MaxDist), + graceDistance); + + if (instanceLodIntersect) + { + var index = i; + var wordIndex = index >> 6; + var bitIndex = index & 0x3f; + var lodWord = chunkEntityLodEnabled.Enabled[wordIndex]; + + lodWord |= 1UL << bitIndex; + chunkEntityLodEnabled.Enabled[wordIndex] = lodWord; } } - - chunkCullingData.MovementGraceFixed16 = Fixed16CamDistance.FromFloatFloor(graceDistance); - chunkCullingData.ForceLowLODPrevious = forceLowLOD; } + + chunkCullingData.MovementGraceFixed16 = Fixed16CamDistance.FromFloatFloor(graceDistance); + chunkCullingData.ForceLowLODPrevious = forceLowLOD; + } diff --git a/Unity.Entities.Graphics/EntitiesGraphicsSystem.cs b/Unity.Entities.Graphics/EntitiesGraphicsSystem.cs index 29b04ce..bd539c9 100644 --- a/Unity.Entities.Graphics/EntitiesGraphicsSystem.cs +++ b/Unity.Entities.Graphics/EntitiesGraphicsSystem.cs @@ -542,7 +542,7 @@ private JobHandle RegisterMaterialsAndMeshes(JobHandle inputDeps) var id = m_RendererSystem.RegisterMaterial(material); if (id == BatchMaterialID.Null) { - Debug.LogWarning($"Registering material {(material != null ? material.Value.ToString() : "null")} at index {i} inside a RenderMeshArray failed."); + Debug.LogWarning($"Registering material {(material ? material.Value.ToString() : "null")} at index {i} inside a RenderMeshArray failed."); } brgRenderArray.UniqueMaterials.Add(id); @@ -553,7 +553,7 @@ private JobHandle RegisterMaterialsAndMeshes(JobHandle inputDeps) var mesh = renderArray.MeshesInternal[i]; var id = m_RendererSystem.RegisterMesh(mesh); if (id == BatchMeshID.Null) - Debug.LogWarning($"Registering mesh {(mesh != null ? mesh.Value.ToString() : "null")} at index {i} inside a RenderMeshArray failed."); + Debug.LogWarning($"Registering mesh {(mesh ? mesh.Value.ToString() : "null")} at index {i} inside a RenderMeshArray failed."); brgRenderArray.UniqueMeshes.Add(id); } @@ -1835,7 +1835,12 @@ private JobHandle UpdateAllBatches(JobHandle inputDependencies) Profiler.EndSample(); var numNewChunksArray = new NativeArray(1, Allocator.TempJob); - int totalChunks = m_EntitiesGraphicsRenderedQuery.CalculateChunkCountWithoutFiltering(); + int totalChunksWithNormalQuery = m_EntitiesGraphicsRenderedQuery.CalculateChunkCountWithoutFiltering(); + // One meta-entity = one chunk of normal entities, so use CalculateEntityCount + int totalChunksWithMetaEntityQuery = m_MetaEntitiesForHybridRenderableChunksQuery.CalculateEntityCountWithoutFiltering(); + // For some reason, the counts returned by these queries may not always match in edge cases. + // Use the larger of the two counts to ensure we never run out of space. + int totalChunks = math.max(totalChunksWithNormalQuery, totalChunksWithMetaEntityQuery); var newChunks = new NativeArray( totalChunks, Allocator.TempJob, diff --git a/ValidationExceptions.json b/ValidationExceptions.json index 266df17..319b97e 100644 --- a/ValidationExceptions.json +++ b/ValidationExceptions.json @@ -1,10 +1,31 @@ { - "ErrorExceptions": [ - { - "ValidationTest": "API Validation", - "ExceptionMessage": "Breaking changes require a new major version.", - "PackageVersion": "1.2.0-pre.12" - } - ], - "WarningExceptions": [] + "ErrorExceptions": [ + { + "ValidationTest": "API Updater Configuration Validation", + "ExceptionMessage": "stdout:\nAPIUpdater Configuration Validation\n-----------------------------------\n\nConfiguration Validation Tests (Failed: 0, Total: 1, Ignored 0):\n----------------------------------------------------------------\n\n\nAuto Generated Tests (Failed: 1, Total: 1, Ignored 0):\n------------------------------------------------------\n1) Expected updates not applied for configuration:\n[*] System.SByte [*] Unity.Rendering.MaterialMeshInfo::Submesh -> * Unity.Rendering.MaterialMeshInfo::SubMesh\n\nInput : unsafe class Test : object { System.SByte Method(System.SByte memberValue, Unity.Rendering.MaterialMeshInfo obj) { System.SByte local = obj.Submesh; return Method(obj.Submesh, obj); } }\nExpected: unsafe class Test : object { System.UInt16 Method(System.UInt16 memberValue, Unity.Rendering.MaterialMeshInfo obj) { System.UInt16 local = obj.SubMesh; return Method(obj.SubMesh, obj); } }\nActual : unsafe class Test : object { System.SByte Method(System.SByte memberValue, Unity.Rendering.MaterialMeshInfo obj) { System.SByte local = obj.SubMesh; return Method(obj.SubMesh, obj); } }\n\n\nBase type validation (Failed: 0, Total: 0, Ignored 0):\n------------------------------------------------------\nstderr:\n", + "PackageVersion": "1.2.0" + }, + { + "ValidationTest": "API Validation", + "ExceptionMessage": "Breaking changes require a new major version.", + "PackageVersion": "1.2.0" + } + ], + "WarningExceptions": [ + { + "ValidationTest": "Manifest Validation", + "ExceptionMessage": "Package dependency com.unity.entities@0.60.0-preview.88 must be promoted to production before this package is promoted to production. (Except for core packages)", + "PackageVersion": "1.2.0" + }, + { + "ValidationTest": "Folder Structure Validation", + "ExceptionMessage": "The Resources Directory should not be used in packages. For more guidance, please visit https://docs.unity3d.com/Manual/BestPracticeUnderstandingPerformanceInUnity6.html", + "PackageVersion": "1.2.0" + }, + { + "ValidationTest": "Package Lifecycle Validation", + "ExceptionMessage": "com.unity.entities.graphics has never been promoted to production before. Please contact Release Management through slack in #devs-pkg-promotion to promote the first version of your package before trying to use this automated pipeline. Read more about this error and potential solutions at https://docs.unity3d.com/Packages/com.unity.package-validation-suite@latest/index.html?preview=1&subfolder=/manual/lifecycle_validation_error.html#the-very-first-version-of-a-package-must-be-promoted-by-release-management", + "PackageVersion": "1.2.0" + } + ] } diff --git a/package.json b/package.json index eebe403..4aa86b4 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "com.unity.entities.graphics", "displayName": "Entities Graphics", - "version": "1.2.0-pre.12", + "version": "1.2.0", "unity": "2022.3", "unityRelease": "11f1", "description": "The Entities Graphics package provides systems and components for drawing meshes using DOTS, including support for instanced mesh rendering and LOD.", "dependencies": { - "com.unity.entities": "1.2.0-pre.12", + "com.unity.entities": "1.2.0", "com.unity.modules.particlesystem": "1.0.0", "com.unity.render-pipelines.core": "14.0.9" }, @@ -17,15 +17,15 @@ "unity" ], "_upm": { - "changelog": "### Added\n\n* `RenderMeshUnmanaged` an unmanaged IComponentData using the new UnityObjRef for big performance gains in baking!\n* Support for light probe anchor overrides\n\n### Changed\n\n* MaterialMeshInfo.SubMesh chaned from sbyte to ushort, allowing for the full range of submesh indices.\n* The sharedcomponents `Lightmaps` and `RenderMeshArray` now store UnityObjRef instead.\n\n### Deprecated\n\n* The baking sharedcomponent `RenderMesh` is now obsolete, in favor of a new `RenderMeshUnmanaged`.\n\n### Fixed\n\n* Improved handling of smaller transforms\n* Light probes now use the center of world bounding box as the reference point, same as game objects\n* Materials sometimes not correctly baked when using ENABLE_MESH_RENDERER_SUBMESH_DATA_SHARING" + "changelog": "### Changed\n\n* fixed the issue with LOD objects being culled when the camera is static\n\n### Fixed\n\n* Entities Graphics should now never run out of space in the NewChunks buffer.\n* A null reference exception thrown in some cases when using MeshRenderers with missing materials and/or meshes" }, "upmCi": { - "footprint": "22f7abd51ca2ffd95a065b596f1181dfa8a4bb35" + "footprint": "8c29b61b26490f1fa6cbfbe876e7bbde992f6711" }, "documentationUrl": "https://docs.unity3d.com/Packages/com.unity.entities.graphics@1.2/manual/index.html", "repository": { "url": "https://github.cds.internal.unity3d.com/unity/dots.git", "type": "git", - "revision": "1ae43e0525b8a09c7fe52ab40c762938a4937244" + "revision": "ea4236421d61011e37e71d22108c5e4e70cf71d7" } }