载入中...
搜索中...
未找到
PetalSolver.cpp
浏览该文件的文档.
2
3#include "common/Assert.h"
4
5#include <algorithm>
6#include <cmath>
7
8namespace eve::gpuagents {
9namespace {
10
12constexpr int kSettled = 0;
13constexpr int kScale = 1;
14constexpr int kSpin = 3;
15
16} // namespace
17
18void PetalSolver::step(std::span<const AgentState> read, std::span<AgentState> write, const EffectProfile& profile,
19 const EnvironmentSnapshot& env, float dt) {
21 EV_PARAM_CHECK(read.size() == write.size());
22 const PetalProfile& p = profile.petal;
23
24 for (size_t i = 0; i < read.size(); ++i) {
25 const AgentState& in = read[i];
26 if (in.alive == 0) {
27 write[i] = in;
28 continue;
29 }
30
31 AgentState out = in;
32 const float scale = in.customData[kScale] > 1e-4f ? in.customData[kScale] : 1.f;
33 const float length = p.length * scale;
34 const float width = p.width * scale;
35 const float mass = std::max(p.mass * scale, 1e-5f);
36
37 if (in.customData[kSettled] > 0.5f) {
38 out.velocity *= 0.9f;
39 out.position.y = p.groundY + length * 0.02f;
40 out.age += dt;
41 if (out.age > p.lifetime) {
42 out.position =
43 glm::vec3(glm::mix(p.worldMin.x, p.worldMax.x, 0.5f), p.worldMax.y * 0.8f,
44 glm::mix(p.worldMin.z, p.worldMax.z, 0.5f));
45 out.velocity = env.windVelocity * 0.5f + glm::vec3(0.f, -0.5f, 0.f);
46 out.age = 0.f;
47 out.customData[kSettled] = 0.f;
48 }
49 write[i] = out;
50 continue;
51 }
52
53 const glm::mat3 R = rotationMatrix(in.rotation);
54 const glm::vec3 normal = R[1];
55 const glm::vec3 edge = R[0];
56
57 glm::vec3 wind = env.windVelocity;
58 if (env.obstacles) {
59 for (const auto& src : env.obstacles->dynamicSources) {
60 const glm::vec3 d = in.position - src.center;
61 const float dist = glm::length(d);
62 if (dist < src.radius * 3.f && dist > 1e-4f) {
63 const glm::vec3 tangential = glm::cross(d, glm::vec3(0.f, 1.f, 0.f));
64 if (glm::length(tangential) > 1e-4f) {
65 wind += glm::normalize(tangential) * (1.5f / dist);
66 }
67 }
68 }
69 }
70
71 const glm::vec3 rel = in.velocity - wind;
72 const float speed = glm::length(rel);
73 const glm::vec3 relDir = speed > 1e-5f ? rel / speed : glm::vec3(0.f, -1.f, 0.f);
74
75 const float areaFront = length * width;
76 const float areaEdge = length * p.thickness * scale;
77 const float cosA = std::abs(glm::dot(normal, relDir));
78 const float sinA = std::sqrt(std::max(0.f, 1.f - cosA * cosA));
79
80 glm::vec3 force = glm::vec3(0.f, -p.gravity * mass, 0.f);
81 force -= relDir * (0.5f * speed * speed * (p.frontalDrag * areaFront * cosA + p.edgeDrag * areaEdge * sinA));
82 glm::vec3 liftAxis = glm::cross(relDir, normal);
83 if (glm::length(liftAxis) > 1e-4f) {
84 liftAxis = glm::normalize(liftAxis);
85 force += glm::cross(liftAxis, relDir) * (p.liftCoeff * areaFront * speed * speed * sinA * 0.5f);
86 }
87
88 out.velocity = in.velocity + (force / mass) * dt;
89 out.position = in.position + out.velocity * dt;
90
91 const glm::vec3 lever = edge * (length * p.pressureCenterOffset);
92 const glm::vec3 torque = glm::cross(lever, force);
93 const float inertia = mass * (length * length + width * width) / 12.f;
94 float spin = in.customData[kSpin];
95 spin += (glm::length(torque) / std::max(inertia, 1e-8f) - p.angularDrag * spin) * dt;
96 spin = std::clamp(spin, -40.f, 40.f);
97 const glm::vec3 axis =
98 glm::length(torque) > 1e-6f ? glm::normalize(torque) : edge;
99 out.rotation = glm::normalize(glm::angleAxis(spin * dt, axis) * in.rotation);
100 out.customData[kSpin] = spin;
101 out.customData[kScale] = scale;
102 out.age = in.age + dt;
103
104 if (out.position.y <= p.groundY + length * 0.05f && out.velocity.y <= p.settleSpeed) {
105 out.position.y = p.groundY + length * 0.02f;
106 out.velocity.y = 0.f;
107 out.velocity.x *= 0.5f;
108 out.velocity.z *= 0.5f;
109 out.customData[kSettled] = 1.f;
110 }
111
112 const glm::vec3 pad(p.softBoundPadding);
113 const bool outOfBounds = out.position.x < p.worldMin.x - pad.x || out.position.y < p.worldMin.y - pad.y ||
114 out.position.z < p.worldMin.z - pad.z || out.position.x > p.worldMax.x + pad.x ||
115 out.position.y > p.worldMax.y + pad.y || out.position.z > p.worldMax.z + pad.z;
116 if (outOfBounds || out.age > p.lifetime) {
117 out.position = glm::vec3(glm::mix(p.worldMin.x + 1.f, p.worldMax.x - 1.f,
118 static_cast<float>((i * 17) % 100) / 100.f),
119 p.worldMax.y * 0.85f,
120 glm::mix(p.worldMin.z + 1.f, p.worldMax.z - 1.f,
121 static_cast<float>((i * 31) % 100) / 100.f));
122 out.velocity = env.windVelocity + glm::vec3(0.f, -1.f, 0.f);
123 out.age = 0.f;
124 out.customData[kSettled] = 0.f;
125 out.customData[kSpin] = 0.f;
126 }
127
128 if (env.obstacles) {
129 env.obstacles->resolve(out.position, out.velocity, p.base.agentRadius, p.base.obstaclePredictTime);
130 }
131 write[i] = out;
132 }
133}
134
135} // namespace eve::gpuagents
EVEngine assertion entry point, backed by zeroerr.
#define EV_PARAM_CHECK(cond,...)
Validate a function parameter / public API precondition.
Definition Assert.h:30
float length
Definition CaveMesh.cpp:94
glm::vec4 p[6]
std::uint32_t width
std::array< float, 3 > scale
Texture * normal
float d
const RoadEdge * edge
float inertia
Definition TreeMesh.cpp:309
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.
void step(std::span< const AgentState > read, std::span< AgentState > write, const EffectProfile &profile, const EnvironmentSnapshot &env, float dt) override
Step.
glm::mat3 rotationMatrix(const glm::quat &q)
Converts a quaternion to a 3x3 rotation matrix (column-major).
Definition AgentState.h:30
Standardized per-agent simulation output shared by all effect kinds.
Definition AgentState.h:12
glm::quat rotation
wxyz storage (glm default).
Definition AgentState.h:15
std::uint32_t alive
0 = recycled / inactive slot.
Definition AgentState.h:18
Type-erased profile bundle owned by an EffectBackend.
Read-only environment semantics prepared by GpuAgentWorld each tick.
Passive petal rigid-body aerodynamic parameters.
uint32_t pad[2]