feat: major engine overhaul - scene demo with lighting, sphere, ground
- Scene Demo: cube + sphere + ground plane with proper lighting - Audio: XAudio2 dynamic loading + WAV playback - Physics: expanded collision system - Renderer: improved pipeline with materials - UI: extended widget system - VisualScript: enhanced serializer + block interactions - ASM: optimized math/memory/profiling routines - Window: mouse input + scroll support
This commit is contained in:
1 parent
2653926d85
commit
0669d102ce
35 files changed
+1844
-314
No files matched your search
+177
-6
@@ -1,9 +1,12 @@
|
||||
#include "physics.h"
|
||||
#include "../include/engine_api.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
|
||||
static void move_collider(Collider* c, Vec3 delta);
|
||||
|
||||
PhysicsWorld* physics_create(void) {
|
||||
PhysicsWorld* w = (PhysicsWorld*)calloc(1, sizeof(PhysicsWorld));
|
||||
w->gravity_enabled = 1;
|
||||
@@ -15,6 +18,15 @@ void physics_destroy(PhysicsWorld* world) {
|
||||
free(world);
|
||||
}
|
||||
|
||||
static void init_body(RigidBody* b) {
|
||||
b->velocity = (Vec3){0, 0, 0};
|
||||
b->acceleration = (Vec3){0, 0, 0};
|
||||
b->mass = 1.0f;
|
||||
b->restitution = 0.5f;
|
||||
b->friction = 0.3f;
|
||||
b->is_kinematic = 0;
|
||||
}
|
||||
|
||||
uint32_t physics_add_aabb(PhysicsWorld* world, uint32_t entity, Vec3 min, Vec3 max) {
|
||||
uint32_t idx = world->collider_count++;
|
||||
Collider* c = &world->colliders[idx];
|
||||
@@ -24,6 +36,7 @@ uint32_t physics_add_aabb(PhysicsWorld* world, uint32_t entity, Vec3 min, Vec3 m
|
||||
c->aabb.max = max;
|
||||
c->is_trigger = 0;
|
||||
c->is_static = 0;
|
||||
init_body(&c->body);
|
||||
return idx;
|
||||
}
|
||||
|
||||
@@ -34,6 +47,9 @@ uint32_t physics_add_sphere(PhysicsWorld* world, uint32_t entity, Vec3 center, f
|
||||
c->type = COLLIDER_SPHERE;
|
||||
c->sphere.center = center;
|
||||
c->sphere.radius = radius;
|
||||
c->is_trigger = 0;
|
||||
c->is_static = 0;
|
||||
init_body(&c->body);
|
||||
return idx;
|
||||
}
|
||||
|
||||
@@ -44,7 +60,11 @@ uint32_t physics_add_plane(PhysicsWorld* world, uint32_t entity, Vec3 normal, fl
|
||||
c->type = COLLIDER_PLANE;
|
||||
vec3_normalize(&normal, &c->plane.normal);
|
||||
c->plane.distance = distance;
|
||||
c->is_trigger = 0;
|
||||
c->is_static = 1;
|
||||
init_body(&c->body);
|
||||
c->body.mass = 0.0f;
|
||||
c->body.is_kinematic = 1;
|
||||
return idx;
|
||||
}
|
||||
|
||||
@@ -55,9 +75,19 @@ void physics_remove_collider(PhysicsWorld* world, uint32_t index) {
|
||||
}
|
||||
|
||||
void physics_update_collider(PhysicsWorld* world, uint32_t index, Vec3 position) {
|
||||
if (!world || index >= world->collider_count) return;
|
||||
Collider* c = &world->colliders[index];
|
||||
if (c->type == COLLIDER_SPHERE) {
|
||||
c->sphere.center = position;
|
||||
} else if (c->type == COLLIDER_AABB) {
|
||||
Vec3 center = {
|
||||
(c->aabb.min.x + c->aabb.max.x) * 0.5f,
|
||||
(c->aabb.min.y + c->aabb.max.y) * 0.5f,
|
||||
(c->aabb.min.z + c->aabb.max.z) * 0.5f
|
||||
};
|
||||
Vec3 delta;
|
||||
vec3_sub(&position, ¢er, &delta);
|
||||
move_collider(c, delta);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +96,7 @@ static int aabb_vs_aabb(const Collider* a, const Collider* b, Vec3* normal, floa
|
||||
Vec3 centerA = {(a->aabb.min.x + a->aabb.max.x) * 0.5f, (a->aabb.min.y + a->aabb.max.y) * 0.5f, (a->aabb.min.z + a->aabb.max.z) * 0.5f};
|
||||
Vec3 centerB = {(b->aabb.min.x + b->aabb.max.x) * 0.5f, (b->aabb.min.y + b->aabb.max.y) * 0.5f, (b->aabb.min.z + b->aabb.max.z) * 0.5f};
|
||||
vec3_sub(¢erA, ¢erB, &diff);
|
||||
Vec3 half_a, half_b, size;
|
||||
Vec3 half_a, half_b;
|
||||
vec3_sub(&a->aabb.max, &a->aabb.min, &half_a);
|
||||
vec3_scale(&half_a, 0.5f, &half_a);
|
||||
vec3_sub(&b->aabb.max, &b->aabb.min, &half_b);
|
||||
@@ -78,9 +108,9 @@ static int aabb_vs_aabb(const Collider* a, const Collider* b, Vec3* normal, floa
|
||||
|
||||
if (dx < 0 && dy < 0 && dz < 0) {
|
||||
*depth = -fmaxf(fmaxf(dx, dy), dz);
|
||||
if (dx > dy && dx > dz) normal = &(Vec3){copysignf(1, diff.x), 0, 0};
|
||||
else if (dy > dz) { normal->x = 0; normal->y = copysignf(1, diff.y); normal->z = 0; }
|
||||
else { normal->x = 0; normal->y = 0; normal->z = copysignf(1, diff.z); }
|
||||
if (dx > dy && dx > dz) { *normal = (Vec3){copysignf(1.0f, diff.x), 0, 0}; }
|
||||
else if (dy > dz) { normal->x = 0; normal->y = copysignf(1.0f, diff.y); normal->z = 0; }
|
||||
else { normal->x = 0; normal->y = 0; normal->z = copysignf(1.0f, diff.z); }
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -192,9 +222,150 @@ int physics_raycast(PhysicsWorld* world, Vec3 origin, Vec3 direction, float max_
|
||||
return hit;
|
||||
}
|
||||
|
||||
static int body_is_movable(Collider* c) {
|
||||
return !c->is_static && !c->body.is_kinematic && c->body.mass > 0.0f;
|
||||
}
|
||||
|
||||
static float body_inv_mass(Collider* c) {
|
||||
if (c->is_static || c->body.is_kinematic || c->body.mass <= 0.0f) return 0.0f;
|
||||
return 1.0f / c->body.mass;
|
||||
}
|
||||
|
||||
static void move_collider(Collider* c, Vec3 delta) {
|
||||
if (c->type == COLLIDER_SPHERE) {
|
||||
vec3_add(&c->sphere.center, &delta, &c->sphere.center);
|
||||
} else if (c->type == COLLIDER_AABB) {
|
||||
vec3_add(&c->aabb.min, &delta, &c->aabb.min);
|
||||
vec3_add(&c->aabb.max, &delta, &c->aabb.max);
|
||||
}
|
||||
}
|
||||
|
||||
RigidBody* physics_get_body(PhysicsWorld* world, uint32_t index) {
|
||||
if (!world || index >= world->collider_count) return NULL;
|
||||
return &world->colliders[index].body;
|
||||
}
|
||||
|
||||
void physics_apply_force(PhysicsWorld* world, uint32_t index, Vec3 force) {
|
||||
RigidBody* b = physics_get_body(world, index);
|
||||
if (!b || b->mass <= 0.0f) return;
|
||||
Vec3 scaled;
|
||||
vec3_scale(&force, 1.0f / b->mass, &scaled);
|
||||
vec3_add(&b->acceleration, &scaled, &b->acceleration);
|
||||
}
|
||||
|
||||
void physics_apply_impulse(PhysicsWorld* world, uint32_t index, Vec3 impulse) {
|
||||
RigidBody* b = physics_get_body(world, index);
|
||||
if (!b || b->mass <= 0.0f) return;
|
||||
Vec3 scaled;
|
||||
vec3_scale(&impulse, 1.0f / b->mass, &scaled);
|
||||
vec3_add(&b->velocity, &scaled, &b->velocity);
|
||||
}
|
||||
|
||||
void physics_step(PhysicsWorld* world, float dt) {
|
||||
(void)world;
|
||||
(void)dt;
|
||||
if (!world || world->collider_count == 0 || dt <= 0.0f) return;
|
||||
|
||||
const float linear_damping = 0.995f;
|
||||
|
||||
// 1. 积分动态刚体
|
||||
for (uint32_t i = 0; i < world->collider_count; i++) {
|
||||
Collider* c = &world->colliders[i];
|
||||
if (!body_is_movable(c)) continue;
|
||||
|
||||
RigidBody* b = &c->body;
|
||||
if (world->gravity_enabled) {
|
||||
vec3_add(&b->acceleration, &world->gravity, &b->acceleration);
|
||||
}
|
||||
|
||||
Vec3 dv;
|
||||
vec3_scale(&b->acceleration, dt, &dv);
|
||||
vec3_add(&b->velocity, &dv, &b->velocity);
|
||||
b->acceleration = (Vec3){0, 0, 0};
|
||||
|
||||
vec3_scale(&b->velocity, linear_damping, &b->velocity);
|
||||
|
||||
Vec3 dp;
|
||||
vec3_scale(&b->velocity, dt, &dp);
|
||||
move_collider(c, dp);
|
||||
}
|
||||
|
||||
// 2. 碰撞检测与响应
|
||||
for (uint32_t i = 0; i < world->collider_count; i++) {
|
||||
Collider* a = &world->colliders[i];
|
||||
for (uint32_t j = i + 1; j < world->collider_count; j++) {
|
||||
Collider* b = &world->colliders[j];
|
||||
if (a->is_static && b->is_static) continue;
|
||||
|
||||
Vec3 normal;
|
||||
float depth = 0.0f;
|
||||
if (!physics_check_collision(a, b, &normal, &depth)) continue;
|
||||
|
||||
// 触发器只报告,不解决
|
||||
if (a->is_trigger || b->is_trigger) continue;
|
||||
|
||||
float inv_a = body_inv_mass(a);
|
||||
float inv_b = body_inv_mass(b);
|
||||
float total_inv = inv_a + inv_b;
|
||||
if (total_inv <= 0.0f) continue;
|
||||
|
||||
// 位置修正(防止沉入)
|
||||
float percent = 0.5f; // 修正比例
|
||||
Vec3 correction;
|
||||
vec3_scale(&normal, depth * percent / total_inv, &correction);
|
||||
if (inv_a > 0.0f) {
|
||||
Vec3 da; vec3_scale(&correction, inv_a, &da);
|
||||
da.x = -da.x; da.y = -da.y; da.z = -da.z;
|
||||
move_collider(a, da);
|
||||
}
|
||||
if (inv_b > 0.0f) {
|
||||
Vec3 db; vec3_scale(&correction, inv_b, &db);
|
||||
move_collider(b, db);
|
||||
}
|
||||
|
||||
// 冲量响应
|
||||
Vec3 rel_v;
|
||||
vec3_sub(&a->body.velocity, &b->body.velocity, &rel_v);
|
||||
float vel_along_normal = vec3_dot(&rel_v, &normal);
|
||||
if (vel_along_normal > 0.0f) continue; // 正在分离
|
||||
|
||||
float e = fminf(a->body.restitution, b->body.restitution);
|
||||
float j = -(1.0f + e) * vel_along_normal / total_inv;
|
||||
|
||||
Vec3 impulse;
|
||||
vec3_scale(&normal, j, &impulse);
|
||||
if (inv_a > 0.0f) {
|
||||
Vec3 va; vec3_scale(&impulse, inv_a, &va);
|
||||
vec3_add(&a->body.velocity, &va, &a->body.velocity);
|
||||
}
|
||||
if (inv_b > 0.0f) {
|
||||
Vec3 vb; vec3_scale(&impulse, inv_b, &vb);
|
||||
vec3_sub(&b->body.velocity, &vb, &b->body.velocity);
|
||||
}
|
||||
|
||||
// 摩擦力
|
||||
vec3_sub(&a->body.velocity, &b->body.velocity, &rel_v);
|
||||
Vec3 tangent;
|
||||
Vec3 vn; vec3_scale(&normal, vec3_dot(&rel_v, &normal), &vn);
|
||||
vec3_sub(&rel_v, &vn, &tangent);
|
||||
float tan_len = vec3_length(&tangent);
|
||||
if (tan_len > 0.0001f) {
|
||||
vec3_scale(&tangent, 1.0f / tan_len, &tangent);
|
||||
float jt = -vec3_dot(&rel_v, &tangent) / total_inv;
|
||||
float mu = sqrtf(a->body.friction * a->body.friction + b->body.friction * b->body.friction);
|
||||
if (jt > j * mu) jt = j * mu;
|
||||
if (jt < -j * mu) jt = -j * mu;
|
||||
Vec3 friction_impulse;
|
||||
vec3_scale(&tangent, jt, &friction_impulse);
|
||||
if (inv_a > 0.0f) {
|
||||
Vec3 va; vec3_scale(&friction_impulse, inv_a, &va);
|
||||
vec3_add(&a->body.velocity, &va, &a->body.velocity);
|
||||
}
|
||||
if (inv_b > 0.0f) {
|
||||
Vec3 vb; vec3_scale(&friction_impulse, inv_b, &vb);
|
||||
vec3_sub(&b->body.velocity, &vb, &b->body.velocity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void physics_set_gravity(PhysicsWorld* world, Vec3 gravity) {
|
||||
|
||||
Reference in new issue
Block a user