How to set the bounding box for handdrawn objects

I have a custom implementation of a AIS_InteractiveObject where GL_ARRAY_BUFFER are managed directly because they're originating from an external library and copying them into Graphic3d_ArrayOfPrimitives would double the used resources (they're send through a callback and are directly uploaded to the GPU).

I was hoping that by overriding PrsMgr_PresentableObject::BoundingBox and setting thePrs->SetInfiniteState(false) and thePrs->SetMutable(true) for the presentation the bounding box would be taken into account by V3d_View::ZFitAll but that didn't work:

both shapes without any bounding box or z near far adaption

The "handdrawn" ais object is a simple yellow box which completely wraps a native occt sphere shape:

occ shape within the handdrawn box

It seems like the actual near and far values for the orthographic projection are summed up by Graphic3d_CView::MinMaxValues using

Graphic3d_Layer::BoundingBox Graphic3d_Structure::addTransformed Graphic3d_Structure::minMaxCoord

and ultimately

Graphic3d_Group::AddPrimitiveArray

which iterates over all attribute arrays of which i have none.

For testing purposes it added the bounds calculated by the external lib as a single line in a Graphic3d_Group with a Graphic3d_ArrayOfPolylines like

auto const aabb = ...
Handle(Graphic3d_Group) group = thePrs->NewGroup();
Handle(Graphic3d_ArrayOfPolylines) lines = new Graphic3d_ArrayOfPolylines(2, 0, 0, Standard_False, Standard_False);
lines->AddVertex(aabb->first);
lines->AddVertex(aabb->second);
group->AddPrimitiveArray(lines);

and got the desired result.

both shapes with bounding box adapted through vertex array

I also tried to adapt Z near and far directly in the overridden OpenGl_Element::Render function like

auto projection = aCtx->ProjectionState.Current();
auto theNear = aCtx->Camera()->ZNear();
auto theFar = aCtx->Camera()->ZFar();
auto const diff = theFar - theNear;
theNear -= 3 * diff;
theFar += 3 * diff;
projection.SetValue(2, 2, (-2.0) / (theFar - theNear));
projection.SetValue(2, 3, (theFar + theNear) / (theFar - theNear));
aCtx->ProjectionState.Push();
aCtx->ProjectionState.SetCurrent(projection);
aCtx->ApplyProjectionMatrix();
// render
// [...]
// reset states
aCtx->ProjectionState.Pop();
aCtx->ApplyModelViewMatrix();

to see if increasing the range to include the z bounds of my object would help but that didn't work; now the handdrawn object is always behind the occ shape:

both shapes with z near far adapted in overridden render method

I hope adapting z near and far in the render method is the right approach and i'm just doing something wrong.

Is it possible to render manually like this and take ad hoc bounding boxes into account or is the only possibility to fill at least a minimum in a Graphic3d_Group so that Graphic3d_Group::AddPrimitiveArray can do the rest and calculate a proper bounding box which then leads to matching Z near and far values?

gkv311 n's picture

Take a look at "VUserDrawObj::Compute()" sample - I think Graphic3d_Group::SetMinMaxValues() method is what you are looking for. There is no need adding a "fake" primitive array into the group.

Lion G.'s picture

Nice! This works for ::Compute !

Is there a way to do this per render call?

Buffers are added to the "same group" and some are constantly transformed like

aCtx->ModelWorldState.ChangeCurrent() = glOw;
aCtx->ApplyModelViewMatrix();