예제 #1
0
파일: Mesh.cs 프로젝트: McManning/Coherence
        int RebuildNormals()
        {
            // We assume it always happens AFTER RebuildVertices
            normals.Resize(vertices.Length);

            InteropLogger.Debug($"RebuildNormals name={Name}, Length={normals.Length}");

            // Normals need to be cast from short -> float from Blender
            var normalScale = 1f / 32767f;

            for (int i = 0; i < verts.Length; i++)
            {
                var vert = verts[i];

                // Like vertex coordinates - we swizzle y/z
                normals[i] = new InteropVector3(
                    vert.no_x * normalScale,
                    vert.no_z * normalScale,
                    vert.no_y * normalScale
                    );
            }

            // Also update all existing split vertices to match
            // the original normal that may have been updated
            foreach (var kv in splitVertices)
            {
                var vertIndex = (int)loops[kv.Key].v;
                normals[kv.Value] = normals[vertIndex];
            }

            // For now we have no splits. Eventually this may
            // change if we add support for split normals
            // coming from a CustomData layer
            return(0);
        }
예제 #2
0
파일: Mesh.cs 프로젝트: McManning/Coherence
        int RebuildVertices()
        {
            // We resize to the number of vertices from Blender
            // PLUS the number of split vertices we already calculated
            // in a prior pass (thus already have the data filled out)
            vertices.Resize(verts.Length + splitVertices.Count);

            InteropLogger.Debug($"RebuildVertices name={Name}, Length={vertices.Length}");

            for (int i = 0; i < verts.Length; i++)
            {
                var vert = verts[i];

                // y/z are swizzled here to convert to Unity's coordinate space
                vertices[i] = new InteropVector3(
                    vert.co_x,
                    vert.co_z,
                    vert.co_y
                    );
            }

            // Also update all existing split vertices to match
            // the original vertex that may have been updated
            foreach (var kv in splitVertices)
            {
                var vertIndex = (int)loops[kv.Key].v;
                vertices[kv.Value] = vertices[vertIndex];
            }

            // This will never split
            return(0);
        }
예제 #3
0
        internal bool Approx(InteropVector3 v)
        {
            var epsilon = 1e-6f;

            return(Math.Abs(x - v.x) < epsilon &&
                   Math.Abs(y - v.y) < epsilon &&
                   Math.Abs(z - v.z) < epsilon);
        }
예제 #4
0
파일: Mesh.cs 프로젝트: McManning/Coherence
        /// <summary>
        /// Copy all mesh data - aligned to loops (thus no combination of like-vertices)
        /// </summary>
        internal void CopyMeshDataAlignedtoLoops(
            MVert[] verts,
            MLoop[] loops,
            MLoopTri[] loopTris,
            MLoopCol[] loopCols,
            List <MLoopUV[]> loopUVs
            )
        {
            #if LEGACY
            Reallocate(loops.Length, loopTris.Length, loopUVs.Count, loopCols != null);

            // Normals need to be cast from short -> float from Blender
            var normalScale = 1f / 32767f;

            for (int i = 0; i < loops.Length; i++)
            {
                var co = verts[loops[i].v].co;
                var no = verts[loops[i].v].no;

                _vertices[i] = new InteropVector3(co[0], co[1], co[2]);
                _normals[i]  = new InteropVector3(
                    no[0] * normalScale,
                    no[1] * normalScale,
                    no[2] * normalScale
                    );

                // Copy UV layers - same length as loops
                for (int layer = 0; layer < loopUVs.Count; layer++)
                {
                    _uvs[layer][i] = new InteropVector2(
                        loopUVs[layer][i].uv
                        );
                }

                // Copy vertex colors - same length as loops
                if (loopCols != null)
                {
                    var col = loopCols[i];
                    _colors[i] = new InteropColor32(
                        col.r,
                        col.g,
                        col.b,
                        col.a
                        );
                }
            }

            // Copy triangles
            for (uint t = 0; t < loopTris.Length; t++)
            {
                for (uint i = 0; i < 3; i++)
                {
                    _triangles[(t * 3) + i] = loopTris[t].tri[i];
                }
            }
            #endif
        }
예제 #5
0
 public static Vector3 ToVector3(this InteropVector3 vec)
 {
     return(new Vector3(vec.x, vec.y, vec.z));
 }
예제 #6
0
파일: Mesh.cs 프로젝트: McManning/Coherence
        /// <summary>
        /// Copy all mesh data from Blender in one go and optimize down as much as possible.
        /// </summary>
        /// <remarks>
        ///     Reference: LuxCoreRender/LuxCore::Scene_DefineBlenderMesh
        ///     for the logic dealing with split normals / UVs / etc.
        /// </remarks>
        /// <param name="verts"></param>
        /// <param name="loops"></param>
        /// <param name="loopTris"></param>
        /// <param name="loopUVs"></param>
        /// <param name="loopCols"></param>
        internal void CopyMeshData_V1(
            MVert[] verts,
            MLoop[] loops,
            MLoopTri[] loopTris,
            MLoopCol[] loopCols,
            List <MLoopUV[]> loopUVs
            )
        {
            #if LEGACY
            // In the case of split vertices - this'll resize DOWN
            // and then resize UP again for split vertices.

            Reallocate(verts.Length, loopTris.Length, loopUVs.Count, loopCols != null);

            var normalScale = 1f / 32767f;

            // Copy in vertex coordinates and normals
            for (int i = 0; i < verts.Length; i++)
            {
                var co = verts[i].co;
                var no = verts[i].no;

                _vertices[i] = new InteropVector3(co[0], co[1], co[2]);

                // Normals need to be cast from short -> float from Blender
                _normals[i] = new InteropVector3(
                    no[0] * normalScale,
                    no[1] * normalScale,
                    no[2] * normalScale
                    );
            }

            // Copy UV layers
            for (int layer = 0; layer < loopUVs.Count; layer++)
            {
                var uvLayer = _uvs[layer];
                for (uint i = 0; i < loopUVs[layer].Length; i++)
                {
                    var vertIndex = loops[i].v;

                    // This will overwrite itself for shared vertices - that's fine.
                    // We'll be handling split UVs when reading in triangle data.
                    uvLayer[vertIndex] = new InteropVector2(
                        loopUVs[layer][i].uv
                        );
                }
            }

            // Copy vertex colors if we got 'em
            if (loopCols != null)
            {
                for (uint i = 0; i < loopCols.Length; i++)
                {
                    var vertIndex = loops[i].v;
                    var col       = loopCols[i];
                    _colors[vertIndex] = new InteropColor32(
                        col.r,
                        col.g,
                        col.b,
                        col.a
                        );
                }
            }

            // Track what triangle vertices need to be split.
            // This maps an index in `triangles` to an index in `loops`
            var splitTris = new Dictionary <uint, uint>();

            // Generate triangle list while identifying any vertices that will need
            // to be split - due to having split UVs, normals, etc in the loop data.
            for (uint t = 0; t < loopTris.Length; t++)
            {
                for (uint i = 0; i < 3; i++)
                {
                    var loopIndex = loopTris[t].tri[i];
                    var vertIndex = loops[loopIndex].v;

                    var split = false; // Assumes .v is already < verts.Length

                    // TODO: Test differing normals - not applicable
                    // here as normals are only read in from MVert

                    // Determine if we should make a new vertex for split UVs
                    for (int layer = 0; layer < loopUVs.Count && !split; layer++)
                    {
                        var loopUV = loopUVs[layer][loopIndex].uv;
                        var vertUV = _uvs[layer][vertIndex];
                        // TODO: Handle floating point errors?
                        if (loopUV[0] != vertUV.x || loopUV[1] != vertUV.y)
                        {
                            split = true;
                        }
                    }

                    // If we have vertex colors, check for split colors
                    if (loopCols != null)
                    {
                        var col     = loopCols[loopIndex];
                        var vertCol = _colors[vertIndex];

                        if (col.r != vertCol.r ||
                            col.g != vertCol.g ||
                            col.b != vertCol.b ||
                            col.a != vertCol.a
                            )
                        {
                            split = true;
                        }
                    }

                    _triangles[(t * 3) + i] = vertIndex;

                    // Track if we need to split the vertex in the triangle
                    // to a new one once we've iterated through everything
                    if (split)
                    {
                        splitTris.Add((t * 3) + i, loopIndex);
                    }
                }
            }

            // 7958 + 32245 = 40203
            // LOOPS are 31488

            // 7958 * 3 = 23874
            // 15744 loop triangles
            // 31488 vertex color indices

            // If we have triangle verts to split - apply all at once so there's
            // only a single re-allocation to our arrays.
            var totalNewVertices = splitTris.Count;
            if (totalNewVertices > 0)
            {
                InteropLogger.Debug($"Splitting {totalNewVertices} vertices");
                var newVertIndex = (uint)verts.Length;

                // Reallocate everything to fit the new set of vertices
                Reallocate(verts.Length + totalNewVertices, loopTris.Length, loopUVs.Count, loopCols != null);

                // Generate new vertices with any split data (normals, UVs, colors, etc)
                foreach (var tri in splitTris.Keys)
                {
                    var prevVertIndex = _triangles[tri]; // MVert index
                    var loopIndex     = splitTris[tri];  // MLoop index

                    // Same coordinates as the original vertex
                    _vertices[newVertIndex] = _vertices[prevVertIndex];

                    // TODO: If there were split normals, that'd be handled here.
                    _normals[newVertIndex] = _normals[prevVertIndex];

                    // Read UVs from loops again to handle any split UVs
                    for (int layer = 0; layer < loopUVs.Count; layer++)
                    {
                        var uv = loopUVs[layer][loopIndex].uv;

                        _uvs[layer][newVertIndex] = new InteropVector2(uv);
                    }

                    // Same deal for vertex colors - copy from the loop
                    if (loopCols != null)
                    {
                        var col = loopCols[loopIndex];
                        _colors[newVertIndex] = new InteropColor32(
                            col.r,
                            col.g,
                            col.b,
                            col.a
                            );
                    }

                    // And finally update the triangle to point to the new vertex
                    _triangles[tri] = newVertIndex;
                    newVertIndex++;
                }
            }
            #endif
        }
예제 #7
0
        /// <summary>
        /// Copy an <see cref="MVert"/> array into <see cref="Vertices"/> and <see cref="Normals"/>.
        /// </summary>
        /// <param name="verts"></param>
        internal void CopyFromMVerts(MVert[] verts)
        {
            var count = verts.Length;

            if (vertices == null)
            {
                vertices = new InteropVector3[count];
            }

            if (normals == null)
            {
                normals = new InteropVector3[count];
            }

            Array.Resize(ref vertices, count);
            Array.Resize(ref normals, count);

            // We're copying the data instead of sending directly into shared memory
            // because we cannot guarantee that:
            //  1.  shared memory will be available for write when this is called
            //  2.  the source MVert array hasn't been reallocated once shared
            //      memory *is* available for write

            // TODO: "Smart" dirtying.
            // If verts don't change, don't flag for updates.
            // Or if verts change, only update a region of the verts.
            // Could do a BeginChangeCheck() ... EndChangeCheck() with
            // a bool retval if changes happened.

            // The idea is to do as much work as possible locally within
            // Blender to transmit the smallest deltas to Unity.

            // On a resize - this is just everything.
            int rangeStart         = count;
            int rangeEnd           = 0;
            int changedVertexCount = 0;

            for (int i = 0; i < count; i++)
            {
                var co = verts[i].co;
                var no = verts[i].no;

                var newVert = new InteropVector3(co[0], co[1], co[2]);

                // Normals need to be cast from short -> float
                var newNorm = new InteropVector3(no[0] / 32767f, no[1] / 32767f, no[2] / 32767f);

                if (!newVert.Approx(vertices[i]) || !newNorm.Approx(normals[i]))
                {
                    rangeStart = Math.Min(rangeStart, i);
                    rangeEnd   = Math.Max(rangeEnd, i);
                    changedVertexCount++;
                }

                vertices[i] = newVert;
                normals[i]  = newNorm;

                // TECHNICALLY I can collect an index list of what changed and send just
                // that to Unity - but is it really worth the extra effort? We'll see!

                // Console.WriteLine($" - v={vertices[i]}, n={normals[i]}");

                // Other issue is that changes may affect index 0, 1, and 1000, 1001 for a quad.
                // Or a change has shifted vertices around in the array due to some sort of
                // esoteric Blender operator. So to play it safe, we just update the whole array
                // until it can be guaranteed that we can identify an accurate slice of updates.
            }

            InteropLogger.Debug(
                $"** Changed {changedVertexCount} vertices within index range " +
                $"[{rangeStart}, {rangeEnd}] covering {rangeEnd - rangeStart} vertices"
                );
        }