generate contact when body type changes at runtime, decoupling, add first ray cast hit query to world query (more to add later such as sphere/box/convex casts), hotfix
This commit is contained in:
@ -335,6 +335,41 @@ bool b3Body::ShouldCollide(const b3Body* other) const
|
||||
return true;
|
||||
}
|
||||
|
||||
void b3Body::SetType(b3BodyType type)
|
||||
{
|
||||
if (m_type == type)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_type = type;
|
||||
|
||||
ResetMass();
|
||||
|
||||
m_force.SetZero();
|
||||
m_torque.SetZero();
|
||||
|
||||
if (m_type == e_staticBody)
|
||||
{
|
||||
m_linearVelocity.SetZero();
|
||||
m_angularVelocity.SetZero();
|
||||
m_sweep.worldCenter0 = m_sweep.worldCenter;
|
||||
m_sweep.orientation0 = m_sweep.orientation;
|
||||
SynchronizeShapes();
|
||||
}
|
||||
|
||||
SetAwake(true);
|
||||
|
||||
DestroyContacts();
|
||||
|
||||
// Move the shape proxies so new contacts can be created.
|
||||
b3BroadPhase* phase = &m_world->m_contactMan.m_broadPhase;
|
||||
for (b3Shape* s = m_shapeList.m_head; s; s = s->m_next)
|
||||
{
|
||||
phase->BufferMove(s->m_broadPhaseID);
|
||||
}
|
||||
}
|
||||
|
||||
void b3Body::Dump() const
|
||||
{
|
||||
i32 bodyIndex = m_islandID;
|
||||
|
@ -79,7 +79,7 @@ void b3CollideCapsuleAndCapsule(b3Manifold& manifold,
|
||||
float32 d1 = b3Distance(clipEdgeA[0].position, cp1);
|
||||
float32 d2 = b3Distance(clipEdgeA[1].position, cp2);
|
||||
|
||||
if (d1 <= totalRadius && d2 <= totalRadius)
|
||||
if (d1 > B3_EPSILON && d1 <= totalRadius && d2 > B3_EPSILON && d2 <= totalRadius)
|
||||
{
|
||||
b3Vec3 n1 = (cp1 - clipEdgeA[0].position) / d1;
|
||||
b3Vec3 n2 = (cp2 - clipEdgeA[1].position) / d2;
|
||||
@ -123,7 +123,7 @@ void b3CollideCapsuleAndCapsule(b3Manifold& manifold,
|
||||
|
||||
float32 distance = b3Distance(pointA, pointB);
|
||||
|
||||
if (distance > 0.0f)
|
||||
if (distance > B3_EPSILON)
|
||||
{
|
||||
b3Vec3 normal = (pointB - pointA) / distance;
|
||||
b3Vec3 center = 0.5f * (pointA + hullA.radius * normal + pointB - hullB.radius * normal);
|
||||
|
@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
#include <bounce/dynamics/shapes/capsule_shape.h>
|
||||
#include <bounce/dynamics/time_step.h>
|
||||
|
||||
b3CapsuleShape::b3CapsuleShape()
|
||||
{
|
||||
|
@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
#include <bounce/dynamics/shapes/sphere_shape.h>
|
||||
#include <bounce/dynamics/time_step.h>
|
||||
|
||||
b3SphereShape::b3SphereShape()
|
||||
{
|
||||
|
@ -377,6 +377,68 @@ void b3World::RayCast(b3RayCastListener* listener, const b3Vec3& p1, const b3Vec
|
||||
m_contactMan.m_broadPhase.RayCast(&callback, input);
|
||||
}
|
||||
|
||||
struct b3RayCastFirstCallback
|
||||
{
|
||||
float32 Report(const b3RayCastInput& input, i32 proxyId)
|
||||
{
|
||||
// Get shape associated with the proxy.
|
||||
void* userData = broadPhase->GetUserData(proxyId);
|
||||
b3Shape* shape = (b3Shape*)userData;
|
||||
|
||||
// Get map from shape local space to world space.
|
||||
b3Transform xf = shape->GetBody()->GetTransform();
|
||||
|
||||
b3RayCastOutput output;
|
||||
bool hit = shape->RayCast(&output, input, xf);
|
||||
if (hit)
|
||||
{
|
||||
// Track minimum time of impact to require less memory.
|
||||
if (output.fraction < output0.fraction)
|
||||
{
|
||||
shape0 = shape;
|
||||
output0 = output;
|
||||
}
|
||||
}
|
||||
|
||||
// Continue the search from where we stopped.
|
||||
return input.maxFraction;
|
||||
}
|
||||
|
||||
b3Shape* shape0;
|
||||
b3RayCastOutput output0;
|
||||
const b3BroadPhase* broadPhase;
|
||||
};
|
||||
|
||||
void b3World::RayCastFirst(b3RayCastListener* listener, const b3Vec3& p1, const b3Vec3& p2) const
|
||||
{
|
||||
b3RayCastInput input;
|
||||
input.p1 = p1;
|
||||
input.p2 = p2;
|
||||
input.maxFraction = 1.0f;
|
||||
|
||||
b3RayCastFirstCallback callback;
|
||||
callback.shape0 = NULL;
|
||||
callback.output0.fraction = B3_MAX_FLOAT;
|
||||
callback.broadPhase = &m_contactMan.m_broadPhase;
|
||||
|
||||
// Perform the ray cast.
|
||||
m_contactMan.m_broadPhase.RayCast(&callback, input);
|
||||
|
||||
if (callback.shape0)
|
||||
{
|
||||
// Ray hits closest shape.
|
||||
float32 fraction = callback.output0.fraction;
|
||||
float32 w1 = 1.0f - fraction;
|
||||
float32 w2 = fraction;
|
||||
|
||||
b3Vec3 point = w1 * input.p1 + w2 * input.p2;
|
||||
b3Vec3 normal = callback.output0.normal;
|
||||
|
||||
// Report the intersection to the user.
|
||||
listener->ReportShape(callback.shape0, point, normal, fraction);
|
||||
}
|
||||
}
|
||||
|
||||
struct b3QueryAABBCallback
|
||||
{
|
||||
bool Report(i32 proxyID)
|
||||
|
@ -25,6 +25,7 @@
|
||||
GLFWwindow* g_window;
|
||||
Settings g_settings;
|
||||
Test* g_test;
|
||||
u32 g_testCount;
|
||||
Camera g_camera;
|
||||
DebugDraw* g_debugDraw;
|
||||
bool g_leftDown;
|
||||
@ -234,7 +235,7 @@ void Interface()
|
||||
ImGui::PushItemWidth(-1.0f);
|
||||
|
||||
ImGui::Text("Test");
|
||||
if (ImGui::Combo("##Test", &g_settings.testID, GetTestName, NULL, e_testCount, e_testCount))
|
||||
if (ImGui::Combo("##Test", &g_settings.testID, GetTestName, NULL, g_testCount, g_testCount))
|
||||
{
|
||||
delete g_test;
|
||||
g_test = g_tests[g_settings.testID].create();
|
||||
@ -248,12 +249,12 @@ void Interface()
|
||||
}
|
||||
if (ImGui::Button("Previous", buttonSize))
|
||||
{
|
||||
g_settings.testID = b3Clamp(g_settings.testID - 1, 0, int(e_testCount) - 1);
|
||||
g_settings.testID = b3Clamp(g_settings.testID - 1, 0, int(g_testCount) - 1);
|
||||
g_settings.lastTestID = -1;
|
||||
}
|
||||
if (ImGui::Button("Next", buttonSize))
|
||||
{
|
||||
g_settings.testID = b3Clamp(g_settings.testID + 1, 0, int(e_testCount) - 1);
|
||||
g_settings.testID = b3Clamp(g_settings.testID + 1, 0, int(g_testCount) - 1);
|
||||
g_settings.lastTestID = -1;
|
||||
}
|
||||
if (ImGui::Button("Exit", buttonSize))
|
||||
@ -419,12 +420,12 @@ int main(int argc, char** args)
|
||||
sprintf(title, "Bounce Testbed Version %d.%d.%d", b3_version.major, b3_version.minor, b3_version.revision);
|
||||
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
||||
|
||||
g_window = glfwCreateWindow(1024, 768, title, NULL, NULL);
|
||||
if (g_window == NULL)
|
||||
{
|
||||
fprintf(stderr, "Failed to opengl GLFW window\n");
|
||||
fprintf(stderr, "Failed to open GLFW window\n");
|
||||
glfwTerminate();
|
||||
return -1;
|
||||
}
|
||||
@ -436,11 +437,13 @@ int main(int argc, char** args)
|
||||
glfwSetKeyCallback(g_window, KeyButton);
|
||||
glfwSetCharCallback(g_window, Char);
|
||||
glfwSwapInterval(1);
|
||||
|
||||
if (gladLoadGL() == 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to load OpenGL extensions\n");
|
||||
fprintf(stderr, "Error: %d\n", glad_glGetError());
|
||||
glfwTerminate();
|
||||
exit(EXIT_FAILURE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("OpenGL %s, GLSL %s\n", glGetString(GL_VERSION), glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||
@ -457,7 +460,13 @@ int main(int argc, char** args)
|
||||
g_debugDraw = new DebugDraw();
|
||||
|
||||
// Run the testbed
|
||||
g_testCount = 0;
|
||||
while (g_tests[g_testCount].create != NULL)
|
||||
{
|
||||
++g_testCount;
|
||||
}
|
||||
g_test = NULL;
|
||||
|
||||
Run();
|
||||
|
||||
// Destroy the last test
|
||||
@ -475,4 +484,5 @@ int main(int argc, char** args)
|
||||
|
||||
// Destroy g_window
|
||||
glfwTerminate();
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -49,7 +49,7 @@ Test::Test()
|
||||
g_camera.m_center.SetZero();
|
||||
g_settings.drawGrid = false;
|
||||
|
||||
m_rayHit.m_shape = NULL;
|
||||
m_rayHit.shape = NULL;
|
||||
m_mouseJoint = NULL;
|
||||
|
||||
{
|
||||
@ -358,7 +358,7 @@ void Test::MouseMove(const Ray3& pw)
|
||||
{
|
||||
if (m_mouseJoint)
|
||||
{
|
||||
float32 hitFraction = m_rayHit.m_fraction;
|
||||
float32 hitFraction = m_rayHit.fraction;
|
||||
float32 w1 = 1.0f - hitFraction;
|
||||
float32 w2 = hitFraction;
|
||||
|
||||
@ -370,7 +370,7 @@ void Test::MouseMove(const Ray3& pw)
|
||||
void Test::MouseLeftDown(const Ray3& pw)
|
||||
{
|
||||
// Clear the current hit
|
||||
m_rayHit.m_shape = NULL;
|
||||
m_rayHit.shape = NULL;
|
||||
if (m_mouseJoint)
|
||||
{
|
||||
b3Body* groundBody = m_mouseJoint->GetBodyA();
|
||||
@ -384,25 +384,23 @@ void Test::MouseLeftDown(const Ray3& pw)
|
||||
b3Vec3 p1 = pw.Start();
|
||||
b3Vec3 p2 = pw.End();
|
||||
|
||||
// Perform the ray cast
|
||||
RayCastListener listener;
|
||||
m_world.RayCast(&listener, p1, p2);
|
||||
listener.hit.shape = NULL;
|
||||
|
||||
int hitId = listener.FindClosestHit();
|
||||
// Perform the ray cast
|
||||
m_world.RayCastFirst(&listener, p1, p2);
|
||||
|
||||
if (hitId >= 0)
|
||||
if (listener.hit.shape)
|
||||
{
|
||||
// Hit
|
||||
// Replace current hit
|
||||
m_rayHit = listener.m_hits[hitId];
|
||||
|
||||
m_rayHit = listener.hit;
|
||||
|
||||
RayHit();
|
||||
}
|
||||
}
|
||||
|
||||
void Test::MouseLeftUp(const Ray3& pw)
|
||||
{
|
||||
m_rayHit.m_shape = NULL;
|
||||
m_rayHit.shape = NULL;
|
||||
if (m_mouseJoint)
|
||||
{
|
||||
b3Body* groundBody = m_mouseJoint->GetBodyA();
|
||||
@ -418,12 +416,12 @@ void Test::RayHit()
|
||||
{
|
||||
b3BodyDef bdef;
|
||||
b3Body* bodyA = m_world.CreateBody(bdef);
|
||||
b3Body* bodyB = m_rayHit.m_shape->GetBody();
|
||||
b3Body* bodyB = m_rayHit.shape->GetBody();
|
||||
|
||||
b3MouseJointDef def;
|
||||
def.bodyA = bodyA;
|
||||
def.bodyB = bodyB;
|
||||
def.target = m_rayHit.m_point;
|
||||
def.target = m_rayHit.point;
|
||||
def.maxForce = 2000.0f * bodyB->GetMass();
|
||||
|
||||
m_mouseJoint = (b3MouseJoint*)m_world.CreateJoint(def);
|
||||
|
@ -47,7 +47,7 @@
|
||||
#include <testbed/tests/varying_friction.h>
|
||||
#include <testbed/tests/varying_restitution.h>
|
||||
|
||||
TestEntry g_tests[e_testCount] =
|
||||
TestEntry g_tests[] =
|
||||
{
|
||||
{ "Quickhull Test", &QuickhullTest::Create },
|
||||
{ "Cluster Test", &Cluster::Create },
|
||||
|
Reference in New Issue
Block a user