The article is not well written, and it all depends on the effect of deception

First on the final effect, although my blog is very few dry goods, but the force is still satisfied with myself, I will try to share more in the future, after all, sharing is really a test of the firm knowledge, undiscovered knowledge blind spot, but also a test of writing ability.

Kwokronny. top

Before the construction of the blog need to see a lot of big guy’s blog, big guys although simple interface, but the depth of the content, the article forced lattice, fascinating, without the flashy blog packaging, let everyone compete to read.

I haven’t designed my own website for a long time, so the aesthetic value has declined a lot. After several days of continuous browsing, I decided that if I want to install better than others, I need to use the technology stack that is not commonly used by others. Three. js is the installation scheme THAT I finally choose.

Began to pack to force

Looking for models

In order to achieve the purpose of 3D effect, modeling is required, which is impossible to learn for a while, so I started to look for free non-commercial 3D models, and found a lot of free materials, and finally chose the character model of MineCraft that I love.

SketchFab(https://sketchfab.com/)

The download model is GLTF, and the example we are looking for is GLTFLoader. You can also download the original structure and re-export it through the 3D editor. Here I recommend Blender3D. The model uploader I choose also happens to have the same name, and I don’t know if it is provided by the software provider.

Try to write

After that, I started the trial compilation of Three. js. First of all, I had to read the documentation of Three. js.

The three.js document suggests that you should read the basic knowledge of 3D quickly on the Internet, as well as the articles written by the big guys to teach you how to play Three. js and so on

Most of the time, my learning method is to try to consult the properties and change the properties on the basis of copying the homework. We can first find the examples that can be copied. First, the model I choose just has the relevant three skeleton animations, so reading the source code of this example, you can first introduce the downloaded model and move it

<! DOCTYPEhtml>
<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>Document</title>
    <style>
      html.body {
        height: 100%;
      }
      .bg-canvas {
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <div class="bg-canvas"></div>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/loaders/GLTFLoader.js"></script>
    <script>
      (function () {
        var scene, renderer, camera, container;
        var mixer, clock, actions;

        function init() {
          // Get draw container and container size
          container = document.querySelector(".bg-canvas");
          var width = container.getBoundingClientRect().width;
          var height = container.getBoundingClientRect().height;

          // Instantiate perspective camera, we see the perspective of the camera.
          camera = new THREE.PerspectiveCamera(45, width / height, 1.2000);
          camera.position.set(0.2.16);

          // Let the model frame animation be updated by this instantiated clock
          clock = new THREE.Clock();

          // Instantiate the scene
          scene = new THREE.Scene();

          // Instantiate the hemispheres light, first light the scene according to the light color
          var hemiLight = new THREE.HemisphereLight(0xf2f2f2.0xf2f2f2);
          hemiLight.position.set(0.50.0);
          scene.add(hemiLight);

          // Instantiate sunlight, add shadows while illuminating the model
          var dirLight = new THREE.DirectionalLight(0xffffff);
          dirLight.position.set(0.30.0);
          dirLight.castShadow = true;
          dirLight.shadow.camera.near = 0.1;
          dirLight.shadow.camera.far = 60;
          scene.add(dirLight);

          var loader = new THREE.GLTFLoader();

          // Load the model
          loader.load("./zombie.gltf".function (gltf) {
            var model = gltf.scene;
            model.traverse(function (object) {
              if (object.isMesh) {
                object.frustumCulled = false;
                // Cast shadows
                object.castShadow = true; }}); model.position.set(0.6.0.2.5);
            model.scale.set(1.5.1.5.1.5);
            scene.add(model);

            // Instantiate the animation mixer
            mixer = new THREE.AnimationMixer(model);
            actions = {
              push_up: mixer.clipAction(gltf.animations[0]),
              idle: mixer.clipAction(gltf.animations[1]),
              walk: mixer.clipAction(gltf.animations[2]),}; actions.idle.play();// Loader takes time to load, so our render animation behavior needs to be in loader's callback function
            animate();
          });

          // Instantiate the WebGL renderer, the configuration can be adjusted against the documentation
          renderer = new THREE.WebGLRenderer({ alpha: true.antialias: true });
          renderer.setPixelRatio(window.devicePixelRatio);
          renderer.setSize(width, height);
          renderer.outputEncoding = THREE.sRGBEncoding;
          renderer.shadowMap.enabled = true;

          renderer.setSize(width, height);
          container.appendChild(renderer.domElement);
        }

        // Animation loop
        function animate() {
          requestAnimationFrame(animate);
          var delta = clock.getDelta();
          mixer.update(delta);
          render();
        }

        function render() { renderer.render(scene, camera); } init(); }) ();</script>
  </body>
</html>
Copy the code

After the above example is completed, we have a general understanding of how to add models, animation rendering, camera perspective, etc., by referring to the relevant classes, check the properties and functions, you can roughly master its usage.

I forget where I got the skin texture, maybe I found a picture with the same UV texture in the model on another download website, just replace the picture, you can download by yourself if necessary

Add elements

There is only one protagonist that is relatively monotonous, we can add some other models according to what we learned from the homework, and enrich the scene.

Finally decided to add this model

// ...
// loader is an instantiated loader and does not need to instantiate the loader multiple times to load the model
loader.load("/gltf/pumpkin.gltf".function (gltf) {
  var model = gltf.scene;
  model.traverse(function (object) {
    if (object.isMesh) {
      object.frustumCulled = false;
      object.castShadow = true; }}); model.rotation.set(0.1.0);
  model.position.set(1.0.1, -2.4);
  let scale = 0.33;
  model.scale.set(scale, scale, scale);
  scene.add(model);
});
// ...
Copy the code

The scene doesn’t have ground for him yet, Zombie and pumpkin are still hanging in the air and need another piece of ground. I randomly searched a lawn map in MineCraft, found a potentially related example in the three.js sample, which happened to have grass in the first one, and found the code snippet in elementary School English.

It is intended to add some simple interactions to the 3D effect, and in order to ensure that the 3D effect is presented in a similar way to the exhibition hall, buttons are available to control the rotation of the main body and the action switch of the Zombie. Finally, the 3D effect is completed by selecting CylinderGeometry.

We also need to adjust the effect of the subject to a suitable position, and when controlling rotation, we need to rotate with multiple geometry, so we need to give these three subject groups.

// Create a 3D object that includes all three subjects of the main effect
stage = new THREE.Object3D();
scene.add(stage);

// New grass

var groundTexture = new THREE.TextureLoader().load("/gltf/textures/grass.png");
// Set the horizontal and vertical application of the texture to repeat rendering
groundTexture.wrapS = groundTexture.wrapT = THREE.RepeatWrapping;
// Set the number of repeat renderings of the texture
groundTexture.repeat.set(4.4);
// Add clarity to the material
groundTexture.anisotropy = 16;
groundTexture.encoding = THREE.sRGBEncoding;

var bottomBase = new THREE.Mesh(new THREE.CylinderBufferGeometry(5.5.0.1.32), new THREE.MeshLambertMaterial({ map: groundTexture }));
// Whether the material accepts shadows
bottomBase.receiveShadow = true;
stage.add(bottomBase);

// ...
// And add scene.add(model) to the loader callback instead
stage.add(model);
Copy the code

Add hazardous containment zones

After confirming the main effect of the layout, because the main effect is mainly in the lower right corner, the upper right corner always feel a little empty, appropriate imagine the scene, finally thought of increasing the isolation belt, yellow and green collocation is also accidentally appropriate, also incidentally set the main color of the blog and other colors design.

Initially, CSS3 applied animation to adjust background-position to achieve the dynamic effect of isolation band. However, those who have a solid foundation in this scheme will find it easy to cause redrawing, and the CPU will be whirring, which is very disturbing.

Therefore, we took some time to change the isolation belt to three.js recently. First of all, we first tried to copy the work in the official example, but did not find similar related examples, we learned from the previous copy work, probably think out the way to achieve the effect, the common nature is texture offset, texture animation.

Texture array, Offset, rotation (Texture animation)

The code implementation for the final quarantine:

// Declare the texture variable outside the animate function because it needs to be referenced
var warningTexture;

/ /...
//function init(){
warningTexture = new THREE.TextureLoader().load("/img/warning_zone.png");
warningTexture.wrapS = THREE.RepeatWrapping;
warningTexture.repeat.set(4.1);

var warningBar = new THREE.Mesh(
  // The geometry is the buffer geometry
  new THREE.PlaneGeometry((0.8 * (424 * 4)) / 60.0.8),
  new THREE.MeshBasicMaterial({ map: warningTexture })
);
scene.add(warningBar);

/ /...
//function animate(){
/ /...
warningTexture.offset.x -= 0.007;
/ /}
Copy the code

To be continued

My blog is an attempt to write a theme based on hexo, which has not been organized into an open source theme project. I will try to share it for your reference when I have time later.

Three. Js I’m just a chicken, big guy look at the excitement, don’t laugh at me, there are good gameplay, also hope not hesitate to give advice ~ haha haha.

Attachment: final code

<! DOCTYPEhtml>
<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>Document</title>
    <style>
      html.body {
        height: 100%;
      }
      .bg-canvas {
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <div class="bg-canvas"></div>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/loaders/GLTFLoader.js"></script>
    <script>
      (function () {
        var scene, renderer, camera, container;
        var mixer, clock, actions, warningTexture;

        function init() {
          // Get draw container and container size
          container = document.querySelector(".bg-canvas");
          var width = container.getBoundingClientRect().width;
          var height = container.getBoundingClientRect().height;

          // Instantiate perspective camera, we see the perspective of the camera.
          camera = new THREE.PerspectiveCamera(45, width / height, 1.2000);
          camera.position.set(0.2.16);

          clock = new THREE.Clock();

          // Instantiate the scene
          scene = new THREE.Scene();

          // Instantiate the hemispheres light, first light the scene according to the light color
          var hemiLight = new THREE.HemisphereLight(0xf2f2f2.0xf2f2f2);
          hemiLight.position.set(0.50.0);
          scene.add(hemiLight);

          var dirLight = new THREE.DirectionalLight(0xffffff);
          dirLight.position.set(0.30.0);
          dirLight.castShadow = true;
          dirLight.shadow.camera.near = 0.1;
          dirLight.shadow.camera.far = 60;
          scene.add(dirLight);

          warningTexture = new THREE.TextureLoader().load("./warning_zone.png");
          warningTexture.wrapS = THREE.RepeatWrapping;
          warningTexture.repeat.set(4.1);

          var warningBar = new THREE.Mesh(
            // The geometry is the buffer geometry
            new THREE.PlaneGeometry((0.8 * (424 * 4)) / 60.0.8),
            new THREE.MeshBasicMaterial({ map: warningTexture })
          );
          warningBar.position.set(0.1.5.5.4);
          warningBar.rotation.set(0, -0.3, -0.1);
          scene.add(warningBar);

          stage = new THREE.Object3D();
          scene.add(stage);

          var groundTexture = new THREE.TextureLoader().load("./textures/grass.png");
          groundTexture.wrapS = groundTexture.wrapT = THREE.RepeatWrapping;
          groundTexture.repeat.set(4.4);
          groundTexture.anisotropy = 16;
          groundTexture.encoding = THREE.sRGBEncoding;

          var bottomBase = new THREE.Mesh(new THREE.CylinderBufferGeometry(5.5.0.1.32), new THREE.MeshLambertMaterial({ map: groundTexture }));
          bottomBase.receiveShadow = true;
          stage.add(bottomBase);

          var loader = new THREE.GLTFLoader();

          loader.load("./pumpkin.gltf".function (gltf) {
            var model = gltf.scene;
            model.traverse(function (object) {
              if (object.isMesh) {
                object.frustumCulled = false;
                object.castShadow = true; }}); model.rotation.set(0.1.0);
            model.position.set(1.0.1, -2.4);
            let scale = 0.33;
            model.scale.set(scale, scale, scale);
            stage.add(model);
          });
          // Load the model
          loader.load("./zombie.gltf".function (gltf) {
            var model = gltf.scene;
            model.traverse(function (object) {
              if (object.isMesh) {
                object.frustumCulled = false;
                // Cast shadows
                object.castShadow = true; }}); model.position.set(0.6.0.2.5);
            model.scale.set(1.5.1.5.1.5);
            stage.add(model);

            // Instantiate the animation mixer
            mixer = new THREE.AnimationMixer(model);
            actions = {
              push_up: mixer.clipAction(gltf.animations[0]),
              idle: mixer.clipAction(gltf.animations[1]),
              walk: mixer.clipAction(gltf.animations[2]),}; actions.walk.play(); animate(); });// Instantiate the WebGL renderer, the configuration can be adjusted against the documentation
          renderer = new THREE.WebGLRenderer({ alpha: true.antialias: true });
          renderer.setPixelRatio(window.devicePixelRatio);
          renderer.setSize(width, height);
          renderer.outputEncoding = THREE.sRGBEncoding;
          renderer.shadowMap.enabled = true;

          renderer.setSize(width, height);
          container.appendChild(renderer.domElement);
        }

        function animate() {
          requestAnimationFrame(animate);
          var delta = clock.getDelta();
          warningTexture.offset.x -= 0.007;
          mixer.update(delta);
          render();
        }

        function render() { renderer.render(scene, camera); } init(); }) ();</script>
  </body>
</html>
Copy the code