Three Cubes Task Part 3
Is it possible to create a cube model out of planes in three.js?
Yes, it is possible to create a cube model out of planes in Three.js. This is commonly referred to as a “box” in Three.js.
To create a box, you can use the BoxGeometry
class in Three.js. This class generates a cube with six rectangular faces, and you can set the dimensions of the cube using the width
, height
, and depth
properties.
Here’s an example code snippet that creates a box in Three.js:
// Create the geometry for the box
const geometry = new THREE.BoxGeometry(1, 1, 1);
// Create a material for the box
const material = new THREE.MeshBasicMaterial({ color: 0xffffff });
// Create a mesh using the geometry and material
const boxMesh = new THREE.Mesh(geometry, material);
// Add the mesh to the scene
scene.add(boxMesh);
stopped the answer, because this is indeed the wrong direction and resharpening the question
Don’t use a BoxGeometry - the question was out of planes (6 planes, 1 for each side)
Yes, it is possible to create a cube model out of six planes in Three.js. Here is an example code snippet to create a cube using planes:
// Define the dimensions of the cube
const cubeWidth = 1;
const cubeHeight = 1;
const cubeDepth = 1;
// Define the material to use for the cube const
cubeMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });
// Create the six planes
const planeFront = new THREE.PlaneGeometry(cubeWidth, cubeHeight);
const planeBack = new THREE.PlaneGeometry(cubeWidth, cubeHeight);
const planeLeft = new THREE.PlaneGeometry(cubeDepth, cubeHeight);
const planeRight = new THREE.PlaneGeometry(cubeDepth, cubeHeight);
const planeTop = new THREE.PlaneGeometry(cubeWidth, cubeDepth);
const planeBottom = new THREE.PlaneGeometry(cubeWidth, cubeDepth);
// Position and rotate the planes to create the cube shape
planeFront.rotateY(Math.PI);
planeFront.translate(0, 0, cubeDepth / 2);
planeBack.translate(0, 0, -cubeDepth / 2);
planeLeft.rotateY(-Math.PI / 2);
planeLeft.translate(-cubeWidth / 2, 0, 0);
planeRight.rotateY(Math.PI / 2);
planeRight.translate(cubeWidth / 2, 0, 0);
planeTop.rotateX(-Math.PI / 2);
planeTop.translate(0, cubeHeight / 2, 0);
planeBottom.rotateX(Math.PI / 2);
planeBottom.translate(0, -cubeHeight / 2, 0);
// Combine the planes into a single mesh const cube = new THREE.Mesh( new
THREE.Geometry().fromBufferGeometry(
“Combine the planes into a single mesh” - WHY?
stupid idea - planes are required and should not be merged into one geometry.
a simple flat entity like Object3D, which allows grouping, does exactly what is wanted.
This code violates the KISS paradigm and does not fulfil the assignment.
new THREE.BufferGeometry().merge([ planeFront, planeBack, planeLeft, planeRight, planeTop, planeBottom, ]) ), cubeMaterial );
// Add the cube to the scene
scene.add(cube);
Note that this code assumes that you have already created a Three.js scene and camera. Also, you can adjust the material and position of the planes to achieve the desired appearance of the cube.
create a basic cube object
With in-sides and out-sides and colourable edges.
My code:
<script>
/**
* the cube is created using six planes,
* and each plane is positioned and rotated to create the cube shape.
* A function is added to create a random material for each plane,
* which gives the cube a more interesting appearance.
*
* NOTICE: The cube is a box with the top open aka not added to the group.
* A box has a visible inside and a certain "wall" thickess.
*/
// Define the camera
const camera = new THREE.PerspectiveCamera(75, 512 / 512, 0.1, 1000);
// Set the camera position and rotation
camera.position.set(0, 1, 3); // was (0, 1, 4.5);
// Define the scene and the cube to be not undefined
let scene = new THREE.Scene();
let cube;
// Define the dimensions of the cube
const cubeWidth = 1;
const cubeHeight = 1;
const cubeDepth = 1;
// Create the six outside planes that will form the cube
const outsideFront = new THREE.PlaneGeometry(cubeWidth, cubeHeight);
const outsideBack = new THREE.PlaneGeometry(cubeWidth, cubeHeight);
const outsideLeft = new THREE.PlaneGeometry(cubeDepth, cubeHeight);
const outsideRight = new THREE.PlaneGeometry(cubeDepth, cubeHeight);
const outsideTop = new THREE.PlaneGeometry(cubeWidth, cubeDepth);
const outsideBottom = new THREE.PlaneGeometry(cubeWidth, cubeDepth);
// and here comes the inside
const insideFront = new THREE.PlaneGeometry(
cubeWidth * 0.998,
cubeHeight * 0.998
);
const insideBack = new THREE.PlaneGeometry(
cubeWidth * 0.998,
cubeHeight * 0.998
);
const insideLeft = new THREE.PlaneGeometry(
cubeDepth * 0.998,
cubeHeight * 0.998
);
const insideRight = new THREE.PlaneGeometry(
cubeDepth * 0.998,
cubeHeight * 0.998
);
const insideTop = new THREE.PlaneGeometry(
cubeWidth * 0.998,
cubeDepth * 0.998
);
const insideBottom = new THREE.PlaneGeometry(
cubeWidth * 0.998,
cubeDepth * 0.998
);
// Position and rotate the planes to create the cube shape
outsideFront.rotateY(Math.PI);
outsideFront.translate(0, 0, cubeDepth / 2);
outsideBack.translate(0, 0, -cubeDepth / 2);
outsideLeft.rotateY(-Math.PI / 2);
outsideLeft.translate(-cubeWidth / 2, 0, 0);
outsideRight.rotateY(Math.PI / 2);
outsideRight.translate(cubeWidth / 2, 0, 0);
outsideTop.rotateX(-Math.PI / 2);
outsideTop.translate(0, cubeHeight / 2, 0);
outsideBottom.rotateX(Math.PI / 2);
outsideBottom.translate(0, -cubeHeight / 2, 0);
//inside
insideFront.rotateY(Math.PI);
insideFront.translate(0, 0, (cubeDepth * 0.98) / 2);
insideBack.translate(0, 0, (-cubeDepth * 0.98) / 2);
insideLeft.rotateY(-Math.PI / 2);
insideLeft.translate((-cubeWidth * 0.98) / 2, 0, 0);
insideRight.rotateY(Math.PI / 2);
insideRight.translate((cubeWidth * 0.98) / 2, 0, 0);
insideTop.rotateX(-Math.PI / 2);
insideTop.translate(0, (cubeHeight * 0.98) / 2, 0);
insideBottom.rotateX(Math.PI / 2);
insideBottom.translate(0, (-cubeHeight * 0.98) / 2, 0);
// Define a function to generate a random material for the cube planes
const makeMaterial = () => {
return new THREE.MeshBasicMaterial({
color: 0xffffff * Math.random(), // generate a random color for each plane
side: THREE.DoubleSide, // render both sides of the plane to ensure visibility from any angle
});
};
// saves the image to a new browser tab or window
const save = async () => {
const dataUrl = renderer.domElement.toDataURL("image/png");
const newWindow = window.open();
newWindow.document.write(`<img src="${dataUrl}">`);
};
// TODO create a group Object scenery and add all cubes, the base plate etc.
const rotateCamera = () => {};
// here we create a box like cube
function createBoxCube() {
// Put the planes into a group
// This allows to address the planes seperatly and not build one mesh!
const cube = new THREE.Object3D();
// Use add function instead of setting the children as an array.
cube.add(new THREE.Mesh(outsideFront, makeMaterial()));
cube.add(new THREE.Mesh(outsideBack, makeMaterial()));
cube.add(new THREE.Mesh(outsideLeft, makeMaterial()));
cube.add(new THREE.Mesh(outsideRight, makeMaterial()));
// keep the box open
// cube.add(new THREE.Mesh(outsideTop, makeMaterial()));
cube.add(new THREE.Mesh(outsideBottom, makeMaterial()));
cube.add(new THREE.Mesh(insideFront, makeMaterial()));
cube.add(new THREE.Mesh(insideBack, makeMaterial()));
cube.add(new THREE.Mesh(insideLeft, makeMaterial()));
cube.add(new THREE.Mesh(insideRight, makeMaterial()));
// keep the box open
// cube.add(new THREE.Mesh(insideTop, makeMaterial()));
cube.add(new THREE.Mesh(insideBottom, makeMaterial()));
const edgeLeft = new THREE.PlaneGeometry(
cubeWidth * 0.98,
cubeDepth * 0.02
);
const edgeRight = new THREE.PlaneGeometry(
cubeWidth * 0.98,
cubeDepth * 0.02
);
const edgeBack = new THREE.PlaneGeometry(
cubeWidth * 0.98,
cubeDepth * 0.02
);
const edgeFront = new THREE.PlaneGeometry(
cubeWidth * 0.98,
cubeDepth * 0.02
);
edgeBack.rotateX(-Math.PI / 2);
edgeBack.translate(0, cubeHeight / 2, (-cubeHeight * 0.98) / 2);
edgeFront.rotateX(-Math.PI / 2);
edgeFront.translate(0, cubeHeight / 2, (cubeHeight * 0.98) / 2);
edgeLeft.rotateY(-Math.PI / 2);
edgeLeft.translate((-cubeHeight * 0.98) / 2, cubeHeight / 2, 0);
edgeRight.rotateY(-Math.PI / 2);
edgeRight.translate((cubeHeight * 0.98) / 2, cubeHeight / 2, 0);
cube.add(new THREE.Mesh(edgeBack, makeMaterial()));
cube.add(new THREE.Mesh(edgeFront, makeMaterial()));
cube.add(new THREE.Mesh(edgeLeft, makeMaterial()));
cube.add(new THREE.Mesh(edgeRight, makeMaterial()));
return cube;
}
function createFrameCube() {
// Put the planes into a group
// This allows to address the planes seperatly and not build one mesh!
const cube = new THREE.Object3D();
// keep the box open
// cube.add(new THREE.Mesh(outsideFront, makeMaterial()));
// cube.add(new THREE.Mesh(outsideBack, makeMaterial()));
cube.add(new THREE.Mesh(outsideLeft, makeMaterial()));
cube.add(new THREE.Mesh(outsideRight, makeMaterial()));
cube.add(new THREE.Mesh(outsideTop, makeMaterial()));
cube.add(new THREE.Mesh(outsideBottom, makeMaterial()));
// keep the box open
// cube.add(new THREE.Mesh(insideFront, makeMaterial()));
// cube.add(new THREE.Mesh(insideBack, makeMaterial()));
cube.add(new THREE.Mesh(insideLeft, makeMaterial()));
cube.add(new THREE.Mesh(insideRight, makeMaterial()));
cube.add(new THREE.Mesh(insideTop, makeMaterial()));
cube.add(new THREE.Mesh(insideBottom, makeMaterial()));
const edgeLeftFront = new THREE.PlaneGeometry(
cubeWidth * 0.02,
cubeDepth * 0.98
);
const edgeRightFront = new THREE.PlaneGeometry(
cubeWidth * 0.02,
cubeDepth * 0.98
);
const edgeTopFront = new THREE.PlaneGeometry(
cubeWidth * 0.98,
cubeDepth * 0.02
);
const edgeBottomFront = new THREE.PlaneGeometry(
cubeWidth * 0.98,
cubeDepth * 0.02
);
const edgeLeft = new THREE.PlaneGeometry(
cubeWidth * 0.02,
cubeDepth * 0.98
);
const edgeRight = new THREE.PlaneGeometry(
cubeWidth * 0.02,
cubeDepth * 0.98
);
const edgeTop = new THREE.PlaneGeometry(cubeWidth * 0.98, cubeDepth * 0.02);
const edgeBottom = new THREE.PlaneGeometry(
cubeWidth * 0.98,
cubeDepth * 0.02
);
edgeLeftFront.translate(-0.49 * cubeDepth, 0, 0.49 * cubeDepth);
edgeRightFront.translate(0.49 * cubeDepth, 0, 0.49 * cubeDepth);
edgeTopFront.translate(0, 0.5 * cubeDepth, 0.49 * cubeDepth);
edgeBottomFront.translate(0, -0.5 * cubeDepth, 0.49 * cubeDepth);
edgeLeft.translate(-0.49 * cubeDepth, 0, -0.49 * cubeDepth);
edgeRight.translate(0.49 * cubeDepth, 0, -0.49 * cubeDepth);
edgeTop.translate(0, 0.5 * cubeDepth, -0.49 * cubeDepth);
edgeBottom.translate(0, -0.5 * cubeDepth, -0.49 * cubeDepth);
cube.add(new THREE.Mesh(edgeLeftFront, makeMaterial()));
cube.add(new THREE.Mesh(edgeRightFront, makeMaterial()));
cube.add(new THREE.Mesh(edgeTopFront, makeMaterial()));
cube.add(new THREE.Mesh(edgeBottomFront, makeMaterial()));
cube.add(new THREE.Mesh(edgeLeft, makeMaterial()));
cube.add(new THREE.Mesh(edgeRight, makeMaterial()));
cube.add(new THREE.Mesh(edgeTop, makeMaterial()));
cube.add(new THREE.Mesh(edgeBottom, makeMaterial()));
console.log("createFrameCube", cube);
return cube;
}
function createDoubleOpenCube() {
// Put the planes into a group
// This allows to address the planes seperatly and not build one mesh!
const cube = new THREE.Object3D();
// keep the box open
// cube.add(new THREE.Mesh(outsideFront, makeMaterial()));
cube.add(new THREE.Mesh(outsideBack, makeMaterial()));
cube.add(new THREE.Mesh(outsideLeft, makeMaterial()));
cube.add(new THREE.Mesh(outsideRight, makeMaterial()));
//cube.add(new THREE.Mesh(outsideTop, makeMaterial()));
cube.add(new THREE.Mesh(outsideBottom, makeMaterial()));
// keep the box open
// cube.add(new THREE.Mesh(insideFront, makeMaterial()));
cube.add(new THREE.Mesh(insideBack, makeMaterial()));
cube.add(new THREE.Mesh(insideLeft, makeMaterial()));
cube.add(new THREE.Mesh(insideRight, makeMaterial()));
//cube.add(new THREE.Mesh(insideTop, makeMaterial()));
cube.add(new THREE.Mesh(insideBottom, makeMaterial()));
const edgeLeftFront = new THREE.PlaneGeometry(
cubeWidth * 0.02,
cubeDepth * 0.98
);
const edgeRightFront = new THREE.PlaneGeometry(
cubeWidth * 0.02,
cubeDepth * 0.98
);
const edgeBottomFront = new THREE.PlaneGeometry(
cubeWidth * 0.98,
cubeDepth * 0.02
);
const edgeLeft = new THREE.PlaneGeometry(
cubeWidth * 0.02,
cubeDepth * 0.98
);
const edgeRight = new THREE.PlaneGeometry(
cubeWidth * 0.02,
cubeDepth * 0.98
);
const edgeBack = new THREE.PlaneGeometry(
cubeWidth * 0.98,
cubeDepth * 0.02
);
edgeLeftFront.translate(-0.49 * cubeDepth, 0, 0.49 * cubeDepth);
edgeRightFront.translate(0.49 * cubeDepth, 0, 0.49 * cubeDepth);
edgeBottomFront.translate(0, -0.49 * cubeDepth, 0.49 * cubeDepth);
edgeLeft.rotateX(-Math.PI / 2);
edgeLeft.translate(-0.49 * cubeDepth, 0.5 * cubeDepth, 0);
edgeRight.rotateX(-Math.PI / 2);
edgeRight.translate(0.49 * cubeDepth, 0.5 * cubeDepth, 0);
edgeBack.rotateX(-Math.PI / 2);
edgeBack.translate(0, -0.49 * cubeDepth, 0.5 * cubeDepth, 0);
cube.add(new THREE.Mesh(edgeLeftFront, makeMaterial()));
cube.add(new THREE.Mesh(edgeRightFront, makeMaterial()));
cube.add(new THREE.Mesh(edgeBottomFront, makeMaterial()));
cube.add(new THREE.Mesh(edgeLeft, makeMaterial()));
cube.add(new THREE.Mesh(edgeRight, makeMaterial()));
cube.add(new THREE.Mesh(edgeBack, makeMaterial()));
return cube;
}
const regenerate = () => {
// Create and add the cube to the scene
scene = new THREE.Scene();
// Rotate the scene to get a better view of the cube
// scene.rotation.X = Math.PI * 0.25;
scene.rotation.y = Math.PI * 0.25;
// TEST
const rnd = Math.floor(Math.random() * 3);
cube =
rnd % 3 == 0
? createBoxCube()
: rnd % 3 == 1
? createFrameCube()
: createDoubleOpenCube();
console.log(cube);
scene.add(cube);
};
// Set up the renderer
const renderer = new THREE.WebGLRenderer({
antialias: true, // smooth graphics
preserveDrawingBuffer: true, // be prepared to capture images
});
renderer.setSize(512, 512);
document.getElementById("container").appendChild(renderer.domElement);
// Render the scene
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.012;
cube.rotation.y -= 0.005;
renderer.render(scene, camera);
}
// now start
regenerate();
animate();
</script>
Here is a certain problem with three.js. Three.js never contained CSG operations like subtract
, union
, and intersect
natively. There where
some good implementations, yet they are broken since the change from Geometry (faces)
to BufferGeometry (Groups, Meshes)
.
Three.js supports merge ,union of to meshes into a solid one, and group via the entity Object3D. Subtract can be achieved in some custom ways utilizing Shape3D - build you own planes and cut into those. That’s a low-level work around.
A good current state of the art library for CSG would be the preferred way, though.
This document is work in progress
Intermission test:
finally prompting the mission
Using an augmented/assisted/artificial intelligence (AI) to create a generative bot, an agent software for art generation. What can chatGTP do, how and where would this be helpful.
ChatGPT’s answer
As an AI language model, ChatGPT can be used to assist in the development of generative bots for art generation. Specifically, ChatGPT can be used to generate text-based prompts and provide suggestions for creative directions based on its training data.
For example, a generative bot that creates abstract art could use ChatGPT to generate prompts such as “Create a piece inspired by the color red” or “Make something that feels chaotic and frenetic.” The bot could also use ChatGPT to suggest specific colors, shapes, or styles to incorporate into the art.
ChatGPT could also be used to help the bot learn and adapt to user feedback. For instance, the bot could ask users to rate generated pieces or provide feedback on specific elements of the art, and then use that feedback to improve its generative abilities.
Overall, using ChatGPT to create a generative bot for art generation could be helpful in automating the creative process and providing a unique way for users to interact with art. It could also provide a platform for artists to experiment with different styles and techniques in a low-pressure, low-stakes environment.
Navigation Three Cubes Part 1 Three Cubes Part 2