예제 #1
0
    static unsafe void GetVoxelsInternal(ref GetVoxelsContext context, int indexStart)
    {
        int i0 = context.indices[indexStart];
        int i1 = context.indices[indexStart + 1];
        int i2 = context.indices[indexStart + 2];

        SimpleMesh.Vertex v0 = context.verts[i0];
        SimpleMesh.Vertex v1 = context.verts[i1];
        SimpleMesh.Vertex v2 = context.verts[i2];

        float3 a = v0.Position;
        float3 b = v1.Position;
        float3 c = v2.Position;

        float3 normalTri;
        {
            float3 normalCross           = cross(b - a, c - a);
            float  normalCrossLengthSqrd = dot(normalCross, normalCross);
            if (normalCrossLengthSqrd == 0f)
            {
                return;
            }
            normalTri = normalCross * rcp(sqrt(normalCrossLengthSqrd));
        }

        // extend every tri by half a voxel by just extending it along the corner-middle dir.
        // it's a naive attempt to get a conservative rasterizer - works good enough in general
        float3 middle = (a + b + c) / 3f;

        a += normalize(a - middle) * 0.5f;
        b += normalize(b - middle) * 0.5f;
        c += normalize(c - middle) * 0.5f;

        // get the AABB
        float3 minf          = min(a, min(b, c));
        float3 maxf          = max(a, max(b, c));
        int3   maxDimensions = context.maxDimensions;
        int3   mini          = clamp(int3(floor(minf)), 0, maxDimensions);
        int3   maxi          = clamp(int3(ceil(maxf)), 0, maxDimensions);

        int written = 0;
        VoxelizedPosition *positions = context.positions;
        int positionsLength          = context.positionLength;

        Color color0 = v0.Color;
        Color color1 = v1.Color;
        Color color2 = v2.Color;

        for (int x = mini.x; x <= maxi.x; x++)
        {
            for (int z = mini.z; z <= maxi.z; z++)
            {
                for (int y = mini.y; y <= maxi.y; y++)
                {
                    float3 voxel = float3(x, y, z) + 0.5f;
                    float  normalDistToTriangle = dot(voxel - a, normalTri);
                    if (abs(normalDistToTriangle) > 0.5f)
                    {
                        continue;                         // distance to the triangle plane is over half a voxel -> the other side will have a voxel instead if we're at 0.5-1.0 dist
                    }

                    // set up barycentric coordinates
                    float3 p     = voxel - normalTri * normalDistToTriangle;
                    float3 p0    = b - a;
                    float3 p1    = c - a;
                    float3 p2    = p - a;
                    float  d00   = dot(p0, p0);
                    float  d01   = dot(p0, p1);
                    float  d11   = dot(p1, p1);
                    float  d20   = dot(p2, p0);
                    float  d21   = dot(p2, p1);
                    float  denom = 1f / (d00 * d11 - d01 * d01);
                    float3 barry;
                    barry.y = (d11 * d20 - d01 * d21) * denom;              // v1
                    barry.z = (d00 * d21 - d01 * d20) * denom;              // v2
                    barry.x = 1.0f - barry.y - barry.z;                     // v0

                    if (any(barry < 0 | barry > 1))
                    {
                        continue;                         // we're on the triangle plane, but outside the triangle
                    }

                    // interpolate vertex colors with the barycentric coordinates
                    Color color;
                    color.r = (color0.r * barry.x + color1.r * barry.y + color2.r * barry.z);
                    color.g = (color0.g * barry.x + color1.g * barry.y + color2.g * barry.z);
                    color.b = (color0.b * barry.x + color1.b * barry.y + color2.b * barry.z);
                    color.a = 1f;

                    float2 uv;
                    uv.x = (v0.UV.x * barry.x + v1.UV.x * barry.y + v2.UV.x * barry.z);
                    uv.y = (v0.UV.y * barry.x + v1.UV.y * barry.y + v2.UV.y * barry.z);

                    int idx = x * (maxDimensions.z + 1) + z;
                    positions[written++] = new VoxelizedPosition
                    {
                        XZIndex       = idx,
                        Y             = (short)y,
                        Color         = color,
                        MaterialIndex = (sbyte)v0.MaterialIndex,
                        UV            = uv
                    };

                    if (written == positionsLength)
                    {
                        goto END;                         // buffer full, our triangle must've been huge
                    }
                }
            }
        }
END:
        context.writtenVoxelCount = written;
    }
예제 #2
0
    public static SimpleMesh Import(string path, bool swapYZ)
    {
        long fileByteSize = new System.IO.FileInfo(path).Length;

        // would use Allocator.Temp, but that doesn't clean up on re-allocation; so total RAM balloons
        NativeArrayList <float3>  positionsLUT  = new NativeArrayList <float3>(1024 * 64, Allocator.Persistent);
        NativeArrayList <Color32> colorsLUT     = new NativeArrayList <Color32>(1024 * 64, Allocator.Persistent);
        NativeArrayList <float2>  uvLookupTable = new NativeArrayList <float2>(1024 * 64, Allocator.Persistent);

        NativeArrayList <SimpleMesh.Vertex> vertexResult = new NativeArrayList <SimpleMesh.Vertex>(1024 * 64, Allocator.Persistent);

        SimpleMesh.MaterialLib activeMaterialLib = default;
        SimpleMesh.Material    activeMaterial    = default;
        char[] splits = new char[] { ' ' };

        Profiler.BeginSample("Read file");
        using (var file = new System.IO.FileStream(path, System.IO.FileMode.Open, System.IO.FileAccess.Read)) {
            using (var text = new System.IO.StreamReader(file)) {
                while (true)
                {
                    if (text.EndOfStream)
                    {
                        break;
                    }
                    string line = text.ReadLine();
                    if (line == null || line.Length == 0)
                    {
                        continue;
                    }

                    // start of a line
                    if (line.StartsWith("v "))
                    {
                        ParsePositionLine();
                    }
                    else if (line.StartsWith("f "))
                    {
                        ParseFaceLine();
                    }
                    else if (line.StartsWith("vt "))
                    {
                        ParseUVLine();
                    }
                    else if (line.StartsWith("vn "))
                    {
                        //
                    }
                    else if (line.StartsWith("mtllib "))
                    {
                        activeMaterialLib = SimpleMesh.MaterialLib.ParseFromObj(path, line.Substring("mtllib ".Length));
                    }
                    else if (line.StartsWith("o "))
                    {
                        //
                    }
                    else if (line.StartsWith("usemtl "))
                    {
                        activeMaterial = activeMaterialLib.GetByName(line.Substring("usemtl ".Length));
                    }
                    continue;

                    void ParseUVLine()
                    {
                        string[] subs = line.Split(splits, System.StringSplitOptions.RemoveEmptyEntries);
                        float2   uv   = new float2(ParseFloat(subs[1]), ParseFloat(subs[2]));

                        uvLookupTable.Add(uv);
                    }

                    void ParsePositionLine()
                    {
                        string[] subs = line.Split(splits, System.StringSplitOptions.RemoveEmptyEntries);
                        float3   pos  = new float3(ParseFloat(subs[1]), ParseFloat(subs[2]), ParseFloat(subs[3]));

                        if (swapYZ)
                        {
                            float t = pos.z;
                            pos.z = pos.y;
                            pos.y = t;
                        }
                        positionsLUT.Add(pos);
                        Color color;

                        if (subs.Length > 6)
                        {
                            color.r = ParseFloat(subs[4]);
                            color.g = ParseFloat(subs[5]);
                            color.b = ParseFloat(subs[6]);
                            color.a = 1f;
                        }
                        else
                        {
                            color = Color.white;
                        }
                        colorsLUT.Add(color);
                    }

                    float ParseFloat(string str)
                    {
                        return(float.Parse(str, System.Globalization.CultureInfo.InvariantCulture));
                    }

                    void ParseFaceLine()
                    {
                        int index           = 2;
                        int entriesPerIndex = 1;

                        for (int i = index; i < line.Length && line[i] != ' '; i++)
                        {
                            if (line[i] == '/')
                            {
                                entriesPerIndex++;
                            }
                        }

                        switch (entriesPerIndex)
                        {
                        case 1:                                 // f v1 v2 v3
                            for (int i = 0; i < 3; i++)
                            {
                                vertexResult.Add(GatherVertex(ParseFaceIndex(line, ref index), -1, -1));
                                index++;
                            }
                            break;

                        case 2:                                 // f v1/vt1 v2/vt2 v3/vt3
                            for (int i = 0; i < 3; i++)
                            {
                                int v = ParseFaceIndex(line, ref index);
                                index++;                                         // skip /
                                int vt = ParseFaceIndex(line, ref index);
                                index++;                                         // skip space between the 3 indices

                                vertexResult.Add(GatherVertex(v, vt, -1));
                            }
                            break;

                        case 3:
                            // f v1/vt1/vn1 ..
                            // f v1//vn1 ..
                            for (int i = 0; i < 3; i++)
                            {
                                int v = ParseFaceIndex(line, ref index);
                                index++;                                         // skip /
                                int vt = -1;
                                if (line[index] != '/')
                                {
                                    // vt1
                                    vt = ParseFaceIndex(line, ref index);
                                }
                                index++;                                         // skip second /
                                int vn = ParseFaceIndex(line, ref index);
                                index++;                                         // skip space between the 3 indices

                                vertexResult.Add(GatherVertex(v, vt, vn));
                            }
                            break;
                        }
                    }

                    SimpleMesh.Vertex GatherVertex(int positionIndex, int textureIndex, int normalIndex)
                    {
                        SimpleMesh.Vertex vertex = default;
                        vertex.Color    = colorsLUT[positionIndex];
                        vertex.Position = positionsLUT[positionIndex];
                        if (textureIndex >= 0)
                        {
                            vertex.UV = uvLookupTable[textureIndex];
                        }

                        vertex.MaterialIndex = activeMaterial?.MaterialIndex ?? -1;
                        return(vertex);
                    }
                }
            }
        }

        positionsLUT.Dispose();
        uvLookupTable.Dispose();
        colorsLUT.Dispose();

        Profiler.EndSample();

        int vertexCount = vertexResult.Count;

        unsafe {
            SimpleMesh.Vertex *vertices = (SimpleMesh.Vertex *)SimpleMesh.MallocHelper <SimpleMesh.Vertex>(vertexCount);
            UnsafeUtility.MemCpy(vertices, vertexResult.Array.GetUnsafePtr(), UnsafeUtility.SizeOf <SimpleMesh.Vertex>() * vertexCount);
            vertexResult.Dispose();

            int *indices = (int *)SimpleMesh.MallocHelper <int>(vertexCount);
            for (int i = 0; i < vertexCount; i++)
            {
                indices[i] = i;
            }

            return(new SimpleMesh(activeMaterialLib, vertices, indices, vertexCount, vertexCount));
        }
    }