Revision: 16706
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=16706
Author: ben2610
Date: 2008-09-23 22:07:15 +0200 (Tue, 23 Sep 2008)
Log Message:
-----------
BGE bug #17657 fixed: dRotY doesn't work properly after 90 degrees rotation.
This problem is caused by discontinuities in the conversion
orientation matrix -> euler angles: the angle sign can
switch and thus the direction of the rotation produced
by the dRot Ipo.
To avoid this bug, the matrix->euler conversion must be
avoided during the game. I took the following approach that
is compatible with Blender (identical effect in the game and
in the 3D view):
- no change in Add mode: Rot and dRot are treated as additional
rotation to the orientation at the start of the Ipo. There is
no matrix->euler conversion and thus no discontinuities.
- Rot Ipo are treated as absolute rotation. All 3 axis should
be specified but if they are not, the startup object orientation
will be used to set the unspecified axis. By doing a matrix->
euler conversion once at the start, the discontinuities are
avoided. If there are also dRot curves, they are treated as
delta of the corresponding Rot curve or startup angle.
- dRot Ipo are treated as Add mode in Local axis.
Note about Add mode: Rot and dRot curves are treated identically
during the game. However, only dRot curves make sense because
they don't interfere with the object orientation in the 3D view.
Modified Paths:
--------------
trunk/blender/source/gameengine/Ketsji/KX_IPO_SGController.cpp
trunk/blender/source/gameengine/Ketsji/KX_IPO_SGController.h
Modified: trunk/blender/source/gameengine/Ketsji/KX_IPO_SGController.cpp
===================================================================
--- trunk/blender/source/gameengine/Ketsji/KX_IPO_SGController.cpp
2008-09-23 15:57:05 UTC (rev 16705)
+++ trunk/blender/source/gameengine/Ketsji/KX_IPO_SGController.cpp
2008-09-23 20:07:15 UTC (rev 16706)
@@ -59,7 +59,9 @@
m_ipo_local(false),
m_modified(true),
m_ipo_start_initialized(false),
- m_ipotime(1.0)
+ m_ipotime(1.0),
+ m_ipo_start_euler(0.0,0.0,0.0),
+ m_ipo_euler_initialized(false)
{
m_game_object = NULL;
for (int i=0; i < KX_MAX_IPO_CHANNELS; i++)
@@ -136,6 +138,11 @@
m_ipo_start_orient = ob->GetLocalOrientation();
m_ipo_start_scale = ob->GetLocalScale();
m_ipo_start_initialized = true;
+ if (!m_ipo_euler_initialized) {
+ // do it only once to avoid angle
discontinuities
+
m_ipo_start_orient.getEuler(m_ipo_start_euler[0], m_ipo_start_euler[1],
m_ipo_start_euler[2]);
+ m_ipo_euler_initialized = true;
+ }
}
//modifies position?
@@ -199,51 +206,87 @@
ob->GetWorldOrientation() *
m_ipo_xform.GetEulerAngles() :
m_ipo_xform.GetEulerAngles(),
false);
}
- } else {
- double yaw=0, pitch=0, roll=0; //final Euler
angles
- double tempYaw=0, tempPitch=0, tempRoll=0;
//temp holders
- if (!m_ipo_add)
- ob->GetLocalOrientation().getEuler(yaw,
pitch, roll);
+ } else if (m_ipo_add) {
+ if (m_ipo_start_initialized) {
+ double yaw=0, pitch=0, roll=0; //delta
Euler angles
- //RotX and dRotX
- if (m_ipo_channels_active[OB_ROT_X]) {
- yaw = (m_ipo_channels_active[OB_DROT_X]
? (m_ipo_xform.GetEulerAngles()[0] + m_ipo_xform.GetDeltaEulerAngles()[0]) :
m_ipo_xform.GetEulerAngles()[0] );
- }
- else if (m_ipo_channels_active[OB_DROT_X] &&
m_ipo_start_initialized) {
- if (!m_ipo_add)
-
m_ipo_start_orient.getEuler(tempYaw, tempPitch, tempRoll);
- yaw = tempYaw +
m_ipo_xform.GetDeltaEulerAngles()[0];
- }
+ //RotX and dRotX
+ if (m_ipo_channels_active[OB_ROT_X])
+ yaw +=
m_ipo_xform.GetEulerAngles()[0];
+ if (m_ipo_channels_active[OB_DROT_X])
+ yaw +=
m_ipo_xform.GetDeltaEulerAngles()[0];
- //RotY dRotY
- if (m_ipo_channels_active[OB_ROT_Y]) {
- pitch =
(m_ipo_channels_active[OB_DROT_Y] ? (m_ipo_xform.GetEulerAngles()[1] +
m_ipo_xform.GetDeltaEulerAngles()[1]) : m_ipo_xform.GetEulerAngles()[1] );
- }
- else if (m_ipo_channels_active[OB_DROT_Y] &&
m_ipo_start_initialized) {
- if (!m_ipo_add)
-
m_ipo_start_orient.getEuler(tempYaw, tempPitch, tempRoll);
- pitch = tempPitch +
m_ipo_xform.GetDeltaEulerAngles()[1];
- }
-
- //RotZ and dRotZ
- if (m_ipo_channels_active[OB_ROT_Z]) {
- roll =
(m_ipo_channels_active[OB_DROT_Z] ? (m_ipo_xform.GetEulerAngles()[2] +
m_ipo_xform.GetDeltaEulerAngles()[2]) : m_ipo_xform.GetEulerAngles()[2] );
- }
- else if (m_ipo_channels_active[OB_DROT_Z] &&
m_ipo_start_initialized) {
- if (!m_ipo_add)
-
m_ipo_start_orient.getEuler(tempYaw, tempPitch, tempRoll);
- roll = tempRoll +
m_ipo_xform.GetDeltaEulerAngles()[2];
- }
- if (m_ipo_add) {
+ //RotY dRotY
+ if (m_ipo_channels_active[OB_ROT_Y])
+ pitch +=
m_ipo_xform.GetEulerAngles()[1];
+ if (m_ipo_channels_active[OB_DROT_Y])
+ pitch +=
m_ipo_xform.GetDeltaEulerAngles()[1];
+
+ //RotZ and dRotZ
+ if (m_ipo_channels_active[OB_ROT_Z])
+ roll +=
m_ipo_xform.GetEulerAngles()[2];
+ if (m_ipo_channels_active[OB_DROT_Z])
+ roll +=
m_ipo_xform.GetDeltaEulerAngles()[2];
+
MT_Matrix3x3 rotation(MT_Vector3(yaw,
pitch, roll));
if (m_ipo_local)
rotation = m_ipo_start_orient *
rotation;
else
rotation = rotation *
m_ipo_start_orient;
ob->SetLocalOrientation(rotation);
- } else {
+ }
+ } else if (m_ipo_channels_active[OB_ROT_X] ||
m_ipo_channels_active[OB_ROT_Y] || m_ipo_channels_active[OB_ROT_Z]) {
+ if (m_ipo_euler_initialized) {
+ // assume all channel absolute
+ // All 3 channels should be specified
but if they are not, we will take
+ // the value at the start of the game
to avoid angle sign reversal
+ double yaw=m_ipo_start_euler[0],
pitch=m_ipo_start_euler[1], roll=m_ipo_start_euler[2];
+
+ //RotX and dRotX
+ if (m_ipo_channels_active[OB_ROT_X]) {
+ yaw =
(m_ipo_channels_active[OB_DROT_X] ? (m_ipo_xform.GetEulerAngles()[0] +
m_ipo_xform.GetDeltaEulerAngles()[0]) : m_ipo_xform.GetEulerAngles()[0] );
+ }
+ else if
(m_ipo_channels_active[OB_DROT_X]) {
+ yaw +=
m_ipo_xform.GetDeltaEulerAngles()[0];
+ }
+
+ //RotY dRotY
+ if (m_ipo_channels_active[OB_ROT_Y]) {
+ pitch =
(m_ipo_channels_active[OB_DROT_Y] ? (m_ipo_xform.GetEulerAngles()[1] +
m_ipo_xform.GetDeltaEulerAngles()[1]) : m_ipo_xform.GetEulerAngles()[1] );
+ }
+ else if
(m_ipo_channels_active[OB_DROT_Y]) {
+ pitch +=
m_ipo_xform.GetDeltaEulerAngles()[1];
+ }
+
+ //RotZ and dRotZ
+ if (m_ipo_channels_active[OB_ROT_Z]) {
+ roll =
(m_ipo_channels_active[OB_DROT_Z] ? (m_ipo_xform.GetEulerAngles()[2] +
m_ipo_xform.GetDeltaEulerAngles()[2]) : m_ipo_xform.GetEulerAngles()[2] );
+ }
+ else if
(m_ipo_channels_active[OB_DROT_Z]) {
+ roll +=
m_ipo_xform.GetDeltaEulerAngles()[2];
+ }
ob->SetLocalOrientation(MT_Vector3(yaw,
pitch, roll));
}
+ } else if (m_ipo_start_initialized) {
+ // only DROT, treat as Add
+ double yaw=0, pitch=0, roll=0; //delta Euler
angles
+
+ //dRotX
+ if (m_ipo_channels_active[OB_DROT_X])
+ yaw =
m_ipo_xform.GetDeltaEulerAngles()[0];
+
+ //dRotY
+ if (m_ipo_channels_active[OB_DROT_Y])
+ pitch =
m_ipo_xform.GetDeltaEulerAngles()[1];
+
+ //dRotZ
+ if (m_ipo_channels_active[OB_DROT_Z])
+ roll =
m_ipo_xform.GetDeltaEulerAngles()[2];
+
+ // dRot are always local
+ MT_Matrix3x3 rotation(MT_Vector3(yaw, pitch,
roll));
+ rotation = m_ipo_start_orient * rotation;
+ ob->SetLocalOrientation(rotation);
}
}
//modifies scale?
Modified: trunk/blender/source/gameengine/Ketsji/KX_IPO_SGController.h
===================================================================
--- trunk/blender/source/gameengine/Ketsji/KX_IPO_SGController.h
2008-09-23 15:57:05 UTC (rev 16705)
+++ trunk/blender/source/gameengine/Ketsji/KX_IPO_SGController.h
2008-09-23 20:07:15 UTC (rev 16706)
@@ -72,6 +72,12 @@
/** if IPO initial position has been set for local normal IPO */
bool m_ipo_start_initialized;
+ /** Euler angles at the start of the game, needed for incomplete ROT
Ipo curves */
+ class MT_Vector3 m_ipo_start_euler;
+
+ /** true is m_ipo_start_euler has been initialized */
+ bool m_ipo_euler_initialized;
+
/** A reference to the original game object. */
class KX_GameObject* m_game_object;
_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs