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 }