javascriptcollectionsthree.jstextures

Fetch Textures From a Collection


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.


Solution

  • 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);