summaryrefslogtreecommitdiff
path: root/Runtime/Dynamics/HingeJoint.cpp
blob: 949496092b3a0a9c1eb657f07e027f53530afde1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
#include "UnityPrefix.h"
#if ENABLE_PHYSICS
#include "Runtime/Utilities/StaticAssert.h"
#include "HingeJoint.h"
#include "Runtime/Misc/BuildSettings.h"
#include "Runtime/Serialize/TransferFunctions/SerializeTransfer.h"
#include "PhysicsManager.h"

#include "External/PhysX/builds/SDKs/Physics/include/NxPhysics.h"

using namespace std;

namespace Unity
{

#define GET_JOINT() static_cast<NxRevoluteJoint*> (m_Joint)

/*
- We awake the hingejoint only once. (AwakeFromLoad)
  At this point we setup the axes. They are never changed afterwards
  -> The perfect solution remembers the old position/rotation of the rigid bodies.
      Then when changing axis/anchor is changed it generates axes that are rleative to the old position/rotation state!
*/

HingeJoint::HingeJoint (MemLabelId label, ObjectCreationMode mode)
:	Super(label, mode)
{
	InitJointLimits (m_Limits);
	InitJointSpring (m_Spring);
	InitJointMotor (m_Motor);

	m_UseLimits = false;
	m_UseMotor = false;
	m_UseSpring = false;

	CompileTimeAssert(sizeof(JointMotor)  == sizeof(NxMotorDesc), "Unity JointMotor type has different size from physx one");
	CompileTimeAssert(sizeof(JointSpring) == sizeof(NxSpringDesc), "Unity JointSpring type has different size from physx one");
	CompileTimeAssert(sizeof(JointLimits) == sizeof(NxJointLimitPairDesc), "Unity JointLimits type has different size from physx one");
}

HingeJoint::~HingeJoint ()
{
}

inline NxSpringDesc ToNovodex (const JointSpring& spring)
{
	JointSpring desc = spring;
	desc.targetPosition = Deg2Rad (desc.targetPosition);
	return (const NxSpringDesc&)desc;
}

inline NxMotorDesc ToNovodex (const JointMotor& motor)
{
	JointMotor desc = motor;
	desc.targetVelocity = Deg2Rad (desc.targetVelocity);
	return (const NxMotorDesc&)desc;
}

#define kHingeJointLimitError "Joint limits for hinge joint out of bounds. Limits need to be between -360 and 360 degrees."
inline NxJointLimitPairDesc ToNovodex (const JointLimits& limits)
{
	NxJointLimitPairDesc l = (const NxJointLimitPairDesc&)limits;
	if(IS_CONTENT_NEWER_OR_SAME(kUnityVersion4_2_a1))
	{
		// PhysX specs limit hinge joints to [-180,180] degress. But it seems 360 works fine
		// and is very useful in practice. Higher numbers produce broken results (case 492847)
		if (l.low.value < -360)
		{
			l.low.value = -360;
			ErrorString (kHingeJointLimitError);
		}
		if (l.low.value > 360)
		{
			l.low.value = 360;
			ErrorString (kHingeJointLimitError);
		}
		if (l.high.value < -360)
		{
			l.high.value = -360;
			ErrorString (kHingeJointLimitError);
		}
		if (l.high.value > 360)
		{
			l.high.value = 360;
			ErrorString (kHingeJointLimitError);
		}
	}
	l.low.value = Deg2Rad (l.low.value);
	l.high.value = Deg2Rad (l.high.value);

	/// DO SOME SPECIAL HANDLING WHEN LOW IS LARGER THAN HIGH!!!!!
	/// MAKE IT MORE INTUITIVE

	if (l.low.value > l.high.value)
		swap (l.low, l.high);

	return l;
}

void HingeJoint::SetUseMotor (bool enable)
{
	SetDirty ();
	m_UseMotor = enable;
	if (m_Joint)
	{
		UInt32 flags = GET_JOINT()->getFlags ();
		if (enable)
			flags |= NX_RJF_MOTOR_ENABLED;
		else
			flags &= ~NX_RJF_MOTOR_ENABLED;
		GET_JOINT()->setFlags (flags);
	}
}

bool HingeJoint::GetUseMotor () const
{
	return m_UseMotor;
}

void HingeJoint::SetUseLimits (bool enable)
{
	SetDirty ();
	m_UseLimits = enable;
	if (m_Joint)
	{
		UInt32 flags = GET_JOINT()->getFlags ();
		if (enable)
			flags |= NX_RJF_LIMIT_ENABLED;
		else
			flags &= ~NX_RJF_LIMIT_ENABLED;
		GET_JOINT()->setFlags (flags);
	}
}

bool HingeJoint::GetUseLimits () const
{
	return m_UseLimits;
}

void HingeJoint::SetUseSpring (bool enable)
{
	SetDirty ();
	m_UseSpring = enable;
	if (m_Joint)
	{
		UInt32 flags = GET_JOINT()->getFlags ();
		if (enable)
			flags |= NX_RJF_SPRING_ENABLED;
		else
			flags &= ~NX_RJF_SPRING_ENABLED;
		GET_JOINT()->setFlags (flags);
	}
}

bool HingeJoint::GetUseSpring () const
{
	return m_UseSpring;
}

JointMotor HingeJoint::GetMotor () const
{
	return m_Motor;
}

void HingeJoint::SetMotor (const JointMotor& motor)
{
	SetDirty ();
	m_Motor = motor;
	if (m_Joint)
	{
		GET_JOINT()->setMotor (ToNovodex (motor));
	}
}

JointSpring HingeJoint::GetSpring () const
{
	return m_Spring;
}

void HingeJoint::SetSpring (const JointSpring& spring)
{
	SetDirty ();
	m_Spring = spring;
	if (m_Joint)
		GET_JOINT()->setSpring (ToNovodex (spring));
}

JointLimits HingeJoint::GetLimits () const
{
	return m_Limits;
}

void HingeJoint::SetLimits (const JointLimits& limits)
{
	SetDirty ();
	m_Limits = limits;
	if (m_Joint)
	{
		GET_JOINT()->setLimits (ToNovodex (limits));

		// Novodex seems to have a bug that it will not update HingeJoints when only the limits are changed.
		// Also call setMotor to force it to update.
		GET_JOINT()->setMotor (ToNovodex (m_Motor));
	}
}

float HingeJoint::GetVelocity () const
{
	if (m_Joint)
		return Rad2Deg (GET_JOINT()->getVelocity ());
	else
		return 0.0F;
}

float HingeJoint::GetAngle () const
{
	if (m_Joint)
		return Rad2Deg (GET_JOINT()->getAngle ());
	else
		return 0.0F;
}

/*
- When the rigid body which is attached with the hinge joint is activated after the joint is loaded
  It will not be connected with the joint!
*/

template<class TransferFunction>
void HingeJoint::Transfer (TransferFunction& transfer)
{
	JointTransferPre (transfer);

	TRANSFER (m_UseSpring);
	transfer.Align();
	TRANSFER (m_Spring);

	TRANSFER (m_UseMotor);
	transfer.Align();
	TRANSFER (m_Motor);

	TRANSFER (m_UseLimits);
	transfer.Align();
	TRANSFER (m_Limits);

	JointTransferPost (transfer);
}

void HingeJoint::Create ()
{
	AssertIf (!IsActive ());

	NxRevoluteJointDesc desc;

	if (m_Joint && m_Joint->getState () == NX_JS_SIMULATING)
		GET_JOINT()->saveToDesc (desc);

	desc.motor = ToNovodex (m_Motor);
	desc.limit = ToNovodex (m_Limits);
	desc.spring = ToNovodex (m_Spring);

	desc.flags = 0;
	if (m_UseMotor)
		desc.flags |= NX_RJF_MOTOR_ENABLED;
	if (m_UseLimits)
		desc.flags |= NX_RJF_LIMIT_ENABLED;
	if (m_UseSpring)
		desc.flags |= NX_RJF_SPRING_ENABLED;

	FINALIZE_CREATE (desc, NxRevoluteJoint);
}

IMPLEMENT_AXIS_ANCHOR(HingeJoint,NxRevoluteJointDesc)

}

IMPLEMENT_CLASS (HingeJoint)
IMPLEMENT_OBJECT_SERIALIZE (HingeJoint)

#undef GET_JOINT
#endif //ENABLE_PHSYICS