Setting Backface Properties#

By default front and backface rendering uses the same properties. In certain situations it can be useful to set different properties for backfaces than for frontfaces.

One straightforward example is when a closed (or close enough) surface has a different color on the inside. Note that the notion of “inside” and “outside” depend on the orientation of the surface normals:

import numpy as np

import pyvista as pv
from pyvista import examples

mesh = pv.ParametricEllipsoid(min_v=np.pi / 2 - 0.2, max_v=np.pi / 2 + 0.2)

# create a shifted copy with flipped normals
mesh_inside_out = mesh.translate((0, 0, 1), inplace=False)
mesh_inside_out.compute_normals(flip_normals=True, inplace=True)
meshes = mesh + mesh_inside_out

backface_params = dict(color='orangered')
meshes.plot(color='aquamarine', backface_params=backface_params, smooth_shading=True)
backface props

A more interesting use case is helping visualize the orientation of complex, self-intersecting surfaces. For instance Catalan's minimal surface has a complex shape, and coloring the front and backfaces differently helps viewers comprehend the intricate structure of the surface. This example also demonstrates use of the backface_prop property of the pyvista.Actor class.

catalan = pv.ParametricCatalanMinimal()
plotter = pv.Plotter()
actor = plotter.add_mesh(catalan, color='dodgerblue', smooth_shading=True)
bprop = actor.backface_prop
bprop.color = 'forestgreen'
bprop.specular = 1.0
bprop.specular_power = 50.0
plotter.show()
backface props

In the case of non-orientable surfaces, adding specific backface properties can make the non-orientable quality very obvious by the emergence of “seams” where the face properties are discontinuous.

henneberg = pv.ParametricHenneberg().scale(0.25, inplace=False)
klein = pv.ParametricKlein().rotate_z(150, inplace=False).translate((6, 0, 0), inplace=False)
meshes = henneberg + klein

backface_params = dict(color='mediumseagreen', specular=1.0, specular_power=50.0)
meshes.plot(color='gold', backface_params=backface_params, smooth_shading=True)
backface props

Of course we aren’t constrained to only setting distinct colors for backfaces; most pyvista.Property attributes can be overridden. However, some of these have no effect, while others merely don’t make any sense. For instance, most objects have the same opacity no matter which direction you look at them. Here is a GIF animation circling around such an asymmetrically opaque Möbius strip:

mobius = pv.ParametricMobius().rotate_z(-90, inplace=False)
backface_params = dict(opacity=0.5)
plotter = pv.Plotter()
plotter.add_mesh(mobius, color='deepskyblue', backface_params=backface_params, smooth_shading=True)
plotter.open_gif('mobius_semiopaque.gif')

viewup = [0, 0, 1]
orbit = plotter.generate_orbital_path(n_points=24, shift=0.0, viewup=viewup)
plotter.orbit_on_path(orbit, write_frames=True, viewup=viewup, step=0.02)
backface props

Apply Backface Properties to Textured Meshes#

Backface textures can also be applied to meshes that have textures applied to them. For this example we load the globe texture with pyvista.examples.load_globe(), clip it, and then apply a different color to the interior surface.

The lighting has been disabled for this example to demonstrate how you can make the interior of the surface appear occluded without any directional lighting simply by providing a different color for backface.

globe = examples.load_globe()
texture = examples.load_globe_texture()
clipped = globe.clip(normal='z', value=4.37e9)

pl = pv.Plotter()
pl.add_mesh(
    clipped,
    backface_params={'color': [0.2, 0.2, 0.2]},
    lighting=False,
    smooth_shading=True,
    texture=texture,
)
pl.show()
backface props

Backface Properties and Physically Based Rendering#

Note that backfaces are automatically culled when physically based rendering is enabled, regardless of the settings of backface parameters.

sphere = pv.Sphere()
clipped_sphere = sphere.clip(normal='z', value=0.4)

pl = pv.Plotter()
pl.set_environment_texture(examples.download_sky_box_cube_map())
pl.add_mesh(
    clipped_sphere,
    backface_params={'color': 'r'},
    pbr=True,
    metallic=1.0,
    roughness=0.2,
)
pl.show()
backface props

See also the Turning the sphere inside out example which relies on distinguishing the inside and the outside of a sphere.

Total running time of the script: (6 minutes 15.300 seconds)

Gallery generated by Sphinx-Gallery