Closed grotius-cnc closed 1 year ago
Thanks for sharing.
Fill free to create a Pull Request to be able to integrate fixes (if they don't cause other problems).
Hi,
Ok i will work it out. Are you ok with a second directory containing a qt gui app with graphical designer layout based on your code? That is a usefull setup when building more complex programs. Then users can choose either your parametric coded example or choose a grapical design example.
I have a tiny request for you. I know you are master kenobi of opencascade. I am a kind of stuck on this problem.
In a cnc program i have 1.200.000+ gcode lines of a pruca slicer nc code. Up to 60.000 gcode lines can be processed by opencascade->make wire etc. No problem.
But loading 1.200.000+ edges -> to wire looks like a impossible task for opencascade. 10 minutes +.
Can you give a few one liners to directly call opengl functions.
I would be happy if something like this is working in your example gui: if(aGlCtx->core11 != NULL){ aGlCtx->core20->glCreateProgram(); aGlCtx.get()->core20->glColor3d(1,1,1); aGlCtx.get()->core20->glBegin(GL_LINE); aGlCtx.get()->core20->glVertex3d(0,0,0); aGlCtx.get()->core20->glVertex3d(1000,1000,1000); aGlCtx.get()->core20->glVertex3d(-1000,-1000,-1000); aGlCtx.get()->core20->glEnd(); }
Earlyer this day i posted the same question over here : https://github.com/tpaviot/oce/issues/746
Are you ok with a second directory containing a qt gui app with graphical designer layout based on your code?
Let me first describe my thoughts behind the current sample. I see two common types of samples:
You may find tutorial-alike samples based on MFC and Qt Widgets frameworks within OCCT. Such samples have many benefits, as they demonstrate many features in a single place, avoid code duplication, and their content allows adding new similar features to application even for users not knowing (well) particular GUI framework by a copy-paste of similar button / menu / dialog. The key drawback of such samples is they are large in code size, tangled in structure (additional hierarchy of classes, shared functionality, multi-project building environment), over-complication (like implementing Multi-Document Interface, or MDI, when your application works only with single document), features are difficult to extract without copying a plenty of dependencies, and others.
In contrast, Hello-World sample (I don't know if there is a better term for that, like "unit-sample") is focused on a single task and should be clean from the burden of unrelated stuff as much as possible. Both sample styles (tutorial and hello) might be helpful to learn new framework and to develop application, so that one may complement another.
As you may see, this repository implements a Hello-World sample, so that I've intentionally tried to simplify project structure (minimal number of source files, no external dependencies) and reduce amounts of unrelated functionality (like importing STEP files or modeling complex geometry) - as sample purpose is to show 3D Viewer initialization using Qt OpenGL widget.
In this concept, I find UI files redundant and over-complicating, as this is only one of the way to use Qt Widgets. But I must admit. that potential user might look at the sample and say - "OK, I see 3D Viewer, but how to put it into UI file that our Qt GUI experts relies on?". So such a sample would be indeed helpful.
I don't like an idea of replacing existing sample with another one using UI files, and have doubts that putting ifdef-blocks for sharing common code wouldn't spoil sample clarity. So I like an idea of putting several samples into dedicated sub-folders with self-sustained list of files - even if this obviously leads to code duplication. So that we would have one sample using QOpenGLWidget in a plain C++ (occt-qopenglwidget
), another using UI files (occt-qopenglwidget-ui
), and maybe one more sample will implement a conventional viewer integration into a general QWidget.
But loading 1.200.000+ edges -> to wire looks like a impossible task for opencascade. 10 minutes +.
If you have a plenty of line segments or polylines to display, then you are probably doing it in a non-efficient way. You are probably constructing Geom_Curve
+ TopoDS_Edge
out of line segments and display them using presentations like AIS_Shape
, but that would bring a lot of overhead on memory and performance.
Instead, TopoDS_Edge
could be created out of Poly_Polygon3D
- a tessellated representation of a curve without analytical Geom_Curve
. You wouldn't be able to use such geometry in modeling algorithms, but it should work for visualization purposes. Or you may sub-class AIS_InteractiveObject
and construct / display Graphic3d_ArrayOfSegments
directly without additional overhead of dealing with B-Rep definition.
Graphic3d_ArrayOfPrimitives
is pretty close to interfaces of low-level graphic libraries - it is mapped into VBO (Vertex Buffer Object) in case of OpenGL, and not much you can do here to improve performance further by using OpenGL directly if you have to display all these segments. The main thing to avoid is creation of many presentations (AIS_InteractiveObject
) or many distinct arrays of primitives - better combining them into larger array(s). Using obsolete OpenGL functionality like immediate rendering (glBegin()
/glVertex3d()
/glEnd()
) would certainly kill performance instead of improving it.
Hi,
Thanks for your fast responce and idea's. I will try out your suggestions about improving. I hope i can bring good news later on this day.
Your "hello world" example is a precious code because of the working qwidget overlay. Also the refined mouse zoom in, zoom out is nice.
I will work out a example, coded as a widget. This is in my opinion the preferred way newbies need to go for.
The progress so far. The overlay works nice.
Hi,
I think i am ready with the example. I see you are from Russia. Perfect !! I like that country. One of my cnc tube cutter's lives there.
https://github.com/grotius-cnc/occt-samples-qopenglwidget/blob/master/occ_gui_app/
Hi,
I tested loading 1.2 milion lines followed by your Poly_Polygon3D
suggestion and it worked.
It load the preview in about 1 minute.
//! Basic impementation example:
TopoDS_Shape ResultShape;
TColgp_Array1OfPnt array (1,5); // sizing array
array.SetValue(1,gp_Pnt(100,0,0));
array.SetValue(2,gp_Pnt(1000,0,0));
array.SetValue(3,gp_Pnt(1000,500,0));
array.SetValue(4,gp_Pnt(100,500,0));
array.SetValue(5,gp_Pnt(100,0,0));
Handle(Poly_Polygon3D) aPolygon = new Poly_Polygon3D(array);
BRep_Builder Brep;
TopoDS_Edge& E = TopoDS::Edge(ResultShape);
Brep.MakeEdge(E,aPolygon);
Handle(AIS_Shape) Ashape=new AIS_Shape(ResultShape);
m_context->Display(Ashape,Standard_False);
After the shape preview, i tried to free as much as possible memory, and it worked.
array.IsDeletable();
aPolygon->Delete();
aPolygon.Nullify();
E.Nullify();
The program was running ok, i let it run for about 25 minutes. The opencascade responce stayed perfect.
NEXT EXAMPLE
One thing i am still interested in the Handle(Graphic3d_ArrayOfPoints)
example you give me,
but i have problems finishing the code. After a while i could let it work.
In this page there is a nice example
https://dev.opencascade.org/doc/overview/html/occt_user_guides__visualization.html
Ok for me i have some standard thing in the header file.
things inside the opencascade header file:
private:
void m_initialize_context();
Handle(AIS_InteractiveContext) m_context;
Handle(V3d_Viewer) m_viewer;
Handle(V3d_View) m_view;
Handle(Graphic3d_GraphicDriver) m_graphic_driver;
Handle(AIS_InteractiveObject) m_aisViewCube;
//! Then in the cpp file i did :
#include <Graphic3d_ArrayOfPrimitives.hxx>
#include <Graphic3d_ArrayOfSegments.hxx>
#include <Graphic3d_ArrayOfPoints.hxx>
#include <AIS_PointCloud.hxx>
#include <Graphic3d_NameOfMaterial.hxx>
//! Create a structure in this Viewer.
Handle(Graphic3d_Structure) aStruct = new Graphic3d_Structure (m_viewer->StructureManager());
aStruct->SetVisual (Graphic3d_TOS_SHADING); // Type of structure
//! Create a group of primitives in this structure.
Handle(Graphic3d_Group) aPrsGroup = aStruct->NewGroup();
//! Ammount of points.
int size=;1200000;
Handle(Graphic3d_ArrayOfPoints) aPointArray=new Graphic3d_ArrayOfPoints(size,Graphic3d_ArrayFlags_None);
//! Fill the point array with points.
for(unsigned int i=0; i<size; i++){
//! Add the x,y,z points.
aPointArray->AddVertex({x,y,z});
}
//! Check if point array result is ok.
std::cout<<"shapearray.isvalid:"<<aPointArray->IsValid()<<std::endl;
//! This is optional.
Handle(Graphic3d_AspectFillArea3d) anAspects = new Graphic3d_AspectFillArea3d (Aspect_IS_SOLID,
Quantity_NOC_RED,
Quantity_NOC_RED, Aspect_TOL_SOLID, 1.0f,
Graphic3d_NOM_ALUMINIUM,Graphic3d_NOM_ALUMINIUM);
aPrsGroup->SetGroupPrimitivesAspect (anAspects);
//! Add the pointarray o the group.
aPrsGroup->AddPrimitiveArray (aPointArray);
// Display presentation in this View
aStruct->Display();
//! This is all done without any line like m_context->Display(Ashape,Standard_False);
This is all done without any line like m_context->Display(Ashape,Standard_False);
V3d_View
provides a low-level interface for displaying presentations - so that you may create Graphic3d_Structure
and display it straight ahead. AIS_InteractiveContext
fulfills other parts like picking, selection, interaction with the objects. And even if object is not intended to be interactive, it still looks useful to place all objects together in context.
Hi,
Thanks. I think the struct is nice to implement. If you have a vector struct, it can manage data on the fly. One of my software users, has a problem loading a stepfile of ~100mb. I think above code example's can solve part's of this problem.
I'm still interested how a eventual opengl api
call should look like from the occt lib
.
Just to expand my knowlegde.
Maybe you can give just one tiny howto example? Only when you have time off course.
Currently coding a third'h occt widget
example. The yesterday example was with a mainwindow app.
Now coding it just as a widget. I have made in total 3 classes to get the widget functional and separate the
opengl stuff with the help off independent classes. Somewhere i saw a comment of you, suggesting to separate opengl
includes from qt and occt. And indeed, this is the only solution to get it work.
In this example i am planning to include a sub-directory with some of my occt draw functions.
Have a good night ! And thanks for the help so far master kenobi
!
I'm still interested how a eventual opengl api call should look like from the occt lib.
The sample comes with OCCT - see VUserDrawObj::Render()
for VUserDrawObj
sample class within OpenGlTest_Commands.cxx
Hi, Sorry to bother you again.
The following code loads a preview with a black background. But no items are showing up. Did you ever get something like this working? I have tried it for several hours, but it seems very difficult.
`
Handle(Aspect_DisplayConnection) a_display_donnection = new Aspect_DisplayConnection();
Handle(OpenGl_GraphicDriver) myglGraphicDriver = new OpenGl_GraphicDriver(a_display_donnection);
WId window_handle = (WId) winId();
Handle(Xw_Window) a_wind = new Xw_Window(a_display_donnection, (Window) window_handle);
Handle(OpenGl_Window) myglWindow = myglGraphicDriver->CreateRenderWindow(a_wind , (Aspect_RenderingContext)0);
Handle(OpenGl_Caps) myglCaps = &myglGraphicDriver->ChangeOptions();
Handle(Graphic3d_StructureManager) myG3dStructureCanager = new Graphic3d_StructureManager(myglGraphicDriver);
OpenGl_StateCounter* myglStateCounter = new OpenGl_StateCounter();
OpenGl_View *myglView = new OpenGl_View(myG3dStructureCanager, myglGraphicDriver, myglCaps, myglStateCounter);
Handle(OpenGl_Workspace) myglWorkSpace = new OpenGl_Workspace(myglView, myglWindow);
Handle(OpenGl_Context) myglContext = myglWorkSpace->GetGlContext();
myglContext->ShaderManager()->BindLineProgram(Handle(OpenGl_TextureSet)(), Aspect_TOL_SOLID, Graphic3d_TOSM_UNLIT, Graphic3d_AlphaMode_Opaque, false, Handle(OpenGl_ShaderProgram)());
OpenGl_Vec4 col(2);
myglContext->SetColor4fv(col);
const OpenGl_Vec3 aVertArray[4] =
{
OpenGl_Vec3(-10.0,-20.0,-30.0),
OpenGl_Vec3(10.0, 20.0, -30.0),
OpenGl_Vec3(10.0, 20.0, 30.0),
OpenGl_Vec3(-10.0,-20.0,30.0),
};
Handle(OpenGl_VertexBuffer) aVertBuffer = new OpenGl_VertexBuffer();
aVertBuffer->Init(myglContext, 3, 4, aVertArray[0].GetData());
aVertBuffer->BindAttribute(myglContext, Graphic3d_TOA_POS);
glDrawArrays(GL_LINE_LOOP, 0, aVertBuffer->GetElemsNb());
aVertBuffer->UnbindAttribute(myglContext, Graphic3d_TOA_POS);
aVertBuffer->Release(myglContext.get());
`
Hi,
After some more day's of investegating i have finally found a solution to use the opengl api with opencascade and get a working display result.
I did not really need a direct opengl request. But i just wanted to know how to do this from inside the opencascade, in case of a future scenario.
I was lost for several day's trying out example after example, without any succes.
Then today i opened the file Occt.pro in qt. This is a qt project file inside the opencascace source code. ~ /oce-upstream-V7_5_0beta/adm/qmake/Occt.pro
It has some comments about how to build the opencascade project in qt. I followed that, and after a while it was building. I had to solve a stupid build error. And it worked out of the box.
Then i had to think about a strategy to get done what i wanted. I focussed on the myview and myviewer files. I was looking for how is OpenGl_View.cxx connected to myview and myviewer... It's quite confusing to work trough the code. But after a while i got a spot.
OpenGl_View_Redraw.cxx, in this file i pasted some OpenGl core code. My screen output was ok. I reqeusted 2 square's.
It drawed what i want. It worked at the renderStructs and the blitBuffers functions.
//! line 1248 OpenGL_View_Redraw_cxx renderStructs //! line 1509 ,, blitBuffers
So now this works, i can do some extra reverse engineering, clean it up, and make a permanent OpenGL core code user interface.
My conclusion. Don't give up the first day.
Then today i opened the file Occt.pro in qt.
I'm not a fan of Qt Creator and it's clumsy bindings to Qt Framework, but so far I haven't seen something more reliable for Linux platform, where I have to debug OCCT from time to time (previously I've used Code::Blocks for that purpose). And since I hate CMake even more than qmake
(that I have to use in some other cross-platform project), and bindings to CMake in Qt Creator are something weird - I've decided to write this funny Occt.pro
project for it that is able to parse FILES
/ PACKAGES
/ EXTERNLIB
and automatically generate projects. Initially I was hoped to make it completely self-sustained, but after some fighting with qmake
limitations, decided to keep using genproj
for generating header files in inc
folder and for configuring paths to dependencies.
I was looking for how is OpenGl_View.cxx connected to myview and myviewer...
There are several ways for combining OCCT 3D Viewer and other OpenGL renderer:
Graphic3d_ShaderProgram
assigned to standard primitive array attributes. It is not writing OpenGL code in C++ directly, but it might be enough for simple customization scenarios.OpenGl_Element
and adding them into OpenGl_Group
within AIS_InteractiveObject::Compute()
.
Called "UserDraw" in some references. This is the most natural approach, as it allows interleaving renderer and reuse OCCT mechanisms for selection and other purposes. OpenGlTest_Commands.cxx
has a sample class demonstrating this approach, and it is actually used in some libraries and projects (though most of them proprietary).OpenGl_View
(for that you need to subclass OpenGl_GraphicDriver
and OpenGl_GraphicDriver::CreateView()
).
In OpenGl_View
there are virtual methods like renderScene()
, renderStructs()
, render()
, redraw()
, redrawImmediate()
that could be used to embed custom renderer. You may take a look onto D3DHost_View
and D3DHost_GraphicDriver
demonstrating some basics of such subclassing (TKD3DHost
is relatively simple library as it doesn't do any actual rendering).In which method to put the code would depend on what your engine actually needs to draw. Modern 3D graphic renderers are complex beasts, so you cannot put an arbitrary immediate-render OpenGL code anywhere and expect it to work properly - you have to understand how existing 3D engine renders scene and embed your code into proper place initializing and leaving OpenGL context state in some valid state. Article TKOpenGl Frame Render Graph might be helpful to oversee basic steps in it.
You cannot find deeper samples of OpenGL user drawing in OCCT for a simple reason - it is an alien and a misconception for OCCT itself. It defines an Graphic3d_GraphicDriver
interface for a good reason - to provide an abstraction level between 3D graphics and it's rendering using low-level OpenGL library. OpenGL is a quite good cross-platform library combining feature-completeness and relative simplicity (compared to overcomplicated Vulkan) that doesn't yet have a better alternative (in all aspects), but in the future there are might be more Graphic3d_GraphicDriver
implementations based on Vulkan, WebGPU, Metal, Direct3D or whatever... And having a custom OpenGL rendering code at application side would prevent straightforward switching to another driver implementation.
Hi,
To build on linux i changed the source at a few points.
The archive of this repository to build on linux : occt-samples-qopenglwidget.tar.gz