private void UpdateMesh(Mesh m, GSubDivisionTree tree) { CreatePolygons(tree); m.Clear(); m.SetVertices(GeneratedVertices); m.SetTriangles(GeneratedTriangles, 0); m.SetUVs(0, GeneratedUv); m.SetColors(GeneratedVertexColors); m.RecalculateBounds(); m.RecalculateNormals(); RecalculateTangentIfNeeded(m); GeneratedVertices.Clear(); GeneratedTriangles.Clear(); GeneratedVertexColors.Clear(); GeneratedUv.Clear(); SetLastUpdatedTimeNow(); }
private void CreatePolygons(GSubDivisionTree tree) { int dispSeed = Terrain.TerrainData.Geometry.DisplacementSeed; float dispStrength = Terrain.TerrainData.Geometry.DisplacementStrength; Texture2D subdivMap = Terrain.TerrainData.Geometry.Internal_SubDivisionMap; Vector2 uv0, uv1, uv2; Vector3 v0, v1, v2; float r; Rand rand; double radius; int baseResolution = Terrain.TerrainData.Geometry.MeshBaseResolution; int resolution = Terrain.TerrainData.Geometry.MeshResolution; int level; double triangleBaseLength = 1f / Terrain.TerrainData.Geometry.ChunkGridSize; IGPolygonProcessor pp = Terrain.TerrainData.Geometry.PolygonProcessor; GPolygon polygon = new GPolygon(); GeneratedUv.Clear(); GeneratedVertices.Clear(); GeneratedVertexColors.Clear(); GeneratedTriangles.Clear(); Vector3 terrainSize = new Vector3( Terrain.TerrainData.Geometry.Width, Terrain.TerrainData.Geometry.Height, Terrain.TerrainData.Geometry.Length); v0 = Vector3.zero; v1 = Vector3.zero; v2 = Vector3.zero; tree.ForEachLeaf((n) => { uv0 = n.V0; uv1 = n.V1; uv2 = n.V2; if (dispStrength > 0) { if (uv0.x != 0 && uv0.x != 1 && uv0.y != 0 && uv0.y != 1) { r = subdivMap.GetPixelBilinear(uv0.x, uv0.y).r; level = baseResolution + Mathf.Min(Mathf.FloorToInt(r / GCommon.SUB_DIV_STEP), resolution - baseResolution); rand = new Rand(dispSeed + (int)(uv0.x * 1000 + uv0.y * 1000)); radius = 0.35 * dispStrength * triangleBaseLength * TriangleEdgeLength[level]; uv0.x = Mathf.Clamp01(uv0.x + (float)((rand.NextDouble() - 0.5) * radius)); uv0.y = Mathf.Clamp01(uv0.y + (float)((rand.NextDouble() - 0.5) * radius)); } if (uv1.x != 0 && uv1.x != 1 && uv1.y != 0 && uv1.y != 1) { r = subdivMap.GetPixelBilinear(uv1.x, uv1.y).r; level = baseResolution + Mathf.Min(Mathf.FloorToInt(r / GCommon.SUB_DIV_STEP), resolution - baseResolution); rand = new Rand(dispSeed + (int)(uv1.x * 1000 + uv1.y * 1000)); radius = 0.35 * dispStrength * triangleBaseLength * TriangleEdgeLength[level]; uv1.x = Mathf.Clamp01(uv1.x + (float)((rand.NextDouble() - 0.5) * radius)); uv1.y = Mathf.Clamp01(uv1.y + (float)((rand.NextDouble() - 0.5) * radius)); } if (uv2.x != 0 && uv2.x != 1 && uv2.y != 0 && uv2.y != 1) { r = subdivMap.GetPixelBilinear(uv2.x, uv2.y).r; level = baseResolution + Mathf.Min(Mathf.FloorToInt(r / GCommon.SUB_DIV_STEP), resolution - baseResolution); rand = new Rand(dispSeed + (int)(uv2.x * 1000 + uv2.y * 1000)); radius = 0.35 * dispStrength * triangleBaseLength * TriangleEdgeLength[level]; uv2.x = Mathf.Clamp01(uv2.x + (float)((rand.NextDouble() - 0.5) * radius)); uv2.y = Mathf.Clamp01(uv2.y + (float)((rand.NextDouble() - 0.5) * radius)); } } Vector4 h0 = Terrain.GetInterpolatedHeightMapSample(uv0); Vector4 h1 = Terrain.GetInterpolatedHeightMapSample(uv1); Vector4 h2 = Terrain.GetInterpolatedHeightMapSample(uv2); if (h0.w >= 0.5f || h1.w >= 0.5f || h2.w >= 0.5f) //alpha channel for visibility { return; } if (pp != null) { polygon.Clear(); v0.Set(uv0.x * terrainSize.x, h0.x * terrainSize.y, uv0.y * terrainSize.z); v1.Set(uv1.x * terrainSize.x, h1.x * terrainSize.y, uv1.y * terrainSize.z); v2.Set(uv2.x * terrainSize.x, h2.x * terrainSize.y, uv2.y * terrainSize.z); polygon.Vertices.Add(v0); polygon.Vertices.Add(v1); polygon.Vertices.Add(v2); polygon.Uvs.Add(uv0); polygon.Uvs.Add(uv1); polygon.Uvs.Add(uv2); polygon.Triangles.Add(0); polygon.Triangles.Add(1); polygon.Triangles.Add(2); pp.Process(this, ref polygon); int currentTrisIndex = GeneratedVertices.Count; for (int i = 0; i < polygon.Triangles.Count; ++i) { GeneratedTriangles.Add(currentTrisIndex + polygon.Triangles[i]); } for (int i = 0; i < polygon.Vertices.Count; ++i) { GeneratedVertices.Add(polygon.Vertices[i]); } for (int i = 0; i < polygon.Uvs.Count; ++i) { GeneratedUv.Add(polygon.Uvs[i]); } if (polygon.VertexColors != null && polygon.VertexColors.Count > 0) { for (int i = 0; i < polygon.VertexColors.Count; ++i) { GeneratedVertexColors.Add(polygon.VertexColors[i]); } } } else { int currentTrisIndex = GeneratedVertices.Count; GeneratedTriangles.Add(currentTrisIndex + 0); GeneratedTriangles.Add(currentTrisIndex + 1); GeneratedTriangles.Add(currentTrisIndex + 2); v0.Set(uv0.x * terrainSize.x, h0.x * terrainSize.y, uv0.y * terrainSize.z); v1.Set(uv1.x * terrainSize.x, h1.x * terrainSize.y, uv1.y * terrainSize.z); v2.Set(uv2.x * terrainSize.x, h2.x * terrainSize.y, uv2.y * terrainSize.z); GeneratedVertices.Add(v0); GeneratedVertices.Add(v1); GeneratedVertices.Add(v2); GeneratedUv.Add(uv0); GeneratedUv.Add(uv1); GeneratedUv.Add(uv2); } }); //Convert vertices terrain local space to chunk local space. //This way we can place the chunk pivot/origin point at the center of its region instead of the terrain pivot. //Chunk position is set by the terrain component. //This step is very important for other task such as level streaming and occlusion culling, etc. //Special thank to Aleš Stupka for the contribution. Matrix4x4 vertexTransformMatrix = Terrain.transform.localToWorldMatrix * transform.worldToLocalMatrix; for (int i = 0; i < GeneratedVertices.Count; ++i) { GeneratedVertices[i] = vertexTransformMatrix.MultiplyPoint(GeneratedVertices[i]); } }