1 /******************************************************************************* 2 * Copyright 2011 See AUTHORS file. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 ******************************************************************************/ 16 17 package com.badlogic.gdx.tests.bullet; 18 19 import java.nio.ShortBuffer; 20 21 import com.badlogic.gdx.Gdx; 22 import com.badlogic.gdx.graphics.VertexAttributes.Usage; 23 import com.badlogic.gdx.graphics.g3d.Model; 24 import com.badlogic.gdx.graphics.g3d.model.MeshPart; 25 import com.badlogic.gdx.math.Vector3; 26 import com.badlogic.gdx.physics.bullet.collision.btAxisSweep3; 27 import com.badlogic.gdx.physics.bullet.collision.btCollisionDispatcher; 28 import com.badlogic.gdx.physics.bullet.collision.btCollisionObject; 29 import com.badlogic.gdx.physics.bullet.collision.btDefaultCollisionConfiguration; 30 import com.badlogic.gdx.physics.bullet.dynamics.btSequentialImpulseConstraintSolver; 31 import com.badlogic.gdx.physics.bullet.softbody.btSoftBody; 32 import com.badlogic.gdx.physics.bullet.softbody.btSoftBodyRigidBodyCollisionConfiguration; 33 import com.badlogic.gdx.physics.bullet.softbody.btSoftBodyWorldInfo; 34 import com.badlogic.gdx.physics.bullet.softbody.btSoftRigidDynamicsWorld; 35 import com.badlogic.gdx.utils.BufferUtils; 36 37 /** @author xoppa */ 38 public class SoftMeshTest extends BaseBulletTest { 39 btSoftBodyWorldInfo worldInfo; 40 btSoftBody softBody; 41 Model model; 42 BulletEntity entity; 43 ShortBuffer indexMap; 44 Vector3 tmpV = new Vector3(); 45 int positionOffset; 46 int normalOffset; 47 48 @Override createWorld()49 public BulletWorld createWorld () { 50 btDefaultCollisionConfiguration collisionConfiguration = new btSoftBodyRigidBodyCollisionConfiguration(); 51 btCollisionDispatcher dispatcher = new btCollisionDispatcher(collisionConfiguration); 52 btAxisSweep3 broadphase = new btAxisSweep3(tmpV1.set(-1000, -1000, -1000), tmpV2.set(1000, 1000, 1000), 1024); 53 btSequentialImpulseConstraintSolver solver = new btSequentialImpulseConstraintSolver(); 54 btSoftRigidDynamicsWorld dynamicsWorld = new btSoftRigidDynamicsWorld(dispatcher, broadphase, solver, 55 collisionConfiguration); 56 57 worldInfo = new btSoftBodyWorldInfo(); 58 worldInfo.setBroadphase(broadphase); 59 worldInfo.setDispatcher(dispatcher); 60 worldInfo.getSparsesdf().Initialize(); 61 62 return new BulletWorld(collisionConfiguration, dispatcher, broadphase, solver, dynamicsWorld); 63 } 64 65 @Override create()66 public void create () { 67 super.create(); 68 69 world.maxSubSteps = 20; 70 71 world.add("ground", 0f, 0f, 0f).setColor(0.25f + 0.5f * (float)Math.random(), 0.25f + 0.5f * (float)Math.random(), 72 0.25f + 0.5f * (float)Math.random(), 1f); 73 74 // Note: not every model is suitable for a one on one translation with a soft body, a better model might be added later. 75 model = objLoader.loadModel(Gdx.files.internal("data/wheel.obj")); 76 MeshPart meshPart = model.nodes.get(0).parts.get(0).meshPart; 77 78 meshPart.mesh.scale(6, 6, 6); 79 80 indexMap = BufferUtils.newShortBuffer(meshPart.size); 81 82 positionOffset = meshPart.mesh.getVertexAttribute(Usage.Position).offset; 83 normalOffset = meshPart.mesh.getVertexAttribute(Usage.Normal).offset; 84 85 softBody = new btSoftBody(worldInfo, meshPart.mesh.getVerticesBuffer(), meshPart.mesh.getVertexSize(), positionOffset, 86 normalOffset, meshPart.mesh.getIndicesBuffer(), meshPart.offset, meshPart.size, indexMap, 0); 87 // Set mass of the first vertex to zero so its unmovable, comment out this line to make it a fully dynamic body. 88 softBody.setMass(0, 0); 89 com.badlogic.gdx.physics.bullet.softbody.btSoftBody.Material pm = softBody.appendMaterial(); 90 pm.setKLST(0.2f); 91 pm.setFlags(0); 92 softBody.generateBendingConstraints(2, pm); 93 // Be careful increasing iterations, it decreases performance (but increases accuracy). 94 softBody.setConfig_piterations(7); 95 softBody.setConfig_kDF(0.2f); 96 softBody.randomizeConstraints(); 97 softBody.setTotalMass(1); 98 softBody.translate(tmpV.set(1, 5, 1)); 99 ((btSoftRigidDynamicsWorld)(world.collisionWorld)).addSoftBody(softBody); 100 101 world.add(entity = new BulletEntity(model, (btCollisionObject)null, 1, 5, 1)); 102 } 103 104 @Override dispose()105 public void dispose () { 106 ((btSoftRigidDynamicsWorld)(world.collisionWorld)).removeSoftBody(softBody); 107 softBody.dispose(); 108 softBody = null; 109 indexMap = null; 110 111 super.dispose(); 112 113 worldInfo.dispose(); 114 worldInfo = null; 115 model.dispose(); 116 model = null; 117 } 118 119 @Override render()120 public void render () { 121 if (world.renderMeshes) { 122 MeshPart meshPart = model.nodes.get(0).parts.get(0).meshPart; 123 softBody.getVertices(meshPart.mesh.getVerticesBuffer(), meshPart.mesh.getVertexSize(), positionOffset, normalOffset, 124 meshPart.mesh.getIndicesBuffer(), meshPart.offset, meshPart.size, indexMap, 0); 125 softBody.getWorldTransform(entity.transform); 126 } 127 super.render(); 128 } 129 130 @Override tap(float x, float y, int count, int button)131 public boolean tap (float x, float y, int count, int button) { 132 shoot(x, y, 20f); 133 return true; 134 } 135 } 136