Getting Started

This guide introduces you to the core abstractions in crater.rs. Understanding these concepts is essential for working effectively with the library.

Installation

Add Crater.rs to your Cargo.toml:

[dependencies]
crater = "0.7.0"

Scalar Fields

A scalar field is a function that assigns a single number to every point in space. In Crater.rs, we use scalar fields to represent geometry implicitly.

For a 3D scalar field, we have a function where:

  • means the point is inside the shape
  • means the point is on the surface
  • means the point is outside the shape

Example: Sphere

A sphere centered at origin with radius has the scalar field:

In Crater.rs:

use crater::{csg::prelude::*};
use burn::backend::wgpu::{Wgpu, WgpuDevice};
use burn::prelude::*;
fn main() {
let device = WgpuDevice::default();
let sphere = Field3D::<Wgpu>::sphere(1.0, device.clone());

// Create a grid of origins in R³
// [n³, 3]
let n = 8; // Grid size
let grid_data = (0..n).flat_map(
        |i| (0..n).flat_map(
            move |j| (0..n).flat_map(
                move |k| [i as f32, j as f32, k as f32]
            )
        )
    ).collect::<Vec<_>>();
let origins = Tensor::<Wgpu, 1, Float>::from_data(
    grid_data.as_slice(),
    &device
).reshape([n * n * n, 3]);

// Evaluate the scalar field at the origins
// [n³, 1]
let evaluations = sphere.evaluate(origins);
}

Isosurfaces

An isosurface is the set of all points where a scalar field equals a constant value. The most common isosurface is at level 0, which represents the surface of the shape.

Creating Isosurfaces

use crater::csg::prelude::*;
use burn::backend::wgpu::{Wgpu, WgpuDevice};
use burn::prelude::*;
fn main() {
let device = WgpuDevice::default();
let sphere = Field3D::<Wgpu>::sphere(1.0, device.clone());
// Continuing from the previous example
let surface = sphere.clone().into_isosurface(0.0);

// Points slightly outside the sphere (f = 0.1)
let outer_surface = sphere.clone().into_isosurface(0.1);

// Points slightly inside the sphere (f = -0.1)
let inner_surface = sphere.clone().into_isosurface(-0.1);
}

Regions

A region represents a solid volume in space. It's the continuous "inside" of an isosurface, defined by where a scalar field is negative.

From Field to Region

use crater::csg::prelude::*;
use burn::backend::wgpu::{Wgpu, WgpuDevice};
use burn::prelude::*;
fn main() {
let device = WgpuDevice::default();
let sphere = Field3D::<Wgpu>::sphere(1.0, device.clone());
let surface = sphere.into_isosurface(0.0);
// Convert to region (solid volume)
let sphere_region = surface.region();
}

The .region() method creates a solid region from the isosurface.

Region Operations

Regions support intuitive boolean operations:

use crater::{csg::prelude::*, primitives::prelude::*};
use burn::backend::wgpu::{Wgpu, WgpuDevice};
use burn::prelude::*;
fn main() {
let device = WgpuDevice::default();
let sphere = Field3D::<Wgpu>::sphere(1.0, device.clone()).into_isosurface(0.0).region();
let cube = BoundingBox::new([-0.8, -0.8, -0.8], [0.8, 0.8, 0.8])
    .into_region(device.clone());

// Union (logical OR)
let union = &sphere | &cube;

// Intersection (logical AND)  
let intersection = &sphere & &cube;

// Negation (logical NOT)
let negation = -&sphere;

// Difference (logical \ and NOT)
let difference = sphere & -cube;
}

Meshing

Isosurfaces can be visualized using marching cubes:

use crater::{csg::prelude::*, primitives::prelude::*, serde::prelude::*};
use burn::backend::wgpu::{Wgpu, WgpuDevice};
use burn::prelude::*;
fn main() {
let device = WgpuDevice::default();
let sphere_field = Field3D::<Wgpu>::sphere(1.0, device.clone());
// Convert isosurface to region for marching cubes
let region = sphere_field.into_isosurface(0.0).region();

// Generate mesh
let mesh = marching_cubes::<Wgpu>(
    &MarchingCubesParams {
        region,
        bounds: BoundingBox::new([-2.0, -2.0, -2.0], [2.0, 2.0, 2.0]),
        resolution: (64, 64, 64),
        algebra: Algebra::default(),
    },
    &device
);

// Export for visualization
let mesh_collection: MeshCollection = mesh.into();
mesh_collection.write_stl("sphere.stl").unwrap();
}

Constructive Solid Geometry (CSG)

CSG allows you to build complex shapes by combining simpler ones using boolean operations.

Basic Operations

Union (OR: |)

Combines two shapes into one larger shape:

use crater::{csg::prelude::*, primitives::prelude::*};
use burn::backend::wgpu::{Wgpu, WgpuDevice};
use burn::prelude::*;
fn main() {
let device = WgpuDevice::default();
let shape1 = Field3D::<Wgpu>::sphere(1.0, device.clone())
    .into_isosurface(0.0)
    .region();
let shape2 = Field3D::<Wgpu>::sphere(1.0, device.clone())
    .into_isosurface(0.0)
    .region()
    .transform(Translate([1.5, 0.0, 0.0]));

let union = &shape1 | &shape2;  // Dumbbell shape
}

Intersection (AND: &)

Keeps only the overlapping parts:

use crater::{csg::prelude::*, primitives::prelude::*};
use burn::backend::wgpu::{Wgpu, WgpuDevice};
use burn::prelude::*;
fn main() {
let device = WgpuDevice::default();
let sphere = Field3D::<Wgpu>::sphere(1.0, device.clone())
    .into_isosurface(0.0)
    .region();
let cube = BoundingBox::new([-0.8, -0.8, -0.8], [0.8, 0.8, 0.8])
    .into_region(device.clone());

let intersection = sphere & cube;  // Rounded cube
}

Transformations

Regions can be transformed using standard geometric operations:

Translation

use crater::{csg::prelude::*, primitives::prelude::*};
use burn::backend::wgpu::{Wgpu, WgpuDevice};
use burn::prelude::*;
fn main() {
let device = WgpuDevice::default();
let sphere_region = Field3D::<Wgpu>::sphere(1.0, device.clone()).into_isosurface(0.0).region();
let moved_sphere = sphere_region.transform(Translate([1.0, 2.0, 0.0]));
}

Rotation

use crater::{csg::prelude::*, primitives::prelude::*};
use burn::backend::wgpu::{Wgpu, WgpuDevice};
use burn::prelude::*;
fn main() {
let device = WgpuDevice::default();
let cylinder_region = Field3D::<Wgpu>::cylinder(1.0, device.clone()).into_isosurface(0.0).region();
let rotated_cylinder = cylinder_region.transform(
    RotateAbout::new(0, 1, std::f32::consts::FRAC_PI_2, &device)
);
}

Scaling

use crater::{csg::prelude::*, primitives::prelude::*};
use burn::backend::wgpu::{Wgpu, WgpuDevice};
use burn::prelude::*;
fn main() {
let device = WgpuDevice::default();
let sphere_region = Field3D::<Wgpu>::sphere(1.0, device.clone()).into_isosurface(0.0).region();
let scaled_sphere = sphere_region
    .transform(ScaleDim(0, 2.0))
    .transform(ScaleDim(1, 1.0))
    .transform(ScaleDim(2, 1.0));
}

Working with Different Dimensions

Crater.rs supports arbitrary dimensions through type parameters:

use crater::{csg::prelude::*, primitives::prelude::*};
use burn::backend::wgpu::{Wgpu, WgpuDevice};
use burn::prelude::*;
fn main() {
let device = WgpuDevice::default();
// 2D shapes
let circle = Field2D::<Wgpu>::circle(1.0, device.clone());
let line = Field2D::<Wgpu>::line([0.0, 1.0], device.clone());

// 3D shapes  
let sphere = Field3D::<Wgpu>::sphere(1.0, device.clone());
let cone = Field3D::<Wgpu>::cone([0.0, 0.0, 1.0], 0.5, device.clone());

// N-dimensional shapes
let hypersphere = FieldND::<4, Wgpu>::hypersphere(1.0, device.clone());
}

Next Steps

Now that you understand the core concepts:

  1. Ray Casting - Learn how to ray cast against Regions
  2. Theory - Mathematical underpinnings of the library