bool KX_RayCast::RayTest(PHY_IPhysicsEnvironment* physics_environment, const MT_Point3& _frompoint, const MT_Point3& topoint, KX_RayCast& callback) { if(physics_environment==NULL) return false; /* prevents crashing in some cases */ // Loops over all physics objects between frompoint and topoint, // calling callback.RayHit for each one. // // callback.RayHit should return true to stop looking, or false to continue. // // returns true if an object was found, false if not. MT_Point3 frompoint(_frompoint); const MT_Vector3 todir( (topoint - frompoint).safe_normalized() ); MT_Point3 prevpoint(_frompoint+todir*(-1.f)); PHY_IPhysicsController* hit_controller; while((hit_controller = physics_environment->rayTest(callback, frompoint.x(),frompoint.y(),frompoint.z(), topoint.x(),topoint.y(),topoint.z())) != NULL) { KX_ClientObjectInfo* info = static_cast<KX_ClientObjectInfo*>(hit_controller->getNewClientInfo()); if (!info) { printf("no info!\n"); MT_assert(info && "Physics controller with no client object info"); break; } // The biggest danger to endless loop, prevent this by checking that the // hit point always progresses along the ray direction.. prevpoint -= callback.m_hitPoint; if (prevpoint.length2() < MT_EPSILON) break; if (callback.RayHit(info)) // caller may decide to stop the loop and still cancel the hit return callback.m_hitFound; // Skip past the object and keep tracing. // Note that retrieving in a single shot multiple hit points would be possible // but it would require some change in Bullet. prevpoint = callback.m_hitPoint; /* We add 0.001 of fudge, so that if the margin && radius == 0., we don't endless loop. */ MT_Scalar marg = 0.001 + hit_controller->GetMargin(); marg *= 2.f; /* Calculate the other side of this object */ MT_Scalar h = MT_abs(todir.dot(callback.m_hitNormal)); if (h <= 0.01) // the normal is almost orthogonal to the ray direction, cannot compute the other side break; marg /= h; frompoint = callback.m_hitPoint + marg * todir; // verify that we are not passed the to point if ((topoint - frompoint).dot(todir) < 0.f) break; } return false; }
void RAS_OpenGLRasterizer::applyTransform(double* oglmatrix,int objectdrawmode ) { /* FIXME: blender: intern/moto/include/MT_Vector3.inl:42: MT_Vector3 operator/(const MT_Vector3&, double): Assertion `!MT_fuzzyZero(s)' failed. Program received signal SIGABRT, Aborted. [Switching to Thread 16384 (LWP 1519)] 0x40477571 in kill () from /lib/libc.so.6 (gdb) bt #7 0x08334368 in MT_Vector3::normalized() const () #8 0x0833e6ec in RAS_OpenGLRasterizer::applyTransform(RAS_IRasterizer*, double*, int) () */ if (objectdrawmode & RAS_IPolyMaterial::BILLBOARD_SCREENALIGNED || objectdrawmode & RAS_IPolyMaterial::BILLBOARD_AXISALIGNED) { // rotate the billboard/halo //page 360/361 3D Game Engine Design, David Eberly for a discussion // on screen aligned and axis aligned billboards // assumed is that the preprocessor transformed all billboard polygons // so that their normal points into the positive x direction (1.0, 0.0, 0.0) // when new parenting for objects is done, this rotation // will be moved into the object MT_Point3 objpos (oglmatrix[12],oglmatrix[13],oglmatrix[14]); MT_Point3 campos = GetCameraPosition(); MT_Vector3 dir = (campos - objpos).safe_normalized(); MT_Vector3 up(0,0,1.0); KX_GameObject* gameobj = (KX_GameObject*)m_clientobject; // get scaling of halo object MT_Vector3 size = gameobj->GetSGNode()->GetWorldScaling(); bool screenaligned = (objectdrawmode & RAS_IPolyMaterial::BILLBOARD_SCREENALIGNED)!=0;//false; //either screen or axisaligned if (screenaligned) { up = (up - up.dot(dir) * dir).safe_normalized(); } else { dir = (dir - up.dot(dir)*up).safe_normalized(); } MT_Vector3 left = dir.normalized(); dir = (up.cross(left)).normalized(); // we have calculated the row vectors, now we keep // local scaling into account: left *= size[0]; dir *= size[1]; up *= size[2]; double maat[16] = {left[0], left[1], left[2], 0, dir[0], dir[1], dir[2], 0, up[0], up[1], up[2], 0, 0, 0, 0, 1}; glTranslated(objpos[0],objpos[1],objpos[2]); glMultMatrixd(maat); } else { if (objectdrawmode & RAS_IPolyMaterial::SHADOW) { // shadow must be cast to the ground, physics system needed here! MT_Point3 frompoint(oglmatrix[12],oglmatrix[13],oglmatrix[14]); KX_GameObject *gameobj = (KX_GameObject*)m_clientobject; MT_Vector3 direction = MT_Vector3(0,0,-1); direction.normalize(); direction *= 100000; MT_Point3 topoint = frompoint + direction; KX_Scene* kxscene = (KX_Scene*) m_auxilaryClientInfo; PHY_IPhysicsEnvironment* physics_environment = kxscene->GetPhysicsEnvironment(); PHY_IPhysicsController* physics_controller = gameobj->GetPhysicsController(); KX_GameObject *parent = gameobj->GetParent(); if (!physics_controller && parent) physics_controller = parent->GetPhysicsController(); if (parent) parent->Release(); KX_RayCast::Callback<RAS_OpenGLRasterizer> callback(this, physics_controller, oglmatrix); if (!KX_RayCast::RayTest(physics_environment, frompoint, topoint, callback)) { // couldn't find something to cast the shadow on... glMultMatrixd(oglmatrix); } else { // we found the "ground", but the cast matrix doesn't take // scaling in consideration, so we must apply the object scale MT_Vector3 size = gameobj->GetSGNode()->GetLocalScale(); glScalef(size[0], size[1], size[2]); } } else { // 'normal' object glMultMatrixd(oglmatrix); } } }