// routine to prepare the displayable object; must set the origin properly void Stage::prepare() { float rot_amount = 0.0, strans[3]; char rot_axes = 'z'; strans[0] = strans[1] = strans[2] = 0.0; // move the stage to its proper position if (need_update && stagePos != NO_STAGE) { if (stagePos == STAGE_ORIGIN) { ; } else if(stagePos == STAGE_LOWER) { strans[1] = -1.0; } else if(stagePos == STAGE_UPPER) { strans[1] = 1.0; } else if(stagePos == STAGE_LEFT) { strans[0] = -1.0; rot_amount = -90.0; } else if(stagePos == STAGE_RIGHT) { strans[0] = 1.0; rot_amount = 90.0; } else if(stagePos == STAGE_BEHIND) { strans[2] = -1.0; rot_axes = 'x'; rot_amount = 90.0; } else { msgErr << "Stage: Illegal stage location " << stagePos << " specified." << sendmsg; stagePos = STAGE_ORIGIN; return; } // update the current transformation need_update = FALSE; // (re)create the command list create_cmdlist(); // reset tranformation glob_trans_on(); rot_on(); reset_transformation(); set_glob_trans(strans[0], strans[1], strans[2]); add_rot(rot_amount, rot_axes); rot_off(); glob_trans_off(); } }
// ---------------------------------------------------------------------------- void btKart::updateVehicle( btScalar step ) { updateAllWheelPositions(); const btTransform& chassisTrans = getChassisWorldTransform(); btVector3 forwardW(chassisTrans.getBasis()[0][m_indexForwardAxis], chassisTrans.getBasis()[1][m_indexForwardAxis], chassisTrans.getBasis()[2][m_indexForwardAxis]); // Simulate suspension // ------------------- m_num_wheels_on_ground = 0; m_visual_wheels_touch_ground = true; for (int i=0;i<m_wheelInfo.size();i++) { rayCast( i); if(m_wheelInfo[i].m_raycastInfo.m_isInContact) m_num_wheels_on_ground++; } // Test if the kart is falling so fast // that the chassis might hit the track // ------------------------------------ bool needs_cushioning_test = false; for(int i=0; i<m_wheelInfo.size(); i++) { btWheelInfo &wheel = m_wheelInfo[i]; if(!wheel.m_was_on_ground && wheel.m_raycastInfo.m_isInContact) { needs_cushioning_test = true; break; } } if(needs_cushioning_test) { const btVector3 &v = m_chassisBody->getLinearVelocity(); btVector3 down(0, 1, 0); btVector3 v_down = (v * down) * down; // Estimate what kind of downward speed can be compensated by the // suspension. Atm the parameters are set that the suspension is // actually capped at max suspension force, so the maximum // speed that can be caught by the suspension without the chassis // hitting the ground can be based on that. Note that there are // 4 suspensions, all adding together. btScalar max_compensate_speed = m_wheelInfo[0].m_maxSuspensionForce * m_chassisBody->getInvMass() * step * 4; // If the downward speed is too fast to be caught by the suspension, // slow down the falling speed by applying an appropriately impulse: if(-v_down.getY() > max_compensate_speed) { btVector3 impulse = down * (-v_down.getY() - max_compensate_speed) / m_chassisBody->getInvMass()*0.5f; //float v_old = m_chassisBody->getLinearVelocity().getY(); //float x = m_wheelInfo[0].m_raycastInfo.m_isInContact ? m_wheelInfo[0].m_raycastInfo.m_contactPointWS.getY() : -100; m_chassisBody->applyCentralImpulse(impulse); //Log::verbose("physics", "Cushioning %f from %f m/s to %f m/s wheel %f kart %f", impulse.getY(), // v_old, m_chassisBody->getLinearVelocity().getY(), x, // m_chassisBody->getWorldTransform().getOrigin().getY() // ); } } for(int i=0; i<m_wheelInfo.size(); i++) m_wheelInfo[i].m_was_on_ground = m_wheelInfo[i].m_raycastInfo.m_isInContact; // If the kart is flying, try to keep it parallel to the ground. // ------------------------------------------------------------- if(m_num_wheels_on_ground==0) { btVector3 kart_up = getChassisWorldTransform().getBasis().getColumn(1); btVector3 terrain_up = m_kart->getMaterial() && m_kart->getMaterial()->hasGravity() ? m_kart->getNormal() : Vec3(0, 1, 0); // Length of axis depends on the angle - i.e. the further awat // the kart is from being upright, the larger the applied impulse // will be, resulting in fast changes when the kart is on its // side, but not overcompensating (and therefore shaking) when // the kart is not much away from being upright. btVector3 axis = kart_up.cross(terrain_up); // To avoid the kart going backwards/forwards (or rolling sideways), // set the pitch/roll to 0 before applying the 'straightening' impulse. // TODO: make this works if gravity is changed. btVector3 av = m_chassisBody->getAngularVelocity(); av.setX(0); av.setZ(0); m_chassisBody->setAngularVelocity(av); // Give a nicely balanced feeling for rebalancing the kart m_chassisBody->applyTorqueImpulse(axis * m_kart->getKartProperties()->getStabilitySmoothFlyingImpulse()); } // Work around: make sure that either both wheels on one axis // are on ground, or none of them. This avoids the problem of // the kart suddenly getting additional angular velocity because // e.g. only one rear wheel is on the ground and then the kart // rotates very abruptly. for(int i=0; i<m_wheelInfo.size(); i+=2) { if( m_wheelInfo[i ].m_raycastInfo.m_isInContact != m_wheelInfo[i+1].m_raycastInfo.m_isInContact) { int wheel_air_index = i; int wheel_ground_index = i+1; if (m_wheelInfo[i].m_raycastInfo.m_isInContact) { wheel_air_index = i+1; wheel_ground_index = i; } btWheelInfo& wheel_air = m_wheelInfo[wheel_air_index]; btWheelInfo& wheel_ground = m_wheelInfo[wheel_ground_index]; wheel_air.m_raycastInfo = wheel_ground.m_raycastInfo; } } // for i=0; i<m_wheelInfo.size(); i+=2 // Apply suspension forcen (i.e. upwards force) // -------------------------------------------- updateSuspension(step); for (int i=0;i<m_wheelInfo.size();i++) { //apply suspension force btWheelInfo& wheel = m_wheelInfo[i]; btScalar suspensionForce = wheel.m_wheelsSuspensionForce; if (suspensionForce > wheel.m_maxSuspensionForce) { suspensionForce = wheel.m_maxSuspensionForce; } btVector3 impulse = wheel.m_raycastInfo.m_contactNormalWS * suspensionForce * step; btVector3 relpos = wheel.m_raycastInfo.m_contactPointWS - getRigidBody()->getCenterOfMassPosition(); getRigidBody()->applyImpulse(impulse, relpos); } // Update friction (i.e. forward force) // ------------------------------------ updateFriction( step); for (int i=0;i<m_wheelInfo.size();i++) { btWheelInfo& wheel = m_wheelInfo[i]; //btVector3 relpos = wheel.m_raycastInfo.m_hardPointWS // - getRigidBody()->getCenterOfMassPosition(); //btVector3 vel = getRigidBody()->getVelocityInLocalPoint(relpos); if (wheel.m_raycastInfo.m_isInContact) { const btTransform& chassisWorldTransform = getChassisWorldTransform(); btVector3 fwd ( chassisWorldTransform.getBasis()[0][m_indexForwardAxis], chassisWorldTransform.getBasis()[1][m_indexForwardAxis], chassisWorldTransform.getBasis()[2][m_indexForwardAxis]); btScalar proj = fwd.dot(wheel.m_raycastInfo.m_contactNormalWS); fwd -= wheel.m_raycastInfo.m_contactNormalWS * proj; } } // If configured, add a force to keep karts on the track // ----------------------------------------------------- float dif = m_kart->getKartProperties()->getStabilityDownwardImpulseFactor(); if(dif!=0 && m_num_wheels_on_ground==4) { float f = -fabsf(m_kart->getSpeed()) * dif; btVector3 downwards_impulse = m_chassisBody->getWorldTransform().getBasis() * btVector3(0, f, 0); m_chassisBody->applyCentralImpulse(downwards_impulse); } // Apply additional impulse set by supertuxkart // -------------------------------------------- if(m_time_additional_impulse>0) { float dt = step > m_time_additional_impulse ? m_time_additional_impulse : step; m_chassisBody->applyCentralImpulse(m_additional_impulse*dt); m_time_additional_impulse -= dt; } // Apply additional rotation set by supertuxkart // --------------------------------------------- if(m_time_additional_rotation>0) { btTransform &t = m_chassisBody->getWorldTransform(); float dt = step > m_time_additional_rotation ? m_time_additional_rotation : step; btQuaternion add_rot(m_additional_rotation.getY()*dt, m_additional_rotation.getX()*dt, m_additional_rotation.getZ()*dt); t.setRotation(t.getRotation()*add_rot); m_chassisBody->setWorldTransform(t); // Also apply the rotation to the interpolated world transform. // This is important (at least if the rotation is only applied // in one frame) since STK will actually use the interpolated // transform, which would otherwise only be updated one frame // later, resulting in a one-frame incorrect rotation of the // kart, or a strongly 'visual jolt' of the kart btTransform &iwt=m_chassisBody->getInterpolationWorldTransform(); iwt.setRotation(iwt.getRotation()*add_rot); m_time_additional_rotation -= dt; } } // updateVehicle
// ---------------------------------------------------------------------------- void btKart::updateVehicle( btScalar step ) { for (int i=0;i<getNumWheels();i++) { updateWheelTransform(i,false); } const btTransform& chassisTrans = getChassisWorldTransform(); btVector3 forwardW(chassisTrans.getBasis()[0][m_indexForwardAxis], chassisTrans.getBasis()[1][m_indexForwardAxis], chassisTrans.getBasis()[2][m_indexForwardAxis]); // Simulate suspension // ------------------- m_num_wheels_on_ground = 0; m_visual_wheels_touch_ground = true; for (int i=0;i<m_wheelInfo.size();i++) { btScalar depth; depth = rayCast( i); if(m_wheelInfo[i].m_raycastInfo.m_isInContact) m_num_wheels_on_ground++; } // If the kart is flying, try to keep it parallel to the ground. if(m_num_wheels_on_ground==0) { btVector3 kart_up = getChassisWorldTransform().getBasis().getColumn(1); btVector3 terrain_up(0,1,0); btVector3 axis = kart_up.cross(terrain_up); // Give a nicely balanced feeling for rebalancing the kart m_chassisBody->applyTorqueImpulse(axis * m_kart->getKartProperties()->getSmoothFlyingImpulse()); } // Work around: make sure that either both wheels on one axis // are on ground, or none of them. This avoids the problem of // the kart suddenly getting additional angular velocity because // e.g. only one rear wheel is on the ground. for(int i=0; i<m_wheelInfo.size(); i+=2) { if( m_wheelInfo[i ].m_raycastInfo.m_isInContact != m_wheelInfo[i+1].m_raycastInfo.m_isInContact) { int wheel_air_index = i; int wheel_ground_index = i+1; if (m_wheelInfo[i].m_raycastInfo.m_isInContact) { wheel_air_index = i+1; wheel_ground_index = i; } btWheelInfo& wheel_air = m_wheelInfo[wheel_air_index]; btWheelInfo& wheel_ground = m_wheelInfo[wheel_ground_index]; wheel_air.m_raycastInfo = wheel_ground.m_raycastInfo; } } // for i=0; i<m_wheelInfo.size(); i+=2 updateSuspension(step); for (int i=0;i<m_wheelInfo.size();i++) { //apply suspension force btWheelInfo& wheel = m_wheelInfo[i]; btScalar suspensionForce = wheel.m_wheelsSuspensionForce; if (suspensionForce > wheel.m_maxSuspensionForce) { suspensionForce = wheel.m_maxSuspensionForce; } btVector3 impulse = wheel.m_raycastInfo.m_contactNormalWS * suspensionForce * step; btVector3 relpos = wheel.m_raycastInfo.m_contactPointWS - getRigidBody()->getCenterOfMassPosition(); getRigidBody()->applyImpulse(impulse, relpos); } updateFriction( step); for (int i=0;i<m_wheelInfo.size();i++) { btWheelInfo& wheel = m_wheelInfo[i]; btVector3 relpos = wheel.m_raycastInfo.m_hardPointWS - getRigidBody()->getCenterOfMassPosition(); btVector3 vel = getRigidBody()->getVelocityInLocalPoint(relpos); if (wheel.m_raycastInfo.m_isInContact) { const btTransform& chassisWorldTransform = getChassisWorldTransform(); btVector3 fwd ( chassisWorldTransform.getBasis()[0][m_indexForwardAxis], chassisWorldTransform.getBasis()[1][m_indexForwardAxis], chassisWorldTransform.getBasis()[2][m_indexForwardAxis]); btScalar proj = fwd.dot(wheel.m_raycastInfo.m_contactNormalWS); fwd -= wheel.m_raycastInfo.m_contactNormalWS * proj; btScalar proj2 = fwd.dot(vel); wheel.m_deltaRotation = (proj2 * step) / (wheel.m_wheelsRadius); wheel.m_rotation += wheel.m_deltaRotation; } else { wheel.m_rotation += wheel.m_deltaRotation; } //damping of rotation when not in contact wheel.m_deltaRotation *= btScalar(0.99); } float f = -m_kart->getSpeed() * m_kart->getKartProperties()->getDownwardImpulseFactor(); btVector3 downwards_impulse = m_chassisBody->getWorldTransform().getBasis() * btVector3(0, f, 0); m_chassisBody->applyCentralImpulse(downwards_impulse); if(m_time_additional_impulse>0) { float dt = step > m_time_additional_impulse ? m_time_additional_impulse : step; m_chassisBody->applyCentralImpulse(m_additional_impulse*dt); m_time_additional_impulse -= dt; } if(m_time_additional_rotation>0) { btTransform &t = m_chassisBody->getWorldTransform(); float dt = step > m_time_additional_rotation ? m_time_additional_rotation : step; btQuaternion add_rot(m_additional_rotation.getY()*dt, m_additional_rotation.getX()*dt, m_additional_rotation.getZ()*dt); t.setRotation(t.getRotation()*add_rot); m_chassisBody->setWorldTransform(t); // Also apply the rotation to the interpolated world transform. // This is important (at least if the rotation is only applied // in one frame) since STK will actually use the interpolated // transform, which would otherwise only be updated one frame // later, resulting in a one-frame incorrect rotation of the // kart, or a strongly 'visual jolt' of the kart btTransform &iwt=m_chassisBody->getInterpolationWorldTransform(); iwt.setRotation(iwt.getRotation()*add_rot); m_time_additional_rotation -= dt; } } // updateVehicle