public void GatherAlphamap(TerrainLayer inputLayer, bool addLayerIfDoesntExist = true) { if (inputLayer == null) { return; } Material copyTerrainLayerMaterial = TerrainPaintUtility.GetCopyTerrainLayerMaterial(); 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) }; GatherInternal( t => { // return the texture to be gathered from this terrain tile SplatmapUserData userData = GetTerrainLayerUserData(t, inputLayer, addLayerIfDoesntExist); if (userData != null) { return(TerrainPaintUtility.GetTerrainAlphaMapChecked(t.terrain, userData.mapIndex)); } else { return(null); } }, new Color(0.0f, 0.0f, 0.0f, 0.0f), "PaintContext.GatherAlphamap", copyTerrainLayerMaterial, 0, t => { // before blit -- setup layer mask in the material SplatmapUserData userData = GetTerrainLayerUserData(t); if (userData == null) { return; } copyTerrainLayerMaterial.SetVector("_LayerMask", layerMasks[userData.channelIndex]); }); }
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, GraphicsFormat.R8G8B8A8_UNorm, GraphicsFormat.None); 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; }
private void GatherInternal( Func <ITerrainInfo, Texture> terrainToTexture, Color defaultColor, string operationName, Material blitMaterial = null, int blitPass = 0, Action <ITerrainInfo> beforeBlit = null, Action <ITerrainInfo> afterBlit = null) { if (blitMaterial == null) { blitMaterial = TerrainPaintUtility.GetBlitMaterial(); } RenderTexture.active = sourceRenderTexture; GL.Clear(true, true, defaultColor); GL.PushMatrix(); GL.LoadPixelMatrix(0, pixelRect.width, 0, pixelRect.height); for (int i = 0; i < m_TerrainTiles.Count; i++) { TerrainTile terrainTile = m_TerrainTiles[i]; if (!terrainTile.gatherEnable) { continue; } Texture sourceTexture = terrainToTexture(terrainTile); if ((sourceTexture == null) || (!terrainTile.gatherEnable)) // double check gatherEnable in case terrainToTexture modified it { continue; } if ((sourceTexture.width != targetTextureWidth) || (sourceTexture.height != targetTextureHeight)) { Debug.LogWarning(operationName + " requires the same resolution texture for all Terrains - mismatched Terrains are ignored.", terrainTile.terrain); continue; } beforeBlit?.Invoke(terrainTile); if (!terrainTile.gatherEnable) // check again, beforeBlit may have modified it { continue; } FilterMode oldFilterMode = sourceTexture.filterMode; sourceTexture.filterMode = FilterMode.Point; blitMaterial.SetTexture("_MainTex", sourceTexture); blitMaterial.SetPass(blitPass); // Draw padded quads to support extended-edge sampling of each terrain tile into empty regions. TerrainPaintUtility.DrawQuadPadded(terrainTile.clippedPCPixels, terrainTile.paddedPCPixels, terrainTile.clippedTerrainPixels, terrainTile.paddedTerrainPixels, sourceTexture); sourceTexture.filterMode = oldFilterMode; afterBlit?.Invoke(terrainTile); } GL.PopMatrix(); RenderTexture.active = oldRenderTexture; }