Skip to content

Commit cd05a1f

Browse files
committed
Transpose: Use vector of structs
instead of struct of unique pointers
1 parent 2f4d353 commit cd05a1f

File tree

4 files changed

+52
-51
lines changed

4 files changed

+52
-51
lines changed

irr/include/WeightBuffer.h

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,15 @@ namespace scene
1818
struct WeightBuffer
1919
{
2020
constexpr static u16 MAX_WEIGHTS_PER_VERTEX = 4;
21-
size_t n_verts;
22-
std::unique_ptr<u16[]> joint_idxs;
23-
std::unique_ptr<f32[]> weights;
21+
// ID-weight pairs for a joint
22+
struct VertexWeights {
23+
std::array<u16, MAX_WEIGHTS_PER_VERTEX> joint_ids = {};
24+
std::array<f32, MAX_WEIGHTS_PER_VERTEX> strengths = {};
25+
void addWeight(u16 joint_id, f32 weight);
26+
void skinVertex(core::vector3df &pos, core::vector3df &normal,
27+
const std::vector<core::matrix4> &joint_transforms) const;
28+
};
29+
std::vector<VertexWeights> weights;
2430

2531
std::optional<std::vector<u32>> animated_vertices;
2632

@@ -29,17 +35,16 @@ struct WeightBuffer
2935
std::unique_ptr<core::vector3df[]> static_positions;
3036
std::unique_ptr<core::vector3df[]> static_normals;
3137

32-
WeightBuffer(size_t n_verts);
38+
WeightBuffer(size_t n_verts) : weights(n_verts) {}
3339

34-
u16 *getJointIndices(u32 vertex_id)
35-
{ return &joint_idxs[vertex_id * MAX_WEIGHTS_PER_VERTEX]; }
36-
const u16 *getJointIndices(u32 vertex_id) const
37-
{ return &joint_idxs[vertex_id * MAX_WEIGHTS_PER_VERTEX]; }
40+
const std::array<u16, MAX_WEIGHTS_PER_VERTEX> &getJointIds(u32 vertex_id) const
41+
{ return weights[vertex_id].joint_ids; }
3842

39-
f32 *getWeights(u32 vertex_id)
40-
{ return &weights[vertex_id * MAX_WEIGHTS_PER_VERTEX]; }
41-
const f32 *getWeights(u32 vertex_id) const
42-
{ return &weights[vertex_id * MAX_WEIGHTS_PER_VERTEX]; }
43+
const std::array<f32, MAX_WEIGHTS_PER_VERTEX> &getWeights(u32 vertex_id) const
44+
{ return weights[vertex_id].strengths; }
45+
46+
size_t size() const
47+
{ return weights.size(); }
4348

4449
void addWeight(u32 vertex_id, u16 joint_id, f32 weight);
4550

@@ -50,8 +55,7 @@ struct WeightBuffer
5055
void skin(IVertexBuffer *dst,
5156
const std::vector<core::matrix4> &joint_transforms) const;
5257

53-
/// Normalizes weights so that they sum to 1.0 per vertex,
54-
/// stores which vertices are animated.
58+
/// Prepares this buffer for use in skinning.
5559
void finalize();
5660

5761
void updateStaticPose(const IVertexBuffer *vbuf);

irr/src/SkinnedMesh.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ void SkinnedMesh::calculateJointBoundingBoxes()
292292
continue;
293293
for (u32 vert_id : weights->animated_vertices.value()) {
294294
for (u16 j = 0; j < WeightBuffer::MAX_WEIGHTS_PER_VERTEX; j++) {
295-
const auto joint_id = weights->getJointIndices(vert_id)[j];
295+
const auto joint_id = weights->getJointIds(vert_id)[j];
296296
const auto *joint = AllJoints[joint_id];
297297
const auto strength = weights->getWeights(vert_id)[j];
298298
if (strength < 1e-6)
@@ -411,7 +411,7 @@ SkinnedMesh *SkinnedMeshBuilder::finalize() &&
411411
auto *buf = mesh->LocalBuffers.at(weight.buffer_id);
412412
if (!buf->Weights)
413413
buf->Weights = WeightBuffer(buf->getVertexCount());
414-
if (weight.vertex_id >= buf->Weights->n_verts) {
414+
if (weight.vertex_id >= buf->Weights->size()) {
415415
throw std::out_of_range("vertex id out of range");
416416
}
417417
buf->Weights->addWeight(weight.vertex_id, weight.joint_id, weight.strength);

irr/src/WeightBuffer.cpp

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,38 +5,31 @@
55

66
namespace scene {
77

8-
WeightBuffer::WeightBuffer(size_t n_verts) :
9-
n_verts(n_verts),
10-
joint_idxs(std::make_unique<u16[]>(MAX_WEIGHTS_PER_VERTEX * n_verts)),
11-
weights(std::make_unique<f32[]>(MAX_WEIGHTS_PER_VERTEX * n_verts))
12-
{}
13-
14-
void WeightBuffer::addWeight(u32 vertex_id, u16 joint_id, f32 weight)
8+
void WeightBuffer::VertexWeights::addWeight(u16 joint_id, f32 weight)
159
{
16-
assert(vertex_id < n_verts);
17-
assert(weight >= 0.f);
18-
f32 *weights = getWeights(vertex_id);
19-
f32 *min_weight = std::min_element(weights, weights + MAX_WEIGHTS_PER_VERTEX);
10+
assert(weight >= 0.0f);
11+
auto min_weight = std::min_element(strengths.begin(), strengths.end());
2012
if (*min_weight > weight)
2113
return;
2214

2315
*min_weight = weight;
24-
getJointIndices(vertex_id)[min_weight - weights] = joint_id;
16+
joint_ids[std::distance(strengths.begin(), min_weight)] = joint_id;
2517
}
2618

27-
void WeightBuffer::skinVertex(u32 vertex_id, core::vector3df &pos, core::vector3df &normal,
19+
void WeightBuffer::addWeight(u32 vertex_id, u16 joint_id, f32 weight)
20+
{
21+
weights[vertex_id].addWeight(joint_id, weight);
22+
}
23+
24+
void WeightBuffer::VertexWeights::skinVertex(core::vector3df &pos, core::vector3df &normal,
2825
const std::vector<core::matrix4> &joint_transforms) const
2926
{
30-
const u16 *joint_idxs = getJointIndices(vertex_id);
31-
const f32 *weights = getWeights(vertex_id);
32-
f32 total_weight = 0.f;
27+
f32 total_weight = 0.0f;
3328
core::vector3df skinned_pos;
3429
core::vector3df skinned_normal;
3530
for (u16 i = 0; i < MAX_WEIGHTS_PER_VERTEX; ++i) {
36-
u16 joint_id = joint_idxs[i];
37-
f32 weight = weights[i];
38-
if (weight <= 0.f)
39-
continue;
31+
u16 joint_id = joint_ids[i];
32+
f32 weight = strengths[i];
4033

4134
const auto &transform = joint_transforms[joint_id];
4235
core::vector3df transformed_pos = pos;
@@ -45,15 +38,20 @@ void WeightBuffer::skinVertex(u32 vertex_id, core::vector3df &pos, core::vector3
4538
skinned_normal += weight * transform.rotateAndScaleVect(normal);
4639
total_weight += weight;
4740
}
48-
if (core::equals(total_weight, 0.f))
41+
if (core::equals(total_weight, 0.0f))
4942
return;
5043

5144
pos = skinned_pos;
5245
// Need to renormalize normal after potentially scaling
5346
normal = skinned_normal.normalize();
5447
}
5548

56-
/// @note src and dst can be the same buffer
49+
void WeightBuffer::skinVertex(u32 vertex_id, core::vector3df &pos, core::vector3df &normal,
50+
const std::vector<core::matrix4> &joint_transforms) const
51+
{
52+
return weights[vertex_id].skinVertex(pos, normal, joint_transforms);
53+
}
54+
5755
void WeightBuffer::skin(IVertexBuffer *dst,
5856
const std::vector<core::matrix4> &joint_transforms) const
5957
{
@@ -71,24 +69,24 @@ void WeightBuffer::skin(IVertexBuffer *dst,
7169
dst->setDirty();
7270
}
7371

74-
/// Normalizes weights so that they sum to 1.0 per vertex,
75-
/// stores which vertices are animated.
7672
void WeightBuffer::finalize()
7773
{
74+
// Normalizes weights so that they sum to 1.0 per vertex,
75+
// stores which vertices are animated.
7876
assert(!animated_vertices.has_value());
7977
animated_vertices.emplace();
80-
for (u32 i = 0; i < n_verts; ++i) {
81-
auto *weights_i = getWeights(i);
82-
f32 total_weight = std::accumulate(weights_i, weights_i + MAX_WEIGHTS_PER_VERTEX, 0.0f);
78+
for (u32 i = 0; i < size(); ++i) {
79+
auto &strengths = weights[i].strengths;
80+
f32 total_weight = std::accumulate(strengths.begin(), strengths.end(), 0.0f);
8381
if (core::equals(total_weight, 0.0f)) {
84-
std::fill(weights_i, weights_i + MAX_WEIGHTS_PER_VERTEX, 0.0f);
82+
std::fill(strengths.begin(), strengths.end(), 0.0f);
8583
continue;
8684
}
8785
animated_vertices->emplace_back(i);
8886
if (core::equals(total_weight, 1.0f))
8987
continue;
90-
for (u16 j = 0; j < MAX_WEIGHTS_PER_VERTEX; ++j)
91-
weights_i[j] /= total_weight;
88+
for (auto &strength : strengths)
89+
strength /= total_weight;
9290
}
9391
animated_vertices->shrink_to_fit();
9492
}

src/unittest/test_irr_gltf_mesh_loader.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -438,12 +438,11 @@ SECTION("simple skin")
438438
REQUIRE(buf->Weights.has_value());
439439
std::vector<f32> weights(buf->getVertexCount(), 0.0f);
440440
for (size_t i = 0; i < buf->getVertexCount(); ++i) {
441-
const auto *joint_ids = buf->Weights->getJointIndices(i);
442-
const auto *joint_ids_end = joint_ids + scene::WeightBuffer::MAX_WEIGHTS_PER_VERTEX;
443-
auto *it = std::find(joint_ids, joint_ids_end, joint->JointID);
444-
if (it == joint_ids_end)
441+
const auto &joint_ids = buf->Weights->getJointIds(i);
442+
const auto it = std::find(joint_ids.begin(), joint_ids.end(), joint->JointID);
443+
if (it == joint_ids.end())
445444
continue;
446-
weights[i] = buf->Weights->getWeights(i)[it - joint_ids];
445+
weights[i] = buf->Weights->getWeights(i)[std::distance(joint_ids.begin(), it)];
447446
}
448447
return weights;
449448
};

0 commit comments

Comments
 (0)