Changes in visualization in OCCT 6.8.0 - Migration hints

Hello,

In my OCCT-based projects I have some functionalities using classes Visual3d_ViewMapping and Visual3d_ViewOrientation that were removed in the current development version. I wasn't able to find a straightforward replacement for the aforementioned classes.

Is there any migration guide planned covering this topic?

Thanks
Pawel

Sergey Anikin's picture

Dear Pawel,

Certainly, we are going to describe some migration steps in the Release Notes of the next OCCT release. Also we plan to publish a technical article describing the new approach to 3D view manipulation involving the camera here on the forum.

It is great that you are starting to experiment with the new API already!
We will try to consider your remarks and questions in the published materials.

Our own experience shows that porting an application that relies on high-level API (V3d package) should not be complicated.
SALOME platform is an example, it has been migrated smoothly to the new API.

And in case if an application performed some low-level view manipulations using Visual3d_ViewMapping and Visual3d_ViewOrientation classes, the application developer should clearly understand the goals of such manipulations - and then try to match them against Graphic3d_Camera API.

Can you post the list of advanced view manipulation tasks, for which you needed Visual3d API?

Pawel's picture

Dear Sergey,

yes, I try to be up to date on the current development state and compile OCCT more or less regularly ;)

Let me describe my use cases:

1. Center the view on a selected feature. For this purpose the method:

V3d_View::Center(X, Y)

is used, which has been deleted recently.

2. Rendering objects using Aspect_GraphicCallbackProc / OpenGL directly. Our application renders some tolerance frames along with texts. Direct OpenGL rendering was the only possibility we found at that time that allowed us to
(a) zoom texts and manage them (almost) as AIS_InteractiveObjects
(b) render texts as overlays

In our current implementation we use the following code to obtain the view parameters of the OCCT viewer and use them when rendering the OpenGL scene:

myView->Size(viewWidth, viewHeight);
ZSize = myView->ZSize();
Depth = myView->Depth();

Visual3d_ViewMapping viewMapping = myView->ViewMapping();
Graphic3d_Vertex projectionReferencePoint = viewMapping.ProjectionReferencePoint();

Left = - viewWidth/2.0 + projectionReferencePoint.X();
Right = viewWidth/2.0 + projectionReferencePoint.X();
Top = viewHeight/2.0 + projectionReferencePoint.Y();
Bottom = -viewHeight/2.0 + projectionReferencePoint.Y();

Visual3d_ViewOrientation viewOrientation = myView->ViewOrientation();
viewReferencePoint = viewOrientation.ViewReferencePoint();

Graphic3d_Vector up = viewOrientation.ViewReferenceUp();
Graphic3d_Vector normal = viewOrientation.ViewReferencePlane();

And for that we used Visual3d_ViewMapping and Visual3d_ViewOrientation classes.

From my point of view, it would be good to have those information back again for compatibility purposes (although I suspect we would have to review our implementation anyway in the future).

Pawel

Sergey Anikin's picture

Dear Pawel,

Thanks a lot for the use cases!
Now let's try to map them onto the new API.
Probably, Visualization - get rid of projection shift from orthographic camera definition might put some light on this topic in general.

1. V3d_View::SetCenter(Xpix, Ypix) method seems to do what you need - i.e. you can call it as soon as non-empty selection is returned and thus center the view at the current mouse position.
Or you can go a bit farther and compute the COG of the selected object, project the COG point onto the screen and finally call SetCenter().

2. Concerning view parameters, it makes sense to have a look at the following methods as an alternative to the obsolete Visual3d services:

  • Graphic3d_Camera::ViewDimensions() or V3d_View::Size()/ZSize() - returns view width, height and depth (or "Z size"). Since the view is symmetric now, you can easily compute top, bottom, left and right limits. Graphic3d_Camera::ZNear()/ZFar() can be used to obtain the near and far clipping distances with respect to the eye.
  • Graphic3d_Camera::Up() or V3d_View::Up() - returns Y direction of the view
  • Graphic3d_Camera::Direction() returns the reverse view normal directed from the eye, V3d_View::Proj() returns the old-style view normal.
  • Graphic3d_Camera::Eye() or V3d_View::Eye() - returns the camera position (same as projection reference point in old implementation)
  • Graphic3d_Camera::Center() or V3d_View::At() - returns the point the camera looks at (or view reference point according to old terminology)

All points and directions are in world coordinates.

It would be great if you tried to migrate your code using the information above and post the results here.
Thanks in advance!

best regards,
Sergey

Pawel's picture

Dear Sergey,

thanks for your comments and hints!

After my vacation I was able to migrate our code using your instructions.

Resolving issue (1) was quite straightforward and I was able to compile the code. The only problem that still remains at the moment is the fact that the projection shift was removed (I guess). The thing is we have some files where the view position was stored and when providing this position to the new methods the resulting transformation seems to be wrong. I'll still have to look into this.

To resolve the second issue I used the following code:

gp_XYZ xyz = myView->Camera()->ViewDimensions();

V3d_Coordinate x, y, z;
myView->At(x, y, z);
V3d_Coordinate X, Y;
myView->Project(x, y, z, X, Y);
Left = X - xyz.X() / 2.0;
Right = X + xyz.X() / 2.0;
Bottom = Y - xyz.Y() / 2.0;
Top = Y + xyz.Y() / 2.0;

viewReferencePoint.SetCoord(x, y, z);

vUp = myView->Camera()->Up();
vNormal = myView->Camera()->Direction().Reversed();

And it seems to be working.

Pawel

Sergey Anikin's picture

Dear Pawel,

As usual, you contribution is really valuable!
Thank you a lot for feedback!
You are right regarding the projection shift, the issue with stored view parameters was not that obvious...Well, I hope this issue does not cause too much pain for you, meanwhile the camera operation is more straightforward without the shift - and more consistent between orthographic and perspective modes.
Can you publish the piece of code that is responsible for restoring the view orientation from a file? I wonder if we can try to emulate the projection shift using the camera API.

Best regards,
Sergey

Pawel's picture

Dear Sergey,

thank you for looking into the issue!

Below is the code snippet that restores the view transformation in our software (OCCT 6.7.0 and below)

V3d_TypeOfUpdate mode = GetDocument()->GetViewer()->UpdateMode();
GetDocument()->GetViewer()->SetUpdateMode(V3d_WAIT);
GetDocument()->GetViewer()->SetViewOff(myView);

myView->SetAt(myAtX,myAtY,myAtZ);
myView->SetEye(myEyeX,myEyeY,myEyeZ);
myView->SetProj(myVx,myVy,myVz);
myView->SetTwist(myTwist);
myView->SetScale(myScale);
myView->SetCenter(myXc,myYc);
myView->SetDepth(myDepth);
myView->SetZSize(myZSize);

GetDocument()->GetViewer()->SetViewOn(myView);
GetDocument()->GetViewer()->Update();
GetDocument()->GetViewer()->SetUpdateMode(mode);

Hope this helps.

Pawel

Sergey Anikin's picture

Dear Pawel,

As far as we understand, you need to treat somehow the non-zero myXc and myYc values stored in the existing data files created with OCCT 6.7.0 or older.

The idea is to convert the projection shift to the world coordinates and translate the camera accordingly. Naturally, this is needed for old data files only.

Can you please try the following solution and let me know the result:

// translation in clip space (projected space)
NCollection_Vec4<float> aProjectionShift =
  NCollection_Vec4<float> (myXc, myYc, 0.0f, 0.0f);

Graphic3d_Mat4 aViewProjectionMatrix =
  myView->Camera()->ProjectionMatrixF() * 
  myView->Camera()->OrientationMatrixF();

// convert to world space
Graphic3d_Mat4 aInverseViewProjMatrix;
aViewProjectionMatrix.Inverted(aInverseViewProjMatrix);
NCollection_Vec4<float> aTranslation =
  aInverseViewProjMatrix * aProjectionShift; 

// apply translation to the camera
myView->Camera()->SetEye(myView->Camera()->Eye() + aTranslation);
myView->Camera()->SetCenter(myView->Camera()->Center() + aTranslation);
Pawel's picture

Dear Sergey,

I tested your code and unfortunately I was not successful.

With the input:

myXc -484.19475112250802
myYc -853.38759343972697

the obtained translation value is:

aTranslation {v=0x00000000008251d8 {-317574.969, 93582.5313, -268645.031, 0.000000000} }

and the rendered scene vanishes...

Below the exact code I used:

myView->SetAt(myAtX,myAtY,myAtZ);
//myView->SetEye(myEyeX,myEyeY,myEyeZ);
myView->SetProj(myVx,myVy,myVz);
myView->SetTwist(myTwist);
myView->SetScale(myScale);
//myView->SetCenter(myXc,myYc);
myView->SetDepth(myDepth);
myView->SetZSize(myZSize);

//==================
// translation in clip space (projected space)
NCollection_Vec4 aProjectionShift = NCollection_Vec4 (myXc, myYc, 0.0f, 0.0f);

Graphic3d_Mat4 aViewProjectionMatrix = myView->Camera()->ProjectionMatrixF() * myView->Camera()->OrientationMatrixF();

// convert to world space
Graphic3d_Mat4 aInverseViewProjMatrix;
aViewProjectionMatrix.Inverted(aInverseViewProjMatrix);
NCollection_Vec4 aTranslation = aInverseViewProjMatrix * aProjectionShift;

// apply translation to the camera
myView->Camera()->SetEye(myView->Camera()->Eye().Translated(gp_Vec(aTranslation.x(), aTranslation.y(), aTranslation.z())));
myView->Camera()->SetCenter(myView->Camera()->Center().Translated(gp_Vec(aTranslation.x(), aTranslation.y(), aTranslation.z())));
//==================

Best regards
Pawel

Sergey Anikin's picture

Dear Pawel,

Can you please try the following line:

myView->Panning(-myXc, -myYc); 

We did this kind of trick while porting old test cases to the camera, but using more complicated code - now it looks that Panning() should do the same.

Best regards,
Sergey

Pawel's picture

Wow!

The simplest solutions prove to be very often the best ;)

Don't forget to mention this solution in the release notes ;)

Thank you!

Andrey BETENEV's picture

Hello,

This is just to clarify that the changes discussed in this thread will not be included in OCCT 6.7.1, but will go to 6.8.0.
I will update topic title accordingly.

Andrey