载入中...
搜索中...
未找到
GpuAgents.cpp
浏览该文件的文档.
2
3#include "common/Diagnostic.h"
6
7#include <simplesquirrel/simplesquirrel.hpp>
8
9#include <cmath>
10#include <functional>
11#include <string>
12
13namespace eve::gpuagents {
14namespace {
15
16glm::vec3 unitFromIndex(int i, std::uint32_t seed) {
17 const float a = static_cast<float>((static_cast<std::uint32_t>(i) * 1103515245u + seed) & 0xFFFFu) / 65535.f;
18 const float b = static_cast<float>(((static_cast<std::uint32_t>(i) * 12345u) ^ seed) & 0xFFFFu) / 65535.f;
19 const float theta = a * 6.2831853f;
20 const float u = b * 2.f - 1.f;
21 const float r = std::sqrt(std::max(0.f, 1.f - u * u));
22 return glm::vec3(r * std::cos(theta), u, r * std::sin(theta));
23}
24
25} // namespace
26
28
32
33EffectProfile GpuAgents::makeProfile(int kind, int maxAgents) const {
34 switch (static_cast<EffectKind>(kind)) {
36 case EffectKind::Bird: return EffectProfile::makeBird(maxAgents);
37 case EffectKind::Petal: return EffectProfile::makePetal(maxAgents);
39 default: return EffectProfile::makeFish(maxAgents);
40 }
41}
42
44 auto backend = std::make_unique<EffectBackend>();
45 auto profile = makeProfile(kind, maxAgents);
46 auto cfg = backend->configure(profile);
47 if (!cfg.ok()) return nullptr;
48 return backend.release();
49}
50
51Result<void> GpuAgents::spawnCloud(EffectBackend* backend, int count, float centerX, float centerY, float centerZ,
52 float spread) const {
53 if (!backend) {
55 Diagnostic::error(DiagnosticCode::InvalidArgument, "backend is null", "backend", {}, "gpuagents"));
56 }
57 if (!backend->simulation().isConfigured()) {
59 "configure", {}, "gpuagents"));
60 }
61 const glm::vec3 center(centerX, centerY, centerZ);
62 const auto& base = backend->simulation().profile().base();
63 const EffectKind kind = backend->kind();
64 return backend->simulation().initialize(count, [&](int i) {
66 const glm::vec3 dir = unitFromIndex(i, base.seed);
67 s.position = center + dir * spread;
68 switch (kind) {
70 s.velocity = dir * 2.f;
71 break;
73 s.velocity = glm::normalize(dir + glm::vec3(0.f, 0.2f, 0.f)) * 6.f;
74 break;
76 s.velocity = glm::vec3(dir.x, -1.f, dir.z);
77 s.customData[1] = 0.75f + 0.5f * (static_cast<float>(i % 10) / 10.f);
78 s.rotation = lookRotation(glm::vec3(0.f, -1.f, 0.f));
79 break;
81 s.position.y = centerY;
82 s.velocity = glm::normalize(glm::vec3(dir.x, 0.f, dir.z) + glm::vec3(1e-3f, 0.f, 0.f)) * 1.5f;
83 break;
84 }
85 s.rotation = lookRotation(glm::length(s.velocity) > 1e-4f ? s.velocity : glm::vec3(0.f, 0.f, 1.f));
86 return s;
87 });
88}
89
91 const std::vector<std::uint32_t>& indices, float originX, float originY,
92 float originZ, float worldSize, int resolution) const {
93 if (!world) {
95 Diagnostic::error(DiagnosticCode::InvalidArgument, "world is null", "world", {}, "gpuagents"));
96 }
97 if (positions.size() % 3 != 0) {
99 DiagnosticCode::InvalidArgument, "positions must be interleaved xyz floats", "positions", {}, "gpuagents"));
100 }
101 std::vector<glm::vec3> verts;
102 verts.reserve(positions.size() / 3);
103 for (size_t i = 0; i + 2 < positions.size(); i += 3) {
104 verts.emplace_back(positions[i], positions[i + 1], positions[i + 2]);
105 }
106 return SurfaceCapture::captureFromTriangles(world->surface(), verts, indices, glm::vec3(originX, originY, originZ),
107 worldSize, resolution, originY);
108}
109
111 if (!world || !binding) {
113 Diagnostic::error(DiagnosticCode::InvalidArgument, "world or binding is null", "binding", {}, "gpuagents"));
114 }
115 return binding->syncFrom(world->surface());
116}
117
118void GpuAgents::expose(ssq::Table& table) {
119 auto cls = table.addClass(name, GpuAgents::create, false);
120 expose(cls);
121
122 auto world = table.addClass<GpuAgentWorld>(
123 "GpuAgentWorld", std::function<GpuAgentWorld*()>([]() -> GpuAgentWorld* { return nullptr; }), true);
124 world.addFunc("setWaterCurrent", &GpuAgentWorld::setWaterCurrent);
125 world.addFunc("setWind", &GpuAgentWorld::setWind);
126 world.addFunc("setVerticalBounds", &GpuAgentWorld::setVerticalBounds);
127 world.addFunc("backendCount", &GpuAgentWorld::backendCount);
128 world.addFunc("stepAll", [](GpuAgentWorld* w, float dt) {
129 if (!w) return false;
130 return w->stepAll(dt).ok();
131 });
132 world.addFunc("bakeEmptyObstacles",
133 [](GpuAgentWorld* w, float ox, float oy, float oz, int dx, int dy, int dz, float cell) {
134 if (!w) return;
135 w->obstacles().bakeEmpty(glm::vec3(ox, oy, oz), glm::ivec3(dx, dy, dz), cell);
136 });
137 world.addFunc("carveSphere", [](GpuAgentWorld* w, float x, float y, float z, float r) {
138 if (!w) return;
139 w->obstacles().carveSphere(glm::vec3(x, y, z), r);
140 });
141 world.addFunc("initFlatSurface", [](GpuAgentWorld* w, float ox, float oy, float oz, float size, int res) {
142 if (!w) return;
143 w->surface().initFlat(glm::vec3(ox, oy, oz), size, res, oy);
144 });
145
146 auto backend = table.addClass<EffectBackend>(
147 "GpuAgentEffectBackend", std::function<EffectBackend*()>([]() -> EffectBackend* { return nullptr; }), true);
148 backend.addFunc("kind", [](EffectBackend* b) { return b ? static_cast<int>(b->kind()) : -1; });
149 backend.addFunc("aliveCount", [](EffectBackend* b) { return b ? b->simulation().aliveCount() : 0; });
150 backend.addFunc("instanceCount", [](EffectBackend* b) { return b ? b->renderer().instanceCount() : 0; });
151 backend.addFunc("reset", [](EffectBackend* b) {
152 if (b) b->reset();
153 });
154 backend.addFunc("step", [](EffectBackend* b, GpuAgentWorld* w, float dt) {
155 if (!b || !w) return false;
156 const bool needSurface = b->kind() == EffectKind::LifeNetwork;
157 return b->step(dt, w->makeSnapshot(needSurface)).ok();
158 });
159}
160
161void GpuAgents::expose(ssq::Class& cls) {
162 cls.addFunc("newWorld", &GpuAgents::newWorld);
163 cls.addFunc("newBackend", &GpuAgents::newBackend);
164 cls.addFunc("spawnCloud", [](GpuAgents* m, EffectBackend* b, int count, float x, float y, float z, float spread) {
165 if (!m) return false;
166 return m->spawnCloud(b, count, x, y, z, spread).ok();
167 });
168 cls.addFunc("registerBackend", [](GpuAgents*, GpuAgentWorld* w, const std::string& name, EffectBackend* b) {
169 if (!w || !b) return false;
170 // Borrowed: script / VM retains ownership of the backend.
171 return w->registerBackend(name, b).ok();
172 });
173 cls.addFunc("captureSurface", [](GpuAgents* m, GpuAgentWorld* w, ssq::Array positions, ssq::Array indices, float ox,
174 float oy, float oz, float size, int res) {
175 if (!m || !w) return false;
176 std::vector<float> pos;
177 pos.reserve(positions.size());
178 for (size_t i = 0; i < positions.size(); ++i) pos.push_back(positions.get<float>(i));
179 std::vector<std::uint32_t> idx;
180 idx.reserve(indices.size());
181 for (size_t i = 0; i < indices.size(); ++i) idx.push_back(static_cast<std::uint32_t>(indices.get<int>(i)));
182 return m->captureSurface(w, pos, idx, ox, oy, oz, size, res).ok();
183 });
184}
185
186} // namespace eve::gpuagents
float w
Definition AnimClip.cpp:738
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
const std::string & s
std::vector< std::uint32_t > verts
Definition Builder.cpp:27
Stable, structured diagnostics shared by engine modules.
HSQOBJECT cls
Definition ECS.cpp:21
float u
Definition Grass.cpp:233
double r
std::vector< std::uint32_t > indices
std::vector< float > positions
TokenKind kind
std::string name
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
#define Module_IMPL(ModuleName, newExpr)
Definition Module.h:26
eve::action::ActionVfxBinding binding
int idx
World3D * world
std::uint32_t seed
Definition PointSet.cpp:807
float dz
float dy
float dx
std::uint32_t count
Cell cell
float size
Definition TreeMesh.cpp:156
V3 dir
Definition TreeMesh.cpp:150
double oy
double ox
float m[16]
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
Binds an EffectProfile to a GpuAgentSimulation and optional renderer.
EffectKind kind() const
Active effect kind.
GpuAgentSimulation & simulation()
Owned simulation.
const EffectProfile & profile() const
Bound profile.
Result< void > initialize(int count, const std::function< AgentState(int)> &spawnFn)
Spawn count alive agents using spawnFn(index) -> AgentState.
bool isConfigured() const
True after successful configure.
World-level registry for GPU agent simulations and environment semantics.
int backendCount() const
Number of registered backends.
void setWaterCurrent(float x, float y, float z)
Set uniform water current.
void setWind(float x, float y, float z)
Set uniform wind.
void setVerticalBounds(float groundY, float ceilingY)
Set ground / ceiling heights for bird clearance.
GPU Agents module — extensible fixed-step agent FX simulation.
Definition GpuAgents.h:29
Result< void > captureSurface(GpuAgentWorld *world, const std::vector< float > &positions, const std::vector< std::uint32_t > &indices, float originX, float originY, float originZ, float worldSize, int resolution) const
Orthographic triangle bake into a world's surface field.
Definition GpuAgents.cpp:90
EffectBackend * newBackend(int kind, int maxAgents)
Create a configured EffectBackend.
Definition GpuAgents.cpp:43
EffectProfile makeProfile(int kind, int maxAgents) const
Build a default EffectProfile value for script helpers.
Definition GpuAgents.cpp:33
GpuAgentWorld * newWorld()
Create an empty World. @ownership Caller / script VM owns the returned world; delete or let the VM fr...
Definition GpuAgents.cpp:29
Result< void > syncLifeFieldBinding(GpuAgentWorld *world, LifeFieldMaterialBinding *binding) const
Pack a world's surface into CPU LifeField / SurfaceData RGBA buffers.
Result< void > spawnCloud(EffectBackend *backend, int count, float centerX, float centerY, float centerZ, float spread) const
Spawn a simple school / flock / petal cloud into a backend.
Definition GpuAgents.cpp:51
Packs SurfaceField channels into Graphics-uploadable RGBA8 textures.
static Result< void > captureFromTriangles(SurfaceField &out, std::span< const glm::vec3 > positions, std::span< const std::uint32_t > indices, const glm::vec3 &originMin, float worldSize, int resolution, float baseHeight=0.f)
Bake triangle positions into out over the given XZ domain.
glm::quat lookRotation(const glm::vec3 &forward, const glm::vec3 &upHint=glm::vec3(0.f, 1.f, 0.f))
Builds a facing quaternion from a unit forward and approximate up.
Definition AgentState.h:36
EffectKind
Effect kind selecting the solver kernel.
Definition AgentState.h:22
std::unordered_map< std::string, SkillDefinition > & table()
Definition Skill.cpp:65
Standardized per-agent simulation output shared by all effect kinds.
Definition AgentState.h:12
Type-erased profile bundle owned by an EffectBackend.
static EffectProfile makePetal(int maxAgents=512)
Factory for a default petal profile.
const EffectProfileBase & base() const
Returns the shared base slice for the active kind.
static EffectProfile makeBird(int maxAgents=256)
Factory for a default bird profile.
static EffectProfile makeFish(int maxAgents=256)
Factory for a default fish profile.
static EffectProfile makeLife(int maxAgents=128, int resolution=64)
Factory for a default life-network profile.