Introducción a Bullet
Transcripción
Introducción a Bullet
VIDEOJUEGOS 2 Introducción a Bullet Motores de físicas V2 Puntos a tratar • • • • • • • • • Arquitectura de Bullet Fases del motor Algoritmos de detección de colisiones Configuración del motor Etapa de la simulación Cuerpos rígidos Cuerpos blandos Contactos Herramientas Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !2 V2 Motores de físicas Motor de físicas Bullet • Motor de físicas Open Source escrito en C++ • Soporta la mayoría de las plataformas • Utiliza aceleración por hardware • GPU utilizando OpenCL (requiere ATI Radeon 5870 o nVidia 470) • NEON en Android / iOS (SIMD) • Cell SPU en Playstation 3 • Permite almacenar y recuperar los datos de la física de ficheros • Blender • Maya (plugin Dynamica Bullet Maya) • Formatos • COLLADA (obsoleto) • Formato propio (.bullet) Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !3 V2 Motores de físicas Arquitectura de la librería Dinámica de cuerpos blandos Paralelización en SPU (Playstation 3) BulletSoftDynamics BulletMultiThreaded Dinámica de cuerpos rígidos BulletDynamics Detección de colisiones BulletCollision Álgebra lineal LinearMath Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !4 V2 Motores de físicas Arquitectura de clases de Bullet • Sigue una arquitectura modular Clase principal que representa el mundo de la simulación física Utiliza los siguientes módulos: btDynamicsWorld Detección gruesa de colisiones (AABB) ! ! ! ! ! ! btBroadphaseInterface Videojuegos II Detección de colisiones y puntos de contacto ! ! btDispatcher Configuración de los algoritmos a utilizar ! btCollisionConfiguration © 2013-2014 Depto. Ciencia de la Computación e IA Resolución de restricciones y contactos ! ! ! ! ! btConstraintSolver Introducción a Bullet !5 V2 Motores de físicas Arquitectura de clases de Bullet • Podemos reemplazar distintos módulos btDiscriteDynamicsWorld btSoftRigidDynamicsWorld btDynamicsWorld btGpu3DGrid btCollisionDispatcher btParallelConstraintSolver btMultiSapBroadphase SpuGatheringCollisionDispatcher btSequentialImpulseConstraintSolver btAxisSweep3 btDispatcher btDbvtBroadphase btDefaultCollisionConfigurator btBroadphaseInterface Videojuegos II btCollisionConfiguration © 2013-2014 Depto. Ciencia de la Computación e IA btConstraintSolver Introducción a Bullet !6 V2 Motores de físicas Fases de la simulación Detección de colisiones Detección gruesa (broadphase) Videojuegos II Detección fina (narrowphase) Simulación física Resolución de contactos © 2013-2014 Depto. Ciencia de la Computación e IA Integración Introducción a Bullet !7 V2 Motores de físicas Algoritmos de broad phase Dynamic Bounding Volume (AABB) Tree Sweep And Prune (SAP) • btDbvtBroadphase • Utiliza una jerarquía de BVs (AABB) • Apropiado para mundos con gran cantidad de objetos dinámicos • btAxisSweep3 • bt32AxisSweep3 (Versión de 32 bits) • Requiere un tamaño fijo del mundo, conocido de antemano • Apropiado cuando la mayoría de objetos tienen poco o ningún movimiento Fast Uniform Grid Videojuegos II • btGpu3DGrid • Acelerado por hardware © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !8 V2 Motores de físicas Inicialización del motor btCollisionConfiguration *collisionConfiguration = new btDefaultCollisionConfiguration(); ! btBroadphaseInterface *broadPhase = new btAxisSweep3(btVector3(-1000, -1000, -1000), btVector3(1000, 1000, 1000)); ! btDispatcher *dispatcher = new btCollisionDispatcher(collisionConfiguration); Fijamos límites del mundo para SAP ! btConstraintSolver *solver = new btSequentialImpulseConstraintSolver(); ! world = new btDiscreteDynamicsWorld(dispatcher, broadPhase, solver, collisionConfiguration); Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !9 V2 Motores de físicas Paso de la simulación • En cada iteración actualizamos la simulación con ! Opcionales ! world-‐>stepSimulation(timeStep, maxSubSteps, fixedTimeStep); ! Tiempo transcurrido desde ! la última actualización (s) Por defecto 1 Por defecto (1.0 / 60.0) ! ! ¡CUIDADO! Los tiempos se indican en segundos ! • La simulación se ejecuta a una tasa fija de 60 fps por defecto • Periodicidad de 16.6 ms (1 / 60) • Se trata de la resolución de la simulación • Podemos cambiarlo con fixedTimeStep Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !10 V2 Motores de físicas Cambios en el framerate • Si el ciclo itera más rápido que la periodicidad fija establecida • No vuelve a realizar simulación cada iteración • Simula el tiempo correspondiente a la tasa fija (por defecto 16.6 ms) • Interpola los resultados según el tiempo real transcurrido (menor que la tasa fija), hasta que haya que volver a simular ! Ejemplo: • Tasa fija 60 fps (16.6ms) • Tasa real 120 fps (8.3ms) ! • Si el ciclo itera más lento y #1 (0 ms) Simulado #2 (8.3 ms) Interpolado #3 (16.6 ms) x Simulado • Se puede realizar más de una simulación al llamar a stepSimulation • Se puede limitar el número máximo de simulaciones con maxSubSteps, debiendo cumplir: timeStep < maxSubSteps * fixedTimeStep Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA En caso de no cumplirse la simulación irá más lenta Introducción a Bullet !11 V2 Motores de físicas Tipos básicos btScalar Valor escalar. Su precisión por defecto es de float, pero se puede cambiar a double btVector3 Vector 3D con componentes (x, y, z) btQuaternion Representa una rotación mediante un quaternion btMatrix3x3 Representa una rotación mediante una matriz de transformación 3x3 btTransform Combina rotación y traslación Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !12 V2 Motores de físicas Objetos del mundo • Encontramos ! btRigidBody ! btCollisionObject • Sus propiedades son Masa btScalar Será 0 para objetos estáticos Forma! btCollisionShape Caja, Esfera, Cono, Maya, etc Tensor de inercia btVector3 Sólo elementos de la diagonal Resistencia al aire btScalar Lineal y angular (damping) Fricción btScalar Lineal y para formas redondas Restitución btScalar Coeficiente de restitución (para colisiones) Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !13 V2 Motores de físicas Creación de un cuerpo • Debemos instanciar un objeto btRigidBody ! btRigidBody *body = new btRigidBody(mass, motionState, shape, localInertia); • Por lo menos debemos proporcionar los anteriores parámetros ! Mass Si especificamos masa 0 será estático, en otro caso dinámico ! Motion State Indica la posición y orientación inicial del cuerpo ! Shape Forma geométrica del cuerpo !Local intertia Tensor de inercia del cuerpo • Podemos añadir datos de usuario (por ejemplo un nodo de Irrlicht) ! body->setUserPointer((void *)(irrNode)); • Finalmente, añadiremos el cuerpo al mundo world->addRigidBody(body); Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !14 V2 Motores de físicas Posición y orientación de los objetos • El objeto btMotionState facilita el acceso a esa información • Almacena esta información como btTransform • Incluye métodos para guardar y consultar este información ! ! btTransform transform; transform.setIdentity(); transform.setOrigin(position); ! ! ! ! btDefaultMotionState *motionState = new btDefaultMotionState(transform); motionState->setWorldTransform(transform); ... Se le pasa el objeto donde motionState->getWorldTransform(transform); leer por referencia ! • Al crear el cuerpo se proporciona un objeto btMotionState • Bullet coge de este objeto la posición al crear el cuerpo Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !15 V2 Motores de físicas Lectura de la posición y orientación • Podemos consultar en motion state la posición tras cada iteración • Bullet guarda la posición del objeto con setWorldTransform ! • Implementación por defecto btDefaultMotionState • Se pueden crear especializaciones mediante herencia • Por ejemplo, hacer render dentro de setWorldTransform ! • También podemos acceder directamente al objeto para obtener su posición y orientación btVector3 posicion = body->getCenterOfMassPosition(); const btQuaternion& orientacion = body->getOrientation(); Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA La posición de los objetos siempre se da respecto a su centro de masas Introducción a Bullet !16 V2 Motores de físicas Tipos de cuerpos Estáticos Cinemáticos Dinámicos Videojuegos II • Tienen masa 0 • El usuario nunca los debe mover • Tienen masa 0 • En cada iteración Bullet lee su motion state • Por lo tanto, el usuario puede moverlos cambiando su motion state • Tienen masa superior a 0 • La posición es determinada por la simulación • El usuario puede leer el motion state para actualizar los gráficos © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !17 V2 Motores de físicas Cuerpos cinemáticos • Se crea como un cuerpo btRigidBody con masa 0 • Esto hará que las fuerzas del mundo no le afecten • Si este cuerpo va a cambiar de posición, debemos marcarlo como cinemático ! ! ! body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); body->setActivationState(DISABLE_DEACTIVATION); ! • Esto hará que Bullet consulte su motion state antes de cada iteración • El motion state puede ser modificado antes de cada actualización de la simulación Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !18 V2 Motores de físicas Tensor de inercia • Se almacenen sólo los elementos de la diagonal del tensor de inercia, en forma de vector de 3 componentes (btVector3) ! • Se puede calcular automáticamente a partir de la forma y la masa de los objetos • La clase btCollisionShape proporciona métodos para calcularlo btCollisionShape *shape = new btSphereShape(radio); ! btVector3 localInertia; shape->calculateLocalInertia(masa, localInertia); Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !19 V2 Motores de físicas Formas para la colisión Objetos estáticos Mapa de alturas Otros btHeightfieldTerrainShape btStaticPlaneShape btBvhTriangleMeshShape btScaledBvhTriangleMeshShape Objetos dinámicos btBoxShape btSphereShape btCapsuleShape btCylinderShape btConeShape btConvexHullShape (forma convexa, limitar número de vértices <100) btCompoundShape (combinación de formas convexas) btGimpactTriangleMeshShape (evitar siempre que sea posible) Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !20 V2 Motores de físicas Ejemplo completo de creación de un cuerpo • Recibimos como entrada mass, scale y position btTransform transform; transform.setIdentity(); transform.setOrigin(position); ! btDefaultMotionState *motionState = new btDefaultMotionState(transform); ! btVector3 halfExtents(scale.X * 0.5f, scale.Y * 0.5f, scale.Z * 0.5f); btCollisionShape *shape = new btBoxShape(halfExtents); ! btVector3 localInertia; shape->calculateLocalInertia(mass, localInertia); ! btRigidBody *body = new btRigidBody(mass, motionState, shape, localInertia); ! body->setUserPointer((void *)(irrNode)); ! world->addRigidBody(body); Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !21 V2 Motores de físicas Actualización de un cuerpo en el mundo • Actualizaremos un nodo de la escena en Irrlicht • Recibimos como entrada el cuerpo body ISceneNode *irrNode = static_cast<ISceneNode *>(body->getUserPointer()); ! // Actualización de la posición btVector3 pos = body->getCenterOfMassPosition(); irrNode->setPosition(vector3df((f32)pos[0], (f32)pos[1], (f32)pos[2])); ! // Actualización de la orientación vector3df euler; const btQuaternion& quat = body->getOrientation(); quaternion q(quat.getX(), quat.getY(), quat.getZ(), quat.getW()); q.toEuler(euler); euler *= RADTODEG; irrNode->setRotation(euler); Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !22 V2 Motores de físicas Depuración • Bullet permite dibujar datos del mundo físico para depuración • • • • Maya de colisión Puntos de contacto y normales Bounding Volumes Restricciones y límites ! • Utilizaremos una clase de tipo btIDebugDraw • Sólo se proporciona una interfaz • Deberemos crear una implementación adaptada al motor gráfico • En ella volcaremos los datos de la física a las estructuras específicas de nuestro motor gráfico Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !23 V2 Motores de físicas Depuración con Irrlicht (I) class DebugDraw : public btIDebugDraw { private: int mode; IVideoDriver* const driver; ILogger* logger; ! Implementamos la interfaz de btIDebugDraw Volcaremos datos de Bullet a estructuras de Irrlicht public: DebugDraw(IrrlichtDevice* const device) : mode(DBG_NoDebug), driver(device->getVideoDriver()), logger(device->getLogger()) { } ! ! ! ! ! void drawLine(const btVector3& from, const btVector3& to, const btVector3& color) { SColor newColor(255, color[0]*255.0, color[1]*255.0, color[2]*255.0); this->driver->draw3DLine(vector3df(from[0], from[1], from[2]), vector3df(to[0], to[1], to[2]), newColor); } void drawContactPoint(const btVector3& PointOnB, const btVector3& normalOnB, btScalar distance, int lifeTime, const btVector3& color) { static const SColor CONTACTPOINT_COLOR(255, 255, 255, 0); const btVector3 to(PointOnB + normalOnB*distance); this->driver->draw3DLine(vector3df(PointOnB[0], PointOnB[1], PointOnB[2]), vector3df(to[0], to[1], to[2]), CONTACTPOINT_COLOR); } void reportErrorWarning(const char* text) { this->logger->log(text, ELL_ERROR); } Único método que debemos implementar obligatoriamente void draw3dText(const btVector3& location, const char* text) { } void setDebugMode(int mode) { this->mode = mode; } int getDebugMode() const { return this->mode; } }; Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !24 V2 Motores de físicas Depuración con Irrlicht (II) • Una vez definida la clase, la vinculamos al mundo físico ! ! DebugDraw debugDraw(device); debugDraw.setDebugMode(btIDebugDraw::DBG_DrawWireframe); world->setDebugDrawer(&debugDraw); ! ! • Dibujamos los datos de depuración en cada iteración SMaterial debugMat; debugMat.Lighting = false; ! driver->setMaterial(debugMat); driver->setTransform(ETS_WORLD, IdentityMatrix); world->debugDrawWorld(); Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Es importante restablecer la matriz de transformación Introducción a Bullet !25 V2 Motores de físicas Restricciones • Crean conexiones entre los cuerpos o limitan grados de libertad • Al menos uno de los cuerpos de la conexión debe ser dinámico • Todas derivan de btTypedConstraint • Tipos Point2Point Los objetos están unidos por un único punto. Podemos utilizarla para encadenar objetos. Hinge La rotación pierde 2 grados de libertad (puede rotar alrededor de un único eje). Por ejemplo para puertas. Slider Puede rotar y desplazarse a lo largo de un único eje. ConeTwist Generic6Dof Videojuegos II Tipo especial de Point2Point que limita el número de grados que puede girar. Util para articulaciones en ragdolls. Permite personalizar los grados de libertad que queremos limitar. © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !26 V2 Motores de físicas Cuerpos blandos • Los cuerpos blandos no tienen una única posición ! • Se componen de partículas conectadas de forma elástica • Se pueden crear a partir de una triangle mesh btSoftBodyHelpers::CreateFromTriMesh ! • Cada partícula (nodo) se puede tratar de forma independiente • Tienen su propia posición • Tienen su propia masa (incluso alguna puede ser estática) ! softbody->setMass(node, 0.0f); • Se les puede aplicar fuerzas de forma individual softbody->addForce(force, node); Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !27 V2 Motores de físicas Layering • Para implementar layering en Bullet utilizamos máscaras binarias ! • Al añadir el cuerpo al mundo podemos especificar la máscara ! int group = 4; // 0100 int mask = 3; // 0011 world->addRigidBody(body, group, mask); ! ! • En broad phase sólo se seleccionarán aquellos cuyas máscaras coincidan al menos en un bit con el grupo de nuestro objeto Grupos 0 1 1 1 Jugadores Videojuegos II Máscaras Muros NPC 0 0 1 1 0 1 0 1 0 0 0 0 Jugadores colisionan con NPCs y muros NPCs con jugadores y muros Muros no colisionan con nada © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !28 V2 Motores de físicas Información de contactos • Proporcionados por el dispatcher • La información de contactos se representa como un objeto de tipo contact manifold • Contiene una serie de puntos de contacto int numManifolds = world->getDispatcher()->getNumManifolds(); for (int i=0;i<numManifolds;i++) { btPersistentManifold* contactManifold = world->getDispatcher()->getManifoldByIndexInternal(i); const btCollisionObject* obA = static_cast<const btCollisionObject*>(contactManifold->getBody0()); const btCollisionObject* obB = static_cast<const btCollisionObject*>(contactManifold->getBody1()); ! } int numContacts = contactManifold->getNumContacts(); for (int j=0;j<numContacts;j++) { btManifoldPoint& pt = contactManifold->getContactPoint(j); } Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !29 V2 Motores de físicas Sensores (triggers) • Podemos obtener aviso de contactos sin simular colisión • P.ej., cuando una pelota atraviesa la portería ! • Utilizamos para ello sensores o triggers • En Bullet deberemos marcarlos con el flag de colisión CF_NO_CONTACT_RESPONSE ! ! body->setCollisionFlags(cubeBody->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE); ! • Nos informará de contactos en el manifold • La simulación no resolverá la colisión (este cuerpo será atravesado por otros) Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !30 V2 Motores de físicas Trazado de rayos ! • Podemos trazar rayos hacia los objetos del mundo de Bullet btVector3 start(0,0,0); btVector3 end(0,0,1); ! btCollisionWorld::ClosestRayResultCallback rayCallback(start, end); ! world->rayTest(start, end, rayCallback); ! if(rayCallback.hasHit()) { btVector3 point = rayCallback.m_hitPointWorld; btVector3 normal = rayCallback.m_hitNormalWorld; btCollisionObject *object = rayCallback.m_collisionObject; } Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !31 V2 Motores de físicas Objetos de colisión • Bullet no detecta colisiones entre cuerpos cinemáticos y estáticos • Siempre debe intervenir un cuerpo dinámico ! • Tenemos la opción de utilizar objetos de colisión Se implementan con btCollisionObject (o subclases) Se comportan de forma similar a cuerpos cinemáticos Permiten detectar colisiones sin simulación física NO son cuerpos rígidos • • • • btCollisionObject platform = new btCollisionObject(); ! btCollisionShape *platformShape = new btBoxShape(btVector3(25,0.5, 25)); platform->setCollisionShape(platformShape); world->addCollisionObject(platform); Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !32 V2 Motores de físicas Ghost Objects • Optimizan la detección de colisiones • Especialización de los objetos de colisión • Permiten consultar sólo las colisiones que se producen con ellos • Mantiene una caché de parejas con las que puede colisionar ! btPairCachingGhostObject *platform = new btPairCachingGhostObject(); ! ! btCollisionShape *platformShape = new btBoxShape(btVector3(25,0.5, 25)); platform->setCollisionShape(platformShape); ! world->addCollisionObject(platform); ! • Para que el ghost object mantenga su lista de colisiones deberemos además configurar el siguiente callback world->getBroadphase()->getOverlappingPairCache()-> setInternalGhostPairCallback(new btGhostPairCallback()); Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !33 V2 Motores de físicas Revisar los contactos del Ghost Object btManifoldArray manifoldArray; btBroadphasePairArray &pairs = body->getOverlappingPairCache()->getOverlappingPairArray(); ! for(int i=0;i< pairs.size();;i++) { manifoldArray.clear(); const btBroadphasePair &pair = pairs[i]; btBroadphasePair *collisionPair = world->getPairCache()->findPair(pair.m_pProxy0, pair.m_pProxy1); if(!collisionPair) continue; ! if(collisionPair->m_algorithm) { collisionPair->m_algorithm->getAllContactManifolds(manifoldArray); } } for(int j=0;j<manifoldArray.size();j++) { btPersistentManifold *manifold = manifoldArray[j]; for(int p=0;p<manifold->getNumContacts();p++) { const btManifoldPoint &contact = manifold->getContactPoint(p); } } ! Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !34 V2 Motores de físicas Controlador de personajes • Para nuestro personaje o NPCs podemos utilizar una forma de colisión de tipo cápsula • Deberemos evitar que el personaje pueda rotar ! ! body->setAngularFactor(0); • Existe un controlador cinemático experimental implementado btPairCachingGhostObject *ghostObject = new btPairCachingGhostObject(); ghostObject->setWorldTransform(transform); ! Utiliza un ghost object para detectar colisiones btScalar characterHeight=1.75; btScalar characterWidth =1.75; btConvexShape* capsule = new btCapsuleShape(characterWidth,characterHeight); ! Recomendable utilizar cápsula ghostObject->setCollisionShape (capsule); ghostObject->setCollisionFlags (btCollisionObject::CF_CHARACTER_OBJECT); ! btScalar stepHeight = btScalar(0.35); character = new btKinematicCharacterController(ghostObject,capsule,stepHeight); Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !35 V2 Motores de físicas Herramientas • Incluyen • Definición de formas de colisión • Propiedades de cuerpos rígidos y restricciones ! • Herramientas disponibles • Dynamica Maya Plugin • Blender ! • Formatos • Formato propio .bullet (permite serializar/deserializar a este formato) • COLLADA (obsoleto) Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !36 V2 Motores de físicas Definir físicas con Blender • Definiremos la física en el modo Blender Game Panel de físicas Propiedades físicas del material Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !37 V2 Motores de físicas Exportar físicas • Creamos un script para exportar físicas a un fichero .bullet ! ! ! ¡CUIDADO! Bullet utiliza un sistema de coordenadas en el que el eje Z es la altura ! • Añadimos un sensor vinculado con el script Al pulsar la tecla P durante la simulación se almacenarán los datos Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !38 V2 Motores de físicas Importar físicas • Debemos incluir el módulo de importación ! ¡CUIDADO! Irrlicht utiliza un sistema de coordenadas en el que el eje Y es la altura #include <BulletWorldImporter/btBulletWorldImporter.h> ! • Importamos los datos grabados ! ! btBulletWorldImporter* fileLoader = new btBulletWorldImporter(world); fileLoader->loadFile("escenario.bullet"); world->setGravity(btVector3(0,-10,0)); ! • Podemos consultar los objetos importados for(int i=0;i<objects.size();i++) { btCollisionObject *obj = objects[i]; printf("Encontrado cuerpo de tipo %d", obj->getCollisionShape()->getShapeType()); } Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !39 V2 Motores de físicas Sistemas de coordenadas • Podemos hacer coincidir los sistemas de coordenadas Blender - Irrlicht ! • Exportamos modelo gráfico en Blender con • Y up • -Z forward ! • Para la maya de colisión, transformamos el modelo con • Giro de -90º alrededor de x • Escalado de -1 en x (mirror) • Aplicamos la transformación (Object > Apply) • Exportamos y deshacemos los cambios Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !40 V2 Motores de físicas Recomendaciones para la exportación • Es posible agrupar todo el escenario en un único objeto • Abrimos el cuadro de herramientas con T • Utilizamos la herramienta Join de Blender • Por defecto se exportará como ScaledBvhTriangleMesh ! • Reducir la poligonización • Podemos utilizar la herramienta Decimate de Blender Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !41 V2 Motores de físicas Optimización del modelo importado • Por defecto Blender no construye el BVH del modelo exportado • Podemos construirlo con Bullet al importar ! for(int i=0;i<objects.size();i++) { btCollisionObject *obj = objects[i]; ! if(obj->getCollisionShape()->getShapeType()== SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE) { ! btScaledBvhTriangleMeshShape *shape = static_cast<btScaledBvhTriangleMeshShape *>(obj->getCollisionShape()); ! if(!shape->getChildShape()->getOwnsBvh()) { ! shape->getChildShape()->buildOptimizedBvh(); } ! } } ! • Si el proceso resulta lento, podemos serializar el objeto btOptimizedBvh • Métodos serializeInPlace y deSerializeInPlace Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !42 V2 Motores de físicas ¿Preguntas...? Videojuegos II © 2013-2014 Depto. Ciencia de la Computación e IA Introducción a Bullet !43