中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么用Three.js實現雪糕地球

發布時間:2022-07-06 10:16:29 來源:億速云 閱讀:146 作者:iii 欄目:開發技術

這篇“怎么用Three.js實現雪糕地球”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“怎么用Three.js實現雪糕地球”文章吧。

  • 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

/*
 * 基礎配置
 */
let isLoaded = false; // 紋理資源是否加載完畢
const loadingScreen = {
  scene: new THREE.Scene(),
  camera: new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  ),
  // 移除加載標志的函數
  removeText() {
    const loadingText = document.querySelector("#canvas-loader");
    if (loadingText.parentNode) {
      loadingText.parentNode.removeChild(loadingText);
    }
  },
};
// 初始化加載器
let loadingManager = new THREE.LoadingManager();
// 監聽加載器 onLoad 事件
loadingManager.onLoad = () => {
  loadingScreen.removeText();
  isLoaded = true;
};
// 創建場景
const scene = new THREE.Scene();
// 創建渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true });
// 渲染器基本設置
renderer.setClearColor("hotpink");
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// canvas 外部容器
const canvasWrapper = document.querySelector("#canvas-wrapper");
// 創建透視相機
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
// 設置相機位置
camera.position.set(0, 0, 220);
// 創建平行光源
const light = new THREE.DirectionalLight();
light.position.set(0, 0, 1);
scene.add(light);
// 創建點光源
const point = new THREE.PointLight(0xeeeeee);
point.position.set(400, 200, 300); //點光源位置
scene.add(point); //點光源添加到場景中
// 創建球體
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"
);
// 材質信息
const materialOpt = {
  map: textureSurface,
  normalMap: textureElevation,
  specularMap: textureSpecular,
  shininess: 80,
};
const material = new THREE.MeshPhongMaterial(materialOpt);
// 創建網格體
const sphere = new THREE.Mesh(geometry, material);
// 設置環境貼圖的顏色深淺
sphere.material.normalScale.set(0.5, 0.5);
// 將模型添加到場景中
scene.add(sphere);
// 將 canvas 元素添加到頁面中
canvasWrapper.appendChild(renderer.domElement);
/*
 * 事件監聽實現動效
 */
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;
};
// 渲染函數
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();
  • 在線體驗(支持PC與移動端): 雪糕地球線上預覽

  • 源碼倉庫: 雪糕地球

ThreeJS 基礎&mdash;&mdash;實現轉動的球體

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

下面首先來看一下 Three 框架的基本組成要素

怎么用Three.js實現雪糕地球

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

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

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

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

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

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

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

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

怎么用Three.js實現雪糕地球

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

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

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

SphereBufferGeometryThree 中實現球體的 API,參數非常多,這里只介紹前三個參數

radius: 球體半徑

widthSegments: 沿經線方向分段數

heightSegments: 沿緯線方向分段數

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

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

渲染網格體 Mesh,并將其添加到場景 Scene 中。

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

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

怎么用Three.js實現雪糕地球

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

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

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

怎么用Three.js實現雪糕地球

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

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

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

怎么用Three.js實現雪糕地球

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

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();

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

ThreeJS 紋理&mdash;&mdash;實現轉動的地球

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

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

怎么用Three.js實現雪糕地球

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

怎么用Three.js實現雪糕地球

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

只使用普通貼圖的雪糕地球看起來已經非常不錯了,但還有進一步美化的空間,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, // 高光部分的亮度
});

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

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

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,
});

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

小包繼續開始查看文檔,環境貼圖中有 normalScale 屬性,可以設置顏色的深淺程度,減少對應屬性值為 0.5,0.5

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

交互式雪糕地球

給地球加一些交互效果:

  • 當鼠標靠近,地球放大;鼠標遠離時,地球縮小

  • 地球隨鼠標方向轉動

上述動效我們可以通過移動相機位置實現。首先設定地球旋轉的最大正負角度為 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 函數中,修改 camera 的位置。

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

移動端同步監聽 touchmove 事件,手機也可以看到雪糕地球的動態效果。

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 效果

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

loading 效果使用小包前面的實現躍動的文字中的效果。

.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,其功能是處理并跟蹤已加載和待處理的數據。當所有加載器加載完成后,會調用 LoadingManager 上的 onLoad 事件。

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

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

以上就是關于“怎么用Three.js實現雪糕地球”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

淮南市| 东城区| 远安县| 当阳市| 灵石县| 横峰县| 钟山县| 阆中市| 犍为县| 湛江市| 康定县| 龙山县| 光泽县| 营口市| 达拉特旗| 巴青县| 舟曲县| 广宁县| 赤峰市| 勃利县| 永德县| 泗水县| 大方县| 徐汇区| 焦作市| 新和县| 铜鼓县| 施甸县| 吉水县| 峡江县| 浏阳市| 巴南区| 富宁县| 呈贡县| 扶绥县| 龙门县| 林州市| 修武县| 五大连池市| 铜鼓县| 红桥区|