载入中...
搜索中...
未找到
FlowerMesh.cpp
浏览该文件的文档.
2
3#include "common/Diagnostic.h"
4
5#include <algorithm>
6#include <cmath>
7#include <cstdint>
8#include <random>
9#include <vector>
10
11namespace eve::procgen {
12namespace {
13
14constexpr float kPi = 3.14159265358979323846f;
15
16// Atlas: left strip = stem green, right = petal face (masked alpha).
17constexpr float kStemUMin = 0.02f;
18constexpr float kStemUMax = 0.28f;
19constexpr float kPetalUMin = 0.38f;
20constexpr float kPetalUMax = 0.98f;
21
22struct V3 {
23 float x = 0.f, y = 0.f, z = 0.f;
24};
25
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; }
30V3 cross(V3 a, V3 b) {
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};
32}
33V3 norm(V3 a) {
34 const float n = std::sqrt(std::max(1e-12f, dot(a, a)));
35 return mul(a, 1.f / n);
36}
37
38float randomRange(std::mt19937 &rng, float lo, float hi) {
39 return std::uniform_real_distribution<float>(lo, hi)(rng);
40}
41
42void basisFor(V3 axis, V3 &right, V3 &forward) {
43 axis = norm(axis);
44 const V3 helper = std::fabs(axis.y) < 0.92f ? V3{0.f, 1.f, 0.f} : V3{1.f, 0.f, 0.f};
45 right = norm(cross(helper, axis));
46 forward = norm(cross(axis, right));
47}
48
49void addStem(MeshBuild &out, float height, float radius, int sides) {
50 const V3 a{0.f, 0.f, 0.f};
51 const V3 b{0.f, height, 0.f};
52 const uint32_t base = uint32_t(out.getVertexCount());
53 for (int ring = 0; ring < 2; ++ring) {
54 const V3 center = ring ? b : a;
55 const float r = ring ? radius * 0.55f : radius;
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));
63 }
64 }
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);
73 }
74}
75
77void addPetal(MeshBuild &out, V3 center, V3 outward, float length, float width, float roll) {
78 V3 right, up;
79 basisFor(outward, right, up);
80 // Tip points along outward; width along right; slight cup along up.
81 const float c = std::cos(roll), s = std::sin(roll);
82 const V3 axisX = add(mul(right, c), mul(up, s));
83 const V3 axisY = outward;
84 const V3 axisZ = norm(cross(axisX, axisY));
85
86 // Six-point lanceolate outline in petal local space (base at -0.5, tip at +0.5).
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};
89
90 const uint32_t base = uint32_t(out.getVertexCount());
91 for (int i = 0; i < 6; ++i) {
92 const V3 p = add(center, add(mul(axisX, kOutlineX[i] * width),
93 add(mul(axisY, kOutlineY[i] * length),
94 mul(axisZ, (0.5f - std::fabs(kOutlineY[i])) * width * 0.12f))));
95 const V3 n = axisZ;
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);
99 }
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)); // double-sided
103 }
104}
105
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; // hemisphere facing up
111 for (int x = 0; x < sides; ++x) {
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)};
115 const V3 p = {c.x + n.x * radius, c.y + n.y * radius, c.z + n.z * radius};
116 // Sample near petal centre (warm yellow in tex.flower).
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);
118 }
119 }
120 for (int y = 0; y < rings; ++y) {
121 for (int x = 0; x < sides; ++x) {
122 const int nx = (x + 1) % sides;
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);
129 }
130 }
131}
132
133} // namespace
134
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);
147
148 std::mt19937 rng(params.getSeed());
149 out.clear();
150
151 addStem(out, height, stemRadius, sides);
152
153 const V3 head{0.f, height, 0.f};
154 addCentre(out, head, petalWidth * 0.28f, 3, std::max(5, sides));
155
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),
160 std::sin(pitch) * std::sin(yaw)});
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));
165 }
166
167 out.setMeta("recipe", "mesh.flower");
168 out.setMeta("petals", std::to_string(petals));
169 out.setMeta("seed", std::to_string(params.getSeed()));
170 if (out.empty()) {
172 eve::DiagnosticCode::Failed, "mesh.flower: generated an empty mesh", "recipe"));
173 }
175}
176
177} // namespace eve::procgen
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
const std::string & s
float length
Definition CaveMesh.cpp:94
float nx
glm::vec4 p[6]
Stable, structured diagnostics shared by engine modules.
uint32_t i1
Definition Grass.cpp:61
uint32_t i2
Definition Grass.cpp:61
uint32_t i0
Definition Grass.cpp:61
float u
Definition Grass.cpp:233
glm::vec3 n
Definition Grass.cpp:63
double r
float v
HexVec3 up
HexVec3 right
std::int32_t c
std::uint32_t height
std::uint32_t width
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
float radius
float d
float t
float axisZ
Definition RockMesh.cpp:22
float axisY
Definition RockMesh.cpp:22
float axisX
Definition RockMesh.cpp:22
int sides
Definition TreeMesh.cpp:322
std::vector< double > phi
float angle
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 success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
CPU triangle mesh from procedural mesh recipes (e.g. marching cubes). Positions/normals are xyz-packe...
Definition MeshBuild.h:19
void setMeta(const std::string &key, const std::string &value)
Sets the meta.
bool empty() const
Empty.
void clear()
Clears .
Definition MeshBuild.cpp:8
Owning, typed generation parameters.
Definition Params.h:27
std::vector< ParamSpec > params
std::vector< double > forward(const Policy &p, const Observation &o)
Forward.
Definition Learning.h:65
double dot(const Vec2 &a, const Vec2 &b)
Dot.
Definition UrbanTypes.h:38
double cross(const Vec2 &a, const Vec2 &b)
Cross.
Definition UrbanTypes.h:36
eve::Result< void > generateFlowerMesh(const Params &params, MeshBuild &out)
Build a small accent flower (stem + radial petals + centre).
int axis(int64_t a, size_t rank)
Axis.