Group
<canvas id="mainCanvas"></canvas>
<script type="importmap">
{
"imports": {
"three": "./js/build/three.module.js",
"three/addons/": "./js/jsm/"
}
}
</script>
<script type="module">
import * as THREE from "three";
import { TrackballControls } from "three/addons/controls/TrackballControls.js";
import { GUI } from "three/addons/libs/lil-gui.module.min.js";
import { initRenderer, initPerspectiveCamera, initAmbientLight, initSpotLight, addPlane } from "./init.js";
function init() {
const gui = new GUI();
const renderer = initRenderer("mainCanvas");
const scene = new THREE.Scene();
const camera = initPerspectiveCamera();
scene.add(camera);
const spotLight = initSpotLight();
scene.add(spotLight);
const ambientLight = initAmbientLight();
scene.add(ambientLight);
const plane = addPlane({ width: 1000, height: 100 });
scene.add(plane);
let sphere;
let cube;
let group;
let box;
let arrow;
const step = 0.03;
const controls = setupControls();
controls.redraw();
render();
function render() {
if (controls.grouping && controls.rotate) {
group.rotation.y += step;
}
if (controls.rotate && !controls.grouping) {
sphere.rotation.y += step;
cube.rotation.y += step;
}
requestAnimationFrame(render);
renderer.render(scene, camera);
}
function setupControls() {
const controls = new (function () {
this.cubePosX = 0;
this.cubePosY = 3;
this.cubePosZ = 10;
this.spherePosX = 10;
this.spherePosY = 5;
this.spherePosZ = 0;
this.groupPosX = 10;
this.groupPosY = 5;
this.groupPosZ = 0;
this.grouping = false;
this.rotate = false;
this.groupScale = 1;
this.cubeScale = 1;
this.sphereScale = 1;
this.redraw = function () {
scene.remove(group);
sphere = createMesh(new THREE.SphereGeometry(5, 10, 10));
cube = createMesh(new THREE.BoxGeometry(6, 6, 6));
sphere.position.set(controls.spherePosX, controls.spherePosY, controls.spherePosZ);
sphere.scale.set(controls.sphereScale, controls.sphereScale, controls.sphereScale);
cube.position.set(controls.cubePosX, controls.cubePosY, controls.cubePosZ);
cube.scale.set(controls.cubeScale, controls.cubeScale, controls.cubeScale);
group = new THREE.Group();
group.position.set(controls.groupPosX, controls.groupPosY, controls.groupPosZ);
group.scale.set(controls.groupScale, controls.groupScale, controls.groupScale);
group.add(sphere);
group.add(cube);
scene.add(group);
controls.positionBoundingBox();
if (arrow) scene.remove(arrow);
arrow = new THREE.ArrowHelper(new THREE.Vector3(0, 1, 0), group.position, 10, 0x0000ff);
scene.add(arrow);
};
this.positionBoundingBox = function () {
scene.remove(box);
const cbox = new THREE.Box3().setFromObject(group);
const size = cbox.getSize(new THREE.Vector3());
const pos = cbox.getCenter(new THREE.Vector3());
box = new THREE.Mesh(
new THREE.BoxGeometry(size.x, size.y, size.z),
new THREE.MeshBasicMaterial({
color: 0x000000,
vertexColors: false,
wireframeLinewidth: 2,
wireframe: true,
})
);
box.position.copy(pos);
scene.add(box);
};
})();
const sphereFolder = gui.addFolder("sphere");
sphereFolder.add(controls, "spherePosX", -20, 20).onChange(function (e) {
sphere.position.x = e;
controls.positionBoundingBox();
controls.redraw();
});
sphereFolder.add(controls, "spherePosZ", -20, 20).onChange(function (e) {
sphere.position.z = e;
controls.positionBoundingBox();
controls.redraw();
});
sphereFolder.add(controls, "spherePosY", -20, 20).onChange(function (e) {
sphere.position.y = e;
controls.positionBoundingBox();
controls.redraw();
});
sphereFolder.add(controls, "sphereScale", 0, 3).onChange(function (e) {
sphere.scale.set(e, e, e);
controls.positionBoundingBox();
controls.redraw();
});
const cubeFolder = gui.addFolder("cube");
cubeFolder.add(controls, "cubePosX", -20, 20).onChange(function (e) {
cube.position.x = e;
controls.positionBoundingBox();
controls.redraw();
});
cubeFolder.add(controls, "cubePosZ", -20, 20).onChange(function (e) {
cube.position.z = e;
controls.positionBoundingBox();
controls.redraw();
});
cubeFolder.add(controls, "cubePosY", -20, 20).onChange(function (e) {
cube.position.y = e;
controls.positionBoundingBox();
controls.redraw();
});
cubeFolder.add(controls, "cubeScale", 0, 3).onChange(function (e) {
cube.scale.set(e, e, e);
controls.positionBoundingBox();
controls.redraw();
});
const groupFolder = gui.addFolder("group");
groupFolder.add(controls, "groupPosX", -20, 20).onChange(function (e) {
group.position.x = e;
controls.positionBoundingBox();
controls.redraw();
});
groupFolder.add(controls, "groupPosZ", -20, 20).onChange(function (e) {
group.position.z = e;
controls.positionBoundingBox();
controls.redraw();
});
groupFolder.add(controls, "groupPosY", -20, 20).onChange(function (e) {
group.position.y = e;
controls.positionBoundingBox();
controls.redraw();
});
groupFolder.add(controls, "groupScale", 0, 3).onChange(function (e) {
group.scale.set(e, e, e);
controls.positionBoundingBox();
controls.redraw();
});
gui.add(controls, "grouping");
gui.add(controls, "rotate");
return controls;
}
}
init();
function createMesh(geom) {
const meshMaterial = new THREE.MeshNormalMaterial();
meshMaterial.side = THREE.DoubleSide;
const plane = new THREE.Mesh(geom, meshMaterial);
return plane;
}
</script>