EtienneCmb / visbrain

A multi-purpose GPU-accelerated open-source suite for brain data visualization
http://visbrain.org
Other
241 stars 65 forks source link

Surface+ arrows: how to avoid transparency of the surface ? #84

Open JulienLefevreMars opened 3 years ago

JulienLefevreMars commented 3 years ago

Hi again :-)

So, I have succeeded in displaying surfaces and vectors, thank you again Etienne. Now I have a little issue regarding the way the surface and the vectors are superimposed. It turns out that all the arrows are displayed, even those that are supposed to be masked (on the picture, points that are on the mesial face of the brain).

Picture

Here is how I create and add the objects: The scene: visb_sc = SceneObj(bgcolor='white', size=(1000, 1000)) the surface (which is opaque) b_obj = BrainObj('Mesh', vertices=np.array(mesh.vertices), faces=np.array(mesh.faces), translucent=False) the vectors v_obj = VectorObj('VectorField', arrows, color='black',arrow_norm=(1.,1.),line_width=1.,arrow_size=3.) and the sequence to add the objects (I skip the texture part at the end, it did not change anything) visb_sc.add_to_subplot(b_obj, row=0, col=0) visb_sc.add_to_subplot(v_obj)

I have tried to reverse the order of add_subplot, but I obtain a completely black picture. Is it a low-level (GL ?) behavior or did I miss something in the parameters of the functions (and sorry in advance if there's a trivial answer !) ?

JulienLefevreMars commented 3 years ago

PS: I can see a first solution, only if the camera axis is fixed, by using the option select in VectorObj and removing vertices that are not directly visible from the viewpoint...

EtienneCmb commented 3 years ago

Yes, this is a known issue of vispy. It's called "tri sorting" where the triangles are z-sorted according to rotations. Unfortunately it's not supported by vispy. The best workaround could be to add multiple subplots where you mask the vectors that should be hidden. Other than that I don't have a solution

JulienLefevreMars commented 3 years ago

Thanks Etienne. I will do something like this. In a first attempt, the vectors to be hidden can be detected based on the angle (>pi/2) between the normal at the point and the vector between the point and the camera. Are you interested by this functionality ?

EtienneCmb commented 3 years ago

Yes it could be interesting to have this feature, maybe something like a drop_hidden in the inputs of the VectorObj

JulienLefevreMars commented 3 years ago

I have started to look at SceneObj class, in particular through this example to set a camera orientation http://visbrain.org/auto_examples/objects/plot_combine_objects.html#sphx-glr-auto-examples-objects-plot-combine-objects-py

but unfortunately, it does not change the viewpoint. I have tried several different azimuth/elevation values in CAM_STATE. Is there another mechanism to modify the position/orientation of the camera/viewpoint ?

(It is important also to note that the property _camera_state is empty... ).

EtienneCmb commented 3 years ago

Hi Julien,

Did you tried to set the input parameter camera_state parameter of the method add_to_subplot and not the one when you define the scene?

Normally it should work, but if it doesn't, you should have access in the class to the camera object (turntable camera for 3d objects)

JulienLefevreMars commented 3 years ago

Hi Etienne,

Thanks a lot ! The first solution works perfectly. Now I am able to obtain the camera position and to find a good criterion for visible/hidden faces. The first attempt by using dot product(normals, point-camera) >0 is not perfect. I think there are better geometric options (number of times a ray starting from the camera cross the object) but the computational cost could increase. And of course it would be a problem if one wants to add a dynamical update of the hidden points when one rotates the object by hand... I let you know maybe on a mattermost channel ?

Good weekend Julien

JulienLefevreMars commented 3 years ago

So, It has been a bit long but I am now able to obtain exactly the location of the camera (which is not camera.center as I thought in the first attempt) by using sort of classical trigonometric formulas (except the -90 shift for azimuth)

az = (camera.azimuth-90) * np.pi / 180 el = camera.elevation * np.pi / 180 d = camera.distance position = np.array([d* np.cos(el)*np.cos(az), d*np.cos(el)*np.sin(az), d*np.sin(el)])

Based on that it is possible to hide points. The first version with criterion on normals works well for convex surfaces, a bit less for brains. See figures

My code is not adapted for a pull request because it uses also slam and a vector_field class. But I can work on it.

The two next steps are a bit challenging: