You can see for example that when I call the function it get align but only the half of the base (sphere) and my rocks are random positioned. So far I got
alignToSurfaceNormal() {
this.group.children.forEach((child) => {
const position = child.position.clone();
// Reset the quaternion to avoid cumulative transformations
child.quaternion.identity();
// Dynamically adjust the ray's origin to ensure it starts far enough above the geometry
const boundingBox = new THREE.Box3().setFromObject(new THREE.Mesh(this.base));
const rayOrigin = position.clone().add(new THREE.Vector3(0, boundingBox.max.y - boundingBox.min.y + 1, 0));
// Cast a single downward ray
const raycaster = new THREE.Raycaster();
raycaster.set(rayOrigin, new THREE.Vector3(0, -1, 0));
const intersects = raycaster.intersectObject(new THREE.Mesh(this.base), true);
if (intersects.length > 0) {
const closestIntersection = intersects[0];
let normal = closestIntersection.face?.normal.clone();
if (normal) {
// Transform the normal to world space
const matrix = closestIntersection.object.matrixWorld;
normal.applyMatrix3(new THREE.Matrix3().getNormalMatrix(matrix)).normalize();
// Skip alignment if normal.y > 0.5
if (normal.y > 0.5) {
//Check why normal act like this
return;
}
// Align the object's up direction to the normal
const quaternion = new THREE.Quaternion();
quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), normal);
child.quaternion.premultiply(quaternion);
}
}
});
}