bool KX_TrackToActuator::Update(double curtime, bool frame) { bool result = false; bool bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); if (bNegativeEvent) { // do nothing on negative events } else if (m_object) { KX_GameObject* curobj = (KX_GameObject*) GetParent(); MT_Vector3 dir = curobj->NodeGetWorldPosition() - ((KX_GameObject*)m_object)->NodeGetWorldPosition(); MT_Matrix3x3 mat; MT_Matrix3x3 oldmat; mat = vectomat(dir, m_trackflag, m_upflag, m_allow3D); oldmat = curobj->NodeGetWorldOrientation(); /* erwin should rewrite this! */ mat = matrix3x3_interpol(oldmat, mat, m_time); /* check if the model is parented and calculate the child transform */ if (m_parentobj) { MT_Point3 localpos; localpos = curobj->GetSGNode()->GetLocalPosition(); // Get the inverse of the parent matrix MT_Matrix3x3 parentmatinv; parentmatinv = m_parentobj->NodeGetWorldOrientation().inverse(); // transform the local coordinate system into the parents system mat = parentmatinv * mat; // append the initial parent local rotation matrix mat = m_parentlocalmat * mat; // set the models tranformation properties curobj->NodeSetLocalOrientation(mat); curobj->NodeSetLocalPosition(localpos); //curobj->UpdateTransform(); } else { curobj->NodeSetLocalOrientation(mat); } result = true; } return result; }
void KX_BlenderSceneConverter::resetNoneDynamicObjectToIpo() { if (addInitFromFrame) { KX_SceneList* scenes = m_ketsjiEngine->CurrentScenes(); int numScenes = scenes->size(); if (numScenes>=0) { KX_Scene* scene = scenes->at(0); CListValue* parentList = scene->GetRootParentList(); for (int ix=0;ix<parentList->GetCount();ix++) { KX_GameObject* gameobj = (KX_GameObject*)parentList->GetValue(ix); if (!gameobj->IsDynamic()) { Object* blenderobject = gameobj->GetBlenderObject(); if (!blenderobject) continue; if (blenderobject->type==OB_ARMATURE) continue; float eu[3]; mat4_to_eul(eu,blenderobject->obmat); MT_Point3 pos = MT_Point3( blenderobject->obmat[3][0], blenderobject->obmat[3][1], blenderobject->obmat[3][2] ); MT_Vector3 eulxyz = MT_Vector3( eu[0], eu[1], eu[2] ); MT_Vector3 scale = MT_Vector3( blenderobject->size[0], blenderobject->size[1], blenderobject->size[2] ); gameobj->NodeSetLocalPosition(pos); gameobj->NodeSetLocalOrientation(MT_Matrix3x3(eulxyz)); gameobj->NodeSetLocalScale(scale); gameobj->NodeUpdateGS(0); } } } } }
bool KX_ConstraintActuator::Update(double curtime, bool frame) { bool result = false; bool bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); if (!bNegativeEvent) { /* Constraint clamps the values to the specified range, with a sort of */ /* low-pass filtered time response, if the damp time is unequal to 0. */ /* Having to retrieve location/rotation and setting it afterwards may not */ /* be efficient enough... Something to look at later. */ KX_GameObject *obj = (KX_GameObject*) GetParent(); MT_Vector3 position = obj->NodeGetWorldPosition(); MT_Vector3 newposition; MT_Vector3 normal, direction, refDirection; MT_Matrix3x3 rotation = obj->NodeGetWorldOrientation(); MT_Scalar filter, newdistance, cosangle; int axis, sign; if (m_posDampTime) { filter = m_posDampTime/(1.0f+m_posDampTime); } else { filter = 0.0f; } switch (m_locrot) { case KX_ACT_CONSTRAINT_ORIX: case KX_ACT_CONSTRAINT_ORIY: case KX_ACT_CONSTRAINT_ORIZ: switch (m_locrot) { case KX_ACT_CONSTRAINT_ORIX: direction[0] = rotation[0][0]; direction[1] = rotation[1][0]; direction[2] = rotation[2][0]; axis = 0; break; case KX_ACT_CONSTRAINT_ORIY: direction[0] = rotation[0][1]; direction[1] = rotation[1][1]; direction[2] = rotation[2][1]; axis = 1; break; default: direction[0] = rotation[0][2]; direction[1] = rotation[1][2]; direction[2] = rotation[2][2]; axis = 2; break; } if ((m_maximumBound < (1.0f-FLT_EPSILON)) || (m_minimumBound < (1.0f-FLT_EPSILON))) { // reference direction needs to be evaluated // 1. get the cosine between current direction and target cosangle = direction.dot(m_refDirVector); if (cosangle >= (m_maximumBound-FLT_EPSILON) && cosangle <= (m_minimumBound+FLT_EPSILON)) { // no change to do result = true; goto CHECK_TIME; } // 2. define a new reference direction // compute local axis with reference direction as X and // Y in direction X refDirection plane MT_Vector3 zaxis = m_refDirVector.cross(direction); if (MT_fuzzyZero2(zaxis.length2())) { // direction and refDirection are identical, // choose any other direction to define plane if (direction[0] < 0.9999f) zaxis = m_refDirVector.cross(MT_Vector3(1.0f,0.0f,0.0f)); else zaxis = m_refDirVector.cross(MT_Vector3(0.0f,1.0f,0.0f)); } MT_Vector3 yaxis = zaxis.cross(m_refDirVector); yaxis.normalize(); if (cosangle > m_minimumBound) { // angle is too close to reference direction, // choose a new reference that is exactly at minimum angle refDirection = m_minimumBound * m_refDirVector + m_minimumSine * yaxis; } else { // angle is too large, choose new reference direction at maximum angle refDirection = m_maximumBound * m_refDirVector + m_maximumSine * yaxis; } } else { refDirection = m_refDirVector; } // apply damping on the direction direction = filter*direction + (1.0f-filter)*refDirection; obj->AlignAxisToVect(direction, axis); result = true; goto CHECK_TIME; case KX_ACT_CONSTRAINT_DIRPX: case KX_ACT_CONSTRAINT_DIRPY: case KX_ACT_CONSTRAINT_DIRPZ: case KX_ACT_CONSTRAINT_DIRNX: case KX_ACT_CONSTRAINT_DIRNY: case KX_ACT_CONSTRAINT_DIRNZ: switch (m_locrot) { case KX_ACT_CONSTRAINT_DIRPX: normal[0] = rotation[0][0]; normal[1] = rotation[1][0]; normal[2] = rotation[2][0]; axis = 0; // axis according to KX_GameObject::AlignAxisToVect() sign = 0; // X axis will be parrallel to direction of ray break; case KX_ACT_CONSTRAINT_DIRPY: normal[0] = rotation[0][1]; normal[1] = rotation[1][1]; normal[2] = rotation[2][1]; axis = 1; sign = 0; break; case KX_ACT_CONSTRAINT_DIRPZ: normal[0] = rotation[0][2]; normal[1] = rotation[1][2]; normal[2] = rotation[2][2]; axis = 2; sign = 0; break; case KX_ACT_CONSTRAINT_DIRNX: normal[0] = -rotation[0][0]; normal[1] = -rotation[1][0]; normal[2] = -rotation[2][0]; axis = 0; sign = 1; break; case KX_ACT_CONSTRAINT_DIRNY: normal[0] = -rotation[0][1]; normal[1] = -rotation[1][1]; normal[2] = -rotation[2][1]; axis = 1; sign = 1; break; case KX_ACT_CONSTRAINT_DIRNZ: normal[0] = -rotation[0][2]; normal[1] = -rotation[1][2]; normal[2] = -rotation[2][2]; axis = 2; sign = 1; break; } normal.normalize(); if (m_option & KX_ACT_CONSTRAINT_LOCAL) { // direction of the ray is along the local axis direction = normal; } else { switch (m_locrot) { case KX_ACT_CONSTRAINT_DIRPX: direction = MT_Vector3(1.0f,0.0f,0.0f); break; case KX_ACT_CONSTRAINT_DIRPY: direction = MT_Vector3(0.0f,1.0f,0.0f); break; case KX_ACT_CONSTRAINT_DIRPZ: direction = MT_Vector3(0.0f,0.0f,1.0f); break; case KX_ACT_CONSTRAINT_DIRNX: direction = MT_Vector3(-1.0f,0.0f,0.0f); break; case KX_ACT_CONSTRAINT_DIRNY: direction = MT_Vector3(0.0f,-1.0f,0.0f); break; case KX_ACT_CONSTRAINT_DIRNZ: direction = MT_Vector3(0.0f,0.0f,-1.0f); break; } } { MT_Vector3 topoint = position + (m_maximumBound) * direction; PHY_IPhysicsEnvironment* pe = KX_GetActiveScene()->GetPhysicsEnvironment(); PHY_IPhysicsController *spc = obj->GetPhysicsController(); if (!pe) { CM_LogicBrickWarning(this, "there is no physics environment!"); goto CHECK_TIME; } if (!spc) { // the object is not physical, we probably want to avoid hitting its own parent KX_GameObject *parent = obj->GetParent(); if (parent) { spc = parent->GetPhysicsController(); } } KX_RayCast::Callback<KX_ConstraintActuator, void> callback(this,dynamic_cast<PHY_IPhysicsController*>(spc)); result = KX_RayCast::RayTest(pe, position, topoint, callback); if (result) { MT_Vector3 newnormal = callback.m_hitNormal; // compute new position & orientation if ((m_option & (KX_ACT_CONSTRAINT_NORMAL|KX_ACT_CONSTRAINT_DISTANCE)) == 0) { // if none option is set, the actuator does nothing but detect ray // (works like a sensor) goto CHECK_TIME; } if (m_option & KX_ACT_CONSTRAINT_NORMAL) { MT_Scalar rotFilter; // apply damping on the direction if (m_rotDampTime) { rotFilter = m_rotDampTime/(1.0f+m_rotDampTime); } else { rotFilter = filter; } newnormal = rotFilter*normal - (1.0f-rotFilter)*newnormal; obj->AlignAxisToVect((sign)?-newnormal:newnormal, axis); if (m_option & KX_ACT_CONSTRAINT_LOCAL) { direction = newnormal; direction.normalize(); } } if (m_option & KX_ACT_CONSTRAINT_DISTANCE) { if (m_posDampTime) { newdistance = filter*(position-callback.m_hitPoint).length()+(1.0f-filter)*m_minimumBound; } else { newdistance = m_minimumBound; } // logically we should cancel the speed along the ray direction as we set the // position along that axis spc = obj->GetPhysicsController(); if (spc && spc->IsDynamic()) { MT_Vector3 linV = spc->GetLinearVelocity(); // cancel the projection along the ray direction MT_Scalar fallspeed = linV.dot(direction); if (!MT_fuzzyZero(fallspeed)) spc->SetLinearVelocity(linV-fallspeed*direction,false); } } else { newdistance = (position-callback.m_hitPoint).length(); } newposition = callback.m_hitPoint-newdistance*direction; } else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) { // no contact but still keep running result = true; goto CHECK_TIME; } } break; case KX_ACT_CONSTRAINT_FHPX: case KX_ACT_CONSTRAINT_FHPY: case KX_ACT_CONSTRAINT_FHPZ: case KX_ACT_CONSTRAINT_FHNX: case KX_ACT_CONSTRAINT_FHNY: case KX_ACT_CONSTRAINT_FHNZ: switch (m_locrot) { case KX_ACT_CONSTRAINT_FHPX: normal[0] = -rotation[0][0]; normal[1] = -rotation[1][0]; normal[2] = -rotation[2][0]; direction = MT_Vector3(1.0f,0.0f,0.0f); break; case KX_ACT_CONSTRAINT_FHPY: normal[0] = -rotation[0][1]; normal[1] = -rotation[1][1]; normal[2] = -rotation[2][1]; direction = MT_Vector3(0.0f,1.0f,0.0f); break; case KX_ACT_CONSTRAINT_FHPZ: normal[0] = -rotation[0][2]; normal[1] = -rotation[1][2]; normal[2] = -rotation[2][2]; direction = MT_Vector3(0.0f,0.0f,1.0f); break; case KX_ACT_CONSTRAINT_FHNX: normal[0] = rotation[0][0]; normal[1] = rotation[1][0]; normal[2] = rotation[2][0]; direction = MT_Vector3(-1.0f,0.0f,0.0f); break; case KX_ACT_CONSTRAINT_FHNY: normal[0] = rotation[0][1]; normal[1] = rotation[1][1]; normal[2] = rotation[2][1]; direction = MT_Vector3(0.0f,-1.0f,0.0f); break; case KX_ACT_CONSTRAINT_FHNZ: normal[0] = rotation[0][2]; normal[1] = rotation[1][2]; normal[2] = rotation[2][2]; direction = MT_Vector3(0.0f,0.0f,-1.0f); break; } normal.normalize(); { PHY_IPhysicsEnvironment* pe = KX_GetActiveScene()->GetPhysicsEnvironment(); PHY_IPhysicsController *spc = obj->GetPhysicsController(); if (!pe) { CM_LogicBrickWarning(this, "there is no physics environment!"); goto CHECK_TIME; } if (!spc || !spc->IsDynamic()) { // the object is not dynamic, it won't support setting speed goto CHECK_TIME; } m_hitObject = NULL; // distance of Fh area is stored in m_minimum MT_Vector3 topoint = position + (m_minimumBound+spc->GetRadius()) * direction; KX_RayCast::Callback<KX_ConstraintActuator, void> callback(this, spc); result = KX_RayCast::RayTest(pe, position, topoint, callback); // we expect a hit object if (!m_hitObject) result = false; if (result) { MT_Vector3 newnormal = callback.m_hitNormal; // compute new position & orientation MT_Scalar distance = (callback.m_hitPoint-position).length()-spc->GetRadius(); // estimate the velocity of the hit point MT_Vector3 relativeHitPoint; relativeHitPoint = (callback.m_hitPoint-m_hitObject->NodeGetWorldPosition()); MT_Vector3 velocityHitPoint = m_hitObject->GetVelocity(relativeHitPoint); MT_Vector3 relativeVelocity = spc->GetLinearVelocity() - velocityHitPoint; MT_Scalar relativeVelocityRay = direction.dot(relativeVelocity); MT_Scalar springExtent = 1.0f - distance/m_minimumBound; // Fh force is stored in m_maximum MT_Scalar springForce = springExtent * m_maximumBound; // damping is stored in m_refDirection [0] = damping, [1] = rot damping MT_Scalar springDamp = relativeVelocityRay * m_refDirVector[0]; MT_Vector3 newVelocity = spc->GetLinearVelocity()-(springForce+springDamp)*direction; if (m_option & KX_ACT_CONSTRAINT_NORMAL) { newVelocity+=(springForce+springDamp)*(newnormal-newnormal.dot(direction)*direction); } spc->SetLinearVelocity(newVelocity, false); if (m_option & KX_ACT_CONSTRAINT_DOROTFH) { MT_Vector3 angSpring = (normal.cross(newnormal))*m_maximumBound; MT_Vector3 angVelocity = spc->GetAngularVelocity(); // remove component that is parallel to normal angVelocity -= angVelocity.dot(newnormal)*newnormal; MT_Vector3 angDamp = angVelocity * ((m_refDirVector[1]>MT_EPSILON)?m_refDirVector[1]:m_refDirVector[0]); spc->SetAngularVelocity(spc->GetAngularVelocity()+(angSpring-angDamp), false); } } else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) { // no contact but still keep running result = true; } // don't set the position with this constraint goto CHECK_TIME; } break; case KX_ACT_CONSTRAINT_LOCX: case KX_ACT_CONSTRAINT_LOCY: case KX_ACT_CONSTRAINT_LOCZ: newposition = position = obj->GetSGNode()->GetLocalPosition(); switch (m_locrot) { case KX_ACT_CONSTRAINT_LOCX: Clamp(newposition[0], m_minimumBound, m_maximumBound); break; case KX_ACT_CONSTRAINT_LOCY: Clamp(newposition[1], m_minimumBound, m_maximumBound); break; case KX_ACT_CONSTRAINT_LOCZ: Clamp(newposition[2], m_minimumBound, m_maximumBound); break; } result = true; if (m_posDampTime) { newposition = filter*position + (1.0f-filter)*newposition; } obj->NodeSetLocalPosition(newposition); goto CHECK_TIME; } if (result) { // set the new position but take into account parent if any obj->NodeSetWorldPosition(newposition); } CHECK_TIME: if (result && m_activeTime > 0 ) { if (++m_currentTime >= m_activeTime) result = false; } } if (!result) { m_currentTime = 0; } return result; } /* end of KX_ConstraintActuator::Update(double curtime,double deltatime) */
void KX_SteeringActuator::HandleActorFace(MT_Vector3& velocity) { if (m_facingMode==0 && (!m_navmesh || !m_normalUp)) return; KX_GameObject* curobj = (KX_GameObject*) GetParent(); MT_Vector3 dir = m_facingMode==0 ? curobj->NodeGetLocalOrientation().getColumn(1) : velocity; if (dir.fuzzyZero()) return; dir.normalize(); MT_Vector3 up(0,0,1); MT_Vector3 left; MT_Matrix3x3 mat; if (m_navmesh && m_normalUp) { dtStatNavMesh* navmesh = m_navmesh->GetNavMesh(); MT_Vector3 normal; MT_Vector3 trpos = m_navmesh->TransformToLocalCoords(curobj->NodeGetWorldPosition()); if (getNavmeshNormal(navmesh, trpos, normal)) { left = (dir.cross(up)).safe_normalized(); dir = (-left.cross(normal)).safe_normalized(); up = normal; } } switch (m_facingMode) { case 1: // TRACK X { left = dir.safe_normalized(); dir = -(left.cross(up)).safe_normalized(); break; }; case 2: // TRACK Y { left = (dir.cross(up)).safe_normalized(); break; } case 3: // track Z { left = up.safe_normalized(); up = dir.safe_normalized(); dir = left; left = (dir.cross(up)).safe_normalized(); break; } case 4: // TRACK -X { left = -dir.safe_normalized(); dir = -(left.cross(up)).safe_normalized(); break; }; case 5: // TRACK -Y { left = (-dir.cross(up)).safe_normalized(); dir = -dir; break; } case 6: // track -Z { left = up.safe_normalized(); up = -dir.safe_normalized(); dir = left; left = (dir.cross(up)).safe_normalized(); break; } } mat.setValue ( left[0], dir[0],up[0], left[1], dir[1],up[1], left[2], dir[2],up[2] ); KX_GameObject* parentObject = curobj->GetParent(); if (parentObject) { MT_Vector3 localpos; localpos = curobj->GetSGNode()->GetLocalPosition(); MT_Matrix3x3 parentmatinv; parentmatinv = parentObject->NodeGetWorldOrientation ().inverse (); mat = parentmatinv * mat; mat = m_parentlocalmat * mat; curobj->NodeSetLocalOrientation(mat); curobj->NodeSetLocalPosition(localpos); } else { curobj->NodeSetLocalOrientation(mat); } }
bool KX_CameraActuator::Update(double curtime, bool frame) { /* wondering... is it really necessary/desirable to suppress negative */ /* events here? */ bool bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); if (bNegativeEvent || !m_ob) return false; KX_GameObject *obj = (KX_GameObject*) GetParent(); MT_Point3 from = obj->NodeGetWorldPosition(); MT_Matrix3x3 frommat = obj->NodeGetWorldOrientation(); /* These casts are _very_ dangerous!!! */ MT_Point3 lookat = ((KX_GameObject*)m_ob)->NodeGetWorldPosition(); MT_Matrix3x3 actormat = ((KX_GameObject*)m_ob)->NodeGetWorldOrientation(); float fp1[3]={0}, fp2[3]={0}, rc[3]; float inp, fac; //, factor = 0.0; /* some factor... */ float mindistsq, maxdistsq, distsq; float mat[3][3]; /* The rules: */ /* CONSTRAINT 1: not implemented */ /* CONSTRAINT 2: can camera see actor? */ /* CONSTRAINT 3: fixed height relative to floor below actor. */ /* CONSTRAINT 4: camera rotates behind actor */ /* CONSTRAINT 5: minimum / maximum distance */ /* CONSTRAINT 6: again: fixed height relative to floor below actor */ /* CONSTRAINT 7: track to floor below actor */ /* CONSTRAINT 8: look a little bit left or right, depending on how the * * character is looking (horizontal x) */ /* ...and then set the camera position. Since we assume the parent of */ /* this actuator is always a camera, just set the parent position and */ /* rotation. We do not check whether we really have a camera as parent. */ /* It may be better to turn this into a general tracking actuator later */ /* on, since lots of plausible relations can be filled in here. */ /* ... set up some parameters ... */ /* missing here: the 'floorloc' of the actor's shadow */ mindistsq= m_minHeight*m_minHeight; maxdistsq= m_maxHeight*m_maxHeight; /* C1: not checked... is a future option */ /* C2: blender test_visibility function. Can this be a ray-test? */ /* C3: fixed height */ from[2] = (15.0f * from[2] + lookat[2] + m_height) / 16.0f; /* C4: camera behind actor */ switch (m_axis) { case OB_POSX: /* X */ fp1[0] = actormat[0][0]; fp1[1] = actormat[1][0]; fp1[2] = actormat[2][0]; fp2[0] = frommat[0][0]; fp2[1] = frommat[1][0]; fp2[2] = frommat[2][0]; break; case OB_POSY: /* Y */ fp1[0] = actormat[0][1]; fp1[1] = actormat[1][1]; fp1[2] = actormat[2][1]; fp2[0] = frommat[0][1]; fp2[1] = frommat[1][1]; fp2[2] = frommat[2][1]; break; case OB_NEGX: /* -X */ fp1[0] = -actormat[0][0]; fp1[1] = -actormat[1][0]; fp1[2] = -actormat[2][0]; fp2[0] = frommat[0][0]; fp2[1] = frommat[1][0]; fp2[2] = frommat[2][0]; break; case OB_NEGY: /* -Y */ fp1[0] = -actormat[0][1]; fp1[1] = -actormat[1][1]; fp1[2] = -actormat[2][1]; fp2[0] = frommat[0][1]; fp2[1] = frommat[1][1]; fp2[2] = frommat[2][1]; break; default: assert(0); break; } inp = fp1[0]*fp2[0] + fp1[1]*fp2[1] + fp1[2]*fp2[2]; fac = (-1.0f + inp) * m_damping; from[0] += fac * fp1[0]; from[1] += fac * fp1[1]; from[2] += fac * fp1[2]; /* only for it lies: cross test and perpendicular bites up */ if (inp < 0.0f) { /* Don't do anything if the cross product is too small. * The camera up-axis becomes unstable and starts to oscillate. * The 0.01f threshold is arbitrary but seems to work well in practice. */ float cross = fp1[0] * fp2[1] - fp1[1] * fp2[0]; if (cross > 0.01f) { from[0] -= fac * fp1[1]; from[1] += fac * fp1[0]; } else if (cross < -0.01f) { from[0] += fac * fp1[1]; from[1] -= fac * fp1[0]; } } /* CONSTRAINT 5: minimum / maximum distance */ rc[0] = (lookat[0]-from[0]); rc[1] = (lookat[1]-from[1]); rc[2] = (lookat[2]-from[2]); distsq = rc[0]*rc[0] + rc[1]*rc[1] + rc[2]*rc[2]; if (distsq > maxdistsq) { distsq = 0.15f * (distsq - maxdistsq) / distsq; from[0] += distsq*rc[0]; from[1] += distsq*rc[1]; from[2] += distsq*rc[2]; } else if (distsq < mindistsq) { distsq = 0.15f * (mindistsq - distsq) / mindistsq; from[0] -= distsq*rc[0]; from[1] -= distsq*rc[1]; from[2] -= distsq*rc[2]; } /* CONSTRAINT 7: track to floor below actor */ rc[0] = (lookat[0]-from[0]); rc[1] = (lookat[1]-from[1]); rc[2] = (lookat[2]-from[2]); Kx_VecUpMat3(rc, mat, 3); /* y up Track -z */ /* now set the camera position and rotation */ obj->NodeSetLocalPosition(from); actormat[0][0] = mat[0][0]; actormat[0][1] = mat[1][0]; actormat[0][2] = mat[2][0]; actormat[1][0] = mat[0][1]; actormat[1][1] = mat[1][1]; actormat[1][2] = mat[2][1]; actormat[2][0] = mat[0][2]; actormat[2][1] = mat[1][2]; actormat[2][2] = mat[2][2]; obj->NodeSetLocalOrientation(actormat); return true; }
bool KX_TrackToActuator::Update(double curtime, bool frame) { bool result = false; bool bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); if (bNegativeEvent) { // do nothing on negative events } else if (m_object) { KX_GameObject* curobj = (KX_GameObject*) GetParent(); MT_Vector3 dir = ((KX_GameObject*)m_object)->NodeGetWorldPosition() - curobj->NodeGetWorldPosition(); if (dir.length2()) dir.normalize(); MT_Vector3 up(0,0,1); #ifdef DSADSA switch (m_upflag) { case 0: { up.setValue(1.0,0,0); break; } case 1: { up.setValue(0,1.0,0); break; } case 2: default: { up.setValue(0,0,1.0); } } #endif if (m_allow3D) { up = (up - up.dot(dir) * dir).safe_normalized(); } else { dir = (dir - up.dot(dir)*up).safe_normalized(); } MT_Vector3 left; MT_Matrix3x3 mat; switch (m_trackflag) { case 0: // TRACK X { // (1.0 , 0.0 , 0.0 ) x direction is forward, z (0.0 , 0.0 , 1.0 ) up left = dir.safe_normalized(); dir = (left.cross(up)).safe_normalized(); mat.setValue ( left[0], dir[0],up[0], left[1], dir[1],up[1], left[2], dir[2],up[2] ); break; }; case 1: // TRACK Y { // (0.0 , 1.0 , 0.0 ) y direction is forward, z (0.0 , 0.0 , 1.0 ) up left = (dir.cross(up)).safe_normalized(); mat.setValue ( left[0], dir[0],up[0], left[1], dir[1],up[1], left[2], dir[2],up[2] ); break; } case 2: // track Z { left = up.safe_normalized(); up = dir.safe_normalized(); dir = left; left = (dir.cross(up)).safe_normalized(); mat.setValue ( left[0], dir[0],up[0], left[1], dir[1],up[1], left[2], dir[2],up[2] ); break; } case 3: // TRACK -X { // (1.0 , 0.0 , 0.0 ) x direction is forward, z (0.0 , 0.0 , 1.0 ) up left = -dir.safe_normalized(); dir = -(left.cross(up)).safe_normalized(); mat.setValue ( left[0], dir[0],up[0], left[1], dir[1],up[1], left[2], dir[2],up[2] ); break; }; case 4: // TRACK -Y { // (0.0 , -1.0 , 0.0 ) -y direction is forward, z (0.0 , 0.0 , 1.0 ) up left = (-dir.cross(up)).safe_normalized(); mat.setValue ( left[0], -dir[0],up[0], left[1], -dir[1],up[1], left[2], -dir[2],up[2] ); break; } case 5: // track -Z { left = up.safe_normalized(); up = -dir.safe_normalized(); dir = left; left = (dir.cross(up)).safe_normalized(); mat.setValue ( left[0], dir[0],up[0], left[1], dir[1],up[1], left[2], dir[2],up[2] ); break; } default: { // (1.0 , 0.0 , 0.0 ) -x direction is forward, z (0.0 , 0.0 , 1.0 ) up left = -dir.safe_normalized(); dir = -(left.cross(up)).safe_normalized(); mat.setValue ( left[0], dir[0],up[0], left[1], dir[1],up[1], left[2], dir[2],up[2] ); } } MT_Matrix3x3 oldmat; oldmat= curobj->NodeGetWorldOrientation(); /* erwin should rewrite this! */ mat= matrix3x3_interpol(oldmat, mat, m_time); if(m_parentobj){ // check if the model is parented and calculate the child transform MT_Point3 localpos; localpos = curobj->GetSGNode()->GetLocalPosition(); // Get the inverse of the parent matrix MT_Matrix3x3 parentmatinv; parentmatinv = m_parentobj->NodeGetWorldOrientation ().inverse (); // transform the local coordinate system into the parents system mat = parentmatinv * mat; // append the initial parent local rotation matrix mat = m_parentlocalmat * mat; // set the models tranformation properties curobj->NodeSetLocalOrientation(mat); curobj->NodeSetLocalPosition(localpos); //curobj->UpdateTransform(); } else { curobj->NodeSetLocalOrientation(mat); } result = true; } return result; }
bool KX_CameraActuator::Update(double curtime, bool frame) { /* wondering... is it really neccesary/desirable to suppress negative */ /* events here? */ bool bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); if (bNegativeEvent || !m_ob) return false; KX_GameObject *obj = (KX_GameObject*) GetParent(); MT_Point3 from = obj->NodeGetWorldPosition(); MT_Matrix3x3 frommat = obj->NodeGetWorldOrientation(); /* These casts are _very_ dangerous!!! */ MT_Point3 lookat = ((KX_GameObject*)m_ob)->NodeGetWorldPosition(); MT_Matrix3x3 actormat = ((KX_GameObject*)m_ob)->NodeGetWorldOrientation(); float fp1[3], fp2[3], rc[3]; float inp, fac; //, factor = 0.0; /* some factor... */ float mindistsq, maxdistsq, distsq; float mat[3][3]; /* The rules: */ /* CONSTRAINT 1: not implemented */ /* CONSTRAINT 2: can camera see actor? */ /* CONSTRAINT 3: fixed height relative to floor below actor. */ /* CONSTRAINT 4: camera rotates behind actor */ /* CONSTRAINT 5: minimum / maximum distance */ /* CONSTRAINT 6: again: fixed height relative to floor below actor */ /* CONSTRAINT 7: track to floor below actor */ /* CONSTRAINT 8: look a little bit left or right, depending on how the character is looking (horizontal x) */ /* ...and then set the camera position. Since we assume the parent of */ /* this actuator is always a camera, just set the parent position and */ /* rotation. We do not check whether we really have a camera as parent. */ /* It may be better to turn this into a general tracking actuator later */ /* on, since lots of plausible relations can be filled in here. */ /* ... set up some parameters ... */ /* missing here: the 'floorloc' of the actor's shadow */ mindistsq= m_minHeight*m_minHeight; maxdistsq= m_maxHeight*m_maxHeight; /* C1: not checked... is a future option */ /* C2: blender test_visibility function. Can this be a ray-test? */ /* C3: fixed height */ from[2] = (15.0*from[2] + lookat[2] + m_height)/16.0; /* C4: camera behind actor */ if (m_x) { fp1[0] = actormat[0][0]; fp1[1] = actormat[1][0]; fp1[2] = actormat[2][0]; fp2[0] = frommat[0][0]; fp2[1] = frommat[1][0]; fp2[2] = frommat[2][0]; } else { fp1[0] = actormat[0][1]; fp1[1] = actormat[1][1]; fp1[2] = actormat[2][1]; fp2[0] = frommat[0][1]; fp2[1] = frommat[1][1]; fp2[2] = frommat[2][1]; } inp= fp1[0]*fp2[0] + fp1[1]*fp2[1] + fp1[2]*fp2[2]; fac= (-1.0 + inp) * m_damping; from[0]+= fac*fp1[0]; from[1]+= fac*fp1[1]; from[2]+= fac*fp1[2]; /* alleen alstie ervoor ligt: cross testen en loodrechte bijtellen */ if(inp<0.0) { if(fp1[0]*fp2[1] - fp1[1]*fp2[0] > 0.0) { from[0]-= fac*fp1[1]; from[1]+= fac*fp1[0]; } else { from[0]+= fac*fp1[1]; from[1]-= fac*fp1[0]; } } /* CONSTRAINT 5: minimum / maximum afstand */ rc[0]= (lookat[0]-from[0]); rc[1]= (lookat[1]-from[1]); rc[2]= (lookat[2]-from[2]); distsq= rc[0]*rc[0] + rc[1]*rc[1] + rc[2]*rc[2]; if(distsq > maxdistsq) { distsq = 0.15*(distsq-maxdistsq)/distsq; from[0] += distsq*rc[0]; from[1] += distsq*rc[1]; from[2] += distsq*rc[2]; } else if(distsq < mindistsq) { distsq = 0.15*(mindistsq-distsq)/mindistsq; from[0] -= distsq*rc[0]; from[1] -= distsq*rc[1]; from[2] -= distsq*rc[2]; } /* CONSTRAINT 7: track to schaduw */ rc[0]= (lookat[0]-from[0]); rc[1]= (lookat[1]-from[1]); rc[2]= (lookat[2]-from[2]); Kx_VecUpMat3(rc, mat, 3); /* y up Track -z */ /* now set the camera position and rotation */ obj->NodeSetLocalPosition(from); actormat[0][0]= mat[0][0]; actormat[0][1]= mat[1][0]; actormat[0][2]= mat[2][0]; actormat[1][0]= mat[0][1]; actormat[1][1]= mat[1][1]; actormat[1][2]= mat[2][1]; actormat[2][0]= mat[0][2]; actormat[2][1]= mat[1][2]; actormat[2][2]= mat[2][2]; obj->NodeSetLocalOrientation(actormat); return true; }