SimCharacter.cpp
#include "SimCharacter.h"
#include <iostream>
#include "SimBox.h"
#include "SimCapsule.h"
cSimCharacter::tParams::tParams()
{
mCharFile = "";
mStateFile = "";
mPos = tVector(0, 0, 0, 0);
}
cSimCharacter::cSimCharacter()
: mWorld(nullptr)
{
mFriction = 0.9;
mRootBodyTrans = tMatrix::Identity();
}
cSimCharacter::~cSimCharacter()
{
}
bool cSimCharacter::Init(std::shared_ptr<cWorld> world, const tParams& params)
{
bool succ = true;
bool succ_skeleton = cCharacter::Init(params.mCharFile);
succ &= succ_skeleton;
mWorld = world;
bool succ_body = true;
if (succ_skeleton)
{
const tVector& root_pos = params.mPos;
succ_body = BuildSimBody(params, root_pos);
LoadDrawShapeDefs(params.mCharFile, mDrawShapeDefs);
}
if (params.mStateFile != "")
{
bool succ_state = ReadState(params.mStateFile);
if (!succ_state)
{
printf("Failed to load character state from %s\n", params.mStateFile.c_str());
}
}
if (succ)
{
RecordDefaultState();
}
return succ;
}
void cSimCharacter::Clear()
{
cCharacter::Clear();
mJoints.clear();
mBodyParts.clear();
mBodyDefs.resize(0, 0);
mDrawShapeDefs.resize(0, 0);
mWorld.reset();
if (HasController())
{
mController->Clear();
}
}
void cSimCharacter::Reset()
{
cCharacter::Reset();
if (HasController())
{
mController->Reset();
}
ClearJointTorques();
#if defined(ENABLE_TRAINING)
ClearEffortBuffer();
#endif
}
void cSimCharacter::Update(double time_step)
{
BuildPose(mPose);
ClearJointTorques();
if (HasController())
{
mController->Update(time_step);
}
// dont clear torques until next frame since they can be useful for visualization
UpdateJoints();
#if defined(ENABLE_TRAINING)
UpdateEffortBuffer(time_step);
#endif
}
tVector cSimCharacter::GetRootPos() const
{
int root_id = GetRootID();
const std::shared_ptr<cSimObj>& root = mBodyParts[root_id];
tVector attach_pt = cKinTree::GetBodyAttachPt(mBodyDefs, root_id);
tVector pos = root->LocalToWorldPos(-attach_pt);
return pos;
}
void cSimCharacter::GetRootRotation(tVector& out_axis, double& out_theta) const
{
int root_id = GetRootID();
const std::shared_ptr<cSimObj>& root = mBodyParts[root_id];
tMatrix3 root_rot_mat = root->GetLocalToWorldRotMat();
tMatrix rot_mat = tMatrix::Identity();
rot_mat.block(0, 0, 3, 3) = mRootBodyTrans.block(0, 0, 3, 3) * root_rot_mat;
cMathUtil::RotMatToAxisAngle(rot_mat, out_axis, out_theta);
}
tVector cSimCharacter::GetRootVel() const
{
int root_id = GetRootID();
const std::shared_ptr<cSimObj>& root = mBodyParts[root_id];
tVector attach_pt = cKinTree::GetBodyAttachPt(mBodyDefs, root_id);
tVector vel = root->GetLinearVelocity(-attach_pt);
return vel;
}
tVector cSimCharacter::GetRootAngVel() const
{
const std::shared_ptr<cSimObj>& root = mBodyParts[GetRootID()];
return root->GetAngularVelocity();
}
const Eigen::MatrixXd& cSimCharacter::GetBodyDefs() const
{
return mBodyDefs;
}
const Eigen::MatrixXd& cSimCharacter::GetDrawShapeDefs() const
{
return mDrawShapeDefs;
}
void cSimCharacter::SetRootPos(const tVector& pos)
{
cKinTree::SetRootPos(mJointMat, pos, mPose);
SetPose(mPose);
}
int cSimCharacter::GetNumBodyParts() const
{
return static_cast<int>(mBodyParts.size());
}
void cSimCharacter::BuildPose(Eigen::VectorXd& out_pose) const
{
const double link_scale = 1;
int num_joints = GetNumJoints();
int num_dof = cKinTree::GetNumDof(mJointMat);
out_pose = Eigen::VectorXd(num_dof);
tVector root_pos = GetRootPos();
out_pose.block(0, 0, cKinTree::gPosDims, 1) = root_pos.block(0, 0, cKinTree::gPosDims, 1);
for (int j = 0; j < num_joints; ++j)
{
int idx = cKinTree::gPosDims + j;
double theta = 0;
tVector axis;
if (j == GetRootID())
{
// note for now theta all with respect to positive z axis
GetRootRotation(axis, theta);
theta = (axis[2] >= 0) ? theta : -theta;
}
else if (mJoints[j].IsValid())
{
CalcJointRotation(j, axis, theta);
}
out_pose(idx) = theta;
}
}
void cSimCharacter::BuildVel(Eigen::VectorXd& out_vel) const
{
const double link_scale_vel = 0;
int num_joints = GetNumJoints();
int num_dof = cKinTree::GetNumDof(mJointMat);
out_vel = Eigen::VectorXd(num_dof);
tVector root_vel = GetRootVel();
out_vel.block(0, 0, cKinTree::gPosDims, 1) = root_vel.block(0, 0, cKinTree::gPosDims, 1);
for (int j = 0; j < num_joints; ++j)
{
int idx = cKinTree::gPosDims + j;
double d_theta = 0;
if (j == GetRootID())
{
// note only consider z
const tVector rot_axis = tVector(0, 0, 1, 0);
tVector ang_vel = GetRootAngVel();
d_theta = rot_axis.dot(ang_vel);
}
else if (mJoints[j].IsValid())
{
const cJoint& joint = mJoints[j];
tVector joint_vel = joint.CalcJointVelRel();
const tVector& axis = joint.GetAxisRel();
d_theta = axis.dot(joint_vel);
}
out_vel(idx) = d_theta;
}
}
void cSimCharacter::SetVel(const Eigen::VectorXd& vel)
{
assert(vel.size() == GetNumDof());
// uses spatial algebra to convert generalized coordinates into
// velocities of each body part
int num_joints = GetNumJoints();
Eigen::VectorXi visited = Eigen::VectorXi::Zero(num_joints);
// use 4d vectors just for convenience
const int dim = 3;
Eigen::MatrixXd world_omegas = Eigen::MatrixXd(num_joints, dim);
Eigen::MatrixXd world_vels = Eigen::MatrixXd(num_joints, dim);
const int joint_vel_offset = cKinTree::gPosDims;
int root_id = GetRootID();
for (int j = 0; j < num_joints; ++j)
{
if (IsValidBodyPart(j))
{
Eigen::Vector3d world_omega = Eigen::Vector3d::Zero();
Eigen::Vector3d world_vel = Eigen::Vector3d::Zero();
int curr_id = j;
while (true)
{
bool has_visited = (visited[curr_id] != 0);
if (has_visited)
{
const Eigen::Vector3d& curr_omega = world_omegas.row(curr_id);
const Eigen::Vector3d& curr_vel = world_vels.row(curr_id);
world_omega += curr_omega;
world_vel += curr_vel;
break;
}
else
{
int idx = joint_vel_offset + curr_id;
double joint_vel = vel(idx);
auto& curr_part = GetBodyPart(curr_id);
tMatrix3 E = curr_part->GetLocalToWorldRotMat();
tMatrix3 E_inv = E.transpose();
Eigen::Vector3d local_omega = Eigen::Vector3d(0, 0, joint_vel);
Eigen::Vector3d local_vel = Eigen::Vector3d::Zero();
if (curr_id == root_id)
{
local_vel.block(0, 0, cKinTree::gPosDims, 1) = vel.block(0, 0, cKinTree::gPosDims, 1);
}
// convert vel to local coordinates
local_vel = E_inv * local_vel;
// convert spatial vector to world coordinates
tVector joint_pos = CalcJointPos(curr_id);
Eigen::Vector3d r = E_inv * -Eigen::Vector3d(joint_pos[0], joint_pos[1], joint_pos[2]);
Eigen::Vector3d curr_omega = E * local_omega;
Eigen::Vector3d curr_vel = E * (-r.cross(local_omega) + local_vel);
world_omega += curr_omega;
world_vel += curr_vel;
}
curr_id = cKinTree::GetParent(mJointMat, curr_id);
if (curr_id == cKinTree::gInvalidJointID)
{
break;
}
}
auto& part = GetBodyPart(j);
visited(j) = 1;
world_omegas.row(j) = world_omega;
world_vels.row(j) = world_vel;
// calculate the spatial velocity at the center of mass
tVector com_pos = part->GetPos();
Eigen::Vector3d r = Eigen::Vector3d(com_pos[0], com_pos[1], com_pos[2]);
Eigen::Vector3d com_omega = world_omega;
Eigen::Vector3d com_vel = -r.cross(world_omega) + world_vel;
part->SetAngularVelocity(tVector(com_omega[0], com_omega[1], com_omega[2], 0));
part->SetLinearVelocity(tVector(com_vel[0], com_vel[1], com_vel[2], 0));
}
}
}
tVector cSimCharacter::CalcJointPos(int joint_id) const
{
const cJoint& joint = mJoints[joint_id];
tVector pos;
if (joint.IsValid())
{
pos = joint.GetPos();
}
else if (joint_id == GetRootID())
{
pos = GetRootPos();
}
else
{
int parent_id = cKinTree::GetParent(mJointMat, joint_id);
assert(parent_id != cKinTree::gInvalidJointID);
assert(IsValidBodyPart(parent_id));
tVector attach_pt = cKinTree::GetScaledAttachPt(mJointMat, joint_id);
tVector part_attach_pt = cKinTree::GetBodyAttachPt(mBodyDefs, parent_id);
attach_pt -= part_attach_pt;
const auto& parent_part = GetBodyPart(parent_id);
pos = parent_part->LocalToWorldPos(attach_pt);
}
return pos;
}
tVector cSimCharacter::CalcJointVel(int joint_id) const
{
const cJoint& joint = mJoints[joint_id];
tVector vel;
if (joint.IsValid())
{
vel = joint.GetVel();
}
else if (joint_id == GetRootID())
{
vel = GetRootVel();
}
else
{
int parent_id = cKinTree::GetParent(mJointMat, joint_id);
assert(parent_id != cKinTree::gInvalidJointID);
assert(IsValidBodyPart(parent_id));
tVector attach_pt = cKinTree::GetScaledAttachPt(mJointMat, joint_id);
tVector part_attach_pt = cKinTree::GetBodyAttachPt(mBodyDefs, parent_id);
attach_pt -= part_attach_pt;
const auto& parent_part = GetBodyPart(parent_id);
vel = parent_part->GetLinearVelocity(attach_pt);
}
return vel;
}
void cSimCharacter::CalcJointWorldRotation(int joint_id, tVector& out_axis, double& out_theta) const
{
if (IsValidBodyPart(joint_id))
{
mBodyParts[joint_id]->GetRotation(out_axis, out_theta);
}
else
{
int parent_id = cKinTree::GetParent(mJointMat, joint_id);
assert(parent_id != cKinTree::gInvalidJointID);
assert(IsValidBodyPart(parent_id));
out_axis = tVector(0, 0, 1, 0);
const auto& parent_part = GetBodyPart(parent_id);
auto rot = parent_part->GetLocalToWorldRotMat();
out_axis.block(0, 0, 3, 1) = rot * out_axis.block(0, 0, 3, 1);
out_theta = 0;
}
}
tVector cSimCharacter::CalcCOM() const
{
tVector com = tVector::Zero();
double total_mass = 0;
for (int i = 0; i < static_cast<int>(mBodyParts.size()); ++i)
{
if (IsValidBodyPart(i))
{
const auto& part = mBodyParts[i];
double mass = part->GetMass();
tVector curr_com = part->GetPos();
com += mass * curr_com;
total_mass += mass;
}
}
com /= total_mass;
return com;
}
tVector cSimCharacter::CalcCOMVel() const
{
tVector com_vel = tVector::Zero();
double total_mass = 0;
for (int i = 0; i < static_cast<int>(mBodyParts.size()); ++i)
{
if (IsValidBodyPart(i))
{
const auto& part = mBodyParts[i];
double mass = part->GetMass();
tVector curr_vel = part->GetLinearVelocity();
com_vel += mass * curr_vel;
total_mass += mass;
}
}
com_vel /= total_mass;
return com_vel;
}
void cSimCharacter::CalcAABB(tVector& out_min, tVector& out_max) const
{
out_min[0] = std::numeric_limits<double>::infinity();
out_min[1] = std::numeric_limits<double>::infinity();
out_min[2] = std::numeric_limits<double>::infinity();
out_max[0] = -std::numeric_limits<double>::infinity();
out_max[1] = -std::numeric_limits<double>::infinity();
out_max[2] = -std::numeric_limits<double>::infinity();
for (int i = 0; i < GetNumBodyParts(); ++i)
{
if (IsValidBodyPart(i))
{
const auto& part = GetBodyPart(i);
tVector curr_min = tVector::Zero();
tVector curr_max = tVector::Zero();
part->CalcAABB(curr_min, curr_max);
out_min = out_min.cwiseMin(curr_min);
out_max = out_max.cwiseMax(curr_max);
}
}
}
const cJoint& cSimCharacter::GetJoint(int joint_id) const
{
return mJoints[joint_id];
}
cJoint& cSimCharacter::GetJoint(int joint_id)
{
return mJoints[joint_id];
}
const std::shared_ptr<cSimObj>& cSimCharacter::GetBodyPart(int idx) const
{
return mBodyParts[idx];
}
std::shared_ptr<cSimObj>& cSimCharacter::GetBodyPart(int idx)
{
return mBodyParts[idx];
}
const std::shared_ptr<cSimObj>& cSimCharacter::GetRootPart() const
{
int root_idx = GetRootID();
return mBodyParts[root_idx];
}
std::shared_ptr<cSimObj> cSimCharacter::GetRootPart()
{
int root_idx = GetRootID();
return mBodyParts[root_idx];
}
void cSimCharacter::RegisterContacts(int contact_flag, int filter_flag)
{
for (int i = 0; i < static_cast<int>(mBodyParts.size()); ++i)
{
if (IsValidBodyPart(i))
{
std::shared_ptr<cSimObj>& part = mBodyParts[i];
part->RegisterContact(contact_flag, filter_flag);
}
}
}
bool cSimCharacter::HasFallen() const
{
return false;
}
bool cSimCharacter::HasStumbled() const
{
return false;
}
bool cSimCharacter::HasExploded() const
{
const double dist_threshold = 0.02 * 0.02;
bool exploded = false;
int num_joints = GetNumJoints();
for (int j = 0; j < num_joints; ++j)
{
const cJoint& joint = GetJoint(j);
if (joint.IsValid())
{
const auto& parent = joint.GetParent();
const auto& child = joint.GetChild();
const tVector& anchor_parent = joint.GetParentAnchor();
const tVector& anchor_child = joint.GetChildAnchor();
tVector parent_pos = parent->LocalToWorldPos(anchor_parent);
tVector child_pos = child->LocalToWorldPos(anchor_child);
tVector delta = child_pos - parent_pos;
double dist = delta.squaredNorm();
if (dist > dist_threshold)
{
exploded = true;
break;
}
}
}
return exploded;
}
bool cSimCharacter::IsEndEffector(int idx) const
{
return false;
}
bool cSimCharacter::IsInContact() const
{
for (int i = 0; i < GetNumBodyParts(); ++i)
{
if (IsValidBodyPart(i))
{
if (IsInContact(i))
{
return true;
}
}
}
return false;
}
bool cSimCharacter::IsInContact(int idx) const
{
return GetBodyPart(idx)->IsInContact();
}
tVector cSimCharacter::GetContactPt(int idx) const
{
return GetBodyPart(idx)->GetContactPt();
}
int cSimCharacter::GetState() const
{
if (HasController())
{
return mController->GetState();
}
assert(false);
return 0;
}
double cSimCharacter::GetPhase() const
{
if (HasController())
{
return mController->GetPhase();
}
assert(false);
return 0;
}
void cSimCharacter::SetController(std::shared_ptr<cCharController> ctrl)
{
RemoveController();
mController = ctrl;
}
void cSimCharacter::RemoveController()
{
if (HasController())
{
mController.reset();
}
}
bool cSimCharacter::HasController() const
{
return mController != nullptr;
}
const std::shared_ptr<cCharController>& cSimCharacter::GetController()
{
return mController;
}
const std::shared_ptr<cCharController>& cSimCharacter::GetController() const
{
return mController;
}
void cSimCharacter::EnableController(bool enable)
{
if (HasController())
{
mController->SetActive(enable);
}
}
void cSimCharacter::ApplyControlForces(const Eigen::VectorXd& tau)
{
assert(tau.size() == GetNumDof());
for (int j = 0; j < GetNumJoints(); ++j)
{
cJoint& joint = GetJoint(j);
if (joint.IsValid())
{
int param_offset = GetParamOffset(j);
int param_size = GetParamSize(j);
auto curr_tau = tau.segment(param_offset, param_size);
assert(curr_tau.size() == 1);
tVector torque = tVector(0, 0, curr_tau[0], 0);
joint.AddTorque(torque);
}
}
}
void cSimCharacter::PlayPossum()
{
if (HasController())
{
mController->SetMode(cController::eModePassive);
}
}
void cSimCharacter::SetPose(const Eigen::VectorXd& pose)
{
cCharacter::SetPose(pose);
for (int i = 0; i < static_cast<int>(mBodyParts.size()); ++i)
{
if (IsValidBodyPart(i))
{
auto& curr_part = mBodyParts[i];
tVector axis;
double theta;
cKinTree::CalcBodyPartRotation(mJointMat, mPose, mBodyDefs, i, axis, theta);
tVector attach_pt = cKinTree::CalcBodyPartPos(mJointMat, mPose, mBodyDefs, i);
curr_part->SetPos(attach_pt);
curr_part->SetRotation(axis, theta);
}
}
}
bool cSimCharacter::BuildSimBody(const tParams& params, const tVector& root_pos)
{
bool succ = true;
succ = LoadBodyDefs(params.mCharFile, mBodyDefs);
int num_joints = GetNumJoints();
mBodyParts.resize(num_joints);
for (int j = 0; j < num_joints; ++j)
{
auto& curr_part = mBodyParts[j];
BuildBodyPart(j, root_pos, mFriction, curr_part);
if (curr_part != nullptr)
{
curr_part->UpdateContact(cWorld::eContactFlagCharacter, cWorld::eContactFlagAll);
curr_part->DisableDeactivation();
}
}
BuildConstraints(params.mPlaneCons);
#if defined(ENABLE_TRAINING)
mEffortBuffer.resize(GetNumJoints());
ClearEffortBuffer();
#endif
int root_id = GetRootID();
mRootBodyTrans = cMathUtil::InvRigidMat(cKinTree::BodyJointTrans(mBodyDefs, root_id));
return true;
}
bool cSimCharacter::LoadBodyDefs(const std::string& char_file, Eigen::MatrixXd& out_body_defs) const
{
bool succ = cKinTree::LoadBodyDefs(char_file, out_body_defs);
int num_joints = GetNumJoints();
int num_body_defs = static_cast<int>(out_body_defs.rows());
assert(num_joints == num_body_defs);
return succ;
}
bool cSimCharacter::LoadDrawShapeDefs(const std::string& char_file, Eigen::MatrixXd& out_draw_defs) const
{
bool succ = cKinTree::LoadDrawShapeDefs(char_file, out_draw_defs);
return succ;
}
void cSimCharacter::BuildBodyPart(int part_id, const tVector& root_pos, double friction, std::shared_ptr<cSimObj>& out_part)
{
cKinTree::eBodyShape shape = cKinTree::GetBodyShape(mBodyDefs, part_id);
switch (shape)
{
case cKinTree::eBodyShapeBox:
{
BuildBoxPart(part_id, root_pos, friction, out_part);
break;
}
case cKinTree::eBodyShapeCapsule:
{
BuildCapsulePart(part_id, root_pos, friction, out_part);
break;
}
default:
out_part = nullptr;
break;
}
}
void cSimCharacter::BuildBoxPart(int part_id, const tVector& root_pos, double friction,
std::shared_ptr<cSimObj>& out_part)
{
tMatrix com_world_trans = cKinTree::BodyWorldTrans(mJointMat, mPose, mBodyDefs, part_id);
tVector pos = com_world_trans * tVector(0, 0, 0, 1);
pos += root_pos;
tVector axis;
double theta;
cMathUtil::RotMatToAxisAngle(com_world_trans, axis, theta);
cSimBox::tParams params;
params.mSize = cKinTree::GetBodySize(mBodyDefs, part_id);
params.mPos = pos;
params.mAxis = axis;
params.mTheta = theta;
params.mFriction = friction;
params.mMass = cKinTree::GetBodyMass(mBodyDefs, part_id);
std::unique_ptr<cSimBox> box = std::unique_ptr<cSimBox>(new cSimBox());
short col_group = GetPartColGroup(part_id);
short col_mask = GetPartColMask(part_id);
box->SetColGroup(col_group);
box->SetColMask(col_mask);
box->Init(mWorld, params);
out_part = std::move(box);
}
void cSimCharacter::BuildCapsulePart(int part_id, const tVector& root_pos, double friction,
std::shared_ptr<cSimObj>& out_part)
{
tMatrix com_world_trans = cKinTree::BodyWorldTrans(mJointMat, mPose, mBodyDefs, part_id);
tVector pos = com_world_trans * tVector(0, 0, 0, 1);
pos += root_pos;
tVector axis;
double theta;
cMathUtil::RotMatToAxisAngle(com_world_trans, axis, theta);
cSimCapsule::tParams params;
tVector size_params = cKinTree::GetBodySize(mBodyDefs, part_id);
params.mHeight = size_params(1);
params.mRadius = size_params(0);
params.mPos = pos;
params.mAxis = axis;
params.mTheta = theta;
params.mFriction = friction;
params.mMass = cKinTree::GetBodyMass(mBodyDefs, part_id);
std::unique_ptr<cSimCapsule> box = std::unique_ptr<cSimCapsule>(new cSimCapsule());
short col_group = GetPartColGroup(part_id);
short col_mask = GetPartColMask(part_id);
box->SetColGroup(col_group);
box->SetColMask(col_mask);
box->Init(mWorld, params);
out_part = std::move(box);
}
void cSimCharacter::BuildConstraints(cWorld::ePlaneCons plane_cons)
{
int num_joints = GetNumJoints();
mJoints.clear();
mJoints.resize(num_joints);
tVector root_pos = GetRootPos();
Eigen::VectorXd default_pose = Eigen::VectorXd::Zero(mPose.size());
for (int j = 0; j < num_joints; ++j)
{
int parent_id = cKinTree::GetParent(mJointMat, j);
tVector joint_pos = cCharacter::CalcJointPos(j);
joint_pos += root_pos;
std::shared_ptr<cSimObj>& curr_part = mBodyParts[j];
bool valid_part = IsValidBodyPart(j);
if (parent_id != cKinTree::gInvalidJointID)
{
if (valid_part)
{
tVector joint_axis = tVector(0, 0, 1, 0);
tMatrix curr_body_mat = cKinTree::BodyJointTrans(mBodyDefs, j);
tMatrix child_parent_mat = cKinTree::ParentChildTrans(mJointMat, default_pose, j);
tMatrix parent_body_mat = cMathUtil::InvRigidMat(cKinTree::BodyJointTrans(mBodyDefs, parent_id));
tMatrix child_parent_body_mat = cMathUtil::InvRigidMat(parent_body_mat) * child_parent_mat * curr_body_mat;
tVector ref_axis;
double ref_theta;
cMathUtil::RotMatToAxisAngle(child_parent_body_mat, ref_axis, ref_theta);
ref_theta = -ref_theta;
const cKinTree::tJointDesc joint_desc = mJointMat.row(j);
std::shared_ptr<cSimObj>& parent = mBodyParts[parent_id];
tVector pos_child = curr_part->WorldToLocalPos(joint_pos);
tVector pos_parent = parent->WorldToLocalPos(joint_pos);
cWorld::tJointParams cons_params;
// cons_params.mType = cWorld::eJointTypeHinge;
cons_params.mType = (cWorld::eJointType) (int) joint_desc(cKinTree::eJointDescType);
// cons_params.mType = curr_part->GetType(); // wrong kind of type
cons_params.mAnchor0 = pos_parent;
cons_params.mAnchor1 = pos_child;
cons_params.mAxis = joint_axis;
cons_params.mLimLow = joint_desc(cKinTree::eJointDescLimLow);
cons_params.mLimHigh = joint_desc(cKinTree::eJointDescLimHigh);
cons_params.mEnableAdjacentCollision = false;
cons_params.mRefTheta = ref_theta;
curr_part->GetRotation(cons_params.mAnchorAxis1, cons_params.mAnchorTheta1);
const double torque_lim = 300;
cJoint& curr_joint = mJoints[j];
curr_joint.Init(mWorld, parent, curr_part, cons_params);
curr_joint.SetTorqueLimit(torque_lim);
}
}
if (valid_part)
{
tVector linear_factor;
tVector angular_factor;
BuildConsFactor(plane_cons, j, linear_factor, angular_factor);
curr_part->Constrain(linear_factor, angular_factor);
}
}
}
void cSimCharacter::BuildConsFactor(cWorld::ePlaneCons plane_cons, int joint_id, tVector& out_linear_factor, tVector& out_angular_factor) const
{
cKinTree::eJointType joint_type = cKinTree::GetJointType(mJointMat, joint_id);
bool is_root = cKinTree::IsRoot(mJointMat, joint_id);
mWorld->BuildConsFactor(plane_cons, out_linear_factor, out_angular_factor);
if (is_root)
{
tVector root_linear_factor;
tVector root_angular_factor;
BuildRootConsFactor(joint_type, root_linear_factor, root_angular_factor);
out_linear_factor = out_linear_factor.cwiseProduct(root_linear_factor);
out_angular_factor = out_angular_factor.cwiseProduct(root_angular_factor);
}
}
void cSimCharacter::BuildRootConsFactor(cKinTree::eJointType joint_type, tVector& out_linear_factor, tVector& out_angular_factor) const
{
out_linear_factor = tVector::Ones();
out_angular_factor = tVector::Ones();
switch (joint_type)
{
case cKinTree::eJointTypeRevolute:
out_linear_factor = tVector::Zero();
out_angular_factor = tVector(0, 0, 1, 0);
break;
case cKinTree::eJointTypePlanar:
out_linear_factor = tVector(1, 1, 0, 0);
out_angular_factor = tVector(0, 0, 1, 0);
break;
case cKinTree::eJointTypePrismatic:
out_linear_factor = tVector(1, 1, 0, 0);
out_angular_factor = tVector(0, 0, 1, 0);
break;
case cKinTree::eJointTypeFixed:
out_linear_factor = tVector::Zero();
out_angular_factor = tVector::Zero();
break;
default:
assert(false); // unsupported joint type
break;
}
}
bool cSimCharacter::IsValidBodyPart(int idx) const
{
return mBodyParts[idx] != nullptr;
}
void cSimCharacter::CalcJointRotation(int joint_id, tVector& out_axis, double& out_theta) const
{
const cJoint& joint = mJoints[joint_id];
if (joint.IsValid())
{
joint.CalcRotation(out_axis, out_theta);
}
else
{
out_axis = tVector(0, 0, 1, 0);
out_theta = cKinTree::GetJointTheta(mJointMat, mPose, joint_id);
}
}
tMatrix cSimCharacter::BuildJointWorldTrans(int joint_id) const
{
const cJoint& joint = mJoints[joint_id];
if (joint.IsValid())
{
return joint.BuildWorldTrans();
}
else
{
return cCharacter::BuildJointWorldTrans(joint_id);
}
}
void cSimCharacter::ClearJointTorques()
{
int num_joints = GetNumJoints();
for (int j = 0; j < num_joints; ++j)
{
cJoint& joint = GetJoint(j);
if (joint.IsValid())
{
joint.ClearTorque();
}
}
}
void cSimCharacter::UpdateJoints()
{
int num_joints = GetNumJoints();
for (int j = 0; j < num_joints; ++j)
{
cJoint& joint = GetJoint(j);
if (joint.IsValid())
{
// if (joint.) would be nice to check joint type and apply force or troque here.
joint.ApplyTorque();
}
}
}
short cSimCharacter::GetPartColGroup(int part_id) const
{
return cContactManager::gFlagAll;
}
short cSimCharacter::GetPartColMask(int part_id) const
{
return cContactManager::gFlagAll;
}
tVector cSimCharacter::GetPartColor(int part_id) const
{
return cKinTree::GetBodyColor(mBodyDefs, part_id);
}
bool cSimCharacter::HasDrawShapes() const
{
return mDrawShapeDefs.size() > 0;
}
double cSimCharacter::GetPoseJointWeight(int joint_id) const
{
return 1;
}
const std::shared_ptr<cWorld>& cSimCharacter::GetWorld() const
{
return mWorld;
}
#if defined(ENABLE_TRAINING)
// effort measured as sum of squared torques
double cSimCharacter::CalcEffort() const
{
double effort = 0;
for (int j = 0; j < GetNumJoints(); ++j)
{
const cJoint& joint = mJoints[j];
if (joint.IsValid())
{
effort += mEffortBuffer[j];
}
}
return effort;
}
void cSimCharacter::ClearEffortBuffer()
{
for (int j = 0; j < GetNumJoints(); ++j)
{
mEffortBuffer[j] = 0;
}
}
void cSimCharacter::UpdateEffortBuffer(double time_step)
{
int num_joints = GetNumJoints();
for (int j = 0; j < num_joints; ++j)
{
const cJoint& joint = GetJoint(j);
if (joint.IsValid())
{
const tVector& torque = joint.GetTorque();
double effort = torque.squaredNorm();
mEffortBuffer[j] += effort * time_step;
}
}
}
#endif // ENABLE_TRAINING