载入中...
搜索中...
未找到
ObstacleField.cpp
浏览该文件的文档.
2
3#include "common/Assert.h"
4
5#include <algorithm>
6#include <cmath>
7
8namespace eve::gpuagents {
9namespace {
10
11float lengthSafe(const glm::vec3& v, float fallback = 1.f) {
12 const float len = glm::length(v);
13 return len > 1e-6f ? len : fallback;
14}
15
16glm::vec3 normalizeSafe(const glm::vec3& v, const glm::vec3& fallback = glm::vec3(0.f, 1.f, 0.f)) {
17 const float len = glm::length(v);
18 return len > 1e-6f ? v / len : fallback;
19}
20
21} // namespace
22
24 dims = {0, 0, 0};
25 distances.clear();
26 dynamicSources.clear();
27}
28
29void ObstacleField::bakeEmpty(const glm::vec3& originMin, const glm::ivec3& d, float cs, float fillDistance) {
30 EV_PARAM_CHECK(d.x > 0);
31 EV_PARAM_CHECK(d.y > 0);
32 EV_PARAM_CHECK(d.z > 0);
33 EV_PARAM_CHECK(cs > 0.f);
34 origin = originMin;
35 cellSize = cs;
36 dims = d;
37 distances.assign(static_cast<size_t>(d.x) * static_cast<size_t>(d.y) * static_cast<size_t>(d.z), fillDistance);
38}
39
40void ObstacleField::carveSphere(const glm::vec3& center, float radius) {
42 EV_PARAM_CHECK(radius >= 0.f);
43 for (int z = 0; z < dims.z; ++z) {
44 for (int y = 0; y < dims.y; ++y) {
45 for (int x = 0; x < dims.x; ++x) {
46 const glm::vec3 p = origin + cellSize * (glm::vec3(x, y, z) + 0.5f);
47 const float d = glm::length(p - center) - radius;
48 const size_t i = static_cast<size_t>(x + dims.x * (y + dims.y * z));
49 distances[i] = std::min(distances[i], d);
50 }
51 }
52 }
53}
54
55void ObstacleField::carveBox(const glm::vec3& minCorner, const glm::vec3& maxCorner) {
57 for (int z = 0; z < dims.z; ++z) {
58 for (int y = 0; y < dims.y; ++y) {
59 for (int x = 0; x < dims.x; ++x) {
60 const glm::vec3 p = origin + cellSize * (glm::vec3(x, y, z) + 0.5f);
61 const glm::vec3 q = glm::max(minCorner - p, p - maxCorner);
62 const float d =
63 glm::length(glm::max(q, glm::vec3(0.f))) + std::min(std::max({q.x, q.y, q.z}), 0.f);
64 const size_t i = static_cast<size_t>(x + dims.x * (y + dims.y * z));
65 distances[i] = std::min(distances[i], d);
66 }
67 }
68 }
69}
70
71void ObstacleField::setDynamicSources(std::vector<DynamicObstacleSource> sources) {
72 dynamicSources = std::move(sources);
73}
74
75float ObstacleField::sampleStatic(const glm::vec3& p) const {
76 if (!hasStaticGrid()) return 1e6f;
77 const glm::vec3 local = (p - origin) / cellSize - 0.5f;
78 const glm::vec3 f = glm::floor(local);
79 const glm::vec3 t = local - f;
80 const auto idx = [&](int x, int y, int z) -> float {
81 x = std::clamp(x, 0, dims.x - 1);
82 y = std::clamp(y, 0, dims.y - 1);
83 z = std::clamp(z, 0, dims.z - 1);
84 return distances[static_cast<size_t>(x + dims.x * (y + dims.y * z))];
85 };
86 const int x0 = static_cast<int>(f.x);
87 const int y0 = static_cast<int>(f.y);
88 const int z0 = static_cast<int>(f.z);
89 const float c000 = idx(x0, y0, z0);
90 const float c100 = idx(x0 + 1, y0, z0);
91 const float c010 = idx(x0, y0 + 1, z0);
92 const float c110 = idx(x0 + 1, y0 + 1, z0);
93 const float c001 = idx(x0, y0, z0 + 1);
94 const float c101 = idx(x0 + 1, y0, z0 + 1);
95 const float c011 = idx(x0, y0 + 1, z0 + 1);
96 const float c111 = idx(x0 + 1, y0 + 1, z0 + 1);
97 const float c00 = c000 * (1.f - t.x) + c100 * t.x;
98 const float c10 = c010 * (1.f - t.x) + c110 * t.x;
99 const float c01 = c001 * (1.f - t.x) + c101 * t.x;
100 const float c11 = c011 * (1.f - t.x) + c111 * t.x;
101 const float c0 = c00 * (1.f - t.y) + c10 * t.y;
102 const float c1 = c01 * (1.f - t.y) + c11 * t.y;
103 return c0 * (1.f - t.z) + c1 * t.z;
104}
105
106glm::vec3 ObstacleField::gradientStatic(const glm::vec3& p) const {
107 const float e = cellSize * 0.5f;
108 const float dx = sampleStatic(p + glm::vec3(e, 0.f, 0.f)) - sampleStatic(p - glm::vec3(e, 0.f, 0.f));
109 const float dy = sampleStatic(p + glm::vec3(0.f, e, 0.f)) - sampleStatic(p - glm::vec3(0.f, e, 0.f));
110 const float dz = sampleStatic(p + glm::vec3(0.f, 0.f, e)) - sampleStatic(p - glm::vec3(0.f, 0.f, e));
111 return normalizeSafe(glm::vec3(dx, dy, dz));
112}
113
114ObstacleSample ObstacleField::sampleDynamic(const glm::vec3& p) const {
115 ObstacleSample best;
116 best.distance = 1e6f;
117 for (const auto& s : dynamicSources) {
118 const glm::vec3 d = p - s.center;
119 const float len = lengthSafe(d);
120 const float dist = len - s.radius;
121 if (dist < best.distance) {
122 best.distance = dist;
123 best.gradient = normalizeSafe(d);
124 }
125 }
126 return best;
127}
128
129ObstacleSample ObstacleField::sample(const glm::vec3& p) const {
130 ObstacleSample out;
131 out.distance = sampleStatic(p);
132 out.gradient = gradientStatic(p);
133 const ObstacleSample dyn = sampleDynamic(p);
134 if (dyn.distance < out.distance) {
135 out = dyn;
136 }
137 return out;
138}
139
140void ObstacleField::resolve(glm::vec3& position, glm::vec3& velocity, float agentRadius, float predictTime) const {
141 const ObstacleSample now = sample(position);
142 const ObstacleSample pred = sample(position + velocity * std::max(predictTime, 0.f));
143 const ObstacleSample& hit = pred.distance < now.distance ? pred : now;
144 if (hit.distance >= agentRadius) return;
145
146 const glm::vec3 n = normalizeSafe(hit.gradient);
147 const float pen = agentRadius - hit.distance;
148 position += n * pen;
149
150 const float vn = glm::dot(velocity, n);
151 if (vn < 0.f) {
152 velocity -= n * vn; // keep tangential, cancel inward normal
153 }
154}
155
156} // namespace eve::gpuagents
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
EVEngine assertion entry point, backed by zeroerr.
#define EV_PARAM_CHECK(cond,...)
Validate a function parameter / public API precondition.
Definition Assert.h:30
const std::string & s
glm::vec4 p[6]
glm::vec3 n
Definition Grass.cpp:63
std::array< double, 10 > q
float v
std::string local
std::array< float, 3 > position
int idx
float f
float radius
bool hit
float d
float t
float dz
float dy
float dx
std::map< Cell, int > best
void setDynamicSources(std::vector< DynamicObstacleSource > sources)
Replace the dynamic obstacle list.
void bakeEmpty(const glm::vec3 &originMin, const glm::ivec3 &dims, float cellSize, float fillDistance=10.f)
Bake an empty (all free) box field.
void carveBox(const glm::vec3 &minCorner, const glm::vec3 &maxCorner)
Carve a solid axis-aligned box (min with existing).
ObstacleSample sample(const glm::vec3 &p) const
Sample combined static+dynamic distance and gradient at p.
bool hasStaticGrid() const
True when a static grid is allocated.
void carveSphere(const glm::vec3 &center, float radius)
Carve a solid sphere into the static grid (min with existing).
void clear()
Clear static grid and dynamic sources.
std::vector< float > distances
std::vector< DynamicObstacleSource > dynamicSources
void resolve(glm::vec3 &position, glm::vec3 &velocity, float agentRadius, float predictTime) const
Push an agent out of obstacles and keep feasible tangential velocity.
One SDF sample with outward gradient.