Using ThreeCSG with BufferGeometry is giving me weird results

geometry
csg
#1

When trying to subtract or union two meshes ( TextGeometry and BufferGeometry), result meshes have missing faces and opposite results, I am using ThreeCSG that supposedly support buffer geometry, I tried converting to normal Geometry and results were the same.
Union:


Subtract:

Here is my code:

async function addObject(values, step, heightScale, offset) {
  var depth = 8;
 
  var geometry = new THREE.BufferGeometry();

  values.unshift(0);
  values.push(0);

  var positions = [];

  for (var i = 0; i < values.length - 1; i++) {
    //back
    positions.push(i * step, 0, 0);
    positions.push(i * step, values[i] * heightScale + offset, 0);
    positions.push((i + 1) * step, values[i + 1] * heightScale + offset, 0);

    positions.push(i * step, 0, 0);
    positions.push((i + 1) * step, values[i + 1] * heightScale + offset, 0);
    positions.push((i + 1) * step, 0, 0);

    //front
    positions.push((i + 1) * step, values[i + 1] * heightScale + offset, depth);
    positions.push(i * step, values[i] * heightScale + offset, depth);
    positions.push(i * step, 0, depth);

    positions.push((i + 1) * step, values[i + 1] * heightScale + offset, depth);
    positions.push((i + 1) * step, 0, depth);
    positions.push(i * step, 0, depth);

    //top
    positions.push(i * step, values[i] * heightScale + offset, 0);
    positions.push(i * step, values[i] * heightScale + offset, depth);
    positions.push((i + 1) * step, values[i + 1] * heightScale + offset, 0);

    positions.push((i + 1) * step, values[i + 1] * heightScale + offset, 0);
    positions.push(i * step, values[i] * heightScale + offset, depth);
    positions.push((i + 1) * step, values[i + 1] * heightScale + offset, depth);

    //bottom
    positions.push(i * step, 0, depth);
    positions.push((i + 1) * step, 0, 0);
    positions.push(i * step, 0, 0);

    positions.push((i + 1) * step, 0, 0);
    positions.push(i * step, 0, depth);
    positions.push((i + 1) * step, 0, depth);
  }

  // itemSize = 3 because there are 3 values (components) per vertex
  geometry.addAttribute(
    "position",
    new THREE.Float32BufferAttribute(positions, 3)
  );

  geometry.computeVertexNormals();

  var material = new THREE.MeshPhongMaterial({
    color: new THREE.Color(0x00ff00),
    shininess: 66,
    opacity: 1,
    transparent: true,
    side: THREE.DoubleSide
  });

  
  //var geometry = new THREE.Geometry().fromBufferGeometry(geometry);
  //geometry.mergeVertices();
  var mesh = new THREE.Mesh(geometry, material);

  return mesh;
}


async function addText(mesh, textLocal, depth, textSize, type, x, y, z) {
  var font = await loadFont("assets/font2.json");
  
  var mesh_bsp = new ThreeBSP(mesh);
  var textGeo = new THREE.TextGeometry(textLocal, {
    size: textSize,
    height: depth,
    curveSegments: 6,
    font: font 
  });

  var text = new THREE.Mesh(textGeo, g_material);
  text.geometry.applyMatrix(new THREE.Matrix4().makeTranslation(x, y, z));

  var text_bsp = new ThreeBSP(text);
  if (type == "subtract") {
    var subtract_bsp = mesh_bsp.subtract(text_bsp);
  } else {
    var subtract_bsp = mesh_bsp.union(text_bsp);
  }
  result = subtract_bsp.toMesh(g_material);
  
  return result;
}

I get diffrent results if I uncomment this two lines:
//var geometry = new THREE.Geometry().fromBufferGeometry(geometry); //geometry.mergeVertices();

Results look like that:
Union:
unionGeo
Subtract front:
subtractGeo
Subtract back:


Any ideas what I am missing?

#2

It looks like the repo you linked to hasn’t been updated since 2017 and probably no longer works with the latest versions of Three.js

I know @manthrax worked on an update to work with more recent versions of Three.js Have you taken a look at his updated version? https://github.com/manthrax/THREE-CSGMesh

2 Likes
#3

Thank you for help. Tested it out and I get same results. No faces are added.
newCsg

#4

Have you considered to post a feature request or bug report at the respective repositories at github? I think the creators of the library can help best.

1 Like
#5

@TimToplak What does your initial geometry look like before you perform the boolean operation? Is your mesh non-manifold?

2 Likes
#6

Yep that was it, thank you! After removing this two lines, that I know that were creating non-manifold and manually adding faces for stard and end:

  values.unshift(0);
  values.push(0);

I saw much better improvements, some of the faces were added, but not all. After that I exported the mesh as *.stl and imported it in Blender to see, where more of non-monifolds causes can be. After a bit of playing around I found out that positions of vertexes pushed to positions array matter.


Code after switching positions:

async function addObject(values, step, heightScale, offset) {
  
  var geometry = new THREE.BufferGeometry();

  var positions = [];

  positions.push(0, 0, 0);
  positions.push(0, values[0] * heightScale + offset, depth);
  positions.push(0, values[0] * heightScale + offset, 0);

  positions.push(0, 0, 0);
  positions.push(0, 0, depth);
  positions.push(0, values[0] * heightScale + offset, depth);

  for (var i = 0; i < values.length - 1; i++) {
    //back
    positions.push(i * step, 0, 0);
    positions.push(i * step, values[i] * heightScale + offset, 0);
    positions.push((i + 1) * step, values[i + 1] * heightScale + offset, 0);

    positions.push(i * step, 0, 0);
    positions.push((i + 1) * step, values[i + 1] * heightScale + offset, 0);
    positions.push((i + 1) * step, 0, 0);

    //front
    positions.push((i + 1) * step, values[i + 1] * heightScale + offset, depth);
    positions.push(i * step, values[i] * heightScale + offset, depth);
    positions.push(i * step, 0, depth);

    positions.push((i + 1) * step, values[i + 1] * heightScale + offset, depth);
    positions.push(i * step, 0, depth);
    positions.push((i + 1) * step, 0, depth);

    //top
    positions.push(i * step, values[i] * heightScale + offset, 0);
    positions.push(i * step, values[i] * heightScale + offset, depth);
    positions.push((i + 1) * step, values[i + 1] * heightScale + offset, 0);

    positions.push((i + 1) * step, values[i + 1] * heightScale + offset, 0);
    positions.push(i * step, values[i] * heightScale + offset, depth);
    positions.push((i + 1) * step, values[i + 1] * heightScale + offset, depth);

    //bottom
    positions.push(i * step, 0, depth);
    positions.push(i * step, 0, 0);
    positions.push((i + 1) * step, 0, 0);

    positions.push(i * step, 0, depth);
    positions.push((i + 1) * step, 0, 0);
    positions.push((i + 1) * step, 0, depth);
  }

  positions.push((values.length - 1) * step, 0, 0);
  positions.push(
    (values.length - 1) * step,
    values[values.length - 1] * heightScale + offset,
    0
  );
  positions.push(
    (values.length - 1) * step,
    values[values.length - 1] * heightScale + offset,
    depth
  );

  positions.push((values.length - 1) * step, 0, 0);
  positions.push(
    (values.length - 1) * step,
    values[values.length - 1] * heightScale + offset,
    depth
  );
  positions.push((values.length - 1) * step, 0, depth);

  // itemSize = 3 because there are 3 values (components) per vertex
  geometry.addAttribute(
    "position",
    new THREE.Float32BufferAttribute(positions, 3)
  );

  geometry.computeVertexNormals();

  var material = new THREE.MeshPhongMaterial({
    color: new THREE.Color(0x00ff00),
    shininess: 66,
    opacity: 1,
    transparent: true,
    side: THREE.DoubleSide
  });

  var geometry = new THREE.Geometry().fromBufferGeometry(geometry);
  geometry.mergeVertices();
  assignUVs(geometry);
  var mesh = new THREE.Mesh(geometry, material);

  return mesh;
}

1 Like
#7

Haha! You’re welcome.