group2 0.1.0
CSE 125 Group 2
Loading...
Searching...
No Matches
Raycast.hpp
Go to the documentation of this file.
1
6
7#pragma once
8
15
16#include <algorithm>
17#include <cmath>
18#include <glm/geometric.hpp>
19
20namespace physics
21{
22
24inline constexpr float k_hitscanRange = 5000.0f;
25
27inline constexpr float k_parallelEpsilon = 1e-6f;
28
31{
32 bool hit{false};
34 glm::vec3 point{0.0f};
35 glm::vec3 normal{0.0f, 1.0f, 0.0f};
37 entt::entity entity{entt::null};
38};
39
41inline bool raycastAABB(glm::vec3 origin,
42 glm::vec3 direction,
43 const WorldAABB& box,
44 float maxDistance,
45 float& outDistance,
46 glm::vec3& outNormal)
47{
48 float tMin = 0.0f;
49 float tMax = maxDistance;
50 glm::vec3 hitNormal{0.0f};
51
52 for (int axis = 0; axis < 3; ++axis) {
53 if (std::abs(direction[axis]) < k_parallelEpsilon) {
54 if (origin[axis] < box.min[axis] || origin[axis] > box.max[axis]) {
55 return false;
56 }
57 continue;
58 }
59
60 const float invDir = 1.0f / direction[axis];
61 float t1 = (box.min[axis] - origin[axis]) * invDir;
62 float t2 = (box.max[axis] - origin[axis]) * invDir;
63 glm::vec3 axisNormal{0.0f};
64 axisNormal[axis] = (invDir >= 0.0f) ? -1.0f : 1.0f;
65
66 if (t1 > t2) {
67 std::swap(t1, t2);
68 axisNormal = -axisNormal;
69 }
70
71 if (t1 > tMin) {
72 tMin = t1;
73 hitNormal = axisNormal;
74 }
75
76 tMax = std::min(tMax, t2);
77 if (tMin > tMax) {
78 return false;
79 }
80 }
81
82 if (tMin < 0.0f || tMin > maxDistance) {
83 return false;
84 }
85
86 outDistance = tMin;
87 outNormal = hitNormal;
88 return true;
89}
90
92inline HitscanHit raycastWorld(glm::vec3 origin, glm::vec3 direction, const WorldGeometry& world)
93{
94 HitscanHit bestHit;
95
96 for (const Plane& plane : world.planes) {
97 const float denom = glm::dot(plane.normal, direction);
98 if (std::abs(denom) < k_parallelEpsilon) {
99 continue;
100 }
101
102 const float distance = (plane.distance - glm::dot(plane.normal, origin)) / denom;
103 if (distance < 0.0f || distance >= bestHit.distance) {
104 continue;
105 }
106
107 bestHit.hit = true;
108 bestHit.distance = distance;
109 bestHit.point = origin + direction * distance;
110 bestHit.normal = plane.normal;
112 }
113
114 for (const WorldAABB& box : world.boxes) {
115 float distance = bestHit.distance;
116 glm::vec3 normal{0.0f};
117 if (!raycastAABB(origin, direction, box, bestHit.distance, distance, normal)) {
118 continue;
119 }
120
121 bestHit.hit = true;
122 bestHit.distance = distance;
123 bestHit.point = origin + direction * distance;
124 bestHit.normal = normal;
126 }
127
128 return bestHit;
129}
130
132inline HitscanHit
133raycastPlayers(Registry& registry, entt::entity shooter, glm::vec3 origin, glm::vec3 direction, float maxDistance)
134{
135 HitscanHit bestHit;
136 bestHit.distance = maxDistance;
137
138 registry.view<Position, CollisionShape>().each(
139 [&](entt::entity entity, const Position& pos, const CollisionShape& shape) {
140 if (entity == shooter) {
141 return;
142 }
143
144 const WorldAABB bounds{
145 .min = pos.value - shape.halfExtents,
146 .max = pos.value + shape.halfExtents,
147 };
148
149 float distance = bestHit.distance;
150 glm::vec3 normal{0.0f};
151 if (!raycastAABB(origin, direction, bounds, bestHit.distance, distance, normal)) {
152 return;
153 }
154
155 bestHit.hit = true;
156 bestHit.distance = distance;
157 bestHit.point = origin + direction * distance;
158 bestHit.normal = normal;
159 bestHit.surface = SurfaceType::Flesh;
160 bestHit.entity = entity;
161 });
162
163 return bestHit;
164}
165
167inline HitscanHit resolveHitscan(Registry& registry, entt::entity shooter, glm::vec3 origin, glm::vec3 direction)
168{
169 HitscanHit bestHit = raycastWorld(origin, direction, testWorld());
170
171 const HitscanHit playerHit = raycastPlayers(registry, shooter, origin, direction, bestHit.distance);
172 if (playerHit.hit && (!bestHit.hit || playerHit.distance < bestHit.distance)) {
173 bestHit = playerHit;
174 }
175
176 if (!bestHit.hit) {
177 bestHit.distance = k_hitscanRange;
178 bestHit.point = origin + direction * k_hitscanRange;
179 }
180
181 return bestHit;
182}
183
184} // namespace physics
AABB collision shape component for physics entities.
World-space position component for ECS entities.
Projectile component and weapon/surface type enumerations.
SurfaceType
Surface material hit by a projectile — drives impact effect parameters.
Definition Projectile.hpp:13
Shared ECS registry type alias for the game engine.
entt::registry Registry
Shared ECS registry type alias.
Definition Registry.hpp:11
Swept AABB and sphere collision queries against world geometry.
Shared test world geometry compiled identically on client and server.
Pure physics math — no ECS types, no registry.
Definition Movement.cpp:14
HitscanHit raycastPlayers(Registry &registry, entt::entity shooter, glm::vec3 origin, glm::vec3 direction, float maxDistance)
Raycast against all player hitboxes (axis-aligned capsule approximation).
Definition Raycast.hpp:133
constexpr float k_hitscanRange
Maximum hitscan distance in world units.
Definition Raycast.hpp:24
const WorldGeometry & testWorld()
The physics test playground.
Definition WorldData.hpp:86
bool raycastAABB(glm::vec3 origin, glm::vec3 direction, const WorldAABB &box, float maxDistance, float &outDistance, glm::vec3 &outNormal)
Ray vs axis-aligned box intersection (slab method).
Definition Raycast.hpp:41
HitscanHit resolveHitscan(Registry &registry, entt::entity shooter, glm::vec3 origin, glm::vec3 direction)
Full hitscan resolution: world geometry first, then players (closest wins).
Definition Raycast.hpp:167
HitscanHit raycastWorld(glm::vec3 origin, glm::vec3 direction, const WorldGeometry &world)
Raycast against all static world geometry (planes + boxes).
Definition Raycast.hpp:92
constexpr float k_parallelEpsilon
Epsilon for parallel-ray checks.
Definition Raycast.hpp:27
Axis-aligned bounding box defined by half-extents from the entity's Position.
Definition CollisionShape.hpp:16
glm::vec3 halfExtents
AABB half-dimensions (units).
Definition CollisionShape.hpp:17
World-space position of an entity, in game units.
Definition Position.hpp:10
glm::vec3 value
XYZ position (Y-up, Quake units).
Definition Position.hpp:11
Result of a hitscan raycast.
Definition Raycast.hpp:31
SurfaceType surface
Definition Raycast.hpp:36
bool hit
Definition Raycast.hpp:32
float distance
Definition Raycast.hpp:33
glm::vec3 normal
Definition Raycast.hpp:35
glm::vec3 point
Definition Raycast.hpp:34
entt::entity entity
Definition Raycast.hpp:37
An infinite plane dividing free space from solid geometry.
Definition SweptCollision.hpp:23
An axis-aligned box in world space, used as static collision geometry.
Definition SweptCollision.hpp:30
glm::vec3 max
Maximum corner (highest x, y, z).
Definition SweptCollision.hpp:32
glm::vec3 min
Minimum corner (lowest x, y, z).
Definition SweptCollision.hpp:31
All world collision geometry for one tick.
Definition SweptCollision.hpp:48
std::span< const Plane > planes
Definition SweptCollision.hpp:49
std::span< const WorldAABB > boxes
Definition SweptCollision.hpp:50