Start to support driving (and rescuing) on physical track objects.

This commit is contained in:
hiker
2014-09-11 21:48:03 +10:00
parent 8e12e68425
commit 68e45db8d3
10 changed files with 228 additions and 61 deletions

View File

@@ -307,6 +307,8 @@ void PhysicalObject::init()
}
case MP_EXACT:
{
m_graphical_offset = Vec3(0,0,0);
extend.setY(0);
TriangleMesh* triangle_mesh = new TriangleMesh();
// In case of readonly materials we have to get the material from
@@ -471,7 +473,8 @@ void PhysicalObject::init()
}
World::getWorld()->getPhysics()->addBody(m_body);
if(m_triangle_mesh)
m_triangle_mesh->setBody(m_body);
} // init
// ----------------------------------------------------------------------------
@@ -504,6 +507,40 @@ void PhysicalObject::update(float dt)
return;
} // update
// ----------------------------------------------------------------------------
/** Does a raycast against this physical object. The physical object must
* have an 'exact' shape, i.e. be a triangle mesh (for other physical objects
* no material information would be available).
* \param from/to The from and to position for the raycast.
* \param xyz The position in world where the ray hit.
* \param material The material of the mesh that was hit.
* \param normal The intrapolated normal at that position.
* \param interpolate_normal If true, the returned normal is the interpolated
* based on the three normals of the triangle and the location of the
* hit point (which is more compute intensive, but results in much
* smoother results).
* \return True if a triangle was hit, false otherwise (and no output
* variable will be set.
*/
bool PhysicalObject::castRay(const btVector3 &from, const btVector3 &to,
btVector3 *hit_point, const Material **material,
btVector3 *normal, bool interpolate_normal) const
{
if(m_body_type!=MP_EXACT)
{
Log::warn("PhysicalObject", "Can only raycast against 'exact' meshes.");
return false;
}
Vec3 dxyz(m_init_xyz);
//bool result = m_triangle_mesh->castRay(from-dxyz, to-dxyz, hit_point,
bool result = m_triangle_mesh->castRay(from, to, hit_point,
material, normal,
interpolate_normal);
// if(result)
// *hit_point += (btVector3)dxyz;
return result;
} // castRay
// ----------------------------------------------------------------------------
void PhysicalObject::reset()
{

View File

@@ -159,6 +159,11 @@ public:
void move (const Vec3& xyz, const core::vector3df& hpr);
void hit (const Material *m, const Vec3 &normal);
bool isSoccerBall () const;
bool castRay(const btVector3 &from,
const btVector3 &to, btVector3 *hit_point,
const Material **material, btVector3 *normal,
bool interpolate_normal) const;
// ------------------------------------------------------------------------
/** Returns the rigid body of this physical object. */
btRigidBody *getBody () { return m_body; }

View File

@@ -33,6 +33,7 @@
TriangleMesh::TriangleMesh() : m_mesh()
{
m_body = NULL;
m_free_body = true;
m_motion_state = NULL;
// FIXME: on VS in release mode this statement actually overwrites
// part of the data of m_mesh, causing a crash later. Debugging
@@ -200,7 +201,8 @@ void TriangleMesh::createPhysicalBody(btCollisionObject::CollisionFlags flags,
*/
void TriangleMesh::removeAll()
{
if(m_body)
// Don't free the physical body if it was created outside this object.
if(m_body && m_free_body)
{
World::getWorld()->getPhysics()->removeBody(m_body);
delete m_body;
@@ -301,6 +303,8 @@ bool TriangleMesh::castRay(const btVector3 &from, const btVector3 &to,
btTransform world_trans;
world_trans.setIdentity();
if(m_body)
world_trans = m_body->getWorldTransform();
btCollisionWorld::ClosestRayResultCallback result(from, to);
@@ -334,8 +338,8 @@ bool TriangleMesh::castRay(const btVector3 &from, const btVector3 &to,
// If this is a rigid body, m_collision_object is NULL, and the
// rigid body is the actual collision object.
btCollisionWorld::rayTestSingle(trans_from, trans_to,
m_collision_object ? m_collision_object
: m_body,
// m_body ? m_body : m_collision_object,
m_collision_object ? m_collision_object : m_body,
m_collision_shape, world_trans,
ray_callback);
// Get the index of the triangle hit

View File

@@ -37,6 +37,9 @@ private:
UserPointer m_user_pointer;
std::vector<const Material*> m_triangleIndex2Material;
btRigidBody *m_body;
/** Keep track if the physical body was created here or not. */
bool m_free_body;
btCollisionObject *m_collision_object;
btTriangleMesh m_mesh;
btVector3 dummy1, dummy2;
@@ -60,6 +63,13 @@ public:
btVector3 getInterpolatedNormal(unsigned int index,
const btVector3 &position) const;
// ------------------------------------------------------------------------
void setBody(btRigidBody *body)
{
assert(!m_body);
m_free_body = false;
m_body = body;
}
// ------------------------------------------------------------------------
const Material* getMaterial(int n) const
{return m_triangleIndex2Material[n];}
// ------------------------------------------------------------------------

View File

@@ -18,14 +18,16 @@
#include "tracks/terrain_info.hpp"
#include <math.h>
#include "modes/world.hpp"
#include "physics/triangle_mesh.hpp"
#include "race/race_manager.hpp"
#include "tracks/track.hpp"
#include "tracks/track_manager.hpp"
#include "tracks/track_object_manager.hpp"
#include "utils/constants.hpp"
#include <math.h>
/** Constructor to initialise terrain data.
*/
TerrainInfo::TerrainInfo()
@@ -59,6 +61,10 @@ void TerrainInfo::update(const Vec3 &from)
const TriangleMesh &tm = World::getWorld()->getTrack()->getTriangleMesh();
tm.castRay(from, to, &m_hit_point, &m_material, &m_normal,
/*interpolate*/false);
// Now also raycast against all track objects (that are driveable).
World::getWorld()->getTrack()->getTrackObjectManager()
->castRay(from, to, &m_hit_point, &m_material,
&m_normal, /*interpolate*/false);
} // update
//-----------------------------------------------------------------------------
/** Update the terrain information based on the latest position.
@@ -74,6 +80,10 @@ void TerrainInfo::update(const btTransform &trans, const Vec3 &offset)
const TriangleMesh &tm = World::getWorld()->getTrack()->getTriangleMesh();
tm.castRay(from, to, &m_hit_point, &m_material, &m_normal,
/*interpolate*/true);
// Now also raycast against all track objects (that are driveable).
World::getWorld()->getTrack()->getTrackObjectManager()
->castRay(from, to, &m_hit_point, &m_material,
&m_normal, /*interpolate*/true);
} // update
// -----------------------------------------------------------------------------

View File

@@ -2389,7 +2389,7 @@ std::vector< std::vector<float> > Track::buildHeightMap()
}
return out;
}
} // buildHeightMap
// ----------------------------------------------------------------------------
/** Returns the rotation of the sun. */

View File

@@ -42,7 +42,7 @@ TrackObject::TrackObject(const XMLNode &xml_node, scene::ISceneNode* parent,
ModelDefinitionLoader& model_def_loader)
{
init(xml_node, parent, model_def_loader);
}
} // TrackObject
// ----------------------------------------------------------------------------
/**
@@ -56,29 +56,33 @@ TrackObject::TrackObject(const core::vector3df& xyz, const core::vector3df& hpr,
bool is_dynamic,
const PhysicalObject::Settings* physics_settings)
{
m_init_xyz = xyz;
m_init_hpr = hpr;
m_init_scale = scale;
m_enabled = true;
m_presentation = NULL;
m_animator = NULL;
m_init_xyz = xyz;
m_init_hpr = hpr;
m_init_scale = scale;
m_enabled = true;
m_presentation = NULL;
m_animator = NULL;
m_physical_object = NULL;
m_interaction = interaction;
m_presentation = presentation;
m_interaction = interaction;
m_presentation = presentation;
if (m_interaction != "ghost" && m_interaction != "none" &&
physics_settings )
{
m_physical_object = new PhysicalObject(is_dynamic,
*physics_settings,
this);
*physics_settings,
this);
}
reset();
} // TrackObject
// ----------------------------------------------------------------------------
/** Initialises the track object based on the specified XML data.
* \param xml_node The XML data.
* \param parent The parent scene node.
* \param model_def_loader Used to load level-of-detail nodes.
*/
void TrackObject::init(const XMLNode &xml_node, scene::ISceneNode* parent,
ModelDefinitionLoader& model_def_loader)
{
@@ -100,6 +104,9 @@ void TrackObject::init(const XMLNode &xml_node, scene::ISceneNode* parent,
xml_node.get("interaction", &m_interaction);
xml_node.get("lod_group", &m_lod_group);
m_is_driveable = false;
xml_node.get("driveable", &m_is_driveable);
bool lod_instance = false;
xml_node.get("lod_instance", &lod_instance);
@@ -252,14 +259,42 @@ void TrackObject::setEnable(bool mode)
// ----------------------------------------------------------------------------
void TrackObject::update(float dt)
{
if (m_presentation != NULL) m_presentation->update(dt);
if (m_presentation) m_presentation->update(dt);
if (m_physical_object != NULL) m_physical_object->update(dt);
if (m_physical_object) m_physical_object->update(dt);
if (m_animator != NULL) m_animator->update(dt);
if (m_animator) m_animator->update(dt);
} // update
// ----------------------------------------------------------------------------
/** Does a raycast against the track object. The object must have a physical
* object.
* \param from/to The from and to position for the raycast.
* \param xyz The position in world where the ray hit.
* \param material The material of the mesh that was hit.
* \param normal The intrapolated normal at that position.
* \param interpolate_normal If true, the returned normal is the interpolated
* based on the three normals of the triangle and the location of the
* hit point (which is more compute intensive, but results in much
* smoother results).
* \return True if a triangle was hit, false otherwise (and no output
* variable will be set.
*/
bool TrackObject::castRay(const btVector3 &from,
const btVector3 &to, btVector3 *hit_point,
const Material **material, btVector3 *normal,
bool interpolate_normal) const
{
if(!m_physical_object)
{
Log::warn("TrackObject", "Can't raycast on non-physical object.");
return false;
}
return m_physical_object->castRay(from, to, hit_point, material, normal,
interpolate_normal);
} // castRay
// ----------------------------------------------------------------------------
void TrackObject::move(const core::vector3df& xyz, const core::vector3df& hpr,

View File

@@ -75,7 +75,10 @@ protected:
bool m_soccer_ball;
bool m_garage;
/** True if a kart can drive on this object. This will */
bool m_is_driveable;
float m_distance;
PhysicalObject* m_physical_object;
@@ -96,46 +99,61 @@ public:
const PhysicalObject::Settings* physicsSettings);
virtual ~TrackObject();
virtual void update(float dt);
virtual void reset();
/** To finish object constructions. Called after the track model
* is ready. */
virtual void init() {};
/** Called when an explosion happens. As a default does nothing, will
* e.g. be overwritten by physical objects etc. */
virtual void handleExplosion(const Vec3& pos, bool directHit) {};
void setEnable(bool mode);
const std::string& getLodGroup() const { return m_lod_group; }
const std::string& getType() const { return m_type; }
bool isSoccerBall() const { return m_soccer_ball; }
bool isGarage() const { return m_garage; }
float getDistance() const { return m_distance; }
const PhysicalObject* getPhysicalObject() const { return m_physical_object; }
PhysicalObject* getPhysicalObject() { return m_physical_object; }
const core::vector3df getInitXYZ() const { return m_init_xyz; }
const core::vector3df getInitRotation() const { return m_init_hpr; }
const core::vector3df getInitScale() const { return m_init_scale; }
void move(const core::vector3df& xyz, const core::vector3df& hpr,
const core::vector3df& scale, bool updateRigidBody);
template<typename T>
T* getPresentation() { return dynamic_cast<T*>(m_presentation); }
template<typename T>
const T* getPresentation() const { return dynamic_cast<T*>(m_presentation); }
ThreeDAnimation* getAnimator() { return m_animator; }
const ThreeDAnimation* getAnimator() const { return m_animator; }
virtual void reset();
void setEnable(bool mode);
const core::vector3df& getPosition() const;
const core::vector3df getAbsolutePosition() const;
const core::vector3df& getRotation() const;
const core::vector3df& getScale() const;
bool castRay(const btVector3 &from,
const btVector3 &to, btVector3 *hit_point,
const Material **material, btVector3 *normal,
bool interpolate_normal) const;
// ------------------------------------------------------------------------
/** To finish object constructions. Called after the track model
* is ready. */
virtual void init() {};
// ------------------------------------------------------------------------
/** Called when an explosion happens. As a default does nothing, will
* e.g. be overwritten by physical objects etc. */
virtual void handleExplosion(const Vec3& pos, bool directHit) {};
// ------------------------------------------------------------------------
const std::string& getLodGroup() const { return m_lod_group; }
// ------------------------------------------------------------------------
const std::string& getType() const { return m_type; }
// ------------------------------------------------------------------------
bool isSoccerBall() const { return m_soccer_ball; }
// ------------------------------------------------------------------------
bool isGarage() const { return m_garage; }
// ------------------------------------------------------------------------
float getDistance() const { return m_distance; }
// ------------------------------------------------------------------------
const PhysicalObject* getPhysicalObject() const { return m_physical_object; }
// ------------------------------------------------------------------------
PhysicalObject* getPhysicalObject() { return m_physical_object; }
// ------------------------------------------------------------------------
const core::vector3df getInitXYZ() const { return m_init_xyz; }
// ------------------------------------------------------------------------
const core::vector3df getInitRotation() const { return m_init_hpr; }
// ------------------------------------------------------------------------
const core::vector3df getInitScale() const { return m_init_scale; }
// ------------------------------------------------------------------------
template<typename T>
T* getPresentation() { return dynamic_cast<T*>(m_presentation); }
// ------------------------------------------------------------------------
template<typename T>
const T* getPresentation() const { return dynamic_cast<T*>(m_presentation); }
// ------------------------------------------------------------------------
ThreeDAnimation* getAnimator() { return m_animator; }
// ------------------------------------------------------------------------
const ThreeDAnimation* getAnimator() const { return m_animator; }
// ------------------------------------------------------------------------
/** Returns if a kart can drive on this object. */
bool isDriveable() const { return m_is_driveable; }
LEAK_CHECK()
}; // TrackObject

View File

@@ -50,11 +50,15 @@ TrackObjectManager::~TrackObjectManager()
* in a separate section that's read before everything and remove all this
* crap
*/
void TrackObjectManager::add(const XMLNode &xml_node, scene::ISceneNode* parent, ModelDefinitionLoader& model_def_loader)
void TrackObjectManager::add(const XMLNode &xml_node, scene::ISceneNode* parent,
ModelDefinitionLoader& model_def_loader)
{
try
{
m_all_objects.push_back(new TrackObject(xml_node, parent, model_def_loader));
TrackObject *obj = new TrackObject(xml_node, parent, model_def_loader);
m_all_objects.push_back(obj);
if(obj->isDriveable())
m_driveable_objects.push_back(obj);
}
catch (std::exception& e)
{
@@ -120,6 +124,40 @@ void TrackObjectManager::update(float dt)
}
} // update
// ----------------------------------------------------------------------------
void TrackObjectManager::castRay(const btVector3 &from,
const btVector3 &to, btVector3 *hit_point,
const Material **material,
btVector3 *normal,
bool interpolate_normal) const
{
float distance = 9999.9f;
// If there was a hit already, compute the current distance
if(*material)
{
distance = hit_point->distance(from);
}
const TrackObject* curr;
for_in (curr, m_driveable_objects)
{
btVector3 new_hit_point;
const Material *new_material;
btVector3 new_normal;
if(curr->castRay(from, to, &new_hit_point, &new_material, &new_normal,
interpolate_normal))
{
float new_distance = new_hit_point.distance(from);
if (new_distance < distance)
{
*material = new_material;
*hit_point = new_hit_point;
*normal = new_normal;
distance = new_distance;
} // if new_distance < distance
} // if hit
} // for all track objects.
} // castRay
// ----------------------------------------------------------------------------
/** Enables or disables fog for a given scene node.
* \param node The node to adjust.

View File

@@ -44,17 +44,27 @@ protected:
* eye candy (to reduce work for physics), ...
*/
enum TrackObjectType {TO_PHYSICAL, TO_GRAPHICAL};
/** The list of all track objects. */
PtrVector<TrackObject> m_all_objects;
/** A second list which holds all objects that karts can drive on. */
PtrVector<TrackObject, REF> m_driveable_objects;
public:
TrackObjectManager();
~TrackObjectManager();
void add(const XMLNode &xml_node, scene::ISceneNode* parent, ModelDefinitionLoader& model_def_loader);
void reset();
void init();
void add(const XMLNode &xml_node, scene::ISceneNode* parent,
ModelDefinitionLoader& model_def_loader);
void update(float dt);
void handleExplosion(const Vec3 &pos, const PhysicalObject *mp,
bool secondary_hits=true);
void reset();
void init();
void castRay(const btVector3 &from,
const btVector3 &to, btVector3 *hit_point,
const Material **material, btVector3 *normal = NULL,
bool interpolate_normal = false) const;
/** Enable or disable fog on objects */
void enableFog(bool enable);