亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

使用Three.js制作一個3D獎牌頁面

 更新時間:2022年01月21日 10:12:49   作者:dragonir  
本文將使用React+Three.js技術(shù)棧,制作一個專屬的3D獎牌頁面,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起動手試一試

背景

本文使用 React + Three.js 技術(shù)棧,實(shí)現(xiàn)粉絲突破1000的3D紀(jì)念頁面,包含的主要知識點(diǎn)包括:Three.js 提供的光源、DirectionLight 平行光、HemisphereLight 半球光源、AmbientLight 環(huán)境光、獎牌素材生成、貼圖知識、MeshPhysicalMaterial 物理材質(zhì)、TWEEN 鏡頭補(bǔ)間動畫、CSS 禮花動畫等。

效果

效果如上圖,頁面由包含我的個人信息的獎牌、1000+ Followers 模型構(gòu)成

在線預(yù)覽:https://dragonir.github.io/3d/#/segmentfault

實(shí)現(xiàn)

引入資源

首先引入開發(fā)功能所需的庫,其中 FBXLoader 用于加在 1000+ 字體模型、OrbitControls 鏡頭軌道控制、TWEEN 用于生成補(bǔ)間動畫、Stats 用于開發(fā)時性能查看。

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";

場景初始化

這部分內(nèi)容主要用于初始化場景和參數(shù),詳細(xì)講解可點(diǎn)擊文章末尾鏈接閱讀我之前的文章,本文不再贅述。

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();
// 給場景設(shè)置好看的背景
scene.background = new THREE.TextureLoader().load(backgroundTexture);
// 攝像機(jī)
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;

為了達(dá)到更好的視覺效果,為OrbitControls設(shè)置了縮放禁用、平移禁用和減小默認(rèn)旋轉(zhuǎn)速度

光照效果

為了模擬真實(shí)的物理場景,本示例中使用了 3種 光源。

// 直射光
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);
// 環(huán)境光
const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0xfffc00);
hemisphereLight.intensity = .3;
scene.add(hemisphereLight);

Three.js 提供的光源

Three.js 庫提供了一些列光源,而且沒種光源都有特定的行為和用途。這些光源包括:

光源名稱描述
AmbientLight 環(huán)境光這是一種基礎(chǔ)光源,它的顏色會添加到整個場景和所有對象的當(dāng)前顏色上
PointLight 點(diǎn)光源空間中的一點(diǎn),朝所有的方向發(fā)射光線
SpotLight 聚光燈光源這種光源有聚光的效果,類似臺燈、天花板上的吊燈,或者手電筒
DirectionLight 平行光也稱為無限光。從這種光源發(fā)出的光線可以看著平行的。例如,太陽光
HemishpereLight 半球光這是一種特殊光源,可以用來創(chuàng)建更加自然的室外光線,模擬放光面和光線微弱的天空
AreaLight 面光源使用這種光源可以指定散發(fā)光線的平面,而不是空間中的一個點(diǎn)
LensFlare 鏡頭眩光這不是一種光源,但是通過 LensFlare 可以為場景中的光源添加眩光效果

THREE.DirectionLight 平行光

THREE.DirectionLight 可以看作是距離很遠(yuǎn)的光,它發(fā)出的所有光線都是相互平行的。平行光的一個范例就是太陽光。被平行光照亮的整個區(qū)域接受到的光強(qiáng)是一樣的。

構(gòu)造函數(shù):

new THREE.DirectionLight(color);

屬性說明:

  • position:光源在場景中的位置。
  • target:目標(biāo)。它的指向很重要。使用 target 屬性,你可以將光源指向場景中的特定對象或位置。此屬性需要一個 THREE.Object3D 對象。
  • intensity:光源照射的強(qiáng)度,默認(rèn)值:1。
  • castShadow:投影,如果設(shè)置為 true,這個光源就會生成陰影。
  • onlyShadow:僅陰影,如果此屬性設(shè)置為 true,則該光源只生成陰影,而不會在場景中添加任何光照。
  • shadow.camera.near:投影近點(diǎn),表示距離光源的哪一個位置開始生成陰影。
  • shadow.camera.far:投影遠(yuǎn)點(diǎn),表示到距離光源的哪一個位置可以生成陰影。
  • shadow.camera.left:投影左邊界。
  • shadow.camera.right:投影右邊界。
  • shadow.camera.top:投影上邊界。
  • shadow.camera.bottom:投影下邊界。
  • shadow.map.width 和 shadow.map.height:陰影映射寬度和陰影映射高度。決定了有多少像素用來生成陰影。當(dāng)陰影具有鋸齒狀邊緣或看起來不光滑時,可以增加這個值。在場景渲染之后無法更改。兩者的默認(rèn)值均為:512

THREE.HemisphereLight 半球光光源

使用半球光光源,可以創(chuàng)建出更加貼近自然的光照效果。

構(gòu)造函數(shù):

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

屬性說明:

  • groundColor:從地面發(fā)出的光線顏色。
  • Color:從天空發(fā)出的光線顏色。
  • intensity:光線照射的強(qiáng)度。

THREE.AmbientLight 環(huán)境光

在創(chuàng)建 THREE.AmbientLight 時,顏色會應(yīng)用到全局。該光源并沒有特別的來源方向,并且不會產(chǎn)生陰影。

構(gòu)造函數(shù):

new THREE.AmbientLight(color);

使用建議:

  • 通常不能將 THREE.AmbientLight 作為場景中唯一的光源,因?yàn)樗鼤鼍爸械乃形矬w渲染為相同的顏色。
  • 使用其他光源,如 THREE.SpotLight 或 THREE.DirectionLight的同時使用它,目的是弱化陰影或給場景添加一些額外顏色。
  • 由于 THREE.AmbientLight 光源不需要指定位置并且會應(yīng)用到全局,所以只需要指定個顏色,然后將它添加到場景中即可。

添加網(wǎng)格和地面

添加網(wǎng)格是為了方便開發(fā),可以調(diào)整模型的合適的相對位置,本例中保留網(wǎng)格的目的是為了頁面更有 3D景深效果。透明材質(zhì)的地面是為了顯示模型的陰影。

// 網(wǎng)格
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);
// 創(chuàng)建地面,透明材質(zhì)顯示陰影
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);

創(chuàng)建獎牌

由于時間關(guān)系,本示例獎牌模型直接使用 Three.js 自帶的基礎(chǔ)立方體模型 THREE.BoxGeometry 來實(shí)現(xiàn),你也可以使用其他立方體如球體、圓珠等,甚至可以使用 Blender 等專業(yè)建模軟件創(chuàng)建自己喜歡的獎牌形狀。(ps:個人覺得立方體也挺好看的 ??)

獎牌UI素材生成

獎牌上下面和側(cè)面貼圖制作:

為了生成的獎牌有黃金質(zhì)感,本例中使用下圖該材質(zhì)貼圖,來生成亮瞎眼的24K純金效果 。

獎牌正面和背面貼圖制作:

獎牌的正面和背面使用的貼圖是 SegmentFault 個人中心頁的截圖,為了更具有金屬效果,我用上面金屬材質(zhì)貼圖給它添加了一個帶有圓角的邊框。

Photoshop 生成圓角金屬邊框具體方法:截圖上面添加金屬圖層 -> 使用框選工具框選需要刪除的內(nèi)容 -> 點(diǎn)擊選擇 -> 點(diǎn)擊修改 -> 點(diǎn)擊平滑 -> 輸入合適的圓角大小 -> 刪除選區(qū) -> 合并圖層 -> 完成并導(dǎo)出圖片。

最終的正反面的材質(zhì)貼圖如下圖所示,為了顯示更清晰,我在 Photoshop 中同時修改了圖片的對比度 和 飽和度,并加了 SegmentFault 的 Logo 在上面。

獎牌正面和背面的法相貼圖制作:

為了生成凹凸質(zhì)感,就需要為模型添加法相貼圖。使用上面已經(jīng)生成的正面和背面的材質(zhì)貼圖,就可以使用在線工具自動生成法相貼圖。生成時可以根據(jù)需要,通過調(diào)整 Strength、LevelBlur 等參數(shù)進(jìn)行樣式微調(diào),并且能夠?qū)崟r預(yù)覽。調(diào)整好后點(diǎn)擊 Download 下載即可。

貼圖在線制作工具傳送門:NormalMap-Online

通過多次調(diào)節(jié)優(yōu)化,最終使用的法相貼圖如下圖所示。

使用上面生成的素材,現(xiàn)在進(jìn)行獎牌模型的構(gòu)建。正面和背面使用個人信息材質(zhì),其他面使用金屬材質(zhì)。然后遍歷對所有面調(diào)整金屬度和粗糙度樣式。

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)});
// 創(chuàng)建紋理數(shù)組
const boxMaps = [metalMap, metalMap, metalMap, metalMap, segmentMap, segmentMap];
// ?? 立方體長寬高比例需要和貼圖的大小比例一致,厚度可以隨便定
box = new THREE.Mesh(new THREE.BoxGeometry(297, 456, 12), boxMaps);
box.material.map(item => {
  // 材質(zhì)樣式調(diào)整
  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);

上面 4 張效果圖依次對應(yīng)的是:

  • 圖1:創(chuàng)建沒有貼圖的 BoxGeometry,只是一個白色的立方體。
  • 圖2:立方體添加 材質(zhì)貼圖,此時沒有凹凸效果。
  • 圖3:立方體添加 法相貼圖,此時產(chǎn)生凹凸效果。
  • 圖4:調(diào)節(jié)立方體材質(zhì)的 金屬度、粗糙程度 和 反射率,更具有真實(shí)感。

Three.js 中的貼圖

貼圖類型

  • map:材質(zhì)貼圖
  • normalMap:法線貼圖
  • bumpMap:凹凸貼圖
  • envMap:環(huán)境貼圖
  • specularMap:高光貼圖
  • lightMap:光照貼圖

貼圖原理

通過紋理貼圖加載器 TextureLoader() 去新創(chuàng)建一個貼圖對象出來,然后再去調(diào)用里面的 load() 方法去加載一張圖片,這樣就會返回一個紋理對象,紋理對象可以作為模型材質(zhì)顏色貼圖 map 屬性的值,材質(zhì)的顏色貼圖屬性 map 設(shè)置后,模型會從紋理貼圖上采集像素值。

MeshPhysicalMaterial 物理材質(zhì)

MeshPhysicalMaterial 類是 PBR 物理材質(zhì),可以更好的模擬光照計算,相比較高光網(wǎng)格材質(zhì)MeshPhongMaterial 渲染效果更逼真。

如果你想展示一個產(chǎn)品,為了更逼真的渲染效果最好選擇該材質(zhì),如果游戲?yàn)榱烁玫娘@示效果可以選擇 PBR 材質(zhì) MeshPhysicalMaterial,而不是高光材質(zhì) MeshPhongMaterial。

特殊屬性

  • .metalness 金屬度屬性:表示材質(zhì)像金屬的程度。非金屬材料,如木材或石材,使用 0.0,金屬使用 1.0,中間沒有(通常). 默認(rèn) 0.5. 0.0 到 1.0 之間的值可用于生銹的金屬外觀。如果還提供了粗糙度貼圖 .metalnessMap,則兩個值都相乘。
  • .roughness 粗糙度屬性:表示材質(zhì)的粗糙程度. 0.0 表示平滑的鏡面反射,1.0 表示完全漫反射. 默認(rèn) 0.5. 如果還提供粗糙度貼圖 .roughnessMap,則兩個值相乘.
  • .metalnessMap 金屬度貼圖:紋理的藍(lán)色通道用于改變材料的金屬度.
  • .roughnessMap 粗糙度貼圖:紋理的綠色通道用于改變材料的粗糙度。

注意使用物理材質(zhì)的時候,一般需要設(shè)置環(huán)境貼圖 .envMap。

加載1000+文字模型

1000+ 字樣的模型使用 THREE.LoadingManager 和 FBXLoader 加載。詳細(xì)使用方法也不再本文中贅述,可參考文章末尾鏈接查看我的其他文章,里面有詳細(xì)描述。

const manager = new THREE.LoadingManager();
manager.onProgress = async(url, loaded, total) => {
  if (Math.floor(loaded / total * 100) === 100) {
    // 設(shè)置加載進(jìn)度
    _this.setState({ loadingProcess: Math.floor(loaded / total * 100) });
    // 加載鏡頭移動補(bǔ)間動畫
    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;
      // 樣式調(diào)整
      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);
});

補(bǔ)間動畫

相機(jī)移動實(shí)現(xiàn)漫游等動畫,頁面打開時,模型加載完畢從大變小的動畫就是通過 TWEEN 實(shí)現(xiàn)的。

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

動畫更新

最后不要忘了要在 requestAnimationFrame 中更新場景、軌道控制器、TWEEN、以及模型的自轉(zhuǎn)等。

// 監(jiān)聽頁面縮放,更新相機(jī)和渲染
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();
  // 獎牌模型自轉(zhuǎn)
  box && (box.rotation.y += .04);
}

禮花動畫

最后,通過 box-shadow 和簡單的 CSS 動畫,給頁面添加禮花綻放效果,營造歡慶氛圍!

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

樣式動畫:

[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;
  }
}

實(shí)現(xiàn)效果:

完整代碼

總結(jié)

本文中主要涉及到的知識點(diǎn)包括:

  • Three.js 提供的光源
  • THREE.DirectionLight 平行光
  • THREE.HemisphereLight 半球光光源
  • THREE.AmbientLight 環(huán)境光
  • 獎牌 UI 素材生成
  • Three.js 中的貼圖
  • MeshPhysicalMaterial 物理材質(zhì)
  • TWEEN 鏡頭補(bǔ)間動畫
  • CSS 禮花動畫

以上就是使用Three.js制作一個3D獎牌頁面的詳細(xì)內(nèi)容,更多關(guān)于Three.js 3D獎牌的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論