public static void CopyFromPositionOnly(this UnityEngine.Mesh mesh, GeneratedMeshContents contents) { if (object.ReferenceEquals(contents, null)) { throw new ArgumentNullException("contents"); } if (contents.description.vertexCount < 3 || contents.description.indexCount < 3) { mesh.Clear(); return; } mesh.SetVertices(contents.positions); mesh.SetTriangles(contents.indices.ToArray(), 0, false); mesh.bounds = contents.bounds; }
/// <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 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)); }
static bool GenerateVertexBuffers(SubMeshCounts subMeshCount, GeneratedMeshContents generatedMesh) { var submeshVertexCount = subMeshCount.vertexCount; var submeshIndexCount = subMeshCount.indexCount; var subMeshSurfaces = subMeshCount.surfaces; if (subMeshSurfaces == null || submeshVertexCount != generatedMesh.positions.Length || submeshIndexCount != generatedMesh.indices.Length || generatedMesh.indices == null || generatedMesh.positions == null) { return(false); } bool needTangents = generatedMesh.tangents != null && (((Int32)subMeshCount.meshQuery.UsedVertexChannels & (Int32)VertexChannelFlags.Tangent) != 0); bool needNormals = generatedMesh.normals != null && (((Int32)subMeshCount.meshQuery.UsedVertexChannels & (Int32)VertexChannelFlags.Normal) != 0); bool needUV0s = generatedMesh.uv0 != null && (((Int32)subMeshCount.meshQuery.UsedVertexChannels & (Int32)VertexChannelFlags.UV0) != 0); bool needTempNormals = needTangents && !needNormals; bool needTempUV0 = needTangents && !needUV0s; var normals = !needTempNormals ? generatedMesh.normals : new Vector3[submeshVertexCount]; var uv0s = !needTempUV0 ? generatedMesh.uv0 : new Vector2[submeshVertexCount]; // double snap_size = 1.0 / ants.SnapDistance(); // copy all the vertices & indices to the sub-meshes for each material for (int surfaceIndex = 0, indexOffset = 0, vertexOffset = 0, surfaceCount = (int)subMeshSurfaces.Count; surfaceIndex < surfaceCount; ++surfaceIndex) { var sourceBuffer = subMeshSurfaces[surfaceIndex]; if (sourceBuffer.indices == null || sourceBuffer.vertices == null || sourceBuffer.indices.Length == 0 || sourceBuffer.vertices.Length == 0) { continue; } for (int i = 0, sourceIndexCount = sourceBuffer.indices.Length; i < sourceIndexCount; i++) { generatedMesh.indices[indexOffset] = (int)(sourceBuffer.indices[i] + vertexOffset); indexOffset++; } var sourceVertexCount = sourceBuffer.vertices.Length; Array.Copy(sourceBuffer.vertices, 0, generatedMesh.positions, vertexOffset, sourceVertexCount); if (needUV0s || needTangents) { Array.Copy(sourceBuffer.uv0, 0, uv0s, vertexOffset, sourceVertexCount); } if (needNormals || needTangents) { Array.Copy(sourceBuffer.normals, 0, normals, vertexOffset, sourceVertexCount); } vertexOffset += sourceVertexCount; } if (needTangents) { ComputeTangents(generatedMesh.indices, generatedMesh.positions, uv0s, normals, generatedMesh.tangents); } return(true); }
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); }