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进行了构造。

因此载入过程基本明了了。除了有一个地方,我没有提,这个地方也非常重要。

这整个过程完成后,模型中的骨头、关节都已在内存中了。

其中使用了一些设计模式,有时间再补充上去。

下一章要问的是,如何显示出来的?

posted @ 2010-12-06 21:18  justin_s  阅读(618)  评论(0编辑  收藏  举报