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 speedOrbitControls
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 name | describe |
---|---|
AmbientLight Ambient Light | This is a base light whose color is added to the current color of the entire scene and all objects |
PointLight point light source | A point in space that emits light in all directions |
SpotLight Spot light source | This light source has a spotlight effect, similar to a table lamp, a chandelier on the ceiling, or a flashlight |
DirectionLight parallel light | Also known as infinite light. Light rays from such a light source can be seen to be parallel. For example, sunlight |
HemishpereLight hemispherical light | This 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 source | Use this light source to specify a plane from which the light is emitted, rather than a point in space |
LensFlare Lens flare | This 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 thetarget
property, you can point the light source at a specific object or location in the scene. This property requires aTHREE.Object3D
object.intensity
: The intensity of the light source, default value:1
.castShadow
: Shadow, if set totrue
, this light will generate shadows.onlyShadow
: Shadows only, if this property is set totrue
, 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
andshadow.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
orTHREE.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:
Figure 1: Creates
BoxGeometry
with no texture, just a white cube.Figure 2: Add
material map to the cube, at this time has no bump effect .
Figure 3: Add
method map to the cube, at this time produces a bump effect .
Figure 4
,
roughness and
reflectance of the cube material for a more realistic feel.
💡
Textures in Three.js
texture type
map
: Material mapnormalMap
: normal mapbumpMap
: Bump mapenvMap
: Environment mapspecularMap
: Specular maplightMap
: Lightmaps
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 thePBR
materialMeshPhysicalMaterial
instead of the specular materialMeshPhongMaterial
.
special properties
.metalness
property: Indicates how much the material resembles metal.0.0
non-metallic materials, such as wood or stone, and 061e8b42136841 for metals, with1.0
in between (usually). Defaults to0.5
.1.0
0.0
and 061e8b42136844 can be used for a rusted metallic look. If a roughness map.metalnessMap
is also provided, both values are multiplied..roughness
Roughness attribute: Indicates the roughness of the material.0.0
means smooth specular reflection,1.0
means full diffuse reflection. Default0.5
. If a roughness map.roughnessMap
is also provided, the two values are multiplied..metalnessMap
Metallicity Map: The blue channel of the texture is used to change the metallicity of the material..roughnessMap
Roughness Map: The green channel of the texture is used to change the roughness of the material.
📌
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 lightTHREE.HemisphereLight
hemispheric light sourceTHREE.AmbientLight
Ambient Light- Medal
UI
material generation Three.js
in 061e8b42136b34MeshPhysicalMaterial
Physical MaterialTWEEN
Lens tween animationCSS
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
- [1]. Three.js realizes the 3D creative page of the Chinese New Year of the Tiger
- [2]. Three.js implements Facebook Metaverse 3D dynamic logo
- [3]. Three.js implements a 3D panoramic detective game
- [4]. Using Three.js to achieve cool acid style 3D pages
- [5]. Environment texture source: dribbble
- [6]. Font model source: sketchfab
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。