public GeneratedMeshKey(GeneratedMeshDescription meshDescription) { geometryHashValue = meshDescription.geometryHashValue; surfaceHashValue = meshDescription.surfaceHashValue; vertexCount = meshDescription.vertexCount; indexCount = meshDescription.indexCount; usedVertexChannels = meshDescription.meshQuery.UsedVertexChannels; }
public static int Calculate(GeneratedMeshDescription meshDescription) { var hashCode = -190551774; hashCode = hashCode * -1521134295 + (int)meshDescription.meshQuery.UsedVertexChannels; hashCode = hashCode * -1521134295 + (int)meshDescription.geometryHashValue; hashCode = hashCode * -1521134295 + (int)meshDescription.surfaceHashValue; hashCode = hashCode * -1521134295 + (int)meshDescription.vertexCount; hashCode = hashCode * -1521134295 + (int)meshDescription.indexCount; return(hashCode); }
private static GeneratedMeshDescription[] GetMeshDescriptions(Int32 treeNodeID, MeshQuery[] meshQueries, VertexChannelFlags vertexChannelMask) { if (meshQueries == null) { throw new ArgumentNullException("meshTypes"); } if (meshQueries.Length == 0) { return(null); } Int32 meshDescriptionCount; var nativeMeshTypeHandle = GCHandle.Alloc(meshQueries, GCHandleType.Pinned); var nativeMeshTypePtr = nativeMeshTypeHandle.AddrOfPinnedObject(); var result = GenerateMeshDescriptions(treeNodeID, meshQueries.Length, nativeMeshTypePtr, vertexChannelMask, out meshDescriptionCount); nativeMeshTypeHandle.Free(); if (!result || meshDescriptionCount == 0) { return(null); } var meshDescriptions = new GeneratedMeshDescription[meshDescriptionCount]; var meshDescriptionsHandle = GCHandle.Alloc(meshDescriptions, GCHandleType.Pinned); var meshDescriptionsPtr = meshDescriptionsHandle.AddrOfPinnedObject(); result = GetMeshDescriptions(treeNodeID, meshDescriptionCount, meshDescriptionsPtr); meshDescriptionsHandle.Free(); if (!result || meshDescriptions[0].vertexCount <= 0 || meshDescriptions[0].indexCount <= 0) { return(null); } return(meshDescriptions); }
/// <summary>Creates and returns a <see cref="Chisel.Core.GeneratedMeshContents"/> for a given <see cref="Chisel.Core.GeneratedMeshDescription"/> created by <see cref="Chisel.Core.CSGTree.GetMeshDescriptions"/></summary> /// <remarks>See the [Create Unity Meshes](~/documentation/createUnityMesh.md) article for more information.</remarks> /// <param name="meshDescription">A <see cref="Chisel.Core.GeneratedMeshDescription"/> created by <see cref="Chisel.Core.CSGTree.GetMeshDescriptions"/>.</param> /// <param name="previousGeneratedMeshContents">The previously generated <see cref="Chisel.Core.GeneratedMeshContents"/>, this can reuse allocated memory if the mesh hasn't changed shape. (optional)</param> /// <returns>A <see cref="Chisel.Core.GeneratedMeshContents"/> that can be used to initialize a [UnityEngine.Mesh](https://docs.unity3d.com/ScriptReference/Mesh.html) with.</returns> /// <seealso cref="Chisel.Core.CSGTree.GetMeshDescriptions"/> public GeneratedMeshContents GetGeneratedMesh(GeneratedMeshDescription meshDescription, GeneratedMeshContents previousGeneratedMeshContents = null) { return(GetGeneratedMesh(treeNodeID, meshDescription, previousGeneratedMeshContents)); }
internal static GeneratedMeshDescription[] GetMeshDescriptions(Int32 treeNodeID, MeshQuery[] meshQueries, VertexChannelFlags vertexChannelMask) { if (!AssertNodeIDValid(treeNodeID) || !AssertNodeType(treeNodeID, CSGNodeType.Tree)) { return(null); } if (meshQueries == null) { throw new ArgumentNullException("meshTypes"); } if (meshQueries.Length == 0) { Debug.Log("meshQueries.Length == 0"); return(null); } if (!IsValidNodeID(treeNodeID)) { Debug.LogError("GenerateMeshDescriptions: Invalid node index used"); return(null); } var treeNodeIndex = treeNodeID - 1; var treeInfo = nodeHierarchies[treeNodeIndex].treeInfo; if (treeInfo == null) { Debug.LogError("GenerateMeshDescriptions: Invalid node index used"); return(null); } treeInfo.subMeshCounts.Clear(); treeInfo.meshDescriptions.Clear(); if (nodeFlags[treeNodeIndex].IsNodeFlagSet(NodeStatusFlags.TreeNeedsUpdate)) { UnityEngine.Profiling.Profiler.BeginSample("UpdateTreeMesh"); try { var handle = UpdateTreeMeshes(new int[] { treeNodeID }); handle.Complete(); } finally { UnityEngine.Profiling.Profiler.EndSample(); } } UnityEngine.Profiling.Profiler.BeginSample("CombineSubMeshes"); try { CombineSubMeshes(treeInfo, meshQueries, vertexChannelMask); } finally { UnityEngine.Profiling.Profiler.EndSample(); } { var flags = nodeFlags[treeNodeIndex]; flags.UnSetNodeFlag(NodeStatusFlags.TreeMeshNeedsUpdate); nodeFlags[treeNodeIndex] = flags; } if (treeInfo.subMeshCounts.Count <= 0) { return(null); } for (int i = (int)treeInfo.subMeshCounts.Count - 1; i >= 0; i--) { var subMesh = treeInfo.subMeshCounts[i]; // Make sure the meshDescription actually holds a mesh if (subMesh.vertexCount == 0 || subMesh.indexCount == 0) { continue; } // Make sure the mesh is valid if (subMesh.vertexCount >= kMaxVertexCount) { Debug.LogError("Mesh has too many vertices (" + subMesh.vertexCount + " > " + kMaxVertexCount + ")"); continue; } var description = new GeneratedMeshDescription { meshQuery = subMesh.meshQuery, surfaceParameter = subMesh.surfaceIdentifier, meshQueryIndex = subMesh.meshIndex, subMeshQueryIndex = subMesh.subMeshIndex, geometryHashValue = subMesh.geometryHash, surfaceHashValue = subMesh.surfaceHash, vertexCount = subMesh.vertexCount, indexCount = subMesh.indexCount }; treeInfo.meshDescriptions.Add(description); } if (treeInfo.meshDescriptions == null || treeInfo.meshDescriptions.Count == 0 || treeInfo.meshDescriptions[0].vertexCount <= 0 || treeInfo.meshDescriptions[0].indexCount <= 0) { return(null); } return(treeInfo.meshDescriptions.ToArray()); }
internal static GeneratedMeshContents GetGeneratedMesh(int treeNodeID, GeneratedMeshDescription meshDescription) { if (!AssertNodeIDValid(treeNodeID) || !AssertNodeType(treeNodeID, CSGNodeType.Tree)) { return(null); } if (meshDescription.vertexCount <= 3 || meshDescription.indexCount <= 3) { Debug.LogWarning(string.Format("{0} called with a {1} that isn't valid", typeof(CSGTree).Name, typeof(GeneratedMeshDescription).Name)); return(null); } var meshIndex = meshDescription.meshQueryIndex; var subMeshIndex = meshDescription.subMeshQueryIndex; if (meshIndex < 0) { Debug.LogError("GetGeneratedMesh: MeshIndex cannot be negative"); return(null); } if (subMeshIndex < 0) { Debug.LogError("GetGeneratedMesh: SubMeshIndex cannot be negative"); return(null); } if (nodeHierarchies[treeNodeID - 1].treeInfo == null) { Debug.LogWarning("Tree has not been initialized properly"); return(null); } TreeInfo tree = nodeHierarchies[treeNodeID - 1].treeInfo; if (tree == null) { Debug.LogError("GetGeneratedMesh: Invalid node index used"); return(null); } if (tree.subMeshCounts == null) { Debug.LogWarning("Tree has not been initialized properly"); return(null); } int subMeshCountSize = (int)tree.subMeshCounts.Count; if (subMeshIndex >= (int)subMeshCountSize) { Debug.LogError("GetGeneratedMesh: SubMeshIndex is higher than the number of generated meshes"); return(null); } if (meshIndex >= (int)subMeshCountSize) { Debug.LogError("GetGeneratedMesh: MeshIndex is higher than the number of generated meshes"); return(null); } int foundIndex = -1; for (int i = 0; i < subMeshCountSize; i++) { if (meshIndex == tree.subMeshCounts[i].meshIndex && subMeshIndex == tree.subMeshCounts[i].subMeshIndex) { foundIndex = i; break; } } if (foundIndex < 0 || foundIndex >= subMeshCountSize) { Debug.LogError("GetGeneratedMesh: Could not find mesh associated with MeshIndex/SubMeshIndex pair"); return(null); } var subMeshCount = tree.subMeshCounts[foundIndex]; if (subMeshCount.indexCount > meshDescription.indexCount) { Debug.LogError("GetGeneratedMesh: The destination indices array (" + meshDescription.indexCount + ") is smaller than the size of the source data (" + (int)subMeshCount.indexCount + ")"); return(null); } if (subMeshCount.vertexCount > meshDescription.vertexCount) { Debug.LogError("GetGeneratedMesh: The destination vertices array (" + meshDescription.vertexCount + ") is smaller than the size of the source data (" + (int)subMeshCount.vertexCount + ")"); return(null); } if (subMeshCount.indexCount == 0 || subMeshCount.vertexCount == 0) { Debug.LogWarning("GetGeneratedMesh: Mesh is empty"); return(null); } var generatedMesh = new GeneratedMeshContents(); var usedVertexChannels = meshDescription.meshQuery.UsedVertexChannels; var vertexCount = meshDescription.vertexCount; var indexCount = meshDescription.indexCount; generatedMesh.description = meshDescription; // create our arrays on the managed side with the correct size bool useTangents = ((usedVertexChannels & VertexChannelFlags.Tangent) == VertexChannelFlags.Tangent); bool useNormals = ((usedVertexChannels & VertexChannelFlags.Normal) == VertexChannelFlags.Normal); bool useUV0 = ((usedVertexChannels & VertexChannelFlags.UV0) == VertexChannelFlags.UV0); generatedMesh.tangents = useTangents ? new NativeArray <float4>(vertexCount, Allocator.Persistent) : default; generatedMesh.normals = useNormals ? new NativeArray <float3>(vertexCount, Allocator.Persistent) : default; generatedMesh.uv0 = useUV0 ? new NativeArray <float2>(vertexCount, Allocator.Persistent) : default; generatedMesh.positions = new NativeArray <float3>(vertexCount, Allocator.Persistent); generatedMesh.indices = new NativeArray <int> (indexCount, Allocator.Persistent); generatedMesh.brushIndices = new NativeArray <int> (indexCount / 3, Allocator.Persistent); generatedMesh.bounds = new Bounds(); var submeshVertexCount = subMeshCount.vertexCount; var submeshIndexCount = subMeshCount.indexCount; if (subMeshCount.surfaces == null || submeshVertexCount != generatedMesh.positions.Length || submeshIndexCount != generatedMesh.indices.Length || generatedMesh.indices == null || generatedMesh.positions == null) { return(null); } var submeshSurfaces = new NativeArray <SubMeshSurface>(subMeshCount.surfaces.Count, Allocator.TempJob); for (int n = 0; n < subMeshCount.surfaces.Count; n++) { submeshSurfaces[n] = subMeshCount.surfaces[n]; } var generateVertexBuffersJob = new GenerateVertexBuffersJob { meshQuery = subMeshCount.meshQuery, surfaceIdentifier = subMeshCount.surfaceIdentifier, submeshIndexCount = subMeshCount.indexCount, submeshVertexCount = subMeshCount.vertexCount, submeshSurfaces = submeshSurfaces, generatedMeshIndices = generatedMesh.indices, generatedMeshBrushIndices = generatedMesh.brushIndices, generatedMeshPositions = generatedMesh.positions, generatedMeshTangents = generatedMesh.tangents, generatedMeshNormals = generatedMesh.normals, generatedMeshUV0 = generatedMesh.uv0 }; generateVertexBuffersJob.Run(); generateVertexBuffersJob.submeshSurfaces.Dispose(); generateVertexBuffersJob.submeshSurfaces = default; var min = new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); var max = new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); for (int i = 0, count = subMeshCount.indexCount; i < count; i++) { var position = generatedMesh.positions[generatedMesh.indices[i]]; min.x = Mathf.Min(min.x, position.x); min.y = Mathf.Min(min.y, position.y); min.z = Mathf.Min(min.z, position.z); max.x = Mathf.Max(max.x, position.x); max.y = Mathf.Max(max.y, position.y); max.z = Mathf.Max(max.z, position.z); } var boundsCenter = (max + min) * 0.5f; var boundsSize = (max - min); if (float.IsInfinity(boundsSize.x) || float.IsInfinity(boundsSize.y) || float.IsInfinity(boundsSize.z) || float.IsNaN(boundsSize.x) || float.IsNaN(boundsSize.y) || float.IsNaN(boundsSize.z)) { return(null); } generatedMesh.bounds = new Bounds(boundsCenter, boundsSize); return(generatedMesh); }
private static GeneratedMeshContents GetGeneratedMesh(int treeNodeID, GeneratedMeshDescription meshDescription, GeneratedMeshContents previousGeneratedMeshContents) { return(CSGManager.GetGeneratedMesh(treeNodeID, meshDescription, previousGeneratedMeshContents)); }
/// <summary>Creates and returns a <see cref="Chisel.Core.GeneratedMeshContents"/> for a given <see cref="Chisel.Core.GeneratedMeshDescription"/> created by <see cref="Chisel.Core.CSGTree.GetMeshDescriptions"/></summary> /// <remarks>See the [Create Unity Meshes](~/documentation/createUnityMesh.md) article for more information.</remarks> /// <param name="meshDescription">A <see cref="Chisel.Core.GeneratedMeshDescription"/> created by <see cref="Chisel.Core.CSGTree.GetMeshDescriptions"/>.</param> /// <param name="previousGeneratedMeshContents">The previously generated <see cref="Chisel.Core.GeneratedMeshContents"/>, this can reuse allocated memory if the mesh hasn't changed shape. (optional)</param> /// <returns>A <see cref="Chisel.Core.GeneratedMeshContents"/> that can be used to initialize a [UnityEngine.Mesh](https://docs.unity3d.com/ScriptReference/Mesh.html) with.</returns> /// <seealso cref="Chisel.Core.CSGTree.GetMeshDescriptions"/> public GeneratedMeshContents GetGeneratedMesh(GeneratedMeshDescription meshDescription) { return(GetGeneratedMesh(treeNodeID, meshDescription)); }
internal static GeneratedMeshContents GetGeneratedMesh(int treeNodeID, GeneratedMeshDescription meshDescription, GeneratedMeshContents previousGeneratedMeshContents) { if (!AssertNodeIDValid(treeNodeID) || !AssertNodeType(treeNodeID, CSGNodeType.Tree)) { return(null); } if (meshDescription.vertexCount <= 0 || meshDescription.indexCount <= 0) { Debug.LogWarning(string.Format("{0} called with a {1} that isn't valid", typeof(CSGTree).Name, typeof(GeneratedMeshDescription).Name)); return(null); } var meshIndex = meshDescription.meshQueryIndex; var subMeshIndex = meshDescription.subMeshQueryIndex; if (meshIndex < 0) { Debug.LogError("GetGeneratedMesh: MeshIndex cannot be negative"); return(null); } if (subMeshIndex < 0) { Debug.LogError("GetGeneratedMesh: SubMeshIndex cannot be negative"); return(null); } if (nodeHierarchies[treeNodeID - 1].treeInfo == null) { Debug.LogWarning("Tree has not been initialized properly"); return(null); } TreeInfo tree = nodeHierarchies[treeNodeID - 1].treeInfo; if (tree == null) { Debug.LogError("GetGeneratedMesh: Invalid node index used"); return(null); } if (tree.subMeshCounts == null) { Debug.LogWarning("Tree has not been initialized properly"); return(null); } int subMeshCountSize = (int)tree.subMeshCounts.Count; if (subMeshIndex >= (int)subMeshCountSize) { Debug.LogError("GetGeneratedMesh: SubMeshIndex is higher than the number of generated meshes"); return(null); } if (meshIndex >= (int)subMeshCountSize) { Debug.LogError("GetGeneratedMesh: MeshIndex is higher than the number of generated meshes"); return(null); } int foundIndex = -1; for (int i = 0; i < subMeshCountSize; i++) { if (meshIndex == tree.subMeshCounts[i].meshIndex && subMeshIndex == tree.subMeshCounts[i].subMeshIndex) { foundIndex = i; break; } } if (foundIndex < 0 || foundIndex >= subMeshCountSize) { Debug.LogError("GetGeneratedMesh: Could not find mesh associated with MeshIndex/SubMeshIndex pair"); return(null); } var subMeshCount = tree.subMeshCounts[foundIndex]; if (subMeshCount.indexCount > meshDescription.indexCount) { Debug.LogError("GetGeneratedMesh: The destination indices array (" + meshDescription.indexCount + ") is smaller than the size of the source data (" + (int)subMeshCount.indexCount + ")"); return(null); } if (subMeshCount.vertexCount > meshDescription.vertexCount) { Debug.LogError("GetGeneratedMesh: The destination vertices array (" + meshDescription.vertexCount + ") is smaller than the size of the source data (" + (int)subMeshCount.vertexCount + ")"); return(null); } if (subMeshCount.indexCount == 0 || subMeshCount.vertexCount == 0) { Debug.LogWarning("GetGeneratedMesh: Mesh is empty"); return(null); } var generatedMesh = (previousGeneratedMeshContents != null) ? previousGeneratedMeshContents : new GeneratedMeshContents(); var usedVertexChannels = meshDescription.meshQuery.UsedVertexChannels; var vertexCount = meshDescription.vertexCount; var indexCount = meshDescription.indexCount; generatedMesh.description = meshDescription; // create our arrays on the managed side with the correct size generatedMesh.tangents = ((usedVertexChannels & VertexChannelFlags.Tangent) == 0) ? null : (generatedMesh.tangents != null && generatedMesh.tangents.Length == vertexCount) ? generatedMesh.tangents : new Vector4[vertexCount]; generatedMesh.normals = ((usedVertexChannels & VertexChannelFlags.Normal) == 0) ? null : (generatedMesh.normals != null && generatedMesh.normals.Length == vertexCount) ? generatedMesh.normals : new Vector3[vertexCount]; generatedMesh.uv0 = ((usedVertexChannels & VertexChannelFlags.UV0) == 0) ? null : (generatedMesh.uv0 != null && generatedMesh.uv0.Length == vertexCount) ? generatedMesh.uv0 : new Vector2[vertexCount]; generatedMesh.positions = (generatedMesh.positions != null && generatedMesh.positions.Length == vertexCount) ? generatedMesh.positions : new Vector3[vertexCount]; generatedMesh.indices = (generatedMesh.indices != null && generatedMesh.indices.Length == indexCount) ? generatedMesh.indices : new int [indexCount]; generatedMesh.bounds = new Bounds(); bool result = CSGManager.GenerateVertexBuffers(subMeshCount, generatedMesh); if (!result) { return(null); } var min = new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); var max = new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); for (int i = 0, count = subMeshCount.indexCount; i < count; i++) { var position = generatedMesh.positions[generatedMesh.indices[i]]; min.x = Mathf.Min(min.x, position.x); min.y = Mathf.Min(min.y, position.y); min.z = Mathf.Min(min.z, position.z); max.x = Mathf.Max(max.x, position.x); max.y = Mathf.Max(max.y, position.y); max.z = Mathf.Max(max.z, position.z); } var boundsCenter = (max + min) * 0.5f; var boundsSize = (max - min); if (float.IsInfinity(boundsSize.x) || float.IsInfinity(boundsSize.y) || float.IsInfinity(boundsSize.z) || float.IsNaN(boundsSize.x) || float.IsNaN(boundsSize.y) || float.IsNaN(boundsSize.z)) { return(null); } generatedMesh.bounds = new Bounds(boundsCenter, boundsSize); return(generatedMesh); }
private static GeneratedMeshContents GetGeneratedMesh(int treeNodeID, GeneratedMeshDescription meshDescription, GeneratedMeshContents previousGeneratedMeshContents) { if (meshDescription.vertexCount <= 0 || meshDescription.indexCount <= 0) { Debug.LogWarning(string.Format("{0} called with a {1} that isn't valid", typeof(CSGTree).Name, typeof(GeneratedMeshDescription).Name)); return(null); } var generatedMesh = (previousGeneratedMeshContents != null) ? previousGeneratedMeshContents : new GeneratedMeshContents(); var usedVertexChannels = meshDescription.meshQuery.UsedVertexChannels; var vertexCount = meshDescription.vertexCount; var indexCount = meshDescription.indexCount; var meshIndex = meshDescription.meshQueryIndex; var subMeshIndex = meshDescription.subMeshQueryIndex; generatedMesh.description = meshDescription; // create our arrays on the managed side with the correct size generatedMesh.tangents = ((usedVertexChannels & VertexChannelFlags.Tangent) == 0) ? null : (generatedMesh.tangents != null && generatedMesh.tangents.Length == vertexCount) ? generatedMesh.tangents : new Vector4[vertexCount]; generatedMesh.normals = ((usedVertexChannels & VertexChannelFlags.Normal) == 0) ? null : (generatedMesh.normals != null && generatedMesh.normals.Length == vertexCount) ? generatedMesh.normals : new Vector3[vertexCount]; generatedMesh.uv0 = ((usedVertexChannels & VertexChannelFlags.UV0) == 0) ? null : (generatedMesh.uv0 != null && generatedMesh.uv0.Length == vertexCount) ? generatedMesh.uv0 : new Vector2[vertexCount]; generatedMesh.positions = (generatedMesh.positions != null && generatedMesh.positions.Length == vertexCount) ? generatedMesh.positions : new Vector3[vertexCount]; generatedMesh.indices = (generatedMesh.indices != null && generatedMesh.indices.Length == indexCount) ? generatedMesh.indices : new int [indexCount]; var indicesHandle = GCHandle.Alloc(generatedMesh.indices, GCHandleType.Pinned); var positionHandle = GCHandle.Alloc(generatedMesh.positions, GCHandleType.Pinned); var tangentHandle = new GCHandle(); var normalHandle = new GCHandle(); var uv0Handle = new GCHandle(); var indicesPtr = indicesHandle.AddrOfPinnedObject(); var positionPtr = positionHandle.AddrOfPinnedObject(); var tangentPtr = IntPtr.Zero; var normalPtr = IntPtr.Zero; var uv0Ptr = IntPtr.Zero; if (generatedMesh.tangents != null) { tangentHandle = GCHandle.Alloc(generatedMesh.tangents, GCHandleType.Pinned); tangentPtr = tangentHandle.AddrOfPinnedObject(); } if (generatedMesh.normals != null) { normalHandle = GCHandle.Alloc(generatedMesh.normals, GCHandleType.Pinned); normalPtr = normalHandle.AddrOfPinnedObject(); } if (generatedMesh.uv0 != null) { uv0Handle = GCHandle.Alloc(generatedMesh.uv0, GCHandleType.Pinned); uv0Ptr = uv0Handle.AddrOfPinnedObject(); } var boundsCenter = Vector3.zero; var boundsSize = Vector3.zero; var result = GetGeneratedMesh((Int32)treeNodeID, (Int32)meshIndex, (Int32)subMeshIndex, (Int32)indexCount, indicesPtr, (Int32)vertexCount, positionPtr, tangentPtr, normalPtr, uv0Ptr, out boundsCenter, out boundsSize); if (generatedMesh.uv0 != null) { uv0Handle.Free(); } if (generatedMesh.normals != null) { normalHandle.Free(); } if (generatedMesh.tangents != null) { tangentHandle.Free(); } positionHandle.Free(); indicesHandle.Free(); if (!result || float.IsInfinity(boundsSize.x) || float.IsInfinity(boundsSize.y) || float.IsInfinity(boundsSize.z) || float.IsNaN(boundsSize.x) || float.IsNaN(boundsSize.y) || float.IsNaN(boundsSize.z)) { return(null); } generatedMesh.bounds = new Bounds(boundsCenter, boundsSize); return(generatedMesh); }