npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

sdf-csg

v0.0.0

Published

SDF-based constructive solid geometry

Downloads

5

Readme

sdf-csg

Generate meshes from signed distance functions and constructive solid geometry operations. This library is heavily based upon Inigo Quilez's 3D SDFs article.

Example

import { Box, Sphere, CappedCylinder } from "sdf-csg";

const sdf = new Sphere(1)
  .setUserData([0, 0, 1])
  .smoothIntersect(new Box(0.75, 0.75, 0.75).setUserData([1, 0, 0]), 0.1)
  .smoothSubtract(
    new CappedCylinder(1, 0.5)
      .smoothUnion(new CappedCylinder(1, 0.5).rotateX(Math.PI / 2), 0.1)
      .smoothUnion(new CappedCylinder(1, 0.5).rotateZ(Math.PI / 2), 0.1)
      .setUserData([0, 1, 0]),
    0.1
  );

const mesh = sdf.generateMesh([64, 64, 64], 0.2);

Live Demo

Note: this project is very much a work in progress. There may be significant changes to the API until the 1.0.0 semantic version is released.

Primitives

All of these return a new SDF.

const sdf = new Box(width: number, height: number, depth: number)
const sdf = new Sphere(radius: number)
const sdf = new BoxFrame(width: number, height: number, depth: number,  edge: number)
const sdf = new Torus(majorRadius: number,  minorRadius: number)
const sdf = new CappedTorus(majorRadius: number,  minorRadius: number,  angle: number)
const sdf = new Link(majorRadius: number,  minorRadius: number,  length: number)
const sdf = new Cone(angle: number,  height: number)
const sdf = new HexagonalPrism(radius: number,  length: number)
const sdf = new Capsule(pointA: number[],  pointB: number[],  radius: number)
const sdf = new CappedCylinder(length: number,  radius: number)
const sdf = new CappedCone(length: number,  radius1: number,  radius2: number)
const sdf = new SolidAngle(angle: number, radius: number)

Operations

All of these return a new SDF.

sdf.union(sdf: SDF)
sdf.subtract(sdf: SDF)
sdf.intersect(sdf: SDF)
sdf.smoothUnion(sdf: SDF, smoothness: number)
sdf.smoothSubtract(sdf: SDF, smoothness: number)
sdf.smoothIntersect(sdf: SDF, smoothness: number)
sdf.translate(x: number, y: number, z: number)
sdf.rotate(quat: number[])
sdf.rotateX(radians: number)
sdf.rotateY(radians: number)
sdf.rotateZ(radians: number)
sdf.scale(amount: number)
sdf.round(amount: number)

Example: smoothUnion

const sdf = new Sphere(1)
  .translate(-0.5, 0, 0)
  .smoothUnion(new Sphere(1).translate(0.5, 0, 0), 0.1)
  .setUserData([1, 0.5, 1]);

Example: smoothSubtract

const sdf = new Sphere(1)
  .translate(-0.5, 0, 0)
  .smoothSubtract(new Sphere(1).translate(0.5, 0, 0), 0.2)
  .setUserData([1, 0.5, 1]);

Example: smoothIntersect

const sdf = new Sphere(1)
  .translate(-0.5, 0, 0)
  .smoothIntersect(new Sphere(1).translate(0.5, 0, 0), 0.2)
  .setUserData([1, 0.5, 1]);

Example: round

const sdf = new HexagonalPrism(0.25, 1)
  .translate(-0.75, 0, 0)
  .union(new HexagonalPrism(0.25, 1).translate(0.75, 0, 0).round(0.1))
  .setUserData([1, 0.5, 1]);

User data

You can assign "user data" - an array of numbers - to components of your SDF. These are interpolated across the SDF and returned by the generateMesh function. Here's an example using them to interpolate color across the surface of the mesh, but you could imagine using them for other purposes, such as values for use with physically based rendering, etc.

const sdf = new Sphere(1)
  .setUserData([1, 0.5, 0.5])
  .translate(-0.75, 0, 0)
  .smoothUnion(new Sphere(1).setUserData([0.5, 0.5, 1]).translate(0.75, 0, 0), 0.5);

Mesh generation

const mesh = sdf.generateMesh(resolution: [number, number, number], padding: number);

Returns a Mesh:

interface Mesh {
  positions: number[][];
  normals: number[][];
  cells: number[][];
  userdata: number[][] | null;
}

Road map

  • The current isosurface extractor generates poor results for edges and corners. Write or use a different one for better results.
  • Isosurface extraction is slow. Speed it up (perhaps the SDF data could be used to skip large chunks of the grid?).
  • The bounds of the SDF are determined analytically, and it's a little buggy (e.g., when using the "smooth" operators), requiring the use of padding when generating the mesh. Some options:
    • Fix the bugs.
    • Determine the bounds numerically, using the value of the SDF to accelerate it.
  • Add more primitives.
  • Add more operators.

Credits

This library is heavily based upon Inigo Quilez's 3D SDFs article.