载入中...
搜索中...
未找到
MeshBuild.cpp
浏览该文件的文档.
1#include "procgen/MeshBuild.h"
2
3#include <algorithm>
4#include <cmath>
5
6namespace eve::procgen {
7
9 positions_.clear();
10 normals_.clear();
11 uvs_.clear();
12 colors_.clear();
13 indices_.clear();
14 triangleGroups_.clear();
15 groupNames_.clear();
16 activeGroup_ = -1;
17 meta_.clear();
18}
19
21 if (vertexCount > 0) {
22 positions_.reserve(size_t(vertexCount) * 3u);
23 normals_.reserve(size_t(vertexCount) * 3u);
24 uvs_.reserve(size_t(vertexCount) * 2u);
25 if (!colors_.empty()) colors_.reserve(size_t(vertexCount) * 4u);
26 }
27 if (indexCount > 0) {
28 indices_.reserve(size_t(indexCount));
29 triangleGroups_.reserve(size_t(indexCount) / 3u);
30 }
31}
32
33void MeshBuild::addVertex(float px, float py, float pz, float nx, float ny, float nz, float u,
34 float v) {
35 positions_.push_back(px);
36 positions_.push_back(py);
37 positions_.push_back(pz);
38 normals_.push_back(nx);
39 normals_.push_back(ny);
40 normals_.push_back(nz);
41 uvs_.push_back(u);
42 uvs_.push_back(v);
43 if (!colors_.empty()) colors_.insert(colors_.end(), {1.f, 1.f, 1.f, 1.f});
44}
45
46void MeshBuild::addTriangle(uint32_t i0, uint32_t i1, uint32_t i2) {
47 indices_.push_back(i0);
48 indices_.push_back(i1);
49 indices_.push_back(i2);
50 triangleGroups_.push_back(activeGroup_);
51}
52
53int MeshBuild::setActiveGroup(const std::string &name) {
54 if (name.empty()) { activeGroup_ = -1; return -1; }
55 for (int i = 0; i < int(groupNames_.size()); ++i) {
56 if (groupNames_[size_t(i)] == name) { activeGroup_ = i; return i; }
57 }
58 groupNames_.push_back(name);
59 activeGroup_ = int(groupNames_.size()) - 1;
60 return activeGroup_;
61}
62
63int MeshBuild::getGroupCount() const { return int(groupNames_.size()); }
64
65std::string MeshBuild::getGroupName(int groupIndex) const {
66 if (groupIndex < 0 || groupIndex >= getGroupCount()) return {};
67 return groupNames_[size_t(groupIndex)];
68}
69
70int MeshBuild::getTriangleGroup(int triangleIndex) const {
71 if (triangleIndex < 0 || triangleIndex >= int(triangleGroups_.size())) return -1;
72 return triangleGroups_[size_t(triangleIndex)];
73}
74
75eve::Result<void> MeshBuild::restoreGroupData(std::vector<std::string> names, std::vector<int> assignments,
76 int activeGroup) {
77 const auto invalid = [&](std::string message, std::string path) {
80 };
81 if (assignments.size() != indices_.size() / 3u || activeGroup < -1 ||
82 activeGroup >= static_cast<int>(names.size()) ||
83 std::any_of(names.begin(), names.end(), [](const std::string &name) { return name.empty(); }) ||
84 std::any_of(assignments.begin(), assignments.end(),
85 [&](int group) { return group < -1 || group >= static_cast<int>(names.size()); }))
86 return invalid("mesh group sidecar is inconsistent with dense mesh streams", "groups");
87 groupNames_ = std::move(names);
88 triangleGroups_ = std::move(assignments);
89 activeGroup_ = activeGroup;
91}
92
93std::unique_ptr<MeshBuild> MeshBuild::copyGroup(int groupIndex) const {
94 if (groupIndex < 0 || groupIndex >= getGroupCount()) return {};
95 auto result = std::make_unique<MeshBuild>();
96 result->setActiveGroup(groupNames_[size_t(groupIndex)]);
97 std::unordered_map<uint32_t, uint32_t> remap;
98 std::vector<float> copiedColors;
99 for (int t = 0; t < int(triangleGroups_.size()); ++t) {
100 if (triangleGroups_[size_t(t)] != groupIndex) continue;
101 uint32_t dst[3];
102 for (int corner = 0; corner < 3; ++corner) {
103 const uint32_t src = indices_[size_t(t) * 3u + size_t(corner)];
104 auto found = remap.find(src);
105 if (found == remap.end()) {
106 const uint32_t next = uint32_t(result->getVertexCount());
107 result->addVertex(getPositionX(int(src)), getPositionY(int(src)), getPositionZ(int(src)),
108 getNormalX(int(src)), getNormalY(int(src)), getNormalZ(int(src)),
109 getUvU(int(src)), getUvV(int(src)));
110 if (hasVertexColors())
111 for (int component = 0; component < 4; ++component)
112 copiedColors.push_back(getColor(int(src), component));
113 remap.emplace(src, next); dst[corner] = next;
114 } else dst[corner] = found->second;
115 }
116 result->addTriangle(dst[0], dst[1], dst[2]);
117 }
118 if (result->empty()) return {};
119 if (!copiedColors.empty()) result->setVertexColors(std::move(copiedColors)).ignore("validated copied color stream");
120 result->meta_ = meta_;
121 result->setMeta("group", groupNames_[size_t(groupIndex)]);
122 return result;
123}
124
125bool MeshBuild::appendTransformed(const MeshBuild *other, float tx, float ty, float tz,
126 float yawDegrees, float sx, float sy, float sz) {
127 if (!other || other == this || other->empty() || std::fabs(sx) < 1e-8f ||
128 std::fabs(sy) < 1e-8f || std::fabs(sz) < 1e-8f)
129 return false;
130 const uint32_t base = uint32_t(getVertexCount());
131 if (other->hasVertexColors() && !hasVertexColors()) colors_.assign(std::size_t(base) * 4u, 1.f);
132 std::vector<int> groupMap(size_t(other->getGroupCount()), -1);
133 const int previousGroup = activeGroup_;
134 for (int i = 0; i < other->getGroupCount(); ++i)
135 groupMap[size_t(i)] = setActiveGroup(other->getGroupName(i));
137 const float radians = yawDegrees * 0.01745329251994329577f;
138 const float c = std::cos(radians), s = std::sin(radians);
139 for (int i = 0; i < other->getVertexCount(); ++i) {
140 const float px = other->getPositionX(i) * sx;
141 const float py = other->getPositionY(i) * sy;
142 const float pz = other->getPositionZ(i) * sz;
143 const float ix = other->getNormalX(i) / sx;
144 const float iy = other->getNormalY(i) / sy;
145 const float iz = other->getNormalZ(i) / sz;
146 float nx = c * ix + s * iz;
147 float ny = iy;
148 float nz = -s * ix + c * iz;
149 const float nl = std::sqrt(nx * nx + ny * ny + nz * nz);
150 if (nl > 1e-8f) { nx /= nl; ny /= nl; nz /= nl; }
151 addVertex(c * px + s * pz + tx, py + ty, -s * px + c * pz + tz,
152 nx, ny, nz, other->getUvU(i), other->getUvV(i));
153 if (other->hasVertexColors())
154 for (int component = 0; component < 4; ++component)
155 colors_[colors_.size() - 4u + std::size_t(component)] = other->getColor(i, component);
156 }
157 const bool mirrored = (sx * sy * sz) < 0.f;
158 for (int i = 0; i + 2 < other->getIndexCount(); i += 3) {
159 const int sourceGroup = other->getTriangleGroup(i / 3);
160 activeGroup_ = sourceGroup >= 0 ? groupMap[size_t(sourceGroup)] : -1;
161 const uint32_t a = base + uint32_t(other->getIndex(i));
162 const uint32_t b = base + uint32_t(other->getIndex(i + 1));
163 const uint32_t cidx = base + uint32_t(other->getIndex(i + 2));
164 if (mirrored) addTriangle(a, cidx, b); else addTriangle(a, b, cidx);
165 }
166 activeGroup_ = previousGroup;
167 return true;
168}
169
170int MeshBuild::getVertexCount() const { return int(positions_.size() / 3u); }
171int MeshBuild::getIndexCount() const { return int(indices_.size()); }
172bool MeshBuild::empty() const { return positions_.empty() || indices_.empty(); }
173
174float MeshBuild::getPositionX(int i) const {
175 if (i < 0 || i >= getVertexCount()) return 0.f;
176 return positions_[size_t(i) * 3u];
177}
178float MeshBuild::getPositionY(int i) const {
179 if (i < 0 || i >= getVertexCount()) return 0.f;
180 return positions_[size_t(i) * 3u + 1u];
181}
182float MeshBuild::getPositionZ(int i) const {
183 if (i < 0 || i >= getVertexCount()) return 0.f;
184 return positions_[size_t(i) * 3u + 2u];
185}
186float MeshBuild::getNormalX(int i) const {
187 if (i < 0 || i >= getVertexCount()) return 0.f;
188 return normals_[size_t(i) * 3u];
189}
190float MeshBuild::getNormalY(int i) const {
191 if (i < 0 || i >= getVertexCount()) return 0.f;
192 return normals_[size_t(i) * 3u + 1u];
193}
194float MeshBuild::getNormalZ(int i) const {
195 if (i < 0 || i >= getVertexCount()) return 0.f;
196 return normals_[size_t(i) * 3u + 2u];
197}
198float MeshBuild::getUvU(int i) const {
199 if (i < 0 || i >= getVertexCount()) return 0.f;
200 return uvs_[size_t(i) * 2u];
201}
202float MeshBuild::getUvV(int i) const {
203 if (i < 0 || i >= getVertexCount()) return 0.f;
204 return uvs_[size_t(i) * 2u + 1u];
205}
206bool MeshBuild::hasVertexColors() const noexcept {
207 return !colors_.empty() && colors_.size() == std::size_t(getVertexCount()) * 4u;
208}
209float MeshBuild::getColor(int vertexIndex, int component) const noexcept {
210 if (!hasVertexColors() || vertexIndex < 0 || vertexIndex >= getVertexCount() || component < 0 || component > 3)
211 return 1.f;
212 return colors_[std::size_t(vertexIndex) * 4u + std::size_t(component)];
213}
215 if (!colors.empty() && colors.size() != std::size_t(getVertexCount()) * 4u)
217 "mesh vertex color count must match the vertex count", "colors", {}, "procgen.mesh"));
218 if (std::any_of(colors.begin(), colors.end(), [](float value) { return !std::isfinite(value); }))
220 "mesh vertex colors must be finite", "colors", {}, "procgen.mesh"));
221 colors_ = std::move(colors);
223}
224eve::Result<void> MeshBuild::setColor(int vertexIndex, float r, float g, float b, float a) {
225 if (vertexIndex < 0 || vertexIndex >= getVertexCount())
227 "mesh vertex index is out of range", "vertexIndex", {}, "procgen.mesh"));
228 if (!std::isfinite(r) || !std::isfinite(g) || !std::isfinite(b) || !std::isfinite(a))
230 "mesh vertex color components must be finite", "color", {}, "procgen.mesh"));
231 if (!hasVertexColors()) colors_.assign(std::size_t(getVertexCount()) * 4u, 1.f);
232 const auto base = std::size_t(vertexIndex) * 4u;
233 colors_[base] = r;
234 colors_[base + 1u] = g;
235 colors_[base + 2u] = b;
236 colors_[base + 3u] = a;
238}
239int MeshBuild::getIndex(int i) const {
240 if (i < 0 || i >= getIndexCount()) return 0;
241 return int(indices_[size_t(i)]);
242}
243
244void MeshBuild::setMeta(const std::string &key, const std::string &value) { meta_[key] = value; }
245
246std::string MeshBuild::getMeta(const std::string &key, const std::string &defaultValue) const {
247 auto it = meta_.find(key);
248 return it == meta_.end() ? defaultValue : it->second;
249}
250
251} // namespace eve::procgen
double value
const std::string & s
building::EdgeCurveGroup group
float py
float nx
float nz
float ny
float pz
std::string message
std::uint32_t vertexCount
std::uint32_t indexCount
tensor::Graph g
Definition GpuGraph.cpp:7
std::uint32_t key
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
double r
float v
std::int32_t c
std::vector< Colorf > px
std::string name
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
std::string path
Definition PlayHost.cpp:110
float t
std::unordered_map< std::uint32_t, std::uint32_t > remap
std::vector< float > colors
bool found
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
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
Definition Status.h:81
CPU triangle mesh from procedural mesh recipes (e.g. marching cubes). Positions/normals are xyz-packe...
Definition MeshBuild.h:19
float getPositionZ(int i) const
Returns the position z.
eve::Result< void > setColor(int vertexIndex, float r, float g, float b, float a)
Set one vertex RGBA (allocates a default-white stream if absent).
float getPositionY(int i) const
Returns the position y.
std::string getMeta(const std::string &key, const std::string &defaultValue) const
Returns the meta.
void addVertex(float px, float py, float pz, float nx, float ny, float nz, float u, float v)
Adds vertex.
Definition MeshBuild.cpp:33
void addTriangle(uint32_t i0, uint32_t i1, uint32_t i2)
Adds triangle.
Definition MeshBuild.cpp:46
std::unique_ptr< MeshBuild > copyGroup(int groupIndex) const
Copies one named group into a standalone compact mesh.
Definition MeshBuild.cpp:93
float getNormalZ(int i) const
Returns the normal z.
int getGroupCount() const
Number of named triangle groups.
Definition MeshBuild.cpp:63
void reserve(int vertexCount, int indexCount)
Reserve.
Definition MeshBuild.cpp:20
void setMeta(const std::string &key, const std::string &value)
Sets the meta.
int setActiveGroup(const std::string &name)
Select/create the named group assigned to subsequently added triangles.
Definition MeshBuild.cpp:53
const std::vector< float > & colors() const
Colors.
Definition MeshBuild.h:131
float getNormalY(int i) const
Returns the normal y.
int getIndexCount() const
Returns the index count.
eve::Result< void > setVertexColors(std::vector< float > colors)
Atomically replace the optional packed RGBA stream; empty removes it.
eve::Result< void > restoreGroupData(std::vector< std::string > names, std::vector< int > assignments, int activeGroup)
Restore the complete group sidecar after dense streams are loaded.
Definition MeshBuild.cpp:75
int getTriangleGroup(int triangleIndex) const
Group index for a triangle (not an index-buffer element), or -1.
Definition MeshBuild.cpp:70
float getUvU(int i) const
Returns the uv u.
float getColor(int vertexIndex, int component) const noexcept
Return one color component, or 1 for an invalid vertex/component or an absent color stream.
bool empty() const
Empty.
bool appendTransformed(const MeshBuild *other, float tx, float ty, float tz, float yawDegrees, float sx, float sy, float sz)
Append another procedural mesh after an affine transform.
void clear()
Clears .
Definition MeshBuild.cpp:8
int activeGroup() const
Return the currently selected group, or -1 when none is active.
Definition MeshBuild.h:64
float getUvV(int i) const
Returns the uv v.
float getNormalX(int i) const
Returns the normal x.
int getIndex(int i) const
std::string getGroupName(int groupIndex) const
Group name, or an empty string for an invalid index.
Definition MeshBuild.cpp:65
bool hasVertexColors() const noexcept
Return whether this mesh owns one packed RGBA color per vertex.
float getPositionX(int i) const
Returns the position x.
const char * defaultValue
Result< int > invalid(std::string message)
Invalid.
@ ProcgenGroupDataInvalid
Mesh group sidecar data is inconsistent with its dense streams.