zoukankan      html  css  js  c++  java
  • 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进行了构造。

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

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

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

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

  • 相关阅读:
    投票通过,PHP 8 确认引入 Union Types 2.0
    Laravel 菜鸟的晋级之路
    给公司写的composer包开发的规范
    Swoft 源码剖析
    听说PHP的生成器yield处理大量数据杠杠的
    读懂JWT的使用,你就会用PHP如何实现了
    python标准库及其它应用
    python常用算法题
    python迭代器实例
    python生成器实例
  • 原文地址:https://www.cnblogs.com/justin_s/p/1898130.html
Copyright © 2011-2022 走看看