三js CSG问题与挤压形状相交

发布于 2025-02-04 17:50:26 字数 5720 浏览 2 评论 0 原文

我有很多意见,我试图挤出然后相交以创建最终的多边形。问题在于结果不是预期的,它具有一些浮动的零件。即使解决方案是检测这些漂浮的额外零件并擦除它们的方法,我也需要以某种方式纠正此问题。

我正在使用此库 https://www.npmjs.com /package/three-csg-ts/v/3.1.10 进行交集的二进制操作。

我不知道这是否是错误,还是我做错了什么。我在挤出设置中尝试了许多不同的配置,但是我仍然有同样的问题。

我对JS或三J的经验不多,所以很抱歉,如果我的代码不那么可读,我已经尽力了。

import './style.css'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { CSG } from 'three-csg-ts'

// Canvas
const canvas = document.querySelector('canvas.webgl')

/**
 * Sizes
 */
 const sizes = {
    width: 1677,
    height: 1287
}

// Scene
const scene = new THREE.Scene()

// View Points
const view_1 = [1019, 516, 1005, 502, 968, 481, 944, 482, 911, 492, 902, 505, 892, 510, 879, 522, 880, 595, 889, 612, 899, 619, 941, 621, 998, 620, 1011, 615, 1018, 599, 1017, 594, 1022, 575, 1023, 541]
const view_2 = [874.9, 221, 878.4, 274.3, 888.2, 296.3, 893.9, 306.1, 902.5, 320.9, 916.5, 327.1, 937.6, 337.1, 960, 329.6, 973.8, 323.1, 983.5, 314.6, 994.3, 307.3, 1008.4, 297.5, 1018, 271, 1019, 253, 1019.1, 239.5, 1006.5, 230, 996.6, 225.2, 987.8, 218.9, 958.8, 204.1, 939.5, 198.9, 892.7, 203.7]
const view_3 = [1002, 867, 985.9, 885.3, 984.7, 918.4, 986.7, 931, 994.9, 941.1, 1001.2, 957.6, 1015, 970.1, 1028.9, 980.9, 1046, 982.2, 1061.3, 980.9, 1077.6, 968.8, 1100.4, 945.5, 1103.4, 900.7, 1093.1, 879.7, 1077.1, 864, 1064.4, 855.6, 1053, 856.9, 1046, 853.7, 1025.7, 856.9, 1012, 859.4]
const view_4 = [619, 648, 592, 681, 597, 702, 607, 719.3, 624.5, 725.9, 646.2, 731.7, 658.2, 735.7, 669.3, 739.3, 680, 742.3, 690.3, 737.5, 697.1, 726.6, 690.1, 711.5, 686, 706, 683, 694, 683, 682, 674, 663, 668, 660, 659, 649, 650, 647, 644, 642, 629, 643]
const view_5 = [1282, 499, 1261, 504, 1256, 509, 1255.7, 508.2, 1251.4, 509.9, 1240, 515.5, 1227.7, 527.7, 1212.2, 587.7, 1210.9, 609, 1213.9, 615.8, 1216, 617.8, 1219.7, 623.3, 1226, 628.6, 1259.3, 625.1, 1267, 615, 1280, 561]
const views = [view_1,view_2,view_3, view_4, view_5]

//Split array in pairs
function chunk(arr, size) {
    return Array.from({ length: Math.ceil(arr.length / size) }, (v, i) =>
      arr.slice(i * size, i * size + size))
}

//Shape constructor and extruder
const extrudeSettings = {
    steps: 8,
    depth: 600,
    bevelEnabled: false,
    bevelThickness: 1,
    bevelSize: 0,
    bevelOffset: 0,
    bevelSegments: 1
};
var degree = 0
var pos = 0
var meshes = []

for(let view in views){
    var point_list = []
    var pair_array = chunk(views[view],2) //separate in pairs
    for (let pair in pair_array){
        point_list.push(new THREE.Vector2(-pair_array[pair][0]+sizes.width/2,-pair_array[pair][1]+sizes.height/2)) //creating vectors
    }
    console.log(point_list)
    var shape = new THREE.Shape(point_list); //constructing the Shape
    extrudeSettings.depth = 600
    var shapeGeom = new THREE.ExtrudeGeometry( shape, extrudeSettings ); //Extruding the shape

    //position transformations
    shapeGeom.rotateX(Math.PI * 0.5); 
    shapeGeom.rotateZ(THREE.MathUtils.degToRad(degree));
    degree += 45
    const shapeMat = new THREE.MeshPhongMaterial({color: "aqua"});
    shapeMat.side = THREE.DoubleSide
    var shapeMesh = new THREE.Mesh(shapeGeom, shapeMat); 
    
    //more position transformations
    shapeMesh.geometry.computeBoundingBox();
    var boundingBox = new THREE.Box3();
    boundingBox.copy( shapeMesh.geometry.boundingBox );
    shapeMesh.updateMatrixWorld( true ); // ensure world matrix is up to date
    boundingBox.applyMatrix4( shapeMesh.matrixWorld );
    shapeMesh.position.x = shapeMesh.position.x - (boundingBox.min.x + boundingBox.max.x)/2
    shapeMesh.position.y = shapeMesh.position.y - (boundingBox.min.y + boundingBox.max.y)/2
    shapeMesh.position.z = shapeMesh.position.z - (boundingBox.min.z + boundingBox.max.z)/2

    //adding to the scene
    shapeMesh.updateMatrix()
    meshes.push(shapeMesh)
    scene.add(shapeMesh); //comment if doesn't want to show the extruded shapes, but only the final result
}

//Intersection
var intersection = meshes[0]
for (let mesh in meshes){
    meshes[mesh].updateMatrix()
    intersection = CSG.intersect(intersection,meshes[mesh])
}
intersection.material = new THREE.MeshNormalMaterial()
scene.add(intersection)

// Lights
scene.add( new THREE.HemisphereLight(0xffffbb,0x080820,2) );

/**
 * Camera
 */
// Base camera
const camera = new THREE.OrthographicCamera( sizes.width / - 2, sizes.width / 2, sizes.height / 2, sizes.height / - 2, 0.1, 3000 );
camera.position.set( 0, 800, 0 );
camera.up = new THREE.Vector3( 0, 0, 1 );
scene.add(camera)

var camera_pivot = new THREE.Object3D()
scene.add( camera_pivot );
camera.lookAt( camera_pivot.position );

// Controls
const controls = new OrbitControls(camera, canvas)
controls.enableDamping = true

/**
 * Renderer
 */
const renderer = new THREE.WebGLRenderer({
    canvas: canvas, 
    preserveDrawingBuffer: true
})
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))

/**
 * Animate
 */

const clock = new THREE.Clock()
const tick = () =>
{
    const elapsedTime = clock.getElapsedTime()  
    // Update Orbital Controls
    controls.update()
    // Render
    renderer.render(scene, camera)
    // Call tick again on the next frame
    window.requestAnimationFrame(tick)
}

tick()


以下是一些屏幕截图,可以解决问题:

​sstatic.net/yzbi9.png“ alt =“挤压形状的交叉”>

我真的认为问题可能是在我使用的挤出方法中,但是我不明白该如何完成正常工作。也许这是我试图进行十字路口的方式,与先前的结果相交。我试图按时间进行两个对象,然后相交两个相交结果,但没有进展。

I have many views that I'm trying to extrude and then intersect in order to create a final polygon. The problem is that the result is not the expected, it has some floating extra parts. I need to correct this somehow, even if the solution is a method to detect these floating extra parts and erase them.

I'm using this library https://www.npmjs.com/package/three-csg-ts/v/3.1.10 to make the binary operation of intersection.

I dont know if it is a bug or if I'm doing something wrong. I've tried so many different configurations for the extrude settings but I still have the same problem.

I don't have much experience with js or ThreeJS, so I'm sorry if my code is not that readable, I've tried my best.

import './style.css'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { CSG } from 'three-csg-ts'

// Canvas
const canvas = document.querySelector('canvas.webgl')

/**
 * Sizes
 */
 const sizes = {
    width: 1677,
    height: 1287
}

// Scene
const scene = new THREE.Scene()

// View Points
const view_1 = [1019, 516, 1005, 502, 968, 481, 944, 482, 911, 492, 902, 505, 892, 510, 879, 522, 880, 595, 889, 612, 899, 619, 941, 621, 998, 620, 1011, 615, 1018, 599, 1017, 594, 1022, 575, 1023, 541]
const view_2 = [874.9, 221, 878.4, 274.3, 888.2, 296.3, 893.9, 306.1, 902.5, 320.9, 916.5, 327.1, 937.6, 337.1, 960, 329.6, 973.8, 323.1, 983.5, 314.6, 994.3, 307.3, 1008.4, 297.5, 1018, 271, 1019, 253, 1019.1, 239.5, 1006.5, 230, 996.6, 225.2, 987.8, 218.9, 958.8, 204.1, 939.5, 198.9, 892.7, 203.7]
const view_3 = [1002, 867, 985.9, 885.3, 984.7, 918.4, 986.7, 931, 994.9, 941.1, 1001.2, 957.6, 1015, 970.1, 1028.9, 980.9, 1046, 982.2, 1061.3, 980.9, 1077.6, 968.8, 1100.4, 945.5, 1103.4, 900.7, 1093.1, 879.7, 1077.1, 864, 1064.4, 855.6, 1053, 856.9, 1046, 853.7, 1025.7, 856.9, 1012, 859.4]
const view_4 = [619, 648, 592, 681, 597, 702, 607, 719.3, 624.5, 725.9, 646.2, 731.7, 658.2, 735.7, 669.3, 739.3, 680, 742.3, 690.3, 737.5, 697.1, 726.6, 690.1, 711.5, 686, 706, 683, 694, 683, 682, 674, 663, 668, 660, 659, 649, 650, 647, 644, 642, 629, 643]
const view_5 = [1282, 499, 1261, 504, 1256, 509, 1255.7, 508.2, 1251.4, 509.9, 1240, 515.5, 1227.7, 527.7, 1212.2, 587.7, 1210.9, 609, 1213.9, 615.8, 1216, 617.8, 1219.7, 623.3, 1226, 628.6, 1259.3, 625.1, 1267, 615, 1280, 561]
const views = [view_1,view_2,view_3, view_4, view_5]

//Split array in pairs
function chunk(arr, size) {
    return Array.from({ length: Math.ceil(arr.length / size) }, (v, i) =>
      arr.slice(i * size, i * size + size))
}

//Shape constructor and extruder
const extrudeSettings = {
    steps: 8,
    depth: 600,
    bevelEnabled: false,
    bevelThickness: 1,
    bevelSize: 0,
    bevelOffset: 0,
    bevelSegments: 1
};
var degree = 0
var pos = 0
var meshes = []

for(let view in views){
    var point_list = []
    var pair_array = chunk(views[view],2) //separate in pairs
    for (let pair in pair_array){
        point_list.push(new THREE.Vector2(-pair_array[pair][0]+sizes.width/2,-pair_array[pair][1]+sizes.height/2)) //creating vectors
    }
    console.log(point_list)
    var shape = new THREE.Shape(point_list); //constructing the Shape
    extrudeSettings.depth = 600
    var shapeGeom = new THREE.ExtrudeGeometry( shape, extrudeSettings ); //Extruding the shape

    //position transformations
    shapeGeom.rotateX(Math.PI * 0.5); 
    shapeGeom.rotateZ(THREE.MathUtils.degToRad(degree));
    degree += 45
    const shapeMat = new THREE.MeshPhongMaterial({color: "aqua"});
    shapeMat.side = THREE.DoubleSide
    var shapeMesh = new THREE.Mesh(shapeGeom, shapeMat); 
    
    //more position transformations
    shapeMesh.geometry.computeBoundingBox();
    var boundingBox = new THREE.Box3();
    boundingBox.copy( shapeMesh.geometry.boundingBox );
    shapeMesh.updateMatrixWorld( true ); // ensure world matrix is up to date
    boundingBox.applyMatrix4( shapeMesh.matrixWorld );
    shapeMesh.position.x = shapeMesh.position.x - (boundingBox.min.x + boundingBox.max.x)/2
    shapeMesh.position.y = shapeMesh.position.y - (boundingBox.min.y + boundingBox.max.y)/2
    shapeMesh.position.z = shapeMesh.position.z - (boundingBox.min.z + boundingBox.max.z)/2

    //adding to the scene
    shapeMesh.updateMatrix()
    meshes.push(shapeMesh)
    scene.add(shapeMesh); //comment if doesn't want to show the extruded shapes, but only the final result
}

//Intersection
var intersection = meshes[0]
for (let mesh in meshes){
    meshes[mesh].updateMatrix()
    intersection = CSG.intersect(intersection,meshes[mesh])
}
intersection.material = new THREE.MeshNormalMaterial()
scene.add(intersection)

// Lights
scene.add( new THREE.HemisphereLight(0xffffbb,0x080820,2) );

/**
 * Camera
 */
// Base camera
const camera = new THREE.OrthographicCamera( sizes.width / - 2, sizes.width / 2, sizes.height / 2, sizes.height / - 2, 0.1, 3000 );
camera.position.set( 0, 800, 0 );
camera.up = new THREE.Vector3( 0, 0, 1 );
scene.add(camera)

var camera_pivot = new THREE.Object3D()
scene.add( camera_pivot );
camera.lookAt( camera_pivot.position );

// Controls
const controls = new OrbitControls(camera, canvas)
controls.enableDamping = true

/**
 * Renderer
 */
const renderer = new THREE.WebGLRenderer({
    canvas: canvas, 
    preserveDrawingBuffer: true
})
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))

/**
 * Animate
 */

const clock = new THREE.Clock()
const tick = () =>
{
    const elapsedTime = clock.getElapsedTime()  
    // Update Orbital Controls
    controls.update()
    // Render
    renderer.render(scene, camera)
    // Call tick again on the next frame
    window.requestAnimationFrame(tick)
}

tick()


Here are some screenshots to ilustrate the problem:

Extruded shapes

Intersection of the extruded shapes

I really think that the problem might be in the extrusion method I'm using, but I don't understand how it should be done to work properly. Or perhaps it's the way i'm trying to do the intersection, one by one intersecting with the previous result. I've tried to do it two objects by time and then intersect two intersection results, but with no progress.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

只有影子陪我不离不弃 2025-02-11 17:50:26

好吧,在使用您的代码一段时间后,我认为我的结果是正确的。

正如您猜到的那样,问题在于交叉点:

//Intersection
var intersection = meshes[0]
for (let mesh in meshes){
    meshes[mesh].updateMatrix()
    intersection = CSG.intersect(intersection,meshes[mesh])
}
intersection.material = new THREE.MeshNormalMaterial()
scene.add(intersection)

这里有问题。如果我已经正确理解了,

老实说,我不确定问题是什么,也许是您将第一个Intersectee设置为网眼[0],然后将整个网格阵列循环,与自己至少相交。当我添加时,如果(网格[mesh] .geometry.uuid ===网格[0]。geometry.uuid)继续; 进入循环,似乎已经工作得很好,但是我会' T将其作为解决方案。

我建议的解决方案是将代码的整个相交部分替换为:

//Intersection
meshes.forEach((mesh) => mesh.updateMatrix());
var intersection = CSG.intersect(...meshes);
intersection.material = new THREE.MeshNormalMaterial()
scene.add(intersection)

首先,我用功能更大的 foreach -prause替换了循环以更新矩阵。

第二,我使用 csg.Intersect 都立即使用网格数组中的所有网格。

这会导致这样的形状:

​。

PS感谢您的有趣交叉代码!我只涉足了三分,并阅读了有关CSG的文章,所以两者都玩起来真的很有趣。 这是我的codesandbox

Well, after playing around with your code for a while, I think my result is correct.

As you guessed, the problem lies here in the intersection part:

//Intersection
var intersection = meshes[0]
for (let mesh in meshes){
    meshes[mesh].updateMatrix()
    intersection = CSG.intersect(intersection,meshes[mesh])
}
intersection.material = new THREE.MeshNormalMaterial()
scene.add(intersection)

There is something wrong here. If I have understood correctly, by the associative property of logical intersection of sets, it shouldn't matter if you do the intesection mesh by mesh (someone correct me if I'm wrong), so the problem isn't that.

To be honest, I'm not sure what the issue is, maybe it's that you set your first intersectee as mesh[0] and then loop the whole mesh array, intersecting at least one shape with itself. When I added if(meshes[mesh].geometry.uuid === meshes[0].geometry.uuid) continue; into the loop, that seemed to work pretty nicely already, but I wouldn't propose that as a solution.

The solution I'm proposing is to replace that whole intersection part of the code with:

//Intersection
meshes.forEach((mesh) => mesh.updateMatrix());
var intersection = CSG.intersect(...meshes);
intersection.material = new THREE.MeshNormalMaterial()
scene.add(intersection)

First, I replaced the loop with a more functional forEach-clause to update the matrices.

Second, I used spread syntax to call CSG.intersect with all of the meshes in the mesh array at once.

This results in a shape like this:

intersected shape

I am not 100% sure if that is the correct result of intersecting so many polygons, but it looks relatively clean and doesn't have any extra floating parts like in your example.

P.S Thanks for the fun intersection code! I have only dabbled with Three.js and read about CSG, so it was really fun to play around with both. Here is my codesandbox.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文