[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [16706] trunk/blender/source/gameengine/ Ketsji: BGE bug #17657 fixed: dRotY doesn' t work properly after 90 degrees rotation.

Benoit Bolsee benoit.bolsee at online.be
Tue Sep 23 22:07:16 CEST 2008


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;
 





More information about the Bf-blender-cvs mailing list