📜 ⬆️ ⬇️

Three.js - 3D do it yourself browser or WebGL gets closer

The topic about three.js from mrdoob at one time slipped on Habré, but has not yet been considered in detail. In this and (possibly) subsequent articles I will try to correct this omission. Unfortunately, three.js does not provide any intelligible documentation, therefore all knowledge on it is obtained experimentally and by picking the WebGL specs, i.e. Any additions to the author of the topic are welcome.

In this article we will create a simple application that will demonstrate the basic capabilities of this engine, work with the camera, light and shadow, and also teach our objects to move. At the end of the article link to the demo files and a screenshot. So, to the point!

The first steps


Our HTML is pretty simple, it doesn’t cause questions and looks like this:

<!DOCTYPE html> <html> <head> <title>Three.js - dice</title> <meta charset="utf-8"> <style> body { margin: 0; padding: 0; overflow: hidden; } </style> <!-- libs --> <script type="text/javascript" src="js/Three.js"></script> <script type="text/javascript" src="js/RequestAnimationFrame.js"></script> <script type="text/javascript" src="js/jquery.js"></script> <!-- app --> <script type="text/javascript" src="js/demoapp.js"></script> </head> <body> </body> </html> 

')
In this example, we will use jQuery, but this is absolutely not critical and it would be quite possible to do without it. RequestAnimationFrame.js, is a small hack to provide cross-browser work (oddly enough) RequestAnimationFrame (more on this below).

Now let's go directly to our demoapp.js script file .
We hang up processing all the code inside the file for the ready document event
  $(document).ready(function() { /** **/}); 

To maintain the simplicity of the example, let's leave the functions standard for demos three.js, - init () and animate () . In the first we have the initialization of everything that we would like to see, and the second will use the requestAnimationFrame and call the render () function, which will already draw all the changes. As our demo application becomes more complex, its architecture will be transferred to backbone.js (but this is a topic that will be discussed in a separate article).

Main elements


The main elements that will take part in our production (note that the main, but not all, in three.js is a fairly rich choice of actions):

1) Camera (THREE.Camera)
These are our “eyes” on the improvised scene of events.
The first parameter shows the distance from the object, the second - the ratio of the sides (as a rule, it is the quotient of the width and height of the window that is used), the third and fourth — near / far, the parameters related to the plane and used for rendering.
 camera = new THREE.Camera(30, window.innerWidth/window.innerHeight,1, 3000); 

Or, you can immediately create a camera that can spin around the scene while the left mouse button is held down, while the right button is clamped, move up and down, and when the middle button is held down, zoom in on the scene. This is done as follows (the parameters passed to the camera quite clearly speak for themselves by name and are shown in the application code):
 camera = new THREE.TrackballCamera({/**parameters**/}); 

It should also be noted that the Cartesian coordinate system is used, i.e. The x axis is directed from the upper left corner of the screen to the lower right, the z axis from the upper right to the lower left, and the y axis from the bottom of the screen to the top, respectively.

2) Scene (THREE.Scene)
The main element. It is on the stage that we will add all the objects we created and the planes (using .addObject or addChild). The initialization of the scene is as follows:
 scene = new THREE.Scene(); 

3) Motor! Mash (THREE.Mesh)
It is with the help of the mesh that almost all the objects in three.js are compiled. To work with it, we need to determine the geometry and material of the mesh.
Geometry is the objects from which the scene is composed (cubes, spheres, cylinders, planes, etc.) This topic is quite voluminous, so now we will not dwell on it in detail. The material, however, is not less voluminous, so for a start you can only clarify two points - you should use MeshFaceMaterial to apply the material specified in the geometry, MeshBasicMaterial may be enough for use in most other cases.
 mesh = new THREE.Mesh( geometry, material ); 

Then we can peacefully add the mesh to the scene.
 scene.addObject( mesh );// .addChild 

Removing an object is also easy with removeObject.
 scene.removeObject(mesh); 


4) Renderer (THREE.WebGLRenderer / CanvasRenderer)
We have two types of renderers available, WebGLRenderer and CanvasRenderer. Already by name you can understand what's what. It should also be noted that, as expected, WebGLRenderer drops fps noticeably stronger on weak machines. Renderers are also easy to use:
 renderer = new THREE.WebGLRenderer( ); 

or
 renderer = new THREE.CanvasRenderer(); 


One of the required actions after the initialization of the renderer is to set its size, - here we are free to choose any size, based on our needs.
 renderer.setSize( window.innerWidth, window.innerHeight ); 

And finally, we need to add a renderer element to the page. This is done as follows and equally for all types of renderers:
 container.appendChild( renderer.domElement ); 

or for jQuery
 container.append(renderer.domElement); 


5) Light.
Yes, it is possible (and sometimes necessary) to apply light to the scene, for example, to obtain shadows from objects (they can, of course, be made using parallel moving planes, but this is rather an exception). There are three types of lighting:
5.1) THREE.AmbientLight is the lighting that affects the whole scene. It has no direction and affects every object of the scene equally, regardless of the location of the object. Accordingly, this light has no position on the coordinate axis.
5.2) THREE.PointLight - lighting emanating from a single point in all directions. I think a comparison with an ordinary light bulb would be appropriate enough.
5.3) THREE.DirectionalLight - light moving in a certain direction (from a given point and to the origin of coordinates). Sunlight, for example, can be attributed to this type of lighting.
In the example, we will only use DirectionalLight to get the shadow from the object placed above the plane.

Apply knowledge


Now you can go directly to the application code. In it, we will use all the above elements, as well as comment on the actions taken. To begin with, we start our application by calling the initialization and animation functions, and also declare the global variables we need.
 //  var container, camera, scene, renderer, floormesh, cubeMesh, phi = 0; init(); animate(); 

Consider the initialization function.
 function init() { //        container = $( 'div' ).attr('id','cardfield'); $('body').append( container ); //  camera = new THREE.TrackballCamera({ fov: 45, aspect: window.innerWidth / window.innerHeight, near: 1, far: 10000, rotateSpeed: 1.0, zoomSpeed: 1.2, panSpeed: 0.8, noZoom: false, noPan: false }); //  ,   ,       camera.position.z = 250; camera.position.y = 175; camera.target.position.y = -75; //  scene = new THREE.Scene(); //  "".       600600   5 var floorgeo = new THREE.CubeGeometry(600,600,5); //          floormesh = new THREE.Mesh(floorgeo, new THREE.MeshBasicMaterial({color: 0x248C0F, opacity:0.9})); //    floormesh.position.y = -200; //      ,     . floormesh.rotation.x = 90 * Math.PI / 180; //   scene.addChild(floormesh); //   var materials = [ //     new THREE.MeshBasicMaterial( { color: 0xE01B4C }), //   new THREE.MeshBasicMaterial( { color: 0x34609E }), //   new THREE.MeshBasicMaterial( { color: 0x7CAD18 }), // new THREE.MeshBasicMaterial( { color: 0x00EDB2 }), //  new THREE.MeshBasicMaterial( { color: 0xED7700 }), //   new THREE.MeshBasicMaterial( { color: 0xB5B1AE }) //   ]; //    50    1,      var cube = new THREE.CubeGeometry( 50, 50, 50, 1, 1, 1, materials ); //   ,     //  ,     cubeMesh = new THREE.Mesh( cube, new THREE.MeshFaceMaterial() ); //    y cubeMesh.position.y = -10; //   scene.addChild( cubeMesh ); //   new THREE.ShadowVolume( cubeMesh ); //   light = new THREE.DirectionalLight( 0xffffff ); //,     light.castShadow = true; //     -150,  .   ( 1  y  0  x  z),            //,          light.position.set( 0, 1, 0 ); //  scene.addChild( light ); // renderer = new THREE.WebGLRenderer(); //    renderer.setSize( window.innerWidth, window.innerHeight ); //      container.append( renderer.domElement ); } 

Perform animation:
 function animate() { requestAnimationFrame( animate ); render(); } 

This feature is a standard part of most three.js applications. Consider it closer. requestAnimationFrame (animate) is a function for providing cross-browser animation (even here ) and provides a recursive call to the render () function, which, in fact, renders all of our happiness.

Rendering
This is where you need to adjust the movements of the camera and objects (of course, you need to adjust the scope of variables in advance so that they are visible in this function)
 function render() { //      (    ) cubeMesh.rotation.x += 0.5 * Math.PI / 90; cubeMesh.rotation.y += 1.0 * Math.PI / 90; cubeMesh.rotation.z += 1.5 * Math.PI / 90; //   ,       x  y cubeMesh.position.x = Math.sin( phi ) * 50; cubeMesh.position.y = Math.cos( phi ) * 50; //   phi+= 0.05; // renderer.render(scene, camera); } 


It should be noted that the example used the three.js version of the build, taken from github (compared to the normal version, the geometry of the shapes was changed, instead of THREE.xxx THREE.xxxGeometry, for example THREE.CubeGeometry on the old version three.js will not work, but THREE.Cube will work. Also the old version does not understand THREE.TrackBallCamera).

Results:


We created our first simple demo, got acquainted with the basic components, without which it is impossible to create any application based on three.js, put the light on and saw the animation cycle in action. In the future, we will deal with the addition of our own textures and object models, the construction of complex scenes, the addition of actions over the objects of the scene and translate all this happiness to backbone.js. The source code of the application is available here .

Source: https://habr.com/ru/post/123400/


All Articles