diff options
author | Joseph Eagar <joeedh@gmail.com> | 2010-01-06 01:33:41 +0300 |
---|---|---|
committer | Joseph Eagar <joeedh@gmail.com> | 2010-01-06 01:33:41 +0300 |
commit | 67ff197cb1b0e79a95bf6546b5fe1a481b79fce1 (patch) | |
tree | 9f78d5cda71d200cab6475eb9c2747f7181adf3a /source/gameengine/Physics | |
parent | 473f235a6eee6c02cf41a1e173f53406b62440aa (diff) | |
parent | ffe13aeb232ac6bad3a98997b4a352f434293193 (diff) |
Merge with trunk/2.5 at r25563
Most likely will not compile for others, I'd appreciate any build errors
and missing files reports (I can never seem to get everything committed
and all the build systems working without help).
Porting over the sculpt/multires tools was a breeze,
thanks goes to brecht for a design that didn't exclude
ngons and was easy to port.
Note that I've not tested externally-backed multires
file support yet. Also, I still need to write version
patch code for some cases.
Some notes:
* Like trunk, topological changes don't update multires right,
so e.g. subdivide will duplicate multires data on the new faces,
instead of subdividing it.
* If you set the debug value (ctrl-alt-d) to 1 it'll turn on
my experiments in speeding up sculpting on higher-res multires
meshes (but note it makes partial redraw not completely accurate).
* There's a bug where you have to go through editmode to get out
of sculpt mode, not sure if I inherited or created this myself.
Diffstat (limited to 'source/gameengine/Physics')
5 files changed, 448 insertions, 338 deletions
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp index 97d9d488db9..4a3ba44e58c 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp @@ -161,338 +161,272 @@ btSoftBody* CcdPhysicsController::GetSoftBody() #include "BulletSoftBody/btSoftBodyHelpers.h" - -void CcdPhysicsController::CreateRigidbody() +bool CcdPhysicsController::CreateSoftbody() { - - //btTransform trans = GetTransformFromMotionState(m_MotionState); - m_bulletMotionState = new BlenderBulletMotionState(m_MotionState); - - ///either create a btCollisionObject, btRigidBody or btSoftBody - - //create a collision object - int shapeType = m_cci.m_collisionShape ? m_cci.m_collisionShape->getShapeType() : 0; //disable soft body until first sneak preview is ready - if (m_cci.m_bSoft && m_cci.m_collisionShape && - (shapeType == CONVEX_HULL_SHAPE_PROXYTYPE)| - (shapeType == TRIANGLE_MESH_SHAPE_PROXYTYPE) | - (shapeType == SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE)) + if (!m_cci.m_bSoft || !m_cci.m_collisionShape || + ((shapeType != CONVEX_HULL_SHAPE_PROXYTYPE)&& + (shapeType != TRIANGLE_MESH_SHAPE_PROXYTYPE) && + (shapeType != SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE))) { - btRigidBody::btRigidBodyConstructionInfo rbci(m_cci.m_mass,m_bulletMotionState,m_collisionShape,m_cci.m_localInertiaTensor * m_cci.m_inertiaFactor); - rbci.m_linearDamping = m_cci.m_linearDamping; - rbci.m_angularDamping = m_cci.m_angularDamping; - rbci.m_friction = m_cci.m_friction; - rbci.m_restitution = m_cci.m_restitution; - - - - - - - btVector3 p(0,0,0);// = getOrigin(); - - - btSoftRigidDynamicsWorld* softDynaWorld = (btSoftRigidDynamicsWorld*)m_cci.m_physicsEnv->getDynamicsWorld(); - - PHY__Vector3 grav; - grav[0] = softDynaWorld->getGravity().getX(); - grav[1] = softDynaWorld->getGravity().getY(); - grav[2] = softDynaWorld->getGravity().getZ(); - softDynaWorld->getWorldInfo().m_gravity.setValue(grav[0],grav[1],grav[2]); //?? + return false; + } + btRigidBody::btRigidBodyConstructionInfo rbci(m_cci.m_mass,m_bulletMotionState,m_collisionShape,m_cci.m_localInertiaTensor * m_cci.m_inertiaFactor); + rbci.m_linearDamping = m_cci.m_linearDamping; + rbci.m_angularDamping = m_cci.m_angularDamping; + rbci.m_friction = m_cci.m_friction; + rbci.m_restitution = m_cci.m_restitution; - //btSoftBody* psb=btSoftBodyHelpers::CreateRope(sbi, btVector3(-10,0,i*0.25),btVector3(10,0,i*0.25), 16,1+2); - - btSoftBody* psb = 0; + btVector3 p(0,0,0);// = getOrigin(); + //btSoftBody* psb=btSoftBodyHelpers::CreateRope(worldInfo, btVector3(-10,0,i*0.25),btVector3(10,0,i*0.25), 16,1+2); + btSoftBody* psb = 0; + btSoftBodyWorldInfo& worldInfo = m_cci.m_physicsEnv->getDynamicsWorld()->getWorldInfo(); - if (m_cci.m_collisionShape->getShapeType() == CONVEX_HULL_SHAPE_PROXYTYPE) + if (m_cci.m_collisionShape->getShapeType() == CONVEX_HULL_SHAPE_PROXYTYPE) + { + btConvexHullShape* convexHull = (btConvexHullShape* )m_cci.m_collisionShape; { - btConvexHullShape* convexHull = (btConvexHullShape* )m_cci.m_collisionShape; - - //psb = btSoftBodyHelpers::CreateFromConvexHull(sbi,&transformedVertices[0],convexHull->getNumPoints()); - + int nvertices = convexHull->getNumPoints(); + const btVector3* vertices = convexHull->getPoints(); + + HullDesc hdsc(QF_TRIANGLES,nvertices,vertices); + HullResult hres; + HullLibrary hlib;/*??*/ + hdsc.mMaxVertices=nvertices; + hlib.CreateConvexHull(hdsc,hres); + + psb=new btSoftBody(&worldInfo,(int)hres.mNumOutputVertices, + &hres.m_OutputVertices[0],0); + for(int i=0;i<(int)hres.mNumFaces;++i) { - int nvertices = convexHull->getNumPoints(); - const btVector3* vertices = convexHull->getPoints(); - btSoftBodyWorldInfo& worldInfo = softDynaWorld->getWorldInfo(); - - HullDesc hdsc(QF_TRIANGLES,nvertices,vertices); - HullResult hres; - HullLibrary hlib;/*??*/ - hdsc.mMaxVertices=nvertices; - hlib.CreateConvexHull(hdsc,hres); - - psb=new btSoftBody(&worldInfo,(int)hres.mNumOutputVertices, - &hres.m_OutputVertices[0],0); - for(int i=0;i<(int)hres.mNumFaces;++i) - { - const int idx[]={ hres.m_Indices[i*3+0], - hres.m_Indices[i*3+1], - hres.m_Indices[i*3+2]}; - if(idx[0]<idx[1]) psb->appendLink( idx[0],idx[1]); - if(idx[1]<idx[2]) psb->appendLink( idx[1],idx[2]); - if(idx[2]<idx[0]) psb->appendLink( idx[2],idx[0]); - psb->appendFace(idx[0],idx[1],idx[2]); - } - - - - hlib.ReleaseResult(hres); + const int idx[]={ hres.m_Indices[i*3+0], + hres.m_Indices[i*3+1], + hres.m_Indices[i*3+2]}; + if(idx[0]<idx[1]) psb->appendLink( idx[0],idx[1]); + if(idx[1]<idx[2]) psb->appendLink( idx[1],idx[2]); + if(idx[2]<idx[0]) psb->appendLink( idx[2],idx[0]); + psb->appendFace(idx[0],idx[1],idx[2]); + } + hlib.ReleaseResult(hres); + } + } else + { + int numtris = 0; + if (m_cci.m_collisionShape->getShapeType() ==SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE) + { + btScaledBvhTriangleMeshShape* scaledtrimeshshape = (btScaledBvhTriangleMeshShape*) m_cci.m_collisionShape; + btBvhTriangleMeshShape* trimeshshape = scaledtrimeshshape->getChildShape(); + ///only deal with meshes that have 1 sub part/component, for now + if (trimeshshape->getMeshInterface()->getNumSubParts()==1) + { + unsigned char* vertexBase; + PHY_ScalarType vertexType; + int numverts; + int vertexstride; + unsigned char* indexbase; + int indexstride; + PHY_ScalarType indexType; + trimeshshape->getMeshInterface()->getLockedVertexIndexBase(&vertexBase,numverts,vertexType,vertexstride,&indexbase,indexstride,numtris,indexType); + psb = btSoftBodyHelpers::CreateFromTriMesh(worldInfo,(const btScalar*)vertexBase,(const int*)indexbase,numtris,false); } - - - - - - } else { - - btSoftBodyWorldInfo& sbi= softDynaWorld->getWorldInfo(); - - if (m_cci.m_collisionShape->getShapeType() ==SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE) + btBvhTriangleMeshShape* trimeshshape = (btBvhTriangleMeshShape*) m_cci.m_collisionShape; + ///only deal with meshes that have 1 sub part/component, for now + if (trimeshshape->getMeshInterface()->getNumSubParts()==1) { - btScaledBvhTriangleMeshShape* scaledtrimeshshape = (btScaledBvhTriangleMeshShape*) m_cci.m_collisionShape; - btBvhTriangleMeshShape* trimeshshape = scaledtrimeshshape->getChildShape(); - - ///only deal with meshes that have 1 sub part/component, for now - if (trimeshshape->getMeshInterface()->getNumSubParts()==1) - { - unsigned char* vertexBase; - PHY_ScalarType vertexType; - int numverts; - int vertexstride; - unsigned char* indexbase; - int indexstride; - int numtris; - PHY_ScalarType indexType; - trimeshshape->getMeshInterface()->getLockedVertexIndexBase(&vertexBase,numverts,vertexType,vertexstride,&indexbase,indexstride,numtris,indexType); - - psb = btSoftBodyHelpers::CreateFromTriMesh(sbi,(const btScalar*)vertexBase,(const int*)indexbase,numtris); - } - } else - { - btBvhTriangleMeshShape* trimeshshape = (btBvhTriangleMeshShape*) m_cci.m_collisionShape; - ///only deal with meshes that have 1 sub part/component, for now - if (trimeshshape->getMeshInterface()->getNumSubParts()==1) - { - unsigned char* vertexBase; - PHY_ScalarType vertexType; - int numverts; - int vertexstride; - unsigned char* indexbase; - int indexstride; - int numtris; - PHY_ScalarType indexType; - trimeshshape->getMeshInterface()->getLockedVertexIndexBase(&vertexBase,numverts,vertexType,vertexstride,&indexbase,indexstride,numtris,indexType); - - psb = btSoftBodyHelpers::CreateFromTriMesh(sbi,(const btScalar*)vertexBase,(const int*)indexbase,numtris); - } - - - //psb = btSoftBodyHelpers::CreateFromTriMesh(sbi,&pts[0].getX(),triangles,numtriangles); + unsigned char* vertexBase; + PHY_ScalarType vertexType; + int numverts; + int vertexstride; + unsigned char* indexbase; + int indexstride; + PHY_ScalarType indexType; + trimeshshape->getMeshInterface()->getLockedVertexIndexBase(&vertexBase,numverts,vertexType,vertexstride,&indexbase,indexstride,numtris,indexType); + + psb = btSoftBodyHelpers::CreateFromTriMesh(worldInfo,(const btScalar*)vertexBase,(const int*)indexbase,numtris,false); } - } - if (m_cci.m_margin > 0.f) + // store face tag so that we can find our original face when doing ray casting + btSoftBody::Face* ft; + int i; + for (i=0, ft=&psb->m_faces[0]; i<numtris; ++i, ++ft) { - psb->getCollisionShape()->setMargin(m_cci.m_margin); - psb->updateBounds(); + // Hack!! use m_tag to store the face number, normally it is a pointer + // add 1 to make sure it is never 0 + ft->m_tag = (void*)((uintptr_t)(i+1)); } + } + if (m_cci.m_margin > 0.f) + { + psb->getCollisionShape()->setMargin(m_cci.m_margin); + psb->updateBounds(); + } + m_object = psb; - - m_object = psb; - - //psb->m_cfg.collisions = btSoftBody::fCollision::SDF_RS;//btSoftBody::fCollision::CL_SS+ btSoftBody::fCollision::CL_RS; - - //psb->m_cfg.collisions = btSoftBody::fCollision::SDF_RS + btSoftBody::fCollision::VF_SS;//CL_SS; - - - //btSoftBody::Material* pm=psb->appendMaterial(); - btSoftBody::Material* pm=psb->m_materials[0]; - pm->m_kLST = m_cci.m_soft_linStiff; - pm->m_kAST = m_cci.m_soft_angStiff; - pm->m_kVST = m_cci.m_soft_volume; - psb->m_cfg.collisions = 0; - - if (m_cci.m_soft_collisionflags & CCD_BSB_COL_CL_RS) - { - psb->m_cfg.collisions += btSoftBody::fCollision::CL_RS; - } else - { - psb->m_cfg.collisions += btSoftBody::fCollision::SDF_RS; - } - if (m_cci.m_soft_collisionflags & CCD_BSB_COL_CL_SS) - { - psb->m_cfg.collisions += btSoftBody::fCollision::CL_SS; - } else - { - psb->m_cfg.collisions += btSoftBody::fCollision::VF_SS; - } - - - psb->m_cfg.kSRHR_CL = m_cci.m_soft_kSRHR_CL; /* Soft vs rigid hardness [0,1] (cluster only) */ - psb->m_cfg.kSKHR_CL = m_cci.m_soft_kSKHR_CL; /* Soft vs kinetic hardness [0,1] (cluster only) */ - psb->m_cfg.kSSHR_CL = m_cci.m_soft_kSSHR_CL; /* Soft vs soft hardness [0,1] (cluster only) */ - psb->m_cfg.kSR_SPLT_CL = m_cci.m_soft_kSR_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ - - psb->m_cfg.kSK_SPLT_CL = m_cci.m_soft_kSK_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ - psb->m_cfg.kSS_SPLT_CL = m_cci.m_soft_kSS_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ - psb->m_cfg.kVCF = m_cci.m_soft_kVCF; /* Velocities correction factor (Baumgarte) */ - psb->m_cfg.kDP = m_cci.m_soft_kDP; /* Damping coefficient [0,1] */ + //btSoftBody::Material* pm=psb->appendMaterial(); + btSoftBody::Material* pm=psb->m_materials[0]; + pm->m_kLST = m_cci.m_soft_linStiff; + pm->m_kAST = m_cci.m_soft_angStiff; + pm->m_kVST = m_cci.m_soft_volume; + psb->m_cfg.collisions = 0; + + if (m_cci.m_soft_collisionflags & CCD_BSB_COL_CL_RS) + { + psb->m_cfg.collisions += btSoftBody::fCollision::CL_RS; + } else + { + psb->m_cfg.collisions += btSoftBody::fCollision::SDF_RS; + } + if (m_cci.m_soft_collisionflags & CCD_BSB_COL_CL_SS) + { + psb->m_cfg.collisions += btSoftBody::fCollision::CL_SS; + } else + { + psb->m_cfg.collisions += btSoftBody::fCollision::VF_SS; + } - psb->m_cfg.kDG = m_cci.m_soft_kDG; /* Drag coefficient [0,+inf] */ - psb->m_cfg.kLF = m_cci.m_soft_kLF; /* Lift coefficient [0,+inf] */ - psb->m_cfg.kPR = m_cci.m_soft_kPR; /* Pressure coefficient [-inf,+inf] */ - psb->m_cfg.kVC = m_cci.m_soft_kVC; /* Volume conversation coefficient [0,+inf] */ - psb->m_cfg.kDF = m_cci.m_soft_kDF; /* Dynamic friction coefficient [0,1] */ - psb->m_cfg.kMT = m_cci.m_soft_kMT; /* Pose matching coefficient [0,1] */ - psb->m_cfg.kCHR = m_cci.m_soft_kCHR; /* Rigid contacts hardness [0,1] */ - psb->m_cfg.kKHR = m_cci.m_soft_kKHR; /* Kinetic contacts hardness [0,1] */ + psb->m_cfg.kSRHR_CL = m_cci.m_soft_kSRHR_CL; /* Soft vs rigid hardness [0,1] (cluster only) */ + psb->m_cfg.kSKHR_CL = m_cci.m_soft_kSKHR_CL; /* Soft vs kinetic hardness [0,1] (cluster only) */ + psb->m_cfg.kSSHR_CL = m_cci.m_soft_kSSHR_CL; /* Soft vs soft hardness [0,1] (cluster only) */ + psb->m_cfg.kSR_SPLT_CL = m_cci.m_soft_kSR_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ - psb->m_cfg.kSHR = m_cci.m_soft_kSHR; /* Soft contacts hardness [0,1] */ - psb->m_cfg.kAHR = m_cci.m_soft_kAHR; /* Anchors hardness [0,1] */ + psb->m_cfg.kSK_SPLT_CL = m_cci.m_soft_kSK_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ + psb->m_cfg.kSS_SPLT_CL = m_cci.m_soft_kSS_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ + psb->m_cfg.kVCF = m_cci.m_soft_kVCF; /* Velocities correction factor (Baumgarte) */ + psb->m_cfg.kDP = m_cci.m_soft_kDP; /* Damping coefficient [0,1] */ + psb->m_cfg.kDG = m_cci.m_soft_kDG; /* Drag coefficient [0,+inf] */ + psb->m_cfg.kLF = m_cci.m_soft_kLF; /* Lift coefficient [0,+inf] */ + psb->m_cfg.kPR = m_cci.m_soft_kPR; /* Pressure coefficient [-inf,+inf] */ + psb->m_cfg.kVC = m_cci.m_soft_kVC; /* Volume conversation coefficient [0,+inf] */ + psb->m_cfg.kDF = m_cci.m_soft_kDF; /* Dynamic friction coefficient [0,1] */ + psb->m_cfg.kMT = m_cci.m_soft_kMT; /* Pose matching coefficient [0,1] */ + psb->m_cfg.kCHR = m_cci.m_soft_kCHR; /* Rigid contacts hardness [0,1] */ + psb->m_cfg.kKHR = m_cci.m_soft_kKHR; /* Kinetic contacts hardness [0,1] */ - if (m_cci.m_gamesoftFlag & CCD_BSB_BENDING_CONSTRAINTS)//OB_SB_GOAL) - { - psb->generateBendingConstraints(2,pm); - } + psb->m_cfg.kSHR = m_cci.m_soft_kSHR; /* Soft contacts hardness [0,1] */ + psb->m_cfg.kAHR = m_cci.m_soft_kAHR; /* Anchors hardness [0,1] */ - psb->m_cfg.piterations = m_cci.m_soft_piterations; - psb->m_cfg.viterations = m_cci.m_soft_viterations; - psb->m_cfg.diterations = m_cci.m_soft_diterations; - psb->m_cfg.citerations = m_cci.m_soft_citerations; + if (m_cci.m_gamesoftFlag & CCD_BSB_BENDING_CONSTRAINTS)//OB_SB_GOAL) + { + psb->generateBendingConstraints(2,pm); + } - if (m_cci.m_gamesoftFlag & CCD_BSB_SHAPE_MATCHING)//OB_SB_GOAL) - { - psb->setPose(false,true);// - } else - { - psb->setPose(true,false); - } + psb->m_cfg.piterations = m_cci.m_soft_piterations; + psb->m_cfg.viterations = m_cci.m_soft_viterations; + psb->m_cfg.diterations = m_cci.m_soft_diterations; + psb->m_cfg.citerations = m_cci.m_soft_citerations; + if (m_cci.m_gamesoftFlag & CCD_BSB_SHAPE_MATCHING)//OB_SB_GOAL) + { + psb->setPose(false,true);// + } else + { + psb->setPose(true,false); + } + + psb->randomizeConstraints(); - - psb->randomizeConstraints(); + if (m_cci.m_soft_collisionflags & (CCD_BSB_COL_CL_RS+CCD_BSB_COL_CL_SS)) + { + psb->generateClusters(m_cci.m_soft_numclusteriterations); + } - if (m_cci.m_soft_collisionflags & (CCD_BSB_COL_CL_RS+CCD_BSB_COL_CL_SS)) - { - psb->generateClusters(m_cci.m_soft_numclusteriterations); - } + psb->setTotalMass(m_cci.m_mass); + + psb->setCollisionFlags(0); -// psb->activate(); -// psb->setActivationState(1); -// psb->setDeactivationTime(1.f); - - //psb->m_materials[0]->m_kLST = 0.1+(i/(btScalar)(n-1))*0.9; - psb->setTotalMass(m_cci.m_mass); - - psb->setCollisionFlags(0); + ///create a mapping between graphics mesh vertices and soft body vertices + { + RAS_MeshObject* rasMesh= GetShapeInfo()->GetMesh(); - ///create a mapping between graphics mesh vertices and soft body vertices + if (rasMesh && !m_softbodyMappingDone) { - RAS_MeshObject* rasMesh= GetShapeInfo()->GetMesh(); - - if (rasMesh && !m_softbodyMappingDone) + //printf("apply\n"); + RAS_MeshSlot::iterator it; + RAS_MeshMaterial *mmat; + RAS_MeshSlot *slot; + size_t i; + + //for each material + for (int m=0;m<rasMesh->NumMaterials();m++) { - - //printf("apply\n"); - RAS_MeshSlot::iterator it; - RAS_MeshMaterial *mmat; - RAS_MeshSlot *slot; - size_t i; - - //for each material - for (int m=0;m<rasMesh->NumMaterials();m++) + mmat = rasMesh->GetMeshMaterial(m); + + slot = mmat->m_baseslot; + for(slot->begin(it); !slot->end(it); slot->next(it)) { - // The vertex cache can only be updated for this deformer: - // Duplicated objects with more than one ploymaterial (=multiple mesh slot per object) - // share the same mesh (=the same cache). As the rendering is done per polymaterial - // cycling through the objects, the entire mesh cache cannot be updated in one shot. - mmat = rasMesh->GetMeshMaterial(m); - - slot = mmat->m_baseslot; - for(slot->begin(it); !slot->end(it); slot->next(it)) + int index = 0; + for(i=it.startvertex; i<it.endvertex; i++,index++) { - int index = 0; - for(i=it.startvertex; i<it.endvertex; i++,index++) + RAS_TexVert* vertex = &it.vertex[i]; + //search closest index, and store it in vertex + vertex->setSoftBodyIndex(0); + btScalar maxDistSqr = 1e30; + btSoftBody::tNodeArray& nodes(psb->m_nodes); + btVector3 xyz = btVector3(vertex->getXYZ()[0],vertex->getXYZ()[1],vertex->getXYZ()[2]); + for (int n=0;n<nodes.size();n++) { - RAS_TexVert* vertex = &it.vertex[i]; - - - //search closest index, and store it in vertex - vertex->setSoftBodyIndex(0); - btScalar maxDistSqr = 1e30; - btSoftBody::tNodeArray& nodes(psb->m_nodes); - btVector3 xyz = btVector3(vertex->getXYZ()[0],vertex->getXYZ()[1],vertex->getXYZ()[2]); - for (int n=0;n<nodes.size();n++) + btScalar distSqr = (nodes[n].m_x - xyz).length2(); + if (distSqr<maxDistSqr) { - btScalar distSqr = (nodes[n].m_x - xyz).length2(); - if (distSqr<maxDistSqr) - { - maxDistSqr = distSqr; - - vertex->setSoftBodyIndex(n); - } + maxDistSqr = distSqr; + + vertex->setSoftBodyIndex(n); } } } } } } - - m_softbodyMappingDone = true; - - - - - + } + m_softbodyMappingDone = true; -// m_object->setCollisionShape(rbci.m_collisionShape); - btTransform startTrans; + btTransform startTrans; + rbci.m_motionState->getWorldTransform(startTrans); - if (rbci.m_motionState) - { - rbci.m_motionState->getWorldTransform(startTrans); - } else - { - startTrans = rbci.m_startWorldTransform; - } - //startTrans.setIdentity(); + m_MotionState->setWorldPosition(startTrans.getOrigin().getX(),startTrans.getOrigin().getY(),startTrans.getOrigin().getZ()); + m_MotionState->setWorldOrientation(0,0,0,1); - //m_object->setWorldTransform(startTrans); - //m_object->setInterpolationWorldTransform(startTrans); - m_MotionState->setWorldPosition(startTrans.getOrigin().getX(),startTrans.getOrigin().getY(),startTrans.getOrigin().getZ()); - m_MotionState->setWorldOrientation(0,0,0,1); + if (!m_prototypeTransformInitialized) + { + m_prototypeTransformInitialized = true; + m_softBodyTransformInitialized = true; + psb->transform(startTrans); + } + m_object->setCollisionFlags(m_object->getCollisionFlags() | m_cci.m_collisionFlags); + if (m_cci.m_do_anisotropic) + m_object->setAnisotropicFriction(m_cci.m_anisotropicFriction); + return true; +} - if (!m_prototypeTransformInitialized) - { - m_prototypeTransformInitialized = true; - m_softBodyTransformInitialized = true; - GetSoftBody()->transform(startTrans); - } -// btVector3 wp = m_softBody->getWorldTransform().getOrigin(); -// MT_Point3 center(wp.getX(),wp.getY(),wp.getZ()); -// m_gameobj->NodeSetWorldPosition(center); +void CcdPhysicsController::CreateRigidbody() +{ + //btTransform trans = GetTransformFromMotionState(m_MotionState); + m_bulletMotionState = new BlenderBulletMotionState(m_MotionState); - } else - { - btRigidBody::btRigidBodyConstructionInfo rbci(m_cci.m_mass,m_bulletMotionState,m_collisionShape,m_cci.m_localInertiaTensor * m_cci.m_inertiaFactor); - rbci.m_linearDamping = m_cci.m_linearDamping; - rbci.m_angularDamping = m_cci.m_angularDamping; - rbci.m_friction = m_cci.m_friction; - rbci.m_restitution = m_cci.m_restitution; - m_object = new btRigidBody(rbci); - } + ///either create a btCollisionObject, btRigidBody or btSoftBody + if (CreateSoftbody()) + // soft body created, done + return; + + //create a rgid collision object + btRigidBody::btRigidBodyConstructionInfo rbci(m_cci.m_mass,m_bulletMotionState,m_collisionShape,m_cci.m_localInertiaTensor * m_cci.m_inertiaFactor); + rbci.m_linearDamping = m_cci.m_linearDamping; + rbci.m_angularDamping = m_cci.m_angularDamping; + rbci.m_friction = m_cci.m_friction; + rbci.m_restitution = m_cci.m_restitution; + m_object = new btRigidBody(rbci); // // init the rigidbody properly @@ -580,6 +514,20 @@ bool CcdPhysicsController::ReplaceControllerShape(btCollisionShape *newShape) m_collisionShape= newShape; m_cci.m_collisionShape= newShape; + if (GetSoftBody()) { + // soft body must be recreated + m_cci.m_physicsEnv->removeCcdPhysicsController(this); + delete m_object; + m_object = NULL; + // force complete reinitialization + m_softbodyMappingDone = false; + m_prototypeTransformInitialized = false; + m_softBodyTransformInitialized = false; + CreateSoftbody(); + assert(m_object); + // reinsert the new body + m_cci.m_physicsEnv->addCcdPhysicsController(this); + } /* Copied from CcdPhysicsEnvironment::addCcdPhysicsController() */ @@ -1461,6 +1409,7 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm, m_vertexArray.clear(); m_polygonIndexArray.clear(); m_triFaceArray.clear(); + m_triFaceUVcoArray.clear(); return false; } @@ -1474,6 +1423,7 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm, numpolys = dm->getNumTessFaces(dm); numverts = dm->getNumVerts(dm); int* index = (int*)dm->getTessFaceDataArray(dm, CD_ORIGINDEX); + MTFace *tface = (MTFace *)dm->getFaceDataArray(dm, CD_MTFACE); m_shapeType = (polytope) ? PHY_SHAPE_POLYTOPE : PHY_SHAPE_MESH; @@ -1487,7 +1437,7 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm, for (int p2=0; p2<numpolys; p2++) { MFace* mf = &mface[p2]; - RAS_Polygon* poly = meshobj->GetPolygon(index[p2]); + RAS_Polygon* poly = meshobj->GetPolygon((index)? index[p2]: p2); // only add polygons that have the collision flag set if (poly->IsCollider()) @@ -1506,7 +1456,7 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm, for (int p2=0; p2<numpolys; p2++) { MFace* mf = &mface[p2]; - RAS_Polygon* poly= meshobj->GetPolygon(index[p2]); + RAS_Polygon* poly= meshobj->GetPolygon((index)? index[p2]: p2); // only add polygons that have the collisionflag set if (poly->IsCollider()) @@ -1554,7 +1504,7 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm, for (int p2=0; p2<numpolys; p2++) { MFace* mf = &mface[p2]; - RAS_Polygon* poly= meshobj->GetPolygon(index[p2]); + RAS_Polygon* poly= meshobj->GetPolygon((index)? index[p2]: p2); // only add polygons that have the collision flag set if (poly->IsCollider()) @@ -1574,15 +1524,24 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm, m_vertexArray.resize(tot_bt_verts*3); m_polygonIndexArray.resize(tot_bt_tris); m_triFaceArray.resize(tot_bt_tris*3); - btScalar *bt= &m_vertexArray[0]; int *poly_index_pt= &m_polygonIndexArray[0]; int *tri_pt= &m_triFaceArray[0]; + UVco *uv_pt = NULL; + if (tface) + { + m_triFaceUVcoArray.resize(tot_bt_tris*3); + uv_pt = &m_triFaceUVcoArray[0]; + } + else + m_triFaceUVcoArray.clear(); + for (int p2=0; p2<numpolys; p2++) { MFace* mf = &mface[p2]; - RAS_Polygon* poly= meshobj->GetPolygon(index[p2]); + MTFace* tf = (tface) ? &tface[p2] : NULL; + RAS_Polygon* poly= meshobj->GetPolygon((index)? index[p2]: p2); // only add polygons that have the collisionflag set if (poly->IsCollider()) @@ -1596,9 +1555,19 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm, tri_pt[1]= vert_remap_array[mf->v2]; tri_pt[2]= vert_remap_array[mf->v3]; tri_pt= tri_pt+3; + if (tf) + { + uv_pt[0].uv[0] = tf->uv[0][0]; + uv_pt[0].uv[1] = tf->uv[0][1]; + uv_pt[1].uv[0] = tf->uv[1][0]; + uv_pt[1].uv[1] = tf->uv[1][1]; + uv_pt[2].uv[0] = tf->uv[2][0]; + uv_pt[2].uv[1] = tf->uv[2][1]; + uv_pt += 3; + } // m_polygonIndexArray - *poly_index_pt= index[p2]; + *poly_index_pt= (index)? index[p2]: p2; poly_index_pt++; // the vertex location @@ -1629,9 +1598,19 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm, tri_pt[1]= vert_remap_array[mf->v3]; tri_pt[2]= vert_remap_array[mf->v4]; tri_pt= tri_pt+3; + if (tf) + { + uv_pt[0].uv[0] = tf->uv[0][0]; + uv_pt[0].uv[1] = tf->uv[0][1]; + uv_pt[1].uv[0] = tf->uv[2][0]; + uv_pt[1].uv[1] = tf->uv[2][1]; + uv_pt[2].uv[0] = tf->uv[3][0]; + uv_pt[2].uv[1] = tf->uv[3][1]; + uv_pt += 3; + } // m_polygonIndexArray - *poly_index_pt= index[p2]; + *poly_index_pt= (index)? index[p2]: p2; poly_index_pt++; // the vertex location @@ -1787,21 +1766,26 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA m_triFaceArray.resize(tot_bt_tris*3); int *tri_pt= &m_triFaceArray[0]; + m_triFaceUVcoArray.resize(tot_bt_tris*3); + UVco *uv_pt= &m_triFaceUVcoArray[0]; + m_polygonIndexArray.resize(tot_bt_tris); int *poly_index_pt= &m_polygonIndexArray[0]; - for(mf= mface, tf= tface, i=0; i < numpolys; mf++, tf++, i++) { if(tf->mode & TF_DYNAMIC) { + int origi = (index)? index[i]: i; + if(mf->v4) { fv_pt= quad_verts; - *poly_index_pt++ = *poly_index_pt++ = index[i]; + *poly_index_pt++ = origi; + *poly_index_pt++ = origi; flen= 4; } else { fv_pt= tri_verts; - *poly_index_pt++ = index[i]; + *poly_index_pt++ = origi; flen= 3; } @@ -1819,6 +1803,9 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA vert_tag_array[v_orig]= false; } *tri_pt++ = vert_remap_array[v_orig]; + uv_pt->uv[0] = tf->uv[*fv_pt][0]; + uv_pt->uv[1] = tf->uv[*fv_pt][1]; + uv_pt++; } } } @@ -1841,18 +1828,23 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA m_polygonIndexArray.resize(tot_bt_tris); int *poly_index_pt= &m_polygonIndexArray[0]; + m_triFaceUVcoArray.clear(); + for(mv= mvert, i=0; i < numverts; mv++, i++) { *bt++ = mv->co[0]; *bt++ = mv->co[1]; *bt++ = mv->co[2]; } for(mf= mface, i=0; i < numpolys; mf++, i++) { + int origi = (index)? index[i]: i; + if(mf->v4) { fv_pt= quad_verts; - *poly_index_pt++ = *poly_index_pt++ = index[i]; + *poly_index_pt++ = origi; + *poly_index_pt++ = origi; } else { fv_pt= tri_verts; - *poly_index_pt++ = index[i]; + *poly_index_pt++ = origi; } for(; *fv_pt > -1; fv_pt++) diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h index 02d723472f6..637007e2857 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h @@ -52,12 +52,16 @@ class btCollisionShape; #define CCD_BSB_COL_VF_SS 16 /* Vertex/Face based soft vs soft */ - // Shape contructor // It contains all the information needed to create a simple bullet shape at runtime class CcdShapeConstructionInfo { public: + struct UVco + { + float uv[2]; + }; + static CcdShapeConstructionInfo* FindMesh(class RAS_MeshObject* mesh, struct DerivedMesh* dm, bool polytope, bool gimpact); CcdShapeConstructionInfo() : @@ -71,6 +75,7 @@ public: m_meshObject(NULL), m_unscaledShape(NULL), m_useGimpact(false), + m_forceReInstance(false), m_weldingThreshold1(0.f), m_shapeProxy(NULL) { @@ -102,7 +107,7 @@ public: btTriangleMeshShape* GetMeshShape(void) { - return m_unscaledShape; + return (m_unscaledShape); } CcdShapeConstructionInfo* GetChildShape(int i) { @@ -173,6 +178,9 @@ public: std::vector<int> m_triFaceArray; // Contains an array of triplets of face indicies // quads turn into 2 tris + std::vector<UVco> m_triFaceUVcoArray; // Contains an array of pair of UV coordinate for each vertex of faces + // quads turn into 2 tris + void setVertexWeldingThreshold1(float threshold) { m_weldingThreshold1 = threshold*threshold; @@ -372,6 +380,7 @@ protected: void GetWorldOrientation(btMatrix3x3& mat); void CreateRigidbody(); + bool CreateSoftbody(); bool Register() { return (m_registerCount++ == 0) ? true : false; diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp index 22722c0927a..477a2c35d4f 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp @@ -375,9 +375,7 @@ m_scalingPropagated(false) //m_dynamicsWorld->getSolverInfo().m_solverMode= SOLVER_USE_WARMSTARTING + SOLVER_USE_2_FRICTION_DIRECTIONS + SOLVER_RANDMIZE_ORDER + SOLVER_USE_FRICTION_WARMSTARTING; m_debugDrawer = 0; - m_gravity = btVector3(0.f,-10.f,0.f); - m_dynamicsWorld->setGravity(m_gravity); - + setGravity(0.f,0.f,-9.81f); } void CcdPhysicsEnvironment::addCcdPhysicsController(CcdPhysicsController* ctrl) @@ -884,7 +882,7 @@ void CcdPhysicsEnvironment::setGravity(float x,float y,float z) { m_gravity = btVector3(x,y,z); m_dynamicsWorld->setGravity(m_gravity); - + m_dynamicsWorld->getWorldInfo().m_gravity.setValue(x,y,z); } @@ -976,6 +974,7 @@ struct FilterClosestRayResultCallback : public btCollisionWorld::ClosestRayResul const btCollisionShape* m_hitTriangleShape; int m_hitTriangleIndex; + FilterClosestRayResultCallback (PHY_IRayCastFilterCallback& phyRayFilter,const btVector3& rayFrom,const btVector3& rayTo) : btCollisionWorld::ClosestRayResultCallback(rayFrom,rayTo), m_phyRayFilter(phyRayFilter), @@ -1019,6 +1018,56 @@ struct FilterClosestRayResultCallback : public btCollisionWorld::ClosestRayResul }; +static bool GetHitTriangle(btCollisionShape* shape, CcdShapeConstructionInfo* shapeInfo, int hitTriangleIndex, btVector3 triangle[]) +{ + // this code is copied from Bullet + const unsigned char *vertexbase; + int numverts; + PHY_ScalarType type; + int stride; + const unsigned char *indexbase; + int indexstride; + int numfaces; + PHY_ScalarType indicestype; + btStridingMeshInterface* meshInterface = NULL; + btTriangleMeshShape* triangleShape = shapeInfo->GetMeshShape(); + + if (triangleShape) + meshInterface = triangleShape->getMeshInterface(); + else + { + // other possibility is gImpact + if (shape->getShapeType() == GIMPACT_SHAPE_PROXYTYPE) + meshInterface = (static_cast<btGImpactMeshShape*>(shape))->getMeshInterface(); + } + if (!meshInterface) + return false; + + meshInterface->getLockedReadOnlyVertexIndexBase( + &vertexbase, + numverts, + type, + stride, + &indexbase, + indexstride, + numfaces, + indicestype, + 0); + + unsigned int* gfxbase = (unsigned int*)(indexbase+hitTriangleIndex*indexstride); + const btVector3& meshScaling = shape->getLocalScaling(); + for (int j=2;j>=0;j--) + { + int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:gfxbase[j]; + + btScalar* graphicsbase = (btScalar*)(vertexbase+graphicsindex*stride); + + triangle[j] = btVector3(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),graphicsbase[2]*meshScaling.getZ()); + } + meshInterface->unLockReadOnlyVertexBase(0); + return true; +} + PHY_IPhysicsController* CcdPhysicsEnvironment::rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ) { btVector3 rayFrom(fromX,fromY,fromZ); @@ -1071,56 +1120,98 @@ PHY_IPhysicsController* CcdPhysicsEnvironment::rayTest(PHY_IRayCastFilterCallbac if (shape == rayCallback.m_hitTriangleShape && rayCallback.m_hitTriangleIndex < shapeInfo->m_polygonIndexArray.size()) { + // save original collision shape triangle for soft body + int hitTriangleIndex = rayCallback.m_hitTriangleIndex; + result.m_meshObject = shapeInfo->GetMesh(); + if (shape->isSoftBody()) + { + // soft body using different face numbering because of randomization + // hopefully we have stored the original face number in m_tag + btSoftBody* softBody = static_cast<btSoftBody*>(rayCallback.m_collisionObject); + if (softBody->m_faces[hitTriangleIndex].m_tag != 0) + { + rayCallback.m_hitTriangleIndex = (int)((uintptr_t)(softBody->m_faces[hitTriangleIndex].m_tag)-1); + } + } + // retrieve the original mesh polygon (in case of quad->tri conversion) result.m_polygon = shapeInfo->m_polygonIndexArray.at(rayCallback.m_hitTriangleIndex); - + // hit triangle in world coordinate, for face normal and UV coordinate + btVector3 triangle[3]; + bool triangleOK = false; + if (filterCallback.m_faceUV && (3*rayCallback.m_hitTriangleIndex) < shapeInfo->m_triFaceUVcoArray.size()) + { + // interpolate the UV coordinate of the hit point + CcdShapeConstructionInfo::UVco* uvCo = &shapeInfo->m_triFaceUVcoArray[3*rayCallback.m_hitTriangleIndex]; + // 1. get the 3 coordinate of the triangle in world space + btVector3 v1, v2, v3; + if (shape->isSoftBody()) + { + // soft body give points directly in world coordinate + btSoftBody* softBody = static_cast<btSoftBody*>(rayCallback.m_collisionObject); + v1 = softBody->m_faces[hitTriangleIndex].m_n[0]->m_x; + v2 = softBody->m_faces[hitTriangleIndex].m_n[1]->m_x; + v3 = softBody->m_faces[hitTriangleIndex].m_n[2]->m_x; + } else + { + // for rigid body we must apply the world transform + triangleOK = GetHitTriangle(shape, shapeInfo, hitTriangleIndex, triangle); + if (!triangleOK) + // if we cannot get the triangle, no use to continue + goto SKIP_UV_NORMAL; + v1 = rayCallback.m_collisionObject->getWorldTransform()(triangle[0]); + v2 = rayCallback.m_collisionObject->getWorldTransform()(triangle[1]); + v3 = rayCallback.m_collisionObject->getWorldTransform()(triangle[2]); + } + // 2. compute barycentric coordinate of the hit point + btVector3 v = v2-v1; + btVector3 w = v3-v1; + btVector3 u = v.cross(w); + btScalar A = u.length(); + + v = v2-rayCallback.m_hitPointWorld; + w = v3-rayCallback.m_hitPointWorld; + u = v.cross(w); + btScalar A1 = u.length(); + + v = rayCallback.m_hitPointWorld-v1; + w = v3-v1; + u = v.cross(w); + btScalar A2 = u.length(); + + btVector3 baryCo; + baryCo.setX(A1/A); + baryCo.setY(A2/A); + baryCo.setZ(1.0f-baryCo.getX()-baryCo.getY()); + // 3. compute UV coordinate + result.m_hitUV[0] = baryCo.getX()*uvCo[0].uv[0] + baryCo.getY()*uvCo[1].uv[0] + baryCo.getZ()*uvCo[2].uv[0]; + result.m_hitUV[1] = baryCo.getX()*uvCo[0].uv[1] + baryCo.getY()*uvCo[1].uv[1] + baryCo.getZ()*uvCo[2].uv[1]; + result.m_hitUVOK = 1; + } + // Bullet returns the normal from "outside". // If the user requests the real normal, compute it now if (filterCallback.m_faceNormal) { - // mesh shapes are shared and stored in the shapeInfo - btTriangleMeshShape* triangleShape = shapeInfo->GetMeshShape(); - if (triangleShape) + if (shape->isSoftBody()) + { + // we can get the real normal directly from the body + btSoftBody* softBody = static_cast<btSoftBody*>(rayCallback.m_collisionObject); + rayCallback.m_hitNormalWorld = softBody->m_faces[hitTriangleIndex].m_normal; + } else { - // this code is copied from Bullet - btVector3 triangle[3]; - const unsigned char *vertexbase; - int numverts; - PHY_ScalarType type; - int stride; - const unsigned char *indexbase; - int indexstride; - int numfaces; - PHY_ScalarType indicestype; - btStridingMeshInterface* meshInterface = triangleShape->getMeshInterface(); - - meshInterface->getLockedReadOnlyVertexIndexBase( - &vertexbase, - numverts, - type, - stride, - &indexbase, - indexstride, - numfaces, - indicestype, - 0); - - unsigned int* gfxbase = (unsigned int*)(indexbase+rayCallback.m_hitTriangleIndex*indexstride); - const btVector3& meshScaling = shape->getLocalScaling(); - for (int j=2;j>=0;j--) + if (!triangleOK) + triangleOK = GetHitTriangle(shape, shapeInfo, hitTriangleIndex, triangle); + if (triangleOK) { - int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:gfxbase[j]; - - btScalar* graphicsbase = (btScalar*)(vertexbase+graphicsindex*stride); - - triangle[j] = btVector3(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),graphicsbase[2]*meshScaling.getZ()); + btVector3 triangleNormal; + triangleNormal = (triangle[1]-triangle[0]).cross(triangle[2]-triangle[0]); + rayCallback.m_hitNormalWorld = rayCallback.m_collisionObject->getWorldTransform().getBasis()*triangleNormal; } - meshInterface->unLockReadOnlyVertexBase(0); - btVector3 triangleNormal; - triangleNormal = (triangle[1]-triangle[0]).cross(triangle[2]-triangle[0]); - rayCallback.m_hitNormalWorld = rayCallback.m_collisionObject->getWorldTransform().getBasis()*triangleNormal; } } + SKIP_UV_NORMAL: + ; } } } diff --git a/source/gameengine/Physics/common/PHY_DynamicTypes.h b/source/gameengine/Physics/common/PHY_DynamicTypes.h index 7ce40001af7..08d94a2850a 100644 --- a/source/gameengine/Physics/common/PHY_DynamicTypes.h +++ b/source/gameengine/Physics/common/PHY_DynamicTypes.h @@ -22,6 +22,20 @@ subject to the following restrictions: struct KX_ClientObjectInfo; class PHY_Shape; +struct PHY__Vector2 +{ + float m_vec[2]; + + operator const float* () const + { + return &m_vec[0]; + } + operator float* () + { + return &m_vec[0]; + } +}; + struct PHY__Vector3 { float m_vec[4]; diff --git a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h index 291dac298dc..86e72c70bb7 100644 --- a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h +++ b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h @@ -52,6 +52,8 @@ struct PHY_RayCastResult const RAS_MeshObject* m_meshObject; // !=NULL for mesh object (only for Bullet controllers) int m_polygon; // index of the polygon hit by the ray, // only if m_meshObject != NULL + int m_hitUVOK; // !=0 if UV coordinate in m_hitUV is valid + PHY__Vector2 m_hitUV; // UV coordinates of hit point }; /** @@ -64,6 +66,7 @@ class PHY_IRayCastFilterCallback public: PHY_IPhysicsController* m_ignoreController; bool m_faceNormal; + bool m_faceUV; virtual ~PHY_IRayCastFilterCallback() { @@ -76,9 +79,10 @@ public: virtual void reportHit(PHY_RayCastResult* result) = 0; - PHY_IRayCastFilterCallback(PHY_IPhysicsController* ignoreController, bool faceNormal=false) + PHY_IRayCastFilterCallback(PHY_IPhysicsController* ignoreController, bool faceNormal=false, bool faceUV=false) :m_ignoreController(ignoreController), - m_faceNormal(faceNormal) + m_faceNormal(faceNormal), + m_faceUV(faceUV) { } |