public static void MakeSharedChildrenMembers(SECTR_Sector sector, List<SECTR_Member.Child> sharedChildren, string undoName) { int numSharedChildren = sharedChildren.Count; for(int childIndex = 0; childIndex < numSharedChildren; ++childIndex) { SECTR_Member.Child child = sharedChildren[childIndex]; bool hasMemberParent = false; Transform parent = child.gameObject.transform; while(parent != null) { if(parent.gameObject != sector.gameObject && parent.GetComponent<SECTR_Member>()) { hasMemberParent = true; break; } else { parent = parent.parent; } } if(!hasMemberParent) { SECTR_Member newMember = child.gameObject.AddComponent<SECTR_Member>(); SECTR_Undo.Created(newMember, undoName); } } sector.ForceUpdate(true); }
public static void MakeSharedChildrenMembers(SECTR_Sector sector, List <SECTR_Member.Child> sharedChildren, string undoName) { int numSharedChildren = sharedChildren.Count; for (int childIndex = 0; childIndex < numSharedChildren; ++childIndex) { SECTR_Member.Child child = sharedChildren[childIndex]; bool hasMemberParent = false; Transform parent = child.gameObject.transform; while (parent != null) { if (parent.gameObject != sector.gameObject && parent.GetComponent <SECTR_Member>()) { hasMemberParent = true; break; } else { parent = parent.parent; } } if (!hasMemberParent) { SECTR_Member newMember = child.gameObject.AddComponent <SECTR_Member>(); SECTR_Undo.Created(newMember, undoName); } } sector.ForceUpdate(true); }
/// Re-adds the data from the specified Sector to the current scene. Safe to call from command line. /// <param name="sector">The Sector to import.</param> /// <returns>Returns true if Sector was successfully imported, false otherwise.</returns> public static bool ImportFromChunk(SECTR_Sector sector) { if (sector == null) { Debug.LogError("Cannot import invalid Sector."); return(false); } if (!sector.Frozen) { Debug.Log("Skipping import of unfrozen Sector"); return(true); } if (!sector.gameObject.isStatic) { Debug.Log("Skipping import of dynamic Sector " + sector.name + "."); return(true); } SECTR_Chunk chunk = sector.GetComponent <SECTR_Chunk>(); if (chunk) { EditorApplication.OpenSceneAdditive(chunk.NodeName); GameObject newNode = GameObject.Find(chunk.NodeName); if (newNode == null) { Debug.LogError("Exported data does not match scene. Skipping import of " + sector.name + "."); return(false); } SECTR_ChunkRef chunkRef = newNode.GetComponent <SECTR_ChunkRef>(); if (chunkRef && chunkRef.RealSector) { newNode = chunkRef.RealSector.gameObject; if (chunkRef.Recentered) { newNode.transform.parent = sector.transform; newNode.transform.localPosition = Vector3.zero; newNode.transform.localRotation = Quaternion.identity; newNode.transform.localScale = Vector3.one; } newNode.transform.parent = null; GameObject.DestroyImmediate(chunkRef.gameObject); } while (newNode.transform.childCount > 0) { newNode.transform.GetChild(0).parent = sector.transform; } // Merge lightmaps into the scene #if !UNITY_STREAM_ENLIGHTEN SECTR_LightmapRef newRef = newNode.GetComponent <SECTR_LightmapRef>(); if (newRef) { int numLightmaps = LightmapSettings.lightmaps.Length; LightmapData[] newLightmaps = new LightmapData[numLightmaps]; for (int lightmapIndex = 0; lightmapIndex < numLightmaps; ++lightmapIndex) { newLightmaps[lightmapIndex] = LightmapSettings.lightmaps[lightmapIndex]; } foreach (SECTR_LightmapRef.RefData refData in newRef.LightmapRefs) { if (refData.index >= 0 && refData.index < numLightmaps) { LightmapData newData = new LightmapData(); newData.lightmapNear = refData.NearLightmap; newData.lightmapFar = refData.FarLightmap; newLightmaps[refData.index] = newData; } } LightmapSettings.lightmaps = newLightmaps; #if !UNITY_4 foreach (SECTR_LightmapRef.RenderData indexData in newRef.LightmapRenderers) { if (indexData.renderer) { indexData.renderer.lightmapIndex = indexData.rendererLightmapIndex; indexData.renderer.lightmapScaleOffset = indexData.rendererLightmapScaleOffset; GameObjectUtility.SetStaticEditorFlags(indexData.renderer.gameObject, GameObjectUtility.GetStaticEditorFlags(indexData.renderer.gameObject) | StaticEditorFlags.BatchingStatic); } if (indexData.terrain) { indexData.terrain.lightmapIndex = indexData.terrainLightmapIndex; } } #endif GameObject.DestroyImmediate(newRef); } #endif // Copy terrain component specially because the generic routine doesn't work for some reason. Terrain terrain = newNode.GetComponent <Terrain>(); if (terrain) { Terrain terrainClone = sector.gameObject.AddComponent <Terrain>(); terrainClone.terrainData = terrain.terrainData; terrainClone.basemapDistance = terrain.basemapDistance; terrainClone.castShadows = terrain.castShadows; terrainClone.detailObjectDensity = terrain.detailObjectDensity; terrainClone.detailObjectDistance = terrain.detailObjectDistance; terrainClone.heightmapMaximumLOD = terrain.heightmapMaximumLOD; terrainClone.heightmapPixelError = terrain.heightmapPixelError; terrainClone.lightmapIndex = terrain.lightmapIndex; terrainClone.treeBillboardDistance = terrain.treeBillboardDistance; terrainClone.treeCrossFadeLength = terrain.treeCrossFadeLength; terrainClone.treeDistance = terrain.treeDistance; terrainClone.treeMaximumFullLODCount = terrain.treeMaximumFullLODCount; terrainClone.Flush(); } // Destroy the placeholder Member if there is one. // It's theoretically possible to have multiple members, so remove them all. SECTR_Member[] oldMembers = newNode.GetComponents <SECTR_Member>(); int numOldMembers = oldMembers.Length; for (int oldIndex = 0; oldIndex < numOldMembers; ++oldIndex) { GameObject.DestroyImmediate(oldMembers[oldIndex]); } // Copy all remaining components over Component[] remainingComponents = newNode.GetComponents <Component>(); int numRemaining = remainingComponents.Length; for (int componentIndex = 0; componentIndex < numRemaining; ++componentIndex) { Component component = remainingComponents[componentIndex]; if (component != newNode.transform && component.GetType() != typeof(Terrain)) { Component componentClone = sector.gameObject.AddComponent(component.GetType()); EditorUtility.CopySerialized(component, componentClone); } } // Enable a TerrainComposer node if there is one. MonoBehaviour terrainNeighbors = sector.GetComponent("TerrainNeighbors") as MonoBehaviour; if (terrainNeighbors) { terrainNeighbors.enabled = true; } GameObject.DestroyImmediate(newNode); sector.Frozen = false; sector.ForceUpdate(true); chunk.enabled = false; return(true); } return(false); }
private static void _SectorizeConnected(Terrain terrain, bool createPortalGeo, bool includeStatic, bool includeDynamic, Dictionary <Terrain, Terrain> processedTerrains, List <Transform> rootTransforms, List <Bounds> rootBounds) { if (terrain && !processedTerrains.ContainsKey(terrain)) { string undoString = "Sectorize Connected"; processedTerrains[terrain] = terrain; terrain.gameObject.isStatic = true; GameObject newSectorObject = new GameObject(terrain.name + " Sector"); newSectorObject.isStatic = true; newSectorObject.transform.parent = terrain.transform.parent; newSectorObject.transform.localPosition = terrain.transform.localPosition; newSectorObject.transform.localRotation = terrain.transform.localRotation; newSectorObject.transform.localScale = terrain.transform.localScale; terrain.transform.parent = newSectorObject.transform; SECTR_Sector newSector = newSectorObject.AddComponent <SECTR_Sector>(); newSector.ForceUpdate(true); SECTR_Undo.Created(newSectorObject, undoString); _Encapsulate(newSector, rootTransforms, rootBounds, undoString); Component terrainNeighbors = terrain.GetComponent("TerrainNeighbors"); if (terrainNeighbors) { System.Type neighborsType = terrainNeighbors.GetType(); Terrain topTerrain = neighborsType.GetField("top").GetValue(terrainNeighbors) as Terrain; if (topTerrain) { SECTR_Sector neighborSector = topTerrain.transform.parent ? topTerrain.transform.parent.GetComponent <SECTR_Sector>() : null; if (neighborSector) { newSector.TopTerrain = neighborSector; neighborSector.BottomTerrain = newSector; _CreatePortal(createPortalGeo, newSector, neighborSector, newSectorObject.transform.parent, undoString); } _SectorizeConnected(topTerrain, createPortalGeo, includeStatic, includeDynamic, processedTerrains, rootTransforms, rootBounds); } Terrain bottomTerrain = neighborsType.GetField("bottom").GetValue(terrainNeighbors) as Terrain; if (bottomTerrain) { SECTR_Sector neighborSector = bottomTerrain.transform.parent ? bottomTerrain.transform.parent.GetComponent <SECTR_Sector>() : null; if (neighborSector) { newSector.BottomTerrain = neighborSector; neighborSector.TopTerrain = newSector; _CreatePortal(createPortalGeo, newSector, neighborSector, newSectorObject.transform.parent, undoString); } _SectorizeConnected(bottomTerrain, createPortalGeo, includeStatic, includeDynamic, processedTerrains, rootTransforms, rootBounds); } Terrain leftTerrain = neighborsType.GetField("left").GetValue(terrainNeighbors) as Terrain; if (leftTerrain) { SECTR_Sector neighborSector = leftTerrain.transform.parent ? leftTerrain.transform.parent.GetComponent <SECTR_Sector>() : null; if (neighborSector) { newSector.LeftTerrain = neighborSector; neighborSector.RightTerrain = newSector; _CreatePortal(createPortalGeo, newSector, neighborSector, newSectorObject.transform.parent, undoString); } _SectorizeConnected(leftTerrain, createPortalGeo, includeStatic, includeDynamic, processedTerrains, rootTransforms, rootBounds); } Terrain rightTerrain = neighborsType.GetField("right").GetValue(terrainNeighbors) as Terrain; if (rightTerrain) { SECTR_Sector neighborSector = rightTerrain.transform.parent ? rightTerrain.transform.parent.GetComponent <SECTR_Sector>() : null; if (neighborSector) { newSector.RightTerrain = neighborSector; neighborSector.LeftTerrain = newSector; _CreatePortal(createPortalGeo, newSector, neighborSector, newSectorObject.transform.parent, undoString); } _SectorizeConnected(rightTerrain, createPortalGeo, includeStatic, includeDynamic, processedTerrains, rootTransforms, rootBounds); } } } }
public static void SectorizeTerrain(Terrain terrain, int sectorsWidth, int sectorsLength, int sectorsHeight, bool splitTerrain, bool createPortalGeo, bool includeStatic, bool includeDynamic) { if (!terrain) { Debug.LogWarning("Cannot sectorize null terrain."); return; } if (terrain.transform.root.GetComponentsInChildren <SECTR_Sector>().Length > 0) { Debug.LogWarning("Cannot sectorize terrain that is already part of a Sector."); } string undoString = "Sectorized " + terrain.name; if (sectorsWidth == 1 && sectorsLength == 1) { SECTR_Sector newSector = terrain.gameObject.AddComponent <SECTR_Sector>(); SECTR_Undo.Created(newSector, undoString); newSector.ForceUpdate(true); return; } if (splitTerrain && (!Mathf.IsPowerOfTwo(sectorsWidth) || !Mathf.IsPowerOfTwo(sectorsLength))) { Debug.LogWarning("Splitting terrain requires power of two sectors in width and length."); splitTerrain = false; } else if (splitTerrain && sectorsWidth != sectorsLength) { Debug.LogWarning("Splitting terrain requires same number of sectors in width and length."); splitTerrain = false; } int terrainLayer = terrain.gameObject.layer; Vector3 terrainSize = terrain.terrainData.size; float sectorWidth = terrainSize.x / sectorsWidth; float sectorHeight = terrainSize.y / sectorsHeight; float sectorLength = terrainSize.z / sectorsLength; int heightmapWidth = (terrain.terrainData.heightmapWidth / sectorsWidth); int heightmapLength = (terrain.terrainData.heightmapHeight / sectorsLength); int alphaWidth = terrain.terrainData.alphamapWidth / sectorsWidth; int alphaLength = terrain.terrainData.alphamapHeight / sectorsLength; int detailWidth = terrain.terrainData.detailWidth / sectorsWidth; int detailLength = terrain.terrainData.detailHeight / sectorsLength; string sceneDir = ""; string sceneName = ""; string exportFolder = splitTerrain ? SECTR_Asset.MakeExportFolder("TerrainSplits", false, out sceneDir, out sceneName) : ""; Transform baseTransform = null; if (splitTerrain) { GameObject baseObject = new GameObject(terrain.name); baseTransform = baseObject.transform; SECTR_Undo.Created(baseObject, undoString); } List <Transform> rootTransforms = new List <Transform>(); List <Bounds> rootBounds = new List <Bounds>(); _GetRoots(includeStatic, includeDynamic, rootTransforms, rootBounds); // Create Sectors string progressTitle = "Sectorizing Terrain"; int progressCounter = 0; EditorUtility.DisplayProgressBar(progressTitle, "Preparing", 0); SECTR_Sector[,,] newSectors = new SECTR_Sector[sectorsWidth, sectorsLength, sectorsHeight]; Terrain[,] newTerrains = splitTerrain ? new Terrain[sectorsWidth, sectorsLength] : null; for (int widthIndex = 0; widthIndex < sectorsWidth; ++widthIndex) { for (int lengthIndex = 0; lengthIndex < sectorsLength; ++lengthIndex) { for (int heightIndex = 0; heightIndex < sectorsHeight; ++heightIndex) { string newName = terrain.name + " " + widthIndex + "-" + lengthIndex + "-" + heightIndex; EditorUtility.DisplayProgressBar(progressTitle, "Creating sector " + newName, progressCounter++ / (float)(sectorsWidth * sectorsLength * sectorsHeight)); GameObject newSectorObject = new GameObject("SECTR " + newName + " Sector"); newSectorObject.transform.parent = baseTransform; Vector3 sectorCorner = new Vector3(widthIndex * sectorWidth, heightIndex * sectorHeight, lengthIndex * sectorLength) + terrain.transform.position; newSectorObject.transform.position = sectorCorner; newSectorObject.isStatic = true; SECTR_Sector newSector = newSectorObject.AddComponent <SECTR_Sector>(); newSector.OverrideBounds = !splitTerrain && (sectorsWidth > 1 || sectorsLength > 1); newSector.BoundsOverride = new Bounds(sectorCorner + new Vector3(sectorWidth * 0.5f, sectorHeight * 0.5f, sectorLength * 0.5f), new Vector3(sectorWidth, sectorHeight, sectorLength)); newSectors[widthIndex, lengthIndex, heightIndex] = newSector; if (splitTerrain && heightIndex == 0) { GameObject newTerrainObject = new GameObject(newName + " Terrain"); newTerrainObject.layer = terrainLayer; newTerrainObject.tag = terrain.tag; newTerrainObject.transform.parent = newSectorObject.transform; newTerrainObject.transform.localPosition = Vector3.zero; newTerrainObject.transform.localRotation = Quaternion.identity; newTerrainObject.transform.localScale = Vector3.one; newTerrainObject.isStatic = true; Terrain newTerrain = newTerrainObject.AddComponent <Terrain>(); newTerrain.terrainData = SECTR_Asset.Create <TerrainData>(exportFolder, newName, new TerrainData()); EditorUtility.SetDirty(newTerrain.terrainData); SECTR_VC.WaitForVC(); // Copy properties // Basic terrain properties newTerrain.editorRenderFlags = terrain.editorRenderFlags; newTerrain.castShadows = terrain.castShadows; newTerrain.heightmapMaximumLOD = terrain.heightmapMaximumLOD; newTerrain.heightmapPixelError = terrain.heightmapPixelError; newTerrain.lightmapIndex = -1; // Can't set lightmap UVs on terrain. newTerrain.materialTemplate = terrain.materialTemplate; #if !UNITY_4 newTerrain.bakeLightProbesForTrees = terrain.bakeLightProbesForTrees; newTerrain.legacyShininess = terrain.legacyShininess; newTerrain.legacySpecular = terrain.legacySpecular; #endif // Copy geometric data int heightmapBaseX = widthIndex * heightmapWidth; int heightmapBaseY = lengthIndex * heightmapLength; int heightmapWidthX = heightmapWidth + (sectorsWidth > 1 ? 1 : 0); int heightmapWidthY = heightmapLength + (sectorsLength > 1 ? 1 : 0); newTerrain.terrainData.heightmapResolution = terrain.terrainData.heightmapResolution / sectorsWidth; newTerrain.terrainData.size = new Vector3(sectorWidth, terrainSize.y, sectorLength); newTerrain.terrainData.SetHeights(0, 0, terrain.terrainData.GetHeights(heightmapBaseX, heightmapBaseY, heightmapWidthX, heightmapWidthY)); #if !UNITY_4 newTerrain.terrainData.thickness = terrain.terrainData.thickness; #endif // Copy alpha maps int alphaBaseX = alphaWidth * widthIndex; int alphaBaseY = alphaLength * lengthIndex; newTerrain.terrainData.splatPrototypes = terrain.terrainData.splatPrototypes; newTerrain.basemapDistance = terrain.basemapDistance; newTerrain.terrainData.baseMapResolution = terrain.terrainData.baseMapResolution / sectorsWidth; newTerrain.terrainData.alphamapResolution = terrain.terrainData.alphamapResolution / sectorsWidth; newTerrain.terrainData.SetAlphamaps(0, 0, terrain.terrainData.GetAlphamaps(alphaBaseX, alphaBaseY, alphaWidth, alphaLength)); // Copy detail info newTerrain.detailObjectDensity = terrain.detailObjectDensity; newTerrain.detailObjectDistance = terrain.detailObjectDistance; newTerrain.terrainData.detailPrototypes = terrain.terrainData.detailPrototypes; newTerrain.terrainData.SetDetailResolution(terrain.terrainData.detailResolution / sectorsWidth, 8); // TODO: extract detailResolutionPerPatch #if !UNITY_4 newTerrain.collectDetailPatches = terrain.collectDetailPatches; #endif int detailBaseX = detailWidth * widthIndex; int detailBaseY = detailLength * lengthIndex; int numLayers = terrain.terrainData.detailPrototypes.Length; for (int layer = 0; layer < numLayers; ++layer) { newTerrain.terrainData.SetDetailLayer(0, 0, layer, terrain.terrainData.GetDetailLayer(detailBaseX, detailBaseY, detailWidth, detailLength, layer)); } // Copy grass and trees newTerrain.terrainData.wavingGrassAmount = terrain.terrainData.wavingGrassAmount; newTerrain.terrainData.wavingGrassSpeed = terrain.terrainData.wavingGrassSpeed; newTerrain.terrainData.wavingGrassStrength = terrain.terrainData.wavingGrassStrength; newTerrain.terrainData.wavingGrassTint = terrain.terrainData.wavingGrassTint; newTerrain.treeBillboardDistance = terrain.treeBillboardDistance; newTerrain.treeCrossFadeLength = terrain.treeCrossFadeLength; newTerrain.treeDistance = terrain.treeDistance; newTerrain.treeMaximumFullLODCount = terrain.treeMaximumFullLODCount; newTerrain.terrainData.treePrototypes = terrain.terrainData.treePrototypes; newTerrain.terrainData.RefreshPrototypes(); foreach (TreeInstance treeInstace in terrain.terrainData.treeInstances) { if (treeInstace.prototypeIndex >= 0 && treeInstace.prototypeIndex < newTerrain.terrainData.treePrototypes.Length && newTerrain.terrainData.treePrototypes[treeInstace.prototypeIndex].prefab) { Vector3 worldSpaceTreePos = Vector3.Scale(treeInstace.position, terrainSize) + terrain.transform.position; if (newSector.BoundsOverride.Contains(worldSpaceTreePos)) { Vector3 localSpaceTreePos = new Vector3((worldSpaceTreePos.x - newTerrain.transform.position.x) / sectorWidth, treeInstace.position.y, (worldSpaceTreePos.z - newTerrain.transform.position.z) / sectorLength); TreeInstance newInstance = treeInstace; newInstance.position = localSpaceTreePos; newTerrain.AddTreeInstance(newInstance); } } } // Copy physics #if UNITY_4_LATE newTerrain.terrainData.physicMaterial = terrain.terrainData.physicMaterial; #endif // Force terrain to rebuild newTerrain.Flush(); UnityEditor.EditorUtility.SetDirty(newTerrain.terrainData); SECTR_VC.WaitForVC(); newTerrain.enabled = false; newTerrain.enabled = true; TerrainCollider terrainCollider = terrain.GetComponent <TerrainCollider>(); if (terrainCollider) { TerrainCollider newCollider = newTerrainObject.AddComponent <TerrainCollider>(); #if !UNITY_4_LATE newCollider.sharedMaterial = terrainCollider.sharedMaterial; #endif newCollider.terrainData = newTerrain.terrainData; } newTerrains[widthIndex, lengthIndex] = newTerrain; SECTR_Undo.Created(newTerrainObject, undoString); } newSector.ForceUpdate(true); SECTR_Undo.Created(newSectorObject, undoString); _Encapsulate(newSector, rootTransforms, rootBounds, undoString); } } } // Create portals and neighbors progressCounter = 0; for (int widthIndex = 0; widthIndex < sectorsWidth; ++widthIndex) { for (int lengthIndex = 0; lengthIndex < sectorsLength; ++lengthIndex) { for (int heightIndex = 0; heightIndex < sectorsHeight; ++heightIndex) { EditorUtility.DisplayProgressBar(progressTitle, "Creating portals...", progressCounter++ / (float)(sectorsWidth * sectorsLength * sectorsHeight)); if (widthIndex < sectorsWidth - 1) { _CreatePortal(createPortalGeo, newSectors[widthIndex + 1, lengthIndex, heightIndex], newSectors[widthIndex, lengthIndex, heightIndex], baseTransform, undoString); } if (lengthIndex < sectorsLength - 1) { _CreatePortal(createPortalGeo, newSectors[widthIndex, lengthIndex + 1, heightIndex], newSectors[widthIndex, lengthIndex, heightIndex], baseTransform, undoString); } if (heightIndex > 0) { _CreatePortal(createPortalGeo, newSectors[widthIndex, lengthIndex, heightIndex], newSectors[widthIndex, lengthIndex, heightIndex - 1], baseTransform, undoString); } } } } if (splitTerrain) { progressCounter = 0; for (int widthIndex = 0; widthIndex < sectorsWidth; ++widthIndex) { for (int lengthIndex = 0; lengthIndex < sectorsLength; ++lengthIndex) { EditorUtility.DisplayProgressBar(progressTitle, "Smoothing split terrain...", progressCounter++ / (float)(sectorsWidth * sectorsLength * sectorsHeight)); // Blend together the seams of the alpha maps, which requires // going through all of the mip maps of all of the layer textures. // We have to blend here rather than when we set the alpha data (above) // because Unity computes mips and we need to blend all of the mips. Terrain newTerrain = newTerrains[widthIndex, lengthIndex]; SECTR_Sector terrainSector = newSectors[widthIndex, lengthIndex, 0]; terrainSector.LeftTerrain = widthIndex > 0 ? newSectors[widthIndex - 1, lengthIndex, 0] : null; terrainSector.RightTerrain = widthIndex < sectorsWidth - 1 ? newSectors[widthIndex + 1, lengthIndex, 0] : null; terrainSector.BottomTerrain = lengthIndex > 0 ? newSectors[widthIndex, lengthIndex - 1, 0] : null; terrainSector.TopTerrain = lengthIndex < sectorsLength - 1 ? newSectors[widthIndex, lengthIndex + 1, 0] : null; terrainSector.ConnectTerrainNeighbors(); // Use reflection trickery to get at the raw texture values. System.Reflection.PropertyInfo alphamapProperty = newTerrain.terrainData.GetType().GetProperty("alphamapTextures", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Static); // Get the texture we'll write into Texture2D[] alphaTextures = (Texture2D[])alphamapProperty.GetValue(newTerrain.terrainData, null); int numTextures = alphaTextures.Length; // Get the textures we'll read from Texture2D[] leftNeighborTextures = terrainSector.LeftTerrain != null ? (Texture2D[])alphamapProperty.GetValue(newTerrains[widthIndex - 1, lengthIndex].terrainData, null) : null; Texture2D[] rightNeighborTextures = terrainSector.RightTerrain != null ? (Texture2D[])alphamapProperty.GetValue(newTerrains[widthIndex + 1, lengthIndex].terrainData, null) : null; Texture2D[] topNeighborTextures = terrainSector.TopTerrain != null ? (Texture2D[])alphamapProperty.GetValue(newTerrains[widthIndex, lengthIndex + 1].terrainData, null) : null; Texture2D[] bottomNeighborTextures = terrainSector.BottomTerrain != null ? (Texture2D[])alphamapProperty.GetValue(newTerrains[widthIndex, lengthIndex - 1].terrainData, null) : null; for (int textureIndex = 0; textureIndex < numTextures; ++textureIndex) { Texture2D alphaTexture = alphaTextures[textureIndex]; Texture2D leftTexture = leftNeighborTextures != null ? leftNeighborTextures[textureIndex] : null; Texture2D rightTexture = rightNeighborTextures != null ? rightNeighborTextures[textureIndex] : null; Texture2D topTexture = topNeighborTextures != null ? topNeighborTextures[textureIndex] : null; Texture2D bottomTexture = bottomNeighborTextures != null ? bottomNeighborTextures[textureIndex] : null; int numMips = alphaTexture.mipmapCount; for (int mipIndex = 0; mipIndex < numMips; ++mipIndex) { Color[] alphaTexels = alphaTexture.GetPixels(mipIndex); int width = (int)Mathf.Sqrt(alphaTexels.Length); int height = width; for (int texelWidthIndex = 0; texelWidthIndex < width; ++texelWidthIndex) { for (int texelHeightIndex = 0; texelHeightIndex < height; ++texelHeightIndex) { // We can take advantage of the build order to average on the leading edges (right and top) // and then copy form the trailing edges (left and bottom) if (texelWidthIndex == 0 && leftTexture) { Color[] neighborTexels = leftTexture.GetPixels(mipIndex); alphaTexels[texelWidthIndex + texelHeightIndex * width] = neighborTexels[(width - 1) + (texelHeightIndex * width)]; } else if (texelWidthIndex == width - 1 && rightTexture) { Color[] neighborTexels = rightTexture.GetPixels(mipIndex); alphaTexels[texelWidthIndex + texelHeightIndex * width] += neighborTexels[0 + (texelHeightIndex * width)]; alphaTexels[texelWidthIndex + texelHeightIndex * width] *= 0.5f; } else if (texelHeightIndex == 0 && bottomTexture) { Color[] neighborTexels = bottomTexture.GetPixels(mipIndex); alphaTexels[texelWidthIndex + texelHeightIndex * width] = neighborTexels[texelWidthIndex + ((height - 1) * width)]; } else if (texelHeightIndex == height - 1 && topTexture) { Color[] neighborTexels = topTexture.GetPixels(mipIndex); alphaTexels[texelWidthIndex + texelHeightIndex * width] += neighborTexels[texelWidthIndex + (0 * width)]; alphaTexels[texelWidthIndex + texelHeightIndex * width] *= 0.5f; } } } alphaTexture.SetPixels(alphaTexels, mipIndex); } alphaTexture.wrapMode = TextureWrapMode.Clamp; alphaTexture.Apply(false); } newTerrain.Flush(); } } } EditorUtility.ClearProgressBar(); // destroy original terrain if (splitTerrain) { SECTR_Undo.Destroy(terrain.gameObject, undoString); } }