“This is the 40th day of my participation in the First Challenge 2022. For details: First Challenge 2022”

The sample code uses version three.js-r93: github.com/mrdoob/thre…

Those of us who play games often know that in games, there will be multiple sub-windows in one window, which will display animations from different angles of the scene. Minimaps, for example, are a good example.

  • In this image, the red box is rendered by different views using a combination of perspective and orthographic cameras.
  • The part circled in red is drawn by orthographic cameras because it never changes in size.
  • Through the previous content, we have learned how to set is graph, this section we will go into this part of the content, so that in the future encounter similar problems, can be very good to follow the lessons, not without ideas.

0. Effect display

  • First, let’s take a look at the final effect display, as shown in the picture:

  • In the picture, there are three canvases, each of which shows different areas of a scene. In graphics, we usually call this display canvas a viewport.
  • Effect of the demo

A shadow?

  • The colors of the multiple buy puzzle in our demo are different, with a slight gradient. There are some shadows at the bottom of the polyhedron, and we can see the shadows by moving the mouse.

How to infer the light source?

  • There is a light, as can be seen from the illumination on the surface of the buy more puzzle.
  • There’s no concentrating effect on the polyhedron, so noThe spotlight.
  • Not every place gets the same light, and it’s unlikely that all doThe ambient light.
  • And I figured it was directional light.

1. Build a static interface

Based on the above description, let’s create a static page first

  • We need three Canvas containers, each representing three canvases.
<div id="container">
    <canvas id="canvas1"></canvas>
    <canvas id="canvas2"></canvas>
    <canvas id="canvas3"></canvas>
</div>
Copy the code
#canvas1.#canvas2.#canvas3 {
    position: relative;
    display: block;
    border: 1pxsolid red ; // border red}#canvas1 {
    width: 300px;
    height: 200px;
}

#canvas2 {
    width: 400px;
    height: 100px;
    left: 150px;
}

#canvas3 {
    width: 200px;
    height: 300px;
    left: 75px;
}     
Copy the code

2. Initialize the view

3. Initialize the scene and lights

4. Define shadow surfaces

  • Run this example to see the effect. You can see a shadow on the ball. How is this shadow implemented?

  • The shadows we have here are not generated by lighting, but by simply using a shade-like map and sticking it onto a flat surface. This is also a method to generate shadows in.
  • To achieve the shadow effect here, we need a shade-like texture, a texture with this texture and a plane with this texture. Create a shade-like plane and place it underneath the polyhedron (ball).
  • We can create the shadow by drawing the canvas, and since it is in the browser, it must be suitable for three.js
// Create canvas
var canvas = document.createElement('canvas');
// Set the canvas size to 128 width and 128 height
canvas.width = 128;
canvas.height = 128;
// Get the drawable context of the canvas
var context = canvas.getContext('2d');
// Create a radioactive gradient that starts at the center of the canvas and ends with a circle of radius canvas.width/2. If you don't understand you can refer to: http://www.w3school.com.cn/htmldom/met_canvasrenderingcontext2d_createradialgradient.asp
var gradient = context.createRadialGradient(canvas.width / 2, canvas.height / 2.0, canvas.width / 2, canvas.height / 2, canvas.width / 2);
// Add a color near the center of the canvas, canvas.width*0.1,
gradient.addColorStop(0.1.'rgba(210,210,210,1)');
// Add a color at the end of the canvas gradient,
gradient.addColorStop(1.'rgba(255,255,255,1)');
// The fill method is the gradient fill created earlier
context.fillStyle = gradient;
// Actually draw the gradient on the canvas.
context.fillRect(0.0, canvas.width, canvas.height);
Copy the code

The implementation effect is as follows:

  • Once the canvas is ready, we turn the canvas into a texture
var shadowTexture = new THREE.CanvasTexture( canvas );
Copy the code
  • CanvasTexture can create a texture from a Canvas canvas. The material is then defined by the texture as follows:
var shadowMaterial = new THREE.MeshBasicMaterial( { map: shadowTexture } );
Copy the code
  • Now that we have the basic material for the plane, we can assign it to the shadow plane. We have three balls, so we need three shadow planes
function initShadowPlane(){
    // Define a plane with a width of 300 and a height of 300.
    var shadowGeo = new THREE.PlaneGeometry(300.300.1.1);
    // Create a Mesh at (0, -250, 0) 250 below the Y-axis.
    mesh = new THREE.Mesh(shadowGeo, shadowMaterial);
    mesh.position.y = - 250;
    // Rotate -90 degrees about the X-axis so that the vertical plane is horizontal. Shadows need to be horizontal.
    mesh.rotation.x = - Math.PI / 2;
    scene.add(mesh);
    // Second plane shadow
    mesh = new THREE.Mesh(shadowGeo, shadowMaterial);
    mesh.position.x = - 400;
    mesh.position.y = - 250;
    mesh.rotation.x = - Math.PI / 2;
    scene.add(mesh);
    // The third plane shadow
    mesh = new THREE.Mesh(shadowGeo, shadowMaterial);
    mesh.position.x = 400;
    mesh.position.y = - 250;
    mesh.rotation.x = - Math.PI / 2;
    scene.add(mesh);
}
Copy the code

This generates three plane shadows and places them in the scene. With shadows, we still need the icosahedron that looks like a sphere, so now we’re going to add the icosahedron.

5. Generate icosahedron and give each vertex a different color

  • Every face of our icosahedron is not a solid color. The colors displayed on the surface are gradient. This gradient is created by assigning a different color value to each vertex of the triangle.
// The radius of the 20-hedron is 200 units
var radius = 200;

// Generate three icosahedron
var geometry1 = new THREE.IcosahedronBufferGeometry( radius, 1 );

/ / from 20 sides of vertex arrays (geometry1. Attributes. The position) in the number of vertices, purpose is to set a color attribute for each vertex
var count = geometry1.attributes.position.count;
// Set a color attribute for the geometry. The name of the color attribute must be 'color', so that three.js can recognize it.
geometry1.addAttribute( 'color'.new THREE.BufferAttribute( new Float32Array( count * 3 ), 3));// Since there are three icosahedrons in the scene, we use the clone function to copy the three. The Clone function will produce exactly the same geometry.
var geometry2 = geometry1.clone();
var geometry3 = geometry1.clone();

// Declare a temporary color value that will be used as an intermediate result.
var color = new THREE.Color();

// Get an array of position attributes for three geometries
var positions1 = geometry1.attributes.position;
var positions2 = geometry2.attributes.position;
var positions3 = geometry3.attributes.position;

// Get an array of colors for three geometries
var colors1 = geometry1.attributes.color;
var colors2 = geometry2.attributes.color;
var colors3 = geometry3.attributes.color;

// Use the HSL color space to set the colors. This color space will be described briefly below.
// Set a color for each vertex
for ( var i = 0; i < count; i ++ ) {

    color.setHSL( ( positions1.getY( i ) / radius + 1 ) / 2.1.0.0.5 );
    colors1.setXYZ( i, color.r, color.g, color.b );

    color.setHSL( 0, ( positions2.getY( i ) / radius + 1 ) / 2.0.5 );
    colors2.setXYZ( i, color.r, color.g, color.b );

    color.setRGB( 1.0.8 - ( positions3.getY( i ) / radius + 1 ) / 2.0 );
    colors3.setXYZ( i, color.r, color.g, color.b );

}
Copy the code

6. Create objects that display both the plane and the wireframes

  • The icosahedron is special in that it shows not only the surface but also the wire frame around the surface. The three-. js engine does not support the simultaneous display of flat and wireframes.
  • To achieve this effect, we can create two identical objects of different materials to approximate this effect.
var material = new THREE.MeshPhongMaterial( {
    color: 0xffffff.flatShading: true.vertexColors: THREE.VertexColors,
    shininess: 0});var wireframeMaterial = new THREE.MeshBasicMaterial( { color: 0x000000.wireframe: true.transparent: true});var mesh = new THREE.Mesh( geometry1, material );
var wireframe = new THREE.Mesh( geometry1, wireframeMaterial );
mesh.add( wireframe );
mesh.position.x = - 400;
mesh.rotation.x = - 1.87;
scene.add( mesh );
Copy the code
  • This code uses different materials to draw two mesh models, which use the same geometry object. The wireframes look like this:

7. Initialize the renderer

renderer = new THREE.WebGLRenderer( { antialias: true}); renderer.setPixelRatio(window.devicePixelRatio );
renderer.setSize( fullWidth, fullHeight );
Copy the code

8. Rendering functions

  • We need to render the results of three views
function animate() {

    for ( var i = 0; i < views.length; ++i ) {

        views[ i ].render();

    }

    requestAnimationFrame( animate );

}
Copy the code

9. Let the scene move with the mouse

  • We control the position of the camera by monitoring the movement of the mouse. Here we get the mouse position in real time (mouseX, mouseY).
document.addEventListener('mousemove', onDocumentMouseMove, false );
function onDocumentMouseMove( event ) {
    mouseX = ( event.clientX - windowHalfX );
    mouseY = ( event.clientY - windowHalfY );
}
Copy the code
  • Here some processing is done for event.clientx and Event.clienty, whose origin is the upper left corner of the window, by subtracting half the distance of the window. Set mouseX and mouseY to 0 when the mouse is over the center of the window, so that the origin appears to move to the center of the window.

Dynamic effect display

Codepen sample code