“This is the 41st day of my participation in the First Challenge 2022.

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

We talked in the last video about multi-camera, multi-view, multi-angle photography, but there are a few other things we need to know about multi-view photography. What about 3dMax-like multi-view displays? Let’s take a look.

3Dmax multi-view

  • If you have worked with 3Dmax, you are familiar with multiple views. See below

  • An object is displayed on our 3Dmax software, but we have 4 Windows showing the front, side, bevel, perspective and solid effects of the object.
  • We can achieve a similar effect with three.js, so let’s get started.

Results show

  • We added three icosaheds and corresponding shadows to the scene. By setting the camera in different positions, the effect is similar to 3Dmax

  • Figure 1: Frontal view
  • Figure 2: Side view
  • Figure 3: The effect seen above
  • Figure 4: The bevel view
  • Figure 1234 will be used to illustrate which part of the work is being done

Scene rendering mode

  • There are actually two ways to render:
    • Multiple cameras, multiple renderers, single scene
      • This is what we did in the last section
    • Multiple cameras, multiple renderers, multiple scenes
      • In this section we are going to talk about rendering
  • implementation
    • Through a scene, put three icosahedron
    • Add the scene to the 4 containers, at this time we do not set up the camera or set up a camera, 4 containers show the same effect
    • By placing four cameras in different positions, different effects can be seen

Static interface

  • Let’s lay out the HTML first
  • We prepared four containers to lay out our scene
<div id="container">
  <div id="container1"></div>
  <div id="container2"></div>
  <div id="container3"></div>
  <div id="container4"></div>
</div>
Copy the code
body {
		color: #808080;
		font-family: Monospace;
		font-size: 13px;
		text-align: center;

		background-color: #fff;
		margin: 0px;
		overflow: hidden;
	}

	#container {
		position: relative;
	}

	#container1,
	#container2,
	#container3,
	#container4 {
		position: absolute;
		border: 1px solid red;
	}

	#container1 {
		width: 500px;
		height: 250px;
	}

	#container2 {
		width: 500px;
		height: 250px;
		left: 520px;
	}

	#container3 {
		width: 500px;
		height: 250px;
		top: 270px;
	}

	#container4 {
		width: 500px;
		height: 250px;
		top: 270px;
		left: 520px;
	}
Copy the code

Initialize the view

  • We need to initialize four canvases to place the different camera positions in our scene
function initView() {
    container1 = document.getElementById("container1");
    container2 = document.getElementById("container2");
    container3 = document.getElementById("container3");
    container4 = document.getElementById("container4");
}
Copy the code

Initialization Scenario

  • We initialize a scene to put our objects, camera, lights, etc
function initScene() {
    scene = new THREE.Scene();
}
Copy the code

Initialize light

  • Initialize an ambient light and add it to the scene
function initLight() {
    light = new THREE.DirectionalLight(0xffffff);
    light.position.set(0.0.1).normalize();
    scene.add(light);
}
Copy the code

Initializing the camera

  • The cameras we use are perspective projections
  • Set distance
const near = 1
const far = 10000
Copy the code

Figure 1 Camera

  • The camera in Figure 1 is looking into the screen
camera1 = new THREE.PerspectiveCamera(45.500 / 250, near, far);
camera1.setViewOffset(500.250.0.0.500.250)
camera1.position.z = 1800 // The z-axis looks towards the origin, facing the screen
Copy the code

Figure 2 Camera

  • Figure 2. The camera needed, as seen from the side
camera2 = new THREE.PerspectiveCamera(45.500 / 250, near, far);
camera2.setViewOffset(500.250.0.0.500.250)
camera2.position.x = 1800 // The X-axis looks at the origin, from the side of the ball to the left
Copy the code
  • Similarly, a camera looking from right to left is placed in Figure 1

Figure 3 Camera

  • Figure 3. The camera needed is viewed from above
    • Here, when we adjust the y position, we also need to adjust the shutter direction to ensure that the shutter is parallel to the Y axis
camera3 = new THREE.PerspectiveCamera(45.500 / 250, near, far);
camera3.setViewOffset(500.250.0.0.500.250)
camera3.position.y = 1800 // The Y-axis is looking at the origin, looking down from above the ball
camera3.up.set(0.0.1) // default is (0,1,0), adjust the shutter direction parallel to the y axis
Copy the code
  • Similar to a downward-looking camera is placed in Figure 1

Figure 4 Camera

  • Figure 3 requires a camera that looks from the bottom right to the top left
camera4 = new THREE.PerspectiveCamera(45.500 / 250, near, far);
camera4.setViewOffset(500.250.0.0.500.250)
// Look at the object diagonally
camera4.position.x = 300
camera4.position.z = 800
Copy the code
  • Similar to a downward-looking camera is placed in Figure 1

Initialize the 20-sided geometry

  • We did that in the last video, but I’m not going to do that in this video, I’m going to look at the code
var shadowMaterial;

function createShadowByCanvas() {
    // 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);
    // Turn the canvas into a texture
    var shadowTexture = new THREE.CanvasTexture(canvas);
    shadowTexture.needsUpdate = true;
    // Add a texture to the material
    shadowMaterial = new THREE.MeshBasicMaterial({ map: shadowTexture });
}

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);
}

// Initialize the object
function initObject() {
    // The radius of the 20-hedron is 200 units
    var radius = 200;

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

    // 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();

    var faceIndices = ['a'.'b'.'c'.'d'];

    var color, f1, f2, f3, p, n, vertexIndex;
 
    for (var i = 0; i < geometry1.faces.length; i++) {

        f1 = geometry1.faces[i];
        f2 = geometry2.faces[i];
        f3 = geometry3.faces[i];

        n = (f1 instanceof THREE.Face3) ? 3 : 4;

        for (var j = 0; j < n; j++) {

            vertexIndex = f1[faceIndices[j]];

            p = geometry1.vertices[vertexIndex];

            color = new THREE.Color(0xffffff);
            color.setHSL((p.y / radius + 1) / 2.1.0.1.0);

            f1.vertexColors[j] = color;

            color = new THREE.Color(0xffffff);
            color.setHSL(0.0, (p.y / radius + 1) / 2.1.0);

            f2.vertexColors[j] = color;

            color = new THREE.Color(0xffffff);
            color.setHSL(0.125 * vertexIndex / geometry1.vertices.length, 1.0.1.0); f3.vertexColors[j] = color; }}var materials = [
        new THREE.MeshLambertMaterial({ color: 0xffffff.shading: THREE.FlatShading, vertexColors: THREE.VertexColors }),
        new THREE.MeshBasicMaterial({ color: 0x000000.shading: THREE.FlatShading, wireframe: true.transparent: true})];/* -- geometry 1-- */
    group1 = THREE.SceneUtils.createMultiMaterialObject( geometry1, materials );
    group1.position.x = -400;
    group1.rotation.x = -1.87;
    scene.add( group1 );
    /* -- geometry 2-- */
    group2 = THREE.SceneUtils.createMultiMaterialObject( geometry2, materials );
    group2.position.x = 400;
    group2.rotation.x = 0;
    scene.add( group2 );
    /* -- geometry 3-- */
    group3 = THREE.SceneUtils.createMultiMaterialObject( geometry3, materials );
    group3.position.x = 0;
    group3.rotation.x = 0;
    scene.add( group3 );
}
Copy the code
  • In the last section, we used the r93 version to implement the 20-sided geometry. In this section, we use the R73 version to implement the geometry, because the R73 version does not existIcosahedronBufferGeometryThis way, so we go throughIcosahedronGeometryMethod to implement.
  • It’s used here as wellTHREE.SceneUtils.createMultiMaterialObjectMethod, which adds an array of materials to a geometry

Initialize the renderer

  • We need 4 renderers to add to 4 containers
renderer1 = new THREE.WebGLRenderer({ antialias: true });
renderer1.setSize(500.250);

renderer2 = new THREE.WebGLRenderer({ antialias: true });
renderer2.setSize(500.250);

renderer3 = new THREE.WebGLRenderer({ antialias: true });
renderer3.setSize(500.250);

renderer4 = new THREE.WebGLRenderer({ antialias: true });
renderer4.setSize(500.250);

container1.appendChild(renderer1.domElement);
container2.appendChild(renderer2.domElement);
container3.appendChild(renderer3.domElement);
container4.appendChild(renderer4.domElement);

Copy the code
  • If only one renderer is used, adding the renderer to the four containers will result in only the last container adding the renderer, which will look like this

Rendering function

  • We need all four cameras to look at the scene, otherwise the camera may not be able to see our object.
function animation() {
    render()
    requestAnimationFrame(animation);
}


function render() {
    camera1.lookAt(scene.position)
    camera2.lookAt(scene.position)
    camera3.lookAt(scene.position)
    camera4.lookAt(scene.position)

    renderer1.render(scene, camera1)
    renderer2.render(scene, camera2)
    renderer3.render(scene, camera3)
    renderer4.render(scene, camera4)
}
Copy the code

Codepen sample code