34
头图

background

Break the defense 😭 ! I suddenly found that the number of fans on the SegmentFault 1000 . It is the first fan of my three blog platforms Nuggets, Blog Park, and SegmentFault 1000 , so I designed and developed this page to commemorate it. Thank you very much for your attention to 🙏 . In the future, I will focus more on the sorting and sharing of front-end knowledge and write more high-quality articles. (I hope other platforms will break the thousand 😂 soon as possible)

As used herein, React + Three.js technology stack, to achieve fan breakthrough 1000 of 3D memorial pages, main points included comprising: Three.js light source provided, DirectionLight parallel light, HemisphereLight hemispherical light, AmbientLight ambient light, medals creative generation, mapping knowledge, MeshPhysicalMaterial physical material, TWEEN lens tween animation, CSS fireworks animation, etc.

Effect

The effect picture is shown in the article 👆 Banner. The page consists of the medals 🥇 and 1000+ Followers 🤣 real time through the following link.

👀 online preview: https://dragonir.github.io/3d/#/segmentfault

accomplish

Introduce resources

First, the libraries required for development functions are introduced. Among them, FBXLoader used to add to the 1000+ font model, OrbitControls lens track control, TWEEN used to generate tween animation, and Stats used for development-time performance viewing.

import * as THREE from "three";
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";
import Stats from "three/examples/jsm/libs/stats.module";

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;
renderer.shadowMap.needsUpdate = true;
container.appendChild(renderer.domElement);
// 场景
scene = new THREE.Scene();
// 给场景设置好看的背景
scene.background = new THREE.TextureLoader().load(backgroundTexture);
// 摄像机
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0, 0);
camera.lookAt(new THREE.Vector3(0, 0, 0));
// 控制器
controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 0);
controls.enableDamping = true;
controls.enableZoom = false;
controls.enablePan = false;
controls.rotateSpeed = .2;
📌 In order to achieve better visual effect, set zoom disable, pan disable and reduce default rotation speed OrbitControls

lighting effect

In order to simulate a real physical scene, 3 light sources are used in this example.

// 直射光
const cubeGeometry = new THREE.BoxGeometry(0.001, 0.001, 0.001);
const cubeMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff });
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.position.set(0, 0, 0);
light = new THREE.DirectionalLight(0xffffff, 1);
light.intensity = 1;
light.position.set(18, 20, 60);
light.castShadow = true;
light.target = cube;
light.shadow.mapSize.width = 512 * 12;
light.shadow.mapSize.height = 512 * 12;
light.shadow.camera.top = 80;
light.shadow.camera.bottom = -80;
light.shadow.camera.left = -80;
light.shadow.camera.right = 80;
scene.add(light);
// 半球光
const ambientLight = new THREE.AmbientLight(0xffffff);
ambientLight.intensity = .8;
scene.add(ambientLight);
// 环境光
const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0xfffc00);
hemisphereLight.intensity = .3;
scene.add(hemisphereLight);

💡 Light source provided by Three.js

Three.js library provides a range of lights, each of which has a specific behavior and purpose. These light sources include:

light source namedescribe
AmbientLight Ambient LightThis is a base light whose color is added to the current color of the entire scene and all objects
PointLight point light sourceA point in space that emits light in all directions
SpotLight Spot light sourceThis light source has a spotlight effect, similar to a table lamp, a chandelier on the ceiling, or a flashlight
DirectionLight parallel lightAlso known as infinite light. Light rays from such a light source can be seen to be parallel. For example, sunlight
HemishpereLight hemispherical lightThis is a special light source that can be used to create more natural outdoor lighting, simulating shiny surfaces and dimly lit skies
AreaLight area light sourceUse this light source to specify a plane from which the light is emitted, rather than a point in space
LensFlare Lens flareThis is not a light source, but with LensFlare it is possible to add a glare effect to the light sources in the scene

💡 THREE.DirectionLight parallel light

THREE.DirectionLight can be seen as light far away, all the rays it emits are parallel to each other. An example of a directional light is Sunlight . The entire area illuminated by the directional light receives the same light intensity.

Constructor :

new THREE.DirectionLight(color);

Property Description :

  • position : The position of the light source in the scene.
  • target : Target. Its pointing is important. Using the target property, you can point the light source at a specific object or location in the scene. This property requires a THREE.Object3D object.
  • intensity : The intensity of the light source, default value: 1 .
  • castShadow : Shadow, if set to true , this light will generate shadows.
  • onlyShadow : Shadows only, if this property is set to true , this light will only generate shadows without adding any lighting to the scene.
  • shadow.camera.near : The near point of the projection, which indicates where from the light source the shadow begins.
  • shadow.camera.far : Projection far point, indicating which position from the light source to generate shadows.
  • shadow.camera.left : Projected left border.
  • shadow.camera.right : Project the right border.
  • shadow.camera.top : Projected upper bounds.
  • shadow.camera.bottom : Projection lower boundary.
  • shadow.map.width and shadow.map.height : Shadow map width and shadow map height. Determines how many pixels are used to generate shadows. Increase this value when shadows have jagged edges or don't look smooth. Cannot be changed after the scene is rendered. The default value for both is: 512 .

💡 THREE.HemisphereLight Hemisphere light source

Using a hemispherical light source, you can create more natural lighting effects .

constructor :

new THREE.HeimsphereLight(groundColor, color, intensity);

Property Description :

  • groundColor : The color of light emitted from the ground.
  • Color : The color of light emitted from the sky.
  • intensity : The intensity of the light hitting.

💡 THREE.AmbientLight Ambient Light

When creating THREE.AmbientLight , the color is applied globally. The light source has no particular source direction, and does not cast shadows .

constructor :

new THREE.AmbientLight(color);

use suggested :

  • THREE.AmbientLight cannot be used as the only light source in the scene, as it will render all objects in the scene to the same color.
  • Use it along with other light sources like THREE.SpotLight or THREE.DirectionLight shadows or add some extra color to the scene.
  • Since the THREE.AmbientLight light source does not need to specify a position and will be applied globally, you only need to specify a color and add it to the scene.

Add grid and ground

The grid is added for the convenience of development, and the appropriate relative position of the model can be adjusted. In this example, the purpose of retaining the grid is to make the page more 3D depth of field effect. The ground of the transparent material is to show the shadow of the model.

// 网格
const grid = new THREE.GridHelper(200, 200, 0xffffff, 0xffffff);
grid.position.set(0, -30, -50);
grid.material.transparent = true;
grid.material.opacity = 0.1;
scene.add(grid);
// 创建地面,透明材质显示阴影
var planeGeometry = new THREE.PlaneGeometry(200, 200);
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, -30, -50);
plane.receiveShadow = true;
scene.add(plane);

Create a medal

Three.js , this example medal model is directly implemented using the basic cube model THREE.BoxGeometry that comes with 061e8b421363a7. You can also use other cubes such as spheres, balls, etc., or even use Blender create your favorite medal shapes. ( ps : 061e8b421363ac : I personally think the cube looks pretty good 😂 )

💡 Medal UI material generation

🥇 Medal top, bottom and side textures make :

In order to generate the medal with a golden texture, in this example, the texture map 👇 bright 24K pure gold effect 🤑 .

🥇 Medal front and back textures make :

The front and back of the medal textures using SegmentFault screenshots personal center of the page, in order to have a more metallic effect, I used 👆 above metal textures to it adds a border with rounded corners .

Photoshop metal frame fillets specific methods : adding a metal layer above screenshot -> content usage marquee tool Kuangxuan be deleted -> click selection -> clicking Edit -> Click smoothing -> enter the appropriate size of the fillet -> delete the selection -> merge FIG Layer -> done and the picture is exported.

The final textures of the front and back as 👇 shown below, in order to show more clearly, I Photoshop also modify the image in contrast and saturation, and added SegmentFault of Logo above.

🥇 The law map of the front and back of the medal makes :

In order to generate bump texture , you need to add law map to the model. Using 👆 , you can use online tools to automatically generate normal maps. When generating, you can Strength , Level , Blur etc., and preview it in real time. After adjustment, click Download download.

🚪 NormalMap-Online Portal:

After multiple adjustments and optimizations, the final 👇 phase map used is shown in the figure below 061e8b42136560.

Using the assets generated above, now proceed to the construction of the medal model. personal information material front and back, and use metal material other sides. Then iterate through and adjust the metallicity and roughness styles for all faces.

let segmentMap = new THREE.MeshPhysicalMaterial({map: new THREE.TextureLoader().load(segmentTexture), normalMap: new THREE.TextureLoader().load(normalMapTexture) });
let metalMap = new THREE.MeshPhysicalMaterial({map: new THREE.TextureLoader().load(metalTexture)});
// 创建纹理数组
const boxMaps = [metalMap, metalMap, metalMap, metalMap, segmentMap, segmentMap];
// 💡 立方体长宽高比例需要和贴图的大小比例一致,厚度可以随便定
box = new THREE.Mesh(new THREE.BoxGeometry(297, 456, 12), boxMaps);
box.material.map(item => {
  // 材质样式调整
  item.metalness = .5;
  item.roughness = .4;
  item.refractionRatio = 1;
  return item;
});
box.scale.set(0.085, 0.085, 0.085);
box.position.set(-22, 2, 0);
box.castShadow = true;
meshes.push(box);
scene.add(box);

👆 above 4 correspond to:

💡 Textures in Three.js

texture type
Texture principle

Use the texture map loader TextureLoader() to create a new texture object, and then call the load() method inside to load a picture, which will return a texture object. The texture object can be used as the value of the map After the color map property of map set, the model will collect pixel values from the texture map.

💡 MeshPhysicalMaterial

MeshPhysicalMaterial class is a PBR physical material, which can better simulate lighting calculations, and is more realistic MeshPhongMaterial

If you want to show a product, it is best to choose this material for a more realistic rendering effect. If the game has a better display effect, you can choose the PBR material MeshPhysicalMaterial instead of the specular material MeshPhongMaterial .
special properties
📌 Note that when using physical materials, it is generally necessary to set the environment map .envMap .

Load 1000+ text models

1000+ words FBXLoader loaded THREE.LoadingManager and 061e8b4213690c. The detailed usage method will not be repeated in this article. You can refer to the link at the end of the article to view my other articles, which have detailed descriptions. 😁

const manager = new THREE.LoadingManager();
manager.onProgress = async(url, loaded, total) => {
  if (Math.floor(loaded / total * 100) === 100) {
    // 设置加载进度
    _this.setState({ loadingProcess: Math.floor(loaded / total * 100) });
    // 加载镜头移动补间动画
    Animations.animateCamera(camera, controls, { x: 0, y: 4, z: 60 }, { x: 0, y: 0, z: 0 }, 3600, () => {});
  } else {
    _this.setState({ loadingProcess: Math.floor(loaded / total * 100) });
  }
};
const fbxLoader = new FBXLoader(manager);
fbxLoader.load(textModel, mesh => {
  mesh.traverse(child => {
    if (child.isMesh) {
      // 生成阴影
      child.castShadow = true;
      // 样式调整
      child.material.metalness = 1;
      child.material.roughness = .2;
      meshes.push(mesh);
    }
  });
  mesh.position.set(16, -4, 0);
  mesh.rotation.x = Math.PI / 2
  mesh.scale.set(.08, .08, .08);
  scene.add(mesh);
});

tween animation

The camera moves to achieve animations such as roaming. When the page is opened, the animation from large to small after the model is loaded is realized through TWEEN .

animateCamera: (camera, controls, newP, newT, time = 2000, callBack) => {
  var tween = new TWEEN.Tween({
    x1: camera.position.x, // 相机x
    y1: camera.position.y, // 相机y
    z1: camera.position.z, // 相机z
    x2: controls.target.x, // 控制点的中心点x
    y2: controls.target.y, // 控制点的中心点y
    z2: controls.target.z, // 控制点的中心点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();
}

animation update

Finally, do not forget to be in requestAnimationFrame update scenario, the track controller, TWEEN , and the rotation model 🌍 and so on.

// 监听页面缩放,更新相机和渲染
function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
  stats && stats.update();
  controls && controls.update();
  TWEEN && TWEEN.update();
  // 奖牌模型自转
  box && (box.rotation.y += .04);
}

fireworks animation

Finally, 🎉 bloom effect to the page box-shadow and a simple CSS 🎅 festive atmosphere!

<div className="firework_1"></div>
<div className="firework_2"></div>
<!-- ... -->
<div className="firework_10"></div>

Style animation:

[class^=firework_] {
  position: absolute;
  width: 0.1rem;
  height: 0.1rem;
  border-radius: 50%;
  transform: scale(8)
}
.firework_1 {
  animation: firework_lg 2s both infinite;
  animation-delay: 0.3s;
  top: 5%;
  left: 5%;
}
@keyframes firework_lg {
  0%, 100% {
    opacity: 0;
  }
  10%, 70% {
    opacity: 1;
  }
  100% {
    box-shadow: -0.9rem 0rem 0 #fff, 0.9rem 0rem 0 #fff, 0rem -0.9rem 0 #fff, 0rem 0.9rem 0 #fff, 0.63rem -0.63rem 0 #fff, 0.63rem 0.63rem 0 #fff, -0.63rem -0.63rem 0 #fff, -0.63rem 0.63rem 0 #fff;
  }
}

Realize the effect:

🔗 full code https://github.com/dragonir/3d/tree/master/src/containers/SegmentFault

Summarize

The main knowledge points involved in this article include:

  • Light source provided by Three.js
  • THREE.DirectionLight parallel light
  • THREE.HemisphereLight hemispheric light source
  • THREE.AmbientLight Ambient Light
  • Medal UI material generation
  • Three.js in 061e8b42136b34
  • MeshPhysicalMaterial Physical Material
  • TWEEN Lens tween animation
  • CSS Fireworks animation

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

appendix


dragonir
1.8k 声望3.9k 粉丝

Accepted ✔