DEV Community

Ali Ozzaim
Ali Ozzaim

Posted on

Creating a 3D Gallery App with Three.js, HTML, and CSS - Part 2

In the first part of this series, we set up the basic structure for our 3D Gallery App using Three.js, HTML, and CSS. We created a simple 3D environment, added a model, and implemented basic navigation controls. In this part, we will enhance our project by adding four walls for our gallery and additional controls to improve user interaction.

Updated Project Structure

First, let's update our folder structure to better organize our code:

3d-gallery-app/
├── index.html
├── styles.css
├── src/
│   ├── main.js
│   ├── modules/
│   │   ├── lighting.js
│   │   ├── walls.js
│   │   └── animation.js
├── public/
│   ├── models/
│   ├── textures/
│   └── animations/
├── package.json
├── vite.config.js
Enter fullscreen mode Exit fullscreen mode

Organizing Code into Modules

To keep our code organized, we'll split the functionality into different modules and we will do it so for each coming parts. We'll create three modules: lighting.js, walls.js, and animation.js.

lighting.js

// src/modules/lighting.js
import * as THREE from 'three';

export function addLighting(scene) {
    const ambientLight = new THREE.AmbientLight(0xffffff, 1);
    scene.add(ambientLight);
}
Enter fullscreen mode Exit fullscreen mode

walls.js


// src/modules/walls.js
import * as THREE from 'three';

export function addWalls(scene) {
    const wallMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff, side: THREE.DoubleSide });

    const wallGeometry = new THREE.PlaneGeometry(10, 5);
    const walls = [];

    // Create and position the walls
    const wall1 = new THREE.Mesh(wallGeometry, wallMaterial);
    wall1.position.set(0, 0, -5);
    walls.push(wall1);

    const wall2 = new THREE.Mesh(wallGeometry, wallMaterial);
    wall2.position.set(0, 0, 5);
    wall2.rotation.y = Math.PI;
    walls.push(wall2);

    const wall3 = new THREE.Mesh(wallGeometry, wallMaterial);
    wall3.position.set(-5, 0, 0);
    wall3.rotation.y = Math.PI / 2;
    walls.push(wall3);

    const wall4 = new THREE.Mesh(wallGeometry, wallMaterial);
    wall4.position.set(5, 0, 0);
    wall4.rotation.y = -Math.PI / 2;
    walls.push(wall4);

    // Add walls to the scene
    walls.forEach(wall => scene.add(wall));
}
Enter fullscreen mode Exit fullscreen mode

animation.js

// src/modules/animation.js
export function animate(renderer, scene, camera, controls) {
    function render() {
        requestAnimationFrame(render);
        controls.update();
        renderer.render(scene, camera);
    }
    render();
}
Enter fullscreen mode Exit fullscreen mode

Updating main.js

Now, let's update main.js to use these modules and add four walls to our gallery.

// src/main.js
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { addLighting } from './modules/lighting.js';
import { addWalls } from './modules/walls.js';
import { animate } from './modules/animation.js';

// Scene, Camera, Renderer
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById('gallery').appendChild(renderer.domElement);

// Lighting
addLighting(scene);

// Load Models if you have one 
const loader = new THREE.GLTFLoader();
loader.load('assets/models/model.gltf', function(gltf) {
    scene.add(gltf.scene);
}, undefined, function(error) {
    console.error(error);
});

// Camera Position
camera.position.set(0, 2, 10);

// Add Walls
addWalls(scene);

// Add OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = true;

// Animation Loop
animate(renderer, scene, camera, controls);

// Handle Window Resize
window.addEventListener('resize', () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
});

// Handle Mouse Click
function onDocumentMouseClick(event) {
    event.preventDefault();
    const mouse = new THREE.Vector2(
        (event.clientX / window.innerWidth) * 2 - 1,
        -(event.clientY / window.innerHeight) * 2 + 1
    );

    const raycaster = new THREE.Raycaster();
    raycaster.setFromCamera(mouse, camera);

    const intersects = raycaster.intersectObjects(scene.children, true);
    if (intersects.length > 0) {
        const intersected = intersects[0].object;
        console.log('Model clicked:', intersected.name);
        // Display model information
    }
}

document.addEventListener('click', onDocumentMouseClick, false);
Enter fullscreen mode Exit fullscreen mode

End of Part 2

By implementing these steps, you've effectively improved the 3D Gallery App by organizing code modules and adding four gallery walls. This setup creates a more vivid environment for users to explore. In the next part, we'll continue to improve the user experience by adding a roof and ceiling, applying textures to the walls, and integrating more advanced features.

Keep an eye on this article for more exciting upgrades and enhancements in Part 3! :)

www.aliozzaim.com

Top comments (1)

Collapse
 
serdar-delikucuk profile image
Serdar Deliküçük

It could be a really useful study