Lock texture in softbody

So I was using the triangle mesh softbody that used the .linkGeom() command to apply colors and textures like shown in the manual. The applied textures however, don’t receive the rotation of the softbody which results in a weird texture display where the texture stays in one spot and gets cut off. When i rotate the body through the .setHpr() command, the texture follows the transform.

I tested if the softbody shares its transform states with parented nodes but only seems to share it’s position and not rotation / scale. How would I fix this issue?

What can i do to keep the texture fixed in place.

It is difficult to answer your question without an example. I think you need to produce a minimal example with resources to continue the discussion.

It would be hard to show you my code as it is made up of various classes in different scripts. But here is how I make the softbody and add the geometry to it (scene = render; scene.bulletworld = bulletworld):

class PressureSoftBodyCollider:
    def __init__(self, shape, name,  mass):
        self.SoftBody = BulletSoftBodyNode.make_tri_mesh(scene.bulletworld.getWorldInfo(), shape)

        self.SoftBody.getMaterial(0).setLinearStiffness(0.1)
        self.SoftBody.getCfg().setDynamicFrictionCoefficient(1)
        self.SoftBody.getCfg().setDampingCoefficient(0.001)
        self.SoftBody.getCfg().setPressureCoefficient(1500)
        self.SoftBody.setPose(True, False)

        self.SoftBody.setName(name)
        self.SoftBody.setTotalMass(mass, True)

        self.np = scene.attachNewNode(self.SoftBody)
        scene.bulletworld.attachSoftBody(self.np.node())

        fmt = GeomVertexFormat.getV3n3t2()
        self.geom = BulletHelper.makeGeomFromFaces(self.SoftBody, fmt)
        self.SoftBody.linkGeom(self.geom)
        self.visNode = GeomNode('Visual')
        self.visNode.addGeom(self.geom)
        self.visualNode = self.np.attachNewNode(self.visNode)

and to apply textures I do:
(I have made a custom Texture class called Texture where to access the panda texture, you do self._texture._texture)

        self._texture = Texture(self.texture.path)

        self._texture._texture.setWrapU(PandaTexture.WM_repeat)
        self._texture._texture.setWrapV(PandaTexture.WM_repeat)
        self.visualNode.setTexture(self._texture._texture)

        self.visualNode.setTexGen(TextureStage.getDefault(), TexGenAttrib.MWorldPosition)

        self.visualNode.setTexProjector(TextureStage.getDefault(), render, self.np)

I also have a video showing the texturing problem. Here is the link:
Bread.mkv

I don’t think it’s difficult to write a minimal example, but I noticed a problem, you’re using a texture coordinate generator. This approach is unlikely to work, you should use the texture coordinates of the geom node.

how could I do this?

edit: like if I apply the texture naked with no other changes, it doesn’t show the full texture. I tried scaling the texture but it did nothing.

Just do it in the 3d modeling editor. You need to create a UV mapping of the texture

I tried using mapped UV models with textures but it still had the same result. Keep in mind I still applied the texture from the model onto it manually as it didn’t apply any texture at default / automatically like normal model loading does. I also checked the models geom’s texture coords and they all matched to a replicated model loaded normally.

Interesting, it works for me, perhaps you interpreted the bullet examples incorrectly. In 8 hours I will be able to provide you with a working code sample.

I looked into the geom’s UV coords of the softbody and found that every patch’s coords are set to
(0.0, 0.0). Its weird how the models geom’s Data2f did not go over to the softbodys geom data.

This is not the case, you don’t need to create a new geom node. All you have to do is get a handle to an existing one.

That’s how I do it, there’s no problem.

from direct.showbase.ShowBase import ShowBase

from panda3d.core import NodePath
from panda3d.bullet import BulletWorld, BulletPlaneShape, BulletRigidBodyNode, BulletSoftBodyNode

class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.world = BulletWorld()
        self.world.set_gravity((0, 0, -9.81))

        bullet_node_ground = BulletRigidBodyNode('ground')
        bullet_node_ground.add_shape(BulletPlaneShape((0, 0, 1), 0))
        self.world.attach_rigid_body(bullet_node_ground)

        model = loader.load_model('models/suzanne.bam')
        geom = model.node().modify_geom(0)

        bullet_soft = BulletSoftBodyNode.make_tri_mesh(self.world.get_world_info(), geom)
        bullet_soft.link_geom(geom)
        bullet_soft.generate_bending_constraints(3)
        bullet_soft.get_cfg().set_positions_solver_iterations(2)
        bullet_soft.randomize_constraints()
        bullet_soft.set_total_mass(50, True)
        self.world.attach_soft_body(bullet_soft)

        model_soft = NodePath(bullet_soft)
        model_soft.set_pos((0, 10, 5))
        model_soft.reparent_to(render)
        model.reparent_to(model_soft)

        taskMgr.add(self.update, 'updateWorld')

    def update(self, task):
        self.world.do_physics(base.clock.get_dt(), 10, 0.008)
        return task.cont

game = Game()
game.run()

resources (846.3 KB)

your code works for .bam files, but I am also trying to get other formats like gltf to work as well.
when I load something either than a .bam, this error appears:

        geom = model.node().modify_geom(0)
           ^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'panda3d.core.ModelRoot' object has no attribute 'modify_geom'

is there a way to allow other formats to also work with the softbody?

You have misinterpreted this circumstance again, there is no difference what format the difference is in how you find the geom object in the hierarchy.

This answer provides an example of how to get exactly the data that is needed, but for this you need to know the hierarchy.

.get_child()

I just tested again and added random UV data to the geom that is sent to make the softbody and the textures now show in a way. All I need right now is a way to extract UV data from a loaded model.

Anyway, you’re off topic. So it has nothing to do with the soft body. The author of the examples for bullet used geometry generation to visualize the body, but not as a way to create visible geometry.

Here is a rebuttal to your claim that my code only works with the bam format.

from direct.showbase.ShowBase import ShowBase

from panda3d.core import NodePath
from panda3d.bullet import BulletWorld, BulletPlaneShape, BulletRigidBodyNode, BulletSoftBodyNode

class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.world = BulletWorld()
        self.world.set_gravity((0, 0, -9.81))

        bullet_node_ground = BulletRigidBodyNode('ground')
        bullet_node_ground.add_shape(BulletPlaneShape((0, 0, 1), 0))
        self.world.attach_rigid_body(bullet_node_ground)

        model = loader.load_model('smiley.egg')
        geom = model.get_child(0).node().modify_geom(0)

        bullet_soft = BulletSoftBodyNode.make_tri_mesh(self.world.get_world_info(), geom)
        bullet_soft.link_geom(geom)
        bullet_soft.generate_bending_constraints(3)
        bullet_soft.get_cfg().set_positions_solver_iterations(2)
        bullet_soft.randomize_constraints()
        bullet_soft.set_total_mass(50, True)
        self.world.attach_soft_body(bullet_soft)

        model_soft = NodePath(bullet_soft)
        model_soft.set_pos((0, 10, 5))
        model_soft.reparent_to(render)
        model.reparent_to(model_soft)

        taskMgr.add(self.update, 'updateWorld')

    def update(self, task):
        self.world.do_physics(base.clock.get_dt(), 10, 0.008)
        return task.cont

game = Game()
game.run()