simbcon分析
这是领域内一经典文章,可贵的是其代码是开源的,对其对待分析有助于国内水平的普遍提高。
因为刚开始写,不完整,不严密,可能不正确,暂时不允许任何形式的软、硬拷贝及转载等。
同行交流请加gtak: justin.seeley.cn@gmail.com
按问答的方式,直接切入。
1. 模型是如何载入的?
模型存放在 src/data下,相关有目录有texture,objects,models,characters
查看 src\appgui\init下 input.conf
loadRBFile ../data/characters/bip2D.rbs
loadController ../data/controllers/bip2D/iWalk.sb
知道,其模型及相应控制器(后话)
bip2D.rbs:
Define the rigid bodies that will make up the character - this is the same as the normal bip3d, but has toe
格式如下,有几个地方含义不明确,看后文分析。
A_RigidBody
name 部位名
mesh mesh存放位置
colour 颜色
mass 质量
moi 惯性张量?
[CDP_Sphere | CDP_Box] 碰撞体
position 位置(重心)
frictionCoefficient 摩擦系数
restitutionCoefficient 恢复力系数?
[planer]
[ODEGroundParameters ?]
/End
ArticulatedFigure
root pelvis
[ballInSocketJoint|hingeJont|universalJoint] ?
name 关节名
parent 父骨头
child 孩子骨头
jointPPos 父亲位置?
jointCPos 孩子位置?
jointLimis 约束参数
/joint
。
。
/End
我们从Character类下手,寻找载入的方法。
看其构造函数,直接传入ArticulatatedFigure,转向此类.构造函数无特殊之处,有loadFromFile方法,应该是重点:
//this is where it happens.
while (!feof(f)){
//get a line from the file...
fgets(buffer, 200, f);
if (strlen(buffer)>195)
throwError("The input file contains a line that is longer than ~200 characters - not allowed");
char *line = lTrim(buffer);
int lineType = getRBLineType(line);
switch (lineType) {
case RB_ROOT:
sscanf(line, "%s", tempName);
if (root != NULL)
throwError("This articulated figure already has a root");
root = world->getARBByName(tempName);
if (root == NULL)
throwError("The articulated rigid body \'%s\' cannot be found!", tempName);
break;
case RB_JOINT_TYPE_UNIVERSAL:
tempJoint = new UniversalJoint(line);
tempJoint->loadFromFile(f, world);
tempJoint->child->AFParent = this;
tempJoint->parent->AFParent = this;
break;
case RB_JOINT_TYPE_HINGE:
tempJoint = new HingeJoint(line);
tempJoint->loadFromFile(f, world);
tempJoint->child->AFParent = this;
tempJoint->parent->AFParent = this;
break;
case RB_JOINT_TYPE_BALL_IN_SOCKET:
tempJoint = new BallInSocketJoint(line);
tempJoint->loadFromFile(f, world);
tempJoint->child->AFParent = this;
tempJoint->parent->AFParent = this;
break;
case RB_END_ARTICULATED_FIGURE:
//make sure that the root does not have a parent, otherwise we'll end up with loops in the articulated figure]
if (root->pJoint != NULL)
throwError("The root of the articulated figure is not allowed to have a parent!");
return;//and... done
break;
case RB_NOT_IMPORTANT:
if (strlen(line)!=0 && line[0] != '#')
tprintf("Ignoring input line: \'%s\'\n", line);
break;
default:
throwError("Incorrect articulated body input file: \'%s\' - unexpected line.", buffer);
}
}
分析这段代码发现,其读取的是文件的后半段,即定义关节部分,推测在其之前还有对同一个文件的调用。
Find All Reference发现:abstractrbengine中loadRBsFromFile方法:
while (!feof(f)){
//get a line from the file...
fgets(buffer, 200, f);
if (strlen(buffer)>195)
throwError("The input file contains a line that is longer than ~200 characters - not allowed");
char *line = lTrim(buffer);
int lineType = getRBLineType(line);
switch (lineType) {
case RB_RB:
//create a new rigid body and have it load its own info...
newBody = new RigidBody();
newBody->loadFromFile(f);
objects.push_back(newBody);
break;
case RB_ARB:
//create a new articulated rigid body and have it load its own info...
newBody = new ArticulatedRigidBody();
newBody->loadFromFile(f);
objects.push_back(newBody);
//remember it as an articulated rigid body to be able to link it with other ABs later on
ABs.push_back((ArticulatedRigidBody*)newBody);
break;
case RB_ARTICULATED_FIGURE:
//we have an articulated figure to worry about...
newFigure = new ArticulatedFigure();
AFs.push_back(newFigure);
newFigure->loadFromFile(f, this);
newFigure->addJointsToList(&jts);
break;
case RB_NOT_IMPORTANT:
if (strlen(line)!=0 && line[0] != '#')
tprintf("Ignoring input line: \'%s\'\n", line);
break;
default:
throwError("Incorrect rigid body input file: \'%s\' - unexpected line.", buffer);
}
}
正是我们想要的。
还可以看到,可以载入RigidBody、ArtiulatedRigidBody、ArticulatedFigure
再看RidgidBody的loadFromFile方法:
//this is where it happens.
while (!feof(f)){
//get a line from the file...
fgets(buffer, 200, f);
if (strlen(buffer)>195)
throwError("The input file contains a line that is longer than ~200 characters - not allowed");
char *line = lTrim(buffer);
int lineType = getRBLineType(line);
switch (lineType) {
case RB_NAME:
sscanf(line, "%s", this->name);
break;
case RB_MESH_NAME:
sscanf(line, "%s", meshName);
tmpMesh = OBJReader::loadOBJFile(meshName);
tmpMesh->computeNormals();
tmpMesh->dontUseTextureMapping();
meshes.push_back(tmpMesh);
break;
case RB_MASS:
if (sscanf(line, "%lf", &t)!=1)
throwError("Incorrect rigid body input file - a mass needs to be specified if the 'mass' keyword is used.");
this->props.setMass(t);
break;
case RB_MOI:
if (sscanf(line, "%lf %lf %lf", &t1, &t2, &t3)!=3)
throwError("Incorrect rigid body input file - the three principal moments of inertia need to be specified if the 'moi' keyword is used.");
if (t1<=0 || t2<=0 || t3<=0)
throwError("Incorrect values for the principal moments of inertia.");
this->props.setMOI(t1, t2, t3);
break;
case RB_END_RB:
return;//and... done
break;
case RB_COLOUR:
if (sscanf(line, "%lf %lf %lf %lf", &r, &g, &b, &a)!=4)
throwError("Incorrect rigid body input file - colour parameter expects 4 arguments (colour %s)\n", line);
if (meshes.size()>0)
meshes[meshes.size()-1]->setColour(r, g, b, a);
break;
case RB_SPHERE:
if (sscanf(line, "%lf %lf %lf %lf", &p1.x, &p1.y, &p1.z, &r)!=4)
throwError("Incorrect rigid body input file - 4 arguments are required to specify a sphere collision detection primitive\n", line);
cdps.push_back(new SphereCDP(this, p1, r));
break;
case RB_CAPSULE:
if (sscanf(line, "%lf %lf %lf %lf %lf %lf %lf", &p1.x, &p1.y, &p1.z, &p2.x, &p2.y, &p2.z, &r)!=7)
throwError("Incorrect rigid body input file - 7 arguments are required to specify a capsule collision detection primitive\n", line);
cdps.push_back(new CapsuleCDP(this, p1, p2, r));
break;
case RB_BOX:
if (sscanf(line, "%lf %lf %lf %lf %lf %lf", &p1.x, &p1.y, &p1.z, &p2.x, &p2.y, &p2.z)!=6)
throwError("Incorrect rigid body input file - 6 arguments are required to specify a box collision detection primitive\n", line);
cdps.push_back(new BoxCDP(this, p1, p2));
break;
case RB_PLANE:
if (sscanf(line, "%lf %lf %lf %lf %lf %lf", &n.x, &n.y, &n.z, &p1.x, &p1.y, &p1.z)!=6)
throwError("Incorrect rigid body input file - 6 arguments are required to specify a plane collision detection primitive\n", line);
cdps.push_back(new PlaneCDP(this, n, p1));
break;
case RB_NOT_IMPORTANT:
if (strlen(line)!=0 && line[0] != '#')
tprintf("Ignoring input line: \'%s\'\n", line);
break;
case RB_LOCKED:
this->props.lockBody();
break;
case RB_POSITION:
if (sscanf(line, "%lf %lf %lf", &state.position.x, &state.position.y, &state.position.z)!=3)
throwError("Incorrect rigid body input file - 3 arguments are required to specify the world coordinates position of a rigid body\n", line);
break;
case RB_ORIENTATION:
if (sscanf(line, "%lf %lf %lf %lf", &t, &t1, &t2, &t3)!=4)
throwError("Incorrect rigid body input file - 4 arguments are required to specify the world coordinates orientation of a rigid body\n", line);
state.orientation = Quaternion::getRotationQuaternion(t, Vector3d(t1, t2, t3).toUnit()) * state.orientation;
break;
case RB_VELOCITY:
if (sscanf(line, "%lf %lf %lf", &state.velocity.x, &state.velocity.y, &state.velocity.z)!=3)
throwError("Incorrect rigid body input file - 3 arguments are required to specify the world coordinates velocity of a rigid body\n", line);
break;
case RB_ANGULAR_VELOCITY:
if (sscanf(line, "%lf %lf %lf", &state.angularVelocity.x, &state.angularVelocity.y, &state.angularVelocity.z)!=3)
throwError("Incorrect rigid body input file - 3 arguments are required to specify the world coordinates angular velocity of a rigid body\n", line);
break;
case RB_FRICTION_COEFF:
if (sscanf(line, "%lf", &props.mu)!=1)
throwError("Incorrect rigid body input file - Expecting a value for the friction coefficient");
if (props.mu<0)
throwError("Incorrect rigid body input file - Friction coefficient should be >= 0");
break;
case RB_RESTITUTION_COEFF:
if (sscanf(line, "%lf", &props.epsilon)!=1)
throwError("Incorrect rigid body input file - Expecting a value for the restitution coefficient");
if (props.epsilon<0 || props.epsilon>1)
throwError("Incorrect rigid body input file - restitution coefficient should be between 0 and 1");
break;
case RB_ODE_GROUND_COEFFS:
if (sscanf(line, "%lf %lf", &t1, &t2)!=2)
throwError("Two parameters need to be provided for the ODE ground parameter settings");
props.groundSoftness = t1;
props.groundPenalty = t2;
break;
case RB_PLANAR:
props.isPlanar = true;
break;
default:
throwError("Incorrect rigid body input file: \'%s\' - unexpected line.", buffer);
}
再往上,发现是SimBiConFramework的构造函数的调用,再往上发现在是ControllerEditor中的调用,在其中构造出character之后,还对controller进行了构造。
因此载入过程基本明了了。除了有一个地方,我没有提,这个地方也非常重要。
这整个过程完成后,模型中的骨头、关节都已在内存中了。
其中使用了一些设计模式,有时间再补充上去。
下一章要问的是,如何显示出来的?

浙公网安备 33010602011771号