From 95a7e5c1250718fb0ba51e48fc0c766463e2837f Mon Sep 17 00:00:00 2001 From: hikerstk Date: Thu, 3 Feb 2011 21:06:50 +0000 Subject: [PATCH] Added smoothing of normals for raycast wheels, but disabled for now (since the normals of some tracks need to be fixed). git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@7600 178a84e3-b1eb-0310-8ba1-8eac791a3b58 --- src/Makefile.am | 2 + src/config/stk_config.cpp | 6 +++ src/config/stk_config.hpp | 2 + src/ide/vc9/supertuxkart.vcproj | 8 +++ src/karts/kart.cpp | 3 +- src/physics/btKartRaycast.cpp | 95 +++++++++++++++++++++++++++++++++ src/physics/btKartRaycast.hpp | 39 ++++++++++++++ src/physics/triangle_mesh.cpp | 62 ++++++++++++++++++++- src/physics/triangle_mesh.hpp | 36 ++++++++++++- src/tracks/track.cpp | 6 ++- src/tracks/track.hpp | 52 +++++++++++------- 11 files changed, 287 insertions(+), 24 deletions(-) create mode 100644 src/physics/btKartRaycast.cpp create mode 100644 src/physics/btKartRaycast.hpp diff --git a/src/Makefile.am b/src/Makefile.am index 0c19d4ee6..4db970ff2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -250,6 +250,8 @@ supertuxkart_SOURCES = \ network/world_loaded_message.hpp \ physics/btKart.cpp \ physics/btKart.hpp \ + physics/btKartRaycast.cpp \ + phsycis/btKartRaycast.hpp \ physics/btUprightConstraint.cpp \ physics/btUprightConstraint.hpp \ physics/irr_debug_drawer.cpp \ diff --git a/src/config/stk_config.cpp b/src/config/stk_config.cpp index 71923cae6..406eddcd8 100644 --- a/src/config/stk_config.cpp +++ b/src/config/stk_config.cpp @@ -158,6 +158,7 @@ void STKConfig::init_defaults() m_max_track_version = -100; m_title_music = NULL; m_enable_networking = true; + m_smooth_normals = false; m_same_powerup_mode = POWERUP_MODE_ONLY_IF_SAME; m_score_increase.clear(); m_leader_intervals.clear(); @@ -222,6 +223,11 @@ void STKConfig::getAllData(const XMLNode * root) leader_node->get("time-per-kart", &m_leader_time_per_kart); } + if (const XMLNode *physics_node= root->getNode("physics")) + { + physics_node->get("smooth-normals", &m_smooth_normals ); + } + if (const XMLNode *startup_node= root->getNode("startup")) { startup_node->get("penalty", &m_penalty_time ); diff --git a/src/config/stk_config.hpp b/src/config/stk_config.hpp index 12d0605be..749471da5 100644 --- a/src/config/stk_config.hpp +++ b/src/config/stk_config.hpp @@ -83,6 +83,8 @@ public: or reverse point order. */ int m_max_history; /** + + @@ -1520,6 +1524,10 @@ RelativePath="..\..\physics\btKart.hpp" > + + diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index 4c846412c..2e348a977 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -46,6 +46,7 @@ #include "network/race_state.hpp" #include "network/network_manager.hpp" #include "physics/btKart.hpp" +#include "physics/btKartRaycast.hpp" #include "physics/btUprightConstraint.hpp" #include "physics/physics.hpp" #include "race/history.hpp" @@ -231,7 +232,7 @@ void Kart::createPhysics() // Create the actual vehicle // ------------------------- m_vehicle_raycaster = - new btDefaultVehicleRaycaster(World::getWorld()->getPhysics()->getPhysicsWorld()); + new btKartRaycaster(World::getWorld()->getPhysics()->getPhysicsWorld()); m_tuning = new btKart::btVehicleTuning(); m_tuning->m_maxSuspensionTravelCm = m_kart_properties->getSuspensionTravelCM(); m_vehicle = new btKart(*m_tuning, m_body, m_vehicle_raycaster, diff --git a/src/physics/btKartRaycast.cpp b/src/physics/btKartRaycast.cpp new file mode 100644 index 000000000..13107ddab --- /dev/null +++ b/src/physics/btKartRaycast.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2005 Erwin Coumans http://continuousphysics.com/Bullet/ + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies. + * Erwin Coumans makes no representations about the suitability + * of this software for any purpose. + * It is provided "as is" without express or implied warranty. +*/ + +#include "LinearMath/btVector3.h" +#include "btKartRaycast.hpp" + +#include "BulletCollision/CollisionDispatch/btCollisionWorld.h" +#include "BulletDynamics/Dynamics/btDynamicsWorld.h" + +#include "modes/world.hpp" +#include "physics/triangle_mesh.hpp" +#include "tracks/track.hpp" + +void* btKartRaycaster::castRay(const btVector3& from, const btVector3& to, + btVehicleRaycasterResult& result) +{ + // ======================================================================== + class ClosestWithNormal : public btCollisionWorld::ClosestRayResultCallback + { + private: + int m_triangle_index; + public: + /** Constructor, initialises the triangle index. */ + ClosestWithNormal(const btVector3 &from, + const btVector3 &to) + : btCollisionWorld::ClosestRayResultCallback(from,to) + { + m_triangle_index = -1; + } // CloestWithNormal + // -------------------------------------------------------------------- + /** Stores the index of the triangle hit. */ + virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, + bool normalInWorldSpace) + { + // We don't always get a triangle index, sometimes (e.g. ray hits + // other kart) we get shapePart=-1, or no localShapeInfo at all + if(rayResult.m_localShapeInfo && + rayResult.m_localShapeInfo->m_shapePart>-1) + m_triangle_index = rayResult.m_localShapeInfo->m_triangleIndex; + return + btCollisionWorld::ClosestRayResultCallback::addSingleResult(rayResult, + normalInWorldSpace); + } + // -------------------------------------------------------------------- + /** Returns the index of the triangle which was hit, or -1 if + * no triangle was hit. */ + int getTriangleIndex() const { return m_triangle_index; } + + }; // CloestWithNormal + // ======================================================================== + + ClosestWithNormal rayCallback(from,to); + + m_dynamicsWorld->rayTest(from, to, rayCallback); + + if (rayCallback.hasHit()) + { + btRigidBody* body = btRigidBody::upcast(rayCallback.m_collisionObject); + if (body && body->hasContactResponse()) + { + result.m_hitPointInWorld = rayCallback.m_hitPointWorld; + result.m_hitNormalInWorld = rayCallback.m_hitNormalWorld; + result.m_hitNormalInWorld.normalize(); + result.m_distFraction = rayCallback.m_closestHitFraction; + const TriangleMesh &tm = + World::getWorld()->getTrack()->getTriangleMesh(); + if(stk_config->m_smooth_normals && + rayCallback.getTriangleIndex()>-1) + { + btVector3 n=result.m_hitNormalInWorld; + result.m_hitNormalInWorld = + tm.getInterpolatedNormal(rayCallback.getTriangleIndex(), + result.m_hitPointInWorld); +#ifdef DEBUG_NORMALS + printf("old %f %f %f new %f %f %f\n", + n.getX(), n.getY(), n.getZ(), + result.m_hitNormalInWorld.getX(), + result.m_hitNormalInWorld.getY(), + result.m_hitNormalInWorld.getZ()); +#endif + } + return body; + } + } + return 0; +} + diff --git a/src/physics/btKartRaycast.hpp b/src/physics/btKartRaycast.hpp new file mode 100644 index 000000000..dc6f3fdf4 --- /dev/null +++ b/src/physics/btKartRaycast.hpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2005 Erwin Coumans http://continuousphysics.com/Bullet/ + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies. + * Erwin Coumans makes no representations about the suitability + * of this software for any purpose. + * It is provided "as is" without express or implied warranty. +*/ +#ifndef BTKARTRAYCASTER_HPP +#define BTKARTRAYCSATER_HPP + +#include "BulletDynamics/Dynamics/btRigidBody.h" +#include "BulletDynamics/ConstraintSolver/btTypedConstraint.h" +#include "BulletDynamics/Vehicle/btVehicleRaycaster.h" +class btDynamicsWorld; +#include "LinearMath/btAlignedObjectArray.h" +#include "BulletDynamics/Vehicle/btWheelInfo.h" +#include "BulletDynamics/Dynamics/btActionInterface.h" + + +class btKartRaycaster : public btVehicleRaycaster +{ + btDynamicsWorld* m_dynamicsWorld; +public: + btKartRaycaster(btDynamicsWorld* world) + :m_dynamicsWorld(world) + { + } + + virtual void* castRay(const btVector3& from,const btVector3& to, + btVehicleRaycasterResult& result); + +}; + + +#endif //RAYCASTVEHICLE_H + diff --git a/src/physics/triangle_mesh.cpp b/src/physics/triangle_mesh.cpp index 360a9b16c..98b3b8629 100644 --- a/src/physics/triangle_mesh.cpp +++ b/src/physics/triangle_mesh.cpp @@ -46,10 +46,22 @@ TriangleMesh::~TriangleMesh() } // ~TriangleMesh // ----------------------------------------------------------------------------- +/** Adds a triangle to the bullet mesh. It also stores the material used for + * this triangle, and the three normals. + * \param t1,t2,t3 Points of the triangle. + * \param n1,n2,n3 Normals at the corresponding points. + * \param m Material used for this triangle + */ void TriangleMesh::addTriangle(const btVector3 &t1, const btVector3 &t2, - const btVector3 &t3, const Material* m) + const btVector3 &t3, + const btVector3 &n1, const btVector3 &n2, + const btVector3 &n3, + const Material* m) { m_triangleIndex2Material.push_back(m); + m_normals.push_back(n1); + m_normals.push_back(n2); + m_normals.push_back(n3); m_mesh.addTriangle(t1, t2, t3); } // addTriangle @@ -106,3 +118,51 @@ void TriangleMesh::removeBody() } // removeBody // ----------------------------------------------------------------------------- +/** Interpolates the normal at the given position for the triangle with + * a given index. The position must be inside of the given triangle. + * \param index Index of the triangle to use. + * \param position The position for which to interpolate the normal. + */ +btVector3 TriangleMesh::getInterpolatedNormal(unsigned int index, + const btVector3 &position) const +{ + btVector3 p1, p2, p3; + getTriangle(index, &p1, &p2, &p3); + btVector3 n1, n2, n3; + getNormals(index, &n1, &n2, &n3); + + // Compute the Barycentric coordinates of position inside triangle + // p1, p2, p3. + btVector3 edge1 = p2 - p1; + btVector3 edge2 = p3 - p1; + + // Area of triangle ABC + btScalar p1p2p3 = edge1.cross(edge2).length2(); + + // Area of BCP + btScalar p2p3p = (p3 - p2).cross(position - p2).length2(); + + // Area of CAP + btScalar p3p1p = edge2.cross(position - p3).length2(); + btScalar s = btSqrt(p2p3p / p1p2p3); + btScalar t = btSqrt(p3p1p / p1p2p3); + btScalar w = 1.0f - s - t; + +#ifdef NORMAL_DEBUGGING + btVector3 regen_position = s * p1 + t * p2 + w * p3; + + if((regen_position - position).length2() >= 0.0001f) + { + printf("bary:\n"); + printf("new: %f %f %f\n", regen_position.getX(),regen_position.getY(),regen_position.getZ()); + printf("old: %f %f %f\n", position.getX(), position.getY(),position.getZ()); + printf("stw: %f %f %f\n", s, t, w); + printf("p1: %f %f %f\n", p1.getX(),p1.getY(),p1.getZ()); + printf("p2: %f %f %f\n", p2.getX(),p2.getY(),p2.getZ()); + printf("p3: %f %f %f\n", p3.getX(),p3.getY(),p3.getZ()); + printf("pos: %f %f %f\n", position.getX(),position.getY(),position.getZ()); + } +#endif + + return s*n1 + t*n2 + w*n3; +} // getInterpolatedNormal diff --git a/src/physics/triangle_mesh.hpp b/src/physics/triangle_mesh.hpp index 44a5ad4d1..5fdec8f1e 100644 --- a/src/physics/triangle_mesh.hpp +++ b/src/physics/triangle_mesh.hpp @@ -24,6 +24,7 @@ #include "btBulletDynamicsCommon.h" #include "physics/user_pointer.hpp" +#include "utils/aligned_array.hpp" class Material; @@ -40,15 +41,46 @@ private: btTriangleMesh m_mesh; btDefaultMotionState *m_motion_state; btCollisionShape *m_collision_shape; + /** The three normals for each triangle. */ + AlignedArray m_normals; public: TriangleMesh(); ~TriangleMesh(); void addTriangle(const btVector3 &t1, const btVector3 &t2, - const btVector3 &t3, const Material* m); + const btVector3 &t3, const btVector3 &n1, + const btVector3 &n2, const btVector3 &n3, + const Material* m); void createBody(btCollisionObject::CollisionFlags flags= (btCollisionObject::CollisionFlags)0); void removeBody(); - const Material* getMaterial(int n) const {return m_triangleIndex2Material[n];} + btVector3 getInterpolatedNormal(unsigned int index, + const btVector3 &position) const; + // ------------------------------------------------------------------------ + const Material* getMaterial(int n) const + {return m_triangleIndex2Material[n];} + // ------------------------------------------------------------------------ + void getTriangle(unsigned int indx, btVector3 *p1, btVector3 *p2, + btVector3 *p3) const + { + const IndexedMeshArray &m = m_mesh.getIndexedMeshArray(); + btVector3 *p = &(((btVector3*)(m[0].m_vertexBase))[3*indx]); + *p1 = p[0]; + *p2 = p[1]; + *p3 = p[2]; + } // getTriangle + // ------------------------------------------------------------------------ + /** Returns the normals of the triangle with the given index. + * \param indx Index of the triangle to get the three normals of. + * \result n1,n2,n3 The three normals. */ + void getNormals(unsigned int indx, btVector3 *n1, btVector3 *n2, + btVector3 *n3) const + { + assert(indx < m_triangleIndex2Material.size()); + unsigned int n = indx*3; + *n1 = m_normals[n ]; + *n2 = m_normals[n+1]; + *n3 = m_normals[n+2]; + } // getNormals }; #endif /* EOF */ diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index 8bc5697cb..0f179d94c 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -439,6 +439,7 @@ void Track::convertTrackToBullet(scene::ISceneNode *node) u16 *mbIndices = mb->getIndices(); Vec3 vertices[3]; + Vec3 normals[3]; irr::video::S3DVertex* mbVertices=(video::S3DVertex*)mb->getVertices(); for(unsigned int j=0; jgetIndexCount(); j+=3) { for(unsigned int k=0; k<3; k++) { @@ -446,9 +447,12 @@ void Track::convertTrackToBullet(scene::ISceneNode *node) core::vector3df v = mbVertices[indx].Pos; mat.transformVect(v); vertices[k]=v; + normals[k]=mbVertices[indx].Normal; } // for k if(tmesh) tmesh->addTriangle(vertices[0], vertices[1], - vertices[2], material ); + vertices[2], normals[0], + normals[1], normals[2], + material ); } // for j } // for igetAngleToNext(n, 0); } + { return m_quad_graph->getAngleToNext(n, 0); } + // ------------------------------------------------------------------------ /** Returns the 2d coordinates of a point when drawn on the mini map * texture. * \param xyz Coordinates of the point to map. @@ -260,23 +268,29 @@ public: */ void mapPoint2MiniMap(const Vec3 &xyz, Vec3 *draw_at) const { m_quad_graph->mapPoint2MiniMap(xyz, draw_at); } + // ------------------------------------------------------------------------ /** Returns the full path of a given file inside this track directory. */ std::string getTrackFile(const std::string &s) const { return m_root+"/"+s; } + // ------------------------------------------------------------------------ /** Returns the number of modes available for this track. */ unsigned int getNumberOfModes() const { return m_all_modes.size(); } + // ------------------------------------------------------------------------ /** Returns the name of the i-th. mode. */ const std::string &getModeName(unsigned int i) const { return m_all_modes[i].m_name;} + // ------------------------------------------------------------------------ /** Returns the default ambient color. */ const video::SColor &getDefaultAmbientColor() const { return m_default_ambient_color;} - /** Sets the current ambient color for a kart with index k. */ - void setAmbientColor(const video::SColor &color, - unsigned int k); + // ------------------------------------------------------------------------ /** Returns the far value for cameras. */ float getCameraFar() const { return m_camera_far; } + // ------------------------------------------------------------------------ + /** Returns the triangle mesh for this track. */ + const TriangleMesh& getTriangleMesh() const {return *m_track_mesh; } + // ------------------------------------------------------------------------ /** Get the number of start positions defined in the scene file. */ unsigned int getNumberOfStartPositions() const { return m_start_transforms.size(); }