diff --git a/AGXUnity/Model/DeformableTerrain.cs b/AGXUnity/Model/DeformableTerrain.cs index 95e27a33..3f1ae56e 100644 --- a/AGXUnity/Model/DeformableTerrain.cs +++ b/AGXUnity/Model/DeformableTerrain.cs @@ -108,7 +108,7 @@ protected override bool Initialize() RemoveInvalidShovels( true, true ); m_initialHeights = TerrainData.GetHeights( 0, 0, TerrainDataResolution, TerrainDataResolution ); - + Terrain.terrainData = Instantiate( Terrain.terrainData ); InitializeNative(); Simulation.Instance.StepCallbacks.PostStepForward += OnPostStepForward; @@ -171,13 +171,6 @@ private void ResetTerrainDataHeightsAndTransform() TerrainData.SetHeights( 0, 0, m_initialHeights ); transform.position = transform.position + MaximumDepth * Vector3.up; - -#if UNITY_EDITOR - // If the editor is closed during play the modified height - // data isn't saved, this resolves corrupt heights in such case. - UnityEditor.EditorUtility.SetDirty( TerrainData ); - UnityEditor.AssetDatabase.SaveAssets(); -#endif } private void OnPostStepForward() diff --git a/AGXUnity/Model/DeformableTerrainConnector.cs b/AGXUnity/Model/DeformableTerrainConnector.cs index e3b3a984..eff41dbe 100644 --- a/AGXUnity/Model/DeformableTerrainConnector.cs +++ b/AGXUnity/Model/DeformableTerrainConnector.cs @@ -22,6 +22,7 @@ public Vector3 GetOffsetPosition() public float[,] WriteTerrainDataOffset() { + Terrain.terrainData = Instantiate( Terrain.terrainData ); if ( float.IsNaN( MaximumDepth ) ) { Debug.LogError( "Writing terrain offset without first setting depth!" ); MaximumDepth = 0; @@ -37,13 +38,6 @@ private void OnDestroy() if ( InitialHeights != null ) { transform.position += MaximumDepth * Vector3.up; Terrain.terrainData.SetHeights( 0, 0, InitialHeights ); - -#if UNITY_EDITOR - // If the editor is closed during play the modified height - // data isn't saved, this resolves corrupt heights in such case. - UnityEditor.EditorUtility.SetDirty( Terrain.terrainData ); - UnityEditor.AssetDatabase.SaveAssets(); -#endif } } } diff --git a/AGXUnity/Model/DeformableTerrainPager.cs b/AGXUnity/Model/DeformableTerrainPager.cs index 4c5d0324..05e4adf5 100644 --- a/AGXUnity/Model/DeformableTerrainPager.cs +++ b/AGXUnity/Model/DeformableTerrainPager.cs @@ -376,10 +376,6 @@ private void InitializeNative() foreach ( var rb in m_rigidbodies ) Native.add( rb.Body.GetInitialized().Native, rb.requiredRadius, rb.preloadRadius ); - if ( MaterialPatches.Length != 0 ) - Debug.LogWarning( "Nonhomogenous terrain is not yet supported for DeformableTerrainPager.", this ); - - GetSimulation().add( Native ); } @@ -411,7 +407,7 @@ private void UpdateHeights() private void UpdateTerrain( agxTerrain.TerrainPager.TileAttachments tile ) { - var terrain = tile.m_terrainTile; + var terrain = tile.m_terrainTile.get(); var modifications = terrain.getModifiedVertices(); if ( modifications.Count == 0 ) return; @@ -423,12 +419,12 @@ private void UpdateTerrain( agxTerrain.TerrainPager.TileAttachments tile ) var result = new float[,] { { 0.0f } }; agx.Vec2i index = new agx.Vec2i(0,0); - Vector2Int tileIndex = GetTileIndex(terrain.get()); + Vector2Int tileIndex = GetTileIndex(terrain); UnityTerrainAdapter.UnityModificationCallback modCallbackFn = ( Terrain tile, Vector2Int unityIndex ) => { tile.terrainData.SetHeightsDelayLOD( unityIndex.x, unityIndex.y, result ); - OnModification?.Invoke( terrain.get(), index, Terrain, unityIndex ); + OnModification?.Invoke( terrain, index, Terrain, unityIndex ); m_updatedTerrains.Add( tile ); }; @@ -813,17 +809,41 @@ public override void TriggerModifyAllCells() public override bool ReplaceTerrainMaterial( DeformableTerrainMaterial oldMat, DeformableTerrainMaterial newMat ) { - throw new NotImplementedException( "Terrain pager does not yet support Inhomogeneous terrain" ); + if ( Native == null ) + return true; + + if ( oldMat == null || newMat == null ) + return false; + + var success = Native.getTemplateTerrain().exchangeTerrainMaterial( oldMat.Native, newMat.Native ); + Native.applyChangesToTemplateTerrain(); + return success; } public override void SetAssociatedMaterial( DeformableTerrainMaterial terrMat, ShapeMaterial shapeMat ) { - throw new NotImplementedException( "Terrain pager does not yet support Inhomogeneous terrain" ); + if ( Native == null ) + return; + + Native.getTemplateTerrain().setAssociatedMaterial( terrMat.Native, shapeMat.Native ); + Native.applyChangesToTemplateTerrain(); } public override void AddTerrainMaterial( DeformableTerrainMaterial terrMat, Shape shape = null ) { - throw new NotImplementedException( "Terrain pager does not yet support Inhomogeneous terrain" ); + if ( Native == null ) + return; + + var template = Native.getTemplateTerrain(); + var idx = template.getMaterialController().getTerrainMaterialIndex( terrMat.Native ); + if ( idx == uint.MaxValue ) { + template.addTerrainMaterial( terrMat.Native ); + idx = template.getMaterialController().getTerrainMaterialIndex( terrMat.Native ); + } + if ( shape != null ) + m_terrainDataSource.addTerrainMaterialSourceGeometry( shape.NativeGeometry, idx ); + + Native.applyChangesToTemplateTerrain(); } protected override bool IsNativeNull() { return Native == null; } diff --git a/AGXUnity/Rendering/TerrainPatchRenderer.cs b/AGXUnity/Rendering/TerrainPatchRenderer.cs index a823a5f9..7c70b514 100644 --- a/AGXUnity/Rendering/TerrainPatchRenderer.cs +++ b/AGXUnity/Rendering/TerrainPatchRenderer.cs @@ -7,28 +7,12 @@ namespace AGXUnity.Rendering { - /// - /// Wrapper class for storing/resetting initial state of TerrainData. - /// This is by no means a complete store/restore, only the parts used by . - /// - class InitialTerrainData + class TileData { - private float[,,] m_alphamaps; - private TerrainLayer[] m_layers; - - public InitialTerrainData( TerrainData td ) - { - m_alphamaps = td.GetAlphamaps( 0, 0, td.alphamapWidth, td.alphamapHeight ); - m_layers = td.terrainLayers; - } - - public void Reset( TerrainData td ) - { - if ( td != null ) { - td.terrainLayers = m_layers; - td.SetAlphamaps( 0, 0, m_alphamaps ); - } - } + public float[,,] alphamap; + public Dictionary m_materialMapping; + public int m_layerCount; + public int m_defaultLayerIndex; } [RequireComponent( typeof( DeformableTerrainBase ) )] @@ -37,11 +21,9 @@ public void Reset( TerrainData td ) public class TerrainPatchRenderer : ScriptComponent { private DeformableTerrainBase terrain; - private float[,,] alphamap; - private Dictionary m_materialMapping; - private InitialTerrainData m_initialData; - private int m_layerCount; - private int m_defaultLayerIndex; + + private Dictionary m_perTileData; + private List m_shouldUpdate; [SerializeField] private TerrainLayer m_defaultLayer; @@ -56,7 +38,7 @@ public TerrainLayer DefaultLayer get => m_defaultLayer; set { - if ( m_initialData != null ) + if ( State == States.INITIALIZED ) Debug.LogError( "Setting material TerrainLayers during runtime is not supported!" ); else m_defaultLayer = value; @@ -77,7 +59,7 @@ public SerializableDictionary ExplicitM get => m_explicitMaterialRenderMap; set { - if ( m_initialData != null ) + if ( State == States.INITIALIZED ) Debug.LogError( "Setting material TerrainLayers during runtime is not supported!" ); else m_explicitMaterialRenderMap = value; @@ -101,7 +83,7 @@ public Dictionary MaterialRenderMap get { var res = ImplicitMaterialRenderMap; - foreach ( var (mat, tl) in ExplicitMaterialRenderMap ) + foreach ( var (mat, tl) in ExplicitMaterialRenderMap ) res[ mat ] = tl; return res; } @@ -109,37 +91,18 @@ public Dictionary MaterialRenderMap public TerrainMaterialPatch[] RenderedPatches => gameObject.GetComponentsInChildren(); - protected override bool Initialize() + private void InitializeTile( Terrain tile ) { - terrain = gameObject.GetInitializedComponent(); - if ( terrain is not DeformableTerrain ) { - Debug.LogError( "Terrain Patch Renderer currently only supports DeformableTerrain!", this ); - return false; - } - - // The patches need to be initialized before the initial update pass, otherwise the materials might not yet have been added. - foreach ( var patch in RenderedPatches ) - patch.GetInitialized(); - - var uTerr = GetComponent(); - var td = uTerr.terrainData; - - m_initialData = new InitialTerrainData( td ); + TileData tileData = new TileData(); + var td = tile.terrainData; var layers = td.terrainLayers.ToList(); - if ( DefaultLayer == null ) { - Debug.LogWarning( "No DefaultLayer provided. Using first layer present in terrain.", this ); - m_defaultLayer = td.terrainLayers[ 0 ]; - m_defaultLayerIndex = 0; - } - else { - if ( !layers.Contains( DefaultLayer ) ) - layers.Add( DefaultLayer ); - m_defaultLayerIndex = layers.IndexOf( DefaultLayer ); - } + if ( !layers.Contains( DefaultLayer ) ) + layers.Add( DefaultLayer ); + tileData.m_defaultLayerIndex = layers.IndexOf( DefaultLayer ); // Initialize terrain layers: 0 is default, 1+ are mapped. - m_materialMapping = new Dictionary(); + tileData.m_materialMapping = new Dictionary(); foreach ( var (mat, tl) in MaterialRenderMap ) { var terrMat = mat.GetInitialized().Native; if ( terrMat != null ) { @@ -150,45 +113,68 @@ protected override bool Initialize() if ( !layers.Contains( tl ) ) layers.Add( tl ); - m_materialMapping.Add( mat.GetInitialized().Native, layers.IndexOf( tl ) ); + tileData.m_materialMapping.Add( mat.GetInitialized().Native, layers.IndexOf( tl ) ); } } td.terrainLayers = layers.ToArray(); - m_layerCount = layers.Count; + tileData.m_layerCount = layers.Count; - alphamap = td.GetAlphamaps( 0, 0, td.alphamapWidth, td.alphamapHeight ); + tileData.alphamap = td.GetAlphamaps( 0, 0, td.alphamapWidth, td.alphamapHeight ); - Simulation.Instance.StepCallbacks.SimulationPost += PostStep; - terrain.OnModification += UpdateTextureAt; + m_perTileData.Add( tile, tileData ); + } - terrain.TriggerModifyAllCells(); + protected override bool Initialize() + { + terrain = gameObject.GetInitializedComponent(); + if ( terrain is MovableTerrain ) { + Debug.LogError( "Terrain Patch Renderer does not support MovableTerrain!", this ); + return false; + } - td.SetAlphamaps( 0, 0, alphamap ); + // The patches need to be initialized before the initial update pass, otherwise the materials might not yet have been added. + foreach ( var patch in RenderedPatches ) + patch.GetInitialized(); - return true; - } + var uTerr = GetComponent(); + var td = uTerr.terrainData; - protected override void OnApplicationQuit() - { - m_initialData?.Reset( GetComponent().terrainData ); - } + m_perTileData = new Dictionary(); + m_shouldUpdate = new List(); - protected override void OnDestroy() - { - m_initialData?.Reset( GetComponent().terrainData ); + if ( DefaultLayer == null ) { + Debug.LogWarning( "No DefaultLayer provided. Using first layer present in terrain.", this ); + m_defaultLayer = td.terrainLayers[ 0 ]; + } + + Simulation.Instance.StepCallbacks.SimulationPost += PostStep; + terrain.OnModification += UpdateTextureAt; + + if ( terrain is DeformableTerrain ) { + InitializeTile( uTerr ); + terrain.TriggerModifyAllCells(); + td.SetAlphamaps( 0, 0, m_perTileData[ uTerr ].alphamap ); + } - base.OnDestroy(); + return true; } private void PostStep() { - var td = GetComponent().terrainData; + foreach ( var terr in m_shouldUpdate ) + terr.terrainData.SetAlphamaps( 0, 0, m_perTileData[ terr ].alphamap ); - td.SetAlphamaps( 0, 0, alphamap ); + m_shouldUpdate.Clear(); } private void UpdateTextureAt( agxTerrain.Terrain aTerr, agx.Vec2i aIdx, Terrain uTerr, Vector2Int uIdx ) { + if ( !m_perTileData.ContainsKey( uTerr ) ) + InitializeTile( uTerr ); + + if ( !m_shouldUpdate.Contains( uTerr ) ) + m_shouldUpdate.Add( uTerr ); + var td = uTerr.terrainData; var alphamapRes = td.alphamapResolution; var heightsRes = td.heightmapResolution - 1; @@ -196,9 +182,11 @@ private void UpdateTextureAt( agxTerrain.Terrain aTerr, agx.Vec2i aIdx, Terrain var modPos = aTerr.getSurfacePositionWorld( aIdx ); var mat = aTerr.getTerrainMaterial( modPos ); - var index = m_materialMapping.GetValueOrDefault(mat,m_defaultLayerIndex); + var data = m_perTileData[uTerr]; + + var index = data.m_materialMapping.GetValueOrDefault(mat,data.m_defaultLayerIndex); - if ( index == m_defaultLayerIndex && State != States.INITIALIZED ) + if ( index == data.m_defaultLayerIndex && State != States.INITIALIZED ) return; var modAlphaX = Mathf.RoundToInt((uIdx.x - 0.5f)/heightsRes * alphamapRes); @@ -212,8 +200,8 @@ private void UpdateTextureAt( agxTerrain.Terrain aTerr, agx.Vec2i aIdx, Terrain for ( int x = modAlphaX; x < modAlphaXend; x++ ) { if ( x < 0 || x >= alphamapRes ) continue; - for ( int i = 0; i < m_layerCount; i++ ) - alphamap[ y, x, i ] = i == index ? 1.0f : 0.0f; + for ( int i = 0; i < data.m_layerCount; i++ ) + data.alphamap[ y, x, i ] = i == index ? 1.0f : 0.0f; } } } diff --git a/Plugins/x86_64/agxDotNet.dll b/Plugins/x86_64/agxDotNet.dll index ae2a8a75..dd24a530 100644 Binary files a/Plugins/x86_64/agxDotNet.dll and b/Plugins/x86_64/agxDotNet.dll differ