DEV Community

Cover image for Set Up Your First ThreeJS Project - Three Part Setup
Helitha Rupasinghe
Helitha Rupasinghe

Posted on • Edited on

Set Up Your First ThreeJS Project - Three Part Setup

Today, I'll teach you how to create an introductory scene with Three.js which is probably the most useful library for you to work with, as it already has many useful functions pre-written, which would otherwise require a lot of effort.

Fundamentals

Three.js is a 3D library that tries to make it as easy as possible to get 3D content on a webpage. Three.js is often confused with WebGL since more often than not, but not always, three.js uses WebGL to draw 3D.

WebGL is a very low-level system that only draws points, lines, and triangles. To do anything useful with WebGL generally requires quite a bit of code and that is where three.js comes in. It handles stuff like scenes, lights, shadows, materials, textures, 3d math, all things that you'd have to write yourself if you were to use WebGL directly.

Getting started

Go ahead and initialise our new project using the CodePen playground or setup your own project on Visual Studio Code with the following file structure under your src folder.

ThreeJS Scene Template
  |- /src
    |- index.html
    |- style.css
    |- Avatar.png
    |- spaceTexture.png
    |- moonTexture.png
    |- normalMap.png
    |- script.js
Enter fullscreen mode Exit fullscreen mode

Part 1: HTML

The HTML is really basic. Edit your index.html and replace it with the following code.

<canvas id="bg"></canvas>   
Enter fullscreen mode Exit fullscreen mode

Part 2: CSS

Next step is to add the following styles and complete our style.css file. Just make sure the div that will wrap the canvas fits the document, and apply any size you want to your plane div element.

@import url('https://fonts.googleapis.com/css2?family=Rubik:wght@700&display=swap');

html, 
body {
  height: 100vh;
}

body {
  background-color: #000;
  color: #fff;
  display: flex;
  align-items: center;
  font-family: 'Rubik', sans-serif;
  margin: 0;
  overflow: hidden;
}

div {
  position: absolute;
  left: 0;
  top: 0;
  padding: 1em;
}
canvas {
  position: fixed;
  top: 0;
  left: 0;
}
Enter fullscreen mode Exit fullscreen mode

Part 3: JavaScript

Now we can implement our JavaScript logic to our ThreeJS setup like so.

import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.126/build/three.module.js';
import { OrbitControls } from 'https://cdn.jsdelivr.net/npm/three@0.126/examples/jsm/controls/OrbitControls.js';

//creating the scene
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

const renderer = new THREE.WebGLRenderer({
  canvas: document.querySelector('#bg'),
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);

const controls = new OrbitControls(camera, renderer.domElement);
controls.enableKeys = false;
controls.maxDistance = 5000.0;
controls.enableDamping = true;
controls.dampingFactor = 0.16;
controls.target.set(0, 0, 0);

// If you use THREE.OrbitControls and you want to change the camera target or position you need to use the update method.
camera.position.set(0, 5, 0);
controls.update();

document.body.appendChild(renderer.domElement);

THREE.ImageUtils.crossOrigin = '';
const texture = THREE.ImageUtils.loadTexture('avatar.png');
texture.anisotropy = renderer.getMaxAnisotropy();

//Stars
function addStar() {
  const geometry = new THREE.SphereGeometry(0.25, 24, 24);
  const material = new THREE.MeshStandardMaterial({ color: 0xffffff });
  const star = new THREE.Mesh(geometry, material);

  const [x, y, z] = Array(3)
    .fill()
    .map(() => THREE.MathUtils.randFloatSpread(300));

  star.position.set(x, y, z);
  scene.add(star);
}

Array(200).fill().forEach(addStar);

// Lights
const pointLight = new THREE.PointLight(0xffffff, 2);
pointLight.position.set(5, 5, 5);

const ambientLight = new THREE.AmbientLight(0xffffff, 1);
scene.add(pointLight, ambientLight);

// Background

const spaceTexture = new THREE.TextureLoader().load('https://media.istockphoto.com/photos/aerosol-clouds-space-haze-or-cosmic-rays-pink-pastel-blue-space-sky-picture-id1306540124?b=1&k=20&m=1306540124&s=170667a&w=0&h=Cpdu6iLmqYM7BFjoq0xvTnR6ws12ba6v7yxAFhCenyI=');
scene.background = spaceTexture;

// Moon
const moonTexture = new THREE.TextureLoader().load('data:image/jpeg;base64,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');
const normalTexture = new THREE.TextureLoader().load('https://www.filterforge.com/filters/9158-normal.jpg');

const moon = new THREE.Mesh(
  new THREE.SphereGeometry(3, 32, 32),
  new THREE.MeshStandardMaterial({
    map: moonTexture,
    normalMap: normalTexture,
  })
);

scene.add(moon);

moon.position.z = 60;
moon.position.setX(-10);


//Torus
const ringGeometry = new THREE.TorusGeometry(10,3,16,100);
const material = new THREE.MeshBasicMaterial({color: 'red'});
const torus = new THREE.Mesh(ringGeometry,material);
scene.add(torus);

//cube
const cubeGeometry = new THREE.BoxGeometry(3, 3, 3);   
let materials = [];
for(let counter = 0; counter < 6; counter++) {
  materials.push(new THREE.MeshBasicMaterial({color: 'white',  map: texture}));
}

var cube = new THREE.Mesh(cubeGeometry, materials);
scene.add(cube);

//loop
var animate = function () {
  requestAnimationFrame( animate );
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;
  torus.rotation.x += 0.01;
  torus.rotation.y += 0.005;
  torus.rotation.z += 0.01;
  moon.rotation.x += 0.005;
  renderer.render(scene, camera);
}; 

animate();
Enter fullscreen mode Exit fullscreen mode

Cool! Now, if you save it, you should see this in the browser:

avatar.png

Recap

If you followed along then you should have completed the project and finished off your basic scene setup with ThreeJS.

Now if you made it this far, then I am linking the code to my Sandbox for you to fork or clone and then the job's done.

Useful resources

https://threejs.org/

Top comments (0)