Пример #1
0
        public static void Build(List <Vector3> targetBuffer, ref Bounds bounds, LocalPools pools)
        {
            Vector3[] vertices = pools.PopVector3Array(24);

            // Vertices as they are seen in faces
            //Front
            vertices[0] = new Vector3(bounds.max.x, bounds.min.y, bounds.min.z);
            vertices[1] = new Vector3(bounds.max.x, bounds.max.y, bounds.min.z);
            vertices[2] = new Vector3(bounds.min.x, bounds.max.y, bounds.min.z);
            vertices[3] = new Vector3(bounds.min.x, bounds.min.y, bounds.min.z);
            //Back
            vertices[4] = new Vector3(bounds.min.x, bounds.min.y, bounds.max.z);
            vertices[5] = new Vector3(bounds.min.x, bounds.max.y, bounds.max.z);
            vertices[6] = new Vector3(bounds.max.x, bounds.max.y, bounds.max.z);
            vertices[7] = new Vector3(bounds.max.x, bounds.min.y, bounds.max.z);
            //Right
            vertices[8]  = new Vector3(bounds.max.x, bounds.min.y, bounds.max.z);
            vertices[9]  = new Vector3(bounds.max.x, bounds.max.y, bounds.max.z);
            vertices[10] = new Vector3(bounds.max.x, bounds.max.y, bounds.min.z);
            vertices[11] = new Vector3(bounds.max.x, bounds.min.y, bounds.min.z);
            //Left
            vertices[12] = new Vector3(bounds.min.x, bounds.min.y, bounds.min.z);
            vertices[13] = new Vector3(bounds.min.x, bounds.max.y, bounds.min.z);
            vertices[14] = new Vector3(bounds.min.x, bounds.max.y, bounds.max.z);
            vertices[15] = new Vector3(bounds.min.x, bounds.min.y, bounds.max.z);
            //Top
            vertices[16] = new Vector3(bounds.max.x, bounds.max.y, bounds.min.z);
            vertices[17] = new Vector3(bounds.max.x, bounds.max.y, bounds.max.z);
            vertices[18] = new Vector3(bounds.min.x, bounds.max.y, bounds.max.z);
            vertices[19] = new Vector3(bounds.min.x, bounds.max.y, bounds.min.z);
            //Bottom
            vertices[20] = new Vector3(bounds.min.x, bounds.min.y, bounds.min.z);
            vertices[21] = new Vector3(bounds.min.x, bounds.min.y, bounds.max.z);
            vertices[22] = new Vector3(bounds.max.x, bounds.min.y, bounds.max.z);
            vertices[23] = new Vector3(bounds.max.x, bounds.min.y, bounds.min.z);

            // Add vertices to buffer
            for (int i = 0; i < 24; i++)
            {
                targetBuffer.Add(vertices[i]);
            }

            pools.PushVector3Array(vertices);
        }
Пример #2
0
        public static void GenerateTangents(this RenderBuffer buffer, LocalPools pools)
        {
            var vertices  = buffer.Vertices;
            var triangles = buffer.Triangles;

            var tan1 = pools.PopVector3Array(vertices.Count);
            var tan2 = pools.PopVector3Array(vertices.Count);

            for (int t = 0; t < triangles.Count; t += 3)
            {
                int i1 = triangles[t + 0];
                int i2 = triangles[t + 1];
                int i3 = triangles[t + 2];

                VertexData vd1 = vertices[i1];
                VertexData vd2 = vertices[i2];
                VertexData vd3 = vertices[i3];

                Vector3 v1 = vd1.Vertex;
                Vector3 v2 = vd2.Vertex;
                Vector3 v3 = vd3.Vertex;

                Vector2 w1 = vd1.UV;
                Vector2 w2 = vd2.UV;
                Vector2 w3 = vd3.UV;

                float x1 = v2.x - v1.x;
                float y1 = v2.y - v1.y;
                float z1 = v2.z - v1.z;

                float x2 = v3.x - v1.x;
                float y2 = v3.y - v1.y;
                float z2 = v3.z - v1.z;

                float s1 = w2.x - w1.x;
                float s2 = w3.x - w1.x;

                float t1 = w2.y - w1.y;
                float t2 = w3.y - w1.y;

                // Avoid division by zero
                float div = s1 * t2 - s2 * t1;
                float r   = (Mathf.Abs(div) > Mathf.Epsilon) ? (1f / div) : 0f;

                Vector3 sdir = new Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
                Vector3 tdir = new Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);

                tan1[i1] += sdir;
                tan1[i2] += sdir;
                tan1[i3] += sdir;

                tan2[i1] += tdir;
                tan2[i2] += tdir;
                tan2[i3] += tdir;
            }

            for (int v = 0; v < vertices.Count; ++v)
            {
                VertexData vd = vertices[v];

                Vector3 n = vd.Normal;
                Vector3 t = tan1[v];

                //Vector3 tmp = (t - n*Vector3.Dot(n, t)).normalized;
                //tangents[v] = new Vector4(tmp.x, tmp.y, tmp.z);
                Vector3.OrthoNormalize(ref n, ref t);

                vd.Tangent = new Vector4(
                    t.x, t.y, t.z,
                    (Vector3.Dot(Vector3.Cross(n, t), tan2[v]) < 0.0f) ? -1.0f : 1.0f
                    );

                tan1[v] = Vector3.zero;
                tan2[v] = Vector3.zero;
            }

            pools.PushVector3Array(tan1);
            pools.PushVector3Array(tan2);
        }
Пример #3
0
        public override void BuildMesh(
            Map map, DrawCallBatcher batcher, int offsetX, int offsetY, int offsetZ,
            int minX, int maxX, int minY, int maxY, int minZ, int maxZ, int lod,
            LocalPools pools
            )
        {
            BlockFace face = 0;

            int stepSize = 1 << lod;

            Assert.IsTrue(lod <= EngineSettings.ChunkConfig.LogSize); // LOD can't be bigger than chunk size
            int width = EngineSettings.ChunkConfig.Size >> lod;

            int[] mins  = { minX >> lod, minY >> lod, minZ >> lod };
            int[] maxes = { maxX >> lod, maxY >> lod, maxZ >> lod };

            int[] x  = { 0, 0, 0 };                                                    // Relative position of a block
            int[] xx = { 0, 0, 0 };                                                    // Relative position of a block after applying lod
            int[] q  = { 0, 0, 0 };                                                    // Direction in which we compare neighbors when building mask (q[d] is our current direction)
            int[] du = { 0, 0, 0 };                                                    // Width in a given dimension (du[u] is our current dimension)
            int[] dv = { 0, 0, 0 };                                                    // Height in a given dimension (dv[v] is our current dimension)
            int[] s  = { map.VoxelLogScaleX, map.VoxelLogScaleY, map.VoxelLogScaleZ }; // Scale in each dimension

            BlockData[] mask = pools.PopBlockDataArray(width * width);
            Vector3[]   vecs = pools.PopVector3Array(4);

            // Iterate over 3 dimensions. Once for front faces, once for back faces
            for (int dd = 0; dd < 2 * 3; dd++)
            {
                int d = dd % 3;
                int u = (d + 1) % 3;
                int v = (d + 2) % 3;

                x[0] = 0;
                x[1] = 0;
                x[2] = 0;

                q[0] = 0;
                q[1] = 0;
                q[2] = 0;
                q[d] = stepSize << s[d];

                // Determine which side we're meshing
                bool backFace = dd < 3;
                switch (dd)
                {
                case 0: face = BlockFace.Left; break;

                case 3: face = BlockFace.Right; break;

                case 1: face = BlockFace.Bottom; break;

                case 4: face = BlockFace.Top; break;

                case 2: face = BlockFace.Back; break;

                case 5: face = BlockFace.Front; break;
                }

                // Move through the dimension from front to back
                for (x[d] = mins[d] - 1; x[d] <= maxes[d];)
                {
                    // Compute the mask
                    int n = 0;

                    for (x[v] = 0; x[v] < mins[v]; x[v]++)
                    {
                        for (x[u] = 0; x[u] < width; x[u]++)
                        {
                            mask[n++] = BlockData.Air;
                        }
                    }

                    for (x[v] = mins[v]; x[v] <= maxes[v]; x[v]++)
                    {
                        for (x[u] = 0; x[u] < mins[u]; x[u]++)
                        {
                            mask[n++] = BlockData.Air;
                        }

                        for (x[u] = mins[u]; x[u] <= maxes[u]; x[u]++)
                        {
                            int realX = (x[0] << lod << s[0]) + offsetX;
                            int realY = (x[1] << lod << s[1]) + offsetY;
                            int realZ = (x[2] << lod << s[2]) + offsetZ;

                            BlockData voxelFace0 = map.GetBlock(realX, realY, realZ);
                            BlockData voxelFace1 = map.GetBlock(realX + q[0], realY + q[1], realZ + q[2]);

                            mask[n++] = (voxelFace0.IsSolid() && voxelFace1.IsSolid())
                                            ? BlockData.Air
                                            : (backFace ? voxelFace1 : voxelFace0);
                        }

                        for (x[u] = maxes[u] + 1; x[u] < width; x[u]++)
                        {
                            mask[n++] = BlockData.Air;
                        }
                    }

                    for (x[v] = maxes[v] + 1; x[v] < width; x[v]++)
                    {
                        for (x[u] = 0; x[u] < width; x[u]++)
                        {
                            mask[n++] = BlockData.Air;
                        }
                    }

                    x[d]++;
                    n = 0;

                    // Build faces from the mask if it's possible
                    int j;
                    for (j = 0; j < width; j++)
                    {
                        int i;
                        for (i = 0; i < width;)
                        {
                            if (mask[n].IsEmpty())
                            {
                                i++;
                                n++;
                                continue;
                            }

                            BlockType type = mask[n].BlockType;

                            // Compute width
                            int w;
                            for (w = 1; i + w < width && mask[n + w].BlockType == type; w++)
                            {
                            }

                            // Compute height
                            bool done = false;
                            int  k;
                            int  h;
                            for (h = 1; j + h < width; h++)
                            {
                                for (k = 0; k < w; k++)
                                {
                                    if (
                                        mask[n + k + h * width].IsEmpty() ||
                                        mask[n + k + h * width].BlockType != type
                                        )
                                    {
                                        done = true;
                                        break;
                                    }
                                }

                                if (done)
                                {
                                    break;
                                }
                            }

                            // Determine whether we really want to build this face
                            // TODO: Skip bottom faces at the bottom of the world
                            bool buildFace = true;
                            if (buildFace)
                            {
                                // Prepare face coordinates and dimensions
                                x[u] = i;
                                x[v] = j;

                                xx[0] = ((x[0] << lod) << s[0]) + offsetX;
                                xx[1] = ((x[1] << lod) << s[1]) + offsetY;
                                xx[2] = ((x[2] << lod) << s[2]) + offsetZ;

                                du[0] = du[1] = du[2] = 0;
                                dv[0] = dv[1] = dv[2] = 0;
                                du[u] = (w << lod) << s[u];
                                dv[v] = (h << lod) << s[v];

                                // Face vertices
                                Vector3Int v1 = new Vector3Int(
                                    xx[0], xx[1], xx[2]
                                    );
                                Vector3Int v2 = new Vector3Int(
                                    xx[0] + du[0], xx[1] + du[1], xx[2] + du[2]
                                    );
                                Vector3Int v3 = new Vector3Int(
                                    xx[0] + du[0] + dv[0], xx[1] + du[1] + dv[1], xx[2] + du[2] + dv[2]
                                    );
                                Vector3Int v4 = new Vector3Int(
                                    xx[0] + dv[0], xx[1] + dv[1], xx[2] + dv[2]
                                    );

                                // Face vertices transformed to world coordinates
                                // 0--1
                                // |  |
                                // |  |
                                // 3--2
                                vecs[0] = new Vector3(v4.X, v4.Y, v4.Z);
                                vecs[1] = new Vector3(v3.X, v3.Y, v3.Z);
                                vecs[2] = new Vector3(v2.X, v2.Y, v2.Z);
                                vecs[3] = new Vector3(v1.X, v1.Y, v1.Z);

                                // Build the face
                                IFaceBuilder builder = BlockDatabase.GetFaceBuilder(type);
                                builder.Build(batcher, ref mask[n], face, backFace, ref vecs, pools);
                            }

                            // Zero out the mask
                            int l;
                            for (l = 0; l < h; ++l)
                            {
                                for (k = 0; k < w; ++k)
                                {
                                    mask[n + k + l * width] = BlockData.Air;
                                }
                            }

                            i += w;
                            n += w;
                        }
                    }
                }
            }

            pools.PushBlockDataArray(mask);
            pools.PushVector3Array(vecs);
        }