3
头图

background

Facebook recently changed its parent company's name to Meta and announced that it has officially begun to enter the meta universe 🪐 field. This article mainly Three.js Meta 's cool 3D dynamic Logo through the 061965569e3ee6 + Blender technology stack, including the basic model torus, torus kinks, pipeline and model generation, model loading, adding animation, adding click events, changing materials, etc.

What is meta universe

yuan universe Metaverse term comes from 1992 in Neal Stephenson's "avalanche", the book describes a parallel to the real world virtual world Metaverse , all in real life people have a network avatar Avatar . Wikipedia description of the yuan universe: through enhanced physical virtual reality, showing the convergence of physical and persistent feature, based on the future of the Internet, with links perception and sharing features 3D virtual space .

The connotation of the meta universe is to absorb the information revolution 5G/6G , Internet revolution web3.0 , artificial intelligence revolution, and VR , AR , MR , especially the results of the virtual reality technology revolution including game engines, showing humans construction and traditional physics The possibility of the world’s parallel holographic digital world; triggered the interaction of information science, quantum science, mathematics and life sciences, and changed the scientific paradigm; promoted breakthroughs in traditional philosophy, sociology and even human science systems; encompassed all digital technologies . Just the scene in the movie 161965569e404a "Number One Player" one day in the future, people can switch their identities anytime and anywhere, freely shuttle between the physical world and the digital world, and live and learn in the meta-universe formed by virtual space and time nodes.

Achieve effect

Entering the topic, let's take a look at the implementation effect of the example in this article.

🔗 online preview: https://dragonir.github.io/3d-meta-logo (due to the large model, the loading progress may be slow, and you need to wait patiently)

Development and realization

📌 Note: The above example animation shows Trial 4 . If you don’t want to see the trial and error process (Trial 1, Trial 2, Trial 3), you can jump directly to Trial 4 paragraph to see the detailed implementation Process. Difficulties are listed in the failure process. If you know the solution, please feel free to enlighten me in the comment area.

Before development, let's take a look at Meta Logo , we can find that it is a ring formed by folding and twisting , so the realization of it can start from the realization of the ring.

Trial 1: THREE.TorusGeometry

Three.js base geometry provides THREE.TorusGeometry (ring), which looks like a donut 🍩 simple pattern. The main parameters:

  • radius : Optional. Define the radius size of the ring. The default value is 1 .
  • tube : Optional. Define the tube radius of the ring. The default value is 0.4 .
  • radialSegments : Optional. Define the number of segments along the length of the ring. The default value is 8 .
  • tubularSegments : Optional. Define the number of segments in the width direction of the ring. The default value is 6 .
  • arc : Optional. Define the length of the torus. The value range is 0 to 2 * π . The default value is 2 * π (a complete circle).

Syntax example:

THREE.TorusGeometry(radius, tube, radialSegments, tubularSegments, arc);
😭 Failure: No way to twist the ring was found.

Trial 2: THREE.TorusKnotGeometry

THREE.TorusKnotGeometry can be used to create a three-dimensional torus kink. The torus kink is a special kind of knot that looks like a tube rotating around itself a few times. The main parameters:

  • radius : Optional. Set the radius of the complete circle. The default value is 1 .
  • tube : Optional. Set the radius of the pipe. The default value is 0.4 .
  • radialSegments : Optional. Specify the number of sections of the pipe section. The more sections there are, the smoother the pipe section circle will be. The default value is 8 .
  • tubularSegments : Optional. Specify the number of segments of the pipeline. The more segments, the smoother the pipeline. The default value is 64 .
  • p : Optional. Determines how many times the geometry will rotate around its rotational symmetry axis. The default value is 2 .
  • q : Optional. Determines how many times the geometry will rotate around its inner ring. The default value is 3 .

Syntax example:

THREE.TorusKnotGeometry(radius, tube, radialSegments, tubularSegments , p, q);

😭 Failure: Did not find a way to control the degree of manual distortion.

Trial three: THREE.TubeGeometry

THREE.TubeGeometry stretches a tube along a three-dimensional spline curve. You can specify some fixed points to define the path, and then use THREE.TubeGeometry create this tube. The main parameters:

  • path : This attribute uses a THREE.SplineCurve3 object to specify the path that the pipeline should follow.
  • segments : This attribute specifies the number of segments used to construct this tube. The default value is 64 . The longer the path, the more segments should be specified.
  • radius : This attribute specifies the radius of the tube. The default value is 1 .
  • radiusSegments : This attribute specifies the number of segments of the pipe circumference. The default value is 8 . The more segments there are, the rounder the pipe looks.
  • closed : If this attribute is set to true , the head and tail of the pipe will be connected, and the default value is false .

Code example

// ...
var controls = new function () {
  // 点的位置坐标
  this.deafultpoints = [
    [0, 0.4, -0.4],
    [0.4, 0, 0],
    [0.4, 0.8, 0.4],
    [0, 0.4, 0.4],
    [-0.4, 0, 0],
    [-0.4, 0.8, -0.4],
    [0, 0.4, -0.4]
  ]
  this.segments = 64;
  this.radius = 1;
  this.radiusSegments = 8;
  this.closed = true;
  this.points = [];
  this.newPoints = function () {
    var points = [];
    for (var i = 0; i < controls.deafultpoints.length; i++) {
      var _x = controls.deafultpoints[i][0] * 22;
      var _y = controls.deafultpoints[i][1] * 22;
      var _z = controls.deafultpoints[i][2] * 22;
      points.push(new THREE.Vector3(_x, _y, _z));
    }
    controls.points = points;
    controls.redraw();
  };
  this.redraw = function () {
    redrawGeometryAndUpdateUI(gui, scene, controls, function() {
      return generatePoints(controls.points, controls.segments, controls.radius, controls.radiusSegments,
        controls.closed);
    });
  };
};
controls.newPoints();
function generatePoints(points, segments, radius, radiusSegments, closed) {
  if (spGroup) scene.remove(spGroup);
  spGroup = new THREE.Object3D();
  var material = new THREE.MeshBasicMaterial({ color: 0xff0000, transparent: false });
  points.forEach(function (point) {
    var spGeom = new THREE.SphereGeometry(0.1);
    var spMesh = new THREE.Mesh(spGeom, material);
    spMesh.position.copy(point);
    spGroup.add(spMesh);
  });
  scene.add(spGroup);
  return new THREE.TubeGeometry(new THREE.CatmullRomCurve3(points), segments, radius, radiusSegments, closed);
}
// ...

😊 Barely succeeded: But the ring formed by the pipes is not round enough. To achieve a perfect arc requires precise coordinates, and no coordinate calculation method has been found for the time being.

Trial four: Blender + Three.js

Although it THREE.TubeGeometry , the effect is not good. To achieve a smooth ring, you need to add an accurate twisted ring curve path function to the pipe. Due to the limited mathematical ability 🤕️ , no way to calculate the twisted arc path has been found for the time being. Therefore, it was decided to solve it from the modeling level.

succeeded 😄: But with Blender model and spent a lot of time 💔 .

Modeling tutorial

When visiting station B, I found a treasure video posted by this big guy, which just solved my problem.

🎦 Portal: [Dynamic Design Tutorial] How can AE+blender play? The dynamic logo of Meta Universe on Facebook has been completely resolved, 100% learned

Modeling with Blender

Use Blender for modeling, and export the fbx format that can carry animation. Don't forget to check the baking animation option when exporting.

Load dependencies

<script src="./assets/libs/three.js"></script>
<script src="./assets/libs/loaders/FBXLoader.js"></script>
<script src="./assets/libs/inflate.min.js"></script>
<script src="./assets/libs/OrbitControls.js"></script>
<script src="./assets/libs/stats.js"></script>

Scene initialization

var container, stats, controls, compose, camera, scene, renderer, light, clickableObjects = [], mixer, mixerArr = [], manMixer;
var clock = new THREE.Clock();
init();
animate();
function init() {
  container = document.createElement('div');
  document.body.appendChild(container);
  // 场景
  scene = new THREE.Scene();
  scene.transparent = true;
  scene.fog = new THREE.Fog(0xa0a0a0, 200, 1000);
  // 透视相机:视场、长宽比、近面、远面
  camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
  camera.position.set(0, 4, 16);
  camera.lookAt(new THREE.Vector3(0, 0, 0));
  // 半球光源:创建室外效果更加自然的光源
  light = new THREE.HemisphereLight(0xefefef);
  light.position.set(0, 20, 0);
  scene.add(light);
  // 平行光
  light = new THREE.DirectionalLight(0x2d2d2d);
  light.position.set(0, 20, 10);
  light.castShadow = true;
  scene.add(light);
  // 环境光
  var ambientLight = new THREE.AmbientLight(0xffffff, .5);
  scene.add(ambientLight);
  // 网格
  var grid = new THREE.GridHelper(100, 100, 0xffffff, 0xffffff);
  grid.position.set(0, -10, 0);
  grid.material.opacity = 0.3;
  grid.material.transparent = true;
  scene.add(grid);
  renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.outputEncoding = THREE.sRGBEncoding;
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 背景色设置为透明
  renderer.setClearAlpha(0);
  // 开启阴影
  renderer.shadowMap.enabled = true;
  container.appendChild(renderer.domElement);
  // 添加镜头控制器
  controls = new THREE.OrbitControls(camera, renderer.domElement);
  controls.target.set(0, 0, 0);
  controls.update();
  window.addEventListener('resize', onWindowResize, false);
  // 初始化性能插件
  stats = new Stats();
  container.appendChild(stats.dom);
}
// 屏幕缩放
function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
}
📌 you want to know the detailed process of scene initialization, you can read my other article "Using three.js to achieve cool acidic style 3D pages" .

Load the Logo model

Use FBXLoader load the model, and set the position and size of the model.

var loader = new THREE.FBXLoader();
loader.load('assets/models/meta.fbx', function (mesh) {
  mesh.traverse(function (child) {
    if (child.isMesh) {
      child.castShadow = true;
      child.receiveShadow = true;
    }
  });
  mesh.rotation.y = Math.PI / 2;
  mesh.position.set(0, 1, 0);
  mesh.scale.set(0.05, 0.05, 0.05);
  scene.add(mesh);
});

Add material

In this article, Logo uses the MeshPhysicalMaterial material, which is a PBR physical material, which can better simulate lighting calculations, and the rendering effect is more realistic MeshPhongMaterial Use THREE.TextureLoader to add the map attribute to the material to load the model texture. The picture below is a texture map of metal texture.

var texLoader = new THREE.TextureLoader();
loader.load('assets/models/meta.fbx', function (mesh) {
  mesh.traverse(function (child) {
    if (child.isMesh) {
      if (child.name === '贝塞尔圆') {
        child.material = new THREE.MeshPhysicalMaterial({
          map: texLoader.load("./assets/images/metal.png"),
          metalness: .2,
          roughness: 0.1,
          exposure: 0.4
        });
      }
    }
  });
})

Add animation

  • AnimationMixer object is an animation player for a specific object in the scene. When multiple objects in the scene are animated independently, you can use one AnimationMixer for each object.
  • The clipAction AnimationMixer object generates an instance that can control the execution of the animation.
loader.load('assets/models/meta.fbx', function (mesh) {
  mesh.animations.map(item => {
    mesh.traverse(child => {
      // 因为模型中有多个物体,并且各自有不同动画,示例中只为贝塞尔圆这个网格添加动画
      if (child.name === '贝塞尔圆') {
        let mixer = new THREE.AnimationMixer(child);
        mixerArr.push(mixer);
        let animationClip = item;
        animationClip.duration = 8;
        let clipAction = mixer.clipAction(animationClip).play();
        animationClip = clipAction.getClip();
      }
    })
  })
});

After adding the animation, don't forget to update the animation requestAnimationFrame

function animate() {
  renderer.render(scene, camera);
  // 获得前后两次执行该方法的时间间隔
  let time = clock.getDelta();
  // 更新logo动画
  mixerArr.map(mixer => {
    mixer && mixer.update(time);
  });
  // 更新人物动画
  manMixer && manMixer.update(time);
  stats.update();
  requestAnimationFrame(animate);
}

Show loading progress

FBXLoader returns two callback functions at the same time, which can be used like the following to show the model loading process display and the logic implementation of loading failure.

<div class="loading" id="loading">
  <p class="text">加载进度<span id="progress">0%</span></p>
<div>
var loader = new THREE.FBXLoader();
loader.load('assets/models/meta.fbx', mesh => {
}, res => {
  // 加载进程
  let progress = (res.loaded / res.total * 100).toFixed(0);
  document.getElementById('progress').innerText = progress;
  if (progress === 100) {
    document.getElementById('loading').style.display = 'none';
  }
}, err => {
  // 加载失败
  console.log(err)
});

Achieve effect

Click to change material

Listener page click event, by HREE.Raycaster get the current click an object, in order to show an example, I click on the object to replace a material THREE.MeshStandardMaterial , and gives it a random color color, metalness a metallic finish and roughness roughness.

//声明raycaster和mouse变量
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
function onMouseClick(event) {
  // 通过鼠标点击的位置计算出raycaster所需要的点的位置,以屏幕中心为原点,值的范围为-1到1.
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
  // 通过鼠标点的位置和当前相机的矩阵计算出raycaster
  raycaster.setFromCamera(mouse, camera);
  // 获取raycaster直线和所有模型相交的数组集合
  let intersects = raycaster.intersectObjects(clickableObjects);
  if (intersects.length > 0) {
    console.log(intersects[0].object)
    let selectedObj = intersects[0].object;
    selectedObj.material = new THREE.MeshStandardMaterial({
      color: `#${Math.random().toString(16).slice(-6)}`,
      metalness: Math.random(),
      roughness: Math.random()
    })
  }
}
window.addEventListener('click', onMouseClick, false);

📌 more information about mesh materials, please refer to the link at the end of the article.

Load character model

The character model loading process is the same as the Logo I added a character who is Turtle Qigong , but I didn’t expect it to fit well with the rotation animation of the Logo 😂 .

loader.load('assets/models/man.fbx', function (mesh) {
  mesh.traverse(function (child) {
    if (child.isMesh) {
      child.castShadow = true;
      child.receiveShadow = true;
    }
  });
  mesh.rotation.y = Math.PI / 2;
  mesh.position.set(-14, -8.4, -3);
  mesh.scale.set(0.085, 0.085, 0.085);
  scene.add(mesh);
  manMixer = new THREE.AnimationMixer(mesh);
  let animationClip = mesh.animations[0];
  let clipAction = manMixer.clipAction(animationClip).play();
  animationClip = clipAction.getClip();
}, res => {
  let progress = (res.loaded / res.total * 100).toFixed(0);
  document.getElementById('progress').innerText = progress + '%';
  if (Number(progress) === 100) {
    document.getElementById('loading').style.display = 'none';
  }
}, err => {
  console.log(err)
});

The example character model in this article comes from mixamo.com . This website has hundreds of characters and thousands of actions that can be freely combined. free to download. You can choose your favorite characters and animation actions to practice Three.js .

Summarize

The main knowledge points involved in this article include:

  • THREE.TorusGeometry : the ring.
  • THREE.TorusKnotGeometry : Torus kink.
  • THREE.TubeGeometry : The pipeline.
  • Blender : Modeling.
  • FBXLoader : Load the model and display the loading progress.
  • TextureLoader : Load the material.
  • THREE.AnimationMixer : Loading animation.
  • THREE.Raycaster : Capture the click model.
🔗 complete code: https://github.com/dragonir/3d-meta-logo

Reference

address of this article: 161965569ebdd9 https://www.cnblogs.com/dragonir/p/15574412.html

dragonir
1.8k 声望3.9k 粉丝

Accepted ✔