mirror of
https://github.com/luanti-org/luanti.git
synced 2025-06-27 16:36:03 +00:00
Fix handling of skinned meshes for nodes
- Rigidly animated models (e.g. the gltf frog node) were not working correctly, since cloning the mesh ignored the transformation matrices. Note that scaling the mesh needs to occur *after* transforming the vertices. - Visual scale did not apply to skinned models, as resetting the animation overwrote scaled vertex data with static positions & normals. For backwards compatibility, we only apply a 10x scale to static (.obj) models.
This commit is contained in:
parent
57c1ab905c
commit
612db5b2ca
6 changed files with 72 additions and 65 deletions
|
@ -1676,7 +1676,7 @@ void MapblockMeshGenerator::drawMeshNode()
|
|||
|
||||
if (cur_node.f->mesh_ptr) {
|
||||
// clone and rotate mesh
|
||||
mesh = cloneMesh(cur_node.f->mesh_ptr);
|
||||
mesh = cloneStaticMesh(cur_node.f->mesh_ptr);
|
||||
bool modified = true;
|
||||
if (facedir)
|
||||
rotateMeshBy6dFacedir(mesh, facedir);
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
// Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
#include "mesh.h"
|
||||
#include "IMeshBuffer.h"
|
||||
#include "SSkinMeshBuffer.h"
|
||||
#include "debug.h"
|
||||
#include "log.h"
|
||||
#include <cmath>
|
||||
|
@ -102,6 +104,21 @@ scene::IAnimatedMesh* createCubeMesh(v3f scale)
|
|||
return anim_mesh;
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline static void transformMeshBuffer(scene::IMeshBuffer *buf,
|
||||
const F &transform_vertex)
|
||||
{
|
||||
const u32 stride = getVertexPitchFromType(buf->getVertexType());
|
||||
u32 vertex_count = buf->getVertexCount();
|
||||
u8 *vertices = (u8 *)buf->getVertices();
|
||||
for (u32 i = 0; i < vertex_count; i++) {
|
||||
auto *vertex = (video::S3DVertex *)(vertices + i * stride);
|
||||
transform_vertex(vertex);
|
||||
}
|
||||
buf->setDirty(scene::EBT_VERTEX);
|
||||
buf->recalculateBoundingBox();
|
||||
}
|
||||
|
||||
void scaleMesh(scene::IMesh *mesh, v3f scale)
|
||||
{
|
||||
if (mesh == NULL)
|
||||
|
@ -112,14 +129,9 @@ void scaleMesh(scene::IMesh *mesh, v3f scale)
|
|||
u32 mc = mesh->getMeshBufferCount();
|
||||
for (u32 j = 0; j < mc; j++) {
|
||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
|
||||
const u32 stride = getVertexPitchFromType(buf->getVertexType());
|
||||
u32 vertex_count = buf->getVertexCount();
|
||||
u8 *vertices = (u8 *)buf->getVertices();
|
||||
for (u32 i = 0; i < vertex_count; i++)
|
||||
((video::S3DVertex *)(vertices + i * stride))->Pos *= scale;
|
||||
|
||||
buf->setDirty(scene::EBT_VERTEX);
|
||||
buf->recalculateBoundingBox();
|
||||
transformMeshBuffer(buf, [scale](video::S3DVertex *vertex) {
|
||||
vertex->Pos *= scale;
|
||||
});
|
||||
|
||||
// calculate total bounding box
|
||||
if (j == 0)
|
||||
|
@ -140,14 +152,9 @@ void translateMesh(scene::IMesh *mesh, v3f vec)
|
|||
u32 mc = mesh->getMeshBufferCount();
|
||||
for (u32 j = 0; j < mc; j++) {
|
||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
|
||||
const u32 stride = getVertexPitchFromType(buf->getVertexType());
|
||||
u32 vertex_count = buf->getVertexCount();
|
||||
u8 *vertices = (u8 *)buf->getVertices();
|
||||
for (u32 i = 0; i < vertex_count; i++)
|
||||
((video::S3DVertex *)(vertices + i * stride))->Pos += vec;
|
||||
|
||||
buf->setDirty(scene::EBT_VERTEX);
|
||||
buf->recalculateBoundingBox();
|
||||
transformMeshBuffer(buf, [vec](video::S3DVertex *vertex) {
|
||||
vertex->Pos += vec;
|
||||
});
|
||||
|
||||
// calculate total bounding box
|
||||
if (j == 0)
|
||||
|
@ -330,44 +337,40 @@ bool checkMeshNormals(scene::IMesh *mesh)
|
|||
return true;
|
||||
}
|
||||
|
||||
template<class VertexType, class SMeshBufferType>
|
||||
static scene::IMeshBuffer *cloneMeshBuffer(scene::IMeshBuffer *mesh_buffer)
|
||||
{
|
||||
auto *v = static_cast<VertexType *>(mesh_buffer->getVertices());
|
||||
u16 *indices = mesh_buffer->getIndices();
|
||||
auto *cloned_buffer = new SMeshBufferType();
|
||||
cloned_buffer->append(v, mesh_buffer->getVertexCount(), indices,
|
||||
mesh_buffer->getIndexCount());
|
||||
// Rigidly animated meshes may have transformation matrices that need to be applied
|
||||
if (auto *sbuf = dynamic_cast<scene::SSkinMeshBuffer *>(mesh_buffer)) {
|
||||
transformMeshBuffer(cloned_buffer, [sbuf](video::S3DVertex *vertex) {
|
||||
sbuf->Transformation.transformVect(vertex->Pos);
|
||||
vertex->Normal = sbuf->Transformation.rotateAndScaleVect(vertex->Normal);
|
||||
vertex->Normal.normalize();
|
||||
});
|
||||
}
|
||||
return cloned_buffer;
|
||||
}
|
||||
|
||||
scene::IMeshBuffer* cloneMeshBuffer(scene::IMeshBuffer *mesh_buffer)
|
||||
{
|
||||
switch (mesh_buffer->getVertexType()) {
|
||||
case video::EVT_STANDARD: {
|
||||
video::S3DVertex *v = (video::S3DVertex *) mesh_buffer->getVertices();
|
||||
u16 *indices = mesh_buffer->getIndices();
|
||||
scene::SMeshBuffer *cloned_buffer = new scene::SMeshBuffer();
|
||||
cloned_buffer->append(v, mesh_buffer->getVertexCount(), indices,
|
||||
mesh_buffer->getIndexCount());
|
||||
return cloned_buffer;
|
||||
case video::EVT_STANDARD:
|
||||
return cloneMeshBuffer<video::S3DVertex, scene::SMeshBuffer>(mesh_buffer);
|
||||
case video::EVT_2TCOORDS:
|
||||
return cloneMeshBuffer<video::S3DVertex2TCoords, scene::SMeshBufferLightMap>(mesh_buffer);
|
||||
case video::EVT_TANGENTS:
|
||||
return cloneMeshBuffer<video::S3DVertexTangents, scene::SMeshBufferTangents>(mesh_buffer);
|
||||
}
|
||||
case video::EVT_2TCOORDS: {
|
||||
video::S3DVertex2TCoords *v =
|
||||
(video::S3DVertex2TCoords *) mesh_buffer->getVertices();
|
||||
u16 *indices = mesh_buffer->getIndices();
|
||||
scene::SMeshBufferLightMap *cloned_buffer =
|
||||
new scene::SMeshBufferLightMap();
|
||||
cloned_buffer->append(v, mesh_buffer->getVertexCount(), indices,
|
||||
mesh_buffer->getIndexCount());
|
||||
return cloned_buffer;
|
||||
}
|
||||
case video::EVT_TANGENTS: {
|
||||
video::S3DVertexTangents *v =
|
||||
(video::S3DVertexTangents *) mesh_buffer->getVertices();
|
||||
u16 *indices = mesh_buffer->getIndices();
|
||||
scene::SMeshBufferTangents *cloned_buffer =
|
||||
new scene::SMeshBufferTangents();
|
||||
cloned_buffer->append(v, mesh_buffer->getVertexCount(), indices,
|
||||
mesh_buffer->getIndexCount());
|
||||
return cloned_buffer;
|
||||
}
|
||||
}
|
||||
// This should not happen.
|
||||
sanity_check(false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
scene::SMesh* cloneMesh(scene::IMesh *src_mesh)
|
||||
scene::SMesh* cloneStaticMesh(scene::IMesh *src_mesh)
|
||||
{
|
||||
scene::SMesh* dst_mesh = new scene::SMesh();
|
||||
for (u16 j = 0; j < src_mesh->getMeshBufferCount(); j++) {
|
||||
|
|
|
@ -93,10 +93,8 @@ void rotateMeshYZby (scene::IMesh *mesh, f64 degrees);
|
|||
*/
|
||||
scene::IMeshBuffer* cloneMeshBuffer(scene::IMeshBuffer *mesh_buffer);
|
||||
|
||||
/*
|
||||
Clone the mesh.
|
||||
*/
|
||||
scene::SMesh* cloneMesh(scene::IMesh *src_mesh);
|
||||
/// Clone a mesh. For an animated mesh, this will clone the static pose.
|
||||
scene::SMesh* cloneStaticMesh(scene::IMesh *src_mesh);
|
||||
|
||||
/*
|
||||
Convert nodeboxes to mesh. Each tile goes into a different buffer.
|
||||
|
|
|
@ -255,7 +255,7 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename,
|
|||
dim = core::dimension2d<u32>(dim.Width, frame_height);
|
||||
}
|
||||
scene::IMesh *original = g_extrusion_mesh_cache->create(dim);
|
||||
scene::SMesh *mesh = cloneMesh(original);
|
||||
scene::SMesh *mesh = cloneStaticMesh(original);
|
||||
original->drop();
|
||||
//set texture
|
||||
mesh->getMeshBuffer(0)->getMaterial().setTexture(0,
|
||||
|
@ -639,7 +639,7 @@ scene::SMesh *getExtrudedMesh(ITextureSource *tsrc,
|
|||
// get mesh
|
||||
core::dimension2d<u32> dim = texture->getSize();
|
||||
scene::IMesh *original = g_extrusion_mesh_cache->create(dim);
|
||||
scene::SMesh *mesh = cloneMesh(original);
|
||||
scene::SMesh *mesh = cloneStaticMesh(original);
|
||||
original->drop();
|
||||
|
||||
//set texture
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "client/texturesource.h"
|
||||
#include "client/tile.h"
|
||||
#include <IMeshManipulator.h>
|
||||
#include <SMesh.h>
|
||||
#include <SkinnedMesh.h>
|
||||
#endif
|
||||
#include "log.h"
|
||||
|
@ -959,23 +960,28 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
|
|||
palette = tsrc->getPalette(palette_name);
|
||||
|
||||
if (drawtype == NDT_MESH && !mesh.empty()) {
|
||||
// Read the mesh and apply scale
|
||||
mesh_ptr = client->getMesh(mesh);
|
||||
if (mesh_ptr) {
|
||||
v3f scale = v3f(BS) * visual_scale;
|
||||
scaleMesh(mesh_ptr, scale);
|
||||
// Note: By freshly reading, we get an unencumbered mesh.
|
||||
if (scene::IMesh *src_mesh = client->getMesh(mesh)) {
|
||||
f32 mesh_scale = 1.0f;
|
||||
if (auto *static_mesh = dynamic_cast<scene::SMesh *>(src_mesh)) {
|
||||
mesh_ptr = static_mesh;
|
||||
// Compatibility: Only apply BS scaling to static meshes (.obj). See #15811.
|
||||
mesh_scale = 10.0f;
|
||||
} else {
|
||||
// We only want to consider static meshes from here on.
|
||||
mesh_ptr = cloneStaticMesh(src_mesh);
|
||||
src_mesh->drop();
|
||||
}
|
||||
scaleMesh(mesh_ptr, v3f(mesh_scale * visual_scale));
|
||||
recalculateBoundingBox(mesh_ptr);
|
||||
if (!checkMeshNormals(mesh_ptr)) {
|
||||
// TODO this should be done consistently when the mesh is loaded
|
||||
infostream << "ContentFeatures: recalculating normals for mesh "
|
||||
<< mesh << std::endl;
|
||||
meshmanip->recalculateNormals(mesh_ptr, true, false);
|
||||
} else {
|
||||
// Animation is not supported, but we need to reset it to
|
||||
// default state if it is animated.
|
||||
// Note: recalculateNormals() also does this hence the else-block
|
||||
if (mesh_ptr->getMeshType() == scene::EAMT_SKINNED)
|
||||
((scene::SkinnedMesh*) mesh_ptr)->resetAnimation();
|
||||
}
|
||||
} else {
|
||||
mesh_ptr = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -342,7 +342,7 @@ struct ContentFeatures
|
|||
enum NodeDrawType drawtype;
|
||||
std::string mesh;
|
||||
#if CHECK_CLIENT_BUILD()
|
||||
scene::IMesh *mesh_ptr; // mesh in case of mesh node
|
||||
scene::SMesh *mesh_ptr; // mesh in case of mesh node
|
||||
video::SColor minimap_color;
|
||||
#endif
|
||||
float visual_scale; // Misc. scale parameter
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue