Raycast adjustments;

This commit is contained in:
bjorn 2024-04-26 00:52:28 -07:00
parent 115f2e24b2
commit 5f6880f8ef
5 changed files with 75 additions and 63 deletions

View File

@ -40,8 +40,7 @@ static int l_lovrColliderGetWorld(lua_State* L) {
static int l_lovrColliderGetShape(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
uint32_t child = lua_gettop(L) == 1 ? ~0u : luax_checku32(L, 2) - 1;
Shape* shape = lovrColliderGetShape(collider, child);
Shape* shape = lovrColliderGetShape(collider);
if (shape) {
luax_pushshape(L, shape);
} else {
@ -550,7 +549,7 @@ static int l_lovrColliderSetTag(lua_State* L) {
// Deprecated
static int l_lovrColliderGetShapes(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
Shape* shape = lovrColliderGetShape(collider, ~0u);
Shape* shape = lovrColliderGetShape(collider);
lua_createtable(L, 1, 0);
luax_pushshape(L, shape);
lua_rawseti(L, -2, 1);

View File

@ -6,28 +6,31 @@
#include <stdbool.h>
#include <string.h>
static void luax_pushcastresult(lua_State* L, CastResult* hit) {
static int luax_pushcastresult(lua_State* L, CastResult* hit) {
luax_pushtype(L, Collider, hit->collider);
luax_pushshape(L, hit->shape);
lua_pushnumber(L, hit->position[0]);
lua_pushnumber(L, hit->position[1]);
lua_pushnumber(L, hit->position[2]);
lua_pushnumber(L, hit->normal[0]);
lua_pushnumber(L, hit->normal[1]);
lua_pushnumber(L, hit->normal[2]);
lua_pushnumber(L, hit->fraction);
lua_pushinteger(L, hit->part);
return 9;
}
static float castCallback(void* userdata, CastResult* hit) {
lua_State* L = userdata;
lua_pushvalue(L, -1);
luax_pushcastresult(L, hit);
lua_call(L, 6, 1);
bool stop = lua_type(L, -1) == LUA_TBOOLEAN && !lua_toboolean(L, -1);
int n = luax_pushcastresult(L, hit);
lua_call(L, n, 1);
float fraction = lua_type(L, -1) == LUA_TNUMBER ? luax_tofloat(L, -1) : 1.f;
lua_pop(L, 1);
return stop ? 0.f : 1.f;
return fraction;
}
static float castClosestCallback(void* userdata, CastResult* hit) {
CastResult* closest = userdata;
*closest = *hit;
*((CastResult*) userdata) = *hit;
return hit->fraction;
}
@ -202,24 +205,20 @@ static int l_lovrWorldUpdate(lua_State* L) {
static int l_lovrWorldRaycast(lua_State* L) {
World* world = luax_checktype(L, 1, World);
int index = 2;
float start[3], end[3];
index = luax_readvec3(L, index, start, NULL);
index = luax_readvec3(L, index, end, NULL);
Raycast raycast;
index = luax_readvec3(L, index, raycast.start, NULL);
index = luax_readvec3(L, index, raycast.end, NULL);
if (lua_isnoneornil(L, index)) {
CastResult closest;
if (lovrWorldRaycast(world, start, end, castClosestCallback, &closest)) {
luax_pushcastresult(L, &closest);
return 6;
} else {
lua_pushnil(L);
return 1;
CastResult hit;
if (lovrWorldRaycast(world, &raycast, castClosestCallback, &hit)) {
return luax_pushcastresult(L, &hit);
}
} else {
luaL_checktype(L, index, LUA_TFUNCTION);
lua_settop(L, index);
lovrWorldRaycast(world, start, end, castCallback, L);
return 0;
lovrWorldRaycast(world, &raycast, castCallback, L);
}
return 0;
}
static int l_lovrWorldQueryBox(lua_State* L) {

View File

@ -42,11 +42,17 @@ typedef struct {
uint32_t tagCount;
} WorldInfo;
typedef struct {
float start[3];
float end[3];
} Raycast;
typedef struct {
Collider* collider;
Shape* shape;
float position[3];
float normal[3];
float fraction;
uint32_t part;
} CastResult;
typedef float CastCallback(void* userdata, CastResult* hit);
@ -60,7 +66,7 @@ uint32_t lovrWorldGetJointCount(World* world);
Collider* lovrWorldGetColliders(World* world, Collider* collider);
Joint* lovrWorldGetJoints(World* world, Joint* joint);
void lovrWorldUpdate(World* world, float dt);
bool lovrWorldRaycast(World* world, float start[3], float end[3], CastCallback* callback, void* userdata);
bool lovrWorldRaycast(World* world, Raycast* raycast, CastCallback* callback, void* userdata);
bool lovrWorldQueryBox(World* world, float position[3], float size[3], QueryCallback* callback, void* userdata);
bool lovrWorldQuerySphere(World* world, float position[3], float radius, QueryCallback* callback, void* userdata);
void lovrWorldGetGravity(World* world, float gravity[3]);
@ -94,7 +100,7 @@ bool lovrColliderIsEnabled(Collider* collider);
void lovrColliderSetEnabled(Collider* collider, bool enable);
World* lovrColliderGetWorld(Collider* collider);
Joint* lovrColliderGetJoints(Collider* collider, Joint* joint);
Shape* lovrColliderGetShape(Collider* collider, uint32_t child);
Shape* lovrColliderGetShape(Collider* collider);
void lovrColliderSetShape(Collider* collider, Shape* shape);
const char* lovrColliderGetTag(Collider* collider);
bool lovrColliderSetTag(Collider* collider, const char* tag);

View File

@ -52,7 +52,6 @@ struct Joint {
static struct {
bool initialized;
Shape* pointShape;
JPH_AllHit_CastShapeCollector* castShapeCollector;
} state;
// Broad phase and object phase layers
@ -78,11 +77,20 @@ static uint32_t findTag(World* world, const char* name) {
return UNTAGGED;
}
static Shape* subshapeToShape(Collider* collider, JPH_SubShapeID id) {
if (collider->shape->type == SHAPE_COMPOUND) {
JPH_SubShapeID remainder;
uint32_t index = JPH_CompoundShape_GetSubShapeIndexFromID((JPH_CompoundShape*) collider->shape->shape, id, &remainder);
return lovrCompoundShapeGetChild(collider->shape, index);
} else {
return collider->shape;
}
}
bool lovrPhysicsInit(void) {
if (state.initialized) return false;
JPH_Init(32 * 1024 * 1024);
state.pointShape = lovrSphereShapeCreate(FLT_EPSILON);
state.castShapeCollector = JPH_AllHit_CastShapeCollector_Create();
return state.initialized = true;
}
@ -179,38 +187,45 @@ void lovrWorldUpdate(World* world, float dt) {
typedef struct {
World* world;
float origin[3];
float direction[3];
Raycast* raycast;
CastCallback* callback;
void* userdata;
} CastInfo;
} RaycastContext;
static float raycastCallback(void* arg, JPH_RayCastResult* result) {
CastInfo* cast = arg;
RaycastContext* ctx = arg;
CastResult hit;
hit.collider = (Collider*) (uintptr_t) JPH_BodyInterface_GetUserData(cast->world->bodies, result->bodyID);
hit.position[0] = cast->origin[0] + cast->direction[0] * result->fraction;
hit.position[1] = cast->origin[1] + cast->direction[1] * result->fraction;
hit.position[2] = cast->origin[2] + cast->direction[2] * result->fraction;
Raycast* raycast = ctx->raycast;
hit.collider = (Collider*) (uintptr_t) JPH_BodyInterface_GetUserData(ctx->world->bodies, result->bodyID);
hit.shape = subshapeToShape(hit.collider, result->subShapeID2);
hit.position[0] = raycast->start[0] + (raycast->end[0] - raycast->start[0]) * result->fraction;
hit.position[1] = raycast->start[1] + (raycast->end[1] - raycast->start[1]) * result->fraction;
hit.position[2] = raycast->start[2] + (raycast->end[2] - raycast->start[2]) * result->fraction;
JPH_Vec3 normal;
JPH_Body_GetWorldSpaceSurfaceNormal(hit.collider->body, result->subShapeID2, vec3_toJolt(hit.position), &normal);
vec3_fromJolt(hit.normal, &normal);
hit.fraction = result->fraction;
hit.part = result->subShapeID2;
return cast->callback(cast->userdata, &hit);
return ctx->callback(ctx->userdata, &hit);
}
bool lovrWorldRaycast(World* world, float start[3], float end[3], CastCallback* callback, void* userdata) {
const JPH_NarrowPhaseQuery* query = JPC_PhysicsSystem_GetNarrowPhaseQueryNoLock(world->system);
bool lovrWorldRaycast(World* world, Raycast* raycast, CastCallback* callback, void* userdata) {
const JPH_NarrowPhaseQuery* query = JPH_PhysicsSystem_GetNarrowPhaseQueryNoLock(world->system);
CastInfo raycast = {
float dir[3];
vec3_init(dir, raycast->end);
vec3_sub(dir, raycast->start);
JPH_RVec3* origin = vec3_toJolt(raycast->start);
JPH_Vec3* direction = vec3_toJolt(dir);
RaycastContext context = {
.world = world,
.origin = { start[0], start[1], start[2] },
.direction = { end[0] - start[0], end[1] - start[1], end[2] - start[2] },
.raycast = raycast,
.callback = callback,
.userdata = userdata
};
JPH_RVec3* origin = vec3_toJolt(raycast.origin);
JPH_Vec3* direction = vec3_toJolt(raycast.direction);
return JPH_NarrowPhaseQuery_CastRay2(query, origin, direction, raycastCallback, &raycast, NULL, NULL, NULL);
return JPH_NarrowPhaseQuery_CastRay2(query, origin, direction, raycastCallback, &context, NULL, NULL, NULL);
}
typedef struct {
@ -425,16 +440,8 @@ Joint* lovrColliderGetJoints(Collider* collider, Joint* joint) {
return joint ? lovrJointGetNext(joint, collider) : collider->joints;
}
Shape* lovrColliderGetShape(Collider* collider, uint32_t child) {
if (collider->shape == state.pointShape) {
return NULL;
}
if (child == ~0u || collider->shape->type != SHAPE_COMPOUND) {
return collider->shape;
}
return lovrCompoundShapeGetChild(collider->shape, child);
Shape* lovrColliderGetShape(Collider* collider) {
return collider->shape == state.pointShape ? NULL : collider->shape;
}
void lovrColliderSetShape(Collider* collider, Shape* shape) {

View File

@ -107,9 +107,10 @@ static void raycastCallback(void* d, dGeomID a, dGeomID b) {
for (int i = 0; i < count; i++) {
CastResult hit;
hit.collider = collider;
hit.shape = collider->shape;
vec3_init(hit.position, contact[i].geom.pos);
vec3_init(hit.normal, contact[i].geom.normal);
hit.fraction = 0.f;
hit.part = 0;
data->shouldStop = data->callback(data->userdata, &hit);
if (data->shouldStop) break;
@ -281,15 +282,15 @@ void lovrWorldSetStepCount(World* world, int iterations) {
dWorldSetQuickStepNumIterations(world->id, iterations);
}
bool lovrWorldRaycast(World* world, float start[3], float end[3], CastCallback* callback, void* userdata) {
bool lovrWorldRaycast(World* world, Raycast* raycast, CastCallback* callback, void* userdata) {
if (callback) {
RaycastData data = { .callback = callback, .userdata = userdata, .shouldStop = false };
float dx = start[0] - end[0];
float dy = start[1] - end[1];
float dz = start[2] - end[2];
float dx = raycast->start[0] - raycast->end[0];
float dy = raycast->start[1] - raycast->end[1];
float dz = raycast->start[2] - raycast->end[2];
float length = sqrtf(dx * dx + dy * dy + dz * dz);
dGeomID ray = dCreateRay(world->space, length);
dGeomRaySet(ray, start[0], start[1], start[2], end[0], end[1], end[2]);
dGeomRaySet(ray, raycast->start[0], raycast->start[1], raycast->start[2], raycast->end[0], raycast->end[1], raycast->end[2]);
dSpaceCollide2(ray, (dGeomID) world->space, &data, raycastCallback);
dGeomDestroy(ray);
return true;
@ -489,7 +490,7 @@ World* lovrColliderGetWorld(Collider* collider) {
return collider->world;
}
Shape* lovrColliderGetShape(Collider* collider, uint32_t child) {
Shape* lovrColliderGetShape(Collider* collider) {
return collider->shape;
}