That said, here's what happened:
I noticed than when creating sphere objects(not polygonal , but created by bullet, which i think uses an analytic representation) and raycasting them, i receive normals that don't seem to be precise. More precisely, while lighting the sphere i get banding artifacts. Here's a screenshot of the issue:

At first, i turned the floating point precision to fp:precise and compiled bullet(2.78 version) with double precision. This did not really help and i thought i try this, after the raycast:
normalCollision = normalize(sphereHitCenter - hitPointReturnedByRaycast);
This did the trick and i got the results i was expecting:

My first question is: why do i need to calculate the normal myself for the sphere? Are there any switches that calculate a better normal for the sphere being hit by the ray? Also, here's the code i'm using for the raycast:
Code: Select all
collisionInfo rayTest(const Endeavour::Math::Vector3f rayFrom, const Endeavour::Math::Vector3f rayTo)
{
struct AllRayResultCallback : public btCollisionWorld::RayResultCallback
{
AllRayResultCallback(const btVector3& rayFromWorld,const btVector3& rayToWorld)
:m_rayFromWorld(rayFromWorld),
m_rayToWorld(rayToWorld)
{
}
btVector3 m_rayFromWorld;//used to calculate hitPointWorld from hitFraction
btVector3 m_rayToWorld;
btVector3 m_hitNormalWorld;
btVector3 m_hitPointWorld;
virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace)
{
//caller already does the filter on the m_closestHitFraction
btAssert(rayResult.m_hitFraction <= m_closestHitFraction);
m_closestHitFraction = rayResult.m_hitFraction;
m_collisionObject = rayResult.m_collisionObject;
if (normalInWorldSpace)
{
m_hitNormalWorld = rayResult.m_hitNormalLocal;
} else
{
///need to transform normal into worldspace
m_hitNormalWorld = m_collisionObject->getWorldTransform().getBasis()*rayResult.m_hitNormalLocal;
}
m_hitPointWorld.setInterpolate3(m_rayFromWorld,m_rayToWorld,rayResult.m_hitFraction);
return 1.f;
}
};
collisionInfo cInfo;
cInfo.collisionOccured = false;
cInfo.userData = NULL;
btVector3 btRayFrom = btVector3(rayFrom.x, rayFrom.y, rayFrom.z);
btVector3 btRayTo = btVector3(rayTo.x, rayTo.y, rayTo.z);
AllRayResultCallback resultCallback(btRayFrom,btRayTo);
dynamicsWorld->rayTest(btRayFrom,btRayTo,resultCallback);
if (resultCallback.hasHit())
{
btVector3 worldNormal = resultCallback.m_hitNormalWorld;
btVector3 worldPosition = resultCallback.m_hitPointWorld;
cInfo.collisionOccured = true;
cInfo.position = Endeavour::Math::Vector3f(worldPosition.x(), worldPosition.y(), worldPosition.z());
cInfo.normal = Endeavour::Math::Vector3f(worldNormal.x(), worldNormal.y(), worldNormal.z());
cInfo.userData = resultCallback.m_collisionObject->getUserPointer();
return cInfo;
}
return cInfo;
}
Code: Select all
btDefaultCollisionConfiguration* collisionConfiguration;
btCollisionDispatcher* dispatcher;
btBroadphaseInterface* overlappingPairCache;
btSequentialImpulseConstraintSolver* solver;
btDynamicsWorld* dynamicsWorld;
void init()
{
collisionConfiguration = new btDefaultCollisionConfiguration();
dispatcher = new btCollisionDispatcher(collisionConfiguration);
btVector3 worldAabbMin(-5000,-5000,-5000);
btVector3 worldAabbMax(5000,5000,5000);
overlappingPairCache = new bt32BitAxisSweep3(worldAabbMin,worldAabbMax);
solver = new btSequentialImpulseConstraintSolver;
dynamicsWorld = new btContinuousDynamicsWorld(dispatcher, overlappingPairCache, solver, collisionConfiguration);
dynamicsWorld->setDebugDrawer(NULL);
dynamicsWorld->setWorldUserInfo(NULL);
dynamicsWorld->setInternalTickCallback(NULL);
}
EDIT:
I corrected the bullet version that i'm using: it's 2.78.