Welcome to the tech preview of ShapeJS. Please note that as this is a preview, geometry generation and API functionality has not yet been fully tested and confirmed to guarantee generation of printable geometry.
Overview
ShapeJS provides a powerful system for generating 3D printable objects via a simple Javascript program. The functionality of ShapeJS is based on a representation of three dimensional objects via voxels on 3 dimensional regular grid.
Roughly speaking the value of each voxel represents the percent of this voxel volume occupied by the shape. More precisely speaking the voxel value is appropriately normalized limited range signed distance function - distance from voxel center to the shape surface. That value is represented internally by default with 8 bit precision which is equivalent to 256 different levels. This more precise representation greatly enhances the quality of generated objects in comparison with more traditional binary values of 0 and 1. The gain in quality is similar to those of grayscale image over black and white image of the same resolution.
The voxel based representation gives ShapeJS greater flexibility in shape generation over traditional representation via triangle meshes. It is similar to advantages 2D raster graphics has over 2D vector graphics. Vector graphics is great for drawing diagrams and raster graphics is on practice the tool of choice for anything else.
The way to fill the voxel grid is to create an object with DataSource interface, which can calculate signed distance function for each point in space. This object is fed to an instance of GridMaker which controls the calculations. The distance function calculations may be very complex task for complex object. But this calculation can be simplified by composing complex object from many simpler one using several simple operations.
There are several predefined simple object like Sphere,Box, Cylinder and Cone. More complex methods include functionality to convert 2D image to a 3D embossed object using ImageBitmap object and importing user provided 3D object using load() function.
The real power of volume sculpting is in the flexibility of combining and transforming objects represented as distance function. There are usual boolean operations on objects which include Union, Intersection, Subtraction, Complement.
There is a flexible set of transformations which can be applied to any DataSource object. Transformations include standard 3D linear transformations like rotation, translation, scale, reflection. Flexibility of using volume based data allows to use arbitrary non linear transformation among those are RingWrap, SphereInversion, FriezeSymmetry, WalPaperSymmetry, ReflectionSymmetry. Several simple transformations can be composed into more complex transformation using CompositeTransform. A transformation can be applied to any DataSource object via its setTransform() method.
ShapeJS Scripts
ShapeJS Scripts are Javascript programs over top the AbFab3D Voxel library. All standard Javascript functionality is supported. In particular we use the Rhino Scripting engine in Java. You can find the project documentation here: Rhino Documentation
Below is a simple ShapeJS program.
function main(args){ // this script will make a sphere var radius = 5*MM; // radius of sphere 5 millimeters var voxelSize = 0.1*MM; // size of grid voxel var gw = radius*1.1; // make the grid size a little larger to have some clearance var grid = createGrid(-gw,gw,-gw,gw,-gw,gw,voxelSize); // create the grid var maker = new GridMaker(); // create instance of grid maker maker.setSource(new Sphere(radius)); // gives GridMaker object to work on maker.makeGrid(grid); // GridMaker fills the grid with data return grid; // return the grid for final processing }
Click Simple Sphere to run this example.
All vss scripts should have function main(args). This function is executed by the ShapeJS scripting engine. It is possible to pass arbitrary arguments (including uploaded files ) to the main(args), but we will explain this later.
Unit of length in ShapeJS is meters. To avoid awkward numbers there are few useful conversion constants MM=0.001 for millimeters, IN=0.0254 for inches.
The primary object of ShapeJS script is a volumetric grid. The result of executing main(args)should be a grid filled with scene data. The scripting engine converts the grid returned by main() into a traditional triangle mesh which is sent back to the browser and displayed in the 3D view.
The grid is created via this function:
grid = createGrid(xmin, xmax, ymin, ymax, zmin, zmax, voxelSize);
The primary tool of ShapeJS is GridMaker. GridMaker fills the grid voxels with values calculated by objects called DataSource. Sphere is one of several prebuilt data sources. Users can also create new DataSource objects directly in their script.
Calling maker.makeGrid(grid) does the actual calculations of the grid. Returning that grid from main initiates the ShapeJS engine conversion of grid data into a triangle mesh which is returned to browser.
Controlling parameter of output mesh
There are few variables which allow user to control behavior of volume sculpting engine.
meshSmoothingWidth Width of gaussian smoothing of the grid before conversion to traingle mesh. The width is given relative the grid voxel size. Default value is 0.5.
meshErrorFactor is maximal errod allowed during mesh decimation (reducing mesh complexity). It is given relative to voxel size. default value is 0.5. Smaller value greatly increase the resultng mesh complexity.
meshMinPartVolume allows to filter out sand size particles from the resulting mesh. All parts of volume less than meshMinPartVolume are discarded. This volume is specified in meters3. Default value is 1*MM3 (one cubic millimeter).
meshMaxPartsCount specifies the maximum number of parts to save. The n largest parts are kept. By default all parts are retained.
Examples
Boolean Operations
In this example we'll show a powerful modeling technique creating objects by using boolean algebra. Many objects can be described by adding and subtracting primitive shapes from them. In this example we create a cool doodad by subtracting a 3D cross from a sphere. Try the example here: Boolean Example
function cross3D(size, thickness){ var union = new Union(); var boxX = new Box(0,0,0,size,thickness, thickeness); var boxY = new Box(0,0,0,thickeness, size, thickeness); var boxZ = new Box(0,0,0,thickeness, thickeness,size); union.add(boxX); union.add(boxY); union.add(boxZ); return union; } function main(args) { var size = args[0]; var thickness = args[1]; var grid = createGrid(-16*MM,16*MM,-16*MM,16*MM,-16*MM,16*MM,0.1*MM); var diff = new Subtraction(new Sphere(15*MM), cross3D(size, thickness)); var maker = new GridMaker(); maker.setSource(diff); maker.makeGrid(grid); return grid; }
This script takes two parameters, the size of the cross and its thickness. The 3D cross is created by unioning together 3 boxes. The boxes are aligned in the x,y and z planes. The source for the grid is the Subtraction of a Sphere and the result of the cross3D function.
Image Popping
One of the nice features of using Voxel grids is the ability to use 2D raster image data. In this example we'll take an image and turn it into a 3D object. Here we use an ImageBitMap source and give it a physical size. We'll place this object on both sides to create a mirror image.
Notice we changed the voxelSize in this example from the typical .1mm default. When dealing with greyscale images you'll likely want higher resolution to get smooth transitions between heights.
Run the example here: Image Poppervar voxelSize = 0.05*MM; function makePart(path, width, height, thickness){ var img = new ImageBitmap(path, width, height, thickness); img.setBaseThickness(0.0); img.setVoxelSize(voxelSize); img.setBlurWidth(2*voxelSize); img.setImagePlace(ImageBitmap.IMAGE_PLACE_BOTH); return img; } function main(args) { var image = args[0]; var x = 10*MM; var y = 22*MM; var z = 3*MM; dest = createGrid(-x,x,-y,y,-z,z,voxelSize); var th = 2*MM; var width = 12*MM; var height = 40*MM; var img = makePart(image, width, height, th); var maker = new GridMaker(); maker.setSource(img); maker.makeGrid(dest); return dest; }
The ImageBitMap may have optional solid base. In this case we set base thickness to be 0, which in effect eliminates the base. The base thickness is given as fraction of the ImageBitMap object thickness. For example, setBaseThickness(0.4) will make ImageBitMap base thickness equal to (0.4*thickness) and the thickness of image will be reduces to 0.6*thickness;
Another useful method of ImageBitMap is setBlurWidth(blurWidth). The blurWidth is given in physical units and should normally be of the same size as voxelSize. The blurring eliminates sharp edges in the image.
Creating your own Creators
The underlying engine for the web examples can be used in your own Javascript creator. Once you have a script you like then we'd encourage you to make a user-interface that's more specific and easier to use. Once you have the parameters ready then you can use a REST call to execute_pipeline that will generate the 3D model. With this model you can easily use the rest of the Shapeways API to store the models, get pricing and add your own markup to the models.
Custom DataSource
You can create your own DataSource inside ShapeJS scripts. A DataSource must implement the getDataValue function. This function will evaluate the data source at a pnt. This function should return signed distance to the objects surface. Signed distance is positive for exterior points, negative for interior points and zero at the surface. To obtain high quality surface the signed distance funtion should be properly normalized to voxel size. See example for a Sphere:importPackage(Packages.abfab3d.util); var radius; var Sphere = { getDataValue : function(pnt, data) { var x = pnt.v[0]; var y = pnt.v[1]; var z = pnt.v[2]; var vs = pnt.getScaledVoxelSize(); var r = r = Math.sqrt(x*x + y*y + z*z); data.v[0] = MathUtil.step10(r, radius, vs); return DataSource.RESULT_OK; } } function main(args){ radius = 5*MM var a = radius*1.1; var voxelSize = 0.1*MM; var dest = createGrid(-a,a,-a,a,-a,a,voxelSize); var maker = new GridMaker(); maker.setSource(Sphere); maker.makeGrid(dest); return dest; }
Javascript Functions
ShapeJS has global helper functions accessible from your script.double sx | x size of grid |
double sy | y size of grid |
double sz | z size of grid |
double voxelSize | The size of each voxel. |
String filename | The name of file to load |
String filename | The name of the file to load |
double voxelSize | The size of voxels to use |
String filename | The name of the file to load |
Grid grid | The grid to load the result into. Will overwrite filled areas with model data, unfilled areas will not be changed. The grid must be large enough to contain the object. |
Java Objects
Specific Java objects are exposed to the scripts. This section lists the objects exposed and provides links to their Javadoc.Math
The java.lang.Math class is available. This is where you will find the typical min,max,sin,cos functions. Please see the posted Javadoc for complete details. Java6 Javadoc
An example usage is:function trigCalcs(radius,angle){ var circ = 2 * Math.PI * radius; var sin = Math.sin(angle); var max = Math.max(radius,10); }