Skip to content

Commit

Permalink
Merge pull request #136 from Algoryx/feature/inhomogeneous-terrain
Browse files Browse the repository at this point in the history
Add support for inhomogeneous terrains
  • Loading branch information
FilipAlg authored Nov 22, 2023
2 parents 04734fa + c8ad0f8 commit ca5ad8f
Show file tree
Hide file tree
Showing 22 changed files with 771 additions and 87 deletions.
58 changes: 53 additions & 5 deletions AGXUnity/Model/DeformableTerrain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.TerrainUtils;
using GUI = AGXUnity.Utils.GUI;

namespace AGXUnity.Model
Expand Down Expand Up @@ -125,8 +126,8 @@ protected override void OnDestroy()
{
ResetTerrainDataHeightsAndTransform();

if ( Properties != null )
Properties.Unregister( this );
if ( TerrainProperties != null )
TerrainProperties.Unregister( this );

if ( Simulation.HasInstance ) {
GetSimulation().remove( Native );
Expand Down Expand Up @@ -196,13 +197,13 @@ private void UpdateHeights( agxTerrain.ModifiedVerticesVector modifiedVertices )
var resY = TerrainDataResolution;
var result = new float[,] { { 0.0f } };
foreach ( var index in modifiedVertices ) {
var i = (int)index.x;
var j = (int)index.y;
var unityIndex = new Vector2Int((int)(resX - index.x - 1), (int)(resY - index.y - 1));
var h = (float)Native.getHeight( index );

result[ 0, 0 ] = h / scale;

TerrainData.SetHeightsDelayLOD( resX - i - 1, resY - j - 1, result );
TerrainData.SetHeightsDelayLOD( unityIndex.x, unityIndex.y, result );
OnModification?.Invoke( Native, index, Terrain, unityIndex );
}

#if UNITY_2019_1_OR_NEWER
Expand Down Expand Up @@ -392,6 +393,53 @@ public override float GetHeight( int x, int y )
return (float)Native.getHeight( idx ) - MaximumDepth;
}

public override void TriggerModifyAllCells()
{
var res = TerrainDataResolution;
var agxIdx = new agx.Vec2i( 0, 0 );
var uTerr = Terrain;
var uIdx = new Vector2Int( 0, 0 );
for (int y = 0; y < res; y++ ) {
agxIdx.y = res - 1 - y;
uIdx.y = y;
for ( int x = 0; x < res; x++ ) {
agxIdx.x = res - 1 - x;
uIdx.x = x;
OnModification?.Invoke( Native, agxIdx, uTerr, uIdx);
}
}
}

public override bool ReplaceTerrainMaterial( DeformableTerrainMaterial oldMat, DeformableTerrainMaterial newMat )
{
if ( Native == null )
return true;

if(oldMat == null || newMat == null )
return false;

return Native.exchangeTerrainMaterial(oldMat.Native, newMat.Native);
}

public override void SetAssociatedMaterial( DeformableTerrainMaterial terrMat, ShapeMaterial shapeMat )
{
if ( Native == null )
return;

Native.setAssociatedMaterial(terrMat.Native, shapeMat.Native);
}

public override void AddTerrainMaterial( DeformableTerrainMaterial terrMat, Shape shape = null )
{
if ( Native == null )
return;

if(shape == null)
Native.addTerrainMaterial( terrMat.Native );
else
Native.addTerrainMaterial( terrMat.Native, shape.NativeGeometry );
}

protected override bool IsNativeNull() { return Native == null; }
protected override void SetShapeMaterial( agx.Material material, agxTerrain.Terrain.MaterialType type ) { Native.setMaterial( material, type ); }
protected override void SetTerrainMaterial( agxTerrain.TerrainMaterial material ) { Native.setTerrainMaterial( material ); }
Expand Down
69 changes: 53 additions & 16 deletions AGXUnity/Model/DeformableTerrainBase.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
using UnityEngine;
using AGXUnity.Collide;
using UnityEngine;
using UnityEngine.Serialization;

namespace AGXUnity.Model
{
[HelpURL( "https://us.download.algoryx.se/AGXUnity/documentation/current/editor_interface.html#deformable-terrain" )]
public abstract class DeformableTerrainBase : ScriptComponent
{
public delegate void OnModificationCallback( agxTerrain.Terrain terr, agx.Vec2i agxIndex, Terrain unityTile, Vector2Int unityIndex );
public OnModificationCallback OnModification;

[SerializeField]
private ShapeMaterial m_material = null;
Expand Down Expand Up @@ -61,48 +65,49 @@ public ShapeMaterial ParticleMaterial
}

[SerializeField]
private DeformableTerrainMaterial m_terrainMaterial = null;
[FormerlySerializedAs("m_terrainMaterial")]
private DeformableTerrainMaterial m_defaultTerrainMaterial = null;

/// <summary>
/// Terrain material associated to this terrain.
/// </summary>
[AllowRecursiveEditing]
public DeformableTerrainMaterial TerrainMaterial
public DeformableTerrainMaterial DefaultTerrainMaterial
{
get { return m_terrainMaterial; }
get { return m_defaultTerrainMaterial; }
set
{
m_terrainMaterial = value;
m_defaultTerrainMaterial = value;

if ( !IsNativeNull() ) {
if ( m_terrainMaterial != null )
SetTerrainMaterial( m_terrainMaterial.GetInitialized<DeformableTerrainMaterial>().Native );
if ( m_defaultTerrainMaterial != null )
SetTerrainMaterial( m_defaultTerrainMaterial.GetInitialized<DeformableTerrainMaterial>().Native );
else
SetTerrainMaterial( DeformableTerrainMaterial.CreateNative( "dirt_1" ) );

}
}
}

[SerializeField]
private DeformableTerrainProperties m_properties = null;
[FormerlySerializedAs("m_properties")]
private DeformableTerrainProperties m_terrainProperties = null;

/// <summary>
/// Terrain properties associated to this terrain.
/// </summary>
[AllowRecursiveEditing]
public DeformableTerrainProperties Properties
public DeformableTerrainProperties TerrainProperties
{
get { return m_properties; }
get { return m_terrainProperties; }
set
{
if ( !IsNativeNull() && m_properties != null )
m_properties.Unregister( this );
if ( !IsNativeNull() && m_terrainProperties != null )
m_terrainProperties.Unregister( this );

m_properties = value;
m_terrainProperties = value;

if ( !IsNativeNull() && m_properties != null )
m_properties.Register( this );
if ( !IsNativeNull() && m_terrainProperties != null )
m_terrainProperties.Register( this );
}
}

Expand Down Expand Up @@ -151,6 +156,8 @@ protected override void OnDisable()
SetEnable( false );
}

public TerrainMaterialPatch[] MaterialPatches { get => GetComponentsInChildren<TerrainMaterialPatch>(); }

/// <summary>
/// Returns an array containing the soil particles used by this terrain
/// </summary>
Expand Down Expand Up @@ -244,6 +251,36 @@ virtual public void OnPropertiesUpdated() { }
/// <returns>The height of the terrain at the specified index.</returns>
abstract public float GetHeight( int x, int y );

/// <summary>
/// Triggers the <see cref="OnModification"/> callback for each terrain cell currently simulated.
/// Note that this function is rather expensive and should only be triggered when delays are acceptable
/// such as during initialization/resets.
/// </summary>
abstract public void TriggerModifyAllCells();

/// <summary>
/// Attempts to replace all voxels of the old material with the new material.
/// </summary>
/// <param name="oldMat">The material to change from</param>
/// <param name="newMat">The material to change to</param>
/// <returns>True if the replace operation was successful.</returns>
abstract public bool ReplaceTerrainMaterial( DeformableTerrainMaterial oldMat, DeformableTerrainMaterial newMat );

/// <summary>
/// Sets the shape material associated with the given terrain material.
/// </summary>
/// <param name="terrMat">The terrain material with which to associate the shape material.</param>
/// <param name="shapeMat">The shape material to associated to the provided terrain material.</param>
abstract public void SetAssociatedMaterial( DeformableTerrainMaterial terrMat, ShapeMaterial shapeMat );

/// <summary>
/// Add a terrain material to a terrain and optionally set all voxels in a given shape to the material.
/// </summary>
/// <param name="terrMat">The material to add to the terrain</param>
/// <param name="shape">If null then the terrain material is simply added to the terrain,
/// else the voxels intersecting the shape is set to the provided material.</param>
abstract public void AddTerrainMaterial( DeformableTerrainMaterial terrMat, Shape shape = null );

abstract protected bool IsNativeNull();
abstract protected void SetShapeMaterial( agx.Material material, agxTerrain.Terrain.MaterialType type );
abstract protected void SetTerrainMaterial( agxTerrain.TerrainMaterial material );
Expand Down
68 changes: 59 additions & 9 deletions AGXUnity/Model/DeformableTerrainPager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using UnityEngine;

namespace AGXUnity.Model
Expand Down Expand Up @@ -338,6 +339,10 @@ 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 );
}

Expand Down Expand Up @@ -379,29 +384,54 @@ private void UpdateTerrain( agxTerrain.TerrainPager.TileAttachments tile )
var zOffset = tile.m_zOffset;
var result = new float[,] { { 0.0f } };

foreach ( var index in modifications ) {
var gi = GetGlobalIndex( terrain, index );
agx.Vec2i index = new agx.Vec2i(0,0);
Vector2Int tileIndex = GetTileIndex(terrain.get());

UnityTerrainAdapter.UnityModificationCallback modCallbackFn = ( Terrain tile, Vector2Int unityIndex ) =>
{
tile.terrainData.SetHeightsDelayLOD( unityIndex.x, unityIndex.y, result );
OnModification?.Invoke( terrain.get(), index, Terrain, unityIndex );
};


foreach ( var index1 in modifications ) {
index.set( index1 );
var gi = GetGlobalIndexInternal( tileIndex, index);
float h = (float)(terrain.getHeight( index ) + zOffset);

result[ 0, 0 ] = h / scale;

m_terrainDataSource.SetUnityHeightDelayed( result, gi );
m_terrainDataSource.OnModification( gi, modCallbackFn );
}
}

private Vector2Int GetGlobalIndex( agxTerrain.TerrainRef terrain, agx.Vec2i index )
[MethodImpl( MethodImplOptions.AggressiveInlining )]
private Vector2Int GetTileIndex( agxTerrain.Terrain terrain )
{
var relTilePos = terrain.getPosition().ToHandedVector3() - transform.position;
var elementsPerTile = TileSize - TileOverlap - 1;
float tileOffset = elementsPerTile * ElementSize;

var relTilePos = terrain.getPosition().ToHandedVector3() - transform.position;
Vector2Int tileIndex = new Vector2Int( Mathf.FloorToInt( relTilePos.x / tileOffset ),
Mathf.FloorToInt( relTilePos.z / tileOffset ) );
tileIndex *= elementsPerTile;
return tileIndex;
}

[MethodImpl( MethodImplOptions.AggressiveInlining )]
private Vector2Int GetGlobalIndexInternal( Vector2Int tileIndex, agx.Vec2i index )
{
tileIndex.x += (int)index.x;
tileIndex.y += (int)index.y;
return tileIndex;
}

private Vector2Int GetGlobalIndex( agxTerrain.Terrain terrain, agx.Vec2i index )
{
var tileIndex = GetTileIndex( terrain );
return GetGlobalIndexInternal( tileIndex, index );
}

public void RecalculateParameters()
{
if ( ValidateParameters() )
Expand Down Expand Up @@ -564,7 +594,7 @@ private void SetHeightsInternal( int xstart, int ystart, float[,] heights, bool
bool tileFound = false;
var tiles = Native.getActiveTileAttachments();
foreach ( var tile in tiles ) {
var gi = GetGlobalIndex( tile.m_terrainTile, new agx.Vec2i( 0, 0 ) );
var gi = GetGlobalIndex( tile.m_terrainTile.get(), new agx.Vec2i( 0, 0 ) );
if ( gi.x > idx.x || gi.y > idx.y || gi.x + TileSize <= idx.x || gi.y + TileSize <= idx.y )
continue;

Expand Down Expand Up @@ -616,7 +646,7 @@ public override void SetHeight( int x, int y, float height )

var tiles = Native.getActiveTileAttachments();
foreach ( var tile in tiles ) {
var gi = GetGlobalIndex( tile.m_terrainTile, new agx.Vec2i( 0, 0 ) );
var gi = GetGlobalIndex( tile.m_terrainTile.get(), new agx.Vec2i( 0, 0 ) );
if ( gi.x > idx.x || gi.y > idx.y || gi.x + TileSize <= idx.x || gi.y + TileSize <= idx.y )
continue;

Expand Down Expand Up @@ -652,7 +682,7 @@ public override void SetHeight( int x, int y, float height )
// When the height arrays for (1), (2) & (3) are all filled we can combine them to yield the total height array.
var tiles = Native.getActiveTileAttachments();
foreach ( var tile in tiles ) {
var gi = GetGlobalIndex( tile.m_terrainTile, new agx.Vec2i( 0, 0 ) );
var gi = GetGlobalIndex( tile.m_terrainTile.get(), new agx.Vec2i( 0, 0 ) );
if ( gi.x > idx.x || gi.y > idx.y || gi.x + TileSize <= idx.x || gi.y + TileSize <= idx.y )
continue;

Expand Down Expand Up @@ -700,7 +730,7 @@ public override float GetHeight( int x, int y )

var tiles = Native.getActiveTileAttachments();
foreach ( var tile in tiles ) {
var gi = GetGlobalIndex( tile.m_terrainTile, new agx.Vec2i( 0, 0 ) );
var gi = GetGlobalIndex( tile.m_terrainTile.get(), new agx.Vec2i( 0, 0 ) );
if ( gi.x > idx.x || gi.y > idx.y || gi.x + TileSize <= idx.x || gi.y + TileSize <= idx.y )
continue;

Expand Down Expand Up @@ -735,6 +765,26 @@ private void TerrainSetHeights( agxTerrain.TerrainPager.TileAttachments tile, in
}
}

public override void TriggerModifyAllCells()
{
throw new NotImplementedException();
}

public override bool ReplaceTerrainMaterial( DeformableTerrainMaterial oldMat, DeformableTerrainMaterial newMat )
{
throw new NotImplementedException( "Terrain pager does not yet support Inhomogeneous terrain" );
}

public override void SetAssociatedMaterial( DeformableTerrainMaterial terrMat, ShapeMaterial shapeMat )
{
throw new NotImplementedException( "Terrain pager does not yet support Inhomogeneous terrain" );
}

public override void AddTerrainMaterial( DeformableTerrainMaterial terrMat, Shape shape = null )
{
throw new NotImplementedException( "Terrain pager does not yet support Inhomogeneous terrain" );
}

protected override bool IsNativeNull() { return Native == null; }
protected override void SetShapeMaterial( agx.Material material, agxTerrain.Terrain.MaterialType type )
{
Expand Down
Loading

0 comments on commit ca5ad8f

Please sign in to comment.