Don't combine static node collision geometry (bug #6027)

depth-refraction
Alexei Kotov 1 year ago committed by Alexei Dobrohotov
parent a9fdb51041
commit 7fd9b27b54

@ -15,6 +15,7 @@
Bug #5870: Disposing of actors who were selected in the console doesn't deselect them like vanilla
Bug #5883: Immobile creatures don't cause water ripples
Bug #5977: Fatigueless NPCs' corpse underwater changes animation on game load
Bug #6027: Collisionshape becomes spiderweb-like when the mesh is too complex
Bug #6313: Followers with high Fight can turn hostile
Bug #6427: Enemy health bar disappears before damaging effect ends
Bug #6550: Cloned body parts don't inherit texture effects

@ -586,7 +586,7 @@ namespace
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_tri_shape_root_node_should_return_shape_with_triangle_mesh_shape)
TEST_F(TestBulletNifLoader, for_tri_shape_root_node_should_return_static_shape)
{
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNiTriShape);
@ -596,14 +596,18 @@ namespace
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
std::unique_ptr<btCompoundShape> compound(new btCompoundShape);
compound->addChildShape(btTransform::getIdentity(), new Resource::TriangleMeshShape(triangles.release(), true));
Resource::BulletShape expected;
expected.mCollisionShape.reset(new Resource::TriangleMeshShape(triangles.release(), true));
expected.mCollisionShape.reset(compound.release());
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader,
for_tri_shape_root_node_with_bounds_should_return_shape_with_bounds_but_with_null_collision_shape)
for_tri_shape_root_node_with_bounds_should_return_static_shape_with_bounds_but_with_null_collision_shape)
{
mNiTriShape.hasBounds = true;
mNiTriShape.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
@ -623,7 +627,7 @@ namespace
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_should_return_shape_with_triangle_mesh_shape)
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_should_return_static_shape)
{
mNiTriShape.parents.push_back(&mNiNode);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
@ -636,13 +640,17 @@ namespace
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
std::unique_ptr<btCompoundShape> compound(new btCompoundShape);
compound->addChildShape(btTransform::getIdentity(), new Resource::TriangleMeshShape(triangles.release(), true));
Resource::BulletShape expected;
expected.mCollisionShape.reset(new Resource::TriangleMeshShape(triangles.release(), true));
expected.mCollisionShape.reset(compound.release());
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_nested_tri_shape_child_should_return_shape_with_triangle_mesh_shape)
TEST_F(TestBulletNifLoader, for_nested_tri_shape_child_should_return_static_shape)
{
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiNode2) }));
mNiNode2.parents.push_back(&mNiNode);
@ -657,13 +665,17 @@ namespace
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
std::unique_ptr<btCompoundShape> compound(new btCompoundShape);
compound->addChildShape(btTransform::getIdentity(), new Resource::TriangleMeshShape(triangles.release(), true));
Resource::BulletShape expected;
expected.mCollisionShape.reset(new Resource::TriangleMeshShape(triangles.release(), true));
expected.mCollisionShape.reset(compound.release());
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_two_tri_shape_children_should_return_shape_with_triangle_mesh_shape_with_all_meshes)
TEST_F(TestBulletNifLoader, for_two_tri_shape_children_should_return_static_shape_with_all_meshes)
{
mNiTriShape.parents.push_back(&mNiNode);
mNiTriShape2.parents.push_back(&mNiNode);
@ -677,16 +689,22 @@ namespace
const auto result = mLoader.load(file);
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 1), btVector3(1, 0, 1), btVector3(1, 1, 1));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
std::unique_ptr<btTriangleMesh> triangles2(new btTriangleMesh(false));
triangles2->addTriangle(btVector3(0, 0, 1), btVector3(1, 0, 1), btVector3(1, 1, 1));
std::unique_ptr<btCompoundShape> compound(new btCompoundShape);
compound->addChildShape(btTransform::getIdentity(), new Resource::TriangleMeshShape(triangles.release(), true));
compound->addChildShape(
btTransform::getIdentity(), new Resource::TriangleMeshShape(triangles2.release(), true));
Resource::BulletShape expected;
expected.mCollisionShape.reset(new Resource::TriangleMeshShape(triangles.release(), true));
expected.mCollisionShape.reset(compound.release());
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader,
for_tri_shape_child_node_and_filename_starting_with_x_and_not_empty_skin_should_return_shape_with_triangle_mesh_shape)
for_tri_shape_child_node_and_filename_starting_with_x_and_not_empty_skin_should_return_static_shape)
{
mNiTriShape.skin = Nif::NiSkinInstancePtr(&mNiSkinInstance);
mNiTriShape.parents.push_back(&mNiNode);
@ -700,14 +718,16 @@ namespace
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
std::unique_ptr<btCompoundShape> compound(new btCompoundShape);
compound->addChildShape(btTransform::getIdentity(), new Resource::TriangleMeshShape(triangles.release(), true));
Resource::BulletShape expected;
expected.mCollisionShape.reset(new Resource::TriangleMeshShape(triangles.release(), true));
expected.mCollisionShape.reset(compound.release());
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader,
for_tri_shape_root_node_and_filename_starting_with_x_should_return_shape_with_compound_shape)
TEST_F(TestBulletNifLoader, for_tri_shape_root_node_and_filename_starting_with_x_should_return_animated_shape)
{
copy(mTransform, mNiTriShape.trafo);
mNiTriShape.trafo.scale = 3;
@ -731,8 +751,7 @@ namespace
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader,
for_tri_shape_child_node_and_filename_starting_with_x_should_return_shape_with_compound_shape)
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_and_filename_starting_with_x_should_return_animated_shape)
{
copy(mTransform, mNiTriShape.trafo);
mNiTriShape.trafo.scale = 3;
@ -759,8 +778,8 @@ namespace
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader,
for_two_tri_shape_children_nodes_and_filename_starting_with_x_should_return_shape_with_compound_shape)
TEST_F(
TestBulletNifLoader, for_two_tri_shape_children_nodes_and_filename_starting_with_x_should_return_animated_shape)
{
copy(mTransform, mNiTriShape.trafo);
mNiTriShape.trafo.scale = 3;
@ -801,7 +820,7 @@ namespace
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_controller_should_return_shape_with_compound_shape)
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_controller_should_return_animated_shape)
{
mController.recType = Nif::RC_NiKeyframeController;
mController.flags |= Nif::Controller::Flag_Active;
@ -831,8 +850,7 @@ namespace
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader,
for_two_tri_shape_children_nodes_where_one_with_controller_should_return_shape_with_compound_shape)
TEST_F(TestBulletNifLoader, for_two_tri_shape_children_nodes_where_one_with_controller_should_return_animated_shape)
{
mController.recType = Nif::RC_NiKeyframeController;
mController.flags |= Nif::Controller::Flag_Active;
@ -856,10 +874,9 @@ namespace
const auto result = mLoader.load(file);
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(
btVector3(4, 8, 12), btVector3(16, 8, 12), btVector3(16, 18.5309906005859375, 6.246893405914306640625));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
std::unique_ptr<Resource::TriangleMeshShape> mesh(new Resource::TriangleMeshShape(triangles.release(), true));
mesh->setLocalScaling(btVector3(1, 1, 1));
mesh->setLocalScaling(btVector3(12, 12, 12));
std::unique_ptr<btTriangleMesh> triangles2(new btTriangleMesh(false));
triangles2->addTriangle(btVector3(0, 0, 1), btVector3(1, 0, 1), btVector3(1, 1, 1));
@ -867,11 +884,11 @@ namespace
mesh2->setLocalScaling(btVector3(12, 12, 12));
std::unique_ptr<btCompoundShape> shape(new btCompoundShape);
shape->addChildShape(mResultTransform2, mesh.release());
shape->addChildShape(mResultTransform2, mesh2.release());
shape->addChildShape(btTransform::getIdentity(), mesh.release());
Resource::BulletShape expected;
expected.mCollisionShape.reset(shape.release());
expected.mAnimatedShapes = { { -1, 0 } };
expected.mAnimatedShapes = { { -1, 1 } };
EXPECT_EQ(*result, expected);
}
@ -921,8 +938,11 @@ namespace
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
std::unique_ptr<btCompoundShape> compound(new btCompoundShape);
compound->addChildShape(btTransform::getIdentity(), new Resource::TriangleMeshShape(triangles.release(), true));
Resource::BulletShape expected;
expected.mAvoidCollisionShape.reset(new Resource::TriangleMeshShape(triangles.release(), false));
expected.mAvoidCollisionShape.reset(compound.release());
EXPECT_EQ(*result, expected);
}
@ -980,8 +1000,12 @@ namespace
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
std::unique_ptr<btCompoundShape> compound(new btCompoundShape);
compound->addChildShape(btTransform::getIdentity(), new Resource::TriangleMeshShape(triangles.release(), true));
Resource::BulletShape expected;
expected.mCollisionShape.reset(new Resource::TriangleMeshShape(triangles.release(), true));
expected.mCollisionShape.reset(compound.release());
expected.mVisualCollisionType = Resource::VisualCollisionType::Camera;
EXPECT_EQ(*result, expected);
@ -1005,8 +1029,11 @@ namespace
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
std::unique_ptr<btCompoundShape> compound(new btCompoundShape);
compound->addChildShape(btTransform::getIdentity(), new Resource::TriangleMeshShape(triangles.release(), true));
Resource::BulletShape expected;
expected.mCollisionShape.reset(new Resource::TriangleMeshShape(triangles.release(), true));
expected.mCollisionShape.reset(compound.release());
expected.mVisualCollisionType = Resource::VisualCollisionType::Camera;
EXPECT_EQ(*result, expected);
@ -1029,8 +1056,11 @@ namespace
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
std::unique_ptr<btCompoundShape> compound(new btCompoundShape);
compound->addChildShape(btTransform::getIdentity(), new Resource::TriangleMeshShape(triangles.release(), true));
Resource::BulletShape expected;
expected.mCollisionShape.reset(new Resource::TriangleMeshShape(triangles.release(), true));
expected.mCollisionShape.reset(compound.release());
expected.mVisualCollisionType = Resource::VisualCollisionType::Default;
EXPECT_EQ(*result, expected);
@ -1054,8 +1084,11 @@ namespace
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
std::unique_ptr<btCompoundShape> compound(new btCompoundShape);
compound->addChildShape(btTransform::getIdentity(), new Resource::TriangleMeshShape(triangles.release(), true));
Resource::BulletShape expected;
expected.mCollisionShape.reset(new Resource::TriangleMeshShape(triangles.release(), true));
expected.mCollisionShape.reset(compound.release());
expected.mVisualCollisionType = Resource::VisualCollisionType::Default;
EXPECT_EQ(*result, expected);
@ -1085,8 +1118,11 @@ namespace
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
std::unique_ptr<btCompoundShape> compound(new btCompoundShape);
compound->addChildShape(btTransform::getIdentity(), new Resource::TriangleMeshShape(triangles.release(), true));
Resource::BulletShape expected;
expected.mCollisionShape.reset(new Resource::TriangleMeshShape(triangles.release(), true));
expected.mCollisionShape.reset(compound.release());
expected.mVisualCollisionType = Resource::VisualCollisionType::Camera;
EXPECT_EQ(*result, expected);
@ -1133,8 +1169,11 @@ namespace
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
std::unique_ptr<btCompoundShape> compound(new btCompoundShape);
compound->addChildShape(btTransform::getIdentity(), new Resource::TriangleMeshShape(triangles.release(), true));
Resource::BulletShape expected;
expected.mCollisionShape.reset(new Resource::TriangleMeshShape(triangles.release(), true));
expected.mCollisionShape.reset(compound.release());
EXPECT_EQ(*result, expected);
}
@ -1154,7 +1193,7 @@ namespace
EXPECT_EQ(*result, expected);
}
TEST_F(TestBulletNifLoader, for_tri_strips_root_node_should_return_shape_with_triangle_mesh_shape)
TEST_F(TestBulletNifLoader, for_tri_strips_root_node_should_return_static_shape)
{
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNiTriStrips);
@ -1165,8 +1204,11 @@ namespace
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
triangles->addTriangle(btVector3(1, 0, 0), btVector3(0, 1, 0), btVector3(1, 1, 0));
std::unique_ptr<btCompoundShape> compound(new btCompoundShape);
compound->addChildShape(btTransform::getIdentity(), new Resource::TriangleMeshShape(triangles.release(), true));
Resource::BulletShape expected;
expected.mCollisionShape.reset(new Resource::TriangleMeshShape(triangles.release(), true));
expected.mCollisionShape.reset(compound.release());
EXPECT_EQ(*result, expected);
}

@ -40,7 +40,7 @@ namespace
return letterPos < path.size() && (path[letterPos] == 'x' || path[letterPos] == 'X');
}
void fillTriangleMesh(btTriangleMesh& mesh, const Nif::NiTriShapeData& data, const osg::Matrixf& transform)
void fillTriangleMesh(btTriangleMesh& mesh, const Nif::NiTriShapeData& data)
{
const std::vector<osg::Vec3f>& vertices = data.vertices;
const std::vector<unsigned short>& triangles = data.triangles;
@ -49,13 +49,13 @@ namespace
for (std::size_t i = 0; i < triangles.size(); i += 3)
{
mesh.addTriangle(Misc::Convert::toBullet(vertices[triangles[i + 0]] * transform),
Misc::Convert::toBullet(vertices[triangles[i + 1]] * transform),
Misc::Convert::toBullet(vertices[triangles[i + 2]] * transform));
mesh.addTriangle(Misc::Convert::toBullet(vertices[triangles[i + 0]]),
Misc::Convert::toBullet(vertices[triangles[i + 1]]),
Misc::Convert::toBullet(vertices[triangles[i + 2]]));
}
}
void fillTriangleMesh(btTriangleMesh& mesh, const Nif::NiTriStripsData& data, const osg::Matrixf& transform)
void fillTriangleMesh(btTriangleMesh& mesh, const Nif::NiTriStripsData& data)
{
mesh.preallocateVertices(static_cast<int>(data.vertices.size()));
mesh.preallocateIndices(static_cast<int>(data.mNumTriangles));
@ -75,9 +75,9 @@ namespace
c = strip[i];
if (a == b || b == c || a == c)
continue;
const btVector3 vertexA = Misc::Convert::toBullet(data.vertices[a] * transform);
const btVector3 vertexB = Misc::Convert::toBullet(data.vertices[b] * transform);
const btVector3 vertexC = Misc::Convert::toBullet(data.vertices[c] * transform);
const btVector3 vertexA = Misc::Convert::toBullet(data.vertices[a]);
const btVector3 vertexB = Misc::Convert::toBullet(data.vertices[b]);
const btVector3 vertexC = Misc::Convert::toBullet(data.vertices[c]);
if (i % 2 == 0)
mesh.addTriangle(vertexA, vertexB, vertexC);
else
@ -117,22 +117,11 @@ namespace
return {};
}
std::monostate fillTriangleMesh(
std::unique_ptr<btTriangleMesh>& mesh, const Nif::NiGeometry& geometry, const osg::Matrixf& transform)
{
return handleNiGeometry(geometry, [&](const auto& data) {
if (mesh == nullptr)
mesh = std::make_unique<btTriangleMesh>(false);
fillTriangleMesh(*mesh, data, transform);
return std::monostate{};
});
}
std::unique_ptr<btTriangleMesh> makeChildMesh(const Nif::NiGeometry& geometry)
{
return handleNiGeometry(geometry, [&](const auto& data) {
auto mesh = std::make_unique<btTriangleMesh>();
fillTriangleMesh(*mesh, data, osg::Matrixf());
fillTriangleMesh(*mesh, data);
return mesh;
});
}
@ -147,8 +136,7 @@ namespace NifBullet
mShape = new Resource::BulletShape;
mCompoundShape.reset();
mStaticMesh.reset();
mAvoidStaticMesh.reset();
mAvoidCompoundShape.reset();
mShape->mFileHash = nif.getHash();
@ -208,30 +196,10 @@ namespace NifBullet
}
if (mCompoundShape)
{
if (mStaticMesh != nullptr && mStaticMesh->getNumTriangles() > 0)
{
btTransform trans;
trans.setIdentity();
std::unique_ptr<btCollisionShape> child
= std::make_unique<Resource::TriangleMeshShape>(mStaticMesh.get(), true);
mCompoundShape->addChildShape(trans, child.get());
std::ignore = child.release();
std::ignore = mStaticMesh.release();
}
mShape->mCollisionShape = std::move(mCompoundShape);
}
else if (mStaticMesh != nullptr && mStaticMesh->getNumTriangles() > 0)
{
mShape->mCollisionShape.reset(new Resource::TriangleMeshShape(mStaticMesh.get(), true));
std::ignore = mStaticMesh.release();
}
if (mAvoidStaticMesh != nullptr && mAvoidStaticMesh->getNumTriangles() > 0)
{
mShape->mAvoidCollisionShape.reset(new Resource::TriangleMeshShape(mAvoidStaticMesh.get(), false));
std::ignore = mAvoidStaticMesh.release();
}
if (mAvoidCompoundShape)
mShape->mAvoidCollisionShape = std::move(mAvoidCompoundShape);
return mShape;
}
@ -409,36 +377,39 @@ namespace NifBullet
if (!niGeometry.skin.empty())
isAnimated = false;
if (isAnimated)
{
std::unique_ptr<btTriangleMesh> childMesh = makeChildMesh(niGeometry);
if (childMesh == nullptr || childMesh->getNumTriangles() == 0)
return;
if (!mCompoundShape)
mCompoundShape.reset(new btCompoundShape);
std::unique_ptr<btTriangleMesh> childMesh = makeChildMesh(niGeometry);
if (childMesh == nullptr || childMesh->getNumTriangles() == 0)
return;
auto childShape = std::make_unique<Resource::TriangleMeshShape>(childMesh.get(), true);
std::ignore = childMesh.release();
auto childShape = std::make_unique<Resource::TriangleMeshShape>(childMesh.get(), true);
std::ignore = childMesh.release();
float scale = niGeometry.trafo.scale;
for (const Nif::Parent* parent = nodeParent; parent != nullptr; parent = parent->mParent)
scale *= parent->mNiNode.trafo.scale;
osg::Quat q = transform.getRotate();
osg::Vec3f v = transform.getTrans();
childShape->setLocalScaling(btVector3(scale, scale, scale));
float scale = niGeometry.trafo.scale;
for (const Nif::Parent* parent = nodeParent; parent != nullptr; parent = parent->mParent)
scale *= parent->mNiNode.trafo.scale;
osg::Quat q = transform.getRotate();
osg::Vec3f v = transform.getTrans();
childShape->setLocalScaling(btVector3(scale, scale, scale));
btTransform trans(btQuaternion(q.x(), q.y(), q.z(), q.w()), btVector3(v.x(), v.y(), v.z()));
btTransform trans(btQuaternion(q.x(), q.y(), q.z(), q.w()), btVector3(v.x(), v.y(), v.z()));
mShape->mAnimatedShapes.emplace(niGeometry.recIndex, mCompoundShape->getNumChildShapes());
if (!avoid)
{
if (!mCompoundShape)
mCompoundShape.reset(new btCompoundShape);
if (isAnimated)
mShape->mAnimatedShapes.emplace(niGeometry.recIndex, mCompoundShape->getNumChildShapes());
mCompoundShape->addChildShape(trans, childShape.get());
std::ignore = childShape.release();
}
else if (avoid)
fillTriangleMesh(mAvoidStaticMesh, niGeometry, transform);
else
fillTriangleMesh(mStaticMesh, niGeometry, transform);
{
if (!mAvoidCompoundShape)
mAvoidCompoundShape.reset(new btCompoundShape);
mAvoidCompoundShape->addChildShape(trans, childShape.get());
}
std::ignore = childShape.release();
}
} // namespace NifBullet

@ -64,10 +64,7 @@ namespace NifBullet
bool isAnimated, bool avoid);
std::unique_ptr<btCompoundShape, Resource::DeleteCollisionShape> mCompoundShape;
std::unique_ptr<btTriangleMesh> mStaticMesh;
std::unique_ptr<btTriangleMesh> mAvoidStaticMesh;
std::unique_ptr<btCompoundShape, Resource::DeleteCollisionShape> mAvoidCompoundShape;
osg::ref_ptr<Resource::BulletShape> mShape;
};

Loading…
Cancel
Save