首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用ThreeCSG的意外结果

使用ThreeCSG的意外结果
EN

Stack Overflow用户
提问于 2017-12-14 17:47:52
回答 1查看 450关注 0票数 2

我正在试验ThreeCSG库,并试图将球体或法线几何替换为定制的形状,在本例中是3js示例中的心脏形状。

不幸的是,我在面对镜头的一侧得到了一个奇怪的结果。下面是一个代码示例:

代码语言:javascript
复制
(function onLoad() {
  var container, camera, scene, renderer;
  var grey = 0xD3D3D3;
  
  init();
  animate();

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

		createHeartMesh();
    createDieCutHandle();
    
    // Creates a CSG cut on the cube based on the passed mesh
    createCSGDiecutHandle();
  }

  function createDieCutHandle() {
    var cubeGeo = new THREE.CubeGeometry(250, 250, 250);
    var mesh = new THREE.Mesh(cubeGeo)
    mesh.position.x = -500;
    scene.add(mesh);
  }
  
  function createCSGDiecutHandle() {
  	var cubeGeo = new THREE.CubeGeometry(250, 250, 250);
    var cubeMesh = new THREE.Mesh(cubeGeo);
    var cubeBSP = new ThreeBSP(cubeMesh);
   
    // Need geometry of the mesh to cut
    var heartShape = getHeartShape();
    var heartGeo = getHeartGeometry(heartShape);
    var meshToCut =  new THREE.Mesh( heartGeo );
    meshToCut.scale.set(10,10,10);
    meshToCut.position.z -= 80;
    var meshToCutBsp = new ThreeBSP(meshToCut)
   
    // var resultBsp = cubeBSP.union(meshToCutBsp);
    var resultBsp = cubeBSP.subtract(meshToCutBsp);
    // var resultBsp = cubeBSP.intersect(meshToCutBsp);
		
    var resultMesh = resultBsp.toMesh(new THREE.MeshLambertMaterial({flatShading: true}));
    resultMesh.geometry.computeVertexNormals();
    scene.add(resultMesh);
  }

	function getHeartShape() {
  	var x = 5, y = 10;
    var heartShape = new THREE.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);
    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;
  }
  
  function getHeartGeometry(heartShape) {
  	var extrudeSettings = {
      steps: 2,
      amount: 16,
      bevelEnabled: true,
      bevelThickness: 5,
      bevelSize: 1,
      bevelSegments: 1
    };
		return new THREE.ExtrudeBufferGeometry( heartShape, extrudeSettings );
  }

  function createHeartMesh() {
    var heartShape = getHeartShape();
		var geometry = getHeartGeometry(heartShape);
    var material = new THREE.MeshNormalMaterial();
    var mesh = new THREE.Mesh(geometry, material);
    mesh.position.x = -500;
    mesh.position.z = -80;
    mesh.scale.set(10, 10, 10);
    
    scene.add(mesh);
  }
  
  /**** Helper functions ****/
  function computeBoundingBox(mesh) {
    var box = new THREE.Box3().setFromObject(mesh);
    var size = box.getSize();

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

  /**** Basic Scene Setup ****/
  function initScene() {
    scene = new THREE.Scene();
    scene.background = new THREE.Color(0xffffff);
  }

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

  function addGridHelper() {
    var planeGeometry = new THREE.PlaneGeometry(2000, 2000);
    planeGeometry.rotateX(-Math.PI / 2);

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

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

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

  function addLighting() {
    addHemisphereLight();
  }

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

  function addAmbientLight() {
    var ambientLight = new THREE.AmbientLight(0x404040);
    scene.add(ambientLight);
  }

  function addHemisphereLight() {
    var hemisphereLight = new THREE.HemisphereLight(0xffffbb, 0x080820, 1);
    scene.add(hemisphereLight);
  }

  function addRenderer() {
    renderer = new THREE.WebGLRenderer({
      antialias: true
    });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    container.appendChild(renderer.domElement);
  }

  function addOrbitControls() {
    var controls = new THREE.OrbitControls(camera, renderer.domElement);
  }

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

  function render() {
    renderer.render(scene, camera);
  }
})();
代码语言:javascript
复制
body {
  background: transparent;
  padding: 0;
  margin: 0;
  font-family: sans-serif;
}

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

左边的立方体只是一个从立方体内部凸出的心脏几何图形--它们不是连接在一起的,它们只是有着相同的位置。

右边的是左的CSG版本,但我试图从立方体中减去心脏。面对镜头的那一面是错误的,因为网眼的那一边似乎在往下渗出,而后面的那一边,如果你看过去的话,是非常好的。

是什么导致了这种行为?我尝试添加属性side: THREE.DoubleSide,但是它没有解决这个问题。

我也看了这个问题,这里,并尝试调用updateMatrix()的心脏网格,但它没有影响。

谢谢

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-12-19 18:35:31

ThreeCSG不能正确地减去凹面网格。但有一个解决办法,因为两半的心脏或凸起。

你可以从长方体中减去心脏的右半部分:

代码语言:javascript
复制
function getHeartShapeRight() {
    var x = 5, y = 10;
    var heartShape = new THREE.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;
}
代码语言:javascript
复制
// right cuboid
var cubeGeoR = new THREE.CubeGeometry(125, 250, 250);
var cubeMeshR = new THREE.Mesh(cubeGeoR);
cubeMeshR.position.x += 62.5;
var cubeBSPR = new ThreeBSP(cubeMeshR);

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

// right subtract
var meshToCutBspR = new ThreeBSP(meshToCutR);
var resultBspR = cubeBSPR.subtract(meshToCutBspR);
var resultMeshR = resultBspR.toMesh(new THREE.MeshLambertMaterial({flatShading: true}));

你可以从长方体中减去心脏的左半部分:

代码语言:javascript
复制
function getHeartShapeLeft() {
    var x = 5, y = 10;
    var heartShape = new THREE.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;
}
代码语言:javascript
复制
// left cuboid
var cubeGeoL = new THREE.CubeGeometry(125, 250, 250);
var cubeMeshL = new THREE.Mesh(cubeGeoL);
cubeMeshL.position.x -= 62.5;
var cubeBSPL = new ThreeBSP(cubeMeshL);

// left part of the heart
var heartShapeL = getHeartShapeLeft();
var heartGeoL = getHeartGeometry(heartShapeL);
var meshToCutL = new THREE.Mesh( heartGeoL );
meshToCutL.scale.set(10,10,10);
meshToCutL.position.z -= 80;
var meshToCutBspL = new ThreeBSP(meshToCutL);

// left subtract
var meshToCutBspL = new ThreeBSP(meshToCutL);
var resultBspL = cubeBSPL.subtract(meshToCutBspL);
var resultMeshL = resultBspL.toMesh(new THREE.MeshLambertMaterial({flatShading: true}));

最后,您可以创建一个由两个部分组成的联盟:

代码语言:javascript
复制
// union of left an right half
var unionBsp = resultBspL.union(resultBspR);
var unionMesh = unionBsp.toMesh(new THREE.MeshLambertMaterial({flatShading: true}));
scene.add(unionMesh);

请参阅代码片段:

代码语言:javascript
复制
(function onLoad() {
  var container, camera, scene, renderer;
  var grey = 0xD3D3D3;
  
  init();
  animate();

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

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

  function createCSGDiecutHandle() {

    // left cuboid
    var cubeGeoL = new THREE.CubeGeometry(125, 250, 250);
    var cubeMeshL = new THREE.Mesh(cubeGeoL);
    cubeMeshL.position.x -= 62.5;
    var cubeBSPL = new ThreeBSP(cubeMeshL);
   
    // left part of the heart
    var heartShapeL = getHeartShapeLeft();
    var heartGeoL = getHeartGeometry(heartShapeL);
    var meshToCutL = new THREE.Mesh( heartGeoL );
    meshToCutL.scale.set(10,10,10);
    meshToCutL.position.z -= 80;
    var meshToCutBspL = new ThreeBSP(meshToCutL);

    // left subtract
    var meshToCutBspL = new ThreeBSP(meshToCutL);
    var resultBspL = cubeBSPL.subtract(meshToCutBspL);
    var resultMeshL = resultBspL.toMesh(new THREE.MeshLambertMaterial({flatShading: true}));

    // right cuboid
    var cubeGeoR = new THREE.CubeGeometry(125, 250, 250);
    var cubeMeshR = new THREE.Mesh(cubeGeoR);
    cubeMeshR.position.x += 62.5;
    var cubeBSPR = new ThreeBSP(cubeMeshR);

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

  function getHeartShapeRight() {
    var x = 5, y = 10;
    var heartShape = new THREE.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;
  }

  function getHeartShapeLeft() {
    var x = 5, y = 10;
    var heartShape = new THREE.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;
  }

  function getHeartGeometry(heartShape) {
    var extrudeSettings = {
      steps: 2,
      amount: 16,
      bevelEnabled: true,
      bevelThickness: 5,
      bevelSize: 1,
      bevelSegments: 1
    };
        return new THREE.ExtrudeBufferGeometry( heartShape, extrudeSettings );
  }

  /**** Helper functions ****/
  function computeBoundingBox(mesh) {
    var box = new THREE.Box3().setFromObject(mesh);
    var size = box.getSize();

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

  /**** Basic Scene Setup ****/
  function initScene() {
    scene = new THREE.Scene();
    scene.background = new THREE.Color(0xffffff);
  }

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

  function addGridHelper() {
    var planeGeometry = new THREE.PlaneGeometry(2000, 2000);
    planeGeometry.rotateX(-Math.PI / 2);

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

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

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

  function addLighting() {
    addHemisphereLight();
  }

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

  function addAmbientLight() {
    var ambientLight = new THREE.AmbientLight(0x404040);
    scene.add(ambientLight);
  }

  function addHemisphereLight() {
    var hemisphereLight = new THREE.HemisphereLight(0xffffbb, 0x080820, 1);
    scene.add(hemisphereLight);
  }

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

  function addOrbitControls() {
    var controls = new THREE.OrbitControls(camera, renderer.domElement);
  }

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

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

  function render() {
    renderer.render(scene, camera);
  }
})();
代码语言:javascript
复制
body {
  background: transparent;
  padding: 0;
  margin: 0;
  font-family: sans-serif;
}

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47819331

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档