14constexpr float kPi = 3.14159265358979323846f;
17constexpr float kStemUMin = 0.02f;
18constexpr float kStemUMax = 0.28f;
19constexpr float kPetalUMin = 0.38f;
20constexpr float kPetalUMax = 0.98f;
23 float x = 0.f,
y = 0.f,
z = 0.f;
26V3 add(V3
a, V3
b) {
return {
a.x +
b.x,
a.y +
b.y,
a.z +
b.z}; }
27V3 sub(V3
a, V3
b) {
return {
a.x -
b.x,
a.y -
b.y,
a.z -
b.z}; }
28V3 mul(V3
a,
float s) {
return {
a.x *
s,
a.y *
s,
a.z *
s}; }
29float dot(V3
a, V3
b) {
return a.x *
b.x +
a.y *
b.y +
a.z *
b.z; }
31 return {
a.y *
b.z -
a.z *
b.y,
a.z *
b.x -
a.x *
b.z,
a.x *
b.y -
a.y *
b.x};
34 const float n = std::sqrt(std::max(1e-12f,
dot(
a,
a)));
35 return mul(
a, 1.f /
n);
38float randomRange(std::mt19937 &rng,
float lo,
float hi) {
39 return std::uniform_real_distribution<float>(lo, hi)(rng);
42void basisFor(V3 axis, V3 &
right, V3 &forward) {
44 const V3 helper = std::fabs(
axis.y) < 0.92f ? V3{0.f, 1.f, 0.f} : V3{1.f, 0.f, 0.f};
50 const V3
a{0.f, 0.f, 0.f};
52 const uint32_t base = uint32_t(out.getVertexCount());
53 for (
int ring = 0; ring < 2; ++ring) {
56 for (
int i = 0; i <
sides; ++i) {
57 const float t = float(i) / float(
sides);
58 const float angle =
t * 2.f * kPi;
59 const V3 radial{std::cos(
angle), 0.f, std::sin(
angle)};
60 const V3
p = add(
center, mul(radial,
r));
61 out.addVertex(
p.x,
p.y,
p.z, radial.x, radial.y, radial.z,
62 kStemUMin +
t * (kStemUMax - kStemUMin),
float(ring));
65 for (
int i = 0; i <
sides; ++i) {
66 const uint32_t
n = uint32_t((i + 1) %
sides);
67 const uint32_t
i0 = base + uint32_t(i);
68 const uint32_t
i1 = base +
n;
69 const uint32_t
i2 = base + uint32_t(
sides) + uint32_t(i);
70 const uint32_t i3 = base + uint32_t(
sides) +
n;
71 out.addTriangle(
i0,
i2,
i1);
72 out.addTriangle(
i1,
i2, i3);
81 const float c = std::cos(
roll),
s = std::sin(
roll);
83 const V3
axisY = outward;
87 constexpr float kOutlineX[6] = {0.f, -0.46f, -0.38f, 0.f, 0.38f, 0.46f};
88 constexpr float kOutlineY[6] = {-0.48f, -0.18f, 0.22f, 0.50f, 0.22f, -0.18f};
90 const uint32_t base = uint32_t(out.getVertexCount());
91 for (
int i = 0; i < 6; ++i) {
94 mul(
axisZ, (0.5f - std::fabs(kOutlineY[i])) *
width * 0.12f))));
96 const float u = kPetalUMin + (0.5f + kOutlineX[i] * 0.5f) * (kPetalUMax - kPetalUMin);
97 const float v = 0.5f + kOutlineY[i] * 0.5f;
98 out.addVertex(
p.x,
p.y,
p.z,
n.x,
n.y,
n.z,
u,
v);
100 for (
int i = 1; i < 5; ++i) {
101 out.addTriangle(base, base + uint32_t(i), base + uint32_t(i + 1));
102 out.addTriangle(base, base + uint32_t(i + 1), base + uint32_t(i));
106void addCentre(MeshBuild &out, V3
c,
float radius,
int rings,
int sides) {
107 const uint32_t base = uint32_t(out.getVertexCount());
108 for (
int y = 0;
y <= rings; ++
y) {
109 const float v = float(
y) / float(rings);
110 const float phi =
v * kPi * 0.55f;
112 const float u = float(
x) / float(
sides);
113 const float theta =
u * 2.f * kPi;
114 const V3
n = {std::sin(
phi) * std::cos(theta), std::cos(
phi), std::sin(
phi) * std::sin(theta)};
117 out.addVertex(
p.x,
p.y,
p.z,
n.x,
n.y,
n.z, 0.68f +
u * 0.12f, 0.45f +
v * 0.2f);
120 for (
int y = 0;
y < rings; ++
y) {
123 const uint32_t
a = base + uint32_t(
y *
sides +
x);
124 const uint32_t
b = base + uint32_t(
y *
sides +
nx);
125 const uint32_t c0 = base + uint32_t((
y + 1) *
sides +
x);
126 const uint32_t
d = base + uint32_t((
y + 1) *
sides +
nx);
127 out.addTriangle(
a, c0,
b);
128 out.addTriangle(
b, c0,
d);
136 const float height = std::clamp(
params.getFloat(
"height", 0.55f), 0.15f, 2.5f);
137 const float petalLength =
138 std::clamp(
params.getFloat(
"petalLength",
height * 0.38f), 0.05f, 1.2f);
139 const float petalWidth =
140 std::clamp(
params.getFloat(
"petalWidth", petalLength * 0.55f), 0.03f, 1.0f);
141 const int petals = std::clamp(
params.getInt(
"petals", 6), 3, 12);
142 const float stemRadius =
143 std::clamp(
params.getFloat(
"stemRadius",
height * 0.035f), 0.005f, 0.12f);
144 const float openAngle =
145 std::clamp(
params.getFloat(
"openAngle", 58.f), 20.f, 85.f) * kPi / 180.f;
146 const int sides = std::clamp(
params.getInt(
"sides", 6), 4, 16);
148 std::mt19937 rng(
params.getSeed());
153 const V3 head{0.f,
height, 0.f};
154 addCentre(out, head, petalWidth * 0.28f, 3, std::max(5,
sides));
156 for (
int i = 0; i < petals; ++i) {
157 const float yaw = (float(i) + randomRange(rng, -0.08f, 0.08f)) * (2.f * kPi /
float(petals));
158 const float pitch = openAngle + randomRange(rng, -0.12f, 0.12f);
159 const V3 outward = norm({std::sin(
pitch) * std::cos(
yaw), std::cos(
pitch),
161 const V3 base = add(head, mul(outward, petalWidth * 0.08f));
162 const float len = petalLength * randomRange(rng, 0.88f, 1.12f);
163 const float wid = petalWidth * randomRange(rng, 0.85f, 1.1f);
164 addPetal(out, base, outward, len, wid, randomRange(rng, -0.25f, 0.25f));
167 out.
setMeta(
"recipe",
"mesh.flower");
168 out.
setMeta(
"petals", std::to_string(petals));
Stable, structured diagnostics shared by engine modules.
std::vector< double > phi
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.
Move-only operation result carrying either a value or Status.
static Result success(T value)
Construct a successful result owning value.
static Result failure(Status status)
Construct a failed result from a structured status.
CPU triangle mesh from procedural mesh recipes (e.g. marching cubes). Positions/normals are xyz-packe...
void setMeta(const std::string &key, const std::string &value)
Sets the meta.
Owning, typed generation parameters.
std::vector< ParamSpec > params
std::vector< double > forward(const Policy &p, const Observation &o)
Forward.
double dot(const Vec2 &a, const Vec2 &b)
Dot.
double cross(const Vec2 &a, const Vec2 &b)
Cross.
eve::Result< void > generateFlowerMesh(const Params ¶ms, MeshBuild &out)
Build a small accent flower (stem + radial petals + centre).
int axis(int64_t a, size_t rank)
Axis.