0

我正在尝试创建一个适合管道领域的 T 恤。它由 2 个合并在一起的管子组成,并有 3个开口,如图所示。

我在threejs中编写了一些代码,我试图创建一个管网1和另一个管网2,然后尝试将它们与库@enable3d/three-graphics/jsm/csg联合到mesh3中——感谢@Marquizzo。使用函数 CSG.union 并将网格添加到场景中后,我可以看到我得到了一个 T 形球,但它还在几何 1 中创建了一个洞,这是意料之外的。您可以在此处看到正确孔(绿色)和错误创建孔(红色)的图片:

这个

相反,它应该看起来像这样,并且是一个几何图形。

在此处输入图像描述

谁能告诉我 CSG 是如何工作的以及为什么我在第一个几何图形的背面有一个额外的孔?

import React, { Component } from 'react';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { CSG } from '@enable3d/three-graphics/jsm/csg';

export default class TubeViewer extends Component {
    componentDidMount() {
        //Add Scene
        this.scene = new THREE.Scene();

        //Add Renderer
        this.renderer = new THREE.WebGLRenderer({ antialias: true });
        this.renderer.setClearColor('#808080');
        this.renderer.shadowMap.enabled = true;
        this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
        this.renderer.setPixelRatio(window.devicePixelRatio);
        this.renderer.setSize(window.innerWidth, window.innerHeight);
        this.mount.appendChild(this.renderer.domElement);

        //Add Camera
        const fov = 60;
        const aspect = window.innerWidth / window.innerHeight;
        const near = 1.0;
        const far = 1000.0;
        this.camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
        this.camera.position.set(1, aspect, 1, 1000);


        //Tee-piece

        const curve1 = new THREE.LineCurve(new THREE.Vector3(2, 0, 0), new THREE.Vector3(2, 0, 0.1));
        const curve11 = new THREE.LineCurve(new THREE.Vector3(2.0, 0, 0.05), new THREE.Vector3(2.05, 0, 0.05));

        const geometry1 = new THREE.TubeGeometry(curve1, 20, 0.025, 8, false);
        const geometry2 = new THREE.TubeGeometry(curve2, 20, 0.025, 8, false);

        const material = new THREE.MeshBasicMaterial({ color: '#C0C0C0' });

        const mesh1 = new THREE.Mesh(geometry1, material);
        const mesh2 = new THREE.Mesh(geometry2, material);

        const mesh3 = CSG.union(mesh1, mesh2);

        this.scene.add(mesh3);


        //Add raycaster to for interactivity
        this.raycaster = new THREE.Raycaster();
        this.mouse = new THREE.Vector2();

        this.renderer.domElement.addEventListener('click', onClick.bind(this), false);

        function onClick(event) {
            event.preventDefault();

            this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
            this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

            this.raycaster.setFromCamera(this.mouse, this.camera);

            var intersects = this.raycaster.intersectObjects(this.scene.children, true);

            if (intersects.length > 0) {
                console.log('Intersection:', intersects[0]);
                //console.log(intersects[0].object.uuid);
                // console.log(`GUID: ${intersects[0]}`);
                let object = intersects[0].object;

                object.material.color.set(Math.random() * 0xffffff);
            }
        }

        //Settings
        //Add Camera Controls
        const controls = new OrbitControls(this.camera, this.renderer.domElement);
        controls.addEventListener('change', this.render); // use if there is no animation loop
        controls.minDistance = 2;
        controls.maxDistance = 10;
        controls.target.set(0, 0, -0.2);
        controls.update();

        ///Add AMBIENT LIGHT
        let light = new THREE.DirectionalLight(0xffffff, 1.0);
        light.position.set(20, 100, 10);
        light.target.position.set(0, 0, 0);
        light.castShadow = true;
        light.shadow.bias = -0.001;
        light.shadow.mapSize.width = 2048;
        light.shadow.mapSize.height = 2048;
        light.shadow.camera.near = 0.1;
        light.shadow.camera.far = 500.0;
        light.shadow.camera.near = 0.5;
        light.shadow.camera.far = 500.0;
        light.shadow.camera.left = 100;
        light.shadow.camera.right = -100;
        light.shadow.camera.top = 100;
        light.shadow.camera.bottom = -100;
        this.scene.add(light);
        light = new THREE.AmbientLight(0xffffff, 0.7);
        this.scene.add(light);

        //Start animation
        this.start();
    }

    //Unmount when animation has stopped
    componentWillUnmount() {
        this.stop();
        this.mount.removeChild(this.renderer.domElement);
    }

    //Function to start animation
    start = () => {
        //Rotate Models
        if (!this.frameId) {
            this.frameId = requestAnimationFrame(this.animate);
        }
    };

    //Function to stop animation
    stop = () => {
        cancelAnimationFrame(this.frameId);
    };

    //Animate models here
    animate = () => {
        //ReDraw scene with camera and scene object
        if (this.cubeMesh) this.cubeMesh.rotation.y += 0.01;
        this.renderScene();
        this.frameId = window.requestAnimationFrame(this.animate);
    };

    //Render the scene
    renderScene = () => {
        if (this.renderer) this.renderer.render(this.scene, this.camera);
    };

    render() {
        return (
            <div
                style={{ width: '800px', height: '800px' }}
                ref={(mount) => {
                    this.mount = mount;
                }}
            />
        );
    }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

enter code here?

4

1 回答 1

0

对于 CSG,您将需要实体。这些管子是打开的。

我创建了一个使用圆柱体的示例(管子用于盖帽),因此您可以对其进行测试。

这些气缸是开放式的,因此它们的失效方式与您的管相同。 https://codepen.io/flatworldstudio/pen/bGBjmrP

 const geometry1 = new THREE.CylinderGeometry(0.1, 0.1, 0.5, 20, 1, true);

这些已关闭,CSG 按预期工作。 https://codepen.io/flatworldstudio/pen/VwmBRoL

const geometry1 = new THREE.CylinderGeometry(0.1, 0.1, 0.5, 20, 1, false);

(我使用的是不同版本的 CSG,但它们似乎都建立在相同的代码上)

于 2021-03-05T14:35:05.450 回答