载入中...
搜索中...
未找到
Mesh.cpp
浏览该文件的文档.
1#include "graphics/Mesh.h"
2
3#include <assimp/mesh.h>
4
5#include "graphics/Graphics.h"
6
7#include <algorithm>
8#include <cmath>
9
10namespace eve::graphics {
11Result<void> Mesh::setTexcoordSet(uint32_t set, std::span<const float> values) {
12 if (gpuVertexCount <= 0 || values.size() != size_t(gpuVertexCount) * 2 ||
13 std::any_of(values.begin(), values.end(), [](float x) { return !std::isfinite(x); }))
15 Diagnostic::error(DiagnosticCode::InvalidArgument, "UV channel must match mesh vertices"));
16 std::vector<float> owned(values.begin(), values.end());
17 texcoords_.insert_or_assign(set, std::move(owned));
18 ++texcoordRevision_;
19 return Result<void>::success();
20}
21std::span<const float> Mesh::texcoordSet(uint32_t set) const {
22 auto found = texcoords_.find(set);
23 return found == texcoords_.end() ? std::span<const float>{} : std::span<const float>(found->second);
24}
25
26
27namespace {
28const std::vector<float> kEmptyAttribute;
29}
30
32 importedUvs_.clear();
33 for (unsigned channel = 0; channel < mesh.GetNumUVChannels(); ++channel) {
34 if (!mesh.HasTextureCoords(channel)) continue;
35 std::vector<float> values;
36 values.reserve(size_t(mesh.mNumVertices) * 2u);
37 for (unsigned i = 0; i < mesh.mNumVertices; ++i) {
38 values.push_back(mesh.mTextureCoords[channel][i].x);
39 values.push_back(mesh.mTextureCoords[channel][i].y);
40 }
41 importedUvs_.push_back(std::move(values));
42 }
43 importedColors_.clear();
44 for (unsigned channel = 0; channel < mesh.GetNumColorChannels(); ++channel) {
45 if (!mesh.HasVertexColors(channel)) continue;
46 std::vector<float> values;
47 values.reserve(size_t(mesh.mNumVertices) * 4u);
48 for (unsigned i = 0; i < mesh.mNumVertices; ++i) {
49 const aiColor4D &c = mesh.mColors[channel][i];
50 values.insert(values.end(), {c.r, c.g, c.b, c.a});
51 }
52 importedColors_.push_back(std::move(values));
53 }
54 importedTangents_.clear();
55 importedBitangents_.clear();
56 if (mesh.HasTangentsAndBitangents()) {
57 importedTangents_.reserve(size_t(mesh.mNumVertices) * 3u);
58 importedBitangents_.reserve(size_t(mesh.mNumVertices) * 3u);
59 for (unsigned i = 0; i < mesh.mNumVertices; ++i) {
60 const aiVector3D &t = mesh.mTangents[i];
61 const aiVector3D &b = mesh.mBitangents[i];
62 importedTangents_.insert(importedTangents_.end(), {t.x, t.y, t.z});
63 importedBitangents_.insert(importedBitangents_.end(), {b.x, b.y, b.z});
64 }
65 }
66}
67
68const std::vector<float> &Mesh::importedUv(int channel) const {
69 return channel >= 0 && static_cast<size_t>(channel) < importedUvs_.size()
70 ? importedUvs_[static_cast<size_t>(channel)]
71 : kEmptyAttribute;
72}
73
74const std::vector<float> &Mesh::importedColor(int channel) const {
75 return channel >= 0 && static_cast<size_t>(channel) < importedColors_.size()
76 ? importedColors_[static_cast<size_t>(channel)]
77 : kEmptyAttribute;
78}
79
80Result<void> Mesh::setSkinPalette(const float* matrices, int matrixCount) {
81 if (!matrices || matrixCount <= 0 || static_cast<size_t>(matrixCount) > skinPalette_.max_size() / 16u)
83 const size_t count = static_cast<size_t>(matrixCount) * 16u;
84 for (size_t i = 0; i < count; ++i)
85 if (!std::isfinite(matrices[i]))
87 Diagnostic::error(DiagnosticCode::InvalidArgument, "Non-finite skin palette matrix"));
88 std::vector<float> replacement(matrices, matrices + count);
89 skinPalette_.swap(replacement);
90 return Result<void>::success();
91}
92
93void Mesh::computeBounds(const float *posXYZ, int vertexCount) {
94 boundsCx = 0.f;
95 boundsCy = 0.f;
96 boundsCz = 0.f;
97 boundsRadius = 0.f;
98 if (!posXYZ || vertexCount <= 0) return;
99
100 const size_t n = size_t(vertexCount);
101 glm::vec3 c(0.f);
102 for (size_t i = 0; i < n; ++i) {
103 c.x += posXYZ[i * 3u + 0u];
104 c.y += posXYZ[i * 3u + 1u];
105 c.z += posXYZ[i * 3u + 2u];
106 }
107 c /= float(n);
108 boundsCx = c.x;
109 boundsCy = c.y;
110 boundsCz = c.z;
111
112 float r = 0.f;
113 for (size_t i = 0; i < n; ++i) {
114 const float dx = posXYZ[i * 3u + 0u] - c.x;
115 const float dy = posXYZ[i * 3u + 1u] - c.y;
116 const float dz = posXYZ[i * 3u + 2u] - c.z;
117 const float d = std::sqrt(dx * dx + dy * dy + dz * dz);
118 if (d > r) r = d;
119 }
120 // Degenerate (single-point) meshes still get a tiny non-zero sphere so
121 // hasBounds() stays meaningful and the culler never drops point geometry.
122 boundsRadius = r > 0.f ? r : 1e-4f;
123}
124
125void Mesh::drawOcclusion(Graphics *gfx, const glm::mat4 &matrix) const {
126 if (!gfx || !getCastOcclusion()) return;
127 const float x = matrix[3][0];
128 const float y = matrix[3][1];
129 const float w = std::sqrt(matrix[0][0] * matrix[0][0] + matrix[0][1] * matrix[0][1]);
130 const float h = std::sqrt(matrix[1][0] * matrix[1][0] + matrix[1][1] * matrix[1][1]);
131 if (w <= 0.f || h <= 0.f) return;
132 gfx->drawOcclusionSolid(x, y, w, h);
133}
134
136 basePos_.clear();
137 baseNrm_.clear();
138 baseUv_.clear();
139 morphs_.clear();
140 morphWeights_.clear();
141 morphDirty_ = false;
142}
143
144void Mesh::initMorphBase(int vertexCount, const float *posXYZ, const float *nrmXYZ,
145 const float *uvST) {
147 if (vertexCount <= 0 || !posXYZ) return;
148 const size_t n = size_t(vertexCount);
149 basePos_.assign(posXYZ, posXYZ + n * 3);
150 if (nrmXYZ)
151 baseNrm_.assign(nrmXYZ, nrmXYZ + n * 3);
152 else
153 baseNrm_.assign(n * 3, 0.f);
154 if (uvST)
155 baseUv_.assign(uvST, uvST + n * 2);
156 else
157 baseUv_.assign(n * 2, 0.f);
158}
159
160bool Mesh::addMorphTarget(const std::string &name, const float *deltaPosXYZ) {
161 if (name.empty() || !deltaPosXYZ || basePos_.empty()) return false;
162 if (hasMorph(name)) return false;
163 MorphTarget t;
164 t.name = name;
165 t.deltaPos.assign(deltaPosXYZ, deltaPosXYZ + basePos_.size());
166 morphs_.push_back(std::move(t));
167 morphWeights_[name] = 0.f;
168 morphDirty_ = true;
169 return true;
170}
171
172bool Mesh::addMorphTargetAbsolute(const std::string &name, const float *absPosXYZ) {
173 if (name.empty() || !absPosXYZ || basePos_.empty()) return false;
174 if (hasMorph(name)) return false;
175 MorphTarget t;
176 t.name = name;
177 t.deltaPos.resize(basePos_.size());
178 for (size_t i = 0; i < basePos_.size(); ++i)
179 t.deltaPos[i] = absPosXYZ[i] - basePos_[i];
180 morphs_.push_back(std::move(t));
181 morphWeights_[name] = 0.f;
182 morphDirty_ = true;
183 return true;
184}
185
187 if (!basePos_.empty()) return int(basePos_.size() / 3);
188 return gpuVertexCount;
189}
190
191int Mesh::getMorphCount() const { return int(morphs_.size()); }
192
193std::string Mesh::getMorphName(int index) const {
194 if (index < 0 || size_t(index) >= morphs_.size()) return {};
195 return morphs_[size_t(index)].name;
196}
197
198bool Mesh::hasMorph(const std::string &name) const {
199 return morphWeights_.find(name) != morphWeights_.end();
200}
201
202bool Mesh::setMorphWeight(const std::string &name, float weight) {
203 auto it = morphWeights_.find(name);
204 if (it == morphWeights_.end()) return false;
205 if (weight < 0.f) weight = 0.f;
206 if (weight > 1.f) weight = 1.f;
207 if (std::fabs(it->second - weight) > 1e-6f) {
208 it->second = weight;
209 morphDirty_ = true;
210 }
211 return true;
212}
213
214float Mesh::getMorphWeight(const std::string &name) const {
215 auto it = morphWeights_.find(name);
216 return it == morphWeights_.end() ? 0.f : it->second;
217}
218
220 for (auto &kv : morphWeights_) {
221 if (kv.second != 0.f) {
222 kv.second = 0.f;
223 morphDirty_ = true;
224 }
225 }
226}
227
228void Mesh::computeMorphedPositions(std::vector<float> &outPos, std::vector<float> &outNrm) const {
229 outPos = basePos_;
230 outNrm = baseNrm_;
231 if (outPos.empty()) return;
232 for (const MorphTarget &t : morphs_) {
233 auto it = morphWeights_.find(t.name);
234 const float w = (it == morphWeights_.end()) ? 0.f : it->second;
235 if (std::fabs(w) < 1e-8f) continue;
236 for (size_t i = 0; i < outPos.size() && i < t.deltaPos.size(); ++i)
237 outPos[i] += t.deltaPos[i] * w;
238 }
239}
240
241} // namespace eve::graphics
float w
Definition AnimClip.cpp:738
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
ActiveSource owned
std::map< std::string, Var > values
std::uint32_t vertexCount
float u
Definition Grass.cpp:233
glm::vec3 n
Definition Grass.cpp:63
double r
std::int32_t c
int h
std::string name
MeleePoint3 b
Definition MeleeHit.cpp:41
float d
float t
Mesh * mesh
bool found
float dz
float dy
float dx
std::uint32_t count
uint32_t index
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
bool getCastOcclusion() const
When false, skipped by Graphics::drawOcclusion / volumetric occluder passes.
Definition Drawable.h:28
virtual void drawOcclusionSolid(float x, float y, float w, float h)
Draws occlusion solid.
void initMorphBase(int vertexCount, const float *posXYZ, const float *nrmXYZ=nullptr, const float *uvST=nullptr)
Capture base pose (xyz packed). Optional normals/uvs (same vertex count).
Definition Mesh.cpp:144
const std::vector< float > & importedUv(int channel) const
Imported uv.
Definition Mesh.cpp:68
void clearMorphData()
Clears morph data.
Definition Mesh.cpp:135
void computeBounds(const float *posXYZ, int vertexCount)
Compute the bounding sphere (centroid + max radius) from positions.
Definition Mesh.cpp:93
int gpuVertexCount
Vertex count of the GPU buffer (morph CPU base may be empty).
Definition Mesh.h:30
bool setMorphWeight(const std::string &name, float weight)
Sets the morph weight.
Definition Mesh.cpp:202
void captureImportedAttributes(const ::aiMesh &mesh)
Retain imported UV/color/tangent streams for custom pipelines and baking.
Definition Mesh.cpp:31
bool addMorphTarget(const std::string &name, const float *deltaPosXYZ)
Adds morph target.
Definition Mesh.cpp:160
bool hasMorph(const std::string &name) const
True when morph.
Definition Mesh.cpp:198
float boundsCx
Model-space bounding sphere used for view/cascade frustum culling. Computed from vertex positions at ...
Definition Mesh.h:59
void drawOcclusion(Graphics *gfx, const glm::mat4 &matrix) const override
Screen-space black proxy for volumetric occlusion. Interprets matrix as 2D affine (translation + scal...
Definition Mesh.cpp:125
float getMorphWeight(const std::string &name) const
Returns the morph weight.
Definition Mesh.cpp:214
bool addMorphTargetAbsolute(const std::string &name, const float *absPosXYZ)
Absolute morph (Assimp aiAnimMesh style): stored as delta from base.
Definition Mesh.cpp:172
void clearMorphWeights()
Clears morph weights.
Definition Mesh.cpp:219
int getMorphCount() const
Returns the morph count.
Definition Mesh.cpp:191
Result< void > setTexcoordSet(uint32_t set, std::span< const float > values)
Copy one packed ST channel; finite values/count are checked atomically. Render-thread only,...
Definition Mesh.cpp:11
std::string getMorphName(int index) const
Returns the morph name.
Definition Mesh.cpp:193
std::span< const float > texcoordSet(uint32_t set) const
Borrow a channel until mutation/destruction; empty means absent. Render-thread only.
Definition Mesh.cpp:21
float boundsRadius
Definition Mesh.h:62
int getVertexCount() const
Returns the vertex count.
Definition Mesh.cpp:186
const std::vector< float > & importedColor(int channel) const
Imported color.
Definition Mesh.cpp:74
Result< void > setSkinPalette(const float *matrices, int matrixCount)
Copy a dynamically sized column-major palette on the render thread. Invalid/non-finite input leaves t...
Definition Mesh.cpp:80
void computeMorphedPositions(std::vector< float > &outPos, std::vector< float > &outNrm) const
Bake current weights into outPos / outNrm (xyz packed).
Definition Mesh.cpp:228
卡牌游戏 UI 工具模块:工厂 + 脚本绑定入口。 功能参考 ycarowr/UiCard:扇形手牌布局、抽牌/洗牌、悬浮放大、拖拽到落牌区、 敌方手牌(背面/偷看)、费用不足置灰,以及可实时调节的布局...
Definition Animation.h:25