Hello everyone who's reading.
I'm trying to create a website where I can mouse scroll through "cards" that are all in a single line, seen with a iso view from the side.
I've set up the scene in THREE.js, but I don't know how to go about having a collection of elements that automatically get used as the card's texture.
To explain better I'd like to:
If someone can help, that would be much appreciated.
Thank you in advance!
Here's the code I have right now:
import './style.css'
import * as THREE from 'three'
// Set up the scene
const canvas = document.querySelector('.webgl');
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff); // Set background color to white
// Create box geometry
const boxGeometry = new THREE.BoxGeometry(1, 1, 0.01);
//Create box material
const boxMaterial = new THREE.MeshStandardMaterial({
transparent: true,
opacity: 0.7
});
const numBoxes = 10; // Boxes number
const boxSpacing = 1; // Boxes spacing
// Create boxes mesh
for (let i = 0; i < 10; i++)
{
const box = new THREE.Mesh(boxGeometry, boxMaterial);
box.position.set(0, 0, -i * boxSpacing)
scene.add(box);
}
// Add ambient light to the scene
const ambientLight = new THREE.AmbientLight(0xffffff, 1); // Soft white light
scene.add(ambientLight);
// Set up the renderer
const renderer = new THREE.WebGLRenderer({canvas: canvas, antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
// Set up the camera
const zoom = 300; // Adjust this value to control the zoom
const sizes = {
width: window.innerWidth,
height: window.innerHeight
}; // Declares sizes value as window sizes
const aspect = window.innerWidth / window.innerHeight; // Set aspect ratio to the window's
const camera = new THREE.OrthographicCamera(
-sizes.width / zoom,
sizes.width / zoom,
sizes.height / zoom,
-sizes.height / zoom,
-10,
1000
);
// const gridHelper = new THREE.GridHelper(100, 100, 0x444444, 0x444444);
// scene.add(gridHelper);
// Camera controls
camera.position.set(2, 2, 5);
camera.lookAt(0, 0, 0)
// Update camera aspect ratio and renderer size when the window is resized
window.addEventListener('resize', () => {
// Update sizes
sizes.width = window.innerWidth;
sizes.height = window.innerHeight;
// Update camera
camera.left = -sizes.width / zoom;
camera.right = sizes.width / zoom;
camera.top = sizes.height / zoom;
camera.bottom = -sizes.height / zoom;
camera.updateProjectionMatrix();
// Update renderer
renderer.setSize(sizes.width, sizes.height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
});
// Render the scene
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
requestAnimationFrame(animate);
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Mirko Pratofiorito</title>
</head>
<body>
<div id="app"></div>
<canvas class="webgl"></canvas>
<script type="module" src="/main.js"></script>
</body>
</html>
I would have tried something but unfortunately I'm fairly new to JS and don't know where to start doing this.
Why not create a collection of the image URLs and then load the textures and create boxes with the correct aspect ratio for each image and possibly add new elements by defining a function to add a new image URL and create a new box with that texture. The function loads the new texture, creates a new box with it, and adds the URL to the imageUrls
collection as below:
import './style.css';
import * as THREE from 'three';
const canvas = document.querySelector('.webgl');
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
const ambientLight = new THREE.AmbientLight(0xffffff, 1);
scene.add(ambientLight);
const renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
const zoom = 300; // Adjust this value to control the zoom
const sizes = {
width: window.innerWidth,
height: window.innerHeight
};
const aspect = window.innerWidth / window.innerHeight;
const camera = new THREE.OrthographicCamera(
-sizes.width / zoom,
sizes.width / zoom,
sizes.height / zoom,
-sizes.height / zoom,
-10,
1000
);
camera.position.set(2, 2, 5);
camera.lookAt(0, 0, 0);
window.addEventListener('resize', () => {
sizes.width = window.innerWidth;
sizes.height = window.innerHeight;
camera.left = -sizes.width / zoom;
camera.right = sizes.width / zoom;
camera.top = sizes.height / zoom;
camera.bottom = -sizes.height / zoom;
camera.updateProjectionMatrix();
renderer.setSize(sizes.width, sizes.height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
});
function createBoxWithTexture(texture, positionZ) {
const aspect = texture.image.width / texture.image.height;
const boxGeometry = new THREE.BoxGeometry(1 * aspect, 1, 0.01);
const boxMaterial = new THREE.MeshStandardMaterial({
map: texture,
transparent: true,
opacity: 0.7
});
const box = new THREE.Mesh(boxGeometry, boxMaterial);
box.position.set(0, 0, -positionZ);
scene.add(box);
}
const loader = new THREE.TextureLoader();
const imageUrls = [
'path/to/image1.jpg',
'path/to/image2.jpg',
'path/to/image3.jpg',
];
imageUrls.forEach((url, index) => {
loader.load(url, (texture) => {
createBoxWithTexture(texture, index * 1.5);
});
});
function addNewImage(url) {
loader.load(url, (texture) => {
createBoxWithTexture(texture, imageUrls.length * 1.5);
imageUrls.push(url); // Add the URL to the collection
});
}
// Example usage:
addNewImage('path/to/newImage.jpg');
// Render the scene
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
requestAnimationFrame(animate);