Problem with backface culling in Conduit

Hi
I recently migrated from Rhino5 to Rhino7. I have code that draws objects with display conduit, and uses back face culling in the conduit. This code was drawing with culled back faces in Rhino5, but it does not work in Rhino7. In Rhino7 it draws without culled back faces. What can be the problem. This is my code :

class CConduitTestBackFaceCulling : public CRhinoDisplayConduit
{
public:
    CConduitTestBackFaceCulling(const ON_Brep* brep, const CRhinoObject* obj);
    ~CConduitTestBackFaceCulling() = default;

    bool ExecConduit(
        CRhinoDisplayPipeline& dp, // pipeline executing this conduit
        UINT nChannel,             // current channel within the pipeline
        bool& bTerminate           // channel termination flag
    );

private:
    const ON_Brep * m_Brep;
    const CRhinoObject* mObject;
};

CConduitTestBackFaceCulling::CConduitTestBackFaceCulling(const ON_Brep* brep, const CRhinoObject* obj)
    : CRhinoDisplayConduit(CSupportChannels::SC_CALCBOUNDINGBOX | CSupportChannels::SC_PREDRAWOBJECTS | CSupportChannels::SC_DRAWOBJECT),
    m_Brep(brep), mObject(obj)
{
}

bool CConduitTestBackFaceCulling::ExecConduit(CRhinoDisplayPipeline& dp, UINT nChannel, bool& bTerminate)
{
    UNREFERENCED_PARAMETER(bTerminate);

    // Determine which channel we're currently executing in...
    switch (nChannel)
    {
    case CSupportChannels::SC_CALCBOUNDINGBOX:
    {
        ON_BoundingBox  bbox;
        m_Brep->GetTightBoundingBox(bbox, false);
        // Now adjust the channel attribute's bounding box with the accumulated one...
        m_pChannelAttrs->m_BoundingBox.Union(bbox);
    }
    break;

    case CSupportChannels::SC_DRAWOBJECT:
    {
        if (m_pChannelAttrs->m_pObject == mObject)
        {
            m_pChannelAttrs->m_bDrawObject = false;
        }
    }
    break;

    case CSupportChannels::SC_PREDRAWOBJECTS:
    {
        dp.PushDepthTesting(false);
        m_pDisplayAttrs->m_bShowIsocurves = false;
        m_pDisplayAttrs->m_bCullBackfaces = true;

        ON_Brep* brep = const_cast<ON_Brep*>(m_Brep);

        CDisplayPipelineMaterial material;
        material.m_FrontMaterial.m_diffuse = ON_Color(0, 0, 255);
        material.m_BackMaterial.m_diffuse = ON_Color(0, 0, 255);
        dp.DrawShadedBrep(brep, &material, 0);
		//dp.DrawShadedBrep(*brep, &material); //in Rhino5

        m_pDisplayAttrs->m_bShowIsocurves = true;
        m_pDisplayAttrs->m_bCullBackfaces = false;
        dp.PopDepthTesting();
       
    }
    break;
    }

    return true;
}
CRhinoCommand::result CCommandTestBackFaceCullingCmd::RunCommand(const CRhinoCommandContext& context)
{
    CRhinoGetObject go;
    go.SetCommandPrompt(L"Select brep");
    go.SetGeometryFilter(ON::brep_object);
    go.GetObjects(1, 1);
    if (go.CommandResult() != success)
        return go.CommandResult();

    CRhinoObjRef ref = go.Object(0);
    const ON_Brep * brep = ref.Brep();

    const CRhinoObject * obj = ref.Object();

    CConduitTestBackFaceCulling conduit(brep, obj);
    conduit.Enable();

    RhinoApp().ActiveDoc()->Regen();

    CRhinoGetPoint gp;
    gp.SetCommandPrompt(L"Select point to stop conduit");
    gp.GetPoint();

    conduit.Disable();
    context.m_doc.Regen();
    return CRhinoCommand::success;
}

I uploaded minimal test example and model , to be tested both in Rhino5 and Rhino7.
Thank you for your help

TestBackFaceCullingCmd.txt (3.9 KB)
Model_BackfaceCull.3dm (25.9 KB)

Hi
Can I get some help with this please

@jeff - is this something you can help with?

I will take a look at this now… If I were to take a guess (WAG at that)…it would be some kind of caching issue where the attributes specified when the draw call is made are not what they should be at the time the meshes are actually drawn…but again, that’s just a guess atm… I’ll know more once I dig into it.

-J

1 Like

It is related to caching as I thought… Meshes in V7 (and V6) are no longer drawn using any kind of “immediate” mode in OpenGL (it’s all been deprecated since GL 3.0)… So Rhino creates buffer objects of the mesh to store on the GPU…once there, setting “display attributes” prior to drawing, may not work as expected. The correct method is to set the engine’s state prior to drawing, since that state gets copied with the buffer objects.

The following snippet is all that is needed for your case:

    CRhinoDisplayEngine*  engine = dp.Engine();

    if (engine != nullptr)
    {
      ECullFaceMode  oldCulling = engine->CullFaceMode();

      engine->SetCullFaceMode(ECullFaceMode::CFM_DRAW_FRONT_FACES);
      dp.DrawShadedBrep(brep, &material, 0);
      engine->SetCullFaceMode(oldCulling);
    }

To turn on “back face culling”, you set the Cull Face Mode to “Front Faces Only”, and then draw…and then return the engine’s state back to the way you found it.

-Jeff

1 Like

Thank you Jeff, it works now.