Public Group

# Bird movement

This topic is 3411 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi i'm working on implementing some kind of flocking behaviour so far it works alright Here's a video:
">video but a major problem is, that the birds arent rotating like real birds would :/ I've been reading a lot about quaternion rotations and flight kinetics and even looked at source codes but they usually involve TONS of math. is this really necessary? Because so far my movement routines are really simple and simple math usually turned out to be the best usually :) here's my simple code for movement and rotation: (it only rotates on the y-axis)
void MhBird::move(D3DXVECTOR3 v)
{

position += v;
rotation = atan2(v.x, v.z);
D3DXMatrixRotationY(&rotationmatrix, rotation);
D3DXMatrixTranslation( &worldmatrix, v.x, v.y, v.z);
D3DXMatrixMultiply(&worldmatrix, &rotationmatrix, &worldmatrix);
}


is there any way to advance this simple function to do the pitch and roll stuff a bird would do? it doesnt have to be absolutely physically correct. just something to get started with. here's my bird class btw if anyone is interested. I used some stuff from this open source project as a foundation http://www.koders.com/cpp/fid0041061C06005834B647EA36B1E18686547EB489.aspx

#pragma once

#include <list>
#include <vector>

class MhBird : public MhObject
{
public:
MhBird();
~MhBird();

void Update(double dTimeDelta);
void move(D3DXVECTOR3 v);
private:

bool FindClosest();

D3DXVECTOR3 Orientation();
D3DXVECTOR3 Separation();

MhObject* nearest;
std::list<MhObject*> closestList;

float nearestDist;

long time_elapsed;

// static variables to tweak
static float preferred_separation_;
static float minUrgency_;
static float maxUrgency_;
static float cohesionFactor_;
static float separationFactor_;
static float alignmentFactor_;
static float allowedDistToPredator_;

D3DXQUATERNION quatrot;

std::vector<MhObject*>::iterator sibling_it;

public:
inline long getTimeElapsed() { return time_elapsed; }
inline void resetTime() { time_elapsed = 0; }
static float predatorFactor_;
static float velMax_;
static float velDrag_;
};

float MhBird::preferred_separation_ = 30.0f;
float MhBird::minUrgency_ = 0.05f;
float MhBird::maxUrgency_ = 20.15f;
float MhBird::cohesionFactor_ = 0.015f;
float MhBird::separationFactor_ = 0.01f;
float MhBird::alignmentFactor_ = 0.01f;
float MhBird::allowedDistToPredator_ = 128.0f;

float MhBird::predatorFactor_ = 0.001f;
float MhBird::velMax_ = 1.7f;
float MhBird::velDrag_ = 0.97f;

int maxClosest = 8;

MhBird::MhBird()
{
nearest = NULL;
nearestDist = 0.0f;
time_elapsed = 0;
}

MhBird::~MhBird()
{
}

void MhBird::move(D3DXVECTOR3 v)
{

position += v;
rotation = atan2(v.x, v.z);
D3DXMatrixRotationY(&rotationmatrix, rotation);
D3DXMatrixTranslation( &worldmatrix, v.x, v.y, v.z);
D3DXMatrixMultiply(&worldmatrix, &rotationmatrix, &worldmatrix);
}

void MhBird::Update(double dTimeDelta)
{

time_elapsed += dTimeDelta;

D3DXVECTOR3 accel(0,0,0);

if (FindClosest())
{
accel += Orientation();
accel += Separation();
}

D3DXVECTOR3 vel = *this->getVel();

vel = velDrag_ * vel + accel;

if (D3DXVec3Length(&vel) > velMax_)
vel = velMax_ * *D3DXVec3Normalize(&vel, &vel);

float len = D3DXVec3Length(&vel);

D3DXVECTOR3 dir = *D3DXVec3Normalize(&vel, &vel);

dir *= len;

D3DXVec3Scale( &dir, &dir, float( 0.1f * dTimeDelta));

this->setVel( dir );

move(dir);
}

bool MhBird::FindClosest()
{

float closest = float(INFINITE);

for (sibling_it=GetSiblingList()->begin(); sibling_it != GetSiblingList()->end(); ++sibling_it)
{

if (*sibling_it == this) continue;

float dist = D3DXVec3Length(& (this->getPos() - (*sibling_it)->getPos()) );

if(dist < closest)
{
closest = dist;
nearest = *sibling_it;
}

}

nearestDist = closest;

return true;
}

D3DXVECTOR3 MhBird::Orientation()
{
D3DXVECTOR3 change(0,0,0);

change = (leader->getPos()- getPos()) + (nearest->getPos() - getPos()) / 2.0f;

else

change = *this->getTargetPos()- getPos();

D3DXVec3Normalize(&change, &change);

change *= 0.05f;

return change;
}

D3DXVECTOR3 MhBird::Separation()
{

D3DXVECTOR3 change(0,0,0);

if (!nearest) return change;

D3DXVECTOR3 change_total(0,0,0);

for (sibling_it=GetSiblingList()->begin(); sibling_it != GetSiblingList()->end(); ++sibling_it)
{

if((*sibling_it) == this)	continue;

D3DXVECTOR3 diff = (*sibling_it)->getPos() - this->getPos();

float nearDist = D3DXVec3Length(&diff);
float ratio = nearDist / preferred_separation_;

if(nearDist == 0.0f)
{
ratio = 0.1f;
diff = MhMath::getRandomVector(MhMath::ST_SPHERE);
}
else if(nearDist < 1.0f)
{
ratio = 0.2f;
diff = MhMath::getRandomVector(MhMath::ST_SPHERE);
}

if (nearDist < preferred_separation_)
{
D3DXVec3Normalize(&change, &(change));
diff *= -ratio;
}
else
{
diff *= 0.0f;
}
change_total += diff;
}

return change_total *= separationFactor_;
}


[Edited by - Daniel E on September 17, 2009 5:52:44 PM]

##### Share on other sites
You should be able to compute a pitch value from the velocity vector (in addition to yaw) fairly easily, e.g.:
float pitch = atan2(v.y, length(v.x, v.z));
For roll, you might try computing the value based on the last yaw delta (that is, how much the yaw value changed during the last update). This might help give the illusion of more natural motion, in that it would cause the birds to bank while turning.

##### Share on other sites
Thanks, that already helped a lot. The pitch part works good as far as i can tell.

I'm not sure about the roll though and how to compute it. I literally compute the difference between the values. The results look correct for the most part but sometimes
the birds rotate very strangly, which could be caused by my velocity computations though. Mind taking a look at the new code?

void MhBird::move(D3DXVECTOR3 v){	static float lastYaw = 0;	setPos(*position + v); // translate worldmatrix	yaw = atan2(v.x, v.z);	float roll = yaw - lastYaw;	float pitch = atan2(v.y, sqrtf(v.x * v.x + v.z * v.z));	lastYaw = yaw;	D3DXMatrixRotationYawPitchRoll(&rotationmatrix, yaw, pitch, roll);	D3DXMatrixMultiply(&worldmatrix, &rotationmatrix, &worldmatrix);}

##### Share on other sites
i'm actually pleased enough with the results for a flock of little birds. so if you dont see totally obvious mistakes, consider this topic solved.

##### Share on other sites
the above code wasn working well btw

here's something that works if you ever want to move some birds in a decent looking way:

(
">new video)

void MhBird::move(D3DXVECTOR3 v){	float yaw = atan2(v.x, v.z);	float yawDelta = abs(yaw - lastYaw);	if(yawDelta > D3DX_PI)		float roll = (2.0f * D3DX_PI - yawDelta) * 5.0f; // 5.0f = roll factor, to do: calculate	else		float roll = yawDelta * 5.0f;	float pitch = atan2(v.y, sqrtf(v.x * v.x + v.z * v.z));	lastYaw = yaw;	D3DXMatrixTranslation( &worldmatrix, v.x, v.y, v.z);	D3DXMatrixRotationYawPitchRoll(&rotationmatrix, yaw, pitch, roll);	D3DXMatrixMultiply(&worldmatrix, &rotationmatrix, &worldmatrix);}

##### Share on other sites
when adding pitch using the tangens formula, you have to be carefull. this works fine as long as you dont turn 180 degrees (otherwise, your left and right will change sides)
using quaternions can solve this.

following is C++

D3DXQUATERNION tmp; //makes quaternion
D3DXQuaternionRotationYawPitchRoll(&tmp, yaw, pitch, roll); //rotates quaternion (object)
D3DXMatrixRotationQuaternion(&tmp, &rotationmatrix); //make a matrix from a quaternion

now you have turned using a quaternion and you have your rotationmatrix back.

##### Share on other sites
thanks! that took my birds to another level

• ### What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 27
• 16
• 10
• 10
• 11
• ### Forum Statistics

• Total Topics
634101
• Total Posts
3015529
×