/******************************************************************************* * Copyright 2011 See AUTHORS file. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package com.badlogic.gdx.tests.bullet; import java.nio.ShortBuffer; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.VertexAttributes.Usage; import com.badlogic.gdx.graphics.g3d.Model; import com.badlogic.gdx.graphics.g3d.model.MeshPart; import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.physics.bullet.collision.btAxisSweep3; import com.badlogic.gdx.physics.bullet.collision.btCollisionDispatcher; import com.badlogic.gdx.physics.bullet.collision.btCollisionObject; import com.badlogic.gdx.physics.bullet.collision.btDefaultCollisionConfiguration; import com.badlogic.gdx.physics.bullet.dynamics.btSequentialImpulseConstraintSolver; import com.badlogic.gdx.physics.bullet.softbody.btSoftBody; import com.badlogic.gdx.physics.bullet.softbody.btSoftBodyRigidBodyCollisionConfiguration; import com.badlogic.gdx.physics.bullet.softbody.btSoftBodyWorldInfo; import com.badlogic.gdx.physics.bullet.softbody.btSoftRigidDynamicsWorld; import com.badlogic.gdx.utils.BufferUtils; /** @author xoppa */ public class SoftMeshTest extends BaseBulletTest { btSoftBodyWorldInfo worldInfo; btSoftBody softBody; Model model; BulletEntity entity; ShortBuffer indexMap; Vector3 tmpV = new Vector3(); int positionOffset; int normalOffset; @Override public BulletWorld createWorld () { btDefaultCollisionConfiguration collisionConfiguration = new btSoftBodyRigidBodyCollisionConfiguration(); btCollisionDispatcher dispatcher = new btCollisionDispatcher(collisionConfiguration); btAxisSweep3 broadphase = new btAxisSweep3(tmpV1.set(-1000, -1000, -1000), tmpV2.set(1000, 1000, 1000), 1024); btSequentialImpulseConstraintSolver solver = new btSequentialImpulseConstraintSolver(); btSoftRigidDynamicsWorld dynamicsWorld = new btSoftRigidDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration); worldInfo = new btSoftBodyWorldInfo(); worldInfo.setBroadphase(broadphase); worldInfo.setDispatcher(dispatcher); worldInfo.getSparsesdf().Initialize(); return new BulletWorld(collisionConfiguration, dispatcher, broadphase, solver, dynamicsWorld); } @Override public void create () { super.create(); world.maxSubSteps = 20; world.add("ground", 0f, 0f, 0f).setColor(0.25f + 0.5f * (float)Math.random(), 0.25f + 0.5f * (float)Math.random(), 0.25f + 0.5f * (float)Math.random(), 1f); // Note: not every model is suitable for a one on one translation with a soft body, a better model might be added later. model = objLoader.loadModel(Gdx.files.internal("data/wheel.obj")); MeshPart meshPart = model.nodes.get(0).parts.get(0).meshPart; meshPart.mesh.scale(6, 6, 6); indexMap = BufferUtils.newShortBuffer(meshPart.size); positionOffset = meshPart.mesh.getVertexAttribute(Usage.Position).offset; normalOffset = meshPart.mesh.getVertexAttribute(Usage.Normal).offset; softBody = new btSoftBody(worldInfo, meshPart.mesh.getVerticesBuffer(), meshPart.mesh.getVertexSize(), positionOffset, normalOffset, meshPart.mesh.getIndicesBuffer(), meshPart.offset, meshPart.size, indexMap, 0); // Set mass of the first vertex to zero so its unmovable, comment out this line to make it a fully dynamic body. softBody.setMass(0, 0); com.badlogic.gdx.physics.bullet.softbody.btSoftBody.Material pm = softBody.appendMaterial(); pm.setKLST(0.2f); pm.setFlags(0); softBody.generateBendingConstraints(2, pm); // Be careful increasing iterations, it decreases performance (but increases accuracy). softBody.setConfig_piterations(7); softBody.setConfig_kDF(0.2f); softBody.randomizeConstraints(); softBody.setTotalMass(1); softBody.translate(tmpV.set(1, 5, 1)); ((btSoftRigidDynamicsWorld)(world.collisionWorld)).addSoftBody(softBody); world.add(entity = new BulletEntity(model, (btCollisionObject)null, 1, 5, 1)); } @Override public void dispose () { ((btSoftRigidDynamicsWorld)(world.collisionWorld)).removeSoftBody(softBody); softBody.dispose(); softBody = null; indexMap = null; super.dispose(); worldInfo.dispose(); worldInfo = null; model.dispose(); model = null; } @Override public void render () { if (world.renderMeshes) { MeshPart meshPart = model.nodes.get(0).parts.get(0).meshPart; softBody.getVertices(meshPart.mesh.getVerticesBuffer(), meshPart.mesh.getVertexSize(), positionOffset, normalOffset, meshPart.mesh.getIndicesBuffer(), meshPart.offset, meshPart.size, indexMap, 0); softBody.getWorldTransform(entity.transform); } super.render(); } @Override public boolean tap (float x, float y, int count, int button) { shoot(x, y, 20f); return true; } }