Generating surfaces with procedural noise

The ProceduralSurfaceGeometry-class is a child of the Geometry class, and carves out a procedural surface of a already existing object. We will here present a basic example where we carve out a procedural surface from a block of beta-cristobalite.

First, we need to import necessary functionality:

from molecular_builder import create_bulk_crystal, carve_geometry, write
from molecular_builder.geometry import ProceduralSurfaceGeometry

Second, a block of beta-cristobalite is generated. We go with a block of dimensions (50Å, 200Å, 200Å).

atoms = create_bulk_crystal("beta_cristobalite", [200, 200, 50])
examples/procedural_noise/block.png

A block of \(\beta\)-cristobalite.

Basic example

To get a basic surface with structures generated by procedural noise, we need to define a point on the surface, its normal vector and the thickness of the noise:

geometry = ProceduralSurfaceGeometry(point=(100, 100, 40),
                                     normal=(0, 0, 1),
                                     thickness=20,
                                     seed=97455
                                     )

The result is

examples/procedural_noise/basic.png

Surface with procedural structures generated using Perlin noise. Scale is 1, octaves is 1.

Noise parameters

There is a bunch of parameters associated with the procedural noise. The scale of the noise structures is given by the scale-parameters, and the number of octaves (levels of details) is given by octaves. To generate different surfaces with the same parameters, change seed. See <https://pypi.org/project/noise/>`_. for more options.

geometry = ProceduralSurfaceGeometry(point=(100, 100, 40),
                                     normal=(0, 0, 1),
                                     thickness=20,
                                     method='simplex',
                                     scale=3,
                                     octaves=2,
                                     seed=16591
                                     )
num_carved = carve_geometry(atoms, geometry, side="out")

The result is

examples/procedural_noise/parameters.png

Surface with procedural structures generated using Simplex noise. Scale is 3, octaves is 2.

Two-level surface

Instead of having continuous surfaces, one may wants to set a threshold and create a two-level surface. As the expectation value of the noise is zero, setting threshold=0 gives a surface where the surface area of the two levels is approximately the same.

geometry = ProceduralSurfaceGeometry(point=(100, 100, 40),
                                     normal=(0, 0, 1),
                                     thickness=20,
                                     method='simplex',
                                     scale=3,
                                     octaves=2,
                                     seed=16591,
                                     threshold=0
                                     )
num_carved = carve_geometry(atoms, geometry, side="out")

The result is

examples/procedural_noise/two_level.png

Surface with two-level structures generated using Simplex noise. Scale is 3, octaves is 2.

Periodic structures

Often it is convenient to have periodic structures. By setting repeat=True, the structures are repeated once in each direction:

geometry = ProceduralSurfaceGeometry(point=(100, 100, 40),
                                     normal=(0, 0, 1),
                                     thickness=20,
                                     method='simplex',
                                     scale=3,
                                     octaves=2,
                                     seed=16591,
                                     threshold=0,
                                     repeat=True
                                     )
num_carved = carve_geometry(atoms, geometry, side="out")

The result is

examples/procedural_noise/periodic.png

Surface with periodic two-level structures. Scale is 3, octaves is 2.

One can also set how often the structures should repeat. By setting repeat=(100, 200), the structures are repeated twice in x-direction and once in y-direction:

geometry = ProceduralSurfaceGeometry(point=(100, 100, 40),
                                     normal=(0, 0, 1),
                                     thickness=20,
                                     method='simplex',
                                     scale=3,
                                     octaves=2,
                                     seed=16591,
                                     threshold=0,
                                     repeat=(100, 200)
                                     )
num_carved = carve_geometry(atoms, geometry, side="out")

The result is

examples/procedural_noise/periodic2.png

Surface with periodic two-level structures. Scale is 3, octaves is 2.

Screwed noise

Another possibility is to make the noise screwed. This is done by setting the relative angle between the x-axis and the noise axis, which by default in 90 degrees. This can be useful when dealing with triclinic systems:

geometry = ProceduralSurfaceGeometry(point=(100, 100, 40),
                                     normal=(0, 0, 1),
                                     thickness=20,
                                     method='simplex',
                                     scale=3,
                                     octaves=2,
                                     seed=16591,
                                     threshold=0,
                                     repeat=True,
                                     angle=45
                                     )
num_carved = carve_geometry(atoms, geometry, side="out")

The result is

examples/procedural_noise/screwed.png

Surface with periodic, screwed two-level structures. Scale is 3, octaves is 2.

Add function

A function can be added to the noise. Here, we add a fucntion that is lineary increasing when x<100 and a lineary decreasing when x>100:

def f(x, y):
    if x < 100:
        return x/100
    else:
        return 1 - (x-100)/100

Then, we set f=f:

geometry = ProceduralSurfaceGeometry(point=(100, 100, 40),
                                     normal=(0, 0, 1),
                                     thickness=20,
                                     method='simplex',
                                     scale=3,
                                     octaves=2,
                                     seed=16591,
                                     threshold=0,
                                     repeat=True,
                                     f=f
                                     )
num_carved = carve_geometry(atoms, geometry, side="out")

The result is

examples/procedural_noise/add_function.png

Surface with periodic two-level structures and an added function. Scale is 3, octaves is 2.