THREE.JS Realizes Personal Resume Website

insert image description here



I. Introduction

9.png

Recently, I found a good technology introduction website on github, which is mainly written in the native three-piece set of html+css+js . On this basis, I used three.js to add a little 3D elements to make this website look more cool.

When changing, I feel that the native is still not as convenient as the framework, and I will extract a version of the vue component later when I have time .

Online access : personal resume
domestic mirror : InsCode
github source code : personal resume

2. Model preparation

2.1 Resource Finding

1.png

For the model, we can slowly build a model by ourselves, but it is time-consuming. If you don't want to model by yourself, you can directly find some resources on the Internet and import them into blender for related modifications.
Here are some useful 3D resource sites:

  1. TurboSquid - https://www.turbosquid.com/
  2. CGTrader - https://www.cgtrader.com/
  3. Sketchfab - https://sketchfab.com/
  4. 3DExport - https://3dexport.com/
  5. Free3D - https://free3d.com/
  6. Unity Asset Store - https://assetstore.unity.com/
  7. Poly by Google - https://poly.google.com/
  8. Clara.io - https://clara.io/
  9. Blend Swap - https://www.blendswap.com/
  10. 3D Warehouse by SketchUp - https://3dwarehouse.sketchup.com/

These sites provide various types of 3D models and textures, including game assets, buildings, characters, animals, vehicles, etc. Some sites provide free resources, while others require payment to download high-quality resources. Hope these sites can help you find the 3D resources you need.

2.2 Resource handling

2.png

After modifying the desired model, because the web page needs to pursue performance, we need to compress the model (generally it can be compressed to 1/10 of the original). After zipping, use the three.js specific DRACOLoader to decompress the file.

2.3 Draco Compression

While we might feel like using Draco compression is a win-win situation, it really isn't.
It is true that it will make the geometry lighter, but the DracoLoader class and decoder must be loaded when first used. Second, it takes time and resources for our computer to decode a compressed file, which may cause a brief freeze when the page is opened, even if we use workers and WebAssembly.
So we have to decide what solution to use based on reality. If a model has 100kb of geometry then Draco compression is not needed, but if we have megabytes of models to load and don't care about some page freezes at start-up then Draco compression may be required.

3. Basic scene

import * as THREE from 'three'
import {
    
     OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import {
    
     DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'
import {
    
     GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import {
    
     GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js'

const canvas = document.querySelector('.webgl')
const rect = canvas.getBoundingClientRect();
const sizes = {
    
    
    width: rect.width,
    height: rect.height
}

let scene, camera, renderer
let controls, gui
let init = () => {
    
    
    //场景
    scene = new THREE.Scene()

    // 相机
    camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 1000)
    camera.position.set(-2.85, 4.37, 2.49)
    camera.lookAt(scene.position)


    // 渲染器
    renderer = new THREE.WebGLRenderer({
    
     canvas: canvas, antialias: true, alpha: true })
    renderer.setSize(sizes.width, sizes.height)
    // renderer.setClearColor('lightsalmon', 0.5)
    renderer.setPixelRatio(window.devicePixelRatio)
    renderer.useLegacyLights = true
    renderer.shadowMap.enabled = true
    renderer.shadowMap.type = THREE.PCFSoftShadowMap

    // 真实性物理渲染
    renderer.physicallyCorrectLights = true
    renderer.outputEncoding = THREE.sRGBEncoding
    renderer.toneMapping = THREE.ACESFilmicToneMapping



    //控制器
    controls = new OrbitControls(camera, renderer.domElement)
    controls.enableDamping = false
    controls.enableZoom = false
    controls.enablePan = false

    controls.minPolarAngle = Math.PI / 6
    controls.maxPolarAngle = Math.PI / 3

    controls.minAzimuthAngle = -Math.PI / 6
    controls.maxAzimuthAngle = Math.PI / 2
}

//加载模型
const dracoLoader = new DRACOLoader()
dracoLoader.setDecoderPath('./assets/js/three/draco/')
const gltfLoader = new GLTFLoader()
gltfLoader.setDRACOLoader(dracoLoader)

let loadModel = () => {
    
    
    gltfLoader.load('./assets/model/office.glb', (gltf) => {
    
    

        const office = gltf.scene
        office.rotation.y = Math.PI / 2
        office.traverse((child) => {
    
    
            if (child instanceof THREE.Mesh) {
    
    

                child.castShadow = true
                child.receiveShadow = true

                if (child.name === 'mac-screen') {
    
    
                    screen = child
                } else if (child.name === 'Chair') {
    
    
                    chair = child
                } else if (child.name === 'lamp-top') {
    
    
                    // console.log(child.position);

                }
            }
        })
        setScreenVideo()
        setChairRotate()
        scene.add(office)
    })
}
//渲染
let animate = () => {
    
    

    controls.update()
    renderer.render(scene, camera)
    requestAnimationFrame(animate)
}

init()
loadModel()
animate()

The scene basis of three.js includes:

  1. Scene (scene): Contains all 3D objects, light sources and cameras.
  2. Camera (camera): defines the perspective and projection method, and controls what we see from the scene.
  3. Renderer: Renders objects in the scene and camera to the screen.
  4. Mesh: The basic component of a 3D object, made up of triangles. Different materials and textures can be used to add color and texture to the mesh.
  5. Material (material): defines the color, texture, lighting and other properties of the mesh.
  6. Light (light source): Adding a light source to the scene can make the object appear more realistically.
  7. Texture: You can add pictures or other patterns to the grid.
  8. Geometry: Describes the shape and size of the mesh.

4. Lighting

4.1 Introduction

In three.js, lighting is used to simulate the lighting conditions in reality, which can make the objects in the scene more realistic. Lights can provide objects with different lighting effects, such as bright sunlight, soft night lights, flickering candles, etc.
There are several types of lights in three.js:

  1. AmbientLight (ambient light): The light source is evenly distributed throughout the scene, making the whole scene look brighter.
  2. DirectionalLight (parallel light): Simulates the sun's rays from one direction, which is directional and can produce light and dark effects.
  3. PointLight (point light source): simulates a light source from a point, which can produce light and dark effects, and can also produce shadows.
  4. SpotLight (spotlight): simulates a light source from a point, which is directional, can produce light and dark effects, and can also produce cone-shaped shadows.

By setting different properties such as light type, color, intensity, position, etc., various lighting effects can be simulated in three.js, making the objects in the scene look more realistic.

4.2 Shadow Camera

3.png
In this case, we want to simulate lighting effects as much as possible, so shadows should also be taken into account. For shadows, a special camera (called a shadow camera) is used to render the scene from the position of the light source, and save the rendered result to a depth texture. This depth texture records the distance of each pixel in the scene from the light source, that is, which objects in the scene block the pixel.
When rendering the scene, the system calculates whether each pixel is in shadow or not based on the depth texture generated by the shadow camera. Specifically, for each pixel, the system calculates whether it is occluded based on its position in the shadow camera, depth information, and the position and orientation of the light source. If the pixel is occluded, its color value is adjusted to simulate the shadow effect, otherwise its color value is unchanged.

4.3 Light rendering

In three.js, there are three types of lights that can be rendered, namely DirectionalLight, PointLight and SpotLight.
These lights can be added to the scene, and by setting their properties to control their position, color, intensity, range and other parameters, so as to achieve different lighting effects.
These lights can be rendered to different types of cameras, as follows:

  1. Directional Light: Parallel light simulates light from one direction, which has directionality and can produce light and dark effects. Parallel light can only be rendered into an Orthographic Camera (OrthographicCamera)
  2. Point Light: A point light simulates the light from a point, which can produce light and dark effects, as well as shadows. Point light sources can only be rendered into perspective cameras (PerspectiveCamera)
  3. Spotlight (SpotLight): The spotlight simulates the light from a point, which is directional and can produce light and dark effects, as well as cone-shaped shadows. Spotlights can only be rendered to perspective cameras (PerspectiveCamera)

4.png

5. Animation

5.1 Multimedia

Use Three.js' VideoTexture to apply video as a texture to 3D objects for cool effects. First of all, when loading the model at the beginning, find the object that needs to be textured and pass it into the function, and add the video texture in the second step.

// 屏幕播放音频
let screen = null
let setScreenVideo = () => {
    
    

    const video = document.createElement('video')
    video.src = './assets/video/kda.mp4'
    video.muted = true
    video.playsInline = true
    video.autoplay = true
    video.loop = true
    video.play()
    const videoTexture = new THREE.VideoTexture(video)

    // 添加真实性渲染,后面改
    screen.material = new THREE.MeshBasicMaterial({
    
    
        map: videoTexture,
    })
}

5.2 Chair rotation

Here, the transition effect is uniformly completed using gsap, which is a JavaScript animation library for creating high-performance and smooth animation effects.
Article reference: The fragrance of GSAP, let me take you to get it~ 1k is considered a small amount! !

// 添加椅子旋转
let chair = null
let setChairRotate = () => {
    
    
    gsap.to(chair.rotation, {
    
    
        y: Math.PI / 4,
        duration: 10,
        ease: 'power1.inOut',
        repeat: -1,
        yoyo: true,
    })
}

5.3 Light and dark transformation

When we switch the light and dark of the interface, the model should change accordingly. So the model should respond to changes. At the beginning, we added **debug-gui to the lights, so that the lights can be debugged at any time.

5.png
6.png

let debugUI = () => {
    
    
    //gui控制器
    gui = new GUI()
    let folder1 = gui.addFolder('环境光')
    folder1.addColor(ambientLight, 'color')
    folder1.add(ambientLight, 'intensity', 0, 10, 0.01)
    folder1.close()

    let folder2 = gui.addFolder('太阳光')
    folder2.add(sunLight.position, 'x', -5, 5, 0.01)
    folder2.add(sunLight.position, 'y', -5, 5, 0.01)
    folder2.add(sunLight.position, 'z', -5, 5, 0.01)
    folder2.addColor(sunLight, 'color')
    folder2.add(sunLight, 'intensity', 0, 10, 0.01)
    folder2.close()


    let folder3 = gui.addFolder('台灯')
    folder3.add(spotLight.position, 'x', -5, 5, 0.01)
    folder3.add(spotLight.position, 'y', -5, 5, 0.01)
    folder3.add(spotLight.position, 'z', -5, 5, 0.01)
    folder3.addColor(spotLight, 'color')
    folder3.add(spotLight, 'intensity', 0, 10, 0.01)
    folder3.close()

    let folder4 = gui.addFolder('相机')
    folder4.add(camera.position, 'x', -10, 10, 0.01)
    folder4.add(camera.position, 'y', -10, 10, 0.01)
    folder4.add(camera.position, 'z', -10, 10, 0.01)
    // folder4
    folder4.add(params, 'showCmeraInfo')

    // gui.close()


}
let gsapTheme = () => {
    
    
    if (getCurrentTheme() === 'light') {
    
    
        gsap.to(ambientLight, {
    
     intensity: 2.5 })
        gsap.to(ambientLight.color, {
    
    
            ...ambientLightColor,
            duration: durationTime
        })
        gsap.to(sunLight, {
    
     intensity: 2.5, duration: durationTime })
        gsap.to(spotLight, {
    
     intensity: 0, duration: durationTime })
    } else {
    
    
        gsap.to(ambientLight, {
    
     intensity: 3.8, duration: durationTime })
        gsap.to(ambientLight.color, {
    
    
            ...ambientDarkColor,
            duration: durationTime
        })
        gsap.to(sunLight, {
    
     intensity: 0, duration: durationTime })
        gsap.to(spotLight, {
    
     intensity: 3.5, duration: durationTime })

    }
}

6. Realistic Rendering

6.1 UV map

The technology here does not manually paste uv maps, but as a basic theory, you still need to master it.
UV mapping is a technique for mapping texture images onto the surface of a three-dimensional object, which relies on the UV coordinate system to determine the position of the texture image on the surface of the object. Among them, U and V represent the coordinates of the texture image in the horizontal and vertical directions, and the value is usually between 0 and 1 (the Uth pixel in the horizontal direction/picture width, the Vth pixel in the vertical direction/picture height) .
For some special 3D mapping techniques, the W coordinate may be used, but in general, the UV coordinate system is sufficient to describe the texture mapping. Unwrapping UV is to expand the surface of the object into a two-dimensional plane for texture mapping. This process also requires the use of the UV coordinate system to determine the position of each point on the unwrapped plane.

6.2 Lighting

In three.js, physicallyCorrectLights is an attribute that specifies whether the renderer uses a physically correct lighting model. When this property is set to true, the renderer uses a physically based lighting model to more accurately simulate real-world lighting effects.

renderer.physicallyCorrectLights = true

6.3 Renderer

Although the effect looks good so far, the color is still a bit lacking and needs to be worked on. This is because of a problem with the WebGLRenderer property.

6.3.1 utputEncoding

7.png8.png

The outputEncoding property controls the output rendering encoding. By default, the value of outputEncoding is THREE.LinearEncoding, which looks okay but not real. It is recommended to change the value to THREE.sRGBEncoding

6.3.2 Tone mapping

Tone mapping is the process of converting the ultra-high dynamic range HDR to the low dynamic range LDR on the screens we display every day.
Explain HDR and LDR (from Zhihu LDR and HDR):

  • Because the screen brightness (physical) produced by different manufacturers is actually not uniform, then when we talk about LDR, it is a value in the range of 0 to 1, corresponding to different screens is to match the lowest brightness of the current screen (0 ) and maximum brightness (1)
  • The difference in brightness in nature is very large. For example, the light intensity of a candle is about 15, while the intensity of sunlight is about 10w. The difference between this is very large, with a super high dynamic range.
  • The highest brightness of the screens we use every day is accumulated through a series of experiences, so it will not harm the eyes when used; but in nature, for example, when we look directly at the sun, it will actually cause damage to the eyes .

In order to change the tone mapping tone mapping, it is necessary to update the toneMapping property on the WebGLRenderer, which has the following values

THREE.NoToneMapping (默认)
THREE.LinearToneMapping
THREE.ReinhardToneMapping
THREE.CineonToneMapping
THREE.ACESFilmicToneMapping

Although our textures are not HDR, using tone mapping can create a more realistic effect.

6.4 Shadow Distortion

Shadow distortion may occur on smooth and flat surfaces for precision reasons when calculating whether a surface is in shadow.
And now what's happening on the hamburger is that the hamburger casts a shadow on its own surface. So we have to adjust the "offset bias" and "normal offset normalBias" properties of the light shadow shadow to fix this shadow distortion.

  • Bias is usually used on flat surfaces, so it won't work for our hamburger. But if you have shadow distortion on a flat surface, try increasing the bias until the distortion disappears.
  • normalBias is usually used for round surfaces, so we increase the normal bias until the shadow distortion disappears.

Guess you like

Origin blog.csdn.net/qq_53673551/article/details/130222381