internal static void CombineSubMeshes(TreeInfo treeInfo, MeshQuery[] meshQueries, VertexChannelFlags vertexChannelMask) { var subMeshCounts = treeInfo.subMeshCounts; subMeshCounts.Clear(); var treeBrushNodeIDs = treeInfo.treeBrushes; var treeBrushNodeCount = (Int32)(treeBrushNodeIDs.Count); if (treeBrushNodeCount <= 0) { return; } uniqueMeshDescriptions.Clear(); for (int b = 0, count_b = treeBrushNodeCount; b < count_b; b++) { var brushNodeID = treeBrushNodeIDs[b]; if (!CSGManager.IsValidNodeID(brushNodeID)) { continue; } var brushNodeIndex = brushNodeID - 1; var nodeType = nodeFlags[brushNodeIndex].nodeType; if (nodeType != CSGNodeType.Brush) { continue; } var brushInfo = nodeHierarchies[brushNodeIndex].brushInfo; if (brushInfo == null) { continue; } var treeNodeID = nodeHierarchies[brushNodeIndex].treeNodeID; var chiselLookupValues = ChiselTreeLookup.Value[treeNodeID - 1]; if (!chiselLookupValues.brushRenderBuffers.TryGetValue(brushNodeIndex, out var brushRenderBuffer) || !brushRenderBuffer.IsCreated) { continue; } ref var brushRenderBufferRef = ref brushRenderBuffer.Value; ref var surfaces = ref brushRenderBufferRef.surfaces;
private static GeneratedMeshDescription[] GetMeshDescriptions(Int32 treeNodeID, MeshQuery[] meshTypes, VertexChannelFlags vertexChannelMask) { if (meshTypes == null) { throw new ArgumentNullException("meshTypes"); } if (meshTypes.Length == 0) { return(null); } Int32 meshDescriptionCount; GCHandle nativeMeshTypeHandle = GCHandle.Alloc(meshTypes, GCHandleType.Pinned); IntPtr nativeMeshTypePtr = nativeMeshTypeHandle.AddrOfPinnedObject(); var result = GenerateMeshDescriptions(treeNodeID, meshTypes.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>Determines what meshes would be generated from the tree from the given <paramref name="meshQuery"/> and <paramref name="vertexChannelMask"/>.</summary> /// <remarks>See the [Create Unity Meshes](~/documentation/createUnityMesh.md) article for more information.</remarks> /// <param name="meshQuery">An array of <see cref="Chisel.Core.MeshQuery"/>'s which describe which surfaces should be combined into meshes</param> /// <param name="vertexChannelMask">A mask to prevent certain vertex channels to be generated. By default this value is to <see cref="Chisel.Core.VertexChannelFlags.All"/>.</param> /// <returns>An array of <see cref="Chisel.Core.GeneratedMeshDescription"/>'s that can be used to generate <see cref="Chisel.Core.GeneratedMeshContents"/> using <see cref="Chisel.Core.CSGTree.GetGeneratedMesh"/></returns> /// <seealso cref="Chisel.Core.CSGTree.GetGeneratedMesh"/> public GeneratedMeshDescription[] GetMeshDescriptions(MeshQuery[] meshQuery, VertexChannelFlags vertexChannelMask = VertexChannelFlags.All) { if (meshQuery == null) { throw new ArgumentNullException("meshQuery"); } return(GetMeshDescriptions(treeNodeID, meshQuery, vertexChannelMask)); }
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()); }
private static GeneratedMeshDescription[] GetMeshDescriptions(Int32 treeNodeID, MeshQuery[] meshQueries, VertexChannelFlags vertexChannelMask) { return(CSGManager.GetMeshDescriptions(treeNodeID, meshQueries, vertexChannelMask)); }
/// <summary>Constructs a <see cref="RealtimeCSG.Foundation.MeshQuery"/> to use to specify which surfaces should be combined into meshes, and should they be subdivided by a particular layer parameter index.</summary> /// <param name="query">Which layer combination would we like to look for and generate a mesh with.</param> /// <param name="mask">What layers do we ignore, and what layers do we include in our comparison. When this value is <see cref="RealtimeCSG.Foundation.LayerUsageFlags.None"/>, <paramref name="mask"/> is set to be equal to <paramref name="query"/>.</param> /// <param name="parameterIndex">Which parameter index we use to, for example, differentiate between different [UnityEngine.Material](https://docs.unity3d.com/ScriptReference/Material.html)s</param> /// <param name="vertexChannels">Which vertex channels need to be used for the meshes we'd like to generate.</param> /// <seealso cref="RealtimeCSG.Foundation.SurfaceLayers" /> public MeshQuery(LayerUsageFlags query, LayerUsageFlags mask = LayerUsageFlags.None, LayerParameterIndex parameterIndex = LayerParameterIndex.None, VertexChannelFlags vertexChannels = VertexChannelFlags.Position) { if (mask == LayerUsageFlags.None) { mask = query; } this.layers = ((uint)query & ~BitMask) | ((uint)parameterIndex << BitShift); this.maskAndChannels = ((uint)mask & ~BitMask) | ((uint)vertexChannels << BitShift); }
internal static void CombineSubMeshes(TreeInfo treeInfo, MeshQuery[] meshQueries, VertexChannelFlags vertexChannelMask) { var subMeshCounts = treeInfo.subMeshCounts; subMeshCounts.Clear(); var treeBrushNodeIDs = treeInfo.treeBrushes; var treeBrushNodeCount = (Int32)(treeBrushNodeIDs.Count); if (treeBrushNodeCount <= 0) { return; } var uniqueMeshDescriptions = new Dictionary <MeshID, int>(); for (Int32 b = 0, count_b = treeBrushNodeCount; b < count_b; b++) { var nodeID = treeBrushNodeIDs[b]; var nodeIndex = nodeID - 1; var nodeType = nodeFlags[nodeIndex].nodeType; if (nodeType != CSGNodeType.Brush) { continue; } var brushOutput = nodeHierarchies[nodeIndex].brushOutput; //var operation_type_bits = GetNodeOperationByIndex(nodeIndex); if (brushOutput == null //|| //brush.triangleMesh == null //|| //((int)operation_type_bits & InfiniteBrushBits) == InfiniteBrushBits ) { continue; } var renderBuffers = brushOutput.renderBuffers; if (renderBuffers.surfaceRenderBuffers.Count == 0) { continue; } var surfaceRenderBuffers = renderBuffers.surfaceRenderBuffers; for (int j = 0, count_j = (int)renderBuffers.surfaceRenderBuffers.Count; j < count_j; j++) { var brushSurfaceBuffer = surfaceRenderBuffers[j]; var surfaceVertexCount = (brushSurfaceBuffer.vertices == null) ? 0 : brushSurfaceBuffer.vertices.Length; var surfaceIndexCount = (brushSurfaceBuffer.indices == null) ? 0 : brushSurfaceBuffer.indices.Length; if (surfaceVertexCount <= 0 || surfaceIndexCount <= 0) { continue; } var surfaceParameter = (brushSurfaceBuffer.meshQuery.LayerParameterIndex == LayerParameterIndex.None) ? 0 : brushSurfaceBuffer.surfaceParameter; var meshID = new MeshID() { meshQuery = brushSurfaceBuffer.meshQuery, surfaceParameter = surfaceParameter }; int generatedMeshIndex; if (!uniqueMeshDescriptions.TryGetValue(meshID, out generatedMeshIndex)) { generatedMeshIndex = -1; } if (generatedMeshIndex == -1 || (subMeshCounts[generatedMeshIndex].vertexCount + surfaceVertexCount) >= kMaxVertexCount) { int meshIndex, subMeshIndex; if (generatedMeshIndex != -1) { generatedMeshIndex = (int)subMeshCounts.Count; var prevMeshCountIndex = generatedMeshIndex; subMeshIndex = subMeshCounts[prevMeshCountIndex].subMeshIndex + 1; meshIndex = subMeshCounts[prevMeshCountIndex].meshIndex; } else { generatedMeshIndex = (int)subMeshCounts.Count; meshIndex = generatedMeshIndex; subMeshIndex = 0; } uniqueMeshDescriptions[meshID] = generatedMeshIndex; SubMeshCounts newSubMesh = new SubMeshCounts(); newSubMesh.meshIndex = meshIndex; newSubMesh.subMeshIndex = subMeshIndex; newSubMesh.meshQuery = meshID.meshQuery; newSubMesh.surfaceIdentifier = surfaceParameter; newSubMesh.indexCount = surfaceIndexCount; newSubMesh.vertexCount = surfaceVertexCount; newSubMesh.surfaceHash = brushSurfaceBuffer.surfaceHash; newSubMesh.geometryHash = brushSurfaceBuffer.geometryHash; newSubMesh.surfaces.Add(brushSurfaceBuffer); subMeshCounts.Add(newSubMesh); continue; } var currentSubMesh = subMeshCounts[generatedMeshIndex]; currentSubMesh.indexCount += surfaceIndexCount; currentSubMesh.vertexCount += surfaceVertexCount; currentSubMesh.surfaceHash = Hashing.XXH64_mergeRound(currentSubMesh.surfaceHash, brushSurfaceBuffer.surfaceHash); currentSubMesh.geometryHash = Hashing.XXH64_mergeRound(currentSubMesh.geometryHash, brushSurfaceBuffer.geometryHash); currentSubMesh.surfaces.Add(brushSurfaceBuffer); } } for (int i = (int)subMeshCounts.Count - 1; i >= 0; i--) { if (subMeshCounts[i].vertexCount != 0 && subMeshCounts[i].indexCount != 0) { continue; } subMeshCounts.RemoveAt(i); } }
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) { 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)) { UpdateTreeMesh(treeNodeID); } CombineSubMeshes(treeInfo, meshQueries, vertexChannelMask); if (treeInfo.subMeshCounts.Count <= 0) { nodeFlags[treeNodeIndex].UnSetNodeFlag(NodeStatusFlags.TreeMeshNeedsUpdate); // Debug.LogWarning("GetMeshDescriptions: No meshes found"); return(null); } if (treeInfo.meshDescriptions == null || treeInfo.meshDescriptions.Count == 0 || treeInfo.meshDescriptions[0].vertexCount <= 0 || treeInfo.meshDescriptions[0].indexCount <= 0) { return(null); } nodeFlags[treeNodeIndex].UnSetNodeFlag(NodeStatusFlags.TreeMeshNeedsUpdate); return(treeInfo.meshDescriptions.ToArray()); }
private static extern bool GenerateMeshDescriptions(Int32 treeNodeID, Int32 meshTypeCount, [In] IntPtr meshTypes, VertexChannelFlags vertexChannelMask, [Out] out Int32 meshDescriptionCount);