VisuTwin Canvas
C++ 3D Engine — Metal Backend
Loading...
Searching...
No Matches
orientedBox.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2025-2026 Arnis Lektauers
3//
4// Created by Arnis Lektauers on 13.02.2026.
5//
6#include "orientedBox.h"
7
8#include <algorithm>
9#include <cmath>
10#include <limits>
11
12namespace visutwin::canvas
13{
14 OrientedBox::OrientedBox() : _halfExtents(0.5f), _aabb()
15 {
16 _aabb.setCenter(0.0f, 0.0f, 0.0f);
17 _aabb.setHalfExtents(_halfExtents);
18 }
19
21 : _halfExtents(halfExtents), _modelTransform(worldTransform.inverse()), _worldTransform(worldTransform), _aabb()
22 {
23 _aabb.setCenter(0.0f, 0.0f, 0.0f);
24 _aabb.setHalfExtents(_halfExtents);
25 }
26
28 {
29 _worldTransform = value;
30 _modelTransform = value.inverse();
31 }
32
34 {
35 _halfExtents = halfExtents;
36 _aabb.setHalfExtents(_halfExtents);
37 }
38
39 bool OrientedBox::intersectsLocalAabbRay(const Ray& localRay, Vector3* localPoint) const
40 {
41 const Vector3 min(-_halfExtents.getX(), -_halfExtents.getY(), -_halfExtents.getZ());
42 const Vector3 max(_halfExtents.getX(), _halfExtents.getY(), _halfExtents.getZ());
43 const Vector3 dir = localRay.direction();
44 const Vector3 origin = localRay.origin();
45
46 float txMin = min.getX() - origin.getX();
47 float txMax = max.getX() - origin.getX();
48 float tyMin = min.getY() - origin.getY();
49 float tyMax = max.getY() - origin.getY();
50 float tzMin = min.getZ() - origin.getZ();
51 float tzMax = max.getZ() - origin.getZ();
52
53 if (dir.getX() == 0.0f) {
54 txMin = txMin < 0.0f ? -std::numeric_limits<float>::max() : std::numeric_limits<float>::max();
55 txMax = txMax < 0.0f ? -std::numeric_limits<float>::max() : std::numeric_limits<float>::max();
56 } else {
57 txMin /= dir.getX();
58 txMax /= dir.getX();
59 }
60 if (dir.getY() == 0.0f) {
61 tyMin = tyMin < 0.0f ? -std::numeric_limits<float>::max() : std::numeric_limits<float>::max();
62 tyMax = tyMax < 0.0f ? -std::numeric_limits<float>::max() : std::numeric_limits<float>::max();
63 } else {
64 tyMin /= dir.getY();
65 tyMax /= dir.getY();
66 }
67 if (dir.getZ() == 0.0f) {
68 tzMin = tzMin < 0.0f ? -std::numeric_limits<float>::max() : std::numeric_limits<float>::max();
69 tzMax = tzMax < 0.0f ? -std::numeric_limits<float>::max() : std::numeric_limits<float>::max();
70 } else {
71 tzMin /= dir.getZ();
72 tzMax /= dir.getZ();
73 }
74
75 const Vector3 realMin(std::min(txMin, txMax), std::min(tyMin, tyMax), std::min(tzMin, tzMax));
76 const Vector3 realMax(std::max(txMin, txMax), std::max(tyMin, tyMax), std::max(tzMin, tzMax));
77
78 const float minMax = std::min(std::min(realMax.getX(), realMax.getY()), realMax.getZ());
79 const float maxMin = std::max(std::max(realMin.getX(), realMin.getY()), realMin.getZ());
80 const bool intersects = minMax >= maxMin && maxMin >= 0.0f;
81 if (intersects && localPoint) {
82 *localPoint = localRay.origin() + localRay.direction() * maxMin;
83 }
84 return intersects;
85 }
86
87 bool OrientedBox::fastIntersectsLocalAabbRay(const Ray& localRay) const
88 {
89 const Vector3 diff = localRay.origin() - Vector3(0.0f);
90 const Vector3 absDiff(std::abs(diff.getX()), std::abs(diff.getY()), std::abs(diff.getZ()));
91 const Vector3 prod(diff.getX() * localRay.direction().getX(), diff.getY() * localRay.direction().getY(),
92 diff.getZ() * localRay.direction().getZ());
93
94 if (absDiff.getX() > _halfExtents.getX() && prod.getX() >= 0.0f) {
95 return false;
96 }
97 if (absDiff.getY() > _halfExtents.getY() && prod.getY() >= 0.0f) {
98 return false;
99 }
100 if (absDiff.getZ() > _halfExtents.getZ() && prod.getZ() >= 0.0f) {
101 return false;
102 }
103
104 const Vector3 absDir(std::abs(localRay.direction().getX()), std::abs(localRay.direction().getY()),
105 std::abs(localRay.direction().getZ()));
106 Vector3 cross = localRay.direction().cross(diff);
107 cross = Vector3(std::abs(cross.getX()), std::abs(cross.getY()), std::abs(cross.getZ()));
108
109 if (cross.getX() > _halfExtents.getY() * absDir.getZ() + _halfExtents.getZ() * absDir.getY()) {
110 return false;
111 }
112 if (cross.getY() > _halfExtents.getX() * absDir.getZ() + _halfExtents.getZ() * absDir.getX()) {
113 return false;
114 }
115 if (cross.getZ() > _halfExtents.getX() * absDir.getY() + _halfExtents.getY() * absDir.getX()) {
116 return false;
117 }
118
119 return true;
120 }
121
122 Vector3 OrientedBox::closestPointOnLocalAabb(const Vector3& localPoint) const
123 {
124 return Vector3(
125 std::max(-_halfExtents.getX(), std::min(localPoint.getX(), _halfExtents.getX())),
126 std::max(-_halfExtents.getY(), std::min(localPoint.getY(), _halfExtents.getY())),
127 std::max(-_halfExtents.getZ(), std::min(localPoint.getZ(), _halfExtents.getZ()))
128 );
129 }
130
131 bool OrientedBox::intersectsRay(const Ray& ray, Vector3* point) const
132 {
133 Ray localRay;
134 localRay.set(_modelTransform.transformPoint(ray.origin()), ray.direction().transformNormal(_modelTransform));
135
136 if (point) {
137 Vector3 localPoint;
138 const bool intersects = intersectsLocalAabbRay(localRay, &localPoint);
139 if (intersects) {
140 *point = _worldTransform.transformPoint(localPoint);
141 }
142 return intersects;
143 }
144
145 return fastIntersectsLocalAabbRay(localRay);
146 }
147
148 bool OrientedBox::containsPoint(const Vector3& point) const
149 {
150 const Vector3 localPoint = _modelTransform.transformPoint(point);
151 return std::abs(localPoint.getX()) <= _halfExtents.getX() &&
152 std::abs(localPoint.getY()) <= _halfExtents.getY() &&
153 std::abs(localPoint.getZ()) <= _halfExtents.getZ();
154 }
155
157 {
158 const Vector3 localCenter = _modelTransform.transformPoint(sphere.center());
159 const Vector3 closest = closestPointOnLocalAabb(localCenter);
160 const Vector3 delta = localCenter - closest;
161 return delta.lengthSquared() <= sphere.radius() * sphere.radius();
162 }
163}
164
Bounding sphere defined by center and radius for intersection and containment tests.
const Vector3 & center() const
bool intersectsBoundingSphere(const BoundingSphere &sphere) const
bool containsPoint(const Vector3 &point) const
const Vector3 & halfExtents() const
Definition orientedBox.h:21
const Matrix4 & worldTransform() const
Definition orientedBox.h:19
void setHalfExtents(const Vector3 &halfExtents)
bool intersectsRay(const Ray &ray, Vector3 *point=nullptr) const
void setWorldTransform(const Matrix4 &value)
Infinite ray defined by origin and direction for raycasting and picking.
Definition ray.h:14
Ray & set(const Vector3 &origin, const Vector3 &direction)
Definition ray.cpp:18
const Vector3 & origin() const
Definition ray.h:19
const Vector3 & direction() const
Definition ray.h:21
4x4 column-major transformation matrix with SIMD acceleration.
Definition matrix4.h:31
Matrix4 inverse() const
3D vector for positions, directions, and normals with multi-backend SIMD acceleration.
Definition vector3.h:29
Vector3 transformNormal(const Matrix4 &mat) const
float lengthSquared() const
Definition vector3.h:233