blender/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.cpp

278 lines
6.8 KiB
C++
Raw Normal View History

/**
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* The contents of this file may be used under the terms of either the GNU
* General Public License Version 2 or later (the "GPL", see
* http://www.gnu.org/licenses/gpl.html ), or the Blender License 1.0 or
* later (the "BL", see http://www.blender.org/BL/ ) which has to be
* bought from the Blender Foundation to become active, in which case the
* above mentioned GPL option does not apply.
*
* The Original Code is Copyright (C) 2002 by NaN Holding BV.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "OdePhysicsEnvironment.h"
#include "PHY_IMotionState.h"
#include "OdePhysicsController.h"
#include <ode/ode.h>
#include <../ode/src/joint.h>
#include <ode/odemath.h>
ODEPhysicsEnvironment::ODEPhysicsEnvironment()
{
m_OdeWorld = dWorldCreate();
m_OdeSpace = dHashSpaceCreate();
m_OdeContactGroup = dJointGroupCreate (0);
dWorldSetCFM (m_OdeWorld,1e-5f);
m_JointGroup = dJointGroupCreate(0);
setFixedTimeStep(true,1.f/60.f);
}
ODEPhysicsEnvironment::~ODEPhysicsEnvironment()
{
dJointGroupDestroy (m_OdeContactGroup);
dJointGroupDestroy (m_JointGroup);
dSpaceDestroy (m_OdeSpace);
dWorldDestroy (m_OdeWorld);
}
void ODEPhysicsEnvironment::setFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep)
{
m_useFixedTimeStep = useFixedTimeStep;
if (useFixedTimeStep)
{
m_fixedTimeStep = fixedTimeStep;
} else
{
m_fixedTimeStep = 0.f;
}
m_currentTime = 0.f;
//todo:implement fixed timestepping
}
float ODEPhysicsEnvironment::getFixedTimeStep()
{
return m_fixedTimeStep;
}
bool ODEPhysicsEnvironment::proceedDeltaTime(double curTime,float timeStep1)
{
float deltaTime = timeStep1;
int numSteps = 1;
if (m_useFixedTimeStep)
{
m_currentTime += timeStep1;
// equal to subSampling (might be a little smaller).
numSteps = (int)(m_currentTime / m_fixedTimeStep);
m_currentTime -= m_fixedTimeStep * (float)numSteps;
deltaTime = m_fixedTimeStep;
//todo: experiment by smoothing the remaining time over the substeps
}
for (int i=0;i<numSteps;i++)
{
// ode collision update
dSpaceCollide (m_OdeSpace,this,&ODEPhysicsEnvironment::OdeNearCallback);
int m_odeContacts = GetNumOdeContacts();
//physics integrator + resolver update
2005-07-16 21:47:54 +00:00
//dWorldStep (m_OdeWorld,deltaTime);
//dWorldQuickStep (m_OdeWorld,deltaTime);
2005-07-16 21:47:54 +00:00
//dWorldID w, dReal stepsize)
//clear collision points
this->ClearOdeContactGroup();
}
2005-02-15 10:02:19 +00:00
return true;
}
void ODEPhysicsEnvironment::setGravity(float x,float y,float z)
{
dWorldSetGravity (m_OdeWorld,x,y,z);
}
int ODEPhysicsEnvironment::createConstraint(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsController* ctrl2,PHY_ConstraintType type,
float pivotX,float pivotY,float pivotZ,float axisX,float axisY,float axisZ)
{
int constraintid = 0;
ODEPhysicsController* dynactrl = (ODEPhysicsController*)ctrl;
ODEPhysicsController* dynactrl2 = (ODEPhysicsController*)ctrl2;
switch (type)
{
case PHY_POINT2POINT_CONSTRAINT:
{
if (dynactrl)
{
dJointID jointid = dJointCreateBall (m_OdeWorld,m_JointGroup);
struct dxBody* bodyid1 = dynactrl->GetOdeBodyId();
struct dxBody* bodyid2=0;
const dReal* pos = dBodyGetPosition(bodyid1);
const dReal* R = dBodyGetRotation(bodyid1);
dReal offset[3] = {pivotX,pivotY,pivotZ};
dReal newoffset[3];
dMULTIPLY0_331 (newoffset,R,offset);
newoffset[0] += pos[0];
newoffset[1] += pos[1];
newoffset[2] += pos[2];
if (dynactrl2)
bodyid2 = dynactrl2->GetOdeBodyId();
dJointAttach (jointid, bodyid1, bodyid2);
dJointSetBallAnchor (jointid, newoffset[0], newoffset[1], newoffset[2]);
constraintid = (int) jointid;
}
break;
}
case PHY_LINEHINGE_CONSTRAINT:
{
if (dynactrl)
{
dJointID jointid = dJointCreateHinge (m_OdeWorld,m_JointGroup);
struct dxBody* bodyid1 = dynactrl->GetOdeBodyId();
struct dxBody* bodyid2=0;
const dReal* pos = dBodyGetPosition(bodyid1);
const dReal* R = dBodyGetRotation(bodyid1);
dReal offset[3] = {pivotX,pivotY,pivotZ};
dReal axisset[3] = {axisX,axisY,axisZ};
dReal newoffset[3];
dReal newaxis[3];
dMULTIPLY0_331 (newaxis,R,axisset);
dMULTIPLY0_331 (newoffset,R,offset);
newoffset[0] += pos[0];
newoffset[1] += pos[1];
newoffset[2] += pos[2];
if (dynactrl2)
bodyid2 = dynactrl2->GetOdeBodyId();
dJointAttach (jointid, bodyid1, bodyid2);
dJointSetHingeAnchor (jointid, newoffset[0], newoffset[1], newoffset[2]);
dJointSetHingeAxis(jointid,newaxis[0],newaxis[1],newaxis[2]);
constraintid = (int) jointid;
}
break;
}
default:
{
//not yet
}
}
return constraintid;
}
void ODEPhysicsEnvironment::removeConstraint(void *constraintid)
{
if (constraintid)
{
dJointDestroy((dJointID) constraintid);
}
}
BGE patch: KX_GameObject::rayCast() improvements to have X-Ray option, return true face normal and hit polygon information. rayCast(to,from,dist,prop,face,xray,poly): The face paremeter determines the orientation of the normal: 0 or omitted => hit normal is always oriented towards the ray origin (as if you casted the ray from outside) 1 => hit normal is the real face normal (only for mesh object, otherwise face has no effect) The ray has X-Ray capability if xray parameter is 1, otherwise the first object hit (other than self object) stops the ray. The prop and xray parameters interact as follow: prop off, xray off: return closest hit or no hit if there is no object on the full extend of the ray. prop off, xray on : idem. prop on, xray off: return closest hit if it matches prop, no hit otherwise. prop on, xray on : return closest hit matching prop or no hit if there is no object matching prop on the full extend of the ray. if poly is 0 or omitted, returns a 3-tuple with object reference, hit point and hit normal or (None,None,None) if no hit. if poly is 1, returns a 4-tuple with in addition a KX_PolyProxy as 4th element. The KX_PolyProxy object holds information on the polygon hit by the ray: the index of the vertex forming the poylgon, material, etc. Attributes (read-only): matname: The name of polygon material, empty if no material. material: The material of the polygon texture: The texture name of the polygon. matid: The material index of the polygon, use this to retrieve vertex proxy from mesh proxy v1: vertex index of the first vertex of the polygon, use this to retrieve vertex proxy from mesh proxy v2: vertex index of the second vertex of the polygon, use this to retrieve vertex proxy from mesh proxy v3: vertex index of the third vertex of the polygon, use this to retrieve vertex proxy from mesh proxy v4: vertex index of the fourth vertex of the polygon, 0 if polygon has only 3 vertex use this to retrieve vertex proxy from mesh proxy visible: visible state of the polygon: 1=visible, 0=invisible collide: collide state of the polygon: 1=receives collision, 0=collision free. Methods: getMaterialName(): Returns the polygon material name with MA prefix getMaterial(): Returns the polygon material getTextureName(): Returns the polygon texture name getMaterialIndex(): Returns the material bucket index of the polygon. getNumVertex(): Returns the number of vertex of the polygon. isVisible(): Returns whether the polygon is visible or not isCollider(): Returns whether the polygon is receives collision or not getVertexIndex(vertex): Returns the mesh vertex index of a polygon vertex getMesh(): Returns a mesh proxy New methods of KX_MeshProxy have been implemented to retrieve KX_PolyProxy objects: getNumPolygons(): Returns the number of polygon in the mesh. getPolygon(index): Gets the specified polygon from the mesh. More details in PyDoc.
2008-08-27 19:34:19 +00:00
PHY_IPhysicsController* ODEPhysicsEnvironment::rayTest(PHY_IRayCastFilterCallback &filterCallback,float fromX,float fromY,float fromZ, float toX,float toY,float toZ)
{
//m_OdeWorld
//collision detection / raytesting
return NULL;
}
void ODEPhysicsEnvironment::OdeNearCallback (void *data, dGeomID o1, dGeomID o2)
{
// \todo if this is a registered collision sensor
// fire the callback
int i;
// if (o1->body && o2->body) return;
ODEPhysicsEnvironment* env = (ODEPhysicsEnvironment*) data;
dBodyID b1,b2;
b1 = dGeomGetBody(o1);
b2 = dGeomGetBody(o2);
// exit without doing anything if the two bodies are connected by a joint
if (b1 && b2 && dAreConnected (b1,b2)) return;
ODEPhysicsController * ctrl1 =(ODEPhysicsController *)dGeomGetData(o1);
ODEPhysicsController * ctrl2 =(ODEPhysicsController *)dGeomGetData(o2);
float friction=ctrl1->getFriction();
float restitution = ctrl1->getRestitution();
//for friction, take minimum
friction=(friction < ctrl2->getFriction() ?
friction :ctrl2->getFriction());
//restitution:take minimum
restitution = restitution < ctrl2->getRestitution()?
restitution : ctrl2->getRestitution();
dContact contact[3]; // up to 3 contacts per box
for (i=0; i<3; i++) {
contact[i].surface.mode = dContactBounce; //dContactMu2;
contact[i].surface.mu = friction;//dInfinity;
contact[i].surface.mu2 = 0;
contact[i].surface.bounce = restitution;//0.5;
contact[i].surface.bounce_vel = 0.1f;
contact[i].surface.slip1=0.0;
}
if (int numc = dCollide (o1,o2,3,&contact[0].geom,sizeof(dContact))) {
// dMatrix3 RI;
// dRSetIdentity (RI);
// const dReal ss[3] = {0.02,0.02,0.02};
for (i=0; i<numc; i++) {
dJointID c = dJointCreateContact (env->m_OdeWorld,env->m_OdeContactGroup,contact+i);
dJointAttach (c,b1,b2);
}
}
}
void ODEPhysicsEnvironment::ClearOdeContactGroup()
{
dJointGroupEmpty (m_OdeContactGroup);
}
int ODEPhysicsEnvironment::GetNumOdeContacts()
{
return m_OdeContactGroup->num;
}