void ArticulatedModel::BoundsCallback::operator()
    (ArticulatedModel::Part* part, const CFrame& worldToPartFrame, 
     shared_ptr<ArticulatedModel> m, const int treeDepth) {
    for (int i = 0; i < m->meshArray().size(); ++i) {
        Mesh* mesh = m->meshArray()[i];
        if (mesh->logicalPart == part) {
            const Box& b = worldToPartFrame.toWorldSpace(mesh->boxBounds);
            AABox partBounds;
            b.getBounds(partBounds);
            bounds.merge(partBounds);
        }
    }
}
Example #2
0
void VisibleEntity::onPose(Array<shared_ptr<Surface> >& surfaceArray) {

    // We have to pose in order to compute bounds that are used for selection in the editor
    // and collisions in simulation, so pose anyway if not visible,
    // but then roll back.
    debugAssert(isFinite(m_frame.translation.x));
    debugAssert(! isNaN(m_frame.rotation[0][0]));
    const int oldLen = surfaceArray.size();

    const bool boundsChangedSincePreviousFrame = poseModel(surfaceArray);

    // Compute bounds for objects that moved
    if (m_lastAABoxBounds.isEmpty() || boundsChangedSincePreviousFrame || (m_lastChangeTime > m_lastBoundsTime)) {

        m_lastSphereBounds = Sphere(m_frame.translation, 0);
        
        const CFrame& myFrameInverse = frame().inverse();

        m_lastObjectSpaceAABoxBounds = AABox::empty();
        m_lastBoxBoundArray.fastClear();

        // Look at all surfaces produced
        for (int i = oldLen; i < surfaceArray.size(); ++i) {
            AABox b;
            Sphere s;
            const shared_ptr<Surface>& surf = surfaceArray[i];

            // body to world transformation for the surface
            CoordinateFrame cframe;
            surf->getCoordinateFrame(cframe, false);
            debugAssertM(cframe.translation.x == cframe.translation.x, "NaN translation");


            surf->getObjectSpaceBoundingSphere(s);
            s = cframe.toWorldSpace(s);
            m_lastSphereBounds.radius = max(m_lastSphereBounds.radius,
                                            (s.center - m_lastSphereBounds.center).length() + s.radius);


            // Take the entity's frame out of consideration, so that we get tight AA bounds 
            // in the Entity's frame
            CFrame osFrame = myFrameInverse * cframe;

            surf->getObjectSpaceBoundingBox(b);

            m_lastBoxBoundArray.append(cframe.toWorldSpace(b));
            const Box& temp = osFrame.toWorldSpace(b);
            m_lastObjectSpaceAABoxBounds.merge(temp);
        }

        // Box can't represent an empty box, so we make empty boxes into real boxes with zero volume here
        if (m_lastObjectSpaceAABoxBounds.isEmpty()) {
            m_lastObjectSpaceAABoxBounds = AABox(Point3::zero());
            m_lastAABoxBounds = AABox(frame().translation);
        }

        m_lastBoxBounds = frame().toWorldSpace(m_lastObjectSpaceAABoxBounds);
        m_lastBoxBounds.getBounds(m_lastAABoxBounds);
        m_lastBoundsTime = System::time();
    }

    if (! m_visible) {
        // Discard my surfaces if I'm invisible; they were only needed for bounds
        surfaceArray.resize(oldLen, false);
    }
}
Example #3
0
void ArticulatedViewer::onInit(const String& filename) {
    ArticulatedModel::clearCache();
    Texture::clearCache();

    m_filename = filename;

    m_selectedPart   = NULL;
    m_selectedMesh   = NULL;
    m_selectedTriangleIndex = -1;
    m_numFaces       = 0;
    m_numVertices    = 0;
    m_shadowMapDirty = true;

    UniversalMaterial::clearCache();
    
    const RealTime start = System::time();
    if (toLower(FilePath::ext(filename)) == "any") {

        if ((toLower(FilePath::ext(FilePath::base(filename))) == "material") ||
            (toLower(FilePath::ext(FilePath::base(filename))) == "universalmaterial")) {

            // Assume that this is an .UniversalMaterial.Any file. Load a square and apply the material
            Any any(Any::TABLE, "ArticulatedModel::Specification");
            any["filename"] = "model/crate/crate4xtex.obj";
            any["stripMaterials"] = true;
            any["preprocess"] = Any(Any::ARRAY);

            Any arg(Any::ARRAY, "setMaterial");
            arg.append(Any(Any::ARRAY, "all"));
            arg.append(Any::fromFile(filename));
            any["preprocess"].append(arg);

            Any arg2(Any::ARRAY, "setTwoSided");
            arg2.append(Any(Any::ARRAY, "all"));
            arg2.append(true);
            any["preprocess"].append(arg2);

            m_model = ArticulatedModel::create(ArticulatedModel::Specification(any));
        } else {

            // Assume that this is an .ArticulatedModel.Any file
            Any any;
            any.load(filename);

            m_model = ArticulatedModel::create(ArticulatedModel::Specification(any));
        }
    } else {
        m_model = ArticulatedModel::fromFile(filename);
    }
    debugPrintf("%s loaded in %f seconds\n", filename.c_str(), System::time() - start);


    Array<shared_ptr<Surface> > arrayModel;
    if (m_model->usesSkeletalAnimation()) {
        Array<G3D::String> animationNames;
        m_model->getAnimationNames(animationNames);
        // TODO: Add support for selecting animations.
        m_model->getAnimation(animationNames[0], m_animation); 
        m_animation.getCurrentPose(0.0f, m_pose);
    } 
    
    m_model->pose(arrayModel, CFrame(), m_pose);

    m_model->countTrianglesAndVertices(m_numFaces, m_numVertices);
    
    m_scale = 1;
    m_offset = Vector3::zero();
    bool overwrite = true;
    
    // Find the size of the bounding box of the entire model
    AABox bounds;
    if (arrayModel.size() > 0) {
        
        for (int x = 0; x < arrayModel.size(); ++x) {		
            
            //merges the bounding boxes of all the seperate parts into the bounding box of the entire object
            AABox temp;
            CFrame cframe;
            arrayModel[x]->getCoordinateFrame(cframe);
            arrayModel[x]->getObjectSpaceBoundingBox(temp);
            Box partBounds = cframe.toWorldSpace(temp);
            
            // Some models have screwed up bounding boxes
            if (partBounds.extent().isFinite()) {
                if (overwrite) {
                    partBounds.getBounds(bounds);
                    overwrite = false;
                } else {
                    partBounds.getBounds(temp);
                    bounds.merge(temp);
                }
            }
        }
        
        if (overwrite) {
            // We never found a part with a finite bounding box
            bounds = AABox(Vector3::zero());
        }
        
        Vector3 extent = bounds.extent();
        Vector3 center = bounds.center();
        
        // Scale to X units
        float scale = 1.0f / max(extent.x, max(extent.y, extent.z));
        
        if (scale <= 0) {
            scale = 1;
        }

        if (! isFinite(scale)) {
            scale = 1;
        }

        m_scale = scale;
        scale *= VIEW_SIZE;
        m_offset = -scale * center;
        

        if (! center.isFinite()) {
            center = Vector3();
        }

        // Transform parts in-place
        m_model->scaleWholeModel(scale);

        ArticulatedModel::CleanGeometrySettings csg;
        // Merging vertices is slow and topology hasn't changed at all, so preclude vertex merging
        csg.allowVertexMerging = false; 
        m_model->cleanGeometry(csg);
    }

    // Get the newly transformed animation
    if (m_model->usesSkeletalAnimation()) {
        Array<String> animationNames;
        m_model->getAnimationNames(animationNames);
        // TODO: Add support for selecting animations.
        m_model->getAnimation(animationNames[0], m_animation); 
        m_animation.getCurrentPose(0.0f, m_pose);
    } 

    // saveGeometry();
}