How to do the intersection of a quadrangular pyramid with a sphere

Hi, I have a code that creates a sphere using “THREE.SphereGeometry” and a quadrilateral pyramid using “THREE.BufferGeometry”, then I make the intersection of the two shapes and draw it a little to the right of the original shapes. I’m not sure if I’m creating the base of the pyramid correctly in “indices”, because when I created the triangle, the intersection returned the correct shape with a spherical bottom, but with a quadrangular pyramid it turns out something incorrect, I’ll attach a screenshot.

Here is my code:

import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { CSG } from 'three-csg-ts';

let camera: THREE.PerspectiveCamera,
  scene: THREE.Scene,
  renderer: THREE.WebGLRenderer;

init();
animate();

function init() {
  renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  scene = new THREE.Scene();

  camera = new THREE.PerspectiveCamera(
    45,
    window.innerWidth / window.innerHeight,
    1,
    10000
  );
  const controls = new OrbitControls(camera, renderer.domElement);
  camera.position.set(0, 20, 10);
  controls.update();


  const createSphere = (scene, maxDistance) => {
    // Параметры THREE.SphereGeometry:
    // 1. Радиус сферы
    // 2. Количество сегментов по горизонтали
    // 3. Количество сегментов по вертикали
    //const biggerRadius = Math.max(xRadius, yRadius);
    //const smallerRadius = Math.min(xRadius, yRadius);
    const radius = maxDistance;
    let sphereGeometry = new THREE.SphereGeometry(radius, 16, 16);
    let sphereMaterial = new THREE.MeshBasicMaterial({
      color: 0x0000ff, // Синий цвет
      opacity: 1,
      transparent: true,
      wireframe: true,
    });
  
    const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
    sphere.position.set(0, maxDistance + 0.5, 0);
  
    scene.add(sphere);
    //console.log(`sphere ${sphere.position.y}`);
    return sphere;
  };

  const createTriangle = (scene, maxDistance) => {
    // Create the vertices of the triangle
    const height = maxDistance;
    const vertices = new Float32Array([
      0, height, 0, // Vertex A
      -1, 0, -1, // Vertex B
      -1, 0, 1, // Vertex C
      1, 0, 1, // Vertex D 
      1, 0, -1 // Vertex D
    ]);

    // Create indexes to define the faces of the triangle
    const indices = new Uint32Array([0, 1, 2, 0, 2, 3, 0, 3, 4,  0, 1, 4, 
      1, 2, 3, 1, 3, 4 ]);

    // Create a buffer geometry
    const geometry = new THREE.BufferGeometry();
    geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
    geometry.setIndex(new THREE.BufferAttribute(indices, 1));
    geometry.scale(1, 1, 1)
    geometry.computeVertexNormals();

    // Create the material
    const material = new THREE.MeshBasicMaterial({ color: 0xff0000, wireframe: true });

    // Create a mesh
    const triangle = new THREE.Mesh(geometry, material);

    // Add a triangle to the scene
    scene.add(triangle);
    return triangle;
  }

  const rectWidth = 5;
  const rectHeight = 2;
  const maxDistance = 8;

  const sphere = createSphere(scene, maxDistance);
  const triangle = createTriangle(scene, maxDistance);
  //triangle.position.x = 3;

  sphere.updateMatrix();
  triangle.updateMatrix();


  // Convert objects to CSG
  const cubeCSG = CSG.fromMesh(sphere);
  const pyramidCSG = CSG.fromMesh(triangle);

  // Perform the subtraction operation
  const subtract  = cubeCSG.intersect(pyramidCSG);

  // Convert the result back to Three.js Mesh
  const resultMesh = CSG.toMesh(subtract, sphere.matrix);
  resultMesh.material = new THREE.MeshNormalMaterial({ wireframe: false });
  resultMesh.position.x = 5;

  scene.add(resultMesh);

}

function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}

image
image
image

I’d guess that you have the winding order of some of your pyramid triangles reversed.

0, 1, 2, 0, 2, 3, 0, 3, 4, → 0, 1, 4, should probably be 0,4,1
1, 2, 3, ->1, 3, 4 should probably be: 3, 4 , 1,

Yes, you are right with “0, 1, 2, 0, 2, 3, 0, 3, 4, → 0, 1, 4, should probably be 0,4,1”, thanks. Now I don’t have a this “bad” side that goes somewhere :slight_smile:
What about 1, 2, 3, ->1, 3, 4 should probably be: 3, 4 , 1 - I tried doing “3,4, 1” and “1,4,3” but the base is empty. I am attaching a screenshot

here is code of creating a pyramid:

const createTriangle = (scene, maxDistance) => {
    // Create the vertices of the triangle
    const height = maxDistance;
    const vertices = new Float32Array([
      0, height, 0, // Vertex A
      -1, 0, -1, // Vertex B
      -1, 0, 1, // Vertex C
      1, 0, 1, // Vertex D 
      1, 0, -1 // Vertex D
    ]);

    // Create indexes to define the faces of the triangle
    const indices = new Uint32Array([
      0, 1, 2, 
      0, 2, 3, 
      0, 3, 4,  
      0, 4, 1,
      1, 2, 3,
      1, 4, 3]);

    // Create a buffer geometry
    const geometry = new THREE.BufferGeometry();
    geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
    geometry.setIndex(new THREE.BufferAttribute(indices, 1));
    geometry.scale(1, 1, 1)
    geometry.computeVertexNormals();

    // Create the material
    const material = new THREE.MeshBasicMaterial({ color: 0xff0000, wireframe: true });

    // Create a mesh
    const triangle = new THREE.Mesh(geometry, material);

    // Add a triangle to the scene
    scene.add(triangle);
    return triangle;
  }

image
image

The entire bottom face was flipped… try this:

// Create indexes to define the faces of the triangle
const indices = new Uint32Array([0, 1, 2, 0, 2, 3, 0, 3, 4,  0, 4, 1, 
  3, 2, 1, 1, 4, 3 ]);

I also made a glitch with your setup:

Yes, it worked, thank you very much.
I think it would be better to make the last triangle not “1,4,3”, but “4, 3, 1” - visually there is no difference, however, logically, the first digit of the new triangle should differ from the last digit of the previous triangle. Or am I thinking wrong?

I don’t think it matters.
The only important thing is the winding order… To make a face oriented outward… Look at the face from the direction you want to be outside, looking in, and then use the vertex indices in clockwise order.

But if it pleases you aesthetically then I don’t think it will hurt anything as long as the winding order is preserved. :slight_smile:

I personally prefer to have the shortest edges defined by the 3 indices…

0 1

3 2

then the triangle indices would be 0,1,2, 2,3,0


0------1
| \    |
|   \  |
3------2

but… it really only matters what helps you visualize it easily and had the correct winding order you want.

Okay, i see, thank you one more time, have a nice day :slight_smile:

1 Like