Skip to content Skip to sidebar Skip to footer

Unexpected Result Using Threecsg

I'm experimenting with the ThreeCSG library and am attempting to swap out the sphere or normal geometry for a custom made Shape, in this case the heart shape from the 3js examples.

Solution 1:

ThreeCSG cannot subtract a concave mesh correctly. But there is a workaround, since both halves of a heart or convex.

You can subtract the right half of the heart from a cuboid:

functiongetHeartShapeRight() {
    var x = 5, y = 10;
    var heartShape = newTHREE.Shape();
    heartShape.moveTo(x - 5, y - 5);
    heartShape.bezierCurveTo(x - 5, y - 5, x - 4, y, x, y);
    heartShape.bezierCurveTo(x + 6, y, x + 6, y - 7, x + 6, y - 7);
    heartShape.bezierCurveTo(x + 6, y - 11, x + 3, y - 15.4, x - 5, y - 19);
    return heartShape;
}
// right cuboidvar cubeGeoR = newTHREE.CubeGeometry(125, 250, 250);
var cubeMeshR = newTHREE.Mesh(cubeGeoR);
cubeMeshR.position.x += 62.5;
var cubeBSPR = newThreeBSP(cubeMeshR);

// right part of the heartvar heartShapeR = getHeartShapeRight();
var heartGeoR = getHeartGeometry(heartShapeR);
var meshToCutR = newTHREE.Mesh( heartGeoR );
meshToCutR.scale.set(10,10,10);
meshToCutR.position.z -= 80;

// right subtractvar meshToCutBspR = newThreeBSP(meshToCutR);
var resultBspR = cubeBSPR.subtract(meshToCutBspR);
var resultMeshR = resultBspR.toMesh(newTHREE.MeshLambertMaterial({flatShading: true}));

And you can subtract the left half of the heart from a cuboid:

functiongetHeartShapeLeft() {
    var x = 5, y = 10;
    var heartShape = newTHREE.Shape();
    heartShape.moveTo(x - 5, y - 19);
    heartShape.bezierCurveTo(x - 12, y - 15.4, x - 16, y - 11, x - 16, y - 7);
    heartShape.bezierCurveTo(x - 16, y - 7, x - 16, y, x - 10, y);
    heartShape.bezierCurveTo(x - 7, y, x - 5, y - 5, x - 5, y - 5);
    return heartShape;
}
// left cuboidvar cubeGeoL = newTHREE.CubeGeometry(125, 250, 250);
var cubeMeshL = newTHREE.Mesh(cubeGeoL);
cubeMeshL.position.x -= 62.5;
var cubeBSPL = newThreeBSP(cubeMeshL);

// left part of the heartvar heartShapeL = getHeartShapeLeft();
var heartGeoL = getHeartGeometry(heartShapeL);
var meshToCutL = newTHREE.Mesh( heartGeoL );
meshToCutL.scale.set(10,10,10);
meshToCutL.position.z -= 80;
var meshToCutBspL = newThreeBSP(meshToCutL);

// left subtractvar meshToCutBspL = newThreeBSP(meshToCutL);
var resultBspL = cubeBSPL.subtract(meshToCutBspL);
var resultMeshL = resultBspL.toMesh(newTHREE.MeshLambertMaterial({flatShading: true}));

Finally you can create a union of both halves:

// union of left an right halfvar unionBsp = resultBspL.union(resultBspR);
var unionMesh = unionBsp.toMesh(newTHREE.MeshLambertMaterial({flatShading: true}));
scene.add(unionMesh);

See the code snippet:

(functiononLoad() {
  var container, camera, scene, renderer;
  var grey = 0xD3D3D3;
  
  init();
  animate();

  functioninit() {
    container = document.getElementById('container');
    initScene();
    addGridHelper();
    addCamera();
    addLighting()
    addRenderer();
    addOrbitControls();

        // Creates a CSG cut on the cube based on the passed meshcreateCSGDiecutHandle();
  }

  functioncreateCSGDiecutHandle() {

    // left cuboidvar cubeGeoL = newTHREE.CubeGeometry(125, 250, 250);
    var cubeMeshL = newTHREE.Mesh(cubeGeoL);
    cubeMeshL.position.x -= 62.5;
    var cubeBSPL = newThreeBSP(cubeMeshL);
   
    // left part of the heartvar heartShapeL = getHeartShapeLeft();
    var heartGeoL = getHeartGeometry(heartShapeL);
    var meshToCutL = newTHREE.Mesh( heartGeoL );
    meshToCutL.scale.set(10,10,10);
    meshToCutL.position.z -= 80;
    var meshToCutBspL = newThreeBSP(meshToCutL);

    // left subtractvar meshToCutBspL = newThreeBSP(meshToCutL);
    var resultBspL = cubeBSPL.subtract(meshToCutBspL);
    var resultMeshL = resultBspL.toMesh(newTHREE.MeshLambertMaterial({flatShading: true}));

    // right cuboidvar cubeGeoR = newTHREE.CubeGeometry(125, 250, 250);
    var cubeMeshR = newTHREE.Mesh(cubeGeoR);
    cubeMeshR.position.x += 62.5;
    var cubeBSPR = newThreeBSP(cubeMeshR);

    // right part of the heartvar heartShapeR = getHeartShapeRight();
    var heartGeoR = getHeartGeometry(heartShapeR);
    var meshToCutR = newTHREE.Mesh( heartGeoR );
    meshToCutR.scale.set(10,10,10);
    meshToCutR.position.z -= 80;
    
    // right subtractvar meshToCutBspR = newThreeBSP(meshToCutR);
    var resultBspR = cubeBSPR.subtract(meshToCutBspR);
    var resultMeshR = resultBspR.toMesh(newTHREE.MeshLambertMaterial({flatShading: true}));
    
    // union of left an right halfvar unionBsp = resultBspL.union(resultBspR);
    var unionMesh = unionBsp.toMesh(newTHREE.MeshLambertMaterial({flatShading: true}));
     scene.add(unionMesh);
  }

  functiongetHeartShapeRight() {
    var x = 5, y = 10;
    var heartShape = newTHREE.Shape();
    heartShape.moveTo(x - 5, y - 5);
    heartShape.bezierCurveTo(x - 5, y - 5, x - 4, y, x, y);
    heartShape.bezierCurveTo(x + 6, y, x + 6, y - 7, x + 6, y - 7);
    heartShape.bezierCurveTo(x + 6, y - 11, x + 3, y - 15.4, x - 5, y - 19);
    return heartShape;
  }

  functiongetHeartShapeLeft() {
    var x = 5, y = 10;
    var heartShape = newTHREE.Shape();
    heartShape.moveTo(x - 5, y - 19);
    heartShape.bezierCurveTo(x - 12, y - 15.4, x - 16, y - 11, x - 16, y - 7);
    heartShape.bezierCurveTo(x - 16, y - 7, x - 16, y, x - 10, y);
    heartShape.bezierCurveTo(x - 7, y, x - 5, y - 5, x - 5, y - 5);
    return heartShape;
  }

  functiongetHeartGeometry(heartShape) {
    var extrudeSettings = {
      steps: 2,
      amount: 16,
      bevelEnabled: true,
      bevelThickness: 5,
      bevelSize: 1,
      bevelSegments: 1
    };
        returnnewTHREE.ExtrudeBufferGeometry( heartShape, extrudeSettings );
  }

  /**** Helper functions ****/functioncomputeBoundingBox(mesh) {
    var box = newTHREE.Box3().setFromObject(mesh);
    var size = box.getSize();

    return {
      width: size.x,
      height: size.y,
      size: size
    }
  }

  /**** Basic Scene Setup ****/functioninitScene() {
    scene = newTHREE.Scene();
    scene.background = newTHREE.Color(0xffffff);
  }

  functionaddCamera() {
    camera = newTHREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 10000);
    camera.position.set(349.11334070460066, 405.44010726325604, 359.3111192889029);
    scene.add(camera);
  }

  functionaddGridHelper() {
    var planeGeometry = newTHREE.PlaneGeometry(2000, 2000);
    planeGeometry.rotateX(-Math.PI / 2);

    var planeMaterial = newTHREE.ShadowMaterial({
      opacity: 0.2
    });
    var plane = newTHREE.Mesh(planeGeometry, planeMaterial);
    plane.position.y = -200;
    plane.receiveShadow = true;
    scene.add(plane);

    var helper = newTHREE.GridHelper(2000, 100);
    helper.material.opacity = 0.25;
    helper.material.transparent = true;
    scene.add(helper);

    var axis = newTHREE.AxesHelper(1000);
    scene.add(axis);
  }

  functionaddLighting() {
    addHemisphereLight();
  }

  functionaddSpotLighting() {
    var light = newTHREE.SpotLight(0xffffff, 1.5);
    light.position.set(0, 1500, 200);
    light.castShadow = true;
    light.shadow = newTHREE.LightShadow(newTHREE.PerspectiveCamera(70, 1, 200, 2000));
    light.shadow.bias = -0.000222;
    light.shadow.mapSize.width = 1024;
    light.shadow.mapSize.height = 1024;
    scene.add(light);
  }

  functionaddAmbientLight() {
    var ambientLight = newTHREE.AmbientLight(0x404040);
    scene.add(ambientLight);
  }

  functionaddHemisphereLight() {
    var hemisphereLight = newTHREE.HemisphereLight(0xffffbb, 0x080820, 1);
    scene.add(hemisphereLight);
  }

  functionaddRenderer() {
    renderer = newTHREE.WebGLRenderer({
      antialias: true
    });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    container.appendChild(renderer.domElement);
    window.onresize = resize;
  }

  functionaddOrbitControls() {
    var controls = newTHREE.OrbitControls(camera, renderer.domElement);
  }

  functionresize() {
    var aspect = window.innerWidth / window.innerHeight;
    renderer.setSize(window.innerWidth, window.innerHeight);
    camera.aspect = aspect;
    camera.updateProjectionMatrix();
  }

  functionanimate() {
    requestAnimationFrame(animate);
    render();
  }

  functionrender() {
    renderer.render(scene, camera);
  }
})();
body {
  background: transparent;
  padding: 0;
  margin: 0;
  font-family: sans-serif;
}

#canvas {
  margin: 10px auto;
  width: 800px;
  height: 350px;
  margin-top: -44px;
}
<divid="container"></div><scriptsrc="https://threejs.org/build/three.js"></script><scriptsrc="https://threejs.org/examples/js/libs/dat.gui.min.js"></script><scriptsrc="https://threejs.org/examples/js/controls/OrbitControls.js"></script><scriptsrc="https://rawgit.com/Wilt/ThreeCSG/develop/ThreeCSG.js"></script><scriptsrc="https://threejs.org/examples/js/loaders/MTLLoader.js"></script><scriptsrc="https://rawgit.com/mrdoob/three.js/dev/examples/js/loaders/LoaderSupport.js"></script><scriptsrc="https://rawgit.com/mrdoob/three.js/dev/examples/js/loaders/OBJLoader2.js"></script>

Post a Comment for "Unexpected Result Using Threecsg"