void GridModel::draw(const core::visual::VisualParams* vparams) { if (!isActive() || !((getNext()==NULL)?vparams->displayFlags().getShowCollisionModels():vparams->displayFlags().getShowBoundingCollisionModels())) return; glDisable(GL_LIGHTING); int level=0; CollisionModel* m = getPrevious(); float color = 1.0f; while (m!=NULL) { m = m->getPrevious(); ++level; color *= 0.5f; } if (isSimulated()) glColor4f(1.0f, 1.0f, 1.0f, color); else glColor4f(1.0f, 1.0f, 0.0f, color); if (color < 1.0f) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(0); } for (int i=0;i<size;i++) { draw(vparams,i); } if (color < 1.0f) { glDisable(GL_BLEND); glDepthMask(1); } if (getPrevious()!=NULL) getPrevious()->draw(vparams); }
void CubeModel::draw(const core::visual::VisualParams* vparams) { if (!isActive() || !((getNext()==NULL)?vparams->displayFlags().getShowCollisionModels():vparams->displayFlags().getShowBoundingCollisionModels())) return; int level=0; CollisionModel* m = getPrevious(); float color = 1.0f; while (m!=NULL) { m = m->getPrevious(); ++level; color *= 0.5f; } Vec<4,float> c; if (isSimulated()) c=Vec<4,float>(1.0f, 1.0f, 1.0f, color); else c=Vec<4,float>(1.0f, 1.0f, 1.0f, color); std::vector< Vector3 > points; for (int i=0; i<size; i++) { const Vector3& vmin = elems[i].minBBox; const Vector3& vmax = elems[i].maxBBox; points.push_back(Vector3(vmin[0], vmin[1], vmin[2])); points.push_back(Vector3(vmin[0], vmin[1], vmax[2])); points.push_back(Vector3(vmin[0], vmax[1], vmin[2])); points.push_back(Vector3(vmin[0], vmax[1], vmax[2])); points.push_back(Vector3(vmax[0], vmin[1], vmin[2])); points.push_back(Vector3(vmax[0], vmin[1], vmax[2])); points.push_back(Vector3(vmax[0], vmax[1], vmin[2])); points.push_back(Vector3(vmax[0], vmax[1], vmax[2])); points.push_back(Vector3(vmin[0], vmin[1], vmin[2])); points.push_back(Vector3(vmin[0], vmax[1], vmin[2])); points.push_back(Vector3(vmin[0], vmin[1], vmax[2])); points.push_back(Vector3(vmin[0], vmax[1], vmax[2])); points.push_back(Vector3(vmax[0], vmin[1], vmin[2])); points.push_back(Vector3(vmax[0], vmax[1], vmin[2])); points.push_back(Vector3(vmax[0], vmin[1], vmax[2])); points.push_back(Vector3(vmax[0], vmax[1], vmax[2])); points.push_back(Vector3(vmin[0], vmin[1], vmin[2])); points.push_back(Vector3(vmax[0], vmin[1], vmin[2])); points.push_back(Vector3(vmin[0], vmax[1], vmin[2])); points.push_back(Vector3(vmax[0], vmax[1], vmin[2])); points.push_back(Vector3(vmin[0], vmin[1], vmax[2])); points.push_back(Vector3(vmax[0], vmin[1], vmax[2])); points.push_back(Vector3(vmin[0], vmax[1], vmax[2])); points.push_back(Vector3(vmax[0], vmax[1], vmax[2])); } vparams->drawTool()->drawLines(points, 1, Vec<4,float>(c)); if (getPrevious()!=NULL) getPrevious()->draw(vparams); }
Vector3f SlideMove( const Vector3f & footPos, const float eyeHeight, const Vector3f & moveDirection, const float moveDistance, const CollisionModel & collisionModel, const CollisionModel & groundCollisionModel ) { // Check for collisions at eye level to prevent slipping under walls. Vector3f eyePos = footPos + UpVector * eyeHeight; // Pop out of any collision models. collisionModel.PopOut( eyePos ); { Planef fowardCollisionPlane; float forwardDistance = moveDistance; if ( !collisionModel.TestRay( eyePos, moveDirection, forwardDistance, &fowardCollisionPlane ) ) { // No collision, move the full distance. eyePos += moveDirection * moveDistance; } else { // Move up to the point of collision. eyePos += moveDirection * forwardDistance; // Project the remaining movement onto the collision plane. const float COLLISION_BOUNCE = 0.001f; // don't creep into the plane due to floating-point rounding const float intoPlane = moveDirection.Dot( fowardCollisionPlane.N ) - COLLISION_BOUNCE; const Vector3f slideDirection = ( moveDirection - fowardCollisionPlane.N * intoPlane ); // Try to finish the move by sliding along the collision plane. float slideDistance = moveDistance; collisionModel.TestRay( eyePos - UpVector * RailHeight, slideDirection, slideDistance, NULL ); eyePos += slideDirection * slideDistance; } } if ( groundCollisionModel.Polytopes.GetSizeI() != 0 ) { // Check for collisions at foot level, which allows following terrain. float downDistance = 10.0f; groundCollisionModel.TestRay( eyePos, - UpVector, downDistance, NULL ); // Maintain the minimum camera height. if ( eyeHeight - downDistance < 1.0f ) { eyePos += UpVector * ( eyeHeight - downDistance ); } } return eyePos - UpVector * eyeHeight; }
std::pair<bool, Real> doPicking(const Ogre::Ray& localRay, const CollisionModel& collisionModel, CullingMode cullingMode) { // Convert our ray to Opcode ray IceMaths::Ray world_ray( IceMaths::Point(localRay.getOrigin().x, localRay.getOrigin().y, localRay.getOrigin().z), IceMaths::Point(localRay.getDirection().x, localRay.getDirection().y, localRay.getDirection().z)); // Be aware we store triangle as ccw in collision mode, and Opcode treat it as cw, // so need to inverse cull mode here. Opcode::CullMode cullMode; switch (cullingMode) { default: case CULL_NONE: cullMode = Opcode::CULLMODE_NONE; break; case CULL_CLOCKWISE: cullMode = Opcode::CULLMODE_CCW; break; case CULL_ANTICLOCKWISE: cullMode = Opcode::CULLMODE_CW; break; } // Cull mode callback for Opcode struct Local { static Opcode::CullMode cullModeCallback(udword triangle_index, void* user_data) { return (Opcode::CullMode) (int) user_data; } }; std::pair<bool, Real> ret; // Do picking Opcode::CollisionFace picked_face; ret.first = Opcode::Picking(picked_face, world_ray, collisionModel.getOpcodeModel(), 0, 0, FLT_MAX, world_ray.mOrig, &Local::cullModeCallback, (void*) (int) cullMode); ret.second = ret.first ? picked_face.mDistance : 0; return ret; }
std::pair<bool, Real> rayCollide(const Ogre::Ray& ray, Ogre::MovableObject* movable, bool accurate, CullingMode cullingMode, bool allowAnimable) { // Get local space axis aligned bounding box const Ogre::AxisAlignedBox& aabb = movable->getBoundingBox(); // Matrix4 to transform local space to world space const Ogre::Matrix4& localToWorld = movable->_getParentNodeFullTransform(); // Matrix4 to transform world space to local space Ogre::Matrix4 worldToLocal = localToWorld.inverse(); // Matrix3 to transform world space normal to local space Ogre::Matrix3 worldToLocalN; worldToLocal.extract3x3Matrix(worldToLocalN); // Convert world space ray to local space ray // Note: // By preserving the scale between world space and local space of the // direction, we don't need to recalculate the distance later. Ogre::Ray localRay; localRay.setOrigin(worldToLocal * ray.getOrigin()); localRay.setDirection(worldToLocalN * ray.getDirection()); // Intersect with axis aligned bounding box, but because we transformed // ray to local space of the bounding box, so this test just like test // with oriented bounding box. std::pair<bool, Real> ret = localRay.intersects(aabb); // Do accurate test if hitted bounding box and user required. if (ret.first && accurate) { if (movable->getMovableType() == Ogre::EntityFactory::FACTORY_TYPE_NAME || allowAnimable && movable->getMovableType() == Ogre::AutoAnimationEntityFactory::FACTORY_TYPE_NAME) { Ogre::Entity* entity = static_cast<Ogre::Entity*>(movable); if (!entity->_isAnimated()) { // Static entity // Get the entity mesh const Ogre::MeshPtr& mesh = entity->getMesh(); // Get the collision mode CollisionModelPtr collisionModel = CollisionModelManager::getSingleton().getCollisionModel(mesh); ret = doPicking(localRay, *collisionModel, cullingMode); } else if (allowAnimable) { // Animation entity bool addedSoftwareAnimation = false; if (entity->getSoftwareAnimationRequests() <= 0) { entity->addSoftwareAnimationRequest(false); entity->_updateAnimation(); addedSoftwareAnimation = true; } CollisionModel collisionModel; collisionModel.addEntity(entity); collisionModel.build(true); ret = doPicking(localRay, collisionModel, cullingMode); if (addedSoftwareAnimation) { entity->removeSoftwareAnimationRequest(false); } } } } return ret; }