Replaced raycast used in detecting the terrain is on: instead of raycast
against the dynamics world, it's now using a raycast against the triangle mesh only (i.e. a single collision body instead of the whole world). Besides being faster, this will allow raycasts with material detection against the 'gfx' (surface) mesh. git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@7694 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
4eae628cab
commit
78eb5a09eb
@ -29,6 +29,7 @@
|
||||
#include "modes/world.hpp"
|
||||
#include "network/network_manager.hpp"
|
||||
#include "network/race_state.hpp"
|
||||
#include "physics/triangle_mesh.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
|
||||
@ -235,9 +236,10 @@ void Powerup::use()
|
||||
Vec3 hit_point;
|
||||
Vec3 normal;
|
||||
const Material* material_hit;
|
||||
btVector3 pos = m_owner->getXYZ();
|
||||
world->getTrack()->getTerrainInfo(pos, &hit_point, &normal,
|
||||
&material_hit);
|
||||
Vec3 pos = m_owner->getXYZ();
|
||||
Vec3 to=pos+Vec3(0, -10000, 0);
|
||||
world->getTrack()->getTriangleMesh().castRay(pos, to, &hit_point,
|
||||
&material_hit, &normal);
|
||||
// This can happen if the kart is 'over nothing' when dropping
|
||||
// the bubble gum
|
||||
if(!material_hit)
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "network/network_manager.hpp"
|
||||
#include "network/race_state.hpp"
|
||||
#include "physics/btKart.hpp"
|
||||
#include "physics/triangle_mesh.hpp"
|
||||
#include "race/highscore_manager.hpp"
|
||||
#include "race/history.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
@ -451,8 +452,10 @@ void World::resetAllKarts()
|
||||
(*i)->getBody()->getMotionState()->getWorldTransform(t);
|
||||
// This test can not be done only once before the loop, since
|
||||
// it can happen that the kart falls through the track later!
|
||||
m_track->getTerrainInfo(t.getOrigin(), &hit_point, &normal,
|
||||
&material);
|
||||
Vec3 to = t.getOrigin()+Vec3(0, -10000, 0);
|
||||
m_track->getTriangleMesh().castRay(t.getOrigin(), to,
|
||||
&hit_point, &material,
|
||||
&normal);
|
||||
if(!material)
|
||||
{
|
||||
fprintf(stderr, "ERROR: no valid starting position for kart %d on track %s.\n",
|
||||
|
@ -19,6 +19,8 @@
|
||||
|
||||
#include "physics/triangle_mesh.hpp"
|
||||
|
||||
#include "btBulletDynamicsCommon.h"
|
||||
|
||||
#include "modes/world.hpp"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -26,14 +28,15 @@
|
||||
*/
|
||||
TriangleMesh::TriangleMesh() : m_mesh()
|
||||
{
|
||||
m_body = NULL;
|
||||
m_motion_state = NULL;
|
||||
m_body = NULL;
|
||||
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
|
||||
// shows that apparently m_collision_shape is at the same address
|
||||
// as m_mesh->m_use32bitIndices and m_use4componentVertices
|
||||
// (and m_mesh->m_weldingThreshold at m_normals
|
||||
m_collision_shape = NULL;
|
||||
m_collision_shape = NULL;
|
||||
m_collision_object = NULL;
|
||||
m_user_pointer.set(this);
|
||||
} // TriangleMesh
|
||||
|
||||
@ -49,6 +52,8 @@ TriangleMesh::~TriangleMesh()
|
||||
delete m_motion_state;
|
||||
delete m_collision_shape;
|
||||
}
|
||||
if(m_collision_object)
|
||||
delete m_collision_object;
|
||||
} // ~TriangleMesh
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -75,18 +80,26 @@ void TriangleMesh::addTriangle(const btVector3 &t1, const btVector3 &t2,
|
||||
/** Creates a collision body only, which can be used for raycasting, but
|
||||
* has no physical properties.
|
||||
*/
|
||||
void TriangleMesh::createCollisionShape()
|
||||
void TriangleMesh::createCollisionShape(bool create_collision_object)
|
||||
{
|
||||
if(m_triangleIndex2Material.size()==0)
|
||||
{
|
||||
m_collision_shape = NULL;
|
||||
m_motion_state = NULL;
|
||||
m_body = NULL;
|
||||
m_collision_shape = NULL;
|
||||
m_motion_state = NULL;
|
||||
m_body = NULL;
|
||||
m_collision_object = NULL;
|
||||
return;
|
||||
}
|
||||
// Now convert the triangle mesh into a static rigid body
|
||||
m_collision_shape = new btBvhTriangleMeshShape(&m_mesh, true);
|
||||
m_collision_shape->setUserPointer(&m_user_pointer);
|
||||
if(create_collision_object)
|
||||
{
|
||||
m_collision_object = new btCollisionObject();
|
||||
btTransform bt;
|
||||
bt.setIdentity();
|
||||
m_collision_object->setWorldTransform(bt);
|
||||
}
|
||||
} // createCollisionShape
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -101,14 +114,15 @@ void TriangleMesh::createCollisionShape()
|
||||
*/
|
||||
void TriangleMesh::createPhysicalBody(btCollisionObject::CollisionFlags flags)
|
||||
{
|
||||
createCollisionShape();
|
||||
// We need the collision shape, but not the collision object (since
|
||||
// this will be creates when the dynamics body is anyway).
|
||||
createCollisionShape(/*create_collision_object*/false);
|
||||
btTransform startTransform;
|
||||
startTransform.setIdentity();
|
||||
m_motion_state = new btDefaultMotionState(startTransform);
|
||||
btRigidBody::btRigidBodyConstructionInfo info(0.0f, m_motion_state,
|
||||
m_collision_shape);
|
||||
m_body=new btRigidBody(info);
|
||||
|
||||
World::getWorld()->getPhysics()->addBody(m_body);
|
||||
|
||||
m_body->setUserPointer(&m_user_pointer);
|
||||
@ -183,3 +197,81 @@ btVector3 TriangleMesh::getInterpolatedNormal(unsigned int index,
|
||||
|
||||
return s*n1 + t*n2 + w*n3;
|
||||
} // getInterpolatedNormal
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Casts a ray from 'from' to 'to'. If a triangle of this mesh was hit,
|
||||
* xyz and material will be set.
|
||||
* \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.
|
||||
* \return True if a triangle was hit, false otherwise (and no output
|
||||
* variable will be set.
|
||||
*/
|
||||
bool TriangleMesh::castRay(const btVector3 &from, const btVector3 &to,
|
||||
btVector3 *xyz, const Material **material,
|
||||
btVector3 *normal) const
|
||||
{
|
||||
btTransform trans_from;
|
||||
trans_from.setIdentity();
|
||||
trans_from.setOrigin(from);
|
||||
|
||||
btTransform trans_to;
|
||||
trans_to.setIdentity();
|
||||
trans_to.setOrigin(to);
|
||||
|
||||
btTransform world_trans;
|
||||
world_trans.setIdentity();
|
||||
|
||||
btCollisionWorld::ClosestRayResultCallback result(from, to);
|
||||
|
||||
|
||||
class MaterialRayResult : public btCollisionWorld::ClosestRayResultCallback
|
||||
{
|
||||
public:
|
||||
const Material* m_material;
|
||||
const TriangleMesh *m_this;
|
||||
// --------------------------------------------------------------------
|
||||
MaterialRayResult(const btVector3 &p1, const btVector3 &p2,
|
||||
const TriangleMesh *me)
|
||||
: btCollisionWorld::ClosestRayResultCallback(p1,p2)
|
||||
{
|
||||
m_material = NULL;
|
||||
m_this = me;
|
||||
} // MaterialRayResult
|
||||
// --------------------------------------------------------------------
|
||||
virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,
|
||||
bool normalInWorldSpace)
|
||||
{
|
||||
m_material =
|
||||
m_this->getMaterial(rayResult.m_localShapeInfo->m_triangleIndex);
|
||||
return btCollisionWorld::ClosestRayResultCallback
|
||||
::addSingleResult(rayResult, normalInWorldSpace);
|
||||
} // AddSingleResult
|
||||
// --------------------------------------------------------------------
|
||||
}; // myCollision
|
||||
|
||||
MaterialRayResult ray_callback(from, to, this);
|
||||
|
||||
// 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_collision_shape, world_trans,
|
||||
ray_callback);
|
||||
if(ray_callback.hasHit())
|
||||
{
|
||||
*xyz = ray_callback.m_hitPointWorld;
|
||||
*material = ray_callback.m_material;
|
||||
*normal = ray_callback.m_hitNormalWorld;
|
||||
normal->normalize();
|
||||
}
|
||||
else
|
||||
{
|
||||
*material = NULL;
|
||||
normal->setValue(0, 1, 0);
|
||||
}
|
||||
return ray_callback.hasHit();
|
||||
|
||||
} // castRay
|
@ -38,6 +38,7 @@ private:
|
||||
UserPointer m_user_pointer;
|
||||
std::vector<const Material*> m_triangleIndex2Material;
|
||||
btRigidBody *m_body;
|
||||
btCollisionObject *m_collision_object;
|
||||
btTriangleMesh m_mesh;
|
||||
btVector3 dummy1, dummy2;
|
||||
btDefaultMotionState *m_motion_state;
|
||||
@ -51,7 +52,7 @@ public:
|
||||
const btVector3 &t3, const btVector3 &n1,
|
||||
const btVector3 &n2, const btVector3 &n3,
|
||||
const Material* m);
|
||||
void createCollisionShape();
|
||||
void createCollisionShape(bool create_collision_object=true);
|
||||
void createPhysicalBody(btCollisionObject::CollisionFlags flags=
|
||||
(btCollisionObject::CollisionFlags)0);
|
||||
void removeBody();
|
||||
@ -64,6 +65,10 @@ public:
|
||||
const btCollisionShape &getCollisionShape() const
|
||||
{return *m_collision_shape;}
|
||||
// ------------------------------------------------------------------------
|
||||
bool castRay(const btVector3 &from, const btVector3 &to,
|
||||
btVector3 *xyz, const Material **material,
|
||||
btVector3 *normal=NULL) const;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the points of the 'indx' triangle.
|
||||
* \param indx Index of the triangle to get.
|
||||
* \param p1,p2,p3 On return the three points of the triangle. */
|
||||
|
@ -50,9 +50,11 @@ TerrainInfo::TerrainInfo(const Vec3 &pos)
|
||||
void TerrainInfo::update(const Vec3& pos)
|
||||
{
|
||||
m_last_material = m_material;
|
||||
World::getWorld()->getTrack()->getTerrainInfo(pos, &m_hit_point,
|
||||
&m_normal, &m_material);
|
||||
m_normal.normalize();
|
||||
btVector3 to(pos);
|
||||
to.setY(-100000.f);
|
||||
|
||||
const TriangleMesh &tm = World::getWorld()->getTrack()->getTriangleMesh();
|
||||
tm.castRay(pos, to, &m_hit_point, &m_material, &m_normal);
|
||||
} // update
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -1122,66 +1122,6 @@ void Track::itemCommand(const Vec3 &xyz, Item::ItemType type,
|
||||
item_manager->newItem(type, loc, normal);
|
||||
} // itemCommand
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Does a ray cast straight down from the given position, and returns
|
||||
* the hit point, material, and normal at the given location (or material
|
||||
* ==NULL if no triangle was hit).
|
||||
* \param pos Positions from which to cast the ray.
|
||||
* \param hit_point On return: the position which was hit.
|
||||
* \param normal On return the normal of the triangle at that point.
|
||||
* \param material The material at the hit point (or NULL if no material
|
||||
* was found.
|
||||
*/
|
||||
void Track::getTerrainInfo(const Vec3 &pos, Vec3 *hit_point, Vec3 *normal,
|
||||
const Material **material) const
|
||||
{
|
||||
btVector3 to_pos(pos);
|
||||
to_pos.setY(-100000.f);
|
||||
|
||||
class MaterialCollision : public btCollisionWorld::ClosestRayResultCallback
|
||||
{
|
||||
public:
|
||||
const Material* m_material;
|
||||
MaterialCollision(const btVector3 &p1, const btVector3 &p2) :
|
||||
btCollisionWorld::ClosestRayResultCallback(p1,p2) {m_material=NULL;}
|
||||
virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,
|
||||
bool normalInWorldSpace) {
|
||||
if(rayResult.m_localShapeInfo && rayResult.m_localShapeInfo->m_shapePart>=0 )
|
||||
{
|
||||
m_material = ((TriangleMesh*)rayResult.m_collisionObject->getUserPointer())->getMaterial(rayResult.m_localShapeInfo->m_triangleIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This can happen if the raycast hits a kart. This should
|
||||
// actually be impossible (since the kart is removed from
|
||||
// the collision group), but now and again the karts don't
|
||||
// have the broadphase handle set (kart::update() for
|
||||
// details), and it might still happen. So in this case
|
||||
// just ignore this callback and don't add it.
|
||||
return 1.0f;
|
||||
}
|
||||
return btCollisionWorld::ClosestRayResultCallback::addSingleResult(rayResult,
|
||||
normalInWorldSpace);
|
||||
} // AddSingleResult
|
||||
}; // myCollision
|
||||
MaterialCollision rayCallback(pos, to_pos);
|
||||
World::getWorld()->getPhysics()->getPhysicsWorld()->rayTest(pos, to_pos, rayCallback);
|
||||
|
||||
if(!rayCallback.hasHit())
|
||||
{
|
||||
*material = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
*hit_point = rayCallback.m_hitPointWorld;
|
||||
*normal = rayCallback.m_hitNormalWorld;
|
||||
*material = rayCallback.m_material;
|
||||
// Note: material might be NULL. This happens if the ray cast does not
|
||||
// hit the track, but another rigid body (kart, moving_physics) - e.g.
|
||||
// assume two karts falling down, one over the other. Bullet does not
|
||||
// have any triangle/material information in this case!
|
||||
} // getTerrainInfo
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Simplified version to determine only the height of the terrain.
|
||||
* \param pos Position at which to determine the height (x,y coordinates
|
||||
@ -1193,6 +1133,7 @@ float Track::getTerrainHeight(const Vec3 &pos) const
|
||||
Vec3 hit_point;
|
||||
Vec3 normal;
|
||||
const Material *m;
|
||||
getTerrainInfo(pos, &hit_point, &normal, &m);
|
||||
Vec3 to=pos+Vec3(0,-10000,0);
|
||||
m_track_mesh->castRay(pos, to, &hit_point, &m, &normal);
|
||||
return hit_point.getY();
|
||||
} // getTerrainHeight
|
||||
|
@ -235,10 +235,6 @@ public:
|
||||
|
||||
/** Starts the music for this track. */
|
||||
void startMusic () const;
|
||||
|
||||
void getTerrainInfo(const Vec3 &pos, Vec3 *hit_point,
|
||||
Vec3* normal,
|
||||
const Material **material) const;
|
||||
float getTerrainHeight(const Vec3 &pos) const;
|
||||
void createPhysicsModel(unsigned int main_track_count);
|
||||
void update(float dt);
|
||||
|
Loading…
x
Reference in New Issue
Block a user