19
头图

background

Year of the Tiger 🐅 Spring Festival is approaching, this article uses the React + Three.js technology stack to realize the interesting 3D creative page. Knowledge contained herein include: ShadowMaterial , MeshPhongMaterial two basic materials, using LoadingManager display model loading progress, OrbitControls easing animation, TWEEN between simple motion tween effects.

accomplish

👀 online preview, already adapted to mobile terminal: https://dragonir.github.io/3d/#/lunar

Introduce resources

Wherein GLTFLoader , FBXLoader for added models, OrbitControls user orbit control lens, TWEEN for generating inter-tween.

import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { TWEEN } from "three/examples/jsm/libs/tween.module.min.js";

scene initialization

This part of the content is mainly used to initialize the scene and parameters. For a detailed explanation, you can click the link at the end of the article to read my previous article, and I will not repeat it in this article.

container = document.getElementById('container');
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
container.appendChild(renderer.domElement);
// 场景
scene = new THREE.Scene();
scene.background = new THREE.TextureLoader().load(bgTexture);
// 雾化效果
scene.fog = new THREE.Fog(0xdddddd, 100, 120);
// 摄像机
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(100, 100, 100);
camera.lookAt(new THREE.Vector3(0, 0, 0));
// 平行光
const cube = new THREE.Mesh(new THREE.BoxGeometry(0.001, 0.001, 0.001), new THREE.MeshLambertMaterial({ color: 0xdc161a }));
cube.position.set(0, 0, 0);
light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(20, 20, 8);
light.target = cube;
scene.add(light);
// 环境光
const ambientLight = new THREE.AmbientLight(0xffffff);
scene.add(ambientLight);
// 聚光灯
const spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-20, 20, -2);
scene.add(spotLight);

💡 Fog scene fog

In this example, when the page is model 161dcd6a0e98f1 is loaded from far to near, and the function that the color changes from white to color is realized by Fog . Fog class defines linear fog, and the density of fog increases linearly with distance, that is, the fog effect of objects in the scene changes linearly with distance.

Constructor : Fog(color, near, far) .

  • color attribute: Indicates the color of the fog. For example, if it is set to red, the distant object in the scene is black, the closest object in the scene is its own color, and the color of the object between the farthest and the closest is the mixture of the object's own color and the fog color.
  • near property: Indicates the minimum distance to apply the fog effect near from the active camera will not be affected by the fog.
  • far property: Indicates the maximum distance to apply the fog effect far from the active camera will not be affected by the fog.

Create the ground

In the present embodiment using the background image, I need a both display the background is transparent, the material can produce a shadow generate ground, then uses the ShadowMaterial material.

var planeGeometry = new THREE.PlaneGeometry(100, 100);
var planeMaterial = new THREE.ShadowMaterial({ opacity: .5 });
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.rotation.x = -0.5 * Math.PI;
plane.position.set(0, -8, 0);
plane.receiveShadow = true;
scene.add(plane);

💡 ShadowMaterial

This material can receive shadows, but is otherwise completely transparent.

constructor : ShadowMaterial(parameters: Object)

  • parameters : (optional) An object that defines the appearance of the material, with one or more properties.

special attributes :

  • .isShadowMaterial[Boolean] : Used to check if this class or a derived class is a shadow material. The default value is true . Since it is usually used for internal optimization, this property value should not be changed.
  • .transparent[Boolean] : Defines whether this material is transparent or not. The default is true .

Create a magic circle

Create a cool spinning self-illuminating circular magic circle on the bottom ground of the tiger 🐅

cycle = new THREE.Mesh(new THREE.PlaneGeometry(40, 40), new THREE.MeshPhongMaterial({
  map: new THREE.TextureLoader().load(cycleTexture),
  transparent: true
}));
cycle.rotation.x = -0.5 * Math.PI;
cycle.position.set(0, -9, 0);
cycle.receiveShadow = true;
scene.add(cycle);

Magic Array's sticker:

💡 MeshPhongMaterial

A material for glossy surfaces with specular highlights. This material uses the non-physical Blinn-Phong model to calculate reflectance.

constructor : MeshPhongMaterial(parameters: Object)

  • parameters : (optional) An object that defines the appearance of the material, with one or more properties.

special properties :

  • .emissive[Color] : The emissive (light) color of the material, basically an inherent color unaffected by other lights. Default is black.
  • .emissiveMap[Texture] : Sets the emission (glow) map. The default value is null . The emission map color is adjusted by the emission color and intensity. If you have an emission map, be sure to set the emission color to something other than black.
  • .emissiveIntensity[Float] : Emitted light intensity. Adjust the glow color. Defaults to 1 .
  • .shininess[Float] : specular , the higher the value, the brighter it is. The default value is 30 .
  • .specular[Color] : The specular color of the material. The default is 0x111111 for the color Color . This defines the glossiness and glossy color of the material.
  • .specularMap[Texture] : The specular map value affects how much the specular and the environment map affect the surface. The default value is null .
And MeshLambertMaterial used in Lambertian different models, can simulate the glossy surface of the material (e.g., painted wood) having a specular highlights. Use Phong calculation coloring coloring model, calculates the shadow of each pixel, and MeshLambertMaterial used Gouraud compared to the model, the model is more accurate results, but at the expense of some performance.
MeshStandardMaterial and MeshPhysicalMaterial also use this shading model. When MeshStandardMaterial or MeshPhysicalMaterial , performance is generally higher at the expense of some graphics precision.

text model

Use FBXLoader to load the 061dcd6a0e9ef9 text model of Gong Xi 3D

const fbxLoader = new FBXLoader();
fbxLoader.load(textModel, mesh => {
  mesh.traverse(child => {
    if (child.isMesh) {
      meshes.push(mesh);
      child.castShadow = true;
      child.receiveShadow = true;
      // 调节材质的金属度、粗糙度、颜色等样式
      child.material.metalness = .2;
      child.material.roughness = .8;
      child.material.color = new THREE.Color(0x111111);
    }
  });
  mesh.position.set(4, 6, -8);
  mesh.rotation.set(-80, 0, 0);
  mesh.scale.set(.32, .32, .32);
  group.add(mesh);
});

📹 3D Text generation tutorial Portal: iBlender Chinese version plug-in foreigners teach you to use Chinese fonts Font 3D Chinese And Japanese Characters Blender plug-in tutorial

tiger model

Tiger model gltf format, using GLTFLoader loading process model, found 🕷 bug , loader can not read to the model volume total value, then using a common loader LoadingManager to manage model loading progress.

const manager = new THREE.LoadingManager();
manager.onStart = (url, loaded, total) => {};
manager.onLoad = () => {};
manager.onProgress = async(url, loaded, total) => {
  if (Math.floor(loaded / total * 100) === 100) {
    this.setState({ loadingProcess: Math.floor(loaded / total * 100) });
  } else {
    this.setState({ loadingProcess: Math.floor(loaded / total * 100) });
  }
};
const gltfLoader = new GLTFLoader(manager);
gltfLoader.load(tigerModel, mesh => {
  mesh.scene.traverse(child => {
    if (child.isMesh) {
      child.castShadow = true;
      child.material.metalness = 0;
      child.material.roughness = .8;
      child.material.transparent = true;
      child.material.side = THREE.DoubleSide;
      child.material.color = new THREE.Color(0xffffff);
    }
  });
  mesh.scene.rotation.y = Math.PI * 9 / 8;
  mesh.scene.position.set(0, -4, 2);
  mesh.scene.scale.set(.75, .75, .75);
  // 💡 加载模型自身动画
  let meshAnimation = mesh.animations[0];
  mixer = new THREE.AnimationMixer(mesh.scene);
  let animationClip = meshAnimation;
  let clipAction = mixer.clipAction(animationClip).play();
  animationClip = clipAction.getClip();
  group.add(mesh.scene);
  scene.add(group)
});

💡 LoadingManager Loader Manager

Its function is to process and keep track of loaded and pending data. If the hardening manager is not set manually, a default global instance loader manager is created and used for the loader. In general, the default load manager is sufficient, but sometimes it is necessary to set up separate loaders, for example, when you want to display separate load bars for objects and textures.

Constructor : LoadingManager(onLoad: Function, onProgress: Function, onError: Function)

  • onLoad : optional, this function will be called when all loaders are loaded.
  • onProgress : optional, this function will be called when each item is complete.
  • onError : optional, this function will be called when a loader encounters an error.

attribute :

  • .onStart[Function] : Called when loading starts. Parameters: url loaded items url ; itemsLoaded currently has the number of add-ons; itemsTotal total of the number of add-ons required. This method is undefined by default.
  • .onLoad[Function] : This function will be called when all items are loaded. By default, this method is undefined unless passed in the constructor.
  • .onProgress[Function] : This method loads each item and is called when the load is complete. Parameters: url loaded items url ; itemsLoaded currently has the number of add-ons; itemsTotal total of the number of add-ons required. By default, this method is undefined unless passed in the constructor.
  • .onError[Function] : This method will be called on any item loading error. Parameters: url of the wrong entry url . By default, this method is undefined unless passed in the constructor.

Add camera movement tweens

After the model is loaded, by using a combination TWEEN.js achieve camera 📷 mobile roaming, that is, to see when you open the page model nearly progressively larger from far and animated.

const Animations = {
  animateCamera: (camera, controls, newP, newT, time = 2000, callBack) => {
    var tween = new TWEEN.Tween({
      x1: camera.position.x,
      y1: camera.position.y,
      z1: camera.position.z,
      x2: controls.target.x,
      y2: controls.target.y,
      z2: controls.target.z,
    });
    tween.to({
      x1: newP.x,
      y1: newP.y,
      z1: newP.z,
      x2: newT.x,
      y2: newT.y,
      z2: newT.z,
    }, time);
    tween.onUpdate(function (object) {
      camera.position.x = object.x1;
      camera.position.y = object.y1;
      camera.position.z = object.z1;
      controls.target.x = object.x2;
      controls.target.y = object.y2;
      controls.target.z = object.z2;
      controls.update();
    });
    tween.onComplete(function () {
      controls.enabled = true;
      callBack();
    });
    tween.easing(TWEEN.Easing.Cubic.InOut);
    tween.start();
  },
}
export default Animations;

Example of calling:

Animations.animateCamera(camera, controls, { x: 0, y: 5, z: 21 }, { x: 0, y: 0, z: 0 }, 2400, () => {});

💡 TWEEN.js

Is a tween animation library that can achieve many animation effects. It makes an object easing from one state to another in a certain period of time. TWEEN.js essence of 061dcd6a0ea2ec is a series of easing function algorithms. Combining Canvas and Three.js can easily achieve many effects.

basically uses :

var tween = new TWEEN.Tween({x: 1})     // position: {x: 1}
.delay(100)                             // 等待100ms
.to({x: 200}, 1000)                     // 1s时间,x到200
.onUpdate(render)                       // 变更期间执行render方法
.onComplete(() => {})                   // 动画完成
.onStop(() => {})                       // 动画停止
.start();                               // 开启动画

📌 make the animation really move, you need to call the update method requestAnimationFrame

TWEEN.update()

Easing Type :

TWEEN.js most powerful part of 061dcd6a0ea3b5 is that it provides many commonly used easing animation types, specified api easing() As used in the example:

tween.easing(TWEEN.Easing.Cubic.InOut);

chained calls to :

TWEEN.js support chained calls, such as in after the end of the animation to be performed A animation B, can do tweenA.chain(tweenB) take advantage of chained calls back and forth to create a cyclical animation:

var tweenA = new TWEEN.Tween(position).to({x: 200}, 1000);
var tweenB = new TWEEN.Tween(position).to({x: 0}, 1000);
tweenA.chain(tweenB);
tweenB.chain(tweenA);
tweenA.start();

Controller jog movement

controls.enableDamping can be set to true to enable the easing effect when the mouse moves the scene, resulting in motion inertia. After opening, 3D more realistic.

controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 0);
controls.enableDamping = true;
controls.maxDistance = 160;

💡 THREE.OrbitControls Parameter control list

//鼠标控制是否可用
controls.enabled = true;
//聚焦坐标
controls.target = new THREE.Vector3();
//最大最小相机移动距离(PerspectiveCamera 景深相机)
controls.minDistance = 0;
controls.maxDistance = Infinity;
//最大最小鼠标缩放大小(OrthographicCamera正交相机)
controls.minZoom = 0;
controls.maxZoom = Infinity;
//最大仰视角和俯视角,范围是0到Math.PI
controls.minPolarAngle = 0;
controls.maxPolarAngle = Math.PI;
//水平方向视角限制,范围[-Math.PI, Math.PI]
controls.minAzimuthAngle = - Infinity;
controls.maxAzimuthAngle = Infinity;
//惯性滑动,滑动大小默认0.25,若开启,那么controls.update()需要加到动画循环函数中
controls.enableDamping = false;
controls.dampingFactor = 0.25;
//滚轮是否可控制zoom,zoom速度默认1
controls.enableZoom = true;
controls.zoomSpeed = 1.0;
//是否可旋转,旋转速度
controls.enableRotate = true;
controls.rotateSpeed = 1.0;
//是否可平移,默认移动速度为7px
controls.enablePan = true;
// 点击箭头键时移动的像素值
controls.keyPanSpeed = 7.0;
//是否自动旋转,自动旋转速度。默认每秒30圈,如果是enabled,那么controls.update()需要加到动画循环函数中
controls.autoRotate = false;
// 当fps为60时每转30s
controls.autoRotateSpeed = 2.0;
//是否能使用键盘
controls.enableKeys = true;
//默认键盘控制上下左右的键
controls.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
//鼠标点击按钮
controls.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT };

Finally don't forget to add the window scaling fit method and the requestAnimationFrame update method.

function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
  let time = clock.getDelta();
  // 老虎动画
  mixer && mixer.update(time);
  // 补间动画
  TWEEN && TWEEN.update();
  // 控制器
  controls && controls.update();
  // 魔法阵
  cycle && (cycle.rotation.z += .01);
}

Loading page 3D text style

3D mainly realized by superimposing multiple layers of text-shadow .

.loading {
  font-size: 64px;
  color: #FFFFFF;
  text-shadow:     0 1px 0 hsl(174,5%,80%),
                   0 2px 0 hsl(174,5%,75%),
                   0 3px 0 hsl(174,5%,70%),
                   0 4px 0 hsl(174,5%,66%),
                   0 5px 0 hsl(174,5%,64%),
                   0 6px 0 hsl(174,5%,62%),
                   0 7px 0 hsl(174,5%,61%),
                   0 8px 0 hsl(174,5%,60%),
                   0 0 5px rgba(0,0,0,.05),
                  0 1px 3px rgba(0,0,0,.2),
                  0 3px 5px rgba(0,0,0,.2),
                 0 5px 10px rgba(0,0,0,.2),
                0 10px 10px rgba(0,0,0,.2),
                0 20px 20px rgba(0,0,0,.3);
}

Effect

The final effect is shown in the figure below. If you are interested, you can preview it online. It has been adapted to the mobile terminal. by this accelerated 161dcd6a0ea624 cerebellum axe 🐅 animation.

Summarize

The main knowledge points involved in this article include:

  • Fog scene fogging
  • ShadowMaterial Shadow Material
  • MeshPhongMaterial mesh material
  • LoadingManager Loader Manager
  • TWEEN.js tween
  • THREE.OrbitControls parameter control
  • CSS 3D Text style

appendix

To learn about scene initialization, lighting, shadows, and other mesh geometry, read my other articles. If you think the article is helpful to you, don't forget to one-click three-link 😂 .

Author of this article: dragonir

dragonir
1.8k 声望3.9k 粉丝

Accepted ✔