Follow me on Twitter Follow me on GitHub
Chandler Prall Thoughts & Experiments for the Web

Constructive solid geometry with Three.js

A few days ago Evan Wallace released his Constructive solid geometry library for WebGL. This library uses Boolean operations (addition, subtraction, union, intersect) to be applied on 3D geometry such as cubes, spheres, or anything else you can throw at it. I thought this would be a very nice capability to have in Three.js and wrote a wrapper for Evan’s CSG library.

Download ThreeCSG.js

First, an example of what code using just the CSG library looks like:

var cube = new CSG.cube();
var sphere = CSG.sphere({radius: 1.3, stacks: 16});
var geometry = cube.subtract(sphere);

 
 
 
 
Let’s add in Three.js and my CSG wrapper:

var cube = THREE.CSG.toCSG(new THREE.CubeGeometry( 2, 2, 2 ));
var sphere = THREE.CSG.toCSG(new THREE.SphereGeometry(1.4, 16, 16));
var geometry = THREE.CSG.fromCSG( sphere.subtract(cube) );
var mesh = new THREE.Mesh(geometry, new THREE.MeshNormalMaterial());

It’s that simple. The toCSG function accepts objects of both THREE.Geometry and THREE.Mesh types. Objects can be positioned either by the mesh’s position or by supplying a second parameter to the toCSG function. Both methods are shown below. (rotation can be set from the mesh’s rotation property or through a supplied third parameter)

var cube_mesh = new THREE.Mesh(
	new THREE.CubeGeometry( 2, 2, 2 )
);
cube_mesh.position.x = 1;

var cube = THREE.CSG.toCSG(cube_mesh);
var sphere = THREE.CSG.toCSG(new THREE.SphereGeometry(1.4, 16, 16));
var geometry = sphere.subtract(cube);
var mesh = new THREE.Mesh(geometry, new THREE.MeshNormalMaterial());

var cube = THREE.CSG.toCSG(
	new THREE.CubeGeometry( 2, 2, 2 ),
	new THREE.Vector3(-1, 0, 0)
);
var sphere = THREE.CSG.toCSG(new THREE.SphereGeometry(1.4, 16, 16));
var geometry = THREE.CSG.fromCSG( sphere.subtract(cube) );
var mesh = new THREE.Mesh(geometry, new THREE.MeshNormalMaterial());

In these examples I only used the built in primitive objects but the same functionality should work for any Three.js compatible models. UV coordinates are not generated (all values are set to 0) but everything else related to THREE.Mesh works as you would expect.

Links, resources
Live demo of the last example
CSG wrapper for Three.js

25 Responses to Constructive solid geometry with Three.js

  1. gova05cse says:

    hi ,
    am a new guy to three.js framework………
    i dunno to setup & run in local machine….. pls help me learn this framework,….

    give me steps to setup three.js and to code it……. expecting basic tutorials pls…….

  2. gova05cse says:

    thanks Mr chanadler ! !
    i am developing a 3d modelling tool using three.js . ….

    now i have completed the task of rendering objects in the platform , i jus want to resize the 3d-object & also need to handle drag events + animating those 3d objects…..

    pls help me to complete my project….. if u have any query then jus visit the site http://WWW.3DTIN.COM , my project is similar to this tool + animation is the xtra feature to be addded………..

  3. bak85 says:

    Hi,

    I’m getting an error message using THREE.js (r49):
    Uncaught TypeError: Cannot call method ‘clone’ of undefined

    Though, the error message does not appear when using r48. Do you know how to solve this?

    • bak85 says:

      UPDATE:

      The error occurs when calling: THREE.CSG.toCSG(geometry);

    • chandler says:

      r49 made a change to how vertex positions are stored. I’ve been working on a new version of ThreeCSG which works with r49, you can find it on github. The new version is much more straightforward to use as well – check out the examples file to see how to use it (basically added subtract, intersect, and union as methods to the THREE.Mesh objects themselves).

  4. Ajay Shah says:

    My Browser always show the following error Script is too busy Do you want to contnue ot stop for Google Chorme as well as firfox

    var obj_1 = new THREE.Mesh(
    new THREE.CubeGeometry(12, 10, 10),
    new THREE.MeshNormalMaterial
    );

    var obj_2 = new THREE.Mesh(
    new THREE.SphereGeometry(10, 28,28),
    new THREE.MeshNormalMaterial
    );

    obj_2.position.set(1.5, 1.5, 1.5);

    // obj_2.subtract( obj_1 );

    scene.add( obj_1 );

    • chandler says:

      The CSG operations are computationally intensive (especially in the new version of ThreeCSG which needs a number of optimizations) which makes browsers ask the user if they want to kill the script of not. I have found spheres to be particularly troublesome for the algorithm.

  5. Pingback: HTML5 3D Animation Notes « Lively's Flash Builder Users Group

  6. aerialist says:

    Hi Chandler,

    Why did you change ThreeCSG.js to be ThreeBSP with its own subtract, union, intersect operations?
    I wish it was kept as wrapper/converter between THREE.geometry and csg.js geometry…

    Recently I noticed csg.js maintained by Joostn as part of his OpenJsCad project is full of features.
    https://github.com/joostn/OpenJsCad/tree/gh-pages

    Do you have any plan or motivation to write converter between Joostn’s csg.js geometry and THREE.js geometry (r55)?

    I tried your original ThreeCSG.js but unfortunately it didn’t work. Joostn’s csg.js has its own CSG.Vector3 and many more fundamental items which somewhat overlap with THREE’s but not exactly same.

    • chandler says:

      The original version, converting to and from Evan Wallace’s geometry format, added additional performance costs which I wanted to avoid. Are there any features in particular you would like to see in ThreeCSG?

  7. gxw says:

    Hello Chandler,

    A feature to possibly consider adding is basic transformations. (.rotate, .translate, etc.) Since ThreeCSG has been changed to ThreeBSP, it seems that we are now unable to utilize the CSG transformation support currently available in csg.js. Or, how can we do this now?

    For example,
    .
    .
    .
    var cube = new ThreeBSP( cubeMesh );
    var sphere = new ThreeBSP(sphereMesh);
    var bigsphere = new ThreeBSP(bigsphereMesh);

    var part_material_remove = cubeBSP.union( sphereBSP );
    part_material_remove.rotate(30,0,0); <– Nice to have!
    part_material_remove.translate(5,0,0); <– Nice to have!
    part = bigsphere.subtract(part_material_remove);
    .
    .
    .

  8. Pingback: Three.js Experiment 3 – Additive Geometry | moczydlowski, seth

  9. nitin kumar says:

    Hi Chandler,

    i have implements subtract using threeBSP but not doing union,in union case one geometry show but another not showing ,how can show these

  10. Srini says:

    Hi Chandler,
    I cannot get the examples of the Boolean operation working. I see that they are failing at
    the lerp routine on line 398 in vector sub() method:
    a.normal.clone().sub( this.normal ).multiplyScalar( t )
    with this error:
    Uncaught TypeError: Cannot read property ‘x’ of undefined

    I tried with different examples and all give me the same error. I am using Three.js r54.

    Thanks,
    Srini

  11. jun says:

    Hello Chandler,

    is it planed to fix bug #9 reported on GitHub (No faceVertexUVs + ThreeCSG = error)? I have encountered the problem, too. It is really a pity because I would like to cut objects imported from stl files (that have no faceVertexUVs) and ThreeBSP crushes there.

    The original version (the converter ThreeCSG) works fine with stl-imported objects but returns geometries that have an issue with the face edges. Usually, in Three.js an edge has exactly two neighbor faces. This fact is used for example by EdgesHelper in Three.js or by the topology.js written by Lee Stemkoski. Both are very useful.
    However, the converter ThreeCSG returns edges that can have more than two neighbor faces. (Or if talking mathematically, the vector between two face vertices can be unique in a geometry, because other neighboring faces can use parts of this edge as their edge.) This fact leads to faulty results in the libs mentioned above.
    I haven’t yet tested if the latter issue also applies to the ThreeBSP version.

    Would be very happy to hear your thoughts on these issues!

    Thanks,
    jun

  12. Abhinav says:

    will this work only with WebGL renderer? or will it work with canvas renderer too?

  13. Dag Rende says:

    Hi I have created a milling machine simulator on the web with ThreeCSG. If you run it you’ll see artifacts on the surface. Are these due to the issue mentioned above?

    The machine is at http://dagrende.github.io/gsim/ including a link to the source.

  14. Pingback: Fix Topology.js Errors - Windows XP, Vista, 7 & 8

  15. Johnny says:

    Hi, great library, one issue; when I use the subdivision modifier for three.js before running it through a boolean operation as implemented in your library, I get a stack size error: maximum call stack size exceeded. Next, when I try to run the modifier after performing a boolean operation as implemented in your library, I get very strange results, the mesh has faces that are protruding. Here is the code for the second instance:

    var smooth = result.geometry.clone() ;
    smooth.mergeVertices();
    var modifier = new THREE.SubdivisionModifier(0.1);
    modifier.modify( smooth );
    var mesh = new THREE.Mesh( smooth, new THREE.MeshPhongMaterial( { wireframe:true, color: 0xffffff } ) );
    scene.add( mesh );

    result is from here:

    var result = subtract_bsp.toMesh( new THREE.MeshLambertMaterial({ shading: THREE.SmoothShading, map: THREE.ImageUtils.loadTexture(‘texture.png’) }) );

    Can you please provide assistance on this issue?

    Thanks.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>