Three.js - Renderer & Responsiveness



Basic Functionality of a Scene

You know that Scene is a container for the camera, lights, and objects we want to render on the screen. Let's look at some basic functionality of the Scene object −

Adding an Object

The function add(object) is used to an object to the scene.

const scene = THREE.Scene()
scene.add(cube) // adds the cube
scene.add(sphere) // adds a sphere

Removing an Object

The function remove(object) removes an object from the scene.

scene.remove(cube) // removes the last added cube
scene.remove(sphere) // removes a sphere

Children

In the scene.children return an array of all the objects in the scene, including the camera and lights.

console.log(scene.children) // outputs all the objects in the scene
console.log(scene.children.length) // outputs number of elements on the
scene

Note − We can give a name to any object using its name attribute. A name is handy for debugging purposes but can also directly access an object from your scene.

Check out the following example.

scene.html

<!DOCTYPE html>
<html lang="en">
   <head>
      <meta charset="UTF-8" />
      <meta http-equiv="X-UA-Compatible" content="ie=edge" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <title>Three.js – The scene
      <style>
         * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: -applesystem, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
               Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
         }
         html,
         body {
            height: 100vh;
            width: 100vw;
            background-color: #262626;
            overflow: hidden;
         }
         #btn-conatiner {
            position: absolute;
            top: 0;
            left: 0;
            height: 10vh;
            width: 100%;
         }
         @media screen and (max-width:600px){
            #btn-container{
               display: flex;
               flex-direction: column;
            }
         }
         .btn {
            padding: 5px 15px;
            margin: 5px 15px;
            font-weight: bold;
            text-transform: uppercase;
         }
         .add {
            color: green;
         }
         .rem {
            color: red;
         }
         #threejs-container {
            position: block;
            width: 100%;
            height: 100%;
         }
      </style>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.js"></script>
   </head>
   <body>
      <div id="btn-conatiner">
         <button class="btn add">Add Cube</button>
         <button class="btn rem">Remove Cube</button>
      </div>
      <div id="threejs-container"></div>
      <script type="module">
         // Experimenting with different methods of scene
         // add, remove, children, getElementById
         // sizes
         let width = window.innerWidth
         let height = window.innerHeight
         const gui = new dat.GUI()
         // scene
         const scene = new THREE.Scene()
         scene.background = new THREE.Color(0x262626)
         // lights
         const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)
         scene.add(ambientLight)
         const light = new THREE.PointLight(0xffffff, 0.5)
         light.position.set(-10, 10, -10)
         // for shadow
         light.castShadow = true
         light.shadow.mapSize.width = 1024
         light.shadow.mapSize.height = 1024
         light.shadow.camera.near = 0.1
         light.shadow.camera.far = 1000
         scene.add(light)
         // camera
         const camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000)
         camera.position.set(0, 10, 40)
         camera.lookAt(0, 0, 0)
         gui.add(camera.position, 'z', 10, 200, 1).name('camera-z')
         // plane
         const planeGeometry = new THREE.PlaneGeometry(100, 100)
         const plane = new THREE.Mesh(
            planeGeometry,
            new THREE.MeshPhongMaterial({ color: 0xffffff, side: THREE.DoubleSide })
         )
         plane.rotateX(Math.PI / 2)
         plane.position.y = -1.75
         plane.receiveShadow = true
         scene.add(plane)
         // scene.add
         function addCube() {
            const cubeSize = Math.ceil(Math.random() * 3)
            const cubeGeometry = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize)const cubeMaterial = new THREE.MeshLambertMaterial({
               color: Math.random() * 0xffffff
            })
            const cube = new THREE.Mesh(cubeGeometry, cubeMaterial)
            cube.castShadow = true
            cube.name = 'cube-' + scene.children.length
            cube.position.x = -30 + Math.round(Math.random() * 50)
            cube.position.y = Math.round(Math.random() * 5)
            cube.position.z = -20 + Math.round(Math.random() * 50)
            scene.add(cube)
         }
         const add = document.querySelector('.add')
         add.addEventListener('click', () => {
            addCube()
            console.log('cube added')
         })
         // scene.remove
         function removeCube() {
            const allChildren = scene.children
            const lastObject = allChildren[allChildren.length - 1]
            if (lastObject.name) {
               scene.remove(lastObject)
            }
         }
         const remove = document.querySelector('.rem')
         remove.addEventListener('click', () => {
            removeCube()
            console.log('cube removed')
         })
         // scene.children
         console.log(scene.children)
         // responsivenesswindow.addEventListener('resize', () => {
            width = window.innerWidth
            height = window.innerHeight
            camera.aspect = width / height
            camera.updateProjectionMatrix()
            renderer.setSize(window.innerWidth, window.innerHeight)
            renderer.render(scene, camera)
         })
         // renderer
         const renderer = new THREE.WebGL1Renderer()
         renderer.setSize(width, height)
         renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
         // animation
         function animate() {
            requestAnimationFrame(animate)
            renderer.render(scene, camera)
         }
         // rendering the scene
         const container = document.querySelector('#threejs-container')
         container.append(renderer.domElement)
         renderer.render(scene, camera)
         animate()
      </script>
   </body>
</html>

Open your console to see the elements on the scene.

Add_Cube

Using name attribute

The function scene.getObjectByName(name) directly returns the object, by specific name, from the scene.

You can also add another argument - recursive.

scene.getObjectByName(name, recursive)

If you set the recursive argument to true, Three.js will search through the complete tree of objects to find the thing with the specified name.

Adding Fog to the scene

This property allows you to set the fog for the scene. The fog renders a haze that hides faraway objects.

scene.fog = new THREE.Fog(0xffffff, 0.015, 100)

This line of code defines a white fog (0xffffff). You can use the preceding two properties to tune how the mist appears. The 0.015 value sets the near property, and the 100 value sets the far property. With these properties, you can determine where the fog starts and how fast it gets denser.

With the THREE.Fog object, the fog increases linearly. There is also a different way to set the mist for the scene; for this, use the following definition −

scene.fog = new THREE.FogExp2(0xffffff, 0.01)

This time, we don't specify near and far, but just the color (0xffffff) and the mist's density(0.01). It's best to experiment a bit with these properties to get the effect you want.

Using the override material property

The overrideMaterial property forces all the objects in the scene to use the same material.

scene.overrideMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff })

Here, all the objects on the scene of the same material, i.e., MeshLambertMaterial.

Note − THREE.Scene is a structure that is sometimes also called a Scenegraph. A scene graph is a structure that can hold all the necessary information of a graphical scene.In Three.js, this means that THREE.Scene contains all the objects, lights, and other objects needed for rendering.

Scene_Graph

Renderer

The renderer uses the camera and the information from the scene to draw the output on the screen, i.e., <canvas> element.

In the Hello cube app, we used the WebGLRenderer. Some other renderers are available, but the WebGLRenderer is by far the most powerful renderer available and usually the only one you need.

Note − There is a canvas-based renderer, a CSS-based renderer, and an SVG-based one. Even though they work and can render simple scenes, I wouldn't recommend using them. They are not being developed actively, very CPU-intensive, and lack features such as good material support and shadows.

Advertisements