React threejs объединяет две трубы, чтобы создать тройник с CSG, который не работает должным образом

Я пытаюсь создать тройник, который подходит для сантехники. Он состоит из 2 соединенных вместе трубок и имеет 3 отверстия, как показано на это изображение.

Я написал некоторый код в threejs, где я пытаюсь создать трубчатую сетку1 и другую трубчатую сетку2, а затем попытаться объединить их в сетку3 с библиотекой @enable3d/three-graphics/jsm/csg - спасибо @Marquizzo. После использования функции CSG.union и добавления сетки в сцену я вижу, что получил один тройник, но он также создал дыру в геометрии 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?


person Ali91    schedule 23.02.2021    source источник
comment
Я думаю, что вы ищете функцию CSG (Constructive Solid Geometry), которая выполняет своего рода логическую операцию для добавления/вычитания/умножения 2 или более геометрий в трехмерном пространстве. Если вы используете Three.js версии 124 или более ранней, вы можете использовать этот инструмент, но если вы используете версию 125 или более позднюю, вам нужно будет использовать этот новый инструмент   -  person Marquizzo    schedule 24.02.2021
comment
Эй, @Marquizzo, я сделал то, что ты сказал, но у меня есть дыра по бокам бота, чего не должно быть. Что-то идет не так. Я не могу понять причину.   -  person Ali91    schedule 24.02.2021
comment
Этот пост до сих пор без ответа. Поэтому надеюсь, что кто-нибудь подскажет или поможет решить проблему.   -  person Ali91    schedule 04.03.2021


Ответы (1)


Для 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, но похоже, что все они построены на одном и том же коде)

person flatworldstudio    schedule 05.03.2021