Skip to content

Commit

Permalink
Fixed cable and wire rendering in Prefab Stage using only Gizmos sinc…
Browse files Browse the repository at this point in the history
…e RuntimeObjects isn't supported.
  • Loading branch information
nmalg committed Jun 13, 2021
1 parent f312e06 commit 6a966c7
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 39 deletions.
36 changes: 18 additions & 18 deletions AGXUnity/Cable.cs
Expand Up @@ -341,24 +341,11 @@ public bool TraverseRoutePoints( Action<RoutePointData> callback )
/// <returns>Array of, equally distant, points defining the cable route.</returns>
public Vector3[] GetRoutePoints()
{
if ( RoutePointCurveUpToDate )
return m_routePointsCache;
if ( m_routePointsCache == null )
m_routePointsCache = new Vector3[] { };

m_routePointsCache = new Vector3[] { };

var result = SynchronizeRoutePointCurve();
if ( result.Successful || Mathf.Abs( result.Error ) < 5.0E-3f ) {
m_routePointResulutionPerUnitLength = ResolutionPerUnitLength;
List<Vector3> routePoints = new List<Vector3>();
m_routePointCurve.Traverse( ( curr, next, type ) =>
{
routePoints.Add( curr.Point );
if ( type == PointCurve.SegmentType.Last && Mathf.Abs( next.Time - 1.0f ) < Mathf.Abs( curr.Time - 1 ) )
routePoints.Add( next.Point );
}, result.SegmentLength );

m_routePointsCache = routePoints.ToArray();
}
if ( m_routePointsCache.Length == 0 && Route.NumNodes > 1 )
SynchronizeRoutePointCurve();

return m_routePointsCache;
}
Expand Down Expand Up @@ -507,6 +494,7 @@ private PointCurve.SegmentationResult SynchronizeRoutePointCurve()
m_routePointCurve = new PointCurve();

m_routePointCurve.LastSuccessfulResult = new PointCurve.SegmentationResult() { Error = float.PositiveInfinity, Successful = false };
m_routePointsCache = new Vector3[] { };

if ( m_routePointCurve.NumPoints == Route.NumNodes ) {
for ( int i = 0; i < Route.NumNodes; ++i )
Expand All @@ -521,8 +509,20 @@ private PointCurve.SegmentationResult SynchronizeRoutePointCurve()
if ( m_routePointCurve.Finalize() ) {
var numSegments = Mathf.Max( Mathf.CeilToInt( ResolutionPerUnitLength * Route.TotalLength ), 1 );
var result = m_routePointCurve.FindSegmentLength( numSegments, PointCurve.DefaultErrorFunc, 5.0E-3f, 1.0E-3f );
if ( result.Successful )
if ( result.Successful ) {
m_routePointResulutionPerUnitLength = ResolutionPerUnitLength;
var routePoints = new List<Vector3>();
m_routePointCurve.Traverse( ( curr, next, type ) =>
{
routePoints.Add( curr.Point );
if ( type == PointCurve.SegmentType.Last && Mathf.Abs( next.Time - 1.0f ) < Mathf.Abs( curr.Time - 1 ) )
routePoints.Add( next.Point );
}, result.SegmentLength );

m_routePointsCache = routePoints.ToArray();

return result;
}
}

return new PointCurve.SegmentationResult() { Error = float.PositiveInfinity, Successful = false };
Expand Down
58 changes: 52 additions & 6 deletions AGXUnity/Rendering/CableRenderer.cs
Expand Up @@ -14,8 +14,17 @@ public class CableRenderer : ScriptComponent
[HideInInspector]
public SegmentSpawner SegmentSpawner { get { return m_segmentSpawner; } }

[System.NonSerialized]
private Cable m_cable = null;

[HideInInspector]
public Cable Cable { get { return GetComponent<Cable>(); } }
public Cable Cable
{
get
{
return m_cable ?? ( m_cable = GetComponent<Cable>() );
}
}

[SerializeField]
private Material m_material = null;
Expand All @@ -36,7 +45,9 @@ public void InitializeRenderer( bool destructLast = false )
m_segmentSpawner = null;
}

m_segmentSpawner = new SegmentSpawner( GetComponent<Cable>(), @"Cable/CableSegment", @"Cable/CableSegmentBegin" );
m_segmentSpawner = new SegmentSpawner( Cable,
@"Cable/CableSegment",
@"Cable/CableSegmentBegin" );
m_segmentSpawner.Initialize( gameObject );
}

Expand Down Expand Up @@ -78,6 +89,11 @@ private void Render( CableRoute route, float radius )
if ( m_segmentSpawner == null )
return;

// Let OnDrawGizmos handle rendering when in prefab edit mode.
// It's not possible to use RuntimeObjects while there.
if ( PrefabUtils.IsEditingPrefab )
return;

m_segmentSpawner.Begin();
try {
var points = Cable.GetRoutePoints();
Expand All @@ -95,7 +111,7 @@ private void Render()
if ( m_segmentSpawner == null )
return;

agxCable.Cable native = Cable.Native;
var native = Cable.Native;
if ( native == null ) {
if ( m_segmentSpawner != null ) {
m_segmentSpawner.Destroy();
Expand All @@ -104,14 +120,19 @@ private void Render()
return;
}

agxCable.CableIterator it = native.begin();
agxCable.CableIterator endIt = native.end();
var it = native.begin();
var endIt = native.end();

m_segmentSpawner.Begin();
try {
float radius = Cable.Radius;
var prevEndPosition = it.EqualWith( endIt ) ?
Vector3.zero :
it.getBeginPosition().ToHandedVector3();
while ( !it.EqualWith( endIt ) ) {
m_segmentSpawner.CreateSegment( it.getBeginPosition().ToHandedVector3(), it.getEndPosition().ToHandedVector3(), radius );
var endPosition = it.getEndPosition().ToHandedVector3();
m_segmentSpawner.CreateSegment( prevEndPosition, endPosition, radius );
prevEndPosition = endPosition;
it.inc();
}
}
Expand All @@ -123,5 +144,30 @@ private void Render()
it.ReturnToPool();
endIt.ReturnToPool();
}

private void DrawGizmos( bool isSelected )
{
if ( Application.isPlaying || !PrefabUtils.IsEditingPrefab )
return;

if ( Cable == null || Cable.Route == null || Cable.Route.NumNodes < 2 )
return;

var defaultColor = Color.Lerp( Color.black, Color.white, 0.15f );
var selectedColor = Color.Lerp( defaultColor, Color.green, 0.15f );
m_segmentSpawner?.DrawGizmos( Cable.GetRoutePoints(),
Cable.Radius,
isSelected ? selectedColor : defaultColor );
}

private void OnDrawGizmos()
{
DrawGizmos( false );
}

private void OnDrawGizmosSelected()
{
DrawGizmos( true );
}
}
}
89 changes: 78 additions & 11 deletions AGXUnity/Rendering/SegmentSpawner.cs
Expand Up @@ -69,17 +69,6 @@ public Material DefaultMaterial
}
}

public GameObject[] Segments
{
get
{
return m_segments == null ? new GameObject[] {} :
( from segmentTransform in m_segments.GetComponentsInChildren<Transform>()
where segmentTransform != m_segments.transform
select segmentTransform.gameObject ).ToArray();
}
}

public SegmentSpawner( ScriptComponent parentComponent, string prefabObjectPath, string separateFirstObjectPath = "" )
{
m_parentComponent = parentComponent;
Expand Down Expand Up @@ -231,5 +220,83 @@ private void AddSelectionProxy( GameObject instance )
foreach ( Transform child in instance.transform )
child.gameObject.GetOrCreateComponent<OnSelectionProxy>().Component = m_parentComponent;
}

public void DrawGizmos( Vector3[] points, float radius, Color color )
{
if ( m_gizmosMeshes == null || m_gizmosMeshes.Length == 0 ) {
var resource = Resources.Load<GameObject>( m_separateFirstObjectPrefabPath );
m_gizmosMeshes = new Mesh[]
{
resource?.transform.GetChild( 0 ).GetComponent<MeshFilter>()?.sharedMesh,
resource?.transform.GetChild( 1 ).GetComponent<MeshFilter>()?.sharedMesh,
resource?.transform.GetChild( 2 ).GetComponent<MeshFilter>()?.sharedMesh
};

if ( Array.Find( m_gizmosMeshes, mesh => mesh == null ) )
m_gizmosMeshes = new Mesh[] { };
}

if ( m_gizmosMeshes.Length != 3 || points.Length < 2 )
return;

var diameter = 2.0f * radius;
var worldMatrix = Matrix4x4.identity;
Gizmos.color = color;
for ( int i = 1; i < points.Length; ++i ) {
var begin = points[ i - 1 ];
var end = points[ i ];
var beginToEnd = end - begin;
var length = beginToEnd.magnitude;
if ( length < 1.0E-4f )
continue;

beginToEnd /= length;

worldMatrix = Matrix4x4.TRS( begin + 0.5f * length * beginToEnd,
Quaternion.FromToRotation( Vector3.up, beginToEnd ),
Vector3.one );
Action<int, Vector3, Quaternion, Vector3> drawMesh = ( index,
localPosition,
localRotation,
localScale ) =>
{
Gizmos.matrix = worldMatrix * Matrix4x4.TRS( localPosition,
localRotation,
localScale );
Gizmos.DrawWireMesh( m_gizmosMeshes[ index ] );
};

var halfLengthUp = 0.5f * length * Vector3.up;
var sphericalScale = diameter * Vector3.one;
var cylindricalScale = new Vector3( diameter, length, diameter );
if ( i == 1 ) {
drawMesh( 0,
halfLengthUp,
Quaternion.identity,
sphericalScale );
drawMesh( 1,
Vector3.zero,
Quaternion.identity,
cylindricalScale );
drawMesh( 2,
-halfLengthUp,
Quaternion.FromToRotation( Vector3.up, Vector3.down ),
sphericalScale );
}
else {
drawMesh( 1,
Vector3.zero,
Quaternion.identity,
cylindricalScale );
drawMesh( 2,
halfLengthUp,
Quaternion.identity,
sphericalScale );
}
}
}

[NonSerialized]
private static Mesh[] m_gizmosMeshes = new Mesh[] { };
}
}
53 changes: 49 additions & 4 deletions AGXUnity/Rendering/WireRenderer.cs
Expand Up @@ -19,6 +19,18 @@ public class WireRenderer : ScriptComponent
[HideInInspector]
public SegmentSpawner SegmentSpawner { get { return m_segmentSpawner; } }

[NonSerialized]
private Wire m_wire = null;

[HideInInspector]
public Wire Wire
{
get
{
return m_wire ?? ( m_wire = GetComponent<Wire>() );
}
}

[SerializeField]
private Material m_material = null;

Expand Down Expand Up @@ -47,7 +59,9 @@ public void InitializeRenderer( bool destructLast = false )
m_segmentSpawner = null;
}

m_segmentSpawner = new SegmentSpawner( GetComponent<Wire>(), @"Wire/WireSegment", @"Wire/WireSegmentBegin" );
m_segmentSpawner = new SegmentSpawner( Wire,
@"Wire/WireSegment",
@"Wire/WireSegmentBegin" );
m_segmentSpawner.Initialize( gameObject );
}

Expand Down Expand Up @@ -77,9 +91,13 @@ protected void LateUpdate()
if ( Application.isPlaying )
return;

Wire wire = GetComponent<Wire>();
if ( wire != null && wire.Native == null )
RenderRoute( wire.Route, wire.Radius );
// Let OnDrawGizmos handle rendering when in prefab edit mode.
// It's not possible to use RuntimeObjects while there.
if ( PrefabUtils.IsEditingPrefab )
return;

if ( Wire != null && Wire.Native == null )
RenderRoute( Wire.Route, Wire.Radius );
}

private void RenderRoute( WireRoute route, float radius )
Expand Down Expand Up @@ -155,5 +173,32 @@ private void Render( Wire wire )
it.ReturnToPool();
endIt.ReturnToPool();
}

private void DrawGizmos( bool isSelected )
{
if ( Application.isPlaying || !PrefabUtils.IsEditingPrefab )
return;

if ( Wire == null || Wire.Route == null || Wire.Route.NumNodes < 2 )
return;

var routePoints = Wire.Route.Select( routePoint => routePoint.Position ).ToArray();

var defaultColor = Color.Lerp( Color.black, Color.white, 0.55f );
var selectedColor = Color.Lerp( defaultColor, Color.green, 0.15f );
m_segmentSpawner?.DrawGizmos( routePoints,
Wire.Radius,
isSelected ? selectedColor : defaultColor );
}

private void OnDrawGizmos()
{
DrawGizmos( false );
}

private void OnDrawGizmosSelected()
{
DrawGizmos( true );
}
}
}

0 comments on commit 6a966c7

Please sign in to comment.