1.9_discover_threejs_book - MartijnKeesmaat/WebGL-practice GitHub Wiki
Introducing the setAnimationLoop Method
Virtual Reality devices handle requestAnimationFrame() differently than normal web pages. This means that our current animate function will not work as a WebVR app.
To make dealing with this easier, a new method called setAnimationLoop was recently added to the WebGLRenderer. This handles setting up of the animation loop for us and makes sure that it works no matter what kind of device we are viewing our app on.
As an added bonus using this method actually makes our code a little cleaner, since calling requestAnimationFrame is handled automatically for us.
renderer.setAnimationLoop( () => {
update();
render();
} );
Texture mapping
The process of stretching an image over a surface
Three.js code structuring
A modular structure for a three.js project
// these need to be accessed inside more than one function so we'll declare them first
let container;
let camera;
let controls;
let renderer;
let scene;
let mesh;
function init() {
container = document.querySelector( '#scene-container' );
scene = new THREE.Scene();
scene.background = new THREE.Color( 0x8FBCD4 );
createCamera();
createControls();
createLights();
createMeshes();
createRenderer();
// start the animation loop
renderer.setAnimationLoop( () => {
update();
render();
} );
}
function createCamera() {
camera = new THREE.PerspectiveCamera(
35, // FOV
container.clientWidth / container.clientHeight, // aspect
0.1, // near clipping plane
100, // far clipping plane
);
camera.position.set( -4, 4, 10 );
}
function createControls() {
}
function createLights() {
const ambientLight = new THREE.HemisphereLight(
0xddeeff, // sky color
0x202020, // ground color
5, // intensity
);
const mainLight = new THREE.DirectionalLight( 0xffffff, 5 );
mainLight.position.set( 10, 10, 10 );
scene.add( ambientLight, mainLight );
}
function createMeshes() {
}
function createRenderer() {
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( container.clientWidth, container.clientHeight );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.gammaFactor = 2.2;
renderer.gammaOutput = true;
renderer.physicallyCorrectLights = true;
container.appendChild( renderer.domElement );
}
// perform any updates to the scene, called once per frame
// avoid heavy computation here
function update() {
// Don't delete this function!
}
// render, or 'draw a still image', of the scene
function render() {
renderer.render( scene, camera );
}
// a function that will be called every time the window gets resized.
// It can get called a lot, so don't put any heavy computation in here!
function onWindowResize() {
// set the aspect ratio to match the new browser window aspect ratio
camera.aspect = container.clientWidth / container.clientHeight;
// update the camera's frustum
camera.updateProjectionMatrix();
// update the size of the renderer AND the canvas
renderer.setSize( container.clientWidth, container.clientHeight );
}
window.addEventListener( 'resize', onWindowResize );
// call the init function to set everything up
init();
Don't remove empty functions
Empty Functions Don’t Affect Performance It’s common practice to leave empty function hanging around to preserve the structure of an app. There are loads of them in the three.js core, waiting for you to replace them with something more useful if you need to.
You might worry that these will affect performance - after all, this empty update function is still being called once per frame in our animation loop. Fortunately, modern JavaScript engines are extremely smart and do all kinds of optimizations, one of which is removing empty functions like this.
An empty function will never be called and doesn’t affect the performance of your app.
Orbital camera
Moving the camera around the scene in such a way as to allow panning, zooming and rotation is a non-trivial task. How can we achieve this in the simplest way possible, with a minimum of effort on our part?
The OrbitControls object is not part of the three.js core. This means the controls come in a separate file, and we’ll need to include that file in our app before we can use them.
HemisphereLight
There is a second ambient light type included with three.js, called the HemisphereLight.
This light type takes advantage of the fact that, in most everyday situations, the light fades from bright at the top of the scene to darker near the ground.
For example, in a typical outdoor scene, objects are brightly lit from above by sunlight, and then more dimly lit by the sunlight bouncing off the ground and illuminating them from below.
Geometries
All the built-in geometries, 20 in total, are listed in the docs and come in two flavors: Geometry, and BufferGeometry.
Transforming
Anything that changes the position, shape, rotation or anything else about the geometry of an object is a transformation. We’re interested in a special subset of these transformations here - translation, rotation, and scaling. Along with shear and reflection, these are called affine transformations
Any transformation that preserves points, straight lines and planes is called an affine transformation. Any lines that are parallel before the transformation will remain parallel after it.
Group
We’ll also introduce an object called Group, which is used for organizing our scene and grouping objects together. Groups hold a position in the scene but are otherwise invisible.
When we move a group around, all of its children will move too. Likewise, if we rotate or scale it, all of its children will be rotated or scaled too. The children can still be still be moved independently as well, of course.
Material.flatShading
This is a Boolean parameter, meaning that we can set it to false (the default) or true. When we turn it on the material will have a faceted look, which can be used to give an object a carved or faceted look0o This is especially useful for low-poly objects.ad
Float & Integer
Note that the parameters all have a type specified in the docs as well, e.g. radiusTop : Float or radialSegments : Integer.
This refers to the type of variable that three.js expects you to pass in here. Float type means any number, while Integer type means whole numbers like -1, 0, 1, 2, 3−1,0,1,2,3 etc and Boolean means either true or false.
Importing models
As seen in my train example it takes a lot of parts to create 3d models. This is still a simple example but if you start working with more complex models it will take a lot of time to create everything in WebGL. Therefore you can import models from software like cinema 4d and blender.
If possible, you should always use glTF format. It’s been specially designed for sharing models on the web, meaning that the file sizes are as small as possible and loading times will be very fast.