public void ScatterHeightmap(string editorUndoName) { var blitMaterial = TerrainPaintUtility.GetHeightBlitMaterial(); blitMaterial.SetFloat("_Height_Offset", 0.0f); blitMaterial.SetFloat("_Height_Scale", 1.0f); ScatterInternal( t => t.terrain.terrainData.heightmapTexture, "PaintContext.ScatterHeightmap", blitMaterial: blitMaterial, beforeBlit: t => { onTerrainTileBeforePaint?.Invoke(t, ToolAction.PaintHeightmap, editorUndoName); blitMaterial.SetFloat("_Height_Offset", (heightWorldSpaceMin - t.terrain.GetPosition().y) / t.terrain.terrainData.size.y * kNormalizedHeightScale); blitMaterial.SetFloat("_Height_Scale", heightWorldSpaceSize / t.terrain.terrainData.size.y); }, afterBlit: t => { t.terrain.terrainData.DirtyHeightmapRegion(t.clippedTerrainPixels, t.terrain.drawInstanced ? TerrainHeightmapSyncControl.None : TerrainHeightmapSyncControl.HeightOnly); OnTerrainPainted(t, ToolAction.PaintHeightmap); }); }
public void ScatterAlphamap(string editorUndoName) { Vector4[] layerMasks = { new Vector4(1, 0, 0, 0), new Vector4(0, 1, 0, 0), new Vector4(0, 0, 1, 0), new Vector4(0, 0, 0, 1) }; Material copyTerrainLayerMaterial = TerrainPaintUtility.GetCopyTerrainLayerMaterial(); var rtdesc = new RenderTextureDescriptor(destinationRenderTexture.width, destinationRenderTexture.height, RenderTextureFormat.ARGB32); rtdesc.sRGB = false; rtdesc.useMipMap = false; rtdesc.autoGenerateMips = false; RenderTexture tempTarget = RenderTexture.GetTemporary(rtdesc); ScatterInternal( t => // We're going to do ALL of the work in this terrainToRT function, as it is very custom, and we'll just return null to skip the ScatterInternal rendering { SplatmapUserData userData = GetTerrainLayerUserData(t); if (userData != null) { onTerrainTileBeforePaint?.Invoke(t, ToolAction.PaintTexture, editorUndoName); int targetAlphamapIndex = userData.mapIndex; int targetChannelIndex = userData.channelIndex; Texture2D targetAlphamapTexture = t.terrain.terrainData.alphamapTextures[targetAlphamapIndex]; destinationRenderTexture.filterMode = FilterMode.Point; sourceRenderTexture.filterMode = FilterMode.Point; // iterate all alphamaps to modify them (have to modify all to renormalize) for (int i = 0; i <= t.terrain.terrainData.alphamapTextureCount; i++) // NOTE: this is a non-standard for loop { // modify the target index last, (skip it the first time) if (i == targetAlphamapIndex) { continue; } int alphamapIndex = (i == t.terrain.terrainData.alphamapTextureCount) ? targetAlphamapIndex : i; Texture2D alphamapTexture = t.terrain.terrainData.alphamapTextures[alphamapIndex]; if ((alphamapTexture.width != targetTextureWidth) || (alphamapTexture.height != targetTextureHeight)) { Debug.LogWarning("PaintContext alphamap operations must use the same resolution for all Terrains - mismatched Terrains are ignored.", t.terrain); continue; } RenderTexture.active = tempTarget; GL.PushMatrix(); GL.LoadPixelMatrix(0, tempTarget.width, 0, tempTarget.height); { copyTerrainLayerMaterial.SetTexture("_MainTex", destinationRenderTexture); copyTerrainLayerMaterial.SetTexture("_OldAlphaMapTexture", sourceRenderTexture); copyTerrainLayerMaterial.SetTexture("_OriginalTargetAlphaMap", targetAlphamapTexture); copyTerrainLayerMaterial.SetTexture("_AlphaMapTexture", alphamapTexture); copyTerrainLayerMaterial.SetVector("_LayerMask", alphamapIndex == targetAlphamapIndex ? layerMasks[targetChannelIndex] : Vector4.zero); copyTerrainLayerMaterial.SetVector("_OriginalTargetAlphaMask", layerMasks[targetChannelIndex]); copyTerrainLayerMaterial.SetPass(1); TerrainPaintUtility.DrawQuad2(t.clippedPCPixels, t.clippedPCPixels, destinationRenderTexture, t.clippedTerrainPixels, alphamapTexture); } GL.PopMatrix(); t.terrain.terrainData.CopyActiveRenderTextureToTexture(TerrainData.AlphamapTextureName, alphamapIndex, t.clippedPCPixels, t.clippedTerrainPixels.min, true); } RenderTexture.active = null; OnTerrainPainted(t, ToolAction.PaintTexture); } return(null); }, "PaintContext.ScatterAlphamap", copyTerrainLayerMaterial, 0); RenderTexture.ReleaseTemporary(tempTarget); }
private void ScatterInternal( Func <ITerrainInfo, RenderTexture> terrainToRT, string operationName, Material blitMaterial = null, int blitPass = 0, Action <ITerrainInfo> beforeBlit = null, Action <ITerrainInfo> afterBlit = null) { var oldRT = RenderTexture.active; if (blitMaterial == null) { blitMaterial = TerrainPaintUtility.GetBlitMaterial(); } for (int i = 0; i < m_TerrainTiles.Count; i++) { TerrainTile terrainTile = m_TerrainTiles[i]; if (!terrainTile.scatterEnable) { continue; } RenderTexture target = terrainToRT(terrainTile); if ((target == null) || (!terrainTile.scatterEnable)) // double check scatterEnable in case terrainToRT modified it { continue; } if ((target.width != targetTextureWidth) || (target.height != targetTextureHeight)) { Debug.LogWarning(operationName + " requires the same resolution for all Terrains - mismatched Terrains are ignored.", terrainTile.terrain); continue; } beforeBlit?.Invoke(terrainTile); if (!terrainTile.scatterEnable) // check again, beforeBlit may have modified it { continue; } RenderTexture.active = target; GL.PushMatrix(); GL.LoadPixelMatrix(0, target.width, 0, target.height); { FilterMode oldFilterMode = destinationRenderTexture.filterMode; destinationRenderTexture.filterMode = FilterMode.Point; blitMaterial.SetTexture("_MainTex", destinationRenderTexture); blitMaterial.SetPass(blitPass); TerrainPaintUtility.DrawQuad(terrainTile.clippedTerrainPixels, terrainTile.clippedPCPixels, destinationRenderTexture); destinationRenderTexture.filterMode = oldFilterMode; } GL.PopMatrix(); afterBlit?.Invoke(terrainTile); } RenderTexture.active = oldRT; }
public void ScatterAlphamap(string editorUndoName) { Vector4[] layerMasks = { new Vector4(1, 0, 0, 0), new Vector4(0, 1, 0, 0), new Vector4(0, 0, 1, 0), new Vector4(0, 0, 0, 1) }; Material copyTerrainLayerMaterial = TerrainPaintUtility.GetCopyTerrainLayerMaterial(); for (int i = 0; i < m_TerrainTiles.Count; i++) { TerrainTile terrainTile = m_TerrainTiles[i]; if (terrainTile.clippedLocalPixels.width == 0 || terrainTile.clippedLocalPixels.height == 0) { continue; } if (onTerrainTileBeforePaint != null) { onTerrainTileBeforePaint(terrainTile, ToolAction.PaintTexture, editorUndoName); } var rtdesc = new RenderTextureDescriptor(destinationRenderTexture.width, destinationRenderTexture.height, RenderTextureFormat.ARGB32); rtdesc.sRGB = false; rtdesc.useMipMap = false; rtdesc.autoGenerateMips = false; RenderTexture destTarget = RenderTexture.GetTemporary(rtdesc); RenderTexture.active = destTarget; RectInt writeRect = terrainTile.clippedPCPixels; Rect readRect = new Rect( writeRect.x / (float)pixelRect.width, writeRect.y / (float)pixelRect.height, writeRect.width / (float)pixelRect.width, writeRect.height / (float)pixelRect.height); destinationRenderTexture.filterMode = FilterMode.Point; int mapIndex = terrainTile.mapIndex; int channelIndex = terrainTile.channelIndex; Texture2D sourceTexTargetChannel = terrainTile.terrain.terrainData.alphamapTextures[mapIndex]; for (int j = 0; j < terrainTile.terrain.terrainData.alphamapTextureCount; j++) { Texture2D sourceTex = terrainTile.terrain.terrainData.alphamapTextures[j]; if ((sourceTex.width != targetTextureWidth) || (sourceTex.height != targetTextureHeight)) { Debug.LogWarning("PaintContext alphamap operations must use the same resolution for all Terrains - mismatched Terrains are ignored.", terrainTile.terrain); continue; } Rect combineRect = new Rect( terrainTile.clippedLocalPixels.x / (float)sourceTex.width, terrainTile.clippedLocalPixels.y / (float)sourceTex.height, terrainTile.clippedLocalPixels.width / (float)sourceTex.width, terrainTile.clippedLocalPixels.height / (float)sourceTex.height); copyTerrainLayerMaterial.SetTexture("_MainTex", destinationRenderTexture); copyTerrainLayerMaterial.SetTexture("_OldAlphaMapTexture", sourceRenderTexture); copyTerrainLayerMaterial.SetTexture("_OriginalTargetAlphaMap", sourceTexTargetChannel); copyTerrainLayerMaterial.SetTexture("_AlphaMapTexture", sourceTex); copyTerrainLayerMaterial.SetVector("_LayerMask", j == mapIndex ? layerMasks[channelIndex] : Vector4.zero); copyTerrainLayerMaterial.SetVector("_OriginalTargetAlphaMask", layerMasks[channelIndex]); copyTerrainLayerMaterial.SetPass(1); GL.PushMatrix(); GL.LoadPixelMatrix(0, destTarget.width, 0, destTarget.height); GL.Begin(GL.QUADS); GL.Color(new Color(1.0f, 1.0f, 1.0f, 1.0f)); GL.MultiTexCoord2(0, readRect.x, readRect.y); GL.MultiTexCoord2(1, combineRect.x, combineRect.y); GL.Vertex3(writeRect.x, writeRect.y, 0.0f); GL.MultiTexCoord2(0, readRect.x, readRect.yMax); GL.MultiTexCoord2(1, combineRect.x, combineRect.yMax); GL.Vertex3(writeRect.x, writeRect.yMax, 0.0f); GL.MultiTexCoord2(0, readRect.xMax, readRect.yMax); GL.MultiTexCoord2(1, combineRect.xMax, combineRect.yMax); GL.Vertex3(writeRect.xMax, writeRect.yMax, 0.0f); GL.MultiTexCoord2(0, readRect.xMax, readRect.y); GL.MultiTexCoord2(1, combineRect.xMax, combineRect.y); GL.Vertex3(writeRect.xMax, writeRect.y, 0.0f); GL.End(); GL.PopMatrix(); if (TerrainPaintUtility.paintTextureUsesCopyTexture) { var rtdesc2 = new RenderTextureDescriptor(sourceTex.width, sourceTex.height, RenderTextureFormat.ARGB32); rtdesc2.sRGB = false; rtdesc2.useMipMap = true; rtdesc2.autoGenerateMips = false; var mips = RenderTexture.GetTemporary(rtdesc2); if (!mips.IsCreated()) { mips.Create(); } // Composes mip0 in a RT with full mipchain. Graphics.CopyTexture(sourceTex, 0, 0, mips, 0, 0); Graphics.CopyTexture(destTarget, 0, 0, writeRect.x, writeRect.y, writeRect.width, writeRect.height, mips, 0, 0, terrainTile.clippedLocalPixels.x, terrainTile.clippedLocalPixels.y); mips.GenerateMips(); // Copy them into sourceTex. Graphics.CopyTexture(mips, sourceTex); RenderTexture.ReleaseTemporary(mips); } else { GraphicsDeviceType deviceType = SystemInfo.graphicsDeviceType; if (deviceType == GraphicsDeviceType.Metal || deviceType == GraphicsDeviceType.OpenGLCore) { sourceTex.ReadPixels(new Rect(writeRect.x, writeRect.y, writeRect.width, writeRect.height), terrainTile.clippedLocalPixels.x, terrainTile.clippedLocalPixels.y); } else { sourceTex.ReadPixels(new Rect(writeRect.x, destTarget.height - writeRect.y - writeRect.height, writeRect.width, writeRect.height), terrainTile.clippedLocalPixels.x, terrainTile.clippedLocalPixels.y); } sourceTex.Apply(); } } RenderTexture.active = null; RenderTexture.ReleaseTemporary(destTarget); OnTerrainPainted(terrainTile, ToolAction.PaintTexture); } }
public void GatherAlphamap(TerrainLayer inputLayer, bool addLayerIfDoesntExist = true) { if (inputLayer == null) { return; } int terrainLayerIndex = TerrainPaintUtility.FindTerrainLayerIndex(originTerrain, inputLayer); if (terrainLayerIndex == -1 && addLayerIfDoesntExist) { terrainLayerIndex = TerrainPaintUtility.AddTerrainLayer(originTerrain, inputLayer); } RenderTexture.active = sourceRenderTexture; GL.Clear(false, true, new Color(0.0f, 0.0f, 0.0f, 0.0f)); GL.PushMatrix(); GL.LoadPixelMatrix(0, pixelRect.width, 0, pixelRect.height); Vector4[] layerMasks = { new Vector4(1, 0, 0, 0), new Vector4(0, 1, 0, 0), new Vector4(0, 0, 1, 0), new Vector4(0, 0, 0, 1) }; Material copyTerrainLayerMaterial = TerrainPaintUtility.GetCopyTerrainLayerMaterial(); for (int i = 0; i < m_TerrainTiles.Count; i++) { TerrainTile terrainTile = m_TerrainTiles[i]; if (terrainTile.clippedLocalPixels.width == 0 || terrainTile.clippedLocalPixels.height == 0) { continue; } int tileLayerIndex = TerrainPaintUtility.FindTerrainLayerIndex(terrainTile.terrain, inputLayer); if (tileLayerIndex == -1) { if (!addLayerIfDoesntExist) { // setting these to zero will prevent them from being used later terrainTile.clippedLocalPixels.width = 0; terrainTile.clippedLocalPixels.height = 0; terrainTile.clippedPCPixels.width = 0; terrainTile.clippedPCPixels.height = 0; continue; } tileLayerIndex = TerrainPaintUtility.AddTerrainLayer(terrainTile.terrain, inputLayer); } terrainTile.mapIndex = tileLayerIndex >> 2; terrainTile.channelIndex = tileLayerIndex & 0x3; Texture sourceTexture = TerrainPaintUtility.GetTerrainAlphaMapChecked(terrainTile.terrain, terrainTile.mapIndex); if ((sourceTexture.width != targetTextureWidth) || (sourceTexture.height != targetTextureHeight)) { Debug.LogWarning("PaintContext alphamap operations must use the same resolution for all Terrains - mismatched Terrains are ignored. (" + sourceTexture.width + " x " + sourceTexture.height + ") != (" + targetTextureWidth + " x " + targetTextureHeight + ")", terrainTile.terrain); continue; } FilterMode oldFilterMode = sourceTexture.filterMode; sourceTexture.filterMode = FilterMode.Point; copyTerrainLayerMaterial.SetVector("_LayerMask", layerMasks[terrainTile.channelIndex]); copyTerrainLayerMaterial.SetTexture("_MainTex", sourceTexture); copyTerrainLayerMaterial.SetPass(0); TerrainPaintUtility.DrawQuad(terrainTile.clippedPCPixels, terrainTile.clippedLocalPixels, sourceTexture); sourceTexture.filterMode = oldFilterMode; } GL.PopMatrix(); RenderTexture.active = oldRenderTexture; }
public void ScatterAlphamap(string editorUndoName) { Vector4[] layerMasks = { new Vector4(1, 0, 0, 0), new Vector4(0, 1, 0, 0), new Vector4(0, 0, 1, 0), new Vector4(0, 0, 0, 1) }; Material copyTerrainLayerMaterial = TerrainPaintUtility.GetCopyTerrainLayerMaterial(); var rtdesc = new RenderTextureDescriptor(destinationRenderTexture.width, destinationRenderTexture.height, RenderTextureFormat.ARGB32); rtdesc.sRGB = false; rtdesc.useMipMap = false; rtdesc.autoGenerateMips = false; RenderTexture destTarget = RenderTexture.GetTemporary(rtdesc); RenderTexture.active = destTarget; for (int i = 0; i < m_TerrainTiles.Count; i++) { TerrainTile terrainTile = m_TerrainTiles[i]; if (terrainTile.clippedLocalPixels.width == 0 || terrainTile.clippedLocalPixels.height == 0) { continue; } onTerrainTileBeforePaint?.Invoke(terrainTile, ToolAction.PaintTexture, editorUndoName); RectInt writeRect = terrainTile.clippedPCPixels; Rect readRect = new Rect( writeRect.x / (float)pixelRect.width, writeRect.y / (float)pixelRect.height, writeRect.width / (float)pixelRect.width, writeRect.height / (float)pixelRect.height); destinationRenderTexture.filterMode = FilterMode.Point; int mapIndex = terrainTile.mapIndex; int channelIndex = terrainTile.channelIndex; var terrainData = terrainTile.terrain.terrainData; var alphamapTextures = terrainData.alphamapTextures; for (int j = 0; j < alphamapTextures.Length; j++) { Texture2D sourceTex = alphamapTextures[j]; if ((sourceTex.width != targetTextureWidth) || (sourceTex.height != targetTextureHeight)) { Debug.LogWarning("PaintContext alphamap operations must use the same resolution for all Terrains - mismatched Terrains are ignored.", terrainTile.terrain); continue; } Rect combineRect = new Rect( terrainTile.clippedLocalPixels.x / (float)sourceTex.width, terrainTile.clippedLocalPixels.y / (float)sourceTex.height, terrainTile.clippedLocalPixels.width / (float)sourceTex.width, terrainTile.clippedLocalPixels.height / (float)sourceTex.height); copyTerrainLayerMaterial.SetTexture("_MainTex", destinationRenderTexture); copyTerrainLayerMaterial.SetTexture("_OldAlphaMapTexture", sourceRenderTexture); copyTerrainLayerMaterial.SetTexture("_OriginalTargetAlphaMap", alphamapTextures[mapIndex]); copyTerrainLayerMaterial.SetTexture("_AlphaMapTexture", sourceTex); copyTerrainLayerMaterial.SetVector("_LayerMask", j == mapIndex ? layerMasks[channelIndex] : Vector4.zero); copyTerrainLayerMaterial.SetVector("_OriginalTargetAlphaMask", layerMasks[channelIndex]); copyTerrainLayerMaterial.SetPass(1); GL.PushMatrix(); GL.LoadPixelMatrix(0, destTarget.width, 0, destTarget.height); GL.Begin(GL.QUADS); GL.Color(new Color(1.0f, 1.0f, 1.0f, 1.0f)); GL.MultiTexCoord2(0, readRect.x, readRect.y); GL.MultiTexCoord2(1, combineRect.x, combineRect.y); GL.Vertex3(writeRect.x, writeRect.y, 0.0f); GL.MultiTexCoord2(0, readRect.x, readRect.yMax); GL.MultiTexCoord2(1, combineRect.x, combineRect.yMax); GL.Vertex3(writeRect.x, writeRect.yMax, 0.0f); GL.MultiTexCoord2(0, readRect.xMax, readRect.yMax); GL.MultiTexCoord2(1, combineRect.xMax, combineRect.yMax); GL.Vertex3(writeRect.xMax, writeRect.yMax, 0.0f); GL.MultiTexCoord2(0, readRect.xMax, readRect.y); GL.MultiTexCoord2(1, combineRect.xMax, combineRect.y); GL.Vertex3(writeRect.xMax, writeRect.y, 0.0f); GL.End(); GL.PopMatrix(); terrainData.CopyActiveRenderTextureToTexture(TerrainData.AlphamapTextureName, j, writeRect, terrainTile.clippedLocalPixels.min, true); } OnTerrainPainted(terrainTile, ToolAction.PaintTexture); } RenderTexture.active = null; RenderTexture.ReleaseTemporary(destTarget); }
internal static void DrawQuad(RectInt destinationPixels, RectInt sourcePixels, Texture sourceTexture) { TerrainPaintUtility.DrawQuad2(destinationPixels, sourcePixels, sourceTexture, sourcePixels, sourceTexture); }