A differentiable framework for generating and deforming 3D microstructured materials using Signed Distance Functions (SDFs) and spline-based lattices.
You can install DeepSDFStruct directly from GitHub using pip:
pip install git+https://github.com/mkofler96/DeepSDFStruct.gitTo add it to your uv project run:
uv add git+https://github.com/mkofler96/DeepSDFStruct.git
If you encounter issues during installation, contact Michael Kofler.
This section shows how to use the main features of this library. Further details can be found in example.ipynb.
Here's a simple example using a pretrained DeepSDF model, lattice structure generation, and deformation:
from DeepSDFStruct.pretrained_models import get_model, PretrainedModels
from DeepSDFStruct.SDF import SDFfromDeepSDF
from DeepSDFStruct.lattice_structure import LatticeSDFStruct
from DeepSDFStruct.parametrization import Constant
from DeepSDFStruct.torch_spline import TorchSpline
import splinepy
import torchmodel = get_model(PretrainedModels.AnalyticRoundCross)
sdf = SDFfromDeepSDF(model)sdf.set_latent_vec(torch.tensor([0.3]))
_ = sdf.plot_slice(origin=(0, 0, 0))import numpy as np
height = 1.0
surface_cps = np.array(
[
[0.0, 0.0, 0.0],
[1.0, 0.0, 0.0],
[2.0, 1.0, 0.0],
[3.0, 1.0, 0.0],
[0.0, 0.0 + height, 0.0],
[1.0, 0.0 + height, 0.0],
[2.0, 1.0 + height, 0.0],
[3.0, 1.0 + height, 0.0],
[0.0, 0.0, 1.0],
[1.0, 0.0, 1.0],
[2.0, 1.0, 1.0],
[3.0, 1.0, 1.0],
[0.0, 0.0 + height, 1.0],
[1.0, 0.0 + height, 1.0],
[2.0, 1.0 + height, 1.0],
[3.0, 1.0 + height, 1.0],
]
)
spline = splinepy.Bezier(degrees=[3, 1, 1], control_points=surface_cps).bspline
deformation_spline = TorchSpline(spline)lattice_struct = LatticeSDFStruct(
tiling=(6, 2, 1),
microtile=sdf,
parametrization=Constant([0.5], device=model.device),
)_ = lattice_struct.plot_slice(origin=(0, 0, 0.5), deformation_function=deformation_spline)Since all SDFs are callable, the signed distance can be obtained by calling e.g.
lattice_struct(torch.tensor([[0, 0, 0], [0, 1, 0]], dtype=torch.float32))The CappedBorderSDF class helps to avoid non-watertight meshs, by capping the borders.
from DeepSDFStruct.SDF import CappedBorderSDF
capped_lattice = CappedBorderSDF(lattice_struct)
_ = capped_lattice.plot_slice(origin=(0, 0, 0.5), deformation_function=deformation_spline)Furthermore, a differentiable surface mesh can be extracted and exporte
from DeepSDFStruct.mesh import create_3D_mesh, export_surface_mesh
surf_mesh, derivative = create_3D_mesh(
capped_lattice, 30, differentiate=True, mesh_type="surface"
)
export_surface_mesh(
"mesh_with_derivative.vtk",surf_mesh, derivative
)The libraries gustaf and meshio can be used to export the mesh to differnt formats.
import gustaf as gus
faces = surf_mesh.to_gus()
gus.io.meshio.export("faces.inp", faces)
gus.io.meshio.export("faces.obj", faces)Finally, there is also a functionality to create a volumetric mesh from the generated surface mesh.
from DeepSDFStruct.mesh import tetrahedralize_surface
volumes, _ = tetrahedralize_surface(faces)
gus.io.mfem.export("volumes.mfem", volumes)A model can be trained by using the train_deep_sdf function that takes as input the experiment directory and the data directory.train_deep_sdf("DeepSDFStruct/trained_models/test_experiment", data_dir)
from DeepSDFStruct.deep_sdf.training import train_deep_sdfExample data can be downloaded from huggingface
from huggingface_hub import snapshot_download
data_dir = snapshot_download(
"mkofler/lattice_structure_unit_cells", repo_type="dataset"
)
train_deep_sdf("DeepSDFStruct/trained_models/test_experiment", data_dir)Note that this data contains the preprocessed and sampled data.
The data that is used for training a DeepSDF model needs to be in the form of .npz files that contain the negative and positive points as an [x,y,z] array.
This can be achieved by using numpy's export function:
np.savez(file_name, neg=neg_points, pos=pos_points)Different types of geometry representations can be used for training. One possibility is to use the python library splinepy:
import splinepy
import numpy as np
from DeepSDFStruct.sampling import SDFSampler
from DeepSDFStruct.splinepy_unitcells.chi_3D import Chi3D
from DeepSDFStruct.splinepy_unitcells.cross_lattice import CrossLattice
outdir = "./training_data"
splitdir = "./training_data/splits"
dataset_name = "example_dataset"
sdf_sampler = SDFSampler(outdir, splitdir, dataset_name)
t_start = 0.1 * np.sqrt(2) / 2
t_end = 0.15 * np.sqrt(2) / 2
crosslattice_tiles = []
for t in np.linspace(t_start, t_end, 3):
tile, _ = CrossLattice().create_tile(np.array([[t]]), make3D=True)
crosslattice_tiles.append(splinepy.Multipatch(tile))
chi = Chi3D()
chi_tiles = []
for phi in np.linspace(0, -np.pi / 6, 2):
for x2 in np.linspace(-0.1, 0.2, 2):
t = 0.1
x1 = 0.2
r = 0.5 * t
tile, _ = chi.create_tile(np.array([[phi, t, x1, x2, r]] * 5))
chi_tiles.append(splinepy.Multipatch(tile))
sdf_sampler.add_class(chi_tiles, class_name="Chi3D_center")
sdf_sampler.add_class(crosslattice_tiles, class_name="CrossLattice")
sdf_sampler.process_geometries(
sampling_strategy="uniform", n_faces=100
)
sdf_sampler.write_json("chi_and_cross.json")For the full documentation, visit mkofler96.github.io/DeepSDFStruct/.
DeepSDFStruct provides a comprehensive set of geometric primitives and SDF operations for creating complex geometries. Below are visual examples of the available primitives and operations.
Click to see 3D primitive code examples
from DeepSDFStruct.sdf_primitives import (
SphereSDF, BoxSDF, CylinderSDF, ConeSDF, TorusSDF,
RoundedBoxSDF, WireframeBoxSDF, CapsuleSDF, EllipsoidSDF,
PyramidSDF, TetrahedronSDF, OctahedronSDF,
DodecahedronSDF, IcosahedronSDF, CappedCylinderSDF,
CappedConeSDF, RoundedCylinderSDF, RoundedConeSDF,
CornerSpheresSDF, CrossMsSDF
)
# Sphere
sphere = SphereSDF(center=[0, 0, 0], radius=1.0)
# Box
box = BoxSDF(center=[0, 0, 0], extents=[1.0, 1.0, 1.0])
# Cylinder (defined by endpoints)
cylinder = CylinderSDF(point_a=[0, 0, -0.5], point_b=[0, 0, 0.5], radius=0.4)
# Cone
cone = ConeSDF(apexpoint=[0, 0, -0.5], axis=[0, 0, 1], radius=0.4, height=1.0)
# Torus
torus = TorusSDF(center=[0, 0, 0], axis=[0, 0, 1], major_radius=1.0, minor_radius=0.3)
# Rounded Box
rounded_box = RoundedBoxSDF(center=[0, 0, 0], extents=[1.0, 1.0, 1.0], radius=0.15)
# Wireframe Box
wireframe_box = WireframeBoxSDF(center=[0, 0, 0], extents=[1.0, 1.0, 1.0], thickness=0.08)
# Capsule
capsule = CapsuleSDF(point_a=[0, 0, -0.5], point_b=[0, 0, 0.5], radius=0.25)
# Ellipsoid
ellipsoid = EllipsoidSDF(center=[0, 0, 0], extents=[0.6, 0.8, 0.5])
# Pyramid
pyramid = PyramidSDF(height=1.0)
# Platonic Solids
tetrahedron = TetrahedronSDF(r=0.8)
octahedron = OctahedronSDF(r=0.8)
dodecahedron = DodecahedronSDF(r=0.8)
icosahedron = IcosahedronSDF(r=0.8)
# With caps and rounded transitions
capped_cylinder = CappedCylinderSDF(point_a=[0, 0, -0.5], point_b=[0, 0, 0.5], radius=0.3)
rounded_cylinder = RoundedCylinderSDF(ra=0.3, rb=0.1, h=1.0)
capped_cone = CappedConeSDF(point_a=[0, 0, -0.5], point_b=[0, 0, 0.5], ra=0.1, rb=0.3)
rounded_cone = RoundedConeSDF(r1=0.1, r2=0.3, h=1.0)
# Special structures
corner_spheres = CornerSpheresSDF(radius=0.15, limit=0.8)
cross_ms = CrossMsSDF(radius=0.15)Click to see 2D primitive code examples
from DeepSDFStruct.sdf_primitives import (
CircleSDF, RectangleSDF, RoundedRectangleSDF,
EquilateralTriangleSDF, HexagonSDF, PolygonSDF
)
# Circle
circle = CircleSDF(center=[0, 0], radius=1.0)
# Rectangle
rectangle = RectangleSDF(center=[0, 0], extents=[2.0, 1.5])
# Rounded Rectangle
rounded_rectangle = RoundedRectangleSDF(center=[0, 0], extents=[2.0, 1.5], radius=0.2)
# Equilateral Triangle
triangle = EquilateralTriangleSDF(size=1.5)
# Hexagon
hexagon = HexagonSDF(size=1.5)
# Custom Polygon (Pentagon)
pentagon = PolygonSDF([
[0, 1],
[0.95, 0.31],
[0.59, -0.81],
[-0.59, -0.81],
[-0.95, 0.31],
])Click to see boolean operation code examples
from DeepSDFStruct.sdf_primitives import SphereSDF, BoxSDF
from DeepSDFStruct.SDF import UnionSDF, DifferenceSDF
sphere = SphereSDF(center=[-0.3, 0, 0], radius=0.5)
box = BoxSDF(center=[0.3, 0, 0], extents=[0.8, 0.8, 0.8])
# Union (can also use + operator)
union = UnionSDF(sphere, box)
# Difference
difference = DifferenceSDF(sphere, box)Click to see transformation operation code examples
import numpy as np
from DeepSDFStruct.sdf_primitives import SphereSDF, TorusSDF, CircleSDF
from DeepSDFStruct.sdf_operations import TwistSDF, DilateSDF, ShellSDF, RepeatSDF, MirrorSDF, CircularArraySDF, RevolveSDF
# Twisted Torus
base_torus = TorusSDF(center=[0, 0, 0], axis=[0, 0, 1], major_radius=1.0, minor_radius=0.2)
twisted_torus = TwistSDF(base_torus, k=np.pi/2)
# Dilated Sphere
sphere = SphereSDF(center=[0, 0, 0], radius=0.5)
dilated_sphere = DilateSDF(sphere, r=0.15)
# Shell
shell_sphere = ShellSDF(sphere, thickness=0.1)
# Repeat (creates infinite grid)
small_sphere = SphereSDF(center=[0, 0, 0], radius=0.2)
repeated_sphere = RepeatSDF(small_sphere, spacing=[0.6, 0.6, 0.6])
# Mirror
off_center_sphere = SphereSDF(center=[0.5, 0, 0], radius=0.3)
mirrored_sphere = MirrorSDF(off_center_sphere, plane_point=[0, 0, 0], plane_normal=[1, 0, 0])
# Circular Array
arrayed_sphere = CircularArraySDF(off_center_sphere, count=6, radius=0.8)
# Revolve (2D to 3D)
circle_2d = CircleSDF(center=[0.8, 0], radius=0.15)
revolved_shape = RevolveSDF(circle_2d, axis='z')All SDFs can be evaluated at query points:
points = torch.tensor([[0, 0, 0], [1, 0, 0]], dtype=torch.float32)
distances = sphere(points) # Returns signed distancesThese images are automatically generated from the actual SDF implementations. Run uv run python benchmarks/generate_sdf_showcase.py to regenerate all showcases.
GitHub: https://github.com/mkofler96/DeepSDFStruct
This project is licensed under the Apache License 2.0.
See the LICENSE file or visit http://www.apache.org/licenses/LICENSE-2.0 for more information.






































