How to fill a box with boxGeometry randomly and no overlap?

Viewed 29

I am using THREE.js in react.

I want to fill 500 number of 1X1X1 box geometry in a 200x200x200 area randomly.

The following code shows how to get the position.xyz with the range from -100 to 100.

However, how to get the position that all 1X1X1 box geometry could not touch each other (no overlapping)?

I have no idea.

function Geometry() {

    const geo_num = 500;
    const box_length = 200;

    const geo_position = useMemo(() => {
        const array = []

        for (let i = 0; i < geo_num; i++) {
            const xdirection = Math.round(Math.random()) * 2 - 1;
            const ydirection = Math.round(Math.random()) * 2 - 1;
            const zdirection = Math.round(Math.random()) * 2 - 1;

            const xpos = Math.random() * box_length * xdirection * 0.5;
            const ypos = Math.random() * box_length * ydirection * 0.5;
            const zpos = Math.random() * box_length * zdirection * 0.5;

            array.push(new THREE.Vector3(xpos, ypos, zpos))
        }

        return array
    })

    return (
        <>
            {
                geo_position.map((element, index) => (
                    <mesh position={element} key={index} >
                        <boxGeometry args={[1, 1, 1]} />
                    </mesh>
                ))
            }
        </>
    )
}
1 Answers

A very rough concept of how you can do it, using an array and its .includes() method:

body{
  overflow: hidden;
  margin: 0;
}
<script type="module">
import * as THREE from "https://cdn.skypack.dev/three@0.136.0";
import {OrbitControls} from "https://cdn.skypack.dev/three@0.136.0/examples/jsm/controls/OrbitControls";

let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(50, 50, 250);
let renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener("resize", event => {
  camera.aspect = innerWidth / innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(innerWidth, innerHeight);
});

let contols = new OrbitControls(camera, renderer.domElement);

let boxCount = 500;
let range = [-100, 100];
let v3Array = [];
let counter = 0;
let v3 = new THREE.Vector3();
while(counter < boxCount){
  let v3 = [
    THREE.MathUtils.randInt(range[0], range[1]).toFixed(0),
    THREE.MathUtils.randInt(range[0], range[1]).toFixed(0),
    THREE.MathUtils.randInt(range[0], range[1]).toFixed(0),
  ].join("|");
  if (!v3Array.includes(v3)){
  v3Array.push(v3);
  counter++
  }
}

v3Array.map( p => {
  let o = new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial({color: Math.random() * 0xffffff, wireframe: true}));
  let pos = p.split("|").map(c => {return parseInt(c)});
  o.position.set(pos[0], pos[1], pos[2]);
  scene.add(o);
});

let boxHelper = new THREE.Box3Helper(new THREE.Box3(new THREE.Vector3().setScalar(range[0] - 0.5), new THREE.Vector3().setScalar(range[1] + 0.5)), "yellow");
scene.add(boxHelper);

renderer.setAnimationLoop( () => {
  renderer.render(scene, camera);
})
</script>

Related