I have a model structured like this:

 1. Root model

     1.1.Child model 1

     1.2 Child model 2

     1.3 Child model 3

     1.4 .....

The model in question is the "sponza" model used in many research articles, for example viewed here, in an otherwise unrelated video: https://www.youtube.com/watch?v=uhmH1PaY9Sw

I have implemented a view frustrum culling alghorithm that produces INSIDE, OUTSIDE or PARTIAL results for each model. The problem is I'm not sure how to apply it when building my renderqueue.

Here's my current alghorithm:

  • If model AABB it OUTSIDE, skip it and all its children
  • If model is INSIDE || (PARTIAL && no child models), render it
  • If model is PARTIAL and has children, dont render it but repeat process for its children

Is this the correct approach? I don't notice any particular performance benefits, unless the view frustrum is completely outside the root model...

void Engine::CullModels(const std::vector<ModelPtr>& allModels, const Mat4& viewProjectionMatrix, const Mat4& parentTransform)
    // TODO: not very cache-friendly
    // this could be a CPU-hotspot for complex scenes
    FrustrumIntersection aabbIntersection(FRUSTRUM_INTERSECTION_INSIDE);
    for (const ModelPtr model : allModels)
        if (!model)

        Mat4 worldMatrix = parentTransform;
        if (model->mSceneNode)
            worldMatrix *= model->mSceneNode->GetNodeTransform();
        const Mat4 worldViewProjMatrix = viewProjectionMatrix * worldMatrix;

        aabbIntersection = IsAABBInFrustum(model->GetAABBCenter(), model->GetAABBExtent(), worldViewProjMatrix);
        if (aabbIntersection == FRUSTRUM_INTERSECTION_OUTSIDE)

        if (aabbIntersection == FRUSTRUM_INTERSECTION_PARTIAL && model->mMesh != INVALID_MESH_ID)
            const MaterialPtr material(model->mMaterial);
            if (material)
                mRenderQueue.emplace_back(Renderable(model->mMesh, worldViewProjMatrix, worldMatrix, model->mMaterialTilingFactor,
                                                    Vec4(material->mDiffuseColor, 1.0f), Vec4(material->mAmbientColor, 1.0f), Vec4(material->mSpecularColor, 1.0f), Vec4(material->mEmissiveColor, 1.0f),
                                                     material->mDiffuseTexture, material->mNormalTexture, material->mSpecularFactor));
                mRenderQueue.emplace_back(Renderable(model->mMesh, worldViewProjMatrix, worldMatrix));

        CullModels(model->mChildren, viewProjectionMatrix, worldMatrix);
  • \$\begingroup\$ Why are you pushing models into a queue? You really dont like your CPU and memory - so many lookups/copies AND creating new objects. \$\endgroup\$ – wondra Dec 5 '14 at 14:37
  • \$\begingroup\$ It's somewhat offtopic, but I'd love any alternatives if you have \$\endgroup\$ – KaiserJohaan Dec 5 '14 at 14:41
  • \$\begingroup\$ I am afraid it might the reason where the gained performance is lost. Try not-doing any culling but also dont move the data in your memory, render read-only the whole tree or even better linear array of models instead of tree.(and report back if my guess was wrong and it had much worse performance). \$\endgroup\$ – wondra Dec 5 '14 at 14:48
  • \$\begingroup\$ I'll probably do that next; if nothing else then for pure interest I'd like to try nailing view frustrum culling first \$\endgroup\$ – KaiserJohaan Dec 5 '14 at 15:20
  • \$\begingroup\$ Also, this presentation might interest you. (also the reason why suggested giving up memory-heavy operations) \$\endgroup\$ – wondra Dec 5 '14 at 16:48

To test culling, you probably want to render to another target without the culling to see if your culling strategy is working as intended.

Second, rather than putting the visible objects into a collection, instead have a flag on each objects on whether or not they are visible. When drawing, skip objects with the flag set to false.

Assuming your view frustum culling algorithm is correct, you need to know whether or not your model is hierarchical, that is, whether the parent AABB fully contains all the children AABBs. If so, then its something like this:

If Parent is visible, render the parent and all its children.

If Parent is not visible, dont render parent and any of its children.

If Parent is partial, render the parent and repeat for every child.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.