-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathraycast.odin
More file actions
118 lines (91 loc) · 3.28 KB
/
Copy pathraycast.odin
File metadata and controls
118 lines (91 loc) · 3.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package main
import "core:math"
Ray :: struct {
hit: bool,
model: ^Model,
position: Vector3,
direction: Vector3
}
CastRay :: proc(screenX, screenY: f32, camera: Camera, projType: ProjectionType, models: []Model) -> Ray {
ndcX := (screenX / f32(SCREEN_WIDTH)) * 2.0 - 1.0
ndcY := (screenY / f32(SCREEN_HEIGHT)) * 2.0 - 1.0
rayOrigin := GetRayOrigin(ndcX, ndcY, camera, projType)
ray: Ray
ray.direction = GetRayDirection(ndcX, ndcY, camera, projType)
closestDist := max(f32)
for &model in models {
center := model.translation
delta := center - rayOrigin
if HasBoxCollider(&model) {
axes := GetAxesFromRotationMatrix(model.rotationMatrix)
size := model.collider.(BoxCollider) * model.scale
tMin := f32(0.0)
tMax := max(f32)
hit := true
for i in 0..<3 {
axis := axes[i]
e := Vector3DotProduct(axis, delta)
f := Vector3DotProduct(axis, ray.direction)
if abs(f) < 1e-6 {
if e < -size[i] || e > size[i] {
hit = false
break
}
continue
}
t1 := (e - size[i]) / f
t2 := (e + size[i]) / f
if t1 > t2 {
t1, t2 = t2, t1
}
tMin = max(tMin, t1)
tMax = min(tMax, t2)
if tMin > tMax {
hit = false
break
}
}
if hit && tMin < closestDist {
closestDist = tMin
ray.hit = true
ray.model = &model
ray.position = rayOrigin + ray.direction * tMin
}
}
else if HasSphereCollider(&model) {
r := model.collider.(SphereCollider) * model.scale
r2 := r * r
tca := Vector3DotProduct(delta, ray.direction)
d2 := Vector3DotProduct(delta, delta) - tca * tca
if d2 > r2 {
continue
}
thc := math.sqrt(r2 - d2)
t1 := tca - thc
t2 := tca + thc
t := t1 < 0 ? t2 : t1
if t >= 0 && t < closestDist {
closestDist = t
ray.hit = true
ray.model = &model
ray.position = rayOrigin + ray.direction * t
}
}
}
return ray
GetRayOrigin :: proc(ndcX, ndcY: f32, camera: Camera, projType: ProjectionType) -> Vector3 {
if projType == .Perspective do return camera.position
aspect := f32(SCREEN_WIDTH) / f32(SCREEN_HEIGHT)
return camera.position + camera.right * (ndcX * aspect) + camera.up * (-ndcY)
}
GetRayDirection :: proc(ndcX, ndcY: f32, camera: Camera, projType: ProjectionType) -> Vector3 {
if projType == .Orthographic do return camera.forward
aspect := f32(SCREEN_WIDTH) / f32(SCREEN_HEIGHT)
tanHalfFov := math.tan_f32(FOV * 0.5 * DEG_TO_RAD)
return Vector3Normalize (
camera.forward +
camera.right * (ndcX * aspect * tanHalfFov) +
camera.up * (-ndcY * tanHalfFov)
)
}
}