Files
watrbx-game-engine/App/v8world/Ball.cpp
T
2025-09-18 17:55:52 -04:00

480 lines
8.4 KiB
C++

#include "stdafx.h"
#include "V8World/Ball.h"
#include "G3D/CollisionDetection.h"
#include "G3D/Sphere.h"
#include "Util/Units.h"
#include "Util/Math.h"
namespace RBX {
Matrix3 Ball::getMomentSolid(float mass) const
{
float c = mass * (2.0f/5.0f) * realRadius * realRadius;
return Math::fromDiagonal(Vector3(c, c, c));
}
float Ball::getVolume() const
{
// sphere volume == 4/3 * pi * r^3
return 1.33333333f * Math::pif() * realRadius * realRadius * realRadius;
}
bool Ball::hitTest(const RbxRay& rayInMe, Vector3& localHitPoint, Vector3& surfaceNormal)
{
bool hit = (G3D::CollisionDetection::collisionTimeForMovingPointFixedSphere(
rayInMe.origin(),
rayInMe.direction(),
G3D::Sphere(Vector3::zero(), realRadius),
localHitPoint,
surfaceNormal)
!= G3D::inf() );
return hit;
}
void Ball::setSize(const G3D::Vector3& _size)
{
Super::setSize(_size);
RBXASSERT(getSize() == _size);
realRadius = _size.x * 0.5f;
if (bulletCollisionObject)
updateBulletCollisionData();
}
size_t Ball::closestSurfaceToPoint( const Vector3& pointInBody ) const
{
float maxDotProd = pointInBody.x;
size_t id = 0;
if( pointInBody.y > maxDotProd )
{
maxDotProd = pointInBody.y;
id = 1;
}
if( pointInBody.z > maxDotProd )
{
maxDotProd = pointInBody.z;
id = 2;
}
if( -pointInBody.x > maxDotProd )
{
maxDotProd = -pointInBody.x;
id = 3;
}
if( -pointInBody.y > maxDotProd )
{
maxDotProd = -pointInBody.y;
id = 4;
}
if( -pointInBody.z > maxDotProd )
{
maxDotProd = -pointInBody.z;
id = 5;
}
return id;
}
Plane Ball::getPlaneFromSurface( const size_t surfaceId ) const
{
switch(surfaceId)
{
case 0:
default:
{
Vector3 normal(1.0f, 0.0f, 0.0f);
Plane aPlane(normal, realRadius);
return aPlane;
}
case 1:
{
Vector3 normal(0.0f, 1.0f, 0.0f);
Plane aPlane(normal, realRadius);
return aPlane;
}
case 2:
{
Vector3 normal(0.0f, 0.0f, 1.0f);
Plane aPlane(normal, realRadius);
return aPlane;
}
case 3:
{
Vector3 normal(-1.0f, 0.0f, 0.0f);
Plane aPlane(normal, realRadius);
return aPlane;
}
case 4:
{
Vector3 normal(0.0f, -1.0f, 0.0f);
Plane aPlane(normal, realRadius);
return aPlane;
}
case 5:
{
Vector3 normal(0.0f, 0.0f, -1.0f);
Plane aPlane(normal, realRadius);
return aPlane;
}
}
}
Vector3 Ball::getSurfaceNormalInBody( const size_t surfaceId ) const
{
switch(surfaceId)
{
case 0:
default:
{
Vector3 normal(1.0f, 0.0f, 0.0f);
return normal;
}
case 1:
{
Vector3 normal(0.0f, 1.0f, 0.0f);
return normal;
}
case 2:
{
Vector3 normal(0.0f, 0.0f, 1.0f);
return normal;
}
case 3:
{
Vector3 normal(-1.0f, 0.0f, 0.0f);
return normal;
}
case 4:
{
Vector3 normal(0.0f, -1.0f, 0.0f);
return normal;
}
case 5:
{
Vector3 normal(0.0f, 0.0f, -1.0f);
return normal;
}
}
}
Vector3 Ball::getSurfaceVertInBody( const size_t surfaceId, const int vertId ) const
{
float x, y, z;
switch(surfaceId)
{
case 0:
default:
{
switch(vertId)
{
case 0:
default:
{
x = realRadius; y = -realRadius; z = realRadius;
break;
}
case 1:
{
x = realRadius; y = -realRadius; z = -realRadius;
break;
}
case 2:
{
x = realRadius; y = realRadius; z = realRadius;
break;
}
case 3:
{
x = realRadius; y = realRadius; z = -realRadius;
break;
}
}
Vector3 virtualVertex(x, y, z);
return virtualVertex;
}
case 1:
{
switch(vertId)
{
case 0:
default:
{
x = realRadius; y = realRadius; z = -realRadius;
break;
}
case 1:
{
x = -realRadius; y = realRadius; z = -realRadius;
break;
}
case 2:
{
x = -realRadius; y = realRadius; z = realRadius;
break;
}
case 3:
{
x = realRadius; y = realRadius; z = realRadius;
break;
}
}
Vector3 virtualVertex(x, y, z);
return virtualVertex;
}
case 2:
{
switch(vertId)
{
case 0:
default:
{
x = -realRadius; y = realRadius; z = realRadius;
break;
}
case 1:
{
x = -realRadius; y = -realRadius; z = realRadius;
break;
}
case 2:
{
x = realRadius; y = -realRadius; z = realRadius;
break;
}
case 3:
{
x = realRadius; y = realRadius; z = realRadius;
break;
}
}
Vector3 virtualVertex(x, y, z);
return virtualVertex;
}
case 3:
{
switch(vertId)
{
case 0:
default:
{
x = -realRadius; y = realRadius; z = -realRadius;
break;
}
case 1:
{
x = -realRadius; y = -realRadius; z = -realRadius;
break;
}
case 2:
{
x = -realRadius; y = -realRadius; z = realRadius;
break;
}
case 3:
{
x = -realRadius; y = realRadius; z = realRadius;
break;
}
}
Vector3 virtualVertex(x, y, z);
return virtualVertex;
}
case 4:
{
switch(vertId)
{
case 0:
default:
{
x = -realRadius; y = -realRadius; z = realRadius;
break;
}
case 1:
{
x = -realRadius; y = -realRadius; z = -realRadius;
break;
}
case 2:
{
x = realRadius; y = -realRadius; z = -realRadius;
break;
}
case 3:
{
x = realRadius; y = -realRadius; z = realRadius;
break;
}
}
Vector3 virtualVertex(x, y, z);
return virtualVertex;
}
case 5:
{
switch(vertId)
{
case 0:
default:
{
x = realRadius; y = -realRadius; z = -realRadius;
break;
}
case 1:
{
x = -realRadius; y = -realRadius; z = -realRadius;
break;
}
case 2:
{
x = -realRadius; y = -realRadius; z = realRadius;
break;
}
case 3:
{
x = realRadius; y = -realRadius; z = realRadius;
break;
}
}
Vector3 virtualVertex(x, y, z);
return virtualVertex;
}
}
}
size_t Ball::getMostAlignedSurface( const Vector3& vecInWorld, const G3D::Matrix3& objectR ) const
{
size_t id = 0;
Vector3 pointInBody = objectR.transpose() * vecInWorld;
float maxDotProd = pointInBody.x;
if( pointInBody.y > maxDotProd )
{
maxDotProd = pointInBody.y;
id = 1;
}
if( pointInBody.z > maxDotProd )
{
maxDotProd = pointInBody.z;
id = 2;
}
if( -pointInBody.x > maxDotProd )
{
maxDotProd = -pointInBody.x;
id = 3;
}
if( -pointInBody.y > maxDotProd )
{
maxDotProd = -pointInBody.y;
id = 4;
}
if( -pointInBody.z > maxDotProd )
{
maxDotProd = -pointInBody.z;
id = 5;
}
return id;
}
int Ball::getNumVertsInSurface( const size_t surfaceId ) const
{
return 4;
}
bool Ball::vertOverlapsFace( const Vector3& pointInBody, const size_t surfaceId ) const
{
switch(surfaceId)
{
case 0:
case 3:
default:
{
if( fabs(pointInBody.y) < realRadius && fabs(pointInBody.z) < realRadius )
return true;
}
case 1:
case 4:
{
if( fabs(pointInBody.x) < realRadius && fabs(pointInBody.z) < realRadius )
return true;
}
case 2:
case 5:
{
if( fabs(pointInBody.x) < realRadius && fabs(pointInBody.y) < realRadius )
return true;
}
}
return false;
}
CoordinateFrame Ball::getSurfaceCoordInBody( const size_t surfaceId ) const
{
// This computes the CS for the specified surface. It is expressed in terms of the body, not world.
// The surface centroid is the origin and the frame is aligned with the surface normal (for z). The y axis of
// this frame is the projection of either the body's y or z axis, depending on which one has a more predominant projection.
CoordinateFrame aCS;
// Compute and set centroid
Vector3 faceCentroid(0.0f, 0.0f, 0.0f);
switch(surfaceId)
{
case 0:
default:
faceCentroid.x = realRadius;
break;
case 1:
faceCentroid.y = realRadius;
break;
case 2:
faceCentroid.z = realRadius;
break;
case 3:
faceCentroid.x = -realRadius;
break;
case 4:
faceCentroid.y = -realRadius;
break;
case 5:
faceCentroid.z = -realRadius;
break;
}
aCS.translation = faceCentroid;
aCS.rotation = Math::getWellFormedRotForZVector(getSurfaceNormalInBody(surfaceId));
return aCS;
}
bool Ball::setUpBulletCollisionData(void)
{
if (!bulletCollisionObject)
updateBulletCollisionData();
return true;
}
void Ball::updateBulletCollisionData()
{
if (!bulletCollisionObject)
bulletCollisionObject.reset(new btCollisionObject());
bulletSphereShape = BulletSphereShapePool::getToken(getSize().x);
bulletCollisionObject->setCollisionShape(const_cast<btSphereShape*>(bulletSphereShape->getShape()));
}
} // namespace RBX