Creating a 3D Gallery App with Three.js, HTML, and CSS - Part 2
Ali Ozzaim
Posted on July 18, 2024
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
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);
}
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));
}
animation.js
// src/modules/animation.js
export function animate(renderer, scene, camera, controls) {
function render() {
requestAnimationFrame(render);
controls.update();
renderer.render(scene, camera);
}
render();
}
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);
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! :)
Posted on July 18, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 29, 2024