- obstacle culling for correct simulation in 3d
- flag for steering actuator termination on reaching target
- path recalculation period
- advance by waypoints (for path following)
This commit is contained in:
Nick Samarin 2010-06-18 23:48:52 +00:00
parent 700c32e738
commit c92d0dfdf6
14 changed files with 215 additions and 65 deletions

@ -544,6 +544,9 @@ class WORLD_PT_game_physics_obstacles(WorldButtonsPanel):
wide_ui = context.region.width > narrowui
layout.prop(gs, "obstacle_simulation", text = "Type")
if gs.obstacle_simulation != 'None':
layout.prop(gs, "level_height", text="Level height")
classes = [
PHYSICS_PT_game_physics,

@ -473,6 +473,7 @@ Scene *add_scene(char *name)
sce->gm.matmode = GAME_MAT_MULTITEX;
sce->gm.obstacleSimulation= OBSTSIMULATION_NONE;
sce->gm.levelHeight = 2.f;
sound_create_scene(sce);

@ -4276,6 +4276,10 @@ static void draw_actuator_steering(uiLayout *layout, PointerRNA *ptr)
row = uiLayoutRow(layout, 0);
uiItemR(row, ptr, "acceleration", 0, NULL, 0);
uiItemR(row, ptr, "turnspeed", 0, NULL, 0);
row = uiLayoutRow(layout, 0);
uiItemR(row, ptr, "selfterminated", 0, NULL, 0);
if (RNA_enum_get(ptr, "mode")==ACT_STEERING_PATHFOLLOWING)
uiItemR(row, ptr, "updateperiod", 0, NULL, 0);
}

@ -215,12 +215,14 @@ typedef struct bArmatureActuator {
} bArmatureActuator;
typedef struct bSteeringActuator {
char pad[4];
char pad[7];
char flag;
int type; /* 0=seek, 1=flee, 2=path following */
float dist;
float velocity;
float acceleration;
float turnspeed;
int updateTime;
struct Object *target;
struct Object *navmesh;
} bSteeringActuator;
@ -518,6 +520,8 @@ typedef struct FreeCamera {
#define ACT_STEERING_SEEK 0
#define ACT_STEERING_FLEE 1
#define ACT_STEERING_PATHFOLLOWING 2
/* steeringactuator->flag */
#define ACT_STEERING_SELFTERMINATED 1
#endif

@ -451,11 +451,12 @@ typedef struct GameData {
* bit 3: (gameengine): Activity culling is enabled.
* bit 5: (gameengine) : enable Bullet DBVT tree for view frustrum culling
*/
short mode, flag, matmode, pad[6];
short mode, flag, matmode/*, pad[2]*/;
short occlusionRes; /* resolution of occlusion Z buffer in pixel */
short physicsEngine;
short ticrate, maxlogicstep, physubstep, maxphystep;
short obstacleSimulation;
float levelHeight;
/* standalone player */
struct GameFraming framing;

@ -1897,6 +1897,17 @@ static void rna_def_steering_actuator(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Target Object", "Set target object");
RNA_def_property_update(prop, NC_LOGIC, NULL);
prop= RNA_def_property(srna, "selfterminated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_STEERING_SELFTERMINATED);
RNA_def_property_ui_text(prop, "Self terminated", "Terminate when target is reached");
RNA_def_property_update(prop, NC_LOGIC, NULL);
prop= RNA_def_property(srna, "updateperiod", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "updateTime");
RNA_def_property_ui_range(prop, -1, 100000, 1, 1);
RNA_def_property_ui_text(prop, "Update period", "Path update period");
RNA_def_property_update(prop, NC_LOGIC, NULL);
prop= RNA_def_property(srna, "navmesh", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Object");
RNA_def_property_pointer_sdna(prop, NULL, "navmesh");

@ -1760,6 +1760,13 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
RNA_def_property_enum_items(prop, obstacle_simulation_items);
RNA_def_property_ui_text(prop, "Obstacle simulation", "Simulation used for obstacle avoidance in the game engine");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop= RNA_def_property(srna, "level_height", PROP_FLOAT, PROP_ACCELERATION);
RNA_def_property_float_sdna(prop, NULL, "levelHeight");
RNA_def_property_range(prop, 0.0f, 200.0f);
RNA_def_property_ui_text(prop, "Level height", "Max difference in heights of obstacles to enable their interaction");
RNA_def_property_update(prop, NC_SCENE, NULL);
}
static void rna_def_scene_render_layer(BlenderRNA *brna)

@ -1057,10 +1057,12 @@ void BL_ConvertActuators(char* maggiename,
break;
}
bool selfTerminated = (stAct->flag & ACT_STEERING_SELFTERMINATED) !=0;
KX_SteeringActuator *tmpstact
= new KX_SteeringActuator(gameobj, mode, targetob, navmeshob,stAct->dist,
stAct->velocity, stAct->acceleration, stAct->turnspeed,
scene->GetObstacleSimulation());
stAct->velocity, stAct->acceleration, stAct->turnspeed,
selfTerminated, stAct->updateTime,
scene->GetObstacleSimulation());
baseact = tmpstact;
break;
}

@ -333,32 +333,53 @@ void KX_NavMeshObject::DrawNavMesh()
if (!m_navMesh)
return;
MT_Vector3 color(0.f, 0.f, 0.f);
for (int i = 0; i < m_navMesh->getPolyDetailCount(); ++i)
enum RenderMode {DETAILED_TRIS, WALLS};
static const RenderMode renderMode = DETAILED_TRIS;
switch (renderMode)
{
const dtStatPoly* p = m_navMesh->getPoly(i);
const dtStatPolyDetail* pd = m_navMesh->getPolyDetail(i);
for (int j = 0; j < pd->ntris; ++j)
case WALLS :
for (int pi=0; pi<m_navMesh->getPolyCount(); pi++)
{
const unsigned char* t = m_navMesh->getDetailTri(pd->tbase+j);
MT_Vector3 tri[3];
for (int k = 0; k < 3; ++k)
{
const float* v;
if (t[k] < p->nv)
v = m_navMesh->getVertex(p->v[t[k]]);
else
v = m_navMesh->getDetailVertex(pd->vbase+(t[k]-p->nv));
float pos[3];
vcopy(pos, v);
flipAxes(pos);
tri[k].setValue(pos);
}
const dtStatPoly* poly = m_navMesh->getPoly(pi);
for (int k=0; k<3; k++)
KX_RasterizerDrawDebugLine(tri[k], tri[(k+1)%3], color);
for (int i = 0, j = (int)poly->nv-1; i < (int)poly->nv; j = i++)
{
if (poly->n[j]) continue;
const float* vj = m_navMesh->getVertex(poly->v[j]);
const float* vi = m_navMesh->getVertex(poly->v[i]);
KX_RasterizerDrawDebugLine(MT_Vector3(vj[0], vj[2], vj[1]), MT_Vector3(vi[0], vi[2], vi[1]), color);
}
}
break;
case DETAILED_TRIS :
for (int i = 0; i < m_navMesh->getPolyDetailCount(); ++i)
{
const dtStatPoly* p = m_navMesh->getPoly(i);
const dtStatPolyDetail* pd = m_navMesh->getPolyDetail(i);
for (int j = 0; j < pd->ntris; ++j)
{
const unsigned char* t = m_navMesh->getDetailTri(pd->tbase+j);
MT_Vector3 tri[3];
for (int k = 0; k < 3; ++k)
{
const float* v;
if (t[k] < p->nv)
v = m_navMesh->getVertex(p->v[t[k]]);
else
v = m_navMesh->getDetailVertex(pd->vbase+(t[k]-p->nv));
float pos[3];
vcopy(pos, v);
flipAxes(pos);
tri[k].setValue(pos);
}
for (int k=0; k<3; k++)
KX_RasterizerDrawDebugLine(tri[k], tri[(k+1)%3], color);
}
}
break;
}
}

@ -166,7 +166,8 @@ static float interpolateToi(float a, const float* dir, const float* toi, const i
return 0;
}
KX_ObstacleSimulation::KX_ObstacleSimulation()
KX_ObstacleSimulation::KX_ObstacleSimulation(MT_Scalar levelHeight)
: m_levelHeight(levelHeight)
{
}
@ -285,12 +286,51 @@ void KX_ObstacleSimulation::DrawObstacles()
else if (m_obstacles[i]->m_shape==KX_OBSTACLE_CIRCLE)
{
KX_RasterizerDrawDebugCircle(m_obstacles[i]->m_pos, m_obstacles[i]->m_rad, bluecolor,
normal.normalized(), SECTORS_NUM);
normal, SECTORS_NUM);
}
}
}
KX_ObstacleSimulationTOI::KX_ObstacleSimulationTOI():
static MT_Point3 nearestPointToObstacle(MT_Point3& pos ,KX_Obstacle* obstacle)
{
switch (obstacle->m_shape)
{
case KX_OBSTACLE_SEGMENT :
{
MT_Vector3 ab = obstacle->m_pos2 - obstacle->m_pos;
if (!ab.fuzzyZero())
{
MT_Vector3 abdir = ab.normalized();
MT_Vector3 v = pos - obstacle->m_pos;
MT_Scalar proj = abdir.dot(v);
CLAMP(proj, 0, ab.length());
MT_Point3 res = obstacle->m_pos + abdir*proj;
return res;
}
}
case KX_OBSTACLE_CIRCLE :
default:
return obstacle->m_pos;
}
}
bool KX_ObstacleSimulation::FilterObstacle(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, KX_Obstacle* otherObst)
{
//filter obstacles by type
if ( (otherObst == activeObst) ||
(otherObst->m_type==KX_OBSTACLE_NAV_MESH && otherObst->m_gameObj!=activeNavMeshObj) )
return false;
//filter obstacles by position
MT_Point3 p = nearestPointToObstacle(activeObst->m_pos, otherObst);
if ( fabs(activeObst->m_pos.z() - p.z()) > m_levelHeight)
return false;
return true;
}
KX_ObstacleSimulationTOI::KX_ObstacleSimulationTOI(MT_Scalar levelHeight):
KX_ObstacleSimulation(levelHeight),
m_avoidSteps(32),
m_minToi(0.5f),
m_maxToi(1.2f),
@ -360,10 +400,10 @@ void KX_ObstacleSimulationTOI::AdjustObstacleVelocity(KX_Obstacle* activeObst, K
for (int i = 0; i < nobs; ++i)
{
KX_Obstacle* ob = m_obstacles[i];
if ( (ob==activeObst) ||
(ob->m_type==KX_OBSTACLE_NAV_MESH && ob->m_gameObj!=activeNavMeshObj) )
bool res = FilterObstacle(activeObst, activeNavMeshObj, ob);
if (!res)
continue;
float htmin,htmax;
if (ob->m_type == KX_OBSTACLE_CIRCLE)

@ -73,9 +73,12 @@ class KX_ObstacleSimulation
protected:
std::vector<KX_Obstacle*> m_obstacles;
MT_Scalar m_levelHeight;
virtual KX_Obstacle* CreateObstacle();
bool FilterObstacle(KX_Obstacle* activeObstacle, KX_NavMeshObject* activeNavMeshObj, KX_Obstacle* otherObstacle);
public:
KX_ObstacleSimulation();
KX_ObstacleSimulation(MT_Scalar levelHeight);
virtual ~KX_ObstacleSimulation();
void DrawObstacles();
@ -114,7 +117,7 @@ protected:
std::vector<TOICircle*> m_toiCircles; // TOI circles (one per active agent)
virtual KX_Obstacle* CreateObstacle();
public:
KX_ObstacleSimulationTOI();
KX_ObstacleSimulationTOI(MT_Scalar levelHeight);
~KX_ObstacleSimulationTOI();
virtual void AdjustObstacleVelocity(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj,
MT_Vector3& velocity, MT_Scalar maxDeltaSpeed,MT_Scalar maxDeltaAngle);

@ -214,7 +214,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
switch (scene->gm.obstacleSimulation)
{
case OBSTSIMULATION_TOI:
m_obstacleSimulation = new KX_ObstacleSimulationTOI;
m_obstacleSimulation = new KX_ObstacleSimulationTOI((MT_Scalar)scene->gm.levelHeight);
break;
default:
m_obstacleSimulation = NULL;

@ -52,6 +52,8 @@ KX_SteeringActuator::KX_SteeringActuator(SCA_IObject *gameobj,
MT_Scalar velocity,
MT_Scalar acceleration,
MT_Scalar turnspeed,
bool isSelfTerminated,
int pathUpdatePeriod,
KX_ObstacleSimulation* simulation) :
SCA_IActuator(gameobj, KX_ACT_STEERING),
m_mode(mode),
@ -60,10 +62,14 @@ KX_SteeringActuator::KX_SteeringActuator(SCA_IObject *gameobj,
m_velocity(velocity),
m_acceleration(acceleration),
m_turnspeed(turnspeed),
m_isSelfTerminated(isSelfTerminated),
m_pathUpdatePeriod(pathUpdatePeriod),
m_updateTime(0),
m_isActive(false),
m_simulation(simulation),
m_obstacle(NULL)
m_isActive(false),
m_simulation(simulation),
m_obstacle(NULL),
m_pathLen(0),
m_wayPointIdx(-1)
{
m_navmesh = static_cast<KX_NavMeshObject*>(navmesh);
if (m_navmesh)
@ -147,6 +153,7 @@ bool KX_SteeringActuator::Update(double curtime, bool frame)
if (m_posevent && !m_isActive)
{
delta = 0;
m_pathUpdateTime = -1;
m_updateTime = curtime;
m_isActive = true;
}
@ -156,61 +163,89 @@ bool KX_SteeringActuator::Update(double curtime, bool frame)
RemoveAllEvents();
if (bNegativeEvent || !delta)
return false; // do nothing on negative events
if (!delta)
return true;
if (!m_target)
return false;
if (bNegativeEvent || !m_target)
return false; // do nothing on negative events
KX_GameObject *obj = (KX_GameObject*) GetParent();
const MT_Point3& mypos = obj->NodeGetWorldPosition();
const MT_Point3& targpos = m_target->NodeGetWorldPosition();
MT_Vector3 vectotarg = targpos - mypos;
MT_Vector3 steervec = MT_Vector3(0, 0, 0);
bool apply_steerforce = true;
bool apply_steerforce = false;
bool terminate = true;
switch (m_mode) {
case KX_STEERING_SEEK:
if (vectotarg.length2()>m_distance*m_distance)
{
apply_steerforce = true;
terminate = false;
steervec = vectotarg;
steervec.normalize();
apply_steerforce = true;
}
break;
case KX_STEERING_FLEE:
if (vectotarg.length2()<m_distance*m_distance)
{
apply_steerforce = true;
terminate = false;
steervec = -vectotarg;
steervec.normalize();
apply_steerforce = true;
}
break;
case KX_STEERING_PATHFOLLOWING:
if (m_navmesh && vectotarg.length2()>m_distance*m_distance)
{
static const int MAX_PATH_LENGTH = 128;
static const MT_Vector3 PATH_COLOR(1,0,0);
terminate = false;
float path[MAX_PATH_LENGTH*3];
int pathlen = m_navmesh->FindPath(mypos, targpos, path, MAX_PATH_LENGTH);
if (pathlen > 1)
static const MT_Scalar WAYPOINT_RADIUS(1.);
if (m_pathUpdateTime<0 || (m_pathUpdatePeriod>=0 &&
curtime - m_pathUpdateTime>((double)m_pathUpdatePeriod/1000)))
{
//debug draw
m_navmesh->DrawPath(path, pathlen, PATH_COLOR);
apply_steerforce = true;
MT_Vector3 waypoint(&path[3]);
steervec = waypoint - mypos;
steervec.z() = 0;
steervec.normalize();
m_pathUpdateTime = curtime;
m_pathLen = m_navmesh->FindPath(mypos, targpos, m_path, MAX_PATH_LENGTH);
m_wayPointIdx = m_pathLen > 1 ? 1 : -1;
}
if (m_wayPointIdx>0)
{
MT_Vector3 waypoint(&m_path[3*m_wayPointIdx]);
if ((waypoint-mypos).length2()<WAYPOINT_RADIUS*WAYPOINT_RADIUS)
{
m_wayPointIdx++;
if (m_wayPointIdx>=m_pathLen)
{
m_wayPointIdx = -1;
terminate = true;
}
else
waypoint.setValue(&m_path[3*m_wayPointIdx]);
}
steervec = waypoint - mypos;
apply_steerforce = true;
//debug draw
static const MT_Vector3 PATH_COLOR(1,0,0);
m_navmesh->DrawPath(m_path, m_pathLen, PATH_COLOR);
}
}
break;
}
if (apply_steerforce)
{
bool isdyna = obj->IsDynamic();
if (isdyna)
steervec.z() = 0;
if (!steervec.fuzzyZero())
steervec.normalize();
MT_Vector3 newvel = m_velocity*steervec;
//adjust velocity to avoid obstacles
@ -222,14 +257,23 @@ bool KX_SteeringActuator::Update(double curtime, bool frame)
KX_RasterizerDrawDebugLine(mypos, mypos + newvel, MT_Vector3(0.,1.,0.));
}
//temporary solution: set 2D steering velocity directly to obj
//correct way is to apply physical force
//MT_Vector3 movement = delta*m_velocity*steervec;
//obj->ApplyMovement(movement, false);
MT_Vector3 curvel = obj->GetLinearVelocity();
newvel.z() = curvel.z();
obj->setLinearVelocity(newvel, false);
if (isdyna)
{
//temporary solution: set 2D steering velocity directly to obj
//correct way is to apply physical force
MT_Vector3 curvel = obj->GetLinearVelocity();
newvel.z() = curvel.z();
obj->setLinearVelocity(newvel, false);
}
else
{
MT_Vector3 movement = delta*newvel;
obj->ApplyMovement(movement, false);
}
}
if (terminate && m_isSelfTerminated)
return false;
}
return true;

@ -43,6 +43,7 @@ class KX_GameObject;
class KX_NavMeshObject;
struct KX_Obstacle;
class KX_ObstacleSimulation;
const int MAX_PATH_LENGTH = 128;
class KX_SteeringActuator : public SCA_IActuator
{
@ -61,6 +62,12 @@ class KX_SteeringActuator : public SCA_IActuator
KX_Obstacle* m_obstacle;
double m_updateTime;
bool m_isActive;
bool m_isSelfTerminated;
float m_path[MAX_PATH_LENGTH*3];
int m_pathLen;
int m_pathUpdatePeriod;
double m_pathUpdateTime;
int m_wayPointIdx;
public:
enum KX_STEERINGACT_MODE
{
@ -79,6 +86,8 @@ public:
MT_Scalar velocity,
MT_Scalar acceleration,
MT_Scalar turnspeed,
bool isSelfTerminated,
int pathUpdatePeriod,
KX_ObstacleSimulation* simulation);
virtual ~KX_SteeringActuator();
virtual bool Update(double curtime, bool frame);