Displaying 2D graphics over 3D

I need to display 2D graphics over my 3D view. The 2D graphics would remain fixed as the 3D view transforms (pans, zooms, rotates, etc.). I believe the right way to approach this is by adding an overlay layer with Visual3d_Layer, but I am not having any luck getting things to display on that layer. In the following code, m_hView is a handle to a V3d_View. Any help would be greatly appreciated.

Standard_Integer w(0), h(0);
Handle(Aspect_Window) hWin = m_hView->Window();
hWin->Size(w,h);

m_hLayer = new Visual3d_Layer(m_hView->View()->ViewManager(), Aspect_TOL_OVERLAY, Standard_False);
m_hLayer->Clear();
m_hLayer->SetViewport(w,h);
m_hLayer->Begin();
m_hLayer->SetColor(Quantity_Color(Quantity_NOC_WHITE));
m_hLayer->SetLineAttributes(Aspect_TOL_SOLID, 2.0);
m_hLayer->BeginPolyline();
m_hLayer->AddVertex(w*0.2, h*0.2, Standard_False);
m_hLayer->AddVertex(w*0.8, h*0.2);
m_hLayer->AddVertex(w*0.8, h*0.8);
m_hLayer->AddVertex(w*0.2, h*0.8);
m_hLayer->AddVertex(w*0.2, h*0.2);
m_hLayer->ClosePrimitive();
m_hLayer->End();
m_hView->Redraw();

Rob Bachrach's picture

Ok, I think I've figured out the coordinate system for the layer. Please correct me if I am wrong:

The x-axis is normalized from -1 to 1. The y-axis is normalized from -1 to y, where y is equal to the height of the view minus 1. The height of the view is equal to ((2.0/pixel_width)*pixel_height). So my code becomes the following to draw a rectangle a constant distance (.1) from the edge of the window:

Standard_Real wn = 2.0, hn = (2.0/Standard_Real(w))*Standard_Real(h);
Standard_Real x1 = -0.9, x2= x1+wn-.2, y1 = -0.9, y2=y1+hn-.2;
m_hLayer->BeginPolyline();
m_hLayer->AddVertex(x1, y1, Standard_False);
m_hLayer->AddVertex(x1, y2);
m_hLayer->AddVertex(x2, y2);
m_hLayer->AddVertex(x2, y1);
m_hLayer->AddVertex(x1, y1);
m_hLayer->ClosePrimitive();

Stephane Routelous's picture

wouah ! that's wierd !

Paul Jimenez's picture

You're right with your findings to some extent. It's right to say that the x-axis goes from -1 to 1 only when the width of the view is bigger than its height, and when using the default values. Calling SetOrtho allows you to change this range.

What you must really do is to take the longest side (w or h). That's the one in the range (-1 to 1 by default). The other side is clipped, so you must calculate the starting/ending point of it in the range using the length of the longest side.

I prefer to use a range from 0 to 10 for both axes, so the code becomes like this:

Standard_Integer w, h;
Handle(Aspect_Window) hWin = m_view->Window();
hWin->Size(w, h);

if (w < h)
{
m_right = h ? 10. * w / h : 10.;
m_bottom = 0.;
}
else
{
m_right = 10.;
m_bottom = w ? 10. * (1. - static_cast(h) / w) : 0.;
}

m_layer->SetViewport(w ? w : 1, h ? h : 1);
m_layer->SetOrtho(0., 10., 0., 10., Aspect_TOC_TOP_LEFT);

I'm using operator ?: to avoid division by 0 and also avoid setting the ViewPort with a 0 value.

Default values for attributes are:

m_left = 0
m_right = 10
m_top = 10
m_bottom = 0

You can easily adjust it to use another range if you want.

I hope that helps to understand layers a bit better.

Paul Jimenez's picture

Actually, take a look at opengl_togl_begin_layer_mode.c, starting at line 258 (OCC 6.3.0). There you'll find how left, right, bottom and top are calculated for all cases.

Wang Chris's picture

Hi, Paul Jimenez

Can the graphics on the layer dynamically change with the window as 3D graphics on 3d view? I tried to find the way, but still not.

Thank you very much!

Wang Chris's picture

There are other two questions:

1)How to hide the 3d graphics on 3d view when draw the 2d graphics on the layer?

2)How to hide teh 2d graphics on the layer when back to 3D view?

Thanks a lot!

Paul Jimenez's picture

> Can the graphics on the layer dynamically change with the window as 3D graphics on 3d view? I tried to find the way, but still not.

For that purpose I keep a handle to the layer somewhere I can easily get it and modify it. When the view is rotated, panned, fitted or zoomed I update the layer. Your conditions to update the layer may be different. I'm using the layer to display where is North with a 3D arrow (tricky implementation that converts from the 3D view to the layer a set of 3D points) and, if origin is out of view, a 2D arrow with a different color pointing to it. To make the whole process easier, I created a new class that encapsulates the Layer to which I add special drawers (the 3D and 2D arrow drawers). When I need to update the layer, I just tell the instance of that class to update itself, so it clears the layer and calls every drawer in it.

> 1)How to hide the 3d graphics on 3d view when draw the 2d graphics on the layer?

Wouldn't opening a new local context without anything inside and hiding the grid work for you?

2)How to hide teh 2d graphics on the layer when back to 3D view?

Just clear the layer. The layer will be drawn, but, since it's empty, you won't see it.

Jun WANG's picture

How to display text on that way?????????

Paul Jimenez's picture

Just for reference, this question "continues" here: http://www.opencascade.org/org/forum/thread_15849/