Cleanup int collision math, which is still wrong

This commit is contained in:
2025-12-20 22:31:32 +01:00
parent 1453b2bbd7
commit d63aeba562
2 changed files with 112 additions and 68 deletions

View File

@@ -181,24 +181,24 @@ movement_state: MovementState,
pub const camera_height_vx = 1.62;
pub const horizontal_speed_sv = c.sv(11.0);
pub const vertical_speed_sv = c.sv(7.49);
pub const horizontal_speed_sv = sv(11.0);
pub const vertical_speed_sv = sv(7.49);
pub const min_pitch_rad = -0.5 * std.math.pi;
pub const max_pitch_rad = 0.5 * std.math.pi;
pub const collision_half_width_sv = c.sv(0.4);
pub const collision_height_sv = c.sv(1.8);
pub const collision_half_width_sv = sv(0.4);
pub const collision_height_sv = sv(1.8);
pub const speed_sv = c.sv(5.612);
pub const step_up_sv = c.sv(0.53125);
pub const step_down_sv = c.sv(0.53125);
pub const jump_velocity_sv = c.sv(6.1237245);
pub const gravity_sv = c.sv(15);
pub const vertical_velocity_cap_sv = c.sv(30);
pub const ground_acceleration_sv = c.sv(56.12);
pub const air_acceleration_sv = c.sv(56.12);
pub const air_speed_limit_sv = c.sv(0.5612);
pub const speed_sv = sv(5.612);
pub const step_up_sv = sv(0.53125);
pub const step_down_sv = sv(0.53125);
pub const jump_velocity_sv = sv(6.1237245);
pub const gravity_sv = sv(15);
pub const vertical_velocity_cap_sv = sv(30);
pub const ground_acceleration_sv = sv(56.12);
pub const air_acceleration_sv = sv(56.12);
pub const air_speed_limit_sv = sv(0.5612);
pub fn init(position_sv: Vector3Int, pitch_rad: f32, yaw_rad: f32) Player {
return .{
@@ -286,9 +286,10 @@ pub fn update(self: *Player, dt: f32, chunks: *const std.AutoHashMapUnmanaged([3
const adjustment = hit.normal_frac
.asVector2Int()
.mulScalarFrac(hit.projected_distance_sv);
std.debug.print("i={} | n={} | d={} | adj={} | disp={}->", .{
std.debug.print("i={} | pos={X} | n={} | d={X} | adj={X} | disp={X}->", .{
i,
hit.normal_frac.vector,
position_sv.vector,
hit.normal_frac.asVector3Frac().vector,
hit.projected_distance_sv,
adjustment.vector,
horizontal_displacement_sv.vector,
@@ -297,7 +298,7 @@ pub fn update(self: *Player, dt: f32, chunks: *const std.AutoHashMapUnmanaged([3
horizontal_displacement_sv,
adjustment,
);
std.debug.print("{}\n", .{horizontal_displacement_sv.vector});
std.debug.print("{X}\n", .{horizontal_displacement_sv.vector});
} else {
break;
}
@@ -325,17 +326,17 @@ fn sweepCastDown(origin_sv: Vector3Int, distance_sv: i32, chunks: *const std.Aut
const min_origin_sv = origin_sv.add(.init(-collision_half_width_sv, -collision_half_width_sv, 0));
const max_origin_sv = origin_sv.add(.init(collision_half_width_sv, collision_half_width_sv, collision_height_sv));
const min_x_vx = voxelFromSubvoxel(.border_up, min_origin_sv.getX());
const min_y_vx = voxelFromSubvoxel(.border_up, min_origin_sv.getY());
const max_x_vx = voxelFromSubvoxel(.border_down, max_origin_sv.getX());
const max_y_vx = voxelFromSubvoxel(.border_down, max_origin_sv.getY());
const min_x_vx = c.subvoxelsToVoxels(.border_up, min_origin_sv.getX());
const min_y_vx = c.subvoxelsToVoxels(.border_up, min_origin_sv.getY());
const max_x_vx = c.subvoxelsToVoxels(.border_down, max_origin_sv.getX());
const max_y_vx = c.subvoxelsToVoxels(.border_down, max_origin_sv.getY());
const start_z_vx = voxelFromSubvoxel(.next_down, min_origin_sv.getZ());
const end_z_vx = voxelFromSubvoxel(.border_up, min_origin_sv.getZ() - distance_sv);
const start_z_vx = c.subvoxelsToVoxels(.border_up, min_origin_sv.getZ()) - 1;
const end_z_vx = c.subvoxelsToVoxels(.border_up, min_origin_sv.getZ() - distance_sv);
var z_vx: i32 = start_z_vx;
while (z_vx >= end_z_vx) : (z_vx -= 1) {
const z_sv = (z_vx + 1) * c.sv_per_vx;
const z_sv = c.voxelsToSubvoxels(z_vx + 1);
var it = Iterator2(i32).init(.{
.min = .{ min_x_vx, min_y_vx },
.max = .{ max_x_vx, max_y_vx },
@@ -358,17 +359,17 @@ fn sweepCastUp(origin_sv: Vector3Int, distance_sv: i32, chunks: *const std.AutoH
const min_origin_sv = origin_sv.add(.init(-collision_half_width_sv, -collision_half_width_sv, 0));
const max_origin_sv = origin_sv.add(.init(collision_half_width_sv, collision_half_width_sv, collision_height_sv));
const min_x_vx = voxelFromSubvoxel(.border_up, min_origin_sv.getX());
const min_y_vx = voxelFromSubvoxel(.border_up, min_origin_sv.getY());
const max_x_vx = voxelFromSubvoxel(.border_down, max_origin_sv.getX());
const max_y_vx = voxelFromSubvoxel(.border_down, max_origin_sv.getY());
const min_x_vx = c.subvoxelsToVoxels(.border_up, min_origin_sv.getX());
const min_y_vx = c.subvoxelsToVoxels(.border_up, min_origin_sv.getY());
const max_x_vx = c.subvoxelsToVoxels(.border_down, max_origin_sv.getX());
const max_y_vx = c.subvoxelsToVoxels(.border_down, max_origin_sv.getY());
const start_z_vx = voxelFromSubvoxel(.next_up, max_origin_sv.getZ());
const end_z_vx = voxelFromSubvoxel(.border_up, max_origin_sv.getZ() + distance_sv);
const start_z_vx = c.subvoxelsToVoxels(.border_down, max_origin_sv.getZ()) + 1;
const end_z_vx = c.subvoxelsToVoxels(.border_down, max_origin_sv.getZ() + distance_sv);
var z_vx: i32 = start_z_vx;
while (z_vx <= end_z_vx) : (z_vx += 1) {
const z_sv = z_vx * c.sv_per_vx;
const z_sv = c.voxelsToSubvoxels(z_vx);
var it = Iterator2(i32).init(.{
.min = .{ min_x_vx, min_y_vx },
.max = .{ max_x_vx, max_y_vx },
@@ -391,8 +392,8 @@ fn sweepCastHorizontal(origin_sv: Vector3Int, ray_sv: Vector2Int, chunks: *const
const min_origin_sv = origin_sv.add(.init(-collision_half_width_sv, -collision_half_width_sv, 0));
const max_origin_sv = origin_sv.add(.init(collision_half_width_sv, collision_half_width_sv, collision_height_sv));
const min_z_vx = voxelFromSubvoxel(.border_up, min_origin_sv.getZ());
const max_z_vx = voxelFromSubvoxel(.border_down, max_origin_sv.getZ());
const min_z_vx = c.subvoxelsToVoxels(.border_up, min_origin_sv.getZ());
const max_z_vx = c.subvoxelsToVoxels(.border_down, max_origin_sv.getZ());
var hit: ?SweepHit = null;
var hit_distance_squared = std.math.inf(f32);
@@ -406,14 +407,14 @@ fn sweepCastHorizontal(origin_sv: Vector3Int, ray_sv: Vector2Int, chunks: *const
const y0_sv = min_origin_sv.getY();
const y1_sv = max_origin_sv.getY();
const start_x_vx = voxelFromSubvoxel(.next_up, x0_sv);
const end_x_vx = voxelFromSubvoxel(.border_down, x0_sv + ray_sv.getX());
const start_x_vx = c.subvoxelsToVoxels(.border_down, x0_sv) + 1;
const end_x_vx = c.subvoxelsToVoxels(.border_down, x0_sv + ray_sv.getX());
var x_vx: i32 = start_x_vx;
px: while (x_vx <= end_x_vx) : (x_vx += 1) {
const x_sv = x_vx * c.sv_per_vx;
const min_y_vx = voxelFromSubvoxel(.border_up, wideMulDivFloor(x_sv - x0_sv, ray_sv.getY(), ray_sv.getX()) + y0_sv);
const max_y_vx = voxelFromSubvoxel(.border_down, wideMulDivCeil(x_sv - x0_sv, ray_sv.getY(), ray_sv.getX()) + y1_sv);
const x_sv = c.voxelsToSubvoxels(x_vx);
const min_y_vx = c.subvoxelsToVoxels(.border_up, wideMulDivFloor(x_sv - x0_sv, ray_sv.getY(), ray_sv.getX()) + y0_sv);
const max_y_vx = c.subvoxelsToVoxels(.border_down, wideMulDivCeil(x_sv - x0_sv, ray_sv.getY(), ray_sv.getX()) + y1_sv);
var it = Iterator2(i32).init(.{
.min = .{ min_y_vx, min_z_vx },
.max = .{ max_y_vx, max_z_vx },
@@ -444,14 +445,14 @@ fn sweepCastHorizontal(origin_sv: Vector3Int, ray_sv: Vector2Int, chunks: *const
const y0_sv = min_origin_sv.getY();
const y1_sv = max_origin_sv.getY();
const start_x_vx = voxelFromSubvoxel(.next_down, x0_sv);
const end_x_vx = voxelFromSubvoxel(.border_up, x0_sv + ray_sv.getX());
const start_x_vx = c.subvoxelsToVoxels(.border_up, x0_sv) - 1;
const end_x_vx = c.subvoxelsToVoxels(.border_up, x0_sv + ray_sv.getX());
var x_vx: i32 = start_x_vx;
nx: while (x_vx >= end_x_vx) : (x_vx -= 1) {
const x_sv = (x_vx + 1) * c.sv_per_vx;
const min_y_vx = voxelFromSubvoxel(.border_up, wideMulDivFloor(x_sv - x0_sv, ray_sv.getY(), ray_sv.getX()) + y0_sv);
const max_y_vx = voxelFromSubvoxel(.border_down, wideMulDivCeil(x_sv - x0_sv, ray_sv.getY(), ray_sv.getX()) + y1_sv);
const x_sv = c.voxelsToSubvoxels(x_vx + 1);
const min_y_vx = c.subvoxelsToVoxels(.border_up, wideMulDivFloor(x_sv - x0_sv, ray_sv.getY(), ray_sv.getX()) + y0_sv);
const max_y_vx = c.subvoxelsToVoxels(.border_down, wideMulDivCeil(x_sv - x0_sv, ray_sv.getY(), ray_sv.getX()) + y1_sv);
var it = Iterator2(i32).init(.{
.min = .{ min_y_vx, min_z_vx },
.max = .{ max_y_vx, max_z_vx },
@@ -482,14 +483,14 @@ fn sweepCastHorizontal(origin_sv: Vector3Int, ray_sv: Vector2Int, chunks: *const
const x0_sv = min_origin_sv.getX();
const x1_sv = max_origin_sv.getX();
const start_y_vx = voxelFromSubvoxel(.next_up, y0_sv);
const end_y_vx = voxelFromSubvoxel(.border_down, y0_sv + ray_sv.getY());
const start_y_vx = c.subvoxelsToVoxels(.border_down, y0_sv) + 1;
const end_y_vx = c.subvoxelsToVoxels(.border_down, y0_sv + ray_sv.getY());
var y_vx = start_y_vx;
py: while (y_vx <= end_y_vx) : (y_vx += 1) {
const y_sv = y_vx * c.sv_per_vx;
const min_x_vx = voxelFromSubvoxel(.border_up, wideMulDivFloor(y_sv - y0_sv, ray_sv.getX(), ray_sv.getY()) + x0_sv);
const max_x_vx = voxelFromSubvoxel(.border_down, wideMulDivCeil(y_sv - y0_sv, ray_sv.getX(), ray_sv.getY()) + x1_sv);
const y_sv = c.voxelsToSubvoxels(y_vx);
const min_x_vx = c.subvoxelsToVoxels(.border_up, wideMulDivFloor(y_sv - y0_sv, ray_sv.getX(), ray_sv.getY()) + x0_sv);
const max_x_vx = c.subvoxelsToVoxels(.border_down, wideMulDivCeil(y_sv - y0_sv, ray_sv.getX(), ray_sv.getY()) + x1_sv);
var it = Iterator2(i32).init(.{
.min = .{ min_x_vx, min_z_vx },
.max = .{ max_x_vx, max_z_vx },
@@ -523,14 +524,14 @@ fn sweepCastHorizontal(origin_sv: Vector3Int, ray_sv: Vector2Int, chunks: *const
const x0_sv = min_origin_sv.getX();
const x1_sv = max_origin_sv.getX();
const start_y_vx = voxelFromSubvoxel(.next_down, y0_sv);
const end_y_vx = voxelFromSubvoxel(.border_up, y0_sv + ray_sv.getY());
const start_y_vx = c.subvoxelsToVoxels(.border_up, y0_sv) - 1;
const end_y_vx = c.subvoxelsToVoxels(.border_up, y0_sv + ray_sv.getY());
var y_vx = start_y_vx;
ny: while (y_vx >= end_y_vx) : (y_vx -= 1) {
const y_sv = (y_vx + 1) * c.sv_per_vx;
const min_x_vx = voxelFromSubvoxel(.border_up, wideMulDivFloor(y_sv - y0_sv, ray_sv.getX(), ray_sv.getY()) + x0_sv);
const max_x_vx = voxelFromSubvoxel(.border_down, wideMulDivCeil(y_sv - y0_sv, ray_sv.getX(), ray_sv.getY()) + x1_sv);
const y_sv = c.voxelsToSubvoxels(y_vx + 1);
const min_x_vx = c.subvoxelsToVoxels(.border_up, wideMulDivFloor(y_sv - y0_sv, ray_sv.getX(), ray_sv.getY()) + x0_sv);
const max_x_vx = c.subvoxelsToVoxels(.border_down, wideMulDivCeil(y_sv - y0_sv, ray_sv.getX(), ray_sv.getY()) + x1_sv);
var it = Iterator2(i32).init(.{
.min = .{ min_x_vx, min_z_vx },
.max = .{ max_x_vx, max_z_vx },
@@ -595,13 +596,6 @@ fn isSolid(chunks: *const std.AutoHashMapUnmanaged([3]i16, Chunk), vx: Vector3In
return maybe_id != .air;
}
const RoundingMode = enum {
border_down,
border_up,
next_down,
next_up,
};
inline fn wideMulDivFloor(a: i32, mul: i32, div: i32) i32 {
return @intCast(@divFloor(@as(i64, a) * @as(i64, mul), div));
}
@@ -610,11 +604,6 @@ inline fn wideMulDivCeil(a: i32, mul: i32, div: i32) i32 {
return @intCast(@divFloor(@as(i64, a) * @as(i64, mul) + @as(i64, div) - 1, div));
}
inline fn voxelFromSubvoxel(comptime rounding_mode: RoundingMode, subvoxel: i32) i32 {
return switch (rounding_mode) {
.border_down => @divFloor(subvoxel - 1, c.sv_per_vx),
.border_up => @divFloor(subvoxel, c.sv_per_vx),
.next_down => @divFloor(subvoxel - c.sv_per_vx, c.sv_per_vx),
.next_up => @divFloor(subvoxel + (c.sv_per_vx - 1), c.sv_per_vx),
};
inline fn sv(comptime vx: comptime_float) comptime_int {
return @intFromFloat(@round(vx * c.sv_per_vx));
}

View File

@@ -38,6 +38,61 @@ pub const sv_per_vx = 4096;
pub const vx_per_ck = 16;
pub const sv_per_ck = sv_per_vx * vx_per_ck;
pub inline fn sv(comptime vx: comptime_float) comptime_int {
return @intFromFloat(@round(vx * sv_per_vx));
pub const RoundingMode = enum {
border_down,
border_up,
};
/// SV to VX
pub inline fn subvoxelsToVoxels(comptime rounding_mode: RoundingMode, sv: i32) i32 {
return switch (rounding_mode) {
.border_down => @divFloor(sv, sv_per_vx - 1),
.border_up => @divFloor(sv, sv_per_vx),
};
}
/// SV to CK
pub inline fn subvoxelsToChunks(comptime rounding_mode: RoundingMode, sv: i32) i32 {
return switch (rounding_mode) {
.border_down => @divFloor(sv, sv_per_ck - 1),
.border_up => @divFloor(sv, sv_per_ck),
};
}
/// SV to CKSV
pub inline fn subvoxelsToChunkSubvoxels(sv: i32) std.math.IntFittingRange(0, sv_per_ck - 1) {
return @intCast(@mod(sv, sv_per_ck));
}
/// SV to VXSV
pub inline fn subvoxelsToVoxelSubvoxels(sv: i32) std.math.IntFittingRange(0, sv_per_vx - 1) {
return @intCast(@mod(sv, sv_per_vx));
}
/// VX to SV
pub inline fn voxelsToSubvoxels(vx: i32) i32 {
return vx * sv_per_vx;
}
/// VX to CK
pub inline fn voxelsToChunks(comptime rounding_mode: RoundingMode, vx: i32) i32 {
return switch (rounding_mode) {
.border_down => @divFloor(vx, vx_per_ck - 1),
.border_up => @divFloor(vx, vx_per_ck),
};
}
/// VX to CKVX
pub inline fn voxelsToChunkVoxels(vx: i32) std.math.IntFittingRange(0, vx_per_ck) {
return @intCast(@mod(vx, vx_per_ck));
}
/// CK to SV
pub inline fn chunksToSubvoxels(ck: i32) i32 {
return ck * sv_per_ck;
}
/// CK to VX
pub inline fn chunksToVoxels(ck: i32) i32 {
return ck * vx_per_ck;
}