Skip to content

Commit bf410ea

Browse files
committed
Merge remote-tracking branch 'origin/master' into feature/openplx-integration
2 parents 19fb0e0 + 1804861 commit bf410ea

23 files changed

+717
-18
lines changed

Diff for: .editorconfig

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ root = true
55
[*.cs]
66

77
dotnet_diagnostic.IDE0005.severity = error
8+
dotnet_diagnostic.IDE0031.severity = none
89

910
#### Core EditorConfig Options ####
1011

Diff for: AGXUnity/CableTunnelingGuard.cs

+248
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
using AGXUnity.Utils;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using UnityEngine;
5+
using UnityEngine.UIElements;
6+
7+
namespace AGXUnity
8+
{
9+
[AddComponentMenu( "AGXUnity/Cable Tunneling Guard" )]
10+
[DisallowMultipleComponent]
11+
[RequireComponent( typeof( AGXUnity.Cable ) )]
12+
[HelpURL( "https://us.download.algoryx.se/AGXUnity/documentation/current/editor_interface.html#cable-tunneling-guard" )]
13+
public class CableTunnelingGuard : ScriptComponent
14+
{
15+
/// <summary>
16+
/// Native instance of the cable tuneling guard.
17+
/// </summary>
18+
public agxCable.CableTunnelingGuard Native { get; private set; }
19+
20+
[System.NonSerialized]
21+
private Cable m_cable = null;
22+
23+
/// <summary>
24+
/// The Cable ScriptComponent that this CableTunnelingGuard follows
25+
/// </summary>
26+
[HideInInspector]
27+
public Cable Cable { get { return m_cable ??= GetComponent<Cable>(); } }
28+
29+
/// <summary>
30+
/// The mesh which is used to visualise a hull
31+
/// </summary>
32+
private Mesh m_mesh = null;
33+
34+
[SerializeField]
35+
private double m_hullScale = 4;
36+
37+
public double HullScale
38+
{
39+
get { return m_hullScale; }
40+
set
41+
{
42+
value = System.Math.Max( value, 1.0f );
43+
44+
if ( m_hullScale != value ) {
45+
m_hullScale = value;
46+
UpdateRenderingMesh();
47+
}
48+
49+
if ( Native != null ) {
50+
Native.setHullScale( m_hullScale );
51+
}
52+
}
53+
}
54+
55+
private void UpdateRenderingMesh()
56+
{
57+
if ( m_mesh == null )
58+
m_mesh = new Mesh();
59+
60+
if ( m_pointCurveCache != null && m_pointCurveCache.Length >= 2 ) {
61+
float segmentLength = ( Cable.GetRoutePoints()[ 0 ]-Cable.GetRoutePoints()[ 1 ] ).magnitude;
62+
CapsuleShapeUtils.CreateCapsuleMesh( Cable.Radius * (float)m_hullScale, segmentLength, 0.7f, m_mesh );
63+
}
64+
}
65+
66+
// See documentation / tutorials for a more detailed description of the native parameters
67+
68+
/// <summary>
69+
/// The angle to cable ends at which and approaching contact is accepted
70+
/// </summary>
71+
[SerializeField]
72+
private double m_angleThreshold = 90.0 * 0.9;
73+
74+
public double AngleThreshold
75+
{
76+
get { return m_angleThreshold; }
77+
set
78+
{
79+
m_angleThreshold = System.Math.Clamp( value, 0, 90 );
80+
if ( Native != null ) {
81+
Native.setAngleThreshold( m_angleThreshold / 180.0 * Mathf.PI );
82+
}
83+
}
84+
}
85+
86+
/// <summary>
87+
/// A parameter which controls how far the estimated penetration depth must be at the enxt step to attempt to
88+
/// prevent a tunneling occurence
89+
/// </summary>
90+
[SerializeField]
91+
private double m_leniency = 0;
92+
93+
public double Leniency
94+
{
95+
get { return m_leniency; }
96+
set
97+
{
98+
m_leniency = value;
99+
if ( Native != null ) {
100+
Native.setLeniency( m_leniency );
101+
}
102+
}
103+
}
104+
105+
/// <summary>
106+
/// The amount of steps for which the component will continue adding contacts to the solver after a contact has
107+
/// been predicted.
108+
/// </summary>
109+
[SerializeField]
110+
private uint m_debounceSteps = 0;
111+
112+
public uint DebounceSteps
113+
{
114+
get { return m_debounceSteps; }
115+
set
116+
{
117+
m_debounceSteps = value;
118+
if ( Native != null ) {
119+
Native.setDebounceSteps( m_debounceSteps );
120+
}
121+
}
122+
}
123+
124+
/// <summary>
125+
/// When set to true the component will not attempt any predictions and will always add the contacts it encounters
126+
/// through the hulls to the solver
127+
/// </summary>
128+
[SerializeField]
129+
private bool m_alwaysAdd = false;
130+
131+
public bool AlwaysAdd
132+
{
133+
get { return m_alwaysAdd; }
134+
set
135+
{
136+
m_alwaysAdd = value;
137+
if ( Native != null ) {
138+
Native.setAlwaysAdd( m_alwaysAdd );
139+
}
140+
}
141+
}
142+
143+
/// <summary>
144+
/// When true the component will predict tunneling with its own segments as well
145+
/// </summary>
146+
[SerializeField]
147+
private bool m_enableSelfInteraction = true;
148+
149+
public bool EnableSelfInteraction
150+
{
151+
get { return m_enableSelfInteraction; }
152+
set
153+
{
154+
m_enableSelfInteraction = value;
155+
if ( Native != null ) {
156+
Native.setEnableSelfInteraction( m_enableSelfInteraction );
157+
}
158+
}
159+
}
160+
161+
protected override bool Initialize()
162+
{
163+
Native = new agxCable.CableTunnelingGuard( m_hullScale );
164+
165+
var cable = Cable?.GetInitialized<Cable>()?.Native;
166+
if ( cable == null ) {
167+
Debug.LogWarning( "Unable to find Cable component for CableTunnelingGuard - cable tunneling guard instance ignored.", this );
168+
return false;
169+
}
170+
171+
cable.addComponent( Native );
172+
173+
return true;
174+
}
175+
176+
protected override void OnDestroy()
177+
{
178+
if ( GetSimulation() == null )
179+
return;
180+
181+
var cable = Cable.Native;
182+
if ( cable != null ) {
183+
cable.removeComponent( Native );
184+
}
185+
186+
Native = null;
187+
188+
base.OnDestroy();
189+
}
190+
191+
protected override void OnEnable()
192+
{
193+
Native?.setEnabled( true );
194+
}
195+
196+
protected override void OnDisable()
197+
{
198+
Native?.setEnabled( false );
199+
}
200+
201+
private void Reset()
202+
{
203+
if ( GetComponent<Cable>() == null )
204+
Debug.LogError( "Component: CableDamage requires Cable component.", this );
205+
}
206+
207+
private Vector3[] m_pointCurveCache = null;
208+
209+
private bool CheckCableRouteChanges()
210+
{
211+
var routePointCahce = Cable.GetRoutePoints();
212+
if ( m_pointCurveCache != routePointCahce ) {
213+
m_pointCurveCache = routePointCahce;
214+
return true;
215+
}
216+
return false;
217+
}
218+
219+
private void OnDrawGizmosSelected()
220+
{
221+
if ( CheckCableRouteChanges() ) {
222+
UpdateRenderingMesh();
223+
}
224+
225+
if ( enabled ) {
226+
// Algoryx orange
227+
Gizmos.color = new Color32( 0xF3, 0x8B, 0x00, 0xF );
228+
if ( Application.isPlaying && Cable?.Native != null ) {
229+
foreach ( var segment in Cable.Native.getSegments() ) {
230+
Vector3 direction = (segment.getEndPosition() - segment.getBeginPosition()).ToHandedVector3();
231+
Vector3 center = segment.getCenterPosition().ToHandedVector3();
232+
Gizmos.DrawWireMesh( m_mesh, center, Quaternion.FromToRotation( Vector3.up, direction ) );
233+
}
234+
}
235+
else if ( m_pointCurveCache != null && m_pointCurveCache.Length != 0 ) {
236+
Vector3 prevPoint = m_pointCurveCache[0];
237+
foreach ( var point in m_pointCurveCache.Skip( 1 ) ) {
238+
Vector3 direction = point-prevPoint;
239+
Vector3 center = prevPoint + direction * 0.5f;
240+
Gizmos.DrawWireMesh( m_mesh, center, Quaternion.FromToRotation( Vector3.up, direction ) );
241+
prevPoint = point;
242+
}
243+
}
244+
}
245+
}
246+
}
247+
248+
}

Diff for: AGXUnity/CableTunnelingGuard.cs.meta

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: AGXUnity/Rendering/ShapeDebugRenderData.cs

+9
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ public override void Synchronize( DebugRenderManager manager )
121121
if ( Node == null )
122122
return;
123123

124+
Node.layer = manager.gameObject.layer;
125+
Node.TraverseChildren( x => x.layer = manager.gameObject.layer );
126+
124127
// Node created - set properties and extra components.
125128
if ( nodeCreated ) {
126129
Node.hideFlags = HideFlags.DontSave;
@@ -220,6 +223,7 @@ private bool TryInitialize( Shape shape, DebugRenderManager manager )
220223
Cone cone = shape as Cone;
221224
HollowCone hollowCone = shape as HollowCone;
222225
HollowCylinder hollowCylinder = shape as HollowCylinder;
226+
Capsule capsule = shape as Capsule;
223227
if ( mesh != null )
224228
Node = InitializeMesh( mesh );
225229
else if ( heightField != null )
@@ -239,6 +243,11 @@ private bool TryInitialize( Shape shape, DebugRenderManager manager )
239243
Node.AddComponent<MeshRenderer>().sharedMaterial = manager.ShapeRenderMaterial;
240244
Node.AddComponent<MeshFilter>().sharedMesh = ShapeVisualCone.GenerateMesh( shape );
241245
}
246+
else if ( capsule != null ) {
247+
Node = new GameObject( PrefabName );
248+
Node.AddComponent<MeshRenderer>().sharedMaterial = manager.ShapeRenderMaterial;
249+
Node.AddComponent<MeshFilter>().sharedMesh = ShapeVisualCapsule.GenerateMesh( shape );
250+
}
242251
else {
243252
Node = PrefabLoader.Instantiate<GameObject>( PrefabName );
244253
Node.transform.localScale = GetShape().GetScale();

Diff for: AGXUnity/Rendering/ShapeVisual.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ protected static GameObject CreateGameObject( Collide.Shape shape, bool isRender
400400
{
401401
GameObject go = null;
402402
try {
403-
go = isRenderData || shape is Collide.Mesh || shape is Collide.HollowCylinder || shape is Collide.Cone || shape is Collide.HollowCone ?
403+
go = isRenderData || shape is Collide.Mesh || shape is Collide.HollowCylinder || shape is Collide.Cone || shape is Collide.HollowCone || shape is Collide.Capsule ?
404404
new GameObject( "" ) :
405405
PrefabLoader.Instantiate<GameObject>( @"Debug/" + shape.GetType().Name + "Renderer" );
406406

Diff for: AGXUnity/Rendering/ShapeVisualCapsule.cs

+33-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using UnityEngine;
1+
using AGXUnity.Utils;
2+
using System.Linq;
3+
using UnityEngine;
24

35
namespace AGXUnity.Rendering
46
{
@@ -10,15 +12,40 @@ namespace AGXUnity.Rendering
1012
[HelpURL( "https://us.download.algoryx.se/AGXUnity/documentation/current/editor_interface.html#create-visual-tool-icon-small-create-visual-tool" )]
1113
public class ShapeVisualCapsule : ShapeVisual
1214
{
15+
private Mesh m_mesh = null;
16+
17+
private const float m_resolution = 1;
18+
19+
/// <summary>
20+
/// Callback when constructed.
21+
/// </summary>
22+
protected override void OnConstruct()
23+
{
24+
gameObject.AddComponent<MeshFilter>();
25+
gameObject.AddComponent<MeshRenderer>();
26+
27+
m_mesh = GenerateMesh( Shape );
28+
gameObject.GetComponent<MeshFilter>().sharedMesh = m_mesh;
29+
}
30+
1331
/// <summary>
14-
/// Capsule visual is three game objects (2 x half sphere + 1 x cylinder),
15-
/// the size has to be updated to all of the children.
32+
/// Callback from Shape when its size has been changed.
1633
/// </summary>
1734
public override void OnSizeUpdated()
1835
{
19-
ShapeDebugRenderData.SetCapsuleSize( gameObject,
20-
( Shape as Collide.Capsule ).Radius,
21-
( Shape as Collide.Capsule ).Height );
36+
transform.localScale = GetUnscaledScale();
37+
38+
m_mesh = GenerateMesh( Shape );
39+
gameObject.GetComponent<MeshFilter>().sharedMesh = m_mesh;
40+
}
41+
42+
/// <summary>
43+
/// Generates custom shape mesh
44+
/// </summary>
45+
public static Mesh GenerateMesh( Collide.Shape shape )
46+
{
47+
Collide.Capsule capsule = shape as Collide.Capsule;
48+
return CapsuleShapeUtils.CreateCapsuleMesh( capsule.Radius, capsule.Height, m_resolution );
2249
}
2350
}
2451
}

Diff for: AGXUnity/RouteNode.cs

+8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
using System;
2+
using UnityEngine;
23

34
namespace AGXUnity
45
{
6+
public interface IExtraNodeData
7+
{
8+
public abstract bool Initialize( WireRouteNode parent );
9+
}
10+
511
[Serializable]
612
public abstract class RouteNode : IFrame
713
{
14+
[field: SerializeReference]
15+
public IExtraNodeData NodeData { get; protected set; } = null;
816
}
917
}

0 commit comments

Comments
 (0)