mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -04:00
1071 lines
31 KiB
C++
1071 lines
31 KiB
C++
// Filename: bulletSoftBodyNode.cxx
|
|
// Created by: enn0x (27Dec10)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
|
//
|
|
// All use of this software is subject to the terms of the revised BSD
|
|
// license. You should have received a copy of this license along
|
|
// with this source code in a file named "LICENSE."
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "bulletSoftBodyNode.h"
|
|
#include "bulletSoftBodyConfig.h"
|
|
#include "bulletSoftBodyMaterial.h"
|
|
#include "bulletSoftBodyShape.h"
|
|
#include "bulletSoftBodyWorldInfo.h"
|
|
#include "bulletHelper.h"
|
|
|
|
#include "geomVertexRewriter.h"
|
|
#include "geomVertexReader.h"
|
|
|
|
TypeHandle BulletSoftBodyNode::_type_handle;
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
BulletSoftBodyNode::
|
|
BulletSoftBodyNode(btSoftBody *body, const char *name) : BulletBodyNode(name) {
|
|
|
|
// Synchronised transform
|
|
_sync = TransformState::make_identity();
|
|
_sync_disable = false;
|
|
|
|
// Softbody
|
|
_soft = body;
|
|
_soft->setUserPointer(this);
|
|
|
|
// Shape
|
|
btCollisionShape *shape_ptr = _soft->getCollisionShape();
|
|
|
|
nassertv(shape_ptr != NULL);
|
|
nassertv(shape_ptr->getShapeType() == SOFTBODY_SHAPE_PROXYTYPE);
|
|
|
|
_shapes.push_back(new BulletSoftBodyShape((btSoftBodyCollisionShape *)shape_ptr));
|
|
|
|
// Rendering
|
|
_geom = NULL;
|
|
_curve = NULL;
|
|
_surface = NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::get_object
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
btCollisionObject *BulletSoftBodyNode::
|
|
get_object() const {
|
|
|
|
return _soft;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::get_cfg
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
BulletSoftBodyConfig BulletSoftBodyNode::
|
|
get_cfg() {
|
|
|
|
return BulletSoftBodyConfig(_soft->m_cfg);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::get_world_info
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
BulletSoftBodyWorldInfo BulletSoftBodyNode::
|
|
get_world_info() {
|
|
|
|
return BulletSoftBodyWorldInfo(*(_soft->m_worldInfo));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::get_num_materials
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
int BulletSoftBodyNode::
|
|
get_num_materials() const {
|
|
|
|
return _soft->m_materials.size();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::get_material
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
BulletSoftBodyMaterial BulletSoftBodyNode::
|
|
get_material(int idx) const {
|
|
|
|
nassertr(idx >= 0 && idx < get_num_materials(), BulletSoftBodyMaterial::empty());
|
|
|
|
btSoftBody::Material *material = _soft->m_materials[idx];
|
|
return BulletSoftBodyMaterial(*material);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::append_material
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
BulletSoftBodyMaterial BulletSoftBodyNode::
|
|
append_material() {
|
|
|
|
btSoftBody::Material *material = _soft->appendMaterial();
|
|
nassertr(material, BulletSoftBodyMaterial::empty());
|
|
|
|
return BulletSoftBodyMaterial(*material);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::get_num_nodes
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
int BulletSoftBodyNode::
|
|
get_num_nodes() const {
|
|
|
|
return _soft->m_nodes.size();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::get_node
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
BulletSoftBodyNodeElement BulletSoftBodyNode::
|
|
get_node(int idx) const {
|
|
|
|
nassertr(idx >=0 && idx < get_num_nodes(), BulletSoftBodyNodeElement::empty());
|
|
return BulletSoftBodyNodeElement(_soft->m_nodes[idx]);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::generate_bending_constraints
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
generate_bending_constraints(int distance, BulletSoftBodyMaterial *material) {
|
|
|
|
if (material) {
|
|
_soft->generateBendingConstraints(distance, &(material->get_material()));
|
|
}
|
|
else {
|
|
_soft->generateBendingConstraints(distance);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::randomize_constraints
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
randomize_constraints() {
|
|
|
|
_soft->randomizeConstraints();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::transform_changed
|
|
// Access: Protected
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
transform_changed() {
|
|
|
|
if (_sync_disable) return;
|
|
|
|
NodePath np = NodePath::any_path((PandaNode *)this);
|
|
CPT(TransformState) ts = np.get_net_transform();
|
|
|
|
LMatrix4f m_sync = _sync->get_mat();
|
|
LMatrix4f m_ts = ts->get_mat();
|
|
|
|
if (!m_sync.almost_equal(m_ts)) {
|
|
_sync = ts;
|
|
|
|
btTransform trans = TransformState_to_btTrans(ts);
|
|
|
|
trans *= _soft->m_initialWorldTransform.inverse();
|
|
_soft->transform(trans);
|
|
|
|
if (ts->has_scale()) {
|
|
LVecBase3f scale = ts->get_scale();
|
|
for (int i=0; i<get_num_shapes(); i++) {
|
|
PT(BulletShape) shape = _shapes[i];
|
|
shape->set_local_scale(scale);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::sync_p2b
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
sync_p2b() {
|
|
|
|
transform_changed();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::sync_b2p
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
sync_b2p() {
|
|
|
|
// Render softbody
|
|
if (_geom) {
|
|
btTransform trans = btTransform::getIdentity();
|
|
get_node_transform(trans, this);
|
|
|
|
PT(GeomVertexData) vdata = _geom->modify_vertex_data();
|
|
|
|
GeomVertexRewriter vertices(vdata, InternalName::get_vertex());
|
|
GeomVertexRewriter normals(vdata, InternalName::get_normal());
|
|
GeomVertexReader indices(vdata, BulletHelper::get_sb_index());
|
|
GeomVertexReader flips(vdata, BulletHelper::get_sb_flip());
|
|
|
|
while (!vertices.is_at_end()) {
|
|
btSoftBody::Node node = _soft->m_nodes[indices.get_data1i()];
|
|
btVector3 v = trans.invXform(node.m_x);
|
|
btVector3 n = node.m_n;
|
|
|
|
if (flips.get_data1i() > 0) n *= -1;
|
|
|
|
vertices.set_data3f(v.getX(), v.getY(), v.getZ());
|
|
normals.set_data3f(n.getX(), n.getY(), n.getZ());
|
|
}
|
|
}
|
|
|
|
if (_curve) {
|
|
btSoftBody::tNodeArray &nodes(_soft->m_nodes);
|
|
|
|
for (int i=0; i < nodes.size(); i++) {
|
|
btVector3 pos = nodes[i].m_x;
|
|
_curve->set_vertex(i, btVector3_to_LPoint3f(pos));
|
|
}
|
|
}
|
|
|
|
if (_surface) {
|
|
btSoftBody::tNodeArray &nodes(_soft->m_nodes);
|
|
|
|
int num_u = _surface->get_num_u_vertices();
|
|
int num_v = _surface->get_num_v_vertices();
|
|
nassertv(num_u * num_v == nodes.size());
|
|
|
|
for (int u=0; u < num_u; u++) {
|
|
for (int v=0; v < num_v; v++) {
|
|
btVector3 pos = nodes[u * num_u + v].m_x;
|
|
_surface->set_vertex(u, v, btVector3_to_LPoint3f(pos));
|
|
}
|
|
}
|
|
}
|
|
|
|
// It is ok to pass the address of a temporary object here, because
|
|
// set_bounds does not store the pointer - it makes a copy using
|
|
// volume->make_copy().
|
|
BoundingBox bb = this->get_aabb();
|
|
LVecBase3f pos = bb.get_approx_center();
|
|
|
|
NodePath np = NodePath::any_path((PandaNode *)this);
|
|
LVecBase3f scale = np.get_net_transform()->get_scale();
|
|
|
|
CPT(TransformState) ts = TransformState::make_pos(pos);
|
|
ts = ts->set_scale(scale);
|
|
|
|
_sync = ts;
|
|
_sync_disable = true;
|
|
np.set_transform(NodePath(), ts);
|
|
_sync_disable = false;
|
|
|
|
Thread *current_thread = Thread::get_current_thread();
|
|
this->r_mark_geom_bounds_stale(current_thread);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::get_closest_node_index
|
|
// Access: Published
|
|
// Description: Returns the index of the node which is closest
|
|
// to the given point. The distance between each node
|
|
// and the given point is computed in world space
|
|
// if local=false, and in local space if local=true.
|
|
////////////////////////////////////////////////////////////////////
|
|
int BulletSoftBodyNode::
|
|
get_closest_node_index(LVecBase3f point, bool local) {
|
|
|
|
btScalar max_dist_sqr = 1e30;
|
|
btVector3 point_x = LVecBase3f_to_btVector3(point);
|
|
|
|
btTransform trans = btTransform::getIdentity();
|
|
if (local == true) {
|
|
get_node_transform(trans, this);
|
|
}
|
|
|
|
btSoftBody::tNodeArray &nodes(_soft->m_nodes);
|
|
int node_idx = 0;
|
|
|
|
for (int i=0; i<nodes.size(); ++i) {
|
|
|
|
btVector3 node_x = nodes[i].m_x;
|
|
btScalar dist_sqr = (trans.invXform(node_x) - point_x).length2();
|
|
|
|
if (dist_sqr < max_dist_sqr) {
|
|
max_dist_sqr = dist_sqr;
|
|
node_idx = i;
|
|
}
|
|
}
|
|
|
|
return node_idx;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::link_geom
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
link_geom(Geom *geom) {
|
|
|
|
nassertv(geom->get_vertex_data()->has_column(InternalName::get_vertex()));
|
|
nassertv(geom->get_vertex_data()->has_column(InternalName::get_normal()));
|
|
|
|
sync_p2b();
|
|
|
|
_geom = geom;
|
|
|
|
PT(GeomVertexData) vdata = _geom->modify_vertex_data();
|
|
|
|
if (!vdata->has_column(BulletHelper::get_sb_index())) {
|
|
CPT(GeomVertexFormat) format = vdata->get_format();
|
|
format = BulletHelper::add_sb_index_column(format);
|
|
vdata->set_format(format);
|
|
}
|
|
|
|
if (!vdata->has_column(BulletHelper::get_sb_flip())) {
|
|
CPT(GeomVertexFormat) format = vdata->get_format();
|
|
format = BulletHelper::add_sb_flip_column(format);
|
|
vdata->set_format(format);
|
|
}
|
|
|
|
GeomVertexReader vertices(vdata, InternalName::get_vertex());
|
|
GeomVertexRewriter indices(vdata, BulletHelper::get_sb_index());
|
|
|
|
while (!vertices.is_at_end()) {
|
|
LVecBase3f point = vertices.get_data3f();
|
|
int node_idx = get_closest_node_index(point, true);
|
|
indices.set_data1i(node_idx);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::unlink_geom
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
unlink_geom() {
|
|
|
|
_geom = NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::link_curve
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
link_curve(NurbsCurveEvaluator *curve) {
|
|
|
|
nassertv(curve->get_num_vertices() == _soft->m_nodes.size());
|
|
|
|
_curve = curve;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::unlink_curve
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
unlink_curve() {
|
|
|
|
_curve = NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::link_surface
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
link_surface(NurbsSurfaceEvaluator *surface) {
|
|
|
|
nassertv(surface->get_num_u_vertices() * surface->get_num_v_vertices() == _soft->m_nodes.size());
|
|
|
|
_surface = surface;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::unlink_surface
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
unlink_surface() {
|
|
|
|
_surface = NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::get_aabb
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
BoundingBox BulletSoftBodyNode::
|
|
get_aabb() const {
|
|
|
|
btVector3 pMin;
|
|
btVector3 pMax;
|
|
|
|
_soft->getAabb(pMin, pMax);
|
|
|
|
return BoundingBox(
|
|
btVector3_to_LPoint3f(pMin),
|
|
btVector3_to_LPoint3f(pMax)
|
|
);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::set_volume_mass
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
set_volume_mass(float mass) {
|
|
|
|
_soft->setVolumeMass(mass);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::set_total_mass
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
set_total_mass(float mass, bool fromfaces) {
|
|
|
|
_soft->setTotalMass(mass, fromfaces);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::set_volume_density
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
set_volume_density(float density) {
|
|
|
|
_soft->setVolumeDensity(density);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::set_total_density
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
set_total_density(float density) {
|
|
|
|
_soft->setTotalDensity(density);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::set_mass
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
set_mass(int node, float mass) {
|
|
|
|
_soft->setMass(node, mass);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::get_mass
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
float BulletSoftBodyNode::
|
|
get_mass(int node) const {
|
|
|
|
return _soft->getMass(node);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::get_total_mass
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
float BulletSoftBodyNode::
|
|
get_total_mass() const {
|
|
|
|
return _soft->getTotalMass();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::get_volume
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
float BulletSoftBodyNode::
|
|
get_volume() const {
|
|
|
|
return _soft->getVolume();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::add_force
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
add_force(const LVector3f &force) {
|
|
|
|
nassertv(!force.is_nan());
|
|
_soft->addForce(LVecBase3f_to_btVector3(force));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::add_force
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
add_force(const LVector3f &force, int node) {
|
|
|
|
nassertv(!force.is_nan());
|
|
_soft->addForce(LVecBase3f_to_btVector3(force), node);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::set_velocity
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
set_velocity(const LVector3f &velocity) {
|
|
|
|
nassertv(!velocity.is_nan());
|
|
_soft->setVelocity(LVecBase3f_to_btVector3(velocity));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::add_velocity
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
add_velocity(const LVector3f &velocity) {
|
|
|
|
nassertv(!velocity.is_nan());
|
|
_soft->addVelocity(LVecBase3f_to_btVector3(velocity));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::add_velocity
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
add_velocity(const LVector3f &velocity, int node) {
|
|
|
|
nassertv(!velocity.is_nan());
|
|
_soft->addVelocity(LVecBase3f_to_btVector3(velocity), node);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::generate_clusters
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
generate_clusters(int k, int maxiterations) {
|
|
|
|
_soft->generateClusters(k, maxiterations);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::release_clusters
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
release_clusters() {
|
|
|
|
_soft->releaseClusters();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::release_cluster
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
release_cluster(int index) {
|
|
|
|
_soft->releaseCluster(index);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::get_num_clusters
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
int BulletSoftBodyNode::
|
|
get_num_clusters() const {
|
|
|
|
return _soft->clusterCount();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::cluster_com
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
LVecBase3f BulletSoftBodyNode::
|
|
cluster_com(int cluster) const {
|
|
|
|
return btVector3_to_LVecBase3f(_soft->clusterCom(cluster));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::set_pose
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
set_pose(bool bvolume, bool bframe) {
|
|
|
|
_soft->setPose(bvolume, bframe);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::append_anchor
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
append_anchor(int node, BulletRigidBodyNode *body, bool disable) {
|
|
|
|
nassertv(node < _soft->m_nodes.size())
|
|
nassertv(body);
|
|
|
|
body->sync_p2b();
|
|
|
|
btRigidBody *ptr =(btRigidBody *)body->get_object();
|
|
_soft->appendAnchor(node, ptr, disable);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::append_anchor
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void BulletSoftBodyNode::
|
|
append_anchor(int node, BulletRigidBodyNode *body, const LVector3f &pivot, bool disable) {
|
|
|
|
nassertv(node < _soft->m_nodes.size())
|
|
nassertv(body);
|
|
nassertv(!pivot.is_nan());
|
|
|
|
body->sync_p2b();
|
|
|
|
btRigidBody *ptr =(btRigidBody *)body->get_object();
|
|
_soft->appendAnchor(node, ptr, LVecBase3f_to_btVector3(pivot), disable);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNodeElement::Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
BulletSoftBodyNodeElement::
|
|
BulletSoftBodyNodeElement(btSoftBody::Node &node) : _node(node) {
|
|
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::get_point_index
|
|
// Access: Private
|
|
// Description: Returns the index of the first point within an
|
|
// array of points which has about the same
|
|
// coordinates as the given point. If no points
|
|
// is found -1 is returned.
|
|
////////////////////////////////////////////////////////////////////
|
|
int BulletSoftBodyNode::
|
|
get_point_index(LVecBase3f p, PTA_LVecBase3f points) {
|
|
|
|
float eps = 1.0e-6f; // TODO make this a config option
|
|
|
|
for (PTA_LVecBase3f::size_type i=0; i<points.size(); i++) {
|
|
if (points[i].almost_equal(p, eps)) {
|
|
return i; // Found
|
|
}
|
|
}
|
|
|
|
return -1; // Not found
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::next_line
|
|
// Access: Published
|
|
// Description: Read on until the next linebreak is detected, or
|
|
// the end of file has been reached.
|
|
////////////////////////////////////////////////////////////////////
|
|
int BulletSoftBodyNode::
|
|
next_line(const char* buffer) {
|
|
|
|
int num_bytes_read = 0;
|
|
|
|
while (*buffer != '\n') {
|
|
buffer++;
|
|
num_bytes_read++;
|
|
}
|
|
|
|
if (buffer[0] == 0x0a) {
|
|
buffer++;
|
|
num_bytes_read++;
|
|
}
|
|
|
|
return num_bytes_read;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::make_rope
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
PT(BulletSoftBodyNode) BulletSoftBodyNode::
|
|
make_rope(BulletSoftBodyWorldInfo &info, const LPoint3f &from, const LPoint3f &to, int res, int fixeds) {
|
|
|
|
btSoftBody *body = btSoftBodyHelpers::CreateRope(
|
|
info.get_info(),
|
|
LVecBase3f_to_btVector3(from),
|
|
LVecBase3f_to_btVector3(to),
|
|
res,
|
|
fixeds);
|
|
|
|
PT(BulletSoftBodyNode) node = new BulletSoftBodyNode(body);
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::make_patch
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
PT(BulletSoftBodyNode) BulletSoftBodyNode::
|
|
make_patch(BulletSoftBodyWorldInfo &info, const LPoint3f &corner00, const LPoint3f &corner10, const LPoint3f &corner01, const LPoint3f &corner11, int resx, int resy, int fixeds, bool gendiags) {
|
|
|
|
btSoftBody *body = btSoftBodyHelpers::CreatePatch(
|
|
info.get_info(),
|
|
LVecBase3f_to_btVector3(corner00),
|
|
LVecBase3f_to_btVector3(corner10),
|
|
LVecBase3f_to_btVector3(corner01),
|
|
LVecBase3f_to_btVector3(corner11),
|
|
resx,
|
|
resy,
|
|
fixeds,
|
|
gendiags);
|
|
|
|
PT(BulletSoftBodyNode) node = new BulletSoftBodyNode(body);
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::make_ellipsoid
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
PT(BulletSoftBodyNode) BulletSoftBodyNode::
|
|
make_ellipsoid(BulletSoftBodyWorldInfo &info, const LPoint3f ¢er, const LVecBase3f &radius, int res) {
|
|
|
|
btSoftBody *body = btSoftBodyHelpers::CreateEllipsoid(
|
|
info.get_info(),
|
|
LVecBase3f_to_btVector3(center),
|
|
LVecBase3f_to_btVector3(radius),
|
|
res);
|
|
|
|
PT(BulletSoftBodyNode) node = new BulletSoftBodyNode(body);
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::make_tri_mesh
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
PT(BulletSoftBodyNode) BulletSoftBodyNode::
|
|
make_tri_mesh(BulletSoftBodyWorldInfo &info, PTA_LVecBase3f points, PTA_int indices, bool randomizeConstraints) {
|
|
|
|
// Eliminate duplicate vertices
|
|
PTA_LVecBase3f mapped_points;
|
|
PTA_int mapped_indices;
|
|
|
|
pmap<int, int> mapping;
|
|
|
|
for (PTA_LVecBase3f::size_type i=0; i<points.size(); i++) {
|
|
LVecBase3f p = points[i];
|
|
int j = get_point_index(p, mapped_points);
|
|
if (j < 0) {
|
|
mapping[i] = mapped_points.size();
|
|
mapped_points.push_back(p);
|
|
}
|
|
else {
|
|
mapping[i] = j;
|
|
}
|
|
}
|
|
|
|
for (PTA_int::size_type i=0; i<indices.size(); i++) {
|
|
int idx = indices[i];
|
|
int mapped_idx = mapping[idx];
|
|
mapped_indices.push_back(mapped_idx);
|
|
}
|
|
|
|
points = mapped_points;
|
|
indices = mapped_indices;
|
|
|
|
// Convert arrays
|
|
int num_vertices = points.size();
|
|
int num_triangles = indices.size() / 3;
|
|
|
|
btScalar *vertices = new btScalar[num_vertices * 3];
|
|
for (int i=0; i < num_vertices; i++) {
|
|
vertices[3*i] = points[i].get_x();
|
|
vertices[3*i+1] = points[i].get_y();
|
|
vertices[3*i+2] = points[i].get_z();
|
|
}
|
|
|
|
int *triangles = new int[num_triangles * 3];
|
|
for (int i=0; i < num_triangles * 3; i++) {
|
|
triangles[i] = indices[i];
|
|
}
|
|
|
|
// Create body
|
|
btSoftBody *body = btSoftBodyHelpers::CreateFromTriMesh(
|
|
info.get_info(),
|
|
vertices,
|
|
triangles,
|
|
num_triangles,
|
|
randomizeConstraints);
|
|
|
|
nassertr(body, NULL);
|
|
|
|
delete[] vertices;
|
|
delete[] triangles;
|
|
|
|
PT(BulletSoftBodyNode) node = new BulletSoftBodyNode(body);
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::make_tri_mesh
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
PT(BulletSoftBodyNode) BulletSoftBodyNode::
|
|
make_tri_mesh(BulletSoftBodyWorldInfo &info, const Geom *geom, bool randomizeConstraints) {
|
|
|
|
// Read vertex data
|
|
PTA_LVecBase3f points;
|
|
PTA_int indices;
|
|
|
|
CPT(GeomVertexData) vdata = geom->get_vertex_data();
|
|
|
|
nassertr(vdata->has_column(InternalName::get_vertex()), NULL);
|
|
|
|
GeomVertexReader vreader(vdata, InternalName::get_vertex());
|
|
|
|
while (!vreader.is_at_end()) {
|
|
LVecBase3f v = vreader.get_data3f();
|
|
points.push_back(v);
|
|
}
|
|
|
|
// Read indices
|
|
for (int i=0; i<geom->get_num_primitives(); i++) {
|
|
|
|
CPT(GeomPrimitive) prim = geom->get_primitive(i);
|
|
prim = prim->decompose();
|
|
|
|
for (int j=0; j<prim->get_num_primitives(); j++) {
|
|
|
|
int s = prim->get_primitive_start(j);
|
|
int e = prim->get_primitive_end(j);
|
|
|
|
for (int k=s; k<e; k++) {
|
|
indices.push_back(prim->get_vertex(k));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create body
|
|
return make_tri_mesh(info, points, indices, randomizeConstraints);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::make_tet_mesh
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
PT(BulletSoftBodyNode) BulletSoftBodyNode::
|
|
make_tet_mesh(BulletSoftBodyWorldInfo &info, PTA_LVecBase3f points, PTA_int indices, bool tetralinks) {
|
|
|
|
// Points
|
|
btAlignedObjectArray<btVector3> pos;
|
|
pos.resize(points.size());
|
|
for (PTA_LVecBase3f::size_type i=0; i<points.size(); i++) {
|
|
LVecBase3f point = points[i];
|
|
pos[i] = LVecBase3f_to_btVector3(point);
|
|
}
|
|
|
|
// Body
|
|
btSoftBody* body = new btSoftBody(&info.get_info(), pos.size(), &pos[0], 0);
|
|
|
|
// Indices
|
|
for (PTA_int::size_type i=0; i<indices.size() / 4; i++) {
|
|
int ni[4];
|
|
|
|
ni[0] = indices[4*i];
|
|
ni[1] = indices[4*i+1];
|
|
ni[2] = indices[4*i+2];
|
|
ni[3] = indices[4*i+3];
|
|
|
|
body->appendTetra(ni[0],ni[1],ni[2],ni[3]);
|
|
|
|
if (tetralinks) {
|
|
body->appendLink(ni[0], ni[1], 0, true);
|
|
body->appendLink(ni[1], ni[2], 0, true);
|
|
body->appendLink(ni[2], ni[0], 0, true);
|
|
body->appendLink(ni[0], ni[3], 0, true);
|
|
body->appendLink(ni[1], ni[3], 0, true);
|
|
body->appendLink(ni[2], ni[3], 0, true);
|
|
}
|
|
}
|
|
|
|
// Node
|
|
PT(BulletSoftBodyNode) node = new BulletSoftBodyNode(body);
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: BulletSoftBodyNode::make_tet_mesh
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
PT(BulletSoftBodyNode) BulletSoftBodyNode::
|
|
make_tet_mesh(BulletSoftBodyWorldInfo &info, const char *ele, const char *face, const char *node) {
|
|
|
|
nassertr(node && node[0], NULL);
|
|
|
|
// Nodes
|
|
btAlignedObjectArray<btVector3> pos;
|
|
|
|
int npos = 0;
|
|
int ndims = 0; // not used
|
|
int nattrb = 0; // not used
|
|
int hasbounds = 0; // not used
|
|
|
|
sscanf(node, "%d %d %d %d", &npos, &ndims, &nattrb, &hasbounds);
|
|
node += next_line(node);
|
|
|
|
pos.resize(npos);
|
|
|
|
for (int i=0; i<pos.size(); ++i) {
|
|
int index = 0;
|
|
float x, y, z;
|
|
|
|
sscanf(node, "%d %f %f %f", &index, &x, &y, &z);
|
|
node += next_line(node);
|
|
|
|
pos[index].setX(btScalar(x));
|
|
pos[index].setY(btScalar(y));
|
|
pos[index].setZ(btScalar(z));
|
|
}
|
|
|
|
// Body
|
|
btSoftBody *body = new btSoftBody(&info.get_info(), npos, &pos[0], 0);
|
|
|
|
// Faces
|
|
if (face && face[0]) {
|
|
int nface = 0;
|
|
int hasbounds = 0; // not used
|
|
|
|
sscanf(face, "%d %d", &nface, &hasbounds);
|
|
face += next_line(face);
|
|
|
|
for (int i=0; i<nface; ++i) {
|
|
int index = 0;
|
|
int ni[3];
|
|
|
|
sscanf(face, "%d %d %d %d", &index, &ni[0], &ni[1], &ni[2]);
|
|
face += next_line(face);
|
|
|
|
body->appendFace(ni[0], ni[1], ni[2]);
|
|
}
|
|
}
|
|
|
|
// Links
|
|
if (ele && ele[0]) {
|
|
int ntetra = 0;
|
|
int ncorner = 0;
|
|
int neattrb = 0;
|
|
|
|
sscanf(ele, "%d %d %d", &ntetra, &ncorner, &neattrb);
|
|
ele += next_line(ele);
|
|
|
|
for (int i=0; i<ntetra; ++i) {
|
|
int index = 0;
|
|
int ni[4];
|
|
|
|
sscanf(ele, "%d %d %d %d %d", &index, &ni[0], &ni[1], &ni[2], &ni[3]);
|
|
ele += next_line(ele);
|
|
|
|
body->appendTetra(ni[0], ni[1], ni[2], ni[3]);
|
|
|
|
body->appendLink(ni[0], ni[1], 0, true);
|
|
body->appendLink(ni[1], ni[2], 0, true);
|
|
body->appendLink(ni[2], ni[0], 0, true);
|
|
body->appendLink(ni[0], ni[3], 0, true);
|
|
body->appendLink(ni[1], ni[3], 0, true);
|
|
body->appendLink(ni[2], ni[3], 0, true);
|
|
}
|
|
}
|
|
|
|
// Node
|
|
PT(BulletSoftBodyNode) sbnode = new BulletSoftBodyNode(body);
|
|
|
|
return sbnode;
|
|
}
|
|
|