void NxMeshManager::SetPivotTransform( Ogre::MeshPtr mesh, const Nx::Vector3 & Position, const Nx::Quaternion & Rotation, const Nx::Vector3 & Scale ) { //from mesh magick / mit licence Nx::Matrix4 transform = Nx::Matrix4::IDENTITY; Nx::Vector3 translate = Nx::Vector3::ZERO; // Apply current transform to the mesh, to get the bounding box to // base te translation on. AxisAlignedBox aabb = getMeshAabb( mesh, transform); //if (alignment == "left") //{ // translate = Vector3(-aabb.getMinimum().x, 0, 0); //} //else if (alignment == "center") //{ // translate = Vector3(-aabb.getCenter().x, 0, 0); //} //else if (alignment == "right") //{ // translate = Vector3(-aabb.getMaximum().x, 0, 0); //} //Position .. only support pivot down / centered //translate = Vector3(0, -aabb.getMinimum().y, 0);// pivot down translate = Position; transform = Nx::Matrix4::getTrans(translate) * transform; //rotation transform = Nx::Matrix4(Rotation) * transform; //scale transform = Nx::Matrix4::getScale(Scale) * transform; // Check whether we have to flip vertex winding. // We do have to, if we changed our right hand base. // We can test it by using the cross product from X and Y and see, if it is a non-negative // projection on Z. Actually it should be exactly Z, as we don't do non-uniform scaling yet, // but the test is cheap either way. Nx::Matrix3 m3; transform.extract3x3Matrix(m3); if (m3.GetColumn(0).crossProduct(m3.GetColumn(1)).dotProduct(m3.GetColumn(2)) < 0) { LogMsg("SetPivotPosition : Flipping vertex winding ... " ); mFlipVertexWinding = true; } //mTransform = transform; NxMat4toOgre( mTransform, transform ) ; mBoundingBox.setNull(); if( mesh->sharedVertexData != NULL) { processVertexData( mesh->sharedVertexData); }else { LogMsg("mesh->sharedVertexData NULL"); } for( int i = 0; i < mesh->getNumSubMeshes(); i++ ) { SubMesh* submesh = mesh->getSubMesh(i); if( submesh->vertexData != NULL ) { LogMsg("SetPivotPosition : Processing vertex data ... " ); processVertexData(submesh->vertexData); }else { LogMsg("submesh->vertexData NULL"); } if (submesh->indexData != NULL) { LogMsg("SetPivotPosition : Processing Index data .." ); processIndexData(submesh->indexData); }else { LogMsg("submesh->indexData NULL"); } } //process pose for( unsigned short i = 0; i < mesh->getPoseCount(); ++i ) { Ogre::Pose * pose = mesh->getPose(i); Ogre::Matrix3 m3x3; mTransform.extract3x3Matrix(m3x3); Pose::VertexOffsetIterator it = pose->getVertexOffsetIterator(); while (it.hasMoreElements()) { Ogre::Vector3 offset = it.peekNextValue(); Ogre::Vector3 newOffset = m3x3 * offset; *it.peekNextValuePtr() = newOffset; it.moveNext(); } } mesh->_setBounds( mBoundingBox, false ); }
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; }