Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: Added initial support for non-homogeneous materials in with the pager #158

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 1 addition & 8 deletions AGXUnity/Model/DeformableTerrain.cs
Original file line number Diff line number Diff line change
@@ -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()
8 changes: 1 addition & 7 deletions AGXUnity/Model/DeformableTerrainConnector.cs
Original file line number Diff line number Diff line change
@@ -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
}
}
}
40 changes: 30 additions & 10 deletions AGXUnity/Model/DeformableTerrainPager.cs
Original file line number Diff line number Diff line change
@@ -376,10 +376,6 @@ private void InitializeNative()
foreach ( var rb in m_rigidbodies )
Native.add( rb.Body.GetInitialized<RigidBody>().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; }
144 changes: 66 additions & 78 deletions AGXUnity/Rendering/TerrainPatchRenderer.cs
Original file line number Diff line number Diff line change
@@ -7,28 +7,12 @@

namespace AGXUnity.Rendering
{
/// <summary>
/// Wrapper class for storing/resetting initial state of TerrainData.
/// This is by no means a complete store/restore, only the parts used by <see cref="TerrainPatchRenderer"/>.
/// </summary>
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<agxTerrain.TerrainMaterial, int> 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<agxTerrain.TerrainMaterial, int> m_materialMapping;
private InitialTerrainData m_initialData;
private int m_layerCount;
private int m_defaultLayerIndex;

private Dictionary<Terrain, TileData> m_perTileData;
private List<Terrain> 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<DeformableTerrainMaterial, TerrainLayer> 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,45 +83,26 @@ public Dictionary<DeformableTerrainMaterial, TerrainLayer> MaterialRenderMap
get
{
var res = ImplicitMaterialRenderMap;
foreach ( var (mat, tl) in ExplicitMaterialRenderMap )
foreach ( var (mat, tl) in ExplicitMaterialRenderMap )
res[ mat ] = tl;
return res;
}
}

public TerrainMaterialPatch[] RenderedPatches => gameObject.GetComponentsInChildren<TerrainMaterialPatch>();

protected override bool Initialize()
private void InitializeTile( Terrain tile )
{
terrain = gameObject.GetInitializedComponent<DeformableTerrainBase>();
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<Terrain>();
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<agxTerrain.TerrainMaterial, int>();
tileData.m_materialMapping = new Dictionary<agxTerrain.TerrainMaterial, int>();
foreach ( var (mat, tl) in MaterialRenderMap ) {
var terrMat = mat.GetInitialized<DeformableTerrainMaterial>().Native;
if ( terrMat != null ) {
@@ -150,55 +113,80 @@ protected override bool Initialize()

if ( !layers.Contains( tl ) )
layers.Add( tl );
m_materialMapping.Add( mat.GetInitialized<DeformableTerrainMaterial>().Native, layers.IndexOf( tl ) );
tileData.m_materialMapping.Add( mat.GetInitialized<DeformableTerrainMaterial>().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<DeformableTerrainBase>();
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<Terrain>();
var td = uTerr.terrainData;

protected override void OnApplicationQuit()
{
m_initialData?.Reset( GetComponent<Terrain>().terrainData );
}
m_perTileData = new Dictionary<Terrain, TileData>();
m_shouldUpdate = new List<Terrain>();

protected override void OnDestroy()
{
m_initialData?.Reset( GetComponent<Terrain>().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<Terrain>().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;

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;
}
}
}
Binary file modified Plugins/x86_64/agxDotNet.dll
Binary file not shown.