public void DrawMesh(TerrainMeshData meshData) { meshFilter.sharedMesh = meshData.CreateMesh(); textureRender.gameObject.SetActive(false); meshFilter.gameObject.SetActive(true); }
public static TerrainMeshData GenerateTerrainMesh(float[,] heightMap, float heightMultiplier, AnimationCurve heightCurve, int levelOfDetail) { int width = heightMap.GetLength(0); int height = heightMap.GetLength(1); float topLeftX = (width - 1) / -2f; float topLeftZ = (height - 1) / 2f; int meshSimplificationIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2; int verticesPerLine = (width - 1) / meshSimplificationIncrement + 1; TerrainMeshData meshData = new TerrainMeshData(verticesPerLine, verticesPerLine); int vertexIndex = 0; for (int y = 0; y < height; y += meshSimplificationIncrement) { for (int x = 0; x < width; x += meshSimplificationIncrement) { meshData.vertices[vertexIndex] = new Vector3(topLeftX + x, /*heightCurve.Evaluate(heightMap[x, y])*/ heightMap[x, y] * heightMultiplier, topLeftZ - y); meshData.uvs[vertexIndex] = new Vector2(x / (float)width, y / (float)height); if (x < width - 1 && y < height - 1) { meshData.AddTriangle(vertexIndex, vertexIndex + verticesPerLine + 1, vertexIndex + verticesPerLine); meshData.AddTriangle(vertexIndex + verticesPerLine + 1, vertexIndex, vertexIndex + 1); } vertexIndex++; } } return(meshData); }
private void CheckAndCreateTowersAndBuildings(TerrainMeshData meshData) { var selectionProbability = (float)_totalBuildingToBeCreated / (_totalTerrainCount - _currentCount); var randomValue = Random.value; if (selectionProbability >= randomValue) { var meshVertexIndex = Mathf.FloorToInt(Random.value * meshData.vertices.Length); var meshVertex = meshData.vertices[meshVertexIndex] + new Vector3(meshData.meshCenter.x, 0, meshData.meshCenter.y); meshVertex.y = heightAboveBaseGround; if (clearingSettings.useOnlyCenterTile && clearingSettings.createClearing) { if (meshData.meshCenter == Vector3.zero) { return; } } var randomNumber = Random.Range(0, 1000) % yRotation.Length; CheckAndPlaceTower(randomNumber, meshVertex, meshData); _totalBuildingToBeCreated -= 1; } _currentCount += 1; }
public static TerrainMeshData GenerateFlatMesh(int chunkSize, int levelOfDetail) { float topLeftX = (chunkSize - 1) / -2f; float topLeftZ = (chunkSize - 1) / 2f; int meshSimplificationIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2; int verticesPerLine = (chunkSize - 1) / meshSimplificationIncrement + 1; TerrainMeshData meshData = new TerrainMeshData(verticesPerLine, verticesPerLine); int vertexIndex = 0; for (int y = 0; y < chunkSize; y += meshSimplificationIncrement) { for (int x = 0; x < chunkSize; x += meshSimplificationIncrement) { meshData.vertices[vertexIndex] = new Vector3(topLeftX + x, 0, topLeftZ - y); meshData.uvs[vertexIndex] = new Vector2(x / (float)chunkSize, y / (float)chunkSize); if (x < chunkSize - 1 && y < chunkSize - 1) { meshData.AddTriangle(vertexIndex, vertexIndex + verticesPerLine + 1, vertexIndex + verticesPerLine); meshData.AddTriangle(vertexIndex + verticesPerLine + 1, vertexIndex, vertexIndex + 1); } vertexIndex++; } } return(meshData); }
//生成TerrainMeshData static void ExportTerrainMeshData(TerrainData terrainData) { if (tempTerrMeshDataDic.ContainsKey(terrainData.name)) { return; } string pathMeshData = string.Format("{0}/{1}.asset", MeshDataExportFolder, terrainData.name); TerrainMeshData meshData = GetStriptableObject <TerrainMeshData>(pathMeshData); //网格分辨率 meshData.resolusion = terrainData.heightmapResolution; //采样高度信息 SamplingHeightMap(terrainData, ref meshData); //没有地形起伏,降低网格分辨率 if (meshData.indexes.Count == 0) { meshData.resolusion = 33; } //采样控制贴图 bool useAphla = terrainData.splatPrototypes.Length % 4 == 0; //基础图素是4的倍数用RGBA List <Color[]> controlMapColors = SamplingControlMap(terrainData, useAphla); //创建控制贴图 for (int i = 0; i < controlMapColors.Count; i++) { CreateTexture(controlMapColors[i], terrainData.name.ToLower(), i, useAphla ? TextureFormat.RGBA32 : TextureFormat.RGB24); } //创建材质 CreateMat(terrainData, ref meshData, useAphla); tempTerrMeshDataDic.Add(terrainData.name, meshData); UnityEditor.EditorUtility.SetDirty(meshData); }
public void LoadData() { if (string.IsNullOrEmpty(mapName)) { LogUtil.WriteWarning("Map name is null or empty. Setting to 'default'"); mapName = "default"; } TerrainMeshData data = FileUtil.LoadFromResources <TerrainMeshData>("terrain_mesh_data_" + mapName); if (data == null || !data.CheckPropertiesValid()) { OnLoadDataFailed(); return; } Mesh loadedMesh = new Mesh { vertices = data.vertices, triangles = data.triangles, colors = data.colours, normals = data.normals }; meshFilter.sharedMesh = loadedMesh; }
void MakeRectangle(int x, int z) { int x_vpos = x + m_moveToVecticePoint.x; int z_vpos = z + m_moveToVecticePoint.y; int terrain_size = m_asset.terrain_Size; int column = m_asset.terrain_Column_Count; int row = (x_vpos) / m_maxResolusion; int col = (z_vpos) / m_maxResolusion; m_terrainIndex = col * column + row; m_terrainName = GetTerrainNameByIndex(m_terrainIndex); m_terrainMeshData = GetTerrainMeshData(m_terrainName); if (m_terrainMeshData == null) { return; } AddVertice(x, z, 0); AddVertice(x + 1, z, 1); AddVertice(x, z + 1, 2); AddVertice(x + 1, z + 1, 3); int matIndex = m_terrainMeshData.matIndex; int triIndex; if (!m_subMeshIndexDic.TryGetValue(matIndex, out triIndex)) { m_subMeshIndexDic.Add(matIndex, m_curTriIndex); triIndex = m_curTriIndex++; } m_triangles[triIndex].Add(INDEXS[0]); m_triangles[triIndex].Add(INDEXS[2]); m_triangles[triIndex].Add(INDEXS[3]); m_triangles[triIndex].Add(INDEXS[0]); m_triangles[triIndex].Add(INDEXS[3]); m_triangles[triIndex].Add(INDEXS[1]); }
private void CheckAndPlaceTower(int randomCannonPoint, Vector3 meshVertex, TerrainMeshData meshData) { var buildingInstance = Instantiate(buildingPrefab, meshVertex, buildingPrefab.transform.rotation); buildingInstance.transform.SetParent(meshData.parent); Vector3 meshMinBounds = meshData.meshBounds.min; Vector3 meshMaxBounds = meshData.meshBounds.max; float terrainLeftX = meshMinBounds.x; float terrainRightX = meshMaxBounds.x; float terrainBottomZ = meshMinBounds.y; float terrainTopZ = meshMaxBounds.y; Collider buildingCollider = buildingInstance.GetComponent <Collider>(); Bounds buildingBounds = buildingCollider.bounds; Vector3 minBounds = buildingBounds.min; Vector3 maxBounds = buildingBounds.max; float buildingLeftX = minBounds.x; float buildingRightX = maxBounds.x; float buildingBottomZ = minBounds.z; float buildingTopZ = maxBounds.z; Vector3 currentBuildingPosition = meshVertex; if (buildingLeftX < terrainLeftX) { currentBuildingPosition.x += ((terrainLeftX - buildingLeftX) + safeBufferDistance); } else if (buildingRightX > terrainRightX) { currentBuildingPosition.x -= ((terrainRightX - buildingRightX) - safeBufferDistance); } if (buildingBottomZ < terrainBottomZ) { currentBuildingPosition.z += ((terrainBottomZ - buildingBottomZ) + safeBufferDistance); } else if (buildingTopZ > terrainTopZ) { currentBuildingPosition.z -= ((terrainTopZ - buildingTopZ) - safeBufferDistance); } buildingInstance.transform.position = currentBuildingPosition; var towerPointsParent = buildingInstance.transform.GetChild(0); var position = towerPointsParent.GetChild(randomCannonPoint).position; var towerInstance = Instantiate( towerPrefab, position, Quaternion.Euler(0, yRotation[randomCannonPoint], 0) ); towerInstance.transform.SetParent(buildingInstance.transform); }
//创建材质 static void CreateMat(TerrainData terrainData, ref TerrainMeshData meshdata, bool useAphla) { if (!Directory.Exists(ExportMatFolder)) { Directory.CreateDirectory(ExportMatFolder); } string pathMaterial = string.Format("{0}/{1}.mat", ExportMatFolder, terrainData.name.ToLower()); Shader shader = useAphla ? Shader.Find(TERRAIN_RGBA_SHADER) : Shader.Find(TERRAIN_RGB_SHADER); Material material = null; if (File.Exists(pathMaterial)) { material = AssetDatabase.LoadAssetAtPath <Material>(pathMaterial); } else { material = new Material(shader); } material.shader = shader; //设置基础纹理 for (int i = 0; i < terrainData.splatPrototypes.Length; ++i) { Texture2D splat = null; Vector2 scale = Vector2.zero; SplatPrototype sp = terrainData.splatPrototypes[i]; splat = sp.texture; scale = new Vector2(terrainData.size.x / sp.tileSize.x, terrainData.size.x / sp.tileSize.y); material.SetTexture("_Splat" + (i + 1), splat); material.SetTextureScale("_Splat" + (i + 1), scale); } //设置控制纹理 int baseMapCount = terrainData.splatPrototypes.Length; int crontrolMapCount = useAphla ? (int)(baseMapCount / 4f) : (baseMapCount % 3 == 0 ? baseMapCount / 3 : (int)(baseMapCount / 3f + 1)); for (int i = 0; i < crontrolMapCount; i++) { string name = terrainData.name.ToLower(); string texDir = string.Format("{0}/{1}", ExportTexFolder, name); string pathTexture = string.Format("{0}/{1}{2}_{3}.png", texDir, CONTROL_MAP_NAME, name, i); Texture2D textureControl = AssetDatabase.LoadAssetAtPath <Texture2D>(pathTexture); material.SetTexture("_Control" + (i + 1), textureControl); } if (File.Exists(pathMaterial)) { EditorUtility.SetDirty(material); AssetDatabase.SaveAssets(); } else { AssetDatabase.CreateAsset(material, pathMaterial); } meshdata.matIndex = matIndex; matIndex++; meshdata.material = material; AssetDatabase.ImportAsset(pathMaterial, ImportAssetOptions.ForceUpdate); }
public static TerrainMeshData GenerateMeshData(int size, LODInfo lodInfo, float[,] heightMap = null, float heightScale = 0, AnimationCurve heightCurve = null) { int lodStep = lodInfo.LodStep; int lodSize = lodInfo.LodSize(size); int triangleVertexCounter = 0; float halfSize = (lodSize - 1) / 2f; TerrainMeshData data = new TerrainMeshData(lodSize); AnimationCurve copyHeightCurve = null; if (heightCurve != null) { copyHeightCurve = new AnimationCurve(heightCurve.keys); } for (int z = 0; z < lodSize; z++) { for (int x = 0; x < lodSize; x++) { int vertexIndex = z * lodSize + x; float height = 0; if (heightMap != null) { float heightSample = heightMap[x * lodStep, z *lodStep]; height = heightSample * heightScale; if (copyHeightCurve != null) { height *= copyHeightCurve.Evaluate(heightSample); } } data.vertices[vertexIndex] = new Vector3((x - halfSize) * lodStep, height, (z - halfSize) * lodStep); data.uvs[vertexIndex] = new Vector2(x / (float)lodSize, z / (float)lodSize); if ((x < lodSize - 1) && (z < lodSize - 1)) { int triangleIndex = triangleVertexCounter * 6; data.triangles[triangleIndex] = vertexIndex; data.triangles[triangleIndex + 1] = vertexIndex + lodSize; data.triangles[triangleIndex + 2] = vertexIndex + lodSize + 1; data.triangles[triangleIndex + 3] = vertexIndex + lodSize + 1; data.triangles[triangleIndex + 4] = vertexIndex + 1; data.triangles[triangleIndex + 5] = vertexIndex; triangleVertexCounter++; } } } return(data); }
public void AddTerrainData(Vector3[] meshVertices, Vector3 meshCenter, Transform parent, Bounds meshBounds) { var meshData = new TerrainMeshData { vertices = meshVertices, meshCenter = meshCenter, parent = parent, meshBounds = meshBounds }; CheckAndCreateTowersAndBuildings(meshData); }
protected sealed override TerrainMeshData[] Task() { int meshCount = _referenceMeshData.Length; TerrainMeshData[] rescaledMeshData = new TerrainMeshData[meshCount]; for (int i = 0; i < meshCount; i++) { rescaledMeshData[i] = RescaleMeshHeight(_referenceMeshData[i]); } _progress = 1.0f; _rescaledMeshData = rescaledMeshData; return(_rescaledMeshData); }
TerrainMeshData GetTerrainMeshData(string name) { if (string.IsNullOrEmpty(name)) { return(null); } TerrainMeshData data = null; if (m_meshData.TryGetValue(name, out data)) { return(data); } data = LoadTerrainMeshData(name); data.Init(); m_meshData.Add(name, data); return(data); }
//采样高度信息 static void SamplingHeightMap(TerrainData terrainData, ref TerrainMeshData meshData) { meshData.indexes = new List <int>(); meshData.heights = new List <float>(); float[,] datas = terrainData.GetHeights(0, 0, terrainData.heightmapWidth, terrainData.heightmapHeight); for (int i = 0; i < terrainData.heightmapWidth; i++) { for (int j = 0; j < terrainData.heightmapHeight; j++) { float height = datas[i, j] * terrainData.size.y - TERRAIN_HEIGHT; if (height > 0.01 || height < -0.001) { int index = i * terrainData.heightmapWidth + j; meshData.indexes.Add(index); meshData.heights.Add(height); } } } }
public void SaveData() { if (string.IsNullOrEmpty(mapName)) { LogUtil.WriteWarning("Map name is null or empty. Setting to 'default'"); mapName = "default"; } Mesh terrainMesh = meshFilter.sharedMesh; TerrainMeshData data = new TerrainMeshData { vertices = terrainMesh.vertices, triangles = terrainMesh.triangles, colours = terrainMesh.colors, normals = terrainMesh.normals }; FileUtil.SaveAsJsonToResources("terrain_mesh_data_" + mapName, data); }
public static TerrainChunk GenerateTerrainMesh(float[,] heightMap, int levelOfDetail) { int width = heightMap.GetLength(0); int height = heightMap.GetLength(1); float topLeftX = (width - 1) / -2f; float topLeftZ = (height - 1) / 2f; int meshSimplificationIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2; int verticesPerLine = (width - 1) / meshSimplificationIncrement + 1; TerrainMeshData MeshData = new TerrainMeshData(verticesPerLine, verticesPerLine); for (int y = 0; y < height; y += meshSimplificationIncrement) { for (int x = 0; x < width; x += meshSimplificationIncrement) { // Add Vertex for this position (index of vertex is width*yPos + xPos) int vertexIndex = MeshData.AddVertex(topLeftX + x, heightMap[x, y], topLeftZ - y); // Add UV (relative position of vertex on the map) MeshData.AddUV(x / (float)width, y / (float)height); // Add the 2 triangles facing down right if we're not at the right or bottom border (because there are no more triangles facing bottom right) // Triangles are constructed clockwise! if (x < width - 1 && y < height - 1) { // Create Triangle that goes from current vertex (i) > vertex below right from current vertext (i+width+1) > vertex below current vertex (i+width) MeshData.AddTriangle(vertexIndex, vertexIndex + verticesPerLine + 1, vertexIndex + verticesPerLine); // Create Triangle that goes from vertex below right current vertex (i+width+1) > current vertex (i) > vertex right from current vertext (i+1) MeshData.AddTriangle(vertexIndex + verticesPerLine + 1, vertexIndex, vertexIndex + 1); } } } return(MeshData.CreateMesh()); }
public static TerrainMeshData GenerateTerrainMesh(float[,] heightMap, MeshSettings meshSettings, int levelOfDetail) { int skipIncrement = (levelOfDetail == 0)?1:levelOfDetail * 2; int numVertsPerLine = meshSettings.numVertsPerLine; Vector2 topLeft = new Vector2(-1, 1) * meshSettings.meshWorldSize / 2f; TerrainMeshData meshData = new TerrainMeshData(numVertsPerLine, skipIncrement, meshSettings.useFlatShading); int[,] vertexIndicesMap = new int[numVertsPerLine, numVertsPerLine]; int meshVertexIndex = 0; int outOfMeshVertexIndex = -1; for (int y = 0; y < numVertsPerLine; y++) { for (int x = 0; x < numVertsPerLine; x++) { bool isOutOfMeshVertex = y == 0 || y == numVertsPerLine - 1 || x == 0 || x == numVertsPerLine - 1; bool isSkippedVertex = x > 2 && x < numVertsPerLine - 3 && y > 2 && y < numVertsPerLine - 3 && ((x - 2) % skipIncrement != 0 || (y - 2) % skipIncrement != 0); if (isOutOfMeshVertex) { vertexIndicesMap [x, y] = outOfMeshVertexIndex; outOfMeshVertexIndex--; } else if (!isSkippedVertex) { vertexIndicesMap [x, y] = meshVertexIndex; meshVertexIndex++; } } } for (int y = 0; y < numVertsPerLine; y++) { for (int x = 0; x < numVertsPerLine; x++) { bool isSkippedVertex = x > 2 && x < numVertsPerLine - 3 && y > 2 && y < numVertsPerLine - 3 && ((x - 2) % skipIncrement != 0 || (y - 2) % skipIncrement != 0); if (!isSkippedVertex) { bool isOutOfMeshVertex = y == 0 || y == numVertsPerLine - 1 || x == 0 || x == numVertsPerLine - 1; bool isMeshEdgeVertex = (y == 1 || y == numVertsPerLine - 2 || x == 1 || x == numVertsPerLine - 2) && !isOutOfMeshVertex; bool isMainVertex = (x - 2) % skipIncrement == 0 && (y - 2) % skipIncrement == 0 && !isOutOfMeshVertex && !isMeshEdgeVertex; bool isEdgeConnectionVertex = (y == 2 || y == numVertsPerLine - 3 || x == 2 || x == numVertsPerLine - 3) && !isOutOfMeshVertex && !isMeshEdgeVertex && !isMainVertex; int vertexIndex = vertexIndicesMap [x, y]; Vector2 percent = new Vector2(x - 1, y - 1) / (numVertsPerLine - 3); Vector2 vertexPosition2D = topLeft + new Vector2(percent.x, -percent.y) * meshSettings.meshWorldSize; float height = heightMap [x, y]; if (isEdgeConnectionVertex) { bool isVertical = x == 2 || x == numVertsPerLine - 3; int dstToMainVertexA = ((isVertical)?y - 2:x - 2) % skipIncrement; int dstToMainVertexB = skipIncrement - dstToMainVertexA; float dstPercentFromAToB = dstToMainVertexA / (float)skipIncrement; float heightMainVertexA = heightMap [(isVertical) ? x : x - dstToMainVertexA, (isVertical) ? y - dstToMainVertexA : y]; float heightMainVertexB = heightMap [(isVertical) ? x : x + dstToMainVertexB, (isVertical) ? y + dstToMainVertexB : y]; height = heightMainVertexA * (1 - dstPercentFromAToB) + heightMainVertexB * dstPercentFromAToB; } meshData.AddVertex(new Vector3(vertexPosition2D.x, height, vertexPosition2D.y), percent, vertexIndex); bool createTriangle = x < numVertsPerLine - 1 && y < numVertsPerLine - 1 && (!isEdgeConnectionVertex || (x != 2 && y != 2)); if (createTriangle) { int currentIncrement = (isMainVertex && x != numVertsPerLine - 3 && y != numVertsPerLine - 3) ? skipIncrement : 1; int a = vertexIndicesMap [x, y]; int b = vertexIndicesMap [x + currentIncrement, y]; int c = vertexIndicesMap [x, y + currentIncrement]; int d = vertexIndicesMap [x + currentIncrement, y + currentIncrement]; meshData.AddTriangle(a, d, c); meshData.AddTriangle(d, a, b); } } } } meshData.ProcessMesh(); return(meshData); }
static void CreateTerrainRoot(TerrainAssets terrainAssets) { GameObject root = GameObject.Find(EXPORT_ROOT_NAME); GameObject.DestroyImmediate(root); root = new GameObject(EXPORT_ROOT_NAME); TerrainRoot hierarchy = root.AddComponent <TerrainRoot>(); GameObject go = new GameObject("Terrain"); go.transform.SetParent(root.transform); go.transform.localPosition = Vector3.zero; go.transform.localRotation = Quaternion.identity; go.transform.localScale = Vector3.one; //MeshFilter MeshFilter filter = go.GetComponent <MeshFilter>(); if (filter == null) { filter = go.AddComponent <MeshFilter>(); } //MeshRenderer MeshRenderer renderer = go.GetComponent <MeshRenderer>(); if (renderer == null) { renderer = go.AddComponent <MeshRenderer>(); } renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; //Material Dictionary <int, Material> matDic = new Dictionary <int, Material>(); for (int i = 0; i < terrainAssets.terrainIndex.Length; i++) { string terrainName = terrainAssets.terrainIndex[i]; if (string.IsNullOrEmpty(terrainName)) { continue; } string pathMeshData = string.Format("{0}/{1}.asset", MeshDataExportFolder, terrainAssets.terrainIndex[i]); TerrainMeshData meshData = GetStriptableObject <TerrainMeshData>(pathMeshData); if (!matDic.ContainsKey(meshData.matIndex)) { matDic.Add(meshData.matIndex, meshData.material); } } Material[] mats = new Material[matDic.Count]; foreach (var kv in matDic) { mats[kv.Key] = kv.Value; } renderer.sharedMaterials = mats; //BoxCollider BoxCollider collider = go.GetComponent <BoxCollider>(); if (collider == null) { collider = go.AddComponent <BoxCollider>(); } hierarchy.RootTerrain = go; string path = string.Format("{0}/TerrainRoot.prefab", ExportFolder); if (File.Exists(path)) { GameObject prefab = AssetDatabase.LoadAssetAtPath <GameObject>(path); PrefabUtility.ReplacePrefab(root, prefab); } else { PrefabUtility.CreatePrefab(path, root); } GameObject.DestroyImmediate(root); }
public void DrawMesh(TerrainMeshData meshData, Texture2D texture) { meshFilter.sharedMesh = meshData.CreateMesh(); meshRenderer.sharedMaterial.mainTexture = texture; }
public void DrawMeshOnly(TerrainMeshData meshData) { meshFilter.sharedMesh = meshData.CreateMesh(); }
protected override void BuildObject(IGameObject cellGameObject, Canvas canvas, Rule rule, TerrainMeshData meshData) { MeshData = meshData; meshData.GenerateObjectData(out Vertices, out Triangles, out Colors); }
/// <summary>Rescale the mesh data and store it in the member variable.</summary> protected abstract TerrainMeshData RescaleMeshHeight(TerrainMeshData referenceMeshData);