Kansei dorifto (no idea why car rotates like that lol)

This commit is contained in:
sergeypdev 2025-01-04 03:42:04 +04:00
parent aa0f945b0c
commit ad2d175b10
2 changed files with 162 additions and 18 deletions

View File

@ -370,18 +370,35 @@ draw :: proc() {
camera := game_camera_3d() camera := game_camera_3d()
points := &get_world().track.points
interpolated_points := calculate_spline_interpolated_points(points[:], context.temp_allocator)
collision, segment_idx := raycast_spline_tube(
interpolated_points,
rl.GetScreenToWorldRay(rl.GetMousePosition(), camera),
)
{ {
rl.BeginMode3D(camera) rl.BeginMode3D(camera)
defer rl.EndMode3D() defer rl.EndMode3D()
rl.DrawModel( if collision.hit {
assets.get_model(&g_mem.assetman, "assets/toyota_corolla_ae86_trueno.glb"), tangent, bitangent := get_point_frame(interpolated_points, segment_idx)
rl.Vector3{0, 0, 0},
1,
rl.WHITE,
)
points := &get_world().track.points rot_matrix: linalg.Matrix3f32
rot_matrix[0] = bitangent
rot_matrix[1] = interpolated_points[segment_idx].normal
rot_matrix[2] = -tangent
angle, axis := linalg.angle_axis_from_quaternion(
linalg.quaternion_from_matrix3(rot_matrix),
)
car_model := assets.get_model(&g_mem.assetman, "assets/toyota_corolla_ae86_trueno.glb")
car_model.transform = rl.MatrixRotate(axis, angle)
rl.DrawModel(car_model, collision.point, 1, rl.WHITE)
}
// road: rl.Mesh // road: rl.Mesh
// defer rl.UnloadMesh(road) // defer rl.UnloadMesh(road)
@ -394,11 +411,6 @@ draw :: proc() {
// road_uvs.allocator = context.temp_allocator // road_uvs.allocator = context.temp_allocator
// road_indices.allocator = context.temp_allocator // road_indices.allocator = context.temp_allocator
interpolated_points := calculate_spline_interpolated_points(
points[:],
context.temp_allocator,
)
{ {
// Debug draw spline road // Debug draw spline road
@ -439,6 +451,10 @@ draw :: proc() {
} }
} }
} }
if collision.hit {
rl.DrawSphereWires(collision.point, 1, 8, 8, rl.RED)
}
} }
{ {
@ -448,6 +464,10 @@ draw :: proc() {
if g_mem.editor { if g_mem.editor {
rl.DrawText("Editor", 5, 5, 8, rl.ORANGE) rl.DrawText("Editor", 5, 5, 8, rl.ORANGE)
if collision.hit {
rl.DrawText(fmt.ctprintf("Segment: %v", segment_idx), 5, 32, 8, rl.ORANGE)
}
switch g_mem.es.track_edit_state { switch g_mem.es.track_edit_state {
case .Select: case .Select:
case .Move: case .Move:
@ -465,7 +485,6 @@ draw :: proc() {
if g_mem.editor { if g_mem.editor {
es := &g_mem.es es := &g_mem.es
points := &get_world().track.points
points_len := len(points) points_len := len(points)
if points_len > 0 { if points_len > 0 {

View File

@ -74,17 +74,142 @@ sample_spline :: proc(points: []rl.Vector3, t: f32) -> rl.Vector3 {
return {} return {}
} }
get_point_frame :: #force_inline proc(
ps: #soa[]Interpolated_Point,
i: int,
) -> (
tangent: rl.Vector3,
bitangent: rl.Vector3,
) {
if len(ps) >= 2 {
tangent =
ps[i + 1].pos - ps[i].pos if (i < len(ps) - 1) else ps[len(ps) - 1].pos - ps[len(ps) - 2].pos
normal := ps[i].normal
bitangent = lg.normalize0(lg.cross(tangent, normal))
}
return
}
point_to_quad_sdf :: proc(p, a, b, c, d: rl.Vector3) -> f32 {
ba := b - a
pa := p - a
cb := c - b
pb := p - b
dc := d - c
pc := p - c
ad := a - d
pd := p - d
nor := lg.cross(ba, ad)
sqrt :: math.sqrt
dot :: lg.dot
cross :: lg.cross
length2 :: lg.length2
min :: math.min
sign :: math.sign
clamp :: math.clamp
return sqrt(
(sign(dot(cross(ba, nor), pa)) + sign(dot(cross(cb, nor), pb)) + sign(dot(cross(dc, nor), pc)) + sign(dot(cross(ad, nor), pd)) < 3.0) ? (min(min(min(length2(ba * clamp(dot(ba, pa) / length2(ba), 0.0, 1.0) - pa), length2(cb * clamp(dot(cb, pb) / length2(cb), 0.0, 1.0) - pb)), length2(dc * clamp(dot(dc, pc) / length2(dc), 0.0, 1.0) - pc)), length2(ad * clamp(dot(ad, pd) / length2(ad), 0.0, 1.0) - pd))) : (dot(nor, pa) * dot(nor, pa) / length2(nor)),
)
}
// point_to_segmented_line_distance :: proc(
// ps: #soa[]Interpolated_Point,
// p: rl.Vector3,
// ) -> (
// min_distance: f32,
// segment_idx: int,
// ok: bool, // is point within spline
// ) {
// min_distance = math.F32_MAX
// segment_idx = -1
// for i in 0 ..< len(ps) - 1 {
// cur, next := ps[i].pos, ps[i + 1].pos
//
// tangent, bitangent := get_point_frame(ps, i)
// next_tangent, next_bitangent := get_point_frame(ps, i + 1)
// normal, next_normal := ps[i].normal, ps[i + 1].normal
//
// tangent_len := lg.length(tangent)
// tangent_norm := tangent / tangent_len if tangent_len > 0 else 0
//
// translated_p := p - cur
//
// // point_to_quad_sdf(p, cur - bitangent * -ROAD_WIDTH, cur)
//
// dot_v := lg.dot(tangent_norm, translated_p)
// // dot_u := lg.dot(bitangent)
//
// distance: f32
// if dot_v < 0 {
// distance = lg.length(translated_p)
// ok = false
// } else if dot_v > tangent_len {
// distance = lg.distance(tangent, translated_p)
// ok = false
// } else {
// projected_p := tangent_norm * dot_v
// distance = lg.distance(projected_p, translated_p)
// ok = true
// }
//
// if distance < min_distance {
// segment_idx = i
// min_distance = distance
// }
// }
//
// return min_distance, segment_idx, ok
// }
/// Find collision with the closest
raycast_spline_tube :: proc(
ps: #soa[]Interpolated_Point,
ray: rl.Ray,
) -> (
collision: rl.RayCollision,
segment_idx: int,
) {
for i in 0 ..< len(ps) - 1 {
cur, next := ps[i].pos, ps[i + 1].pos
_, bitangent := get_point_frame(ps, i)
_, next_bitangent := get_point_frame(ps, i + 1)
// normal, next_normal := ps[i].normal, ps[i + 1].normal
p1 := cur + bitangent * -ROAD_WIDTH
p2 := cur + bitangent * ROAD_WIDTH
p3 := next + next_bitangent * -ROAD_WIDTH
p4 := next + next_bitangent * ROAD_WIDTH
segment_idx = i
collision = rl.GetRayCollisionTriangle(ray, p1, p2, p3)
if collision.hit {
break
}
collision = rl.GetRayCollisionTriangle(ray, p2, p4, p3)
if collision.hit {
break
}
}
return
}
calculate_spline_interpolated_points :: proc( calculate_spline_interpolated_points :: proc(
points: []rl.Vector3, points: []rl.Vector3,
allocator := context.allocator, allocator := context.allocator,
) -> []Interpolated_Point { ) -> #soa[]Interpolated_Point {
points_len := len(points) points_len := len(points)
ctrl_rotations := calculate_spline_ctrl_rotations(points, context.temp_allocator) ctrl_rotations := calculate_spline_ctrl_rotations(points, context.temp_allocator)
if points_len >= 2 { if points_len >= 2 {
interpolated_points := make( interpolated_points := make_soa(
[]Interpolated_Point, #soa[]Interpolated_Point,
(points_len - 1) * SPLINE_SUBDIVS_V + 1, (points_len - 1) * SPLINE_SUBDIVS_V + 1,
allocator, allocator,
) )
@ -132,7 +257,7 @@ calculate_spline_interpolated_points :: proc(
return nil return nil
} }
debug_draw_spline :: proc(interpolated_points: []Interpolated_Point) { debug_draw_spline :: proc(interpolated_points: #soa[]Interpolated_Point) {
rlgl.Begin(rlgl.LINES) rlgl.Begin(rlgl.LINES)
defer rlgl.End() defer rlgl.End()
for i in 0 ..< len(interpolated_points) - 1 { for i in 0 ..< len(interpolated_points) - 1 {
@ -160,7 +285,7 @@ debug_draw_spline :: proc(interpolated_points: []Interpolated_Point) {
} }
} }
debug_draw_spline_mesh :: proc(interpolated_points: []Interpolated_Point) { debug_draw_spline_mesh :: proc(interpolated_points: #soa[]Interpolated_Point) {
rlgl.Begin(rlgl.TRIANGLES) rlgl.Begin(rlgl.TRIANGLES)
defer rlgl.End() defer rlgl.End()