Creating a 3D Gallery App with Three.js, HTML, and CSS - Part 3
Ali Ozzaim
Posted on July 19, 2024
In the previous part of this series, we organized our code into modules and added four walls to our 3D gallery. Now, we will build on that foundation by adding a roof, floor, and textures, as well as some advanced features to make our gallery more interactive and visually appealing.
Updated Project Structure
First, let's add a few more files to our project structure for the textures:
3d-gallery-app/
├── index.html
├── styles.css
├── src/
│ ├── main.js
│ ├── modules/
│ │ ├── lighting.js
│ │ ├── walls.js
│ │ ├── roof.js
│ │ ├── floor.js
│ │ ├── textures.js
│ │ └── animation.js
├── public/
│ ├── models/
│ ├── textures/
│ │ ├── wall-texture.jpg
│ │ ├── floor-texture.jpg
│ │ └── roof-texture.jpg
├── package.json
├── vite.config.js
Adding the Roof and Floor
Let's start by creating the roof and floor modules.
// src/modules/roof.js
import * as THREE from 'three';
export function addRoof(scene, textureLoader) {
const roofTexture = textureLoader.load('public/textures/roof-texture.jpg');
const roofMaterial = new THREE.MeshBasicMaterial({ map: roofTexture, side: THREE.DoubleSide });
const roofGeometry = new THREE.PlaneGeometry(10, 10);
const roof = new THREE.Mesh(roofGeometry, roofMaterial);
roof.rotation.x = Math.PI / 2;
roof.position.y = 5;
scene.add(roof);
}
floor.js
// src/modules/floor.js
import * as THREE from 'three';
export function addFloor(scene, textureLoader) {
const floorTexture = textureLoader.load('public/textures/floor-texture.jpg');
const floorMaterial = new THREE.MeshBasicMaterial({ map: floorTexture, side: THREE.DoubleSide });
const floorGeometry = new THREE.PlaneGeometry(10, 10);
const floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.rotation.x = -Math.PI / 2;
floor.position.y = -5;
scene.add(floor);
}
Updating main.js
Finally, update main.js to pass the texture loader to the modules when adding walls, roof, and floor.
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 { addRoof } from './modules/roof.js';
import { addFloor } from './modules/floor.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);
// Texture Loader
const textureLoader = new THREE.TextureLoader();
// 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, Roof, and Floor
addWalls(scene, textureLoader);
addRoof(scene, textureLoader);
addFloor(scene, textureLoader);
// 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 3
By following these steps, you've successfully added a roof and floor to your 3D gallery and applied textures to make it more visually appealing.
Note
We haven't added new textures for the walls. You can search for wall textures online, download them, and replace the existing texture to further customize your gallery. Try to experiment with different textures to see how they change the look and feel of your gallery.
Continue to read for Part 4, which will cover user controls and key listeners for even more interactive features!
Posted on July 19, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 29, 2024