Пример #1
0
        public void CalculateMesh()
        {
                                #if WDEBUG
            if (!ThreadWorker.multithreading)
            {
                Profiler.BeginSample("Calculate Mesh");
            }
                                #endif

            //reading data
            if (meshWorker.stop)
            {
                return;
            }
            int margin = voxeland.meshMargin;

            //top and bottom points
            int topPoint; int bottomPoint;
            voxeland.data.GetTopBottomPoints(rect.Expanded(margin), out topPoint, out bottomPoint, ignoreEmptyColumns: true);

            //empty mesh check
            if (topPoint == 0)
            {
                hiWrapper    = null; loWrapper = null; grassWrapper = null;
                indexToCoord = null;
                return;                         //exit to apply without stopping
            }

            //creating and filling matrix
            Matrix3 <byte> matrix = new Matrix3 <byte>(rect.offset.x - margin, bottomPoint - 1, rect.offset.z - margin, rect.size.x + margin * 2, topPoint - bottomPoint + 2, rect.size.z + margin * 2);
            voxeland.data.FillMatrix(matrix);

            //calculating verts
            if (meshWorker.stop)
            {
                return;
            }
            ChunkMesh.Face[] faces; Vector3[] verts;
            ChunkMesh.CalculateFaces(out faces, out verts, matrix, margin: margin);

            if (faces == null || verts == null || faces.Length == 0)
            {
                hiWrapper = null; loWrapper = null; return;
            }

            ChunkMesh.RelaxMesh(faces, verts, iterations: voxeland.relaxIterations, strength: voxeland.relaxStrength);

            hiWrapper = ChunkMesh.CalculateMesh(faces, verts, hipoly: true);
            loWrapper = ChunkMesh.CalculateMesh(faces, verts, hipoly: false);

            //normals
            if (meshWorker.stop)
            {
                return;
            }
            hiWrapper.normals = ChunkMesh.CalculateNormals(faces, verts, smoothIterations: voxeland.normalsSmooth);
            loWrapper.normals = hiWrapper.normals.Truncated(loWrapper.verts.Length);

            //types
            if (meshWorker.stop)
            {
                return;
            }

            int maxChannelsCount;
            switch (voxeland.channelEncoding)
            {
            case Voxeland.ChannelEncoding.MegaSplat: maxChannelsCount = 256; break;

            case Voxeland.ChannelEncoding.RTP: maxChannelsCount = 4; break;

            default: maxChannelsCount = 24; break;
            }
            maxChannelsCount = Mathf.Min(maxChannelsCount, voxeland.landTypes.array.Length);


            if (voxeland.channelEncoding == Voxeland.ChannelEncoding.Voxeland)
            {
                float[] chWeights = new float[verts.Length];
                hiWrapper.tangents = new Vector4[verts.Length];
                for (int ch = 0; ch < maxChannelsCount; ch++)
                {
                    if (!ChunkMesh.IsChannelUsed(faces, ch))
                    {
                        continue;
                    }
                    ChunkMesh.FillChWeights(faces, verts, ch, ref chWeights);
                    ChunkMesh.EncodeChWeights(chWeights, ch, ref hiWrapper.tangents);
                }
                loWrapper.tangents = hiWrapper.tangents.Truncated(loWrapper.verts.Length);
            }

            else if (voxeland.channelEncoding == Voxeland.ChannelEncoding.MegaSplat)
            {
                float[] chWeights = new float[verts.Length];
                hiWrapper.colors = new Color[verts.Length];
                Vector4[] uvs2 = new Vector4[verts.Length];

                byte[]  topTypes  = new byte[verts.Length];
                byte[]  secTypes  = new byte[verts.Length];
                float[] topBlends = new float[verts.Length];                         //blend value of the top type
                float[] secBlends = new float[verts.Length];

                ChunkMesh.EncodeMegaSplatFilters(faces, ref hiWrapper.colors);
                for (int ch = 0; ch < maxChannelsCount; ch++)
                {
                    if (!ChunkMesh.IsChannelUsed(faces, ch))
                    {
                        continue;
                    }
                    ChunkMesh.FillChWeights(faces, verts, ch, ref chWeights);
                    ChunkMesh.FillMegaSplatChTopTypes(chWeights, ch, topTypes, secTypes, topBlends, secBlends);
                }

                ChunkMesh.EncodeMegaSplatChWeights(topTypes, secTypes, topBlends, secBlends, ref hiWrapper.colors, ref uvs2);

                hiWrapper.uvs4    = new List <Vector4> [4];
                hiWrapper.uvs4[3] = new List <Vector4>();                        //3rd channel
                hiWrapper.uvs4[3].AddRange(uvs2);

                hiWrapper.uv = new Vector2[hiWrapper.verts.Length];
                for (int i = 0; i < hiWrapper.verts.Length; i++)
                {
                    hiWrapper.uv[i] = new Vector2(-hiWrapper.verts[i].x, hiWrapper.verts[i].z);
                }

                hiWrapper.tangents = new Vector4[hiWrapper.verts.Length];
                for (int i = 0; i < hiWrapper.verts.Length; i++)
                {
                    hiWrapper.tangents[i] = new Vector4(0, 1, 0, 1);
                }
            }

            else if (voxeland.channelEncoding == Voxeland.ChannelEncoding.RTP)
            {
                float[] chWeights = new float[verts.Length];
                hiWrapper.colors = new Color[verts.Length];

                for (int ch = 0; ch < maxChannelsCount; ch++)
                {
                    if (!ChunkMesh.IsChannelUsed(faces, ch))
                    {
                        continue;
                    }
                    ChunkMesh.FillChWeights(faces, verts, ch, ref chWeights);
                    ChunkMesh.EncodeColorChWeights(chWeights, ch, ref hiWrapper.colors);
                }
                loWrapper.colors = hiWrapper.colors.Truncated(loWrapper.verts.Length);
            }

            //index to coordinate array
            if (meshWorker.stop)
            {
                return;
            }
            indexToCoord = ChunkMesh.CalculateIndexToCoord(faces);

            //calculating grass
            if (meshWorker.stop)
            {
                return;
            }
            Matrix2 <byte> grassMatrix = new Matrix2 <byte>(rect);
            voxeland.data.FillGrass(grassMatrix);

            Matrix2 <ushort> topLevels = new Matrix2 <ushort>(rect);
            voxeland.data.FillHeightmap(topLevels);

            //offset lo border verts to prevent seams
            ChunkMesh.OffsetBorderVerts(loWrapper.verts, loWrapper.normals, rect.size.x, -0.15f);

            if (meshWorker.stop)
            {
                return;
            }
            grassWrapper = ChunkMesh.CalculateGrassMesh(grassMatrix, topLevels, loWrapper.verts, loWrapper.normals, loWrapper.tris, indexToCoord, voxeland.grassTypes);

                                #if WDEBUG
            if (!ThreadWorker.multithreading)
            {
                Profiler.EndSample();
            }
                                #endif
        }
Пример #2
0
        public void ApplyMesh()
        {
                                #if WDEBUG
            Profiler.BeginSample("Apply Mesh");
                                #endif

            if (meshWorker.stop)
            {
                return;
            }

            //resetting collider if it has empty mesh before applying loMesh - otherwise it will not be refreshed (seems to be Unity bug)
            if (meshCollider.sharedMesh != null && meshCollider.sharedMesh.vertexCount == 0 && loWrapper != null && loWrapper.verts.Length != 0)
            {
                meshCollider.sharedMesh = null;
            }

            //apply meshes
            if (loWrapper == null || hiWrapper == null)
            {
                hiMesh.Clear(); loMesh.Clear(); grassMesh.Clear();
            }
            else
            {
                //TODO: create new meshes instead re-using
                hiWrapper.ApplyTo(hiMesh);
                loWrapper.ApplyTo(loMesh);
            }

            //apply collider (in thread)
            if (colliderRequired)
            {
                colliderApplier.Start();
            }
            else
            {
                Clear(collider: true);
            }

            //apply grass
            if (grassWrapper == null || grassWrapper.verts.Length == 0)
            {
                if (grassMesh != null)
                {
                    grassMesh.Clear();
                }
            }
            else
            {
                if (grassMesh == null)
                {
                    grassMesh = new Mesh();
                }
                //grassWrapper.uv3 = new Vector2[grassWrapper.verts.Length];
                //for (int c=0; c<grassWrapper.uv3.Length; c++) grassWrapper.uv3[c] = new Vector2(1,1);
                grassWrapper.ApplyTo(grassMesh);
                grassFilter.sharedMesh = grassMesh;
            }

            //renaming meshes to provide highlight change
            int meshVer = 0;
            if (hiMesh.name.Contains("VoxelandTerrainHi"))
            {
                System.Int32.TryParse(hiMesh.name.Replace("VoxelandTerrainHi", ""), out meshVer);
            }
            if (meshVer > 100000000)
            {
                meshVer = 0;
            }

            hiMesh.name = "VoxelandTerrainHi" + (meshVer + 1);
            loMesh.name = "VoxelandTerrainLo" + (meshVer + 1);

            //purging wrappers
            loWrapper    = null;
            hiWrapper    = null;
            grassWrapper = null;

            //making ambient to apply this frame to prevent flickering
            if (!ambientWorker.calculated)
            {
                Debug.LogError("Ambient is not calculated"); //this should not happen
            }
            ambientWorker.FinalizeNow();                     //forcing ambient to apply this frame (without condition!)

            /* Disabling seams flashes. Do not forget to use new meshes and disable mesh assigning in lod switch
             *      foreach (Chunk chunk in voxeland.chunks.All())
             *      {
             *              if (chunk.meshFilter.sharedMesh == null)
             *                      chunk.meshFilter.sharedMesh = chunk.loMesh;
             *
             *              else if (chunk.meshRenderer.enabled && chunk.meshFilter.sharedMesh != chunk.hiMesh && chunk.meshFilter.sharedMesh != chunk.loMesh) //if nmew mesh not assigned
             *              {
             *                      bool allReady = true;
             *                      foreach(Coord neigCoord in coord.Neightbours())
             *                      {
             *                              if (voxeland.chunks[neigCoord] == null || voxeland.chunks[neigCoord].meshWorker == null) continue;
             *                              if (!voxeland.chunks[neigCoord].meshWorker.ready) allReady = false;
             *                      }
             *
             *                      if (allReady)
             *                      {
             *                              if (chunk.meshFilter.sharedMesh.name.Contains("TerrainHi"))
             *                                      chunk.meshFilter.sharedMesh = chunk.hiMesh;
             *                              else chunk.meshFilter.sharedMesh = chunk.loMesh;
             *                      }
             *              }
             *      }
             * }*/

            //enabling renderer on apply
            if (meshRequired && !meshRenderer.enabled)
            {
                meshRenderer.enabled = true; voxeland.CallOnChunkVisibilityChanged(this, true);
            }

                                #if WDEBUG
            Profiler.EndSample();
                                #endif
        }
Пример #3
0
        public void Append(MeshWrapper addMesh, Vector3 offset = new Vector3(), float size = 1, float height = 1)    //custom verts length can be larger than addMesh vert count
        {
            /*for (int v=0; v<addMesh.verts.Length; v++) //TODO test iteration inside "if"
             * {
             *      if (customVerts==null) verts[vertCounter+v] = addMesh.verts[v];// + offset;
             *      else verts[vertCounter+v] = customVerts[v];
             *
             *      if (normals!=null && addMesh.normals!=null)
             *      {
             *              if (customNormals==null) normals[vertCounter+v] = addMesh.normals[v];
             *              else normals[vertCounter+v] = customNormals[v];
             *      }
             *
             *      if (uv!=null && addMesh.uv!=null) uv[vertCounter+v] = addMesh.uv[v];
             *      if (uv2!=null && addMesh.uv2!=null) uv2[vertCounter+v] = addMesh.uv2[v];
             *      if (uv3!=null && addMesh.uv3!=null) uv3[vertCounter+v] = addMesh.uv3[v];
             *      if (uv4!=null && addMesh.uv4!=null) uv4[vertCounter+v] = addMesh.uv4[v];
             *      if (colors!=null && addMesh.colors!=null) colors[vertCounter+v] = addMesh.colors[v];
             *      if (tangents!=null && addMesh.tangents!=null) tangents[vertCounter+v] = addMesh.tangents[v];
             * }*/


            //this definitely works faster:

            //standard case (verts+normals+uv)
            if (normals != null && uv != null && addMesh.normals != null && normals.Length != 0 && addMesh.normals.Length != 0 && addMesh.uv != null && uv.Length != 0 && addMesh.uv.Length != 0)
            {
                for (int v = 0; v < addMesh.verts.Length; v++)
                {
                    int v2 = vertCounter + v;
                    verts[v2]   = new Vector3(addMesh.verts[v].x * size + offset.x, addMesh.verts[v].y * size * height + offset.y, addMesh.verts[v].z * size + offset.z);
                    normals[v2] = addMesh.normals[v];
                    uv[v2]      = addMesh.uv[v];
                }
            }

            //special cases when there's no normals or uvs
            else
            {
                for (int v = 0; v < addMesh.verts.Length; v++)
                {
                    verts[vertCounter + v] = new Vector3(addMesh.verts[v].x * size + offset.x, addMesh.verts[v].y * size * height + offset.y, addMesh.verts[v].z * size + offset.z);
                }

                if (normals != null && addMesh.normals != null && normals.Length != 0 && addMesh.normals.Length != 0)
                {
                    for (int v = 0; v < addMesh.normals.Length; v++)
                    {
                        normals[vertCounter + v] = addMesh.normals[v];
                    }
                }

                if (uv != null && addMesh.uv != null && uv.Length != 0 && addMesh.uv.Length != 0)
                {
                    for (int v = 0; v < addMesh.verts.Length; v++)
                    {
                        uv[vertCounter + v] = addMesh.uv[v];
                    }
                }
            }

            //additional cases
            if (uv2 != null && addMesh.uv2 != null && uv2.Length != 0 && addMesh.uv2.Length != 0)
            {
                for (int v = 0; v < addMesh.verts.Length; v++)
                {
                    uv2[vertCounter + v] = addMesh.uv2[v];
                }
            }

            if (uv3 != null && addMesh.uv3 != null && uv3.Length != 0 && addMesh.uv3.Length != 0)
            {
                for (int v = 0; v < addMesh.verts.Length; v++)
                {
                    uv3[vertCounter + v] = addMesh.uv3[v];
                }
            }

            if (uv4 != null && addMesh.uv4 != null && uv4.Length != 0 && addMesh.uv4.Length != 0)
            {
                for (int v = 0; v < addMesh.verts.Length; v++)
                {
                    uv4[vertCounter + v] = addMesh.uv4[v];
                }
            }

            if (uv != null && addMesh.uv != null && uv.Length != 0 && addMesh.uv.Length != 0)
            {
                for (int v = 0; v < addMesh.verts.Length; v++)
                {
                    uv[vertCounter + v] = addMesh.uv[v];
                }
            }

            if (colors != null && addMesh.colors != null && colors.Length != 0 && addMesh.colors.Length != 0)
            {
                for (int v = 0; v < addMesh.verts.Length; v++)
                {
                    colors[vertCounter + v] = addMesh.colors[v];
                }
            }

            if (tangents != null && addMesh.tangents != null && tangents.Length != 0 && addMesh.tangents.Length != 0)
            {
                for (int v = 0; v < addMesh.verts.Length; v++)
                {
                    tangents[vertCounter + v] = addMesh.tangents[v];
                }
            }

            //tris
            for (int t = 0; t < addMesh.tris.Length; t++)
            {
                tris[triCounter + t] = addMesh.tris[t] + vertCounter;
            }

            //counters
            vertCounter += addMesh.verts.Length;
            triCounter  += addMesh.tris.Length;
        }