欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Three.js實現(xiàn)雪糕地球的使用示例詳解

 更新時間:2022年07月05日 15:09:57   作者:戰(zhàn)場小包  
這篇文章主要為大家介紹了Three.js實現(xiàn)雪糕地球的使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

前言

最近的天氣有幾分酷熱,去實驗室的道路也有幾分漫長,走著走著,小包感覺靈魂已經(jīng)被熱出竅了?;氐綄嶒炇?,把空調(diào)打開,雪糕吃上,靜坐了幾分鐘,才重新感覺到靈魂的滋味,葛優(yōu)躺在實驗室的小床上,思維開始天馬行空,世上有一萬種方式能讓小包涼快,但地球母親吶,她卻日漸炎熱,誰能來給她降降溫?

躺著躺著,進入了夢鄉(xiāng),小包夢到未來有一天,人類超級發(fā)達,可以穿梭時空,但發(fā)展的代價也是巨大的,地球母親不堪重負,熱度超標,我們卻束手無策,科學(xué)家最后想出一個古老的辦法,將地球的一周用冰包裹起來,進行物理降溫。這很讓人驚悚,小包醒來后,枯坐了一會,決定做一個雪糕地球,不只是一種整活調(diào)侃,也是一種反思與警示,保護地球,人人有責。

  • style
* {
    -webkit-user-select: none;
       -moz-user-select: none;
        -ms-user-select: none;
            user-select: none;
  }
  body {
    height: 100vh;
    background-color: hotpink;
    margin: 0;
    padding: 0;
    overflow: hidden;
  }
  .loader {
    display: flex;
    color: white;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 5em;
    width: 100%;
    height: 100%;
    font-family: "Baloo Bhaijaan", cursive;
  }
  .loader span {
    text-shadow: 0 1px #bbb, 0 2px #bbb, 0 3px #bbb, 0 4px #bbb, 0 5px #bbb,
      0 6px transparent, 0 7px transparent, 0 8px transparent,
      0 9px transparent, 0 10px 10px rgba(0, 0, 0, 0.4);
    text-shadow: 0 1px #bbb, 0 2px #bbb, 0 3px #bbb, 0 4px #bbb,
        0 5px #bbb, 0 6px #bbb, 0 7px #bbb, 0 8px #bbb, 0 9px #bbb,
        0 50px 25px rgba(0, 0, 0, 0.2);
      transform: translateY(-20px);
  }
  •  script
/*
 * 基礎(chǔ)配置
 */
let isLoaded = false; // 紋理資源是否加載完畢
const loadingScreen = {
  scene: new THREE.Scene(),
  camera: new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  ),
  // 移除加載標志的函數(shù)
  removeText() {
    const loadingText = document.querySelector("#canvas-loader");
    if (loadingText.parentNode) {
      loadingText.parentNode.removeChild(loadingText);
    }
  },
};
// 初始化加載器
let loadingManager = new THREE.LoadingManager();
// 監(jiān)聽加載器 onLoad 事件
loadingManager.onLoad = () => {
  loadingScreen.removeText();
  isLoaded = true;
};
// 創(chuàng)建場景
const scene = new THREE.Scene();
// 創(chuàng)建渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true });
// 渲染器基本設(shè)置
renderer.setClearColor("hotpink");
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// canvas 外部容器
const canvasWrapper = document.querySelector("#canvas-wrapper");
// 創(chuàng)建透視相機
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
// 設(shè)置相機位置
camera.position.set(0, 0, 220);
// 創(chuàng)建平行光源
const light = new THREE.DirectionalLight();
light.position.set(0, 0, 1);
scene.add(light);
// 創(chuàng)建點光源
const point = new THREE.PointLight(0xeeeeee);
point.position.set(400, 200, 300); //點光源位置
scene.add(point); //點光源添加到場景中
// 創(chuàng)建球體
const cRadius = 100;
const geometry = new THREE.SphereBufferGeometry(
  cRadius,
  cRadius * 6.4,
  cRadius * 6.4
);
// 紋理圖
const textureLoader = new THREE.TextureLoader(loadingManager);
const textureSurface = textureLoader.load(
  "https://s3-us-west-2.amazonaws.com/s.cdpn.io/249663/world-surface.jpg"
);
const textureElevation = textureLoader.load(
  "https://s3-us-west-2.amazonaws.com/s.cdpn.io/249663/world-elevation.jpg"
);
const textureSpecular = textureLoader.load(
  "https://s3-us-west-2.amazonaws.com/s.cdpn.io/249663/world-specular.jpg"
);
// 材質(zhì)信息
const materialOpt = {
  map: textureSurface,
  normalMap: textureElevation,
  specularMap: textureSpecular,
  shininess: 80,
};
const material = new THREE.MeshPhongMaterial(materialOpt);
// 創(chuàng)建網(wǎng)格體
const sphere = new THREE.Mesh(geometry, material);
// 設(shè)置環(huán)境貼圖的顏色深淺
sphere.material.normalScale.set(0.5, 0.5);
// 將模型添加到場景中
scene.add(sphere);
// 將 canvas 元素添加到頁面中
canvasWrapper.appendChild(renderer.domElement);
/*
 * 事件監(jiān)聽實現(xiàn)動效
 */
let mouseX = 0;
let mouseY = 0;
const moveAnimate = {
  coordinates(clientX, clientY) {
    const limit = 270;
    const limitNeg = limit * -1;
    mouseX = clientX - window.innerWidth / 2;
    mouseY = clientY - window.innerHeight / 2;
    mouseX = mouseX >= limit ? limit : mouseX;
    mouseX = mouseX <= limitNeg ? limitNeg : mouseX;
    mouseY = mouseY >= limit ? limit : mouseY;
    mouseY = mouseY <= limitNeg ? limitNeg : mouseY;
  },
  onMouseMove(e) {
    moveAnimate.coordinates(e.clientX, e.clientY);
  },
  onTouchMove(e) {
    const touchX = e.changedTouches[0].clientX;
    const touchY = e.changedTouches[0].clientY;
    moveAnimate.coordinates(touchX, touchY);
  },
};
document.addEventListener("mousemove", moveAnimate.onMouseMove);
document.addEventListener("touchmove", moveAnimate.onTouchMove);
const onWindowResize = () => {
  const w = window.innerWidth;
  const h = window.innerHeight;
  camera.aspect = w / h;
  camera.updateProjectionMatrix();
  renderer.setSize(w, h);
};
window.addEventListener("resize", onWindowResize);
const createAnimRotation = () => {
  const speed = 0.005;
  sphere.rotation.z += speed / 2;
  sphere.rotation.y += speed;
};
// 渲染函數(shù)
const render = () => {
  if (!isLoaded) {
    renderer.render(loadingScreen.scene, loadingScreen.camera);
    requestAnimationFrame(render);
    return;
  }
  camera.position.x += (mouseX * -1 - camera.position.x) * 0.05;
  camera.position.y += (mouseY - camera.position.y) * 0.05;
  camera.lookAt(scene.position);
  createAnimRotation();
  renderer.render(scene, camera);
  requestAnimationFrame(render);
};
render();

ThreeJS 基礎(chǔ)——實現(xiàn)轉(zhuǎn)動的球體

Three.js 是一款運行在瀏覽器中的 3D 引擎,你可以用它創(chuàng)建各種三維場景,包括了攝影機、光影、材質(zhì)等各種對象,大家或多或少應(yīng)該都見識過 Three 的傳說。這是小包第一次使用 Three,因此小包會圍繞雪糕地球實現(xiàn)的各種細節(jié)講起。

下面首先來看一下 Three 框架的基本組成要素(圖源: Three.js 教程)

Three 中最重要的三個對象即場景、相機和渲染器。場景即放置模型、光照的場地;相機設(shè)置以何種方式何種角度來觀看場景,渲染器將效果渲染到網(wǎng)頁中。這三個概念都不難理解,下面我們用代碼實現(xiàn)這三個對象。

// 場景
const scene = new THREE.Scene();
// 透視相機
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
// 渲染器
const renderer = new THREE.WebGLRenderer();
// 設(shè)置渲染區(qū)域尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
// body元素中插入canvas對象
document.body.appendChild(renderer.domElement);
// 設(shè)置背景顏色
renderer.setClearColor("hotpink");
// 執(zhí)行渲染操作   指定場景、相機作為參數(shù)
renderer.render(scene, camera);

Three 中有多種相機,本文章主要使用透視相機(PerspectiveCamera),其原理與人眼所看的景象類似,共有四個參數(shù):

PerspectiveCamera( fov : Number, aspect : Number, near : Number, far : Number )

fov: 表示能看到的角度范圍,值為角度,類似于人的視角。

aspect: 表示渲染窗口的長寬比,如果網(wǎng)頁中只有一個 canvas,其值通常設(shè)置為網(wǎng)頁視口的寬高比

near/far: near/far 分別代表攝像機的近剪切面和遠剪切面

文字有些難以理解,可以參考一下下圖:

打開瀏覽器,看一下會渲染出什么?目前只能看到全粉色的網(wǎng)頁,這是因為目前的場景中并沒有添加 3D 模型對象。

接下來我們來添加一個球體模型,作為地球的基底。

const cRadius = 100;
const geometry = new THREE.SphereBufferGeometry(
  cRadius,
  cRadius * 6.4,
  cRadius * 6.4
);

SphereBufferGeometryThree 中實現(xiàn)球體的 API,參數(shù)非常多,這里只介紹前三個參數(shù)

radius: 球體半徑

widthSegments: 沿經(jīng)線方向分段數(shù)

heightSegments: 沿緯線方向分段數(shù)

為球體添加材質(zhì) Material,目前我們只添加一個顏色屬性。

// 材質(zhì)對象Material
const material = new THREE.MeshLambertMaterial({
  color: 0x0000ff,
});

渲染網(wǎng)格體 Mesh,并將其添加到場景 Scene 中。

// 網(wǎng)格體 Mesh,兩個參數(shù)分別為幾何體和材質(zhì)
const sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);

重新打開網(wǎng)站,并沒有看到球體,還是一片粉茫茫的寂寥,天理何在?

Three 相機的初始位置默認為 (0,0,0),相機焦點默認為 Z 軸負半軸方向,球體的半徑是 100,也就是說目前相機位于球體內(nèi)部,因此我們需要調(diào)整相機位置。

// 設(shè)置相機的位置
camera.position.set(0, 0, 220);
// 設(shè)置相機焦點的方向
camera.lookAt(scene.position);

當當當當,網(wǎng)頁中就可以成功看到一個黑色球體了,額有點奇怪,我們明明設(shè)置的是 0x0000ff 顏色,怎么會顯示一個黑色模型?

小包苦思冥想: 萬物本沒有顏色,顏色是光的反射。在整個場景中,目前是沒有光源的,因此下面分別添加平行光(DirectionalLight)和點光源(PointLight)

平行光是沿著特定方向發(fā)射的光,其表現(xiàn)類似無限遠的陽光,文章使用它來模擬太陽光。點光源是從一個點向各個方向發(fā)射的光源,使用它來增加整體的亮度。

// 聲明平行光
const light = new THREE.DirectionalLight();
// 設(shè)置平行光源位置
light.position.set(0, 0, 1);
// 將平行光源添加到場景中
scene.add(light);
// 聲明點光源
const point = new THREE.PointLight(0xeeeeee);
// 設(shè)置點光源位置
point.position.set(400, 200, 300);
// 點光源添加到場景中
scene.add(point);

立體效果看起來不明顯,沒事,接下來我們讓球體動起來。接下來,給球體添加一個 z 軸和 y 軸的轉(zhuǎn)動。

const createAnimRotation = () =&gt; {
  const speed = 0.005;
  sphere.rotation.z += speed / 2;
  sphere.rotation.y += speed;
};
const render = () =&gt; {
  createAnimRotation();
  renderer.render(scene, camera);
  requestAnimationFrame(render);
};
render();

由于球體是對稱的,轉(zhuǎn)動看起來并不明顯,如果你特別想看到轉(zhuǎn)動效果,可以將 SphereBufferGeometry 暫時更換為 BoxBufferGeometry。

ThreeJS 紋理——實現(xiàn)轉(zhuǎn)動的地球

上文已經(jīng)成功實現(xiàn)地球,接下來我們來為地球披上衣服。本文實現(xiàn)的是雪糕地球,因此小包直接為其披上雪糕外衣。

Three 可以將一張紋理圖映射到幾何體上,具體的映射原理我們不做探究,映射的思想可以參考下圖。

選取一張雪糕地球的紋理圖,使用下面的代碼實現(xiàn)紋理貼圖效果。

// 紋理加載器對象
const textureLoader = new THREE.TextureLoader();
const textureSurface = textureLoader.load(
  "https://s3-us-west-2.amazonaws.com/s.cdpn.io/249663/world-surface.jpg"
);
// 設(shè)置紋理貼圖
const material = new THREE.MeshLambertMaterial({ map: textureSurface });

只使用普通貼圖的雪糕地球看起來已經(jīng)非常不錯了,但還有進一步美化的空間,Three 提供了高光貼圖,使用高光貼圖,會有高亮部分顯示。

const textureSpecular = textureLoader.load(
  "https://s3-us-west-2.amazonaws.com/s.cdpn.io/249663/world-specular.jpg"
);
const material = new THREE.MeshPhongMaterial({
  map: textureSurface,
  specularMap: textureSpecular,
  shininess: 80, // 高光部分的亮度
});

雖然動圖錄制的幀數(shù)太低,還是依稀可以看到一些高亮區(qū)域。

Three 還提供了環(huán)境貼圖,環(huán)境貼圖可以增加表面的細節(jié),使三維模型更加立體。

const textureElevation = textureLoader.load(
  "https://s3-us-west-2.amazonaws.com/s.cdpn.io/249663/world-elevation.jpg"
);
const material = new THREE.MeshPhongMaterial({
  map: textureSurface,
  normalMap: textureElevation,
  specularMap: textureSpecular,
  shininess: 80,
});

立體效果是有了,但是具體看起來一言難盡,顏色有些許暗淡,不符合雪糕的風(fēng)格。

小包繼續(xù)開始查看文檔,環(huán)境貼圖中有 normalScale 屬性,可以設(shè)置顏色的深淺程度,減少對應(yīng)屬性值為 0.5,0.5

sphere.material.normalScale.set(0.5, 0.5);

交互式雪糕地球

給地球加一些交互效果:

  • 當鼠標靠近,地球放大;鼠標遠離時,地球縮小
  • 地球隨鼠標方向轉(zhuǎn)動

上述動效我們可以通過移動相機位置實現(xiàn)。首先設(shè)定地球旋轉(zhuǎn)的最大正負角度為 270。

// 定義動效對象
let mouseX = 0;
let mouseY = 0;
const moveAnimate = {
  coordinates(clientX, clientY) {
    const limit = 270;
    const limitNeg = limit * -1;
    mouseX = clientX - window.innerWidth / 2;
    mouseY = clientY - window.innerHeight / 2;
    mouseX = mouseX &gt;= limit ? limit : mouseX;
    mouseX = mouseX &lt;= limitNeg ? limitNeg : mouseX;
    mouseY = mouseY &gt;= limit ? limit : mouseY;
    mouseY = mouseY &lt;= limitNeg ? limitNeg : mouseY;
  },
  onMouseMove(e) {
    moveAnimate.coordinates(e.clientX, e.clientY);
  },
};
document.addEventListener("mousemove", moveAnimate.onMouseMove);

通過上述事件計算出 mouseXmouseY 的值,在 render 函數(shù)中,修改 camera 的位置。

camera.position.x += (mouseX * -1 - camera.position.x) * 0.05;
camera.position.y += (mouseY - camera.position.y) * 0.05;
camera.lookAt(scene.position);

移動端同步監(jiān)聽 touchmove 事件,手機也可以看到雪糕地球的動態(tài)效果。

const moveAnimate = {
  onTouchMove(e) {
    const touchX = e.changedTouches[0].clientX;
    const touchY = e.changedTouches[0].clientY;
    moveAnimate.coordinates(touchX, touchY);
  },
};
document.addEventListener("touchmove", moveAnimate.onTouchMove);

添加 loading 效果

紋理的加載需要一定的時間,因此添加一個轉(zhuǎn)場 loading 效果。

loading 效果使用小包前面的實現(xiàn)躍動的文字中的效果。

.loader {
  display: flex;
  color: white;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 5em;
  width: 100%;
  height: 100%;
  font-family: "Baloo Bhaijaan", cursive;
}
.loader span {
  text-shadow: 0 1px #bbb, 0 2px #bbb, 0 3px #bbb, 0 4px #bbb, 0 5px #bbb, 0 6px
      transparent, 0 7px transparent, 0 8px transparent, 0 9px transparent, 0
      10px 10px rgba(0, 0, 0, 0.4);
  text-shadow: 0 1px #bbb, 0 2px #bbb, 0 3px #bbb, 0 4px #bbb, 0 5px #bbb, 0 6px
      #bbb, 0 7px #bbb, 0 8px #bbb, 0 9px #bbb, 0 50px 25px rgba(0, 0, 0, 0.2);
  transform: translateY(-20px);
}

Three 提供了 LoadingManager,其功能是處理并跟蹤已加載和待處理的數(shù)據(jù)。當所有加載器加載完成后,會調(diào)用 LoadingManager 上的 onLoad 事件。

因此我們定義一個 LoadingManager,當觸發(fā) onLoad 事件后,將頁面中的加載標志移除。

const loadingScreen = {
  scene: new THREE.Scene(),
  camera: new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  ),
  // 移除加載標志的函數(shù)
  removeText() {
    const loadingText = document.querySelector("#canvas-loader");
    if (loadingText.parentNode) {
      loadingText.parentNode.removeChild(loadingText);
    }
  },
};
// 初始化加載器
let loadingManager = new THREE.LoadingManager();
// 監(jiān)聽加載器 onLoad 事件
loadingManager.onLoad = () =&gt; {
  loadingScreen.removeText();
  isLoaded = true;
};
// 紋理圖加載器傳入 loadingManager
const textureLoader = new THREE.TextureLoader(loadingManager);

參考鏈接

Three中文文檔

以上就是Three.js實現(xiàn)雪糕地球的使用示例詳解的詳細內(nèi)容,更多關(guān)于Three.js雪糕地球的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論