mirror of
https://github.com/luanti-org/luanti.git
synced 2025-10-05 19:31:04 +00:00
Fix handling of skinned meshes for nodes
Second try after the revert in 8a28339
due to an unexpected regression.
- 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 now apply a 10x scale to static, non-glTF models.
We now do scale static meshes, as the bug that caused meshes not to be scaled was limited to skeletally animated meshes,
hence we ought not to reproduce it for skinned meshes that do not take advantage of skeletal animations (e.g. current MTG doors).
However, glTF models (e.g. Wuzzy's eyeballs) up until recently were always affected due to technical reasons
(using skeletal animation for rigid animation).
Thus, to preserve behavior, we:
1. Do not apply 10x scale to glTF models.
2. Apply 10x scale to obj models.
3. Apply 10x scale to static x or b3d models, but not to animated ones.
See also: #16141
This commit is contained in:
parent
30e33d71cc
commit
7ac5502fdf
12 changed files with 118 additions and 75 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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue