Hello everyone. I have a question to ask: How do we make an object face another one (with torque)?
Thank you for your answers
Moderators: Sascha Willems, walaber
matrix = BodyGetMatrix (body);
float mass, Ixx, Iyzz Izz = BodyGetMassMatrix (...)
vector currentDir = matrix.Rotate (0,0,1); // say local z is look direction of body
vector targetDir (1,0,0); // it should look at world x direction
float axis, vector angle = MakeAxisAndAngle (currentDir, targetDir);
vector targetAngVel = angle * angle / timestep; // make angular velocity from axis and angle (optional: scale by factor between 0.0 and 1.0 - see below)
vector curAngVel = BodyGetOmega();
targetAngVel -= curAngVel;
// here you could try NewtonBodySetOmega(targetAngVel), but using torque is better...
vector torque = targetAngVel / timestep; // make torque from angular velocity...
torque = matrix.Unrotate (torque); // go to local space to apply inertia
torque[0] *= Ixx;
torque[1] *= Iyy;
torque[2] *= Izz;
torque = matrix.Rotate (torque); // back to world space
torque *= 0.3; // something between 0.0 and 1.0; recommended <0.5, 1.0 would do full rotation in one step, but will generate overspin
static void angleBetween2(glm::vec3 v1,glm::vec3 v2, glm::vec3 &axis, float &angle) {
// turn vectors into unit vectors
glm::vec3 n1 = glm::normalize(v1);
glm::vec3 n2 = glm::normalize(v2);
angle = glm::acos(glm::dot(n1,n2));
// if no noticable rotation is available return zero rotation
// this way we avoid Cross product artifacts
if( glm::abs(angle) < 0.0001f)
axis = glm::vec3(0.f,0.f,1.f);
else
axis = glm::cross(n1, n2);
}
float m[16];
NewtonBodyGetMatrix (body, m);
dgMatrix matrix(m);
float mass, Ixx, Iyy, Izz;
NewtonBodyGetMassMatrix(body, &mass, &Ixx, &Iyy, &Izz);
float angle;
glm::vec3 axis;
angleBetween2(s.pos,e->mset().pos,axis,angle);//e is the other body and "s" and "mset()" is the struct containing the position, torque, force, ...
glm::vec3 targetAngVel = axis * angle; // make angular velocity from axis and angle
float v[3];
NewtonBodyGetOmega(body, v);
glm::vec3 curAngVel = glm::make_vec3(v);
targetAngVel -= curAngVel;
dgVector torque = dgVector(glm::value_ptr(targetAngVel*angle)); // make torque from angular velocity...
torque = matrix.UnrotateVector(torque); // go to local space to apply inertia
torque[0] *= Ixx;
torque[1] *= Iyy;
torque[2] *= Izz;
torque = matrix.RotateVector(torque); // back to world space
void ForceAndTorqueCallback (const NewtonBody* body, dFloat timestep, int threadIndex)
{
dFloat Ixx;
dFloat Iyy;
dFloat Izz;
dFloat mass;
BodyData *data = (BodyData*) BodyGetUserData (body);
sVec3 force (0.0f, mass * propsPhysics::f[propsPhysics::gravity], 0.0f);
force += data->force;
NewtonBodyAddForce (body, &force[0]);
sVec3 torque = data->torque;
NewtonBodyAddTorque (body, &torque[0]);
data->ClearForces(); // set torque and force to zero
}
//quaternion is four floats (x,y,z,w), first three is xyz vector and 4th is scalar w part
__forceinline void FromVecToVecNonUniformLength (const sVec3 &dir0, const sVec3 &dir1)
{
*((sVec3*)this) = dir0.Cross(dir1); // cast to vector part
(*this)[3] = 1.0 + dir0.Dot(dir1); // cast to scalar part
Normalize(); // like a vector normalization, but with all four values, not just three
}
__forceinline void ToAxisAndAngle (sVec3 &axis, sScalar &angle) //const
{
sScalar length2 = ((sVec3*)this)->SqL(); // squared length of vector part = this.Dot(this)
if ( length2 > FP_EPSILON2)
{
angle = 2.0 * acos(w());
float invlen = 1.0f / sqrt(length2);
axis = *((sVec3*)this) * invlen;
}
else
{
angle = 0;
axis = sVec3 (1.0, 0.0, 0.0);
}
}
Body *bLook, *bAt;
void CreateLookAtTest () // scene setup
{
sMat4 m; m.Identity(); m.Reset4thColumn();
Shape *shape = world->CreateBoxShape (sVec3(2.0, 0.5, 0.5));
m[3] = sVec3 (0, 1.0, 0);
bLook = world->CreateRigidBody (2.0, m, shape);
world->ReleaseShape (shape);
shape = world->CreateBoxShape (sVec3(0.5, 0.5, 0.5));
m[3] = sVec3 (0, 1.0, 3.0);
bAt = world->CreateRigidBody (2.0, m, shape);
world->ReleaseShape (shape);
}
void StepLookAtTest (float timestep) // called before newton update
{
sMat4 m;
BodyGetMatrix (bLook, m);
float mass, Ixx, Iyy, Izz;
BodyGetMassMatrix (bLook, mass, Ixx, Iyy, Izz);
sMat4 m2;
BodyGetMatrix (bAt, m2);
sVec3 &targetPos = m2[3];
sVec3 axis; float angle;
sQuat rot; rot.FromVecToVecNonUniformLength (m[0], targetPos - m[3]);
rot.ToAxisAndAngle (axis, angle);
sVec3 targetAngVel = axis * angle / timestep * 0.3; // make angular velocity from axis and angle
sVec3 curAngVel;
BodyGetAngVel (bLook, curAngVel); // == NewtonBodyGetOmega (bLook, &curAngVel[0]);
targetAngVel -= curAngVel;
sVec3 torque = targetAngVel / timestep; // make torque from angular velocity...
torque = m.Unrotate(torque); // go to local space to apply inertia
torque[0] *= Ixx;
torque[1] *= Iyy;
torque[2] *= Izz;
torque = m.Rotate(torque); // back to world space
BodyData *data = (BodyData*) BodyGetUserData(bLook);
data->torque += torque;
}
static void angleBetween2 (sVec3 n1, sVec3 n2, sVec3 &axis, float &angle)
{
// turn vectors into unit vectors
n1.Normalize();
n2.Normalize();
angle = acos(n1.Dot(n2));
// if no noticable rotation is available return zero rotation
// this way we avoid Cross product artifacts
if(fabs(angle) < 0.0001f)
axis = sVec3(0.f,0.f,1.f);
else
axis = sVec3(n1.Cross(n2)).Unit();
}
sVec3 axis; float angle;
//sQuat rot; rot.FromVecToVecNonUniformLength (m[0], targetPos - m[3]);
//rot.ToAxisAndAngle (axis, angle);
angleBetween2 (m[0], targetPos - m[3], axis, angle);
Body *shoot(){//shoot a bullet from the front of the object
dgMatrix m(glm::value_ptr(s.model));
dgVector v = m.m_front;
glm::vec3 pp = -glm::make_vec3(&v[0]);
float mass = msphere*mass_metal+1.f;
float life = 1.f;//mass*l_mult;
MovSet mset(s.pos+pp, mass, life);
Body *b = new Body(mset, def_mat, NewtonCreateSphere(world, 10.f*SCALE,0, NULL));
NewtonBodySetVelocity(b->body, glm::value_ptr(pp*10.f));
//NewtonBodySetContinuousCollisionMode(b->body, 1);
return b;
}
Body *update(float ts){ //return NULL if the body does not create any body, otherwise yes and it pushes a body in a vector for collision
if(is_fire){
if(e->mset().life <= 0.f){ //either body is "dead" or body is invincible like flat terrain
e = NULL;
is_fire = false;
return NULL;
}
float m[16];
NewtonBodyGetMatrix (body, m);
dgMatrix matrix(m);
glm::mat4 m2 = glm::make_mat4(m);
float mass, Ixx, Iyy, Izz;
NewtonBodyGetMassMatrix(body, &mass, &Ixx, &Iyy, &Izz);
float angle;
glm::vec3 axis;
/*glm::quat rot;
FromVecToVecNonUniformLength (rot, glm::vec3(m2[0]), e->mset().pos - glm::vec3(m2[3]));
ToAxisAndAngle (rot, axis, angle);*/
angleBetween2 (glm::vec3(m[0]), glm::vec3(e->mset().model[3]) - glm::vec3(m[3]), axis, angle);
glm::vec3 targetAngVel = axis * angle; // make angular velocity from axis and angle
float v[3];
NewtonBodyGetOmega(body, v);
targetAngVel -= glm::make_vec3(v);
dgVector torque = dgVector(glm::value_ptr(targetAngVel)); // make torque from angular velocity...
torque = matrix.UnrotateVector(torque); // go to local space to apply inertia
torque[0] *= Ixx;
torque[1] *= Iyy;
torque[2] *= Izz;
torque = matrix.RotateVector(torque); // back to world space
s.torque += glm::make_vec3(&torque[0]);
return shoot();
}
return NULL;
}
#define GRAVITY 1.f
static glm::vec3 GRAVITY_POINT = glm::vec3(0.f);
static void ApplyTransform(const NewtonBody* body, const dFloat* matrix, int threadId){
dgMatrix m(matrix);
MovSet *mset = (MovSet*) NewtonBodyGetUserData(body);
glm::vec3 p = glm::make_vec3(&m.m_posit[0]);
mset->pos = p;
mset->model = glm::make_mat4(matrix);
}
static void ApplyForceAndTorque(const NewtonBody* body, dFloat timestep, int threadId){
MovSet *mset = (MovSet*) NewtonBodyGetUserData(body);
glm::vec3 gravity = (GRAVITY_POINT-mset->pos)*GRAVITY*mset->mass;
#ifdef Y_GRAVITY
mset->force.y += gravity.y;//gravity;
#else
mset->force += gravity;//gravity;
#endif
NewtonBodyAddForce(body, glm::value_ptr(mset->force));
NewtonBodyAddTorque(body, glm::value_ptr(mset->torque));
mset->force = glm::vec3(0.f);
mset->torque = glm::vec3(0.f);
}
struct MovSet{
glm::vec3 pos;
glm::vec3 force, torque;
glm::mat4 model;
float mass;
float life;
float rlife;
unsigned int id, g;
MovSet(glm::vec3 p, float m, float l, float rl = 0.f)
: pos(p), mass(m), id(0), g(0), force(0.f), torque(0.f), model(1.f), life(l), rlife(rl){
force = glm::vec3(0.f);
torque = glm::vec3(0.f);
model = glm::mat4(1.f);
}
void use(unsigned int _g, unsigned int _id){
g = _g;
id = _id;
}
void damage(float l){
life -= l;
}
};
static void angleBetween2(glm::vec3 v1,glm::vec3 v2, glm::vec3 &axis, float &angle) {
// turn vectors into unit vectors
glm::vec3 n1 = glm::normalize(v1);
glm::vec3 n2 = glm::normalize(v2);
angle = glm::acos(glm::dot(n1,n2));
// if no noticable rotation is available return zero rotation
// this way we avoid Cross product artifacts
/*if( glm::abs(angle) < 0.0001f)
axis = glm::vec3(0.f,0.f,1.f);
else*/
axis = glm::normalize(glm::cross(n1, n2));
}
inline void FromVecToVecNonUniformLength (glm::quat q, const glm::vec3 &dir0, const glm::vec3 &dir1)
{
glm::vec3 v = glm::cross(dir0,dir1); // cast to vector part
q.x = v.x;
q.y = v.y;
q.z = v.z;
q.w = 1.f + glm::dot(dir0,dir1); // cast to scalar part
q = glm::normalize(q);
}
inline void ToAxisAndAngle (glm::quat q, glm::vec3 &axis, float &angle) //const
{
float length2 = glm::length(glm::vec3(q.x, q.y, q.z)); // squared length of vector part = this.Dot(this)
if ( length2 > 8.854e-12f)
{
angle = 2.f * glm::acos(q.w);
float invlen = 1.f / glm::sqrt(length2);
axis = glm::vec3(q.x, q.y, q.z) * invlen;
}
else
{
angle = 0.f;
axis = glm::vec3(1.f, 0.f, 0.f);
}
}
float m[16];
NewtonBodyGetMatrix (body, m);
glm::vec3 targetAngVel = -axis * angle;
Users browsing this forum: No registered users and 0 guests