MRG: Brain silhouette#8771
Conversation
|
Result looks good with SSAO on
Code snippet def _enable_ssao(self, dataset):
bounds = np.asarray(dataset.GetBounds())
basic_pass = vtk.vtkRenderStepsPass()
scene_size = np.linalg.norm(bounds[:3] - bounds[3:])
ssao = vtk.vtkSSAOPass()
ssao.SetRadius(0.1 * scene_size) # comparison radius
ssao.SetBias(0.001 * scene_size) # comparison bias
ssao.SetKernelSize(128) # number of samples used
ssao.BlurOff() # do not blur occlusion
ssao.SetDelegatePass(basic_pass)
self.plotter.renderer.SetPass(ssao)But I ran into visual artifacts on Reference: https://blog.kitware.com/ssao/ |
|
Is it the combination of depth peeling + SSAO? |
I think there is a depth peeling step in |
|
So maybe you need to disable |
|
(i.e., don't call |
|
Depth peeling is disabled by default in the |
|
Avoiding |
|
After f722e74 :
|
|
Wow, that looks great! It makes all the renderings look much better in a realistic sense. In some cases it makes them less usable, such as the volumetric case -- but I think this is mostly because the brain opacity is too high in that case. Can you see what something like this example looks like? On And locally on your PR I see: |
|
Oh yeah I reproduce this on multi-renderers as well. It's trivial to solve the silhouette but SSAO gives this weird empty plot 🤔 |
|
I have the same behaviour with the standard MWEimport numpy as np
import vtk
import pyvista as pv
def _enable_ssao(plotter, dataset=None, idx=None):
lightsP = vtk.vtkLightsPass()
opaqueP = vtk.vtkOpaquePass()
translucentP = vtk.vtkTranslucentPass()
volumeP = vtk.vtkVolumetricPass()
collection = vtk.vtkRenderPassCollection()
collection.AddItem(lightsP)
# opaque passes
ssaoCamP = vtk.vtkCameraPass()
ssaoCamP.SetDelegatePass(opaqueP)
if dataset is None:
ssaoP = vtk.vtkSSAOPass()
ssaoP.SetRadius(30)
ssaoP.SetBias(0.1)
ssaoP.SetKernelSize(32)
ssaoP.SetBlur(True)
else:
bounds = np.asarray(dataset.GetBounds())
scene_size = np.linalg.norm(bounds[:3] - bounds[3:])
ssaoP = vtk.vtkSSAOPass()
ssaoP.SetRadius(0.1 * scene_size) # comparison radius
ssaoP.SetBias(0.001 * scene_size) # comparison bias
ssaoP.SetKernelSize(128) # number of samples used
ssaoP.BlurOff() # do not blur occlusion
ssaoP.SetDelegatePass(ssaoCamP)
collection.AddItem(ssaoP)
# translucent and volumic passes
ddpP = vtk.vtkDualDepthPeelingPass()
ddpP.SetTranslucentPass(translucentP)
ddpP.SetVolumetricPass(volumeP)
collection.AddItem(ddpP)
# finally overlays
overP = vtk.vtkOverlayPass()
collection.AddItem(overP)
sequence = vtk.vtkSequencePass()
sequence.SetPasses(collection)
camP = vtk.vtkCameraPass()
camP.SetDelegatePass(sequence)
if idx is None:
plotter.renderer.SetPass(camP)
else:
plotter.renderers[idx].SetPass(camP)
p = pv.Plotter(shape=(2, 1))
p.subplot(0, 0)
p.add_mesh(pv.Sphere())
_enable_ssao(p)
p.subplot(1, 0)
p.add_mesh(pv.Cone())
_enable_ssao(p)
p.show() |
|
I confirm that better isolation fixes this. I built a custom Qt Plotter that contains separated instances of Code snippetimport numpy as np
import vtk
import pyvista as pv
import pyvistaqt as pvqt
def _enable_ssao(plotter, dataset=None, idx=None):
lightsP = vtk.vtkLightsPass()
opaqueP = vtk.vtkOpaquePass()
translucentP = vtk.vtkTranslucentPass()
volumeP = vtk.vtkVolumetricPass()
collection = vtk.vtkRenderPassCollection()
collection.AddItem(lightsP)
# opaque passes
ssaoCamP = vtk.vtkCameraPass()
ssaoCamP.SetDelegatePass(opaqueP)
if dataset is None:
ssaoP = vtk.vtkSSAOPass()
ssaoP.SetRadius(30)
ssaoP.SetBias(0.1)
ssaoP.SetKernelSize(32)
ssaoP.SetBlur(True)
else:
bounds = np.asarray(dataset.GetBounds())
scene_size = np.linalg.norm(bounds[:3] - bounds[3:])
ssaoP = vtk.vtkSSAOPass()
ssaoP.SetRadius(0.1 * scene_size) # comparison radius
ssaoP.SetBias(0.001 * scene_size) # comparison bias
ssaoP.SetKernelSize(128) # number of samples used
ssaoP.BlurOff() # do not blur occlusion
ssaoP.SetDelegatePass(ssaoCamP)
collection.AddItem(ssaoP)
# translucent and volumic passes
ddpP = vtk.vtkDualDepthPeelingPass()
ddpP.SetTranslucentPass(translucentP)
ddpP.SetVolumetricPass(volumeP)
collection.AddItem(ddpP)
# finally overlays
overP = vtk.vtkOverlayPass()
collection.AddItem(overP)
sequence = vtk.vtkSequencePass()
sequence.SetPasses(collection)
camP = vtk.vtkCameraPass()
camP.SetDelegatePass(sequence)
if idx is None:
plotter.renderer.SetPass(camP)
else:
plotter.renderers[idx].SetPass(camP)
p = pvqt.Plotter(shape=(2, 2))
p.interactors[0].add_mesh(pv.Sphere())
_enable_ssao(p.interactors[0])
p.interactors[1].add_mesh(pv.Cone())
_enable_ssao(p.interactors[1])
p.interactors[2].add_mesh(pv.Box())
_enable_ssao(p.interactors[2])
p.interactors[3].add_mesh(pv.Cylinder())
_enable_ssao(p.interactors[3])
p.show() |
|
I think this can move forward without SSAO. It makes it less impactful/realistic though. SSAO will need |
|
Agreed, let's move forward with Can you modify |
mne/utils/docs.py
Outdated
| """ | ||
| docdict['brain_kwargs'] = """ | ||
| brain_kwargs : dict | None | ||
| Additional arguments to brain.__init__ (e.g., |
There was a problem hiding this comment.
| Additional arguments to brain.__init__ (e.g., | |
| Additional arguments to the :class:`mne.viz.Brain` constructor (e.g., |
|
And don't forget |
















This PR follows #8749 (comment) and adds a
silhouetteparameter toBrain.__init__().What would be even more helpful for this kind of mesh is ambient occlusion.