Hello everyone, I’m Qiufeng. In my last post, I talked about the goals of Three.js series and Pokemon games, so today I’m going to talk about perspective following in games through Three.js. I trust my readers to play games at some point, such as King of Glory, PUBG, Pokemon, Zelda, Protogod, etc. Do you know what perspective they are from? Do you know the difference between first person and third person? How can we achieve this in code? If you are curious about the above questions and can’t answer them completely. So please follow me down below.

Perspective on

First of all, let’s look at the concept of first person perspective, third person perspective. In fact for us First person and third person, it is very familiar with, is the first person in his own tone on one thing, such as express autobiography in this form, the third person is innocent bystander, a lot of novels, for example, is he (XXX) expansion came to be, the audience is god perspective look at the whole story. The corresponding first-person perspective and third-person perspective are the same concept, but visually. ** So do they have the above differences? ** The advantage of the first person perspective is that it can bring maximum immersion to the player. Observing the scene and screen from the first person perspective of “I” can make the player feel the details in a more detailed way. The most common ones are things like PUBG and Need for Speed.

And the first-person perspective has its limits. The player’s field of vision is limited, preventing him from seeing the wider field of vision. Another is that the first-person view gives the player “3D vertigo”. Dizziness occurs when the reaction speed is even less than camera speed. What about the third-person perspective? His advantage is freedom and wide vision. The movement of the character is separated from the Angle of view. One is used to control the direction of the character, while the other is used to control the direction of the vision.

Its disadvantage is that it can not focus well on the local, easy to miss details. But in general, most games today offer a switch between the two perspectives to suit different situations. For example, in absolute survival, walking with a third-person view and moving, shooting with a first-person view. Ok, so far we have seen the differences between the first person perspective and the third person perspective. So let’s take the third person perspective as an example, how do we achieve such an effect? (Once written in the third person, it can be changed into the first person with minor modifications, so take the more complicated third person.) How many steps does it take to put an elephant in the fridge? Three steps! Open the fridge, put the elephant in the fridge, close the fridge. Obviously putting an elephant in a fridge is a very difficult thing to do, but at a macro level, it’s three steps. Therefore, we have divided the third person view into three steps:

Steps to break up

We all know that in the physical and real world, we move by our legs. When we take off, we move. So what does this process look like on a larger scale? In fact, if you look at it from outside the Earth, from a more distant point of view, we move more like a translational change. Similarly, when we represent motion in a computer, we use translation. And if you’re not familiar with it now, it doesn’t matter. Let’s look at the following coordinate axis. (The side length of the small square is 1)

The little block moving from position A1 to position A2 is a shift, if you express it mathematically

What does that mean? So we’re going to increase the x value of all the little points in the cube by 2, and keep the y value the same. So let’s just take some arbitrary values and verify that. For example, the little box in position A1 is (0,0) in the lower left corner. By changing above, it becomes (2, 0). If we look at the little box in A2, the new position is (2, 0); If I plug in the (1,1) in the upper right corner, it becomes (3,1), which is exactly where we moved to. So there’s nothing wrong with this. But later on, people decided that something like this was a little bit less general. As to why do you say here is not universal, in the back of the series will explain in detail, because also involves other changes, such as rotation, scaling, they can be used to describe a matrix, a matrix way so if translation is also can be used to express, so the whole problem becomes simple, that is to say: Change in motion = change in matrix Let’s see what happens when we convert our original expression into a matrix:

Can you explain a little bit about where this matrix on the right comes from

The top left part is called the identity matrix, and then the two and zero is the shift that we need, and the reason why we went from two to three is because we introduced the idea of a homogeneous matrix. The same principle, analogies to three dimensions, we need to use a four dimensional matrix. So one of the things that we want to get at the end of this series of examples is that all motion is matrix change.

We all know that in the real world, our eyes have a limited view of what we can see. The same goes for computers. Assuming that our field of view is a 3 by 3 square in a computer, let’s use the previous example. The yellow area is the visible area of our field of view:

So now we’re going to move our little block 3 to the right, and then we’re going to move the net 1.

At this point, we’ll notice that we can no longer see the patch in our field of vision. Imagine we’re playing a shooter and the enemy is moving in front of us. What do we do to find it? Yes, we rotate our heads to expose the enemy to our view. Something like this:

This locks the enemy in, keeping the character in view and relatively still. It’s not enough to have the camera pointing at the person. We also have to have our camera pointing at the person. Why? First of all, we’ll use our axis example, but this time we’ll expand the Z-axis: then we’ll look at the normal plane screenshot

Screenshots:

Now let’s move our little block 1 to -z:

Screenshots:

At this point we see that the cube gets smaller, and the more it moves in the -z direction, the smaller we see it. At this point, we didn’t change our perspective, but we still couldn’t track the patch well. So we need to move to the position of our perspective, when we can’t see a distant landmark, what do we do? That’s right, stay close!

Screenshots:

Perfect! Now we through the explanation of three directions, will be how to achieve a third person perspective function from the theoretical realization!

To get the code

Next we just need to follow our above theory, to achieve the code is good, the code can not be we use another language to achieve the way, know the principle is very simple. 1. Initialize the canvas scene

<canvas class="webgl"></canvas> ... <script> // render scene const scene = new three.scene () // render camera const camera = new three.perspectivecamera (75, sizes.width / sizes.height); camera.position.y = 6; camera.position.z = 18; const controls = new OrbitControls(camera, canvas) controls.enableDamping = true; // Set the damping by calling scene.add(camera) in update; // const renderer = new three. WebGLRenderer({canvas}) renderer.setSize(size.width, sizes.height) renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) renderer.render(scene, camera); </script>Copy the code

Scene, camera, renderer are some fixed things, this section is not mainly to explain, can be understood as our project initialization some necessary statements. This time we opened the page, it was black, for the sake of beauty, I added a floor to the whole scene.

// Set the floor to const geometry = new THREE.PlaneGeometry(1000, 1000, 1, 1); . / / floor map const floorTexture = new THREE ImageUtils. LoadTexture (' 12. Jpeg); floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping; floorTexture.repeat.set( 10, 10 ); // const floorMaterial = new three. MeshBasicMaterial({map: floorTexture, side: three. DoubleSide}); const floor = new THREE.Mesh(geometry, floorMaterial); // Set floor position flores.position. y = -1.5; floor.rotation.x = - Math.PI / 2; scene.add(floor); `! [](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/aa8cea3705594d10a7e01e7225283a78~tplv-k3u1fbpfcp-zoom-1.image) This time the picture is good \~2. Character movement According to the theory, we need to add a character, here for convenience, also add a small square:Copy the code
// Small slider const boxgeometry = new THREE. Boxgeometry (1, 1, 1); const boxMaterials = []; for (let i = 0; i < 6; i++) { const boxMaterial = new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff, }); boxMaterials.push(boxMaterial); } // Small const box = new THREE.Mesh(boxgeometry, boxMaterials); box.position.y = 1; box.position.z = 8; scene.add(box);Copy the code

I added six different colors to the small pieces to make them look good.

It’s still a little rough and ready, but it’s often said that high-end ingredients need only the most understated cooking. It’s a small piece, but it has all the organs. Now that we’ve rendered the tiles, all we have to do is bind the shortcut keys.

Corresponding code:

// Const keyboard = new threex.keyboardState (); const clock = new THREE.Clock(); const tick = () => { const delta = clock.getDelta(); const moveDistance = 5 * delta; const rotateAngle = Math.PI / 2 * delta; if (keyboard.pressed("down")) box.translateZ(moveDistance); if (keyboard.pressed("up")) box.translateZ(-moveDistance); if (keyboard.pressed("left")) box.translateX(-moveDistance); if (keyboard.pressed("right")) box.translateX(moveDistance); If (keyboard.pressed("w")) box.rotateonaxis (new three.vector3 (1,0,0), rotateAngle); If (keyboard.pressed("s")) box.rotateonaxis (new three.vector3 (1,0,0), -rotateangle); If (keyboard.pressed("a")) box.rotateonaxis (new three.vector3 (0,1,0), rotateAngle); Vector3(0,1,0), -rotateangle); if (keyboard.pressed("d")) box.rotateonaxis (new three.vector3 (0,1,0), -rotateangle); renderer.render(scene, camera) window.requestAnimationFrame(tick) } tick();Copy the code

So translateZ, translateX, these two functions are literally translateZ and x, if you want to go forward, you go -z, if you want to go left, you go -x. What does clock.getDelta () mean? Simply put, the getDelta () method is used to get the interval between two executions of the method. For example, we want to move 5 units forward in a second, but moving directly would be too blunt, so we want to animate it. We know that in order to achieve smooth animation, it is generally implemented through the browser’s APIrequestAnimationFrame, and the browser will control the rendering frequency. Under ideal performance, the rendering frequency is about 60 times per second. In actual projects, if the scene to be rendered is more complex, it is generally lower than 60 times. This means that the interval between frames is greater than 16.67ms. So in order to move those 5 units, we split up the distance that we need to move per frame into those 60 renders. And finally, rotateOnAxios, which is basically how you rotate the little box.

RotateOnWorldAxis (Axis: Vector3, Angle: Float) : This axis — a normalized vector in world space. Angle — An Angle expressed in radians.

3. Camera and Character Synchronization Review part of the theory, the last step is that we want to keep the camera (human eye) and the object relatively still, that is, the distance is constant.

const tick = () => { ... const relativeCameraOffset = new THREE.Vector3(0, 5, 10); const cameraOffset = relativeCameraOffset.applyMatrix4( box.matrixWorld ); camera.position.x = cameraOffset.x; camera.position.y = cameraOffset.y; camera.position.z = cameraOffset.z; // Always have the camera look at the object controls.target = box.position; . }Copy the code

There is one more core point is relativeCameraOffset. ApplyMatrix4 (box. MatrixWorld); In fact, we have talked about this in the theory part, because the basic principle of object movement is to make matrix change, so to keep the distance between the camera (human eye) and the object unchanged, we only need to make the camera (human eye) and the object make the same change. In three. js, all changes of the object itself are recorded in the.matrix, so long as the external scene does not change, then the.matrixworld is equal to.matrix. And applyMatrix4 just means multiply.

Results demonstrate

So I finally implemented the whole feature! See you next time!

Source code address: github.com/hua1995116/…

Go back to my previous articles and you may get more!

  • I wrote a 720° shoe showroom for Hongxing Erke: 1100+ likes

  • 2021 Front End Learning Path Book List — The Path to Personal Growth: 570+ likes

  • From a design website on the front-end watermarking (detailed tutorial) : 790+ likes

  • Unlock the secrets of “file download” : 140+ likes

  • 10 cross-domain solutions (with the ultimate trick) : 940+ likes

conclusion

❤️ follow + like + favorites + comments + forward ❤️, original is not easy, encourage the author to create better articles

Pay attention to the public number autumn wind notes, a focus on front-end interview, engineering, open source front-end public number