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

Reply via email to