GithubHelp home page GithubHelp logo

manthrax / three-csgmesh Goto Github PK

View Code? Open in Web Editor NEW
448.0 14.0 56.0 113.45 MB

Conversion of a CSG library for use with modern THREE.js

JavaScript 96.91% HTML 2.75% CSS 0.33%
csg computational-solid-geometry threejs three-js

three-csgmesh's Introduction

THREE-CSGMesh

Conversion of a CSG - (Constructive Solid Geometry) library for use with modern THREE.js

Original version: Copyright (c) 2011 Evan Wallace (http://madebyevan.com/), under the MIT license.

THREE.js rework by thrax under MIT license.

Here's a running demo https://manthrax.github.io/THREE-CSGMesh/demos/CSGDemo.html csg screenshot

And a shinier, slightly more complex demo: https://manthrax.github.io/THREE-CSGMesh/demos/CSGShinyDemo.html

csg screenshot

And a more complex example showing a text mesh cut into another complex mesh via an intermediate cube:

https://manthrax.github.io/THREE-CSGMesh/v2/index.html csg screenshot

An example showing multiple material groups, and vertex color channel:

https://manthrax.github.io/THREE-CSGMesh/demos/CSGMulti.html

csg screenshot

CSG is the name of a technique for generating a new geometry as a function of two input geometries.

CSG is sometimes referred to as "Boolean" operators in 3d modelling packages.

Internally it uses a structure called a BSP (binary space partitioning) tree to carry out these operations.

The supported operations are .subtract, .union, and .intersect.

By using different combinations of these 3 operations, and changing the order of the input models, you can construct any combination of the input models.

In the first screenshot/demo above, I show the possible results with a cube and a sphere...

In blue is the result of the .union operation, for sphere->cube and cube->sphere (the result is same in this case )

In green is the result of the .intersect operation, for sphere->cube and cube->sphere (the result is same in this case )

In red is the result of the .subtract operation, for sphere->cube and cube->sphere. Here the result differs based on the order of the inputs.

Example usage:

EXAMPLE 0:

//Minimal example.. subtract mesh b from mesh a:
import {CSG} from "three-csg.js"
scene.add(CSG.toMesh(CSG.subtract(CSG.fromMesh(a),CSG.fromMesh(b)),a.material))

EXAMPLE 1. Verbose... step by step..

// Make 2 box meshes.. 

let meshA = new THREE.Mesh(new THREE.BoxGeometry(1,1,1))
let meshB = new THREE.Mesh(new THREE.BoxGeometry(1,1,1))

//offset one of the boxes by half its width..

meshB.position.add(new THREE.Vector3( 0.5, 0.5, 0.5)

//Make sure the .matrix of each mesh is current

meshA.updateMatrix()
meshB.updateMatrix()

 //Create a bsp tree from each of the meshes
 
let bspA = CSG.fromMesh( meshA )                        
let bspB = CSG.fromMesh( meshB )

// Subtract one bsp from the other via .subtract... other supported modes are .union and .intersect
 
let bspResult = bspA.subtract(bspB)

//Get the resulting mesh from the result bsp, and assign meshA.material to the resulting mesh

let meshResult = CSG.toMesh( bspResult, meshA.matrix, meshA.material )

three-csgmesh's People

Contributors

hamidb80 avatar manthrax avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

three-csgmesh's Issues

intersecting a box with a cone results in a slice of the surface of the cone instead of a solid object

When intersecting a BoxBufferGeom with a ConeBufferGeom I don't end up with a solid object, i get a slice of the surface of the cone. I imagine I'm doing something wrong, but i can't for the life of me figure it out.

I started from the two BoxGeom's example in the README (which worked!) then modified them to be different shapes. I am using react-three-fiber but the CSG stuff is separate and deals only with normal three objects.

Equally puzzling, box.subtract(cone) gives the same exact result as intersect (slice of the surface of the cone).

cone-box-intersection-manthrax

  • cone.subtract(box) gives the inverse of intersect - a hollow cone with a slice of its surface missing.
  • box.union(cone) gives the same exact result as cone.subtract(box)!

cone-box-union-manthrax

demo code: https://codesandbox.io/s/manthrax-shapes-hollow-bsqij?file=/src/App.js

FWIW, I've been trying out a bunch of three CSG libs and having issues with pointy objects like cones in all of them. The common denominator here appears to be me, but I just can't understand where i've gone wrong?

Cleaning up EdgesGeometry

I have a problem that after CSG operations leave unnecessary cords showing when transforming the resulting geometry with THREE.EdgesGeometry(). The following issue listed on Three explains the issue quite nicely: mrdoob/three.js#10517 ... and also gives a solution (although for outdated Three.Geometry class that is no longer available). Is there any chance breaking up faces can be handled inside your awesome CSG library? ... or would you know how to convert that old code he did to work with Three.BufferGeometry (it's a bit over my head)?

Multi Material

HI, i have problem with converted mesh materials
on right side original mesh
on bottom subtracted mesh
and on middle CSG mesh
here is a screen shot and a simple part of code
` let texture1: THREE.Texture = Textures.getTexture('1');
texture1.wrapS = texture1.wrapT = THREE.RepeatWrapping;
texture1.repeat.set(1, 1);
let texture2: THREE.Texture = Textures.getTexture('2');
texture2.wrapS = texture2.wrapT = THREE.RepeatWrapping;
// texture2.repeat.set(1, 0.2);
let mat1: THREE.MeshBasicMaterial = new THREE.MeshBasicMaterial({map: texture1});
let mat2: THREE.MeshBasicMaterial = new THREE.MeshBasicMaterial({map: texture2});
let materials: Array<THREE.MeshBasicMaterial> = [
mat1,
mat2,
mat2
];
let meshA: THREE.Mesh = this.tjs.addMesh(new THREE.Mesh(new THREE.CylinderGeometry(4, 4, 3, 20), materials));
let meshB: THREE.Mesh = this.tjs.addMesh(new THREE.Mesh(new THREE.CylinderGeometry(2, 2, 3, 20), materials));
// Create a bsp tree from each of the meshes
let bspA: CSG = CSG.fromMesh(meshA);
let bspB: CSG = CSG.fromMesh(meshB);

    // Subtract one bsp from the other via .subtract. other supported modes are .union and .intersect
    let bspResult: CSG = bspA.subtract(bspB);

    // Get the resulting mesh from the result bsp
    this.tjs.addMesh(CSG.toMesh(bspResult, meshA.matrix)).material = materials;

    meshA.position.x = 9;
    meshB.position.z = 9;`

or maybe you know how to figure out with this issue
sorry for my Eanglish :)
Thanks!
qq

Remaining face after subtract operation

Hi again!

After some subtraction operations, there is a remaining face in the result.

In this case, I am given a wall and a sloped roof as separate objects. The wall is given as a parallelepiped and I am using subtract operations to clip it with the shape of the roof.

image

Nevertheless, when I apply the operation, this is the result:

image
image

As you can see, the operation has been carried out correctly, but there is a face that remains. I am not sure wether this is a precission problem or something else.

I am aware that knowing the cause of this issue might be hard, but I was hoping to find a way around this problem (maybe a way to tweak the precission of the CSG operation or a way to detect when this kind of isolated face is generated to filter it out).

Thank you very much in advance! πŸ™‚

Subtract, intersect, union, etc. functions only work with manipulating Sphere geometries

Hello! I am trying to use your Three-CSGMesh library after having no luck subtracting geometries with other Three.js/CSG.js libraries. Subtracting a sphere from any other geometry works perfectly fine, but subtracting other types of Three.js geometries doesn't work, etc. subtracting a BoxGeometry from a Box Geometry, etc. I would most definitely appreciate it if you can look into this, thank you!

npm

Thanks alot for this great library! Do you have any plans to publish it on npm? This would make it easier to use it.

Meshes are re-positioned back at the origin before subtraction,union,etc. operations

Hello there! I have been trying to subtract shapes using CSG.js and Three.js, and haven't had any luck with ThreeCSG.js, so I am trying to use your library instead. Subtracting the shapes is working fine, but I am having one issue with your library that I cannot get around.

I am using your helper function doCSG( ) to convert Three.Mesh cubes into CSG objects, then subtract one cube from the other. Specifically, I want to subtract a smaller cube from the larger cube so that the end result looks like a cube with a small chunk taken out of one corner.

I'm using your helper function, doCSG( ). And here's the basic code for subtracting the cubes:

var meshA = new THREE.Mesh(new THREE.BoxGeometry(10,10,10), material);
	var meshB = new THREE.Mesh(new THREE.BoxGeometry(9,9,9));
	meshB.position.add(new THREE.Vector3( 10,10,10));
	meshA.position.add(new THREE.Vector3( 5, 5, 5));
	var meshC = doCSG( meshA,meshB, 'subtract',meshA.material);
	scene.add(meshC);

However, in the rendered scene, when I end up with is simply the larger cube. After doing some experimentation, I realize that the smaller cube was indeed subtracted from the larger cube, but both cubes were repositioned at the origin before the subtraction operation.

I would very much appreciate it if you could fix this issue, so that the positions of meshes are preserved before performing subtraction operations or any other operation. I suspect the issue has something to do with with the matrix transformations in the fromMesh() function but I am not sure. Thank you very much!

conversion back to THREE.Mesh misses the uv

In the loop at line 453:

   for(var j=3;j<=pvlen;j++){

It does the calculation for UV, but most of what's done is lost and not utilized in the created mesh (fvuv, fuv and fnml)

Note that there are a few other things, while trying to convert it to typescript the compiler found other issues, for example:

Line 480:

  m.matrix.decompose(m.position,m.rotation,m.scale)

m.rotation is Euler (latest THREE version as of 26/6) but matrix.decompose expects a quaternion, im not sure if this would fix it:

  m.matrix.decompose(m.position, new THREE.Quaternion().setFromEuler(m.rotation), m.scale);

then CSG:fromGeometry builds vertices passing a Vector2 as uv, I'm unsure if this works as expected, it then makes a new Vector receiving a Vector2 as constructor parameter (didn't go too deep into it, not sure if there's actually an issue)

Any plans to convert / adapt it to typescript?

Anyway sorry for the 'many issues one report' :D

Does CSG support planes?

I use a "planes" to interact with a "box", but it return wrong geometry. Does the CSG support planes like mesh, not a solid mesh.

subtract() and intersect() are swapped in some operations

Hola! πŸ™‚

I have noticed that in some operations the subtract() and intersect() are swapped. This means that even though I am using operand1.subtract(operand2), the result is the intersection of both geometries. If I do operand1.intersect(operand2), the result is the difference.

I am using this for the Three.js IFC Loader. The vast majority of the boolean operations are simple parallelepiped (subtracting the opening of a window or a door). For example (wall and windows/doors are separated; the openings need to be applied only on the walls):

image

If I make the volumes I am using for the operations visible:

image

As said, it works fine in the majority of the cases. But I have come across a door with an opening that is a bit more complex, but still quite simple (a sliding door):

image

What you see in the image is the volume that needs to be subtracted overlapped with the result; so, it has made an intersect operation. If I change subtract() by intersect(), the result is a subtraction (what I want):

image
image

Do you know what might be causing this? Thank you in advance!

[question]: Getting position information and UV coordinates for the intersection of meshes

Hi Manthrax!

I've been looking into how meshes intersect and discovered this library. I wanted to use the intersection of two meshes to update a UV map and apply a dot texture by intersecting a sphere with a really complicated and unpredictably shaped mesh.

I was wondering if it was possible to get the coordinates and/or UV coordinates of the result of the intersection operation on the surface of the target mesh, but not turn that intersection into a mesh or add it to the scene, just to use that information for texture mapping purposes, that could be used to index position information and UV information on the target mesh?

thank you for reading, please let me know if you have any guidance on this

Material Groups

I'm trying to figure out material groups.

If I subtract B from A, I'd like A to retain it's material however apply the material from B along the intersection, resulting in 2 materials on the new mesh.

I had a look at CSGStress.html but it shows a torus and not the screenshot shown in your readme.

Any thoughts on how I can achieve this? I've tried passing an array of materials, but the mesh "disappears" if I try this method.

Thanks in advance.

ConeGeometry / LatheGeometry incorrect result

intersecting a box with a cone results in a slice of the surface of the cone instead of a solid object
I did not test cone , only test LatheGeometry.

CSG.toMesh(
    CSG.fromMesh(A).intersect(CSG.fromMesh(B)),
    A.matrix,
    A.material
 );

giladdarshan suggest change Line #73 to

return CSG.fromPolygons(polys.filter(p=>!isNaN(p.plane.normal.x)));

This issue still exists , subtract and union both return partial of the LatheGeometry , intersect returns something close to A-B but not exactly A-B

Do multiple substract on 1 Mesh

Hello

Can i do multiple substracts on 1 Mesh?
When i substract multiple Meshs from one Mesh i received corrupted Meshs?
How can i substract multipletime one Mesh?

In my sample the resulting mesh is devided in two, after than i do a second substract, the resulting mesh is corrupt.

Thanks

ExtrudeGeometry can't be correctlly processed by csg

  const path = new THREE.Path()
  path.add(new THREE.LineCurve3(new THREE.Vector3(0, 0, 0), new THREE.Vector3(200, 0, 350)))
  
  const shape = new THREE.Shape();
  shape.moveTo(-50, 50);
  shape.lineTo(-50, -50);
  shape.lineTo(50, -50);
  shape.lineTo(50, 50);
  shape.lineTo(-50, 50);

  const shape2 = new THREE.Shape();
  shape2.moveTo(-55, 55);
  shape2.lineTo(-55, -55);
  shape2.lineTo(55, -55);
  shape2.lineTo(55, 55);
  shape2.lineTo(-55, 55);

  const extrudeSettings = {
    depth: 100,
    extrudePath: path,
  }
  const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
  const geometry2 = new THREE.ExtrudeGeometry(shape2, extrudeSettings);

  const csg1 = ThreeCSG.fromGeometry(geometry);
  const csg2 = ThreeCSG.fromGeometry(geometry2);
  const csg = csg2.subtract(csg1);

  const material = new THREE.MeshPhongMaterial({
    color: 0x999999,
  });

  const mesh = new THREE.Mesh(ThreeCSG.toGeometry(csg), material);
  scene.add(mesh)

I want to use extrudeGeometry and ThreeCSG to make tunnel. So I made two shape, one is bigger than the other. And I extrude them with a single path. After that i subtract the smaller geometry from the bigger one.
But the result is not correct.
extrudeCsg

If i change end vector of the paht to (200, 0 ,300),the result is ok.
I don't know what happend.

TypeError: cannot read property array of undefined in fromGeometry of a custom geometry

I have a simple custom geometry created by setting an array of vertices to a BufferGeometry like this:

  const geometry = new THREE.BufferGeometry();
  geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
  geometry.computeVertexNormals();

This renders just fine, but when I try to create a BSP from the mesh I get a TypeError as below, and I don't know where to go from here to get it working. Any clues much appreciated!

demo: https://codesandbox.io/s/manthrax-crash-jm533?file=/src/App.js:2576-2732

TypeError
Cannot read property 'array' of undefined

Function._csgLib.CSG.fromGeometry
/src/three-csg.js:60:25
  57 | const nx = normalattr.array[vp];
  58 | const ny = normalattr.array[vp + 1];
  59 | const nz = normalattr.array[vp + 2];
> 60 | const u = uvattr.array[vt];
     |                 ^
  61 | const v = uvattr.array[vt + 1];
  62 | vertices[j] = new Vertex(
  63 |   {

View compiled
Function._csgLib.CSG.fromMesh
/src/three-csg.js:94:18
  91 | const ttvv0 = new THREE.Vector3();
  92 | const tmpm3 = new THREE.Matrix3();
  93 | CSG.fromMesh = function (mesh, objectIndex) {
> 94 |   const csg = CSG.fromGeometry(mesh.geometry, objectIndex);
     |                  ^
  95 |   tmpm3.getNormalMatrix(mesh.matrix);
  96 |   for (let i = 0; i < csg.polygons.length; i++) {
  97 |     const p = csg.polygons[i];

Subtract from mesh, without closing the mesh?

In the example I see so far, subtracting a mesh causes the remaining mesh to be closed off. Is it possible to do the subtraction, but without closing the mesh that was subtracted from?

Not working with imported STL files.

Thanks for your awesome code! It works great with meshes that I create in code, however i'm having an issue getting it to work with meshes that are made from imported STL files.

I’m using this STL loader that is included in the same version of three.js that you are using but im getting this error:

Uncaught TypeError: Cannot read properties of undefined (reading 'x')

It seems to be running into a problem on line 21 of three-csg.js, right here:

vertices.push(new Vertex(vs[f[fm[j]]],f.vertexNormals[j],geom.faceVertexUvs[0][i][j]))

I was previously using ThreeCSG from Chandler Prall with this same STL loader and didn't have any issues. I upgraded to your code because of the update matrix feature but now I can't work with my imported STLs. 😭

Any ideas how we could fix this?

Problem with Rotation

Hello,

i have a problem with substract, union an intersect when the parent Groups of a mesh are rotated.
The position of the meshs in World are not apply before doing the substract.

Please view my code Sample:

`
private csgSample(){

var scene = this.baseScene.scene;


const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000

)
camera.position.x = 0.5
camera.position.y = 2
camera.position.z = 2.5
camera.up.set(0, 0, 1);

this.baseScene.camera = camera;
this.baseScene.controls = new OrbitControls(camera, this.baseScene.renderer.domElement);

  //create a cube and sphere and intersect them
  const cubeMesh = new THREE.Mesh(
    new THREE.BoxGeometry(2, 2, 2),
    new THREE.MeshPhongMaterial({ color: 0xff0000,
      opacity: 0.5,
      transparent:true, })
)
const sphereMesh = new THREE.Mesh(
    new THREE.SphereGeometry(1.45, 8, 8),
    new THREE.MeshPhongMaterial({ color: 0x0000ff ,
      opacity: 0.5,
      transparent:true,})
)

var g = new THREE.Group();
g.position.set(0.5, 0, 0.5);
g.rotation.x = 15;
cubeMesh.position.set(0, 0, 1);
g.add(cubeMesh);
scene.add(g)

sphereMesh.position.set(0, 0, 0)
scene.add(sphereMesh)

scene.updateMatrix();
scene.updateMatrixWorld(true);

var meshResult  = CSG.subtract( cubeMesh, sphereMesh);

meshResult.material = new THREE.MeshPhongMaterial({
    color: 0xff00ff
})
//g.add(meshResult);
meshResult.position.set(0, 0, -5)
scene.add(meshResult)

scene.updateMatrix();
scene.updateMatrixWorld(true);

}
`
image

What i doing wrong?

Thanks

Improving Performance

Hello,

I've been learning how THREE-CSGMesh works in an attempt to improve the performance when dealing with a large number of objects.
As an example, making 14 holes in a plate/cube (as shown below), with the current subtract function, it will need to create a total of ~28 BSP trees (a/b nodes in the function).
2022-02-09_00-36-41

By adding support for an array of CSG objects, I'm able to cut down the total operation time from ~1.9 seconds to ~0.21 seconds as it only creates ~15 BSP trees for the above example:

    subtract(csg) {
        let a = new Node(this.clone().polygons);
        a.invert();
        if (csg.isCSG) {
            csg = [csg];
        }
        for (let i = 0; i < csg.length; i++) {
            let b = new Node(csg[i].clone().polygons);
            a.clipTo(b);
            b.clipTo(a);
            b.invert();
            b.clipTo(a);
            b.invert();
            a.build(b.allPolygons());
        }
        a.invert();
        return CSG.fromPolygons(a.allPolygons());
    }

What are your thoughts on this? are there any downsides I'm not seeing?

Thanks,
Gilad

Stuck on Any Operation between two STL files

When I use one STL file and one any three js geometry then all operations are performed but when I use both STL files then not any error comes but web page going to stuck not perform any action. issue is when two STL files used and any operation is performed it goes stuck not perform further any work it looks like as it goes an unlimited loop that not beaks and not return from. You have any solution. Please tell me urgently.

The issue doesn't work to make a hole in a plane

Hi

Thank you for your CSGMesh. I have one problem in CSG-the "subtract" operation. One I tried to make a hole in the plane, I got the problem. The problem is that after the operation, part of the cube is attached to the plane. Please take a look at the screenshots

image

image

I want to get the result like the image below(I used the Boolean object in 3dsMax)
image

Can you resolve the issue?

Thank you

Face of mesh missing after subtraction

Hello!

First of all, congratulations for the library, it is really fast, efective and easy to use.

I am using this library to perform the boolean operations in the ifc loader and viewer I am developing for Three.js. IFC is the format used by architects / engineers to store building models.

Today I have faced a strange issue. I am developing the doors; each door has an associated bounding box (a simple parallelepiped volume) that is used to create the whole in the wall. I have tested and it works perfectly in most walls, but I have come across a wall that does not perform as expected; one of it's faces is eliminated after the boolean operation.

This is strange, because all the walls are extrusions created with the same function (they are a simple Three.js extrusion). I am digging into the geometry of this specific wall, but it looks identical to the others. If you have any idea why this might be happening (normals, vertex, matrices, etc), I may well find the issue investigating in that direction.

You can observe the missing face in the two images below. In the first image, the wall of the right is missing the face closer to the camera, so the inner sides are visible. The other face has inverted normals, but is still there. In the second picture the remaining face is not visible due to backface culling; only the inner sides are visible.

Thank you in advance!

1
2

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.