src/PhysicalObject.cpp

Go to the documentation of this file.
00001 
00002 #ifndef DOLOG
00003 //#define DOLOG
00004 #undef  DOLOG
00005 #endif
00006 
00007 
00008 #include <fstream>
00009 #include <stdexcept>
00010 
00011 #include "PhysicalObject.h"
00012 
00013 
00018 PhysicalObject::PhysicalObject(bool enablePhysics)
00019     : mTransform(),
00020         mInverseTransform(),
00021         mPhysicsOn(enablePhysics),
00022         mMass(INFINITY),
00023         mPosition(),
00024         mScaling(1.0f),
00025         mRotation(),
00026         mVelocity(),
00027         mAngularVelocity(),
00028         mTime(0.0f)
00029 {
00030 }
00031 
00032 
00035 PhysicalObject::~PhysicalObject()
00036 {
00037 }
00038 
00039 
00042 void PhysicalObject::updateProperties(float t)
00043 {/*{{{*/
00044     LLOG(mTime);
00045 //    dump();    // FIXME DEBUG
00046     assert(t >= -0.0f && t >= mTime - EPSILON);
00047     
00048     float dt = t - mTime;   // delta time
00049     Vec3f dv(0, 0, 0);      // delta velocity
00050     Vec3f dw(0, 0, 0);      // delta angular velocity
00051     LLOG("Updating properties to time : " << t << "  dt = " << dt);
00052     if (dt < EPSILON)
00053     {
00054         LLOG("no need for update");
00055         return;
00056     }
00057 //    dump();    // FIXME DEBUG
00058 
00059     // determine if the ball is sliding or rolling
00060     const Vec3f vw = mAngularVelocity.cross(WORLD_UP * -BALL_RADIUS);
00061     const Vec3f v_perimeter = vw + mVelocity;
00062     bool adjustAngularVelocity = false;
00063     LLOG("v_p   = " << v_perimeter << "  |v_p|   = " << v_perimeter.length());
00064     LLOG("w x r = " << vw << "  |w x r| = " << vw.length());
00065     if (mVelocity.length() < PHYS_EPS)
00066     {
00067         if (mVelocity.length() > EPSILON)
00068         {
00069             LLOG("\n\n\n");
00070 //            dump();    // FIXME DEBUG
00071             LLOG("\nSTOPPING\n\n\n");
00072         }
00073         // ball should stop
00074         mAngularVelocity    = Vec3f(0, 0, 0);
00075         mVelocity           = Vec3f(0, 0, 0);
00076         mTime               = t;
00077 
00078         // update transormation matrices
00079         resetTransform();
00080         scale(mScaling, mScaling, mScaling);
00081         rotate(mRotation.length(), mRotation);
00082         translate(mPosition);
00083         return;
00084     }
00085     else if (v_perimeter.length() < PHYS_EPS)
00086     {
00087         LLOG("ROLLS");
00088         // ball rolls
00089         if (mVelocity.length() > EPSILON)
00090             dv = mVelocity.normal() * -MUE_ROLLING * GRAVITY * dt;
00091         adjustAngularVelocity = true;
00092     }
00093     else
00094     {
00095         LLOG("SLIDES");
00096         // ball slides
00097         Vec3f f_friction(0, 0, 0);
00098         if (v_perimeter.length() > EPSILON)
00099         {
00100             // delta linear speed
00101 //            LOG("old dv = " << v_perimeter.normal() * -MUE_SLIDING * GRAVITY * dt);
00102 //            dv          = v_perimeter.normal() * -MUE_SLIDING * GRAVITY * dt;
00103             // friction force
00104             f_friction  = v_perimeter.normal() * -MUE_SLIDING * GRAVITY * mMass;
00105         }
00106         LLOG("F  = " << f_friction << "  |F|  = " << f_friction.length());
00107         // delta angular speed
00108         dw = (WORLD_UP * -BALL_RADIUS).cross(f_friction) * 2.5f * dt / (mMass * BALL_RADIUS * BALL_RADIUS);
00109         if ((WORLD_UP * -BALL_RADIUS).cross(f_friction).length() < PHYS_EPS)
00110         {
00111             LLOG("ROTATES");
00112             // ball rotates along vertical axis
00113             f_friction = mAngularVelocity.cross(WORLD_UP_MASK.normal()) * -MUE_SLIDING * GRAVITY * mMass;
00114             dw = (WORLD_UP_MASK.normal() * CONTACT_RADIUS).cross(f_friction) * 2.5f * dt / (mMass * BALL_RADIUS * BALL_RADIUS);
00115         }
00116         // energy * 2 / m
00117         float Ekin      = mVelocity.dot(mVelocity) + 0.4f * BALL_RADIUS * BALL_RADIUS * mAngularVelocity.dot(mAngularVelocity);
00118         float dErot     = 0.4f * BALL_RADIUS * BALL_RADIUS * (mAngularVelocity + dw).dot(mAngularVelocity + dw);
00119         float dEfrict   = MUE_SLIDING * GRAVITY * v_perimeter.length() * dt;
00120         LLOG("Ekin       = " << Ekin);
00121         LLOG("dErot      = " << dErot);
00122         LLOG("dEfrict    = " << dEfrict);
00123         if (v_perimeter.length() > EPSILON)
00124         {
00125             float dE = Ekin - dErot - dEfrict;
00126             if (dE < 0.0f)
00127                 dv = - v_perimeter.normal() * (mVelocity.length() + sqrt(- dE));
00128             else
00129                 dv = - v_perimeter.normal() * (mVelocity.length() - sqrt(dE));
00130         }
00131     }
00132     LLOG("dv = " << dv << "  |dv| = " << dv.length());
00133     LLOG("dw = " << dw << "  |dw| = " << dw.length());
00134 
00135     // delta rotation
00136     Vec3f dr;
00137     // delta position
00138     Vec3f ds = dv * 0.5f * dt + mVelocity * dt;
00139     LLOG("ds = " << ds << "  |ds| = " << ds.length());
00140 
00141     // update transformations now if sliding
00142     if (!adjustAngularVelocity)
00143     {
00144         mRotation += dw * 0.5f * dt + mAngularVelocity * dt;
00145         LLOG("dr = " << (dw * 0.5f * dt + mAngularVelocity * dt)
00146                 << "  |dr| = " << (dw * 0.5f * dt + mAngularVelocity * dt).length());
00147 
00148         // update transormation matrices
00149         resetTransform();
00150         scale(mScaling, mScaling, mScaling);
00151         rotate(mRotation.length(), mRotation);
00152         translate(mPosition + WORLD_UP_MASK.scaled(ds));
00153     }
00154 
00155     // update properties
00156     mVelocity           = WORLD_UP_MASK.scaled(mVelocity + dv);
00157     Vec3f oldAV         = mAngularVelocity;
00158     mAngularVelocity    += dw;
00159     mTime               = t;
00160 
00161     // test if we should ensure correct rolling
00162     const Vec3f v_perimeter2 = mAngularVelocity.cross(WORLD_UP * -BALL_RADIUS) + mVelocity;
00163     if (adjustAngularVelocity || v_perimeter.dot(v_perimeter - v_perimeter2) * v_perimeter2.dot(v_perimeter - v_perimeter2) < 0.0f)
00164     {
00165         LLOG("adjusting w : " << mAngularVelocity << "(" << mAngularVelocity.length() << ") -> "
00166                 << (WORLD_UP * BALL_RADIUS).cross(mVelocity) / (BALL_RADIUS * BALL_RADIUS)
00167                 << "(" << (WORLD_UP * BALL_RADIUS).cross(mVelocity).length() / (BALL_RADIUS * BALL_RADIUS) << ")");
00168 
00169         // recalculate angular velocity aligned to velocity
00170         mAngularVelocity = (WORLD_UP * BALL_RADIUS).cross(mVelocity) / (BALL_RADIUS * BALL_RADIUS);
00171         dw = mAngularVelocity - oldAV;
00172     }
00173 
00174     // update transformations again if rolling
00175     if (adjustAngularVelocity)
00176     {
00177         mRotation += dw * 0.5f * dt + oldAV * dt;
00178         // update transormation matrices
00179         resetTransform();
00180         scale(mScaling, mScaling, mScaling);
00181         rotate(mRotation.length(), mRotation);
00182         translate(mPosition + WORLD_UP_MASK.scaled(ds));
00183     }
00184 
00185     LLOG("result:");
00186 //#ifdef DOLOG
00187 //    dump();    // FIXME DEBUG
00188 //#endif
00189     LLOG("\n");
00190 }/*}}}*/
00191 
00192 
00197 void PhysicalObject::writeDump(std::ostream & outs)
00198 {
00199     if (!mPhysicsOn)
00200     {
00201         throw std::logic_error("Physics must be on to write to file");
00202     }
00203 
00204     int magic = 0x316a626f;
00205     outs.write(reinterpret_cast<const char *>(&magic), sizeof(int));
00206 
00207     outs.write(reinterpret_cast<const char *>(&mTransform), sizeof(Matrix));
00208     outs.write(reinterpret_cast<const char *>(&mInverseTransform), sizeof(Matrix));
00209     outs.write(reinterpret_cast<const char *>(&mMass), sizeof(float));
00210     outs.write(reinterpret_cast<const char *>(&mPosition), sizeof(Vec3f));
00211     outs.write(reinterpret_cast<const char *>(&mScaling), sizeof(float));
00212     outs.write(reinterpret_cast<const char *>(&mRotation), sizeof(Vec3f));
00213     outs.write(reinterpret_cast<const char *>(&mVelocity), sizeof(Vec3f));
00214     outs.write(reinterpret_cast<const char *>(&mAngularVelocity), sizeof(Vec3f));
00215     outs.write(reinterpret_cast<const char *>(&mTime), sizeof(float));
00216 }
00217 
00218 
00223 void PhysicalObject::readDump(std::istream & ins)
00224 {
00225     if (!mPhysicsOn)
00226     {
00227         throw std::logic_error("Physics must be on to read from file");
00228     }
00229 
00230     int magic;
00231     ins.read(reinterpret_cast<char *>(&magic), sizeof(int));
00232     if (magic != 0x316a626f)
00233     {
00234         throw std::logic_error("Could not find object data");
00235     }
00236     ins.clear();
00237 
00238     ins.read(reinterpret_cast<char *>(&mTransform), sizeof(Matrix));
00239     ins.clear();
00240     ins.read(reinterpret_cast<char *>(&mInverseTransform), sizeof(Matrix));
00241     ins.clear();
00242     ins.read(reinterpret_cast<char *>(&mMass), sizeof(float));
00243     ins.clear();
00244     ins.read(reinterpret_cast<char *>(&mPosition), sizeof(Vec3f));
00245     ins.clear();
00246     ins.read(reinterpret_cast<char *>(&mScaling), sizeof(float));
00247     ins.clear();
00248     ins.read(reinterpret_cast<char *>(&mRotation), sizeof(Vec3f));
00249     ins.clear();
00250     ins.read(reinterpret_cast<char *>(&mVelocity), sizeof(Vec3f));
00251     ins.clear();
00252     ins.read(reinterpret_cast<char *>(&mAngularVelocity), sizeof(Vec3f));
00253     ins.clear();
00254     ins.read(reinterpret_cast<char *>(&mTime), sizeof(float));
00255     ins.clear();
00256 }
00257 
00258 

Generated on Fri Feb 1 00:01:42 2008 for Grayfall by  doxygen 1.5.1