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 revolution5G/6G
, Internet revolutionweb3.0
, artificial intelligence revolution, andVR
,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 . Justthe 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 is1
.tube
: Optional. Define the tube radius of the ring. The default value is0.4
.radialSegments
: Optional. Define the number of segments along the length of the ring. The default value is8
.tubularSegments
: Optional. Define the number of segments in the width direction of the ring. The default value is6
.arc
: Optional. Define the length of the torus. The value range is0
to2 * π
. The default value is2 * π
(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 is1
.tube
: Optional. Set the radius of the pipe. The default value is0.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 is8
.tubularSegments
: Optional. Specify the number of segments of the pipeline. The more segments, the smoother the pipeline. The default value is64
.p
: Optional. Determines how many times the geometry will rotate around its rotational symmetry axis. The default value is2
.q
: Optional. Determines how many times the geometry will rotate around its inner ring. The default value is3
.
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 aTHREE.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 is64
. The longer the path, the more segments should be specified.radius
: This attribute specifies the radius of the tube. The default value is1
.radiusSegments
: This attribute specifies the number of segments of the pipe circumference. The default value is8
. The more segments there are, the rounder the pipe looks.closed
: If this attribute is set totrue
, the head and tail of the pipe will be connected, and the default value isfalse
.
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 oneAnimationMixer
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
- [1]. Use three.js to realize a cool acidic style 3D page
- [2]. ThreeJs know the material
- [3]. impression of Animation of Three
- [4]. What is the meta universe?
address of this article: 161965569ebdd9 https://www.cnblogs.com/dragonir/p/15574412.html
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。