예제 #1
0
        private void InitAudioVisualizer()
        {
            totalTriangles        = (int)sampleMesh.GetIndexCount(0) / 3;
            audioProfile.bandSize = totalTriangles;

            audioProcessor = new AudioProcessor(ref audioSource, ref audioProfile);

            MeshUtil.DeepCopyMesh(ref sampleMesh, out modifiedSampleMesh);
            audioVFX.SetMesh(VFXPropertyId.mesh_sampleMesh, modifiedSampleMesh);
            audioVFX.SetInt(VFXPropertyId.int_triangleCount, totalTriangles);
            modifiedSampleMesh.MarkDynamic();
            meshFilter.mesh = modifiedSampleMesh;

            // transferring mesh data to native arrays to be processed parallely
            Mesh.MeshDataArray sampleMeshData = Mesh.AcquireReadOnlyMeshData(sampleMesh);
            normals = MeshUtil.NativeGetNormals(sampleMeshData[0], Allocator.Persistent);
            normals.AsReadOnly();

            triangles = MeshUtil.NativeGetIndices(sampleMeshData[0], Allocator.Persistent);
            triangles.AsReadOnly();

            vertices = MeshUtil.NativeGetVertices(sampleMeshData[0], Allocator.Persistent);

            // audio processing attributes
            samples          = new NativeArray <float>(audioProfile.sampleSize, Allocator.Persistent);
            bandDistribution = new NativeArray <int>(audioProfile.bandSize + 1, Allocator.Persistent);
            bandDistribution.CopyFrom(audioProcessor.bandDistribution);
            bandDistribution.AsReadOnly();

            prevBands = new NativeArray <float>(totalTriangles, Allocator.Persistent);
            prevBands.CopyFrom(prevBands);

            bandVelocities = new NativeArray <float>(totalTriangles, Allocator.Persistent);
            bandVelocities.CopyFrom(bandVelocities);

            sampleMeshData.Dispose();

            if (seed != 0)
            {
                // if randomized is turned on
                int[] seqArray = MathUtil.GenerateSeqArray(totalTriangles);
                MathUtil.ShuffleArray <int>(ref seqArray, seed);

                // triangle indices
                NativeArray <int> trianglesCopy = new NativeArray <int>(triangles, Allocator.Temp);

                for (int s = 0; s < seqArray.Length; s++)
                {
                    triangles[s * 3]     = trianglesCopy[seqArray[s] * 3];
                    triangles[s * 3 + 1] = trianglesCopy[seqArray[s] * 3 + 1];
                    triangles[s * 3 + 2] = trianglesCopy[seqArray[s] * 3 + 2];
                }

                trianglesCopy.Dispose();
            }
        }
예제 #2
0
        Initialize(Mesh sourceMesh, Transform transform)
        {
            using (var dataArray = Mesh.AcquireReadOnlyMeshData(sourceMesh))
            {
                var data = dataArray[0];

                // Vertex/index count
                var vtxCount = data.vertexCount;
                var idxCount = data.GetSubMesh(0).indexCount;

                // Triangle/voxel/fragment count
                var triCount = idxCount / 3;
                var vxlCount = (triCount + SourcePerVoxel - 1) / SourcePerVoxel;
                var frgCount = triCount - vxlCount;

                // Source index array
                Debug.Assert(data.indexFormat == IndexFormat.UInt32);
                var idx = data.GetIndexData <uint>();

                // Read buffers allocation
                using (var vtx = MemoryUtil.TempJobArray <float3>(vtxCount))
                    using (var uvs = MemoryUtil.TempJobArray <float2>(vtxCount))
                    {
                        // Retrieve vertex attribute arrays.
                        data.GetVertices(vtx.Reinterpret <Vector3>());
                        data.GetUVs(0, uvs.Reinterpret <Vector2>());

                        // Output buffer
                        var outVxl = MemoryUtil.Array <Element>(vxlCount);
                        var outFrg = MemoryUtil.Array <Element>(frgCount);

                        // Invoke and wait the initializer jobs.
                        var xform = transform.localToWorldMatrix;

                        new InitializationJob
                        {
                            Indices   = idx, Vertices = vtx, UVs = uvs,
                            Transform = xform, IsVoxel = true, Output = outVxl
                        }
                        .Schedule(vxlCount, 64).Complete();

                        new InitializationJob
                        {
                            Indices   = idx, Vertices = vtx, UVs = uvs,
                            Transform = xform, IsVoxel = false, Output = outFrg
                        }
                        .Schedule(frgCount, 64).Complete();

                        return(outVxl, outFrg);
                    }
            }
        }
예제 #3
0
        public void UpdateControlPoints()
        {
            count = controlPoints.Length;

            if (vertices == null || vertices.Length != _skinnedMeshRenderer.sharedMesh.vertexCount)
            {
                                #if UNITY_2020_1_OR_NEWER
                using (var dataArray = Mesh.AcquireReadOnlyMeshData(_skinnedMeshRenderer.sharedMesh)) {
                    var data = dataArray[0];

                    if (vertices != null && vertices.IsCreated)
                    {
                        vertices.Dispose();
                    }

                    vertices = new NativeArray <Vector3>(skinnedMeshRenderer.sharedMesh.vertexCount, Allocator.Persistent);

                    data.GetVertices(vertices);
                }
                                #else
                if (vertices != null && vertices.IsCreated)
                {
                    vertices.Dispose();
                }

                vertices = new NativeArray <Vector3>(skinnedMeshRenderer.sharedMesh.vertices, Allocator.Persistent);
                                #endif
            }

            updateControlPoints = false;

            for (c = 0; c < count; c++)
            {
                currentControlPoint = points.GetPoint(controlPoints[c]);

                if (vertices[c].x != currentControlPoint.x ||
                    vertices[c].y != currentControlPoint.y ||
                    vertices[c].z != currentControlPoint.z)
                {
                    updateControlPoints = true;

                    vertices[c] = currentControlPoint;
                }
            }

            if (updateControlPoints)
            {
                _skinnedMeshRenderer.sharedMesh.SetVertices(vertices);
            }
        }
예제 #4
0
        /// <summary>\copydoc WireMesh(Mesh)</summary>
        public void WireMesh(Mesh mesh, Color color)
        {
            PushColor(color);
#if UNITY_2020_1_OR_NEWER
            // Use a burst compiled function to draw the lines
            // This is significantly faster than pure C# (about 5x).
            var meshDataArray = Mesh.AcquireReadOnlyMeshData(mesh);
            var meshData      = meshDataArray[0];

            JobWireMesh.JobWireMeshFunctionPointer(ref meshData, ref this);
            meshDataArray.Dispose();
#else
            Debug.LogError("The WireMesh method is only suppored in Unity 2020.1 or later");
#endif
            PopColor();
        }
예제 #5
0
    // Start is called before the first frame update
    void Start()
    {
        var mesh = MeshFilter.mesh;

        using (var dataArray = Mesh.AcquireReadOnlyMeshData(mesh))
        {
            var data = dataArray[0];
            // prints "2"
            Debug.Log(data.vertexCount);
            var gotVertices = new NativeArray <Vector3>(mesh.vertexCount, Allocator.TempJob);
            data.GetVertices(gotVertices);
            // prints "(1.0, 1.0, 1.0)" and "(0.0, 0.0, 0.0)"
            foreach (var v in gotVertices)
            {
                Debug.Log(v);
            }
            gotVertices.Dispose();
        }
    }
예제 #6
0
        void OnValidate()
        {
            _pointCount = Mathf.Max(64, _pointCount);

            // We assume that someone changed the values/references in the
            // serialized fields, so let us dispose the internal objects to
            // re-initialize them with the new values/references. #BADCODE
            DisposeInternals();


            using (var dataArray = Mesh.AcquireReadOnlyMeshData(_sources[0].sharedMesh))
            {
                for (var i = 0; i < dataArray.Length; i++)
                {
                    var data = dataArray[i];
                    Debug.Log(string.Format("{0}: {1}", i, dataArray[i].vertexCount));
                }
            }
        }
예제 #7
0
        void OnEnable()
        {
            // Only skin up to 2 bones, more than this messes up the skinning.
            if (skinnedMeshRenderer != null)
            {
                skinnedMeshRenderer.quality = SkinQuality.Bone2;

                                #if UNITY_2020_1_OR_NEWER
                using (var dataArray = Mesh.AcquireReadOnlyMeshData(_skinnedMeshRenderer.sharedMesh)) {
                    var data = dataArray[0];

                    vertices = new NativeArray <Vector3>(_skinnedMeshRenderer.sharedMesh.vertexCount, Allocator.Persistent);

                    data.GetVertices(vertices);
                }
                                #else
                vertices = new NativeArray <Vector3>(_skinnedMeshRenderer.sharedMesh.vertices, Allocator.Persistent);
                                #endif
            }
        }
예제 #8
0
        Build(Mesh source, Transform transform, Transform effector)
        {
            using (var dataArray = Mesh.AcquireReadOnlyMeshData(source))
            {
                var data = dataArray[0];

                // Vertex/index count
                var vcount = data.vertexCount;
                var icount = data.GetSubMesh(0).indexCount;

                // Source index array
                Debug.Assert(data.indexFormat == IndexFormat.UInt32);
                var src_idx = data.GetIndexData <uint>();

                // Read buffer allocation
                using (var src_pos = MemoryUtil.TempJobArray <float3>(vcount))
                    using (var src_uv0 = MemoryUtil.TempJobArray <float2>(vcount))
                    {
                        // Retrieve vertex attribute arrays.
                        data.GetVertices(src_pos.Reinterpret <Vector3>());
                        data.GetUVs(0, src_uv0.Reinterpret <Vector2>());

                        // Output buffer
                        var out_vtx = MemoryUtil.TempJobArray <Vertex>(icount);

                        // Invoke and wait the array generator job.
                        new VertexArrayJob
                        {
                            Idx = src_idx, Pos = src_pos, UV0 = src_uv0,
                            Xfm = transform.localToWorldMatrix,
                            Eff = effector.worldToLocalMatrix,
                            Out = out_vtx.Reinterpret <Triangle>(Vertex.StructSize)
                        }
                        .Schedule(icount / 3, 64).Complete();

                        return(out_vtx);
                    }
            }
        }
예제 #9
0
        // This is for editing control points
        void OnSceneGUI()
        {
            if (Weightpainter.isPainting)
            {
                if (skin != null)
                {
                    skin.editingPoints = false;
                }

                return;
            }

            // If we have a skin and control points then update them
            if (skin != null && skinnedMeshRenderer != null && skinnedMesh != null &&
                skin.controlPoints != null && skin.controlPoints.Length > 0 && skin.points != null)
            {
                e = Event.current;

                EditorGUI.BeginChangeCheck();

                r        = HandleUtility.GUIPointToWorldRay(e.mousePosition);
                mousePos = r.origin;

                selectDistance = HandleUtility.GetHandleSize(mousePos) * baseSelectDistance;

                // Create the vertices here for the handle points
                if (!skin.editingPoints)
                {
                    bakeMesh = new Mesh();

                                        #if UNITY_2020_2_OR_NEWER
                    skinnedMeshRenderer.BakeMesh(bakeMesh, true);
                                        #else
                    skinnedMeshRenderer.BakeMesh(bakeMesh);
                                        #endif

                    skinnedMesh = skinnedMeshRenderer.sharedMesh;

                    // Always clear vertices before getting new ones

                                        #if UNITY_2020_1_OR_NEWER
                    using (var dataArray = Mesh.AcquireReadOnlyMeshData(bakeMesh)) {
                        var data = dataArray[0];

                        if (vertices == null || vertices != null && vertices.Length != bakeMesh.vertexCount)
                        {
                            if (vertices.IsCreated)
                            {
                                vertices.Dispose();
                            }

                            vertices = new NativeArray <Vector3>(bakeMesh.vertexCount, Allocator.Persistent);
                        }

                        data.GetVertices(vertices);
                    }
                                        #else
                    if (vertices != null && vertices.IsCreated)
                    {
                        vertices.Dispose();
                    }

                    vertices = new NativeArray <Vector3>(bakeMesh.vertices, Allocator.Persistent);
                                        #endif

                    boneMatrices = new Matrix4x4[skinnedMeshRenderer.bones.Length];
                    weights      = skinnedMesh.boneWeights;
                    bindposes    = skinnedMesh.bindposes;
                    bones        = skinnedMeshRenderer.bones;

                    // First apply the scale, then transform it to World Space
                    for (int i = 0; i < bakeMesh.vertexCount; i++)
                    {
                                                #if !UNITY_2020_2_OR_NEWER
                        vertices[i] = Vector3.Scale(bakeMesh.vertices[i], skinnedMeshRenderer.transform.lossyScale);
                                                #endif
                        vertices[i] = skinnedMeshRenderer.transform.TransformPoint(vertices[i]);
                    }

                    // Always clear vertices before getting new ones

                                        #if UNITY_2020_1_OR_NEWER
                    using (var dataArray = Mesh.AcquireReadOnlyMeshData(skinnedMesh)) {
                        var data = dataArray[0];

                        if (newVertices == null || newVertices != null && newVertices.Length != skinnedMesh.vertexCount)
                        {
                            if (newVertices.IsCreated)
                            {
                                newVertices.Dispose();
                            }

                            newVertices = new NativeArray <Vector3>(skinnedMesh.vertexCount, Allocator.Persistent);
                        }

                        data.GetVertices(newVertices);
                    }
                                        #else
                    if (newVertices != null && newVertices.IsCreated)
                    {
                        newVertices.Dispose();
                    }

                    newVertices = new NativeArray <Vector3>(skinnedMesh.vertices, Allocator.Persistent);
                                        #endif

                    // Debug.Log("Created new baked mesh.");
                }

                if (e.type == EventType.MouseDrag && e.button == 0 && e.isMouse)
                {
                    /*if (!skin.editingPoints) {
                     *      Debug.Log("Started editing points");
                     * }*/

                    skin.editingPoints = true;
                }
                else if (e.type == EventType.MouseUp || vertices.Length != skinnedMeshRenderer.sharedMesh.vertexCount)
                {
                    skin.editingPoints = false;

                    // Debug.Log("Stopped editing points");
                }

                #region Draw vertex handles
                Handles.color = handleColor;

                for (int i = 0; i < skin.controlPoints.Length; i++)
                {
                    if (Handles.Button(vertices[i], Quaternion.identity, selectDistance, selectDistance, Handles.CircleHandleCap))
                    {
                        selectedIndex = i;
                    }

                    if (selectedIndex == i)
                    {
                        EditorGUI.BeginChangeCheck();

                        // If we are editing points then the position handle drives the vertex
                        if (skin.editingPoints)
                        {
                            vertices[i] = Handles.PositionHandle(vertices[i], Quaternion.identity);

                            // Need to create matrices based on the skin's bones
                            for (int b = 0; b < boneMatrices.Length; b++)
                            {
                                if (bones[b] != null)
                                {
                                    boneMatrices[b] = bones[b].localToWorldMatrix * bindposes[b];
                                }
                            }

                            weight = weights[i];

                            vertexMatrix = new Matrix4x4();

                            // Since we are only using 2 bones for the Skin2D, only use the first 2 bones and weights
                            for (int n = 0; n < 16; n++)
                            {
                                vertexMatrix[n] =
                                    boneMatrices[weight.boneIndex0][n] * weight.weight0 +
                                    boneMatrices[weight.boneIndex1][n] * weight.weight1;
                            }

                            // DEBUG HERE TO CHECK FOR DISCREPANCIES //

                            /*Vector3 debugVert = vertexMatrix.MultiplyPoint(skinnedMesh.vertices[i]);
                             *
                             * Debug.Log("New Vertex: " + debugVert.x + ", " + debugVert.y + ", " + debugVert.z);
                             * Debug.Log("Original Vertex: " + vertices[i].x + ", " + vertices[i].y + ", " + vertices[i].z);
                             *
                             * Handles.DotHandleCap(
                             *      i,
                             *      debugVert,
                             *      Quaternion.identity,
                             *      selectDistance,
                             *      EventType.Repaint
                             *      );*/

                            // Invert the matrix to get the local space position of the vertex
                            newVert = vertexMatrix.inverse.MultiplyPoint(vertices[i]);

                            skin.controlPoints[i].position = newVert;
                            skin.points.SetPoint(skin.controlPoints[i]);

                            newVertices[i] = skin.points.GetPoint(skin.controlPoints[i]);

                            if (EditorGUI.EndChangeCheck())
                            {
                                Undo.RecordObject(skin, "Changed Control Point");
                                Undo.RecordObject(skin.points, "Changed Control Point");

                                EditorUtility.SetDirty(this);
                            }
                        }
                        else
                        {
                            currentControlPoint = skin.points.GetPoint(skin.controlPoints[i]);

                            // If we are not editing points then just use the world space offset for the position handle
                            offset = vertices[i] - skin.transform.TransformPoint(currentControlPoint);

                            vertices[i] = Handles.PositionHandle(skin.transform.TransformPoint(currentControlPoint) + offset, Quaternion.identity);

                            // Debug.Log("Not editing points.");
                        }
                    }
                }

                if (skin.editingPoints)
                {
                    skinnedMeshRenderer.sharedMesh.SetVertices(newVertices);

                    skin.UpdateControlPoints();

                    // Debug.Log("Set new vertices");
                }
                #endregion
            }
            else
            {
                skin.editingPoints = false;
            }
        }
예제 #10
0
        /// <summary>
        /// Applies Draco compression to a given mesh and returns the encoded result (one per submesh)
        /// The quantization paramters help to find a balance between encoded size and quality / precision.
        /// </summary>
        /// <param name="unityMesh">Input mesh</param>
        /// <param name="encodingSpeed">Encoding speed level. 0 means slow and small. 10 is fastest.</param>
        /// <param name="decodingSpeed">Decoding speed level. 0 means slow and small. 10 is fastest.</param>
        /// <param name="positionQuantization">Vertex position quantization</param>
        /// <param name="normalQuantization">Normal quantization</param>
        /// <param name="texCoordQuantization">Texture coordinate quantization</param>
        /// <param name="colorQuantization">Color quantization</param>
        /// <param name="genericQuantization">Generic quantization (e.g. blend weights and indices). unused at the moment</param>
        /// <returns></returns>
        public static unsafe EncodeResult[] EncodeMesh(
            Mesh unityMesh,
            int encodingSpeed        = 0,
            int decodingSpeed        = 4,
            int positionQuantization = 14,
            int normalQuantization   = 10,
            int texCoordQuantization = 12,
            int colorQuantization    = 8,
            int genericQuantization  = 12
            )
        {
#if UNITY_2020_1_OR_NEWER
            if (!unityMesh.isReadable)
            {
                Debug.LogError("Mesh is not readable");
                return(null);
            }

            var mesh             = unityMesh;
            var result           = new EncodeResult[mesh.subMeshCount];
            var vertexAttributes = mesh.GetVertexAttributes();

            var strides   = new int[DracoNative.maxStreamCount];
            var attrDatas = new Dictionary <VertexAttribute, AttributeData>();

            foreach (var attribute in vertexAttributes)
            {
                var attrData = new AttributeData {
                    offset = strides[attribute.stream], stream = attribute.stream
                };
                var size = attribute.dimension * GetAttributeSize(attribute.format);
                strides[attribute.stream]     += size;
                attrDatas[attribute.attribute] = attrData;
            }

            var streamCount = 1;
            for (var stream = 0; stream < strides.Length; stream++)
            {
                var stride = strides[stream];
                if (stride <= 0)
                {
                    continue;
                }
                streamCount = stream + 1;
            }

            var dataArray = Mesh.AcquireReadOnlyMeshData(mesh);
            var data      = dataArray[0];

            var vData    = new NativeArray <byte> [streamCount];
            var vDataPtr = new IntPtr[streamCount];
            for (var stream = 0; stream < streamCount; stream++)
            {
                vData[stream]    = data.GetVertexData <byte>(stream);
                vDataPtr[stream] = (IntPtr)vData[stream].GetUnsafeReadOnlyPtr();
            }

            for (int submeshIndex = 0; submeshIndex < mesh.subMeshCount; submeshIndex++)
            {
                var submesh = mesh.GetSubMesh(submeshIndex);

                if (submesh.topology != MeshTopology.Triangles)
                {
                    Debug.LogError("Only triangles are supported");
                    return(null);
                }
                var indices   = mesh.GetIndices(submeshIndex);
                var faceCount = indices.Length / 3;

                var dracoEncoder = dracoEncoderCreate(mesh.vertexCount);

                var attributeIds = new Dictionary <VertexAttribute, uint>();

                foreach (var pair in attrDatas)
                {
                    var attribute = pair.Key;
                    var attrData  = pair.Value;
                    var format    = mesh.GetVertexAttributeFormat(attribute);
                    var dimension = mesh.GetVertexAttributeDimension(attribute);
                    var stride    = strides[attrData.stream];
                    var baseAddr  = vDataPtr[attrData.stream] + attrData.offset;
                    attributeIds[attribute] = dracoEncoderSetAttribute(dracoEncoder, (int)GetAttributeType(attribute), GetDataType(format), dimension, stride, baseAddr);
                }

                var indicesData = (IntPtr)UnsafeUtility.PinGCArrayAndGetDataAddress(indices, out var gcHandle);
                dracoEncoderSetIndices(dracoEncoder, DataType.DT_UINT32, (uint)indices.Length, indicesData);
                UnsafeUtility.ReleaseGCObject(gcHandle);

                // For both encoding and decoding (0 = slow and best compression; 10 = fast)
                dracoEncoderSetCompressionSpeed(dracoEncoder, Mathf.Clamp(encodingSpeed, 0, 10), Mathf.Clamp(decodingSpeed, 0, 10));
                dracoEncoderSetQuantizationBits(
                    dracoEncoder,
                    Mathf.Clamp(positionQuantization, 4, 24),
                    Mathf.Clamp(normalQuantization, 4, 24),
                    Mathf.Clamp(texCoordQuantization, 4, 24),
                    Mathf.Clamp(colorQuantization, 4, 24),
                    Mathf.Clamp(genericQuantization, 4, 24)
                    );

                dracoEncoderEncode(dracoEncoder, false);

                var dracoDataSize = (int)dracoEncoderGetByteLength(dracoEncoder);

                var dracoData = new NativeArray <byte>(dracoDataSize, Allocator.Persistent);
                dracoEncoderCopy(dracoEncoder, dracoData.GetUnsafePtr());

                result[submeshIndex] = new EncodeResult {
                    indexCount  = dracoEncoderGetEncodedIndexCount(dracoEncoder),
                    vertexCount = dracoEncoderGetEncodedVertexCount(dracoEncoder),
                    data        = dracoData
                };

                dracoEncoderRelease(dracoEncoder);
            }

            for (var stream = 0; stream < streamCount; stream++)
            {
                vData[stream].Dispose();
            }
            dataArray.Dispose();

            return(result);
#else
            Debug.LogError("Draco Encoding only works on Unity 2020.1 or newer");
            return(null);
#endif
        }
예제 #11
0
        /// <summary>
        /// Attempts to copy the data of the current <see cref="Mesh"/> to another one, as fast as possible,
        /// with minimal allocations (a few tens of bytes in scenarios with very large meshes).
        /// </summary>
        public static void CopyTo(this Mesh inMesh, ref Mesh outMesh)
        {
            if (inMesh == null)
            {
                return;
            }

            if (outMesh == null)
            {
                outMesh = new Mesh();
            }
            else
            {
                outMesh.Clear();
            }

            outMesh.name   = inMesh.name;
            outMesh.bounds = inMesh.bounds;

            using (var readArray = Mesh.AcquireReadOnlyMeshData(inMesh))
            {
                //-------------------------------------------------------------
                // INPUT INFO
                //-------------------------------------------------------------
                var readData = readArray[0];

                // Formats
                var vertexFormat = inMesh.GetVertexAttributes();
                var indexFormat  = inMesh.indexFormat;
                var isIndexShort = indexFormat == IndexFormat.UInt16;

                // Counts
                var vertexCount = readData.vertexCount;
                var indexCount  =
                    isIndexShort ? readData.GetIndexData <ushort>().Length : readData.GetIndexData <uint>().Length;

                // Element Size in bytes
                var indexSize  = isIndexShort ? SHORT_SIZE : INT_SIZE;
                var vertexSize = 0;

                for (var i = 0; i < vertexFormat.Length; i++)
                {
                    // 4 bytes per component by default
                    var size = FLOAT_SIZE;

                    switch (vertexFormat[i].format)
                    {
                    case VertexAttributeFormat.Float16:
                    case VertexAttributeFormat.UNorm16:
                    case VertexAttributeFormat.SNorm16:
                    case VertexAttributeFormat.UInt16:
                    case VertexAttributeFormat.SInt16:
                        size = 2;
                        break;

                    case VertexAttributeFormat.UNorm8:
                    case VertexAttributeFormat.SNorm8:
                    case VertexAttributeFormat.UInt8:
                    case VertexAttributeFormat.SInt8:
                        size = 1;
                        break;
                    }

                    vertexSize += vertexFormat[i].dimension * size;
                }


                //-------------------------------------------------------------
                // OUTPUT SETUP
                //-------------------------------------------------------------
                var writeArray = Mesh.AllocateWritableMeshData(1);
                var writeData  = writeArray[0];
                writeData.SetVertexBufferParams(vertexCount, vertexFormat);
                writeData.SetIndexBufferParams(indexCount, indexFormat);

                //-------------------------------------------------------------
                // MEMORY COPYING
                //-------------------------------------------------------------
                NativeArray <byte> inData;
                NativeArray <byte> outData;

                // Vertices
                inData  = readData.GetVertexData <byte>();
                outData = writeData.GetVertexData <byte>();

            #if USE_UNSAFE
                unsafe
                {
                    UnityUnsafeUtility.MemCpy(outData.GetUnsafePtr(), inData.GetUnsafeReadOnlyPtr(),
                                              vertexCount * vertexSize);
                }
            #else
                inData.CopyTo(outData);
            #endif


                // Indices
                inData  = readData.GetIndexData <byte>();
                outData = writeData.GetIndexData <byte>();

            #if USE_UNSAFE
                unsafe
                {
                    UnityUnsafeUtility.MemCpy(outData.GetUnsafePtr(), inData.GetUnsafeReadOnlyPtr(),
                                              indexCount * indexSize);
                }
            #else
                inData.CopyTo(outData);
            #endif

                //-------------------------------------------------------------
                // FINALIZATION
                //-------------------------------------------------------------
                writeData.subMeshCount = inMesh.subMeshCount;

                // Set all sub-meshes
                for (var i = 0; i < inMesh.subMeshCount; i++)
                {
                    writeData.SetSubMesh(i,
                                         new SubMeshDescriptor((int)inMesh.GetIndexStart(i),
                                                               (int)inMesh.GetIndexCount(i)));
                }


                Mesh.ApplyAndDisposeWritableMeshData(writeArray, outMesh);
            }
        }
예제 #12
0
        /// <summary>
        /// Combine transformed instances of a mesh.
        /// </summary>
        public static Mesh CopyReplicate(this Mesh mesh, NativeArray <float4x4> matrices)
        {
            using (var readArray = Mesh.AcquireReadOnlyMeshData(mesh))
            {
                var m = new Mesh
                {
                    subMeshCount = 1,
                    indexFormat  = IndexFormat.UInt32
                };

                //-------------------------------------------------------------
                // COLLECT ALL NECESSARY INPUT INFO
                //-------------------------------------------------------------
                // Source -----------------------------------------------------
                var readData = readArray[0];

                // Formats
                var sourceVertexSize  = mesh.SizeOfVertex();
                var sourceIndexFormat = mesh.indexFormat;

                // Counts
                var sourceVertexCount = readData.vertexCount;
                var sourceIndexCount  = readData.GetIndexCount();

                // Destination -----------------------------------------------------
                var destIndexFormat  = IndexFormat.UInt32;
                var destVertexFormat = mesh.CopyVertexFormat(0, 1);
                var destIndexCount   = sourceIndexCount * matrices.Length;
                var destVertexCount  = sourceVertexCount * matrices.Length;

                var hasStream1 = !mesh.IsVertexPositionOnly();


                //-------------------------------------------------------------
                // OUTPUT SETUP
                //-------------------------------------------------------------
                var writeArray = Mesh.AllocateWritableMeshData(1);
                var writeData  = writeArray[0];

                writeData.SetVertexBufferParams(destVertexCount, destVertexFormat);
                writeData.SetIndexBufferParams(destIndexCount, destIndexFormat);

                //-------------------------------------------------------------
                // MEMORY COPYING
                //-------------------------------------------------------------
                // Replicate every other vertex attribute ---------------------
                // Essentially skip the first 12 bytes (= 3 floats) of every vertex,
                // because we know they represent position, and we handled this above.
                // Everything that is not VertexPosition will be written to stream 1 !
                unsafe
                {
                    if (hasStream1)
                    {
                        var inData  = readData.GetVertexData <byte>();
                        var outData = writeData.GetVertexData <byte>(1); // Notice that we write to stream 1!

                        var destElementSize = sourceVertexSize - FLOAT3_SIZE;
                        var source          =
                            FLOAT3_SIZE +
                            (byte *)inData.GetUnsafeReadOnlyPtr();     // Begin after the first vertex = first 12 bytes
                        var copies = matrices.Length;

                        var noPosition =
                            new NativeArray <byte>(destElementSize * readData.vertexCount, Allocator.TempJob);

                        // REMOVE POSITIONS FROM ORIGINAL MESH STREAM
                        Unity.Collections.LowLevel.Unsafe.UnsafeUtility
                        .MemCpyStride(destination: noPosition.GetUnsafePtr(),
                                      destinationStride: destElementSize,
                                      source: source,
                                      sourceStride: sourceVertexSize,
                                      elementSize: destElementSize,
                                      count: readData.vertexCount);

                        // REPLICATE NORMALS,COLORS,UV ETC INTO THE MERGED MESH
                        UnsafeUtility.MemCpyReplicate(destination: outData, source: noPosition, count: copies);

                        noPosition.Dispose();
                    }


                    // Transform Vertices ----------------------------------------
                    var inVertices  = new NativeArray <Vector3>(sourceVertexCount, Allocator.TempJob);
                    var outVertices = writeData.GetVertexData <float3>(0);

                    readData.GetVertices(inVertices);

                    new HelperJobs.TransformVerticesJob
                    {
                        inputVertices  = inVertices.Reinterpret <float3>(),
                        matrices       = matrices,
                        outputVertices = outVertices
                    }.Schedule(destVertexCount, 128).Complete();


                    //Indices ---------------------------------------------------
                    var inData2  = readData.GetIndexData <byte>().GetUnsafeReadOnlyPtr();
                    var outData2 = writeData.GetIndexData <int>();

                    if (sourceIndexFormat == IndexFormat.UInt16)
                    {
                        new HelperJobs.OffsetReplicateIndicesJob <ushort>
                        {
                            inputIndices        = inData2,
                            outputIndices       = outData2,
                            originalVertexCount = sourceVertexCount,
                            originalIndexCount  = sourceIndexCount
                        }.Schedule(destIndexCount, 128).Complete();
                    }
                    else
                    {
                        new HelperJobs.OffsetReplicateIndicesJob <uint>
                        {
                            inputIndices        = inData2,
                            outputIndices       = outData2,
                            originalVertexCount = sourceVertexCount,
                            originalIndexCount  = sourceIndexCount
                        }.Schedule(destIndexCount, 128).Complete();
                    }

                    inVertices.Dispose();
                }

                writeData.subMeshCount = 1;
                writeData.SetSubMesh(0, new SubMeshDescriptor(0, destIndexCount, mesh.GetTopology(0)));
                Mesh.ApplyAndDisposeWritableMeshData(writeArray, m);
                m.RecalculateBounds();

                return(m);
            }
예제 #13
0
        public MeshCollection Finalize()
        {
#if UNITY_2020_1_OR_NEWER
            Mesh.MeshDataArray data = Mesh.AcquireReadOnlyMeshData(meshData);
            var meshes           = new NativeArray <RasterizationMesh>(this.meshes.Count, Allocator.Persistent);
            int meshBufferOffset = vertexBuffers.Count;

            UnityEngine.Profiling.Profiler.BeginSample("Copying vertices");
            for (int i = 0; i < data.Length; i++)
            {
                var rawMeshData = data[i];
                var verts       = new NativeArray <Vector3>(rawMeshData.vertexCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
                rawMeshData.GetVertices(verts);
                int totalIndices = 0;
                for (int subMeshIndex = 0; subMeshIndex < rawMeshData.subMeshCount; subMeshIndex++)
                {
                    totalIndices += rawMeshData.GetSubMesh(subMeshIndex).indexCount;
                }
                var tris   = new NativeArray <int>(totalIndices, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
                int offset = 0;
                for (int subMeshIndex = 0; subMeshIndex < rawMeshData.subMeshCount; subMeshIndex++)
                {
                    var submesh = rawMeshData.GetSubMesh(subMeshIndex);
                    rawMeshData.GetIndices(tris.GetSubArray(offset, submesh.indexCount), subMeshIndex);
                    offset += submesh.indexCount;
                }

                vertexBuffers.Add(verts);
                triangleBuffers.Add(tris);
            }
            UnityEngine.Profiling.Profiler.EndSample();

            for (int i = 0; i < meshes.Length; i++)
            {
                var gatheredMesh = this.meshes[i];
                int bufferIndex;
                if (gatheredMesh.meshDataIndex >= 0)
                {
                    bufferIndex = meshBufferOffset + gatheredMesh.meshDataIndex;
                }
                else
                {
                    bufferIndex = -(gatheredMesh.meshDataIndex + 1);
                }

                var bounds = gatheredMesh.bounds;
                var slice  = vertexBuffers[bufferIndex].Reinterpret <float3>();
                if (bounds == new Bounds())
                {
                    UnityEngine.Profiling.Profiler.BeginSample("CalculateBounds");
                    // Recalculate bounding box
                    float4x4 m = gatheredMesh.matrix;
                    unsafe {
                        CalculateBoundsInvoke((float3 *)slice.GetUnsafeReadOnlyPtr(), slice.Length, ref m, out bounds);
                    }
                    UnityEngine.Profiling.Profiler.EndSample();
                }

                var triangles = triangleBuffers[bufferIndex];
                meshes[i] = new RasterizationMesh {
                    vertices  = new UnsafeSpan <float3>(slice),
                    triangles = new UnsafeSpan <int>(triangles.Slice(0, gatheredMesh.indicesCount != -1 ? gatheredMesh.indicesCount : triangles.Length)),
                    area      = gatheredMesh.area,
                    bounds    = bounds,
                    matrix    = gatheredMesh.matrix,
                    solid     = gatheredMesh.solid,
                };
            }

            cachedMeshes.Clear();
            ObjectPoolSimple <Dictionary <MeshCacheItem, int> > .Release(ref cachedMeshes);

            ListPool <GatheredMesh> .Release(ref this.meshes);

            data.Dispose();

            return(new MeshCollection(vertexBuffers, triangleBuffers, meshes));
#else
            throw new System.NotImplementedException("The burst version of recast is only supported in Unity 2020.1 or later");
#endif
        }
예제 #14
0
    public static void CreateMesh_MeshDataApi()
    {
        var sw = Stopwatch.StartNew();

        // Find all MeshFilter objects in the scene
        smp1.Begin();
        var meshFilters = FindObjectsOfType <MeshFilter>();

        smp1.End();

        // Need to figure out how large the output mesh needs to be (in terms of vertex/index count),
        // as well as get transforms and vertex/index location offsets for each mesh.
        smp2.Begin();
        var jobs = new ProcessMeshDataJob();

        jobs.CreateInputArrays(meshFilters.Length);
        var inputMeshes = new List <Mesh>(meshFilters.Length);

        var vertexStart = 0;
        var indexStart  = 0;
        var meshCount   = 0;

        for (var i = 0; i < meshFilters.Length; ++i)
        {
            var mf = meshFilters[i];
            var go = mf.gameObject;
            if (go.CompareTag("EditorOnly"))
            {
                DestroyImmediate(go);
                continue;
            }

            var mesh = mf.sharedMesh;
            inputMeshes.Add(mesh);
            jobs.vertexStart[meshCount] = vertexStart;
            jobs.indexStart[meshCount]  = indexStart;
            jobs.xform[meshCount]       = go.transform.localToWorldMatrix;
            vertexStart           += mesh.vertexCount;
            indexStart            += (int)mesh.GetIndexCount(0);
            jobs.bounds[meshCount] = new float3x2(new float3(Mathf.Infinity), new float3(Mathf.NegativeInfinity));
            ++meshCount;
        }
        smp2.End();

        // Acquire read-only data for input meshes
        jobs.meshData = Mesh.AcquireReadOnlyMeshData(inputMeshes);

        // Create and initialize writable data for the output mesh
        var outputMeshData = Mesh.AllocateWritableMeshData(1);

        jobs.outputMesh = outputMeshData[0];
        jobs.outputMesh.SetIndexBufferParams(indexStart, IndexFormat.UInt32);
        jobs.outputMesh.SetVertexBufferParams(vertexStart,
                                              new VertexAttributeDescriptor(VertexAttribute.Position),
                                              new VertexAttributeDescriptor(VertexAttribute.Normal, stream: 1));

        // Launch mesh processing jobs
        var handle = jobs.Schedule(meshCount, 4);

        // Create destination Mesh object
        smp3.Begin();
        var newMesh = new Mesh();

        newMesh.name = "CombinedMesh";
        var sm = new SubMeshDescriptor(0, indexStart, MeshTopology.Triangles);

        sm.firstVertex = 0;
        sm.vertexCount = vertexStart;

        // Wait for jobs to finish, since we'll have to access the produced mesh/bounds data at this point
        handle.Complete();

        // Final bounding box of the whole mesh is union of the bounds of individual transformed meshes
        var bounds = new float3x2(new float3(Mathf.Infinity), new float3(Mathf.NegativeInfinity));

        for (var i = 0; i < meshCount; ++i)
        {
            var b = jobs.bounds[i];
            bounds.c0 = math.min(bounds.c0, b.c0);
            bounds.c1 = math.max(bounds.c1, b.c1);
        }
        sm.bounds = new Bounds((bounds.c0 + bounds.c1) * 0.5f, bounds.c1 - bounds.c0);
        jobs.outputMesh.subMeshCount = 1;
        jobs.outputMesh.SetSubMesh(0, sm, MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontValidateIndices | MeshUpdateFlags.DontNotifyMeshUsers);
        Mesh.ApplyAndDisposeWritableMeshData(outputMeshData, new[] { newMesh }, MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontValidateIndices | MeshUpdateFlags.DontNotifyMeshUsers);
        newMesh.bounds = sm.bounds;
        smp3.End();

        // Dispose of the read-only mesh data and temporary bounds array
        smp4.Begin();
        jobs.meshData.Dispose();
        jobs.bounds.Dispose();
        smp4.End();

        // Create new GameObject with the new mesh
        var newGo = new GameObject("CombinedMesh", typeof(MeshFilter), typeof(MeshRenderer));

        newGo.tag = "EditorOnly";
        var newMf = newGo.GetComponent <MeshFilter>();
        var newMr = newGo.GetComponent <MeshRenderer>();

        newMr.material   = AssetDatabase.LoadAssetAtPath <Material>("Assets/CreateMeshFromAllSceneMeshes/MaterialForNewlyCreatedMesh.mat");
        newMf.sharedMesh = newMesh;
        //newMesh.RecalculateNormals(); // faster to do normal xform in the job

        var dur = sw.ElapsedMilliseconds;

        Debug.Log($"Took {dur/1000.0:F2}sec for {meshCount} objects, total {vertexStart} verts");

        Selection.activeObject = newGo;
    }