Skip to content

Commit b43befc

Browse files
committed
Fall back to SW skinning
fixme seems to cause a segfault in opengl driver? (if that isn't an earlier regression...)
1 parent 531fe7e commit b43befc

File tree

13 files changed

+94
-94
lines changed

13 files changed

+94
-94
lines changed

irr/include/AnimatedMeshSceneNode.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,6 @@ class AnimatedMeshSceneNode : public ISceneNode
157157
void setRenderFromIdentity(bool On);
158158

159159
private:
160-
//! Get a static mesh for the current frame of this animated mesh
161-
IMesh *getMeshForCurrentFrame();
162160

163161
void buildFrameNr(u32 timeMs);
164162
void checkJoints();

irr/include/CVertexBuffer.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <memory>
88
#include <vector>
9+
#include "EHardwareBufferFlags.h"
910
#include "IVertexBuffer.h"
1011
#include "WeightBuffer.h"
1112
#include "irr_ptr.h"
@@ -77,14 +78,24 @@ struct CVertexBuffer final : public IVertexBuffer
7778

7879
const WeightBuffer *getWeightBuffer() const override
7980
{
80-
return Weights.get();
81+
return UseSwSkinning ? nullptr : Weights.get();
82+
}
83+
84+
void useSwSkinning() override
85+
{
86+
if (!Weights || UseSwSkinning)
87+
return;
88+
UseSwSkinning = true;
89+
MappingHint = EHM_STREAM;
90+
Weights->updateStaticPose(this);
8191
}
8292

8393
//! Vertices of this buffer
8494
std::vector<T> Data;
8595

8696
//! Optional weights for skinning
8797
irr_ptr<WeightBuffer> Weights;
98+
bool UseSwSkinning = false;
8899
};
89100

90101
//! Standard buffer

irr/include/IAnimatedMesh.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ class IAnimatedMesh : public IMesh
1919
//! Gets the maximum frame number, 0 if the mesh is static.
2020
virtual f32 getMaxFrameNumber() const = 0;
2121

22+
virtual void prepareForAnimation(u16 max_hw_joints) = 0;
23+
2224
//! Returns the type of the animated mesh. Useful for safe downcasts.
2325
E_ANIMATED_MESH_TYPE getMeshType() const = 0;
2426
};

irr/include/IVertexBuffer.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,10 @@ class IVertexBuffer : public virtual IReferenceCounted, public HWBuffer
5050
//! returns texture coord of vertex i
5151
virtual core::vector2df &getTCoords(u32 i) = 0;
5252

53-
//! Get weight buffer associated with this vertex buffer, if any
53+
//! Get weight buffer for upload to the GPU, if any
5454
virtual const WeightBuffer *getWeightBuffer() const = 0;
55+
//! Enable software skinning
56+
virtual void useSwSkinning() = 0;
5557
};
5658

5759
} // end namespace scene

irr/include/SMesh.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,8 @@ struct SMesh final : public IAnimatedMesh
137137
// Slightly hacky: Eventually should be consolidated with SSkinnedMesh,
138138
// with all the animation-related parts behind an optional.
139139

140-
virtual f32 getMaxFrameNumber() const override { return 0.0f; }
140+
f32 getMaxFrameNumber() const override { return 0.0f; }
141+
void prepareForAnimation(u16 max_hw_joints) override {}
141142
E_ANIMATED_MESH_TYPE getMeshType() const override { return EAMT_STATIC; }
142143
};
143144

irr/include/SkinnedMesh.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ class SkinnedMesh : public IAnimatedMesh
5959
//! If the duration is 0, it is a static (=non animated) mesh.
6060
f32 getMaxFrameNumber() const override;
6161

62+
void prepareForAnimation(u16 max_hw_joints) override;
63+
64+
bool useSoftwareSkinning() const { return UseSwSkinning; }
65+
6266
//! Turns the given array of local matrices into an array of global matrices
6367
//! by multiplying with respective parent matrices.
6468
void calculateGlobalMatrices(std::vector<core::matrix4> &matrices) const;
@@ -366,6 +370,7 @@ class SkinnedMesh : public IAnimatedMesh
366370

367371
bool HasAnimation;
368372
bool PreparedForSkinning;
373+
bool UseSwSkinning = false;
369374

370375
SourceFormat SrcFormat;
371376
};

irr/include/WeightBuffer.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,13 @@ struct WeightBuffer final : public HWBuffer
3333

3434
std::optional<std::vector<u32>> animated_vertices;
3535

36-
// A bit of a hack for now: Store static positions here so we can use them for skinning.
36+
// A bit of a hack for now: Back up static pose here so we can use it for software skinning.
3737
// Ideally we might want a design where we do not mutate the original vertex buffer at all.
38-
std::unique_ptr<core::vector3df[]> static_positions;
39-
std::unique_ptr<core::vector3df[]> static_normals;
38+
struct VertexGeometry {
39+
core::vector3df pos;
40+
core::vector3df normal;
41+
};
42+
std::unique_ptr<VertexGeometry[]> static_pose;
4043

4144
WeightBuffer(size_t n_verts) : weights(n_verts)
4245
{ MappingHint = scene::EHM_STATIC; }
@@ -64,14 +67,14 @@ struct WeightBuffer final : public HWBuffer
6467

6568
/// @note src and dst can be the same buffer
6669
void skin(IVertexBuffer *dst,
67-
const std::vector<core::matrix4> &joint_transforms) const;
70+
const std::vector<core::matrix4> &joint_transforms);
6871

6972
/// Prepares this buffer for use in skinning.
7073
void finalize();
7174

7275
void updateStaticPose(const IVertexBuffer *vbuf);
7376

74-
void resetToStatic(IVertexBuffer *vbuf) const;
77+
void resetToStaticPose(IVertexBuffer *vbuf) const;
7578
};
7679

7780
} // end namespace scene

irr/src/AnimatedMeshSceneNode.cpp

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -147,23 +147,6 @@ void AnimatedMeshSceneNode::OnRegisterSceneNode()
147147
}
148148
}
149149

150-
IMesh *AnimatedMeshSceneNode::getMeshForCurrentFrame()
151-
{
152-
if (Mesh->getMeshType() != EAMT_SKINNED) {
153-
return Mesh;
154-
}
155-
156-
// As multiple scene nodes may be sharing the same skinned mesh, we have to
157-
// re-animate it every frame to ensure that this node gets the mesh that it needs.
158-
159-
auto *skinnedMesh = static_cast<SkinnedMesh *>(Mesh);
160-
161-
// Matrices have already been calculated in OnAnimate
162-
// TODO skinnedMesh->skinMesh(PerJoint.GlobalMatrices);
163-
164-
return skinnedMesh;
165-
}
166-
167150
//! OnAnimate() is called just before rendering the whole scene.
168151
void AnimatedMeshSceneNode::OnAnimate(u32 timeMs)
169152
{
@@ -213,23 +196,25 @@ void AnimatedMeshSceneNode::render()
213196

214197
++PassCount;
215198

216-
scene::IMesh *m = getMeshForCurrentFrame();
217-
assert(m);
218-
219199
if (auto *sm = dynamic_cast<SkinnedMesh *>(Mesh)) {
220-
// TODO check whether there are any weights to make use of these joint transforms
221-
driver->setJointTransforms(sm->calculateSkinMatrices(PerJoint.GlobalMatrices));
222200
sm->rigidAnimation(PerJoint.GlobalMatrices);
201+
// TODO check whether there are any weights to make use of these joint transforms
202+
if (sm->useSoftwareSkinning()) {
203+
// Perform software skinning; matrices have already been calculated in OnAnimate
204+
sm->skinMesh(PerJoint.GlobalMatrices);
205+
} else {
206+
driver->setJointTransforms(sm->calculateSkinMatrices(PerJoint.GlobalMatrices));
207+
}
223208
}
224209
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
225210

226-
for (u32 i = 0; i < m->getMeshBufferCount(); ++i) {
211+
for (u32 i = 0; i < Mesh->getMeshBufferCount(); ++i) {
227212
const bool transparent = driver->needsTransparentRenderPass(Materials[i]);
228213

229214
// only render transparent buffer if this is the transparent render pass
230215
// and solid only in solid pass
231216
if (transparent == isTransparentPass) {
232-
scene::IMeshBuffer *mb = m->getMeshBuffer(i);
217+
scene::IMeshBuffer *mb = Mesh->getMeshBuffer(i);
233218
const video::SMaterial &material = ReadOnlyMaterials ? mb->getMaterial() : Materials[i];
234219
if (RenderFromIdentity)
235220
driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
@@ -252,11 +237,11 @@ void AnimatedMeshSceneNode::render()
252237
if (DebugDataVisible & scene::EDS_NORMALS) {
253238
const f32 debugNormalLength = 1.f;
254239
const video::SColor debugNormalColor = video::SColor(255, 34, 221, 221);
255-
const u32 count = m->getMeshBufferCount();
240+
const u32 count = Mesh->getMeshBufferCount();
256241

257242
// draw normals
258243
for (u32 g = 0; g < count; ++g) {
259-
scene::IMeshBuffer *mb = m->getMeshBuffer(g);
244+
scene::IMeshBuffer *mb = Mesh->getMeshBuffer(g);
260245
if (RenderFromIdentity)
261246
driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
262247
else if (Mesh->getMeshType() == EAMT_SKINNED)
@@ -271,8 +256,8 @@ void AnimatedMeshSceneNode::render()
271256

272257
// show bounding box
273258
if (DebugDataVisible & scene::EDS_BBOX_BUFFERS) {
274-
for (u32 g = 0; g < m->getMeshBufferCount(); ++g) {
275-
const IMeshBuffer *mb = m->getMeshBuffer(g);
259+
for (u32 g = 0; g < Mesh->getMeshBufferCount(); ++g) {
260+
const IMeshBuffer *mb = Mesh->getMeshBuffer(g);
276261

277262
if (Mesh->getMeshType() == EAMT_SKINNED)
278263
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation * ((SSkinMeshBuffer *)mb)->Transformation);
@@ -305,8 +290,8 @@ void AnimatedMeshSceneNode::render()
305290
debug_mat.ZBuffer = video::ECFN_DISABLED;
306291
driver->setMaterial(debug_mat);
307292

308-
for (u32 g = 0; g < m->getMeshBufferCount(); ++g) {
309-
const IMeshBuffer *mb = m->getMeshBuffer(g);
293+
for (u32 g = 0; g < Mesh->getMeshBufferCount(); ++g) {
294+
const IMeshBuffer *mb = Mesh->getMeshBuffer(g);
310295
if (RenderFromIdentity)
311296
driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
312297
else if (Mesh->getMeshType() == EAMT_SKINNED)

irr/src/CSceneManager.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ IAnimatedMesh *CSceneManager::getUncachedMesh(io::IReadFile *file, const io::pat
137137
file->seek(0);
138138
IAnimatedMesh *msh = (*it)->createMesh(file);
139139
if (msh) {
140+
msh->prepareForAnimation(Driver->getMaxJointTransforms());
140141
MeshCache->addMesh(cachename, msh);
141142
msh->drop();
142143
os::Printer::log("Loaded mesh", filename, ELL_DEBUG);

irr/src/OpenGL/BufferObject.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ void OGLBufferObject::upload(const void *data, size_t size, size_t offset,
3434
GL.BufferSubData(m_target, offset, size, data);
3535
}
3636

37-
// TODO binding should perhaps be a separate step from the upload?
37+
// In the future, binding should perhaps be a separate step from the upload?
3838
if (m_target == TARGET_UBO)
3939
GL.BindBufferBase(GL_UNIFORM_BUFFER, 0, m_name);
4040
else

0 commit comments

Comments
 (0)