關於從入門 three.js 到作出 3d 地球這件事

轉載自:lulu_upcss

https://segmentfault.com/a/1190000039647481html

開篇介紹

若是你沒接觸過3d可視化技術, 你也許會認爲可視化很是難, 光是一個物體的陰影要如何計算就至關複雜, 可是告訴你個好消息, 陰影的計算都是集成好的, 而咱們只要設置好光源的位置,繪製好物體就能夠了, 真的沒有想象中那麼複雜, 本文面向有前端基礎,但零可視化基礎的同窗, 我會從最基礎的入門知識提及。前端

學習可視化方面的技術會讓咱們對計算機, 對前端技術有更深的理解, 還能夠作出更多有趣味的東西來, 本文是我踩了好多坑後總結出來的, 我更清楚一個初入門的小白哪裏不懂。vue

three.jswebgl 的第三方庫, 它更適合不太複雜的可視化項目, 而咱們要作的3d地球項目使用它來作會更簡單, 因此選擇了它, 放心後面也會說webgl相關知識 。web

當前效果以下:面試

一. 關於此係列文章

  1. 自食其力:不論是在公司仍是網上都有相似的庫, 可是當遇到bug或是缺乏功能的狀況時就會很麻煩, 例如咱們公司的FGL庫(一個內網繪製3d景象的技術), 它官網上的例子不少都是錯的, 使用起來也是一堆問題, 好比沒法精準選擇某個國家, 點擊事件消融等bug。還好比說 Echarts的地球, 它太注重真實感而且用起來有點卡, 以及交互作的不太好。
  2. 直指核心: 去年我經過看書、看文章、看視頻認真的學習 three.js, 並作出了3d地球這個項目, 而這個系列文章將會直指作出3d地圖的核心知識, 儘可能不隨意擴散知識面。
  3. 更好入門: 網上的教學文章千篇一概, 點進去閱讀完感受其對於一個 three.js零基礎的同窗來講都不太好懂, 教學視頻裏的知識點太普遍, 事無鉅細的羅列, 而這個系列文章將更突出繪製3d地球這個重點。
  4. 同道中人: 我學習 three.js就是爲了作出3d地球, 期間走了很多彎路, 被某些問題卡了好久, 因此我更懂一個剛入門的人困惑的點在哪裏。
  5. 專一vue: 市面上較少專門針對 vue作到開箱即用的3d地球插件, 而咱們就要編寫這樣一款產品。
  6. 不斷學習: 編寫文章也是我提升本身能力的一種方法, 死磕每一個知識點讓本身的理解更上一層樓。

二. 任務目標

  1. 入門 three.js技術。
  2. 繪製出3d地球。
  3. 作成專門 vue使用的庫。
  4. 後期也會介紹 着色器的概念與基本的使用技巧。
  5. 會介紹少許 webgl的相關用法, 而且會有部分數學知識。

三. 文章主線劇情與支線任務

  • 主線劇情: 圍繞着如何作出3d地球, 這部分在vue工程裏面進行。
  • 支線任務: 每一個分散的知識點, 可能與3d地球不要緊, 可是它能幫助咱們更好的理解3d技術, 而這些知識點我就不在vue項目裏面演示了, 會單首創建一個html文件來演示說明。

四. 理解座標系: 彆着急寫代碼先有基本模型

像繪製圖形這類技術, 最基本的概念就座標系, 下圖是二維座標系, 咱們的故事就從這個傢伙開始。     咱們用(0, 0)表示座標的中心點, 繪製一條起點爲中心點長度爲1的線段可使用 (0, 0) (1, 0)這兩個點相連表示。ajax

關於向量的概念後面須要用數學知識的時候再介紹, 前幾篇文章就越通俗越好。

three.js中咱們要打交道的就是下面這位三維座標系     他的座標原點就是(0, 0, 0), 繪製一條起點爲中心點的長度爲1的線段能夠是 (0, 0, 0) (1, 0, 0)算法

這裏要記住, three.js裏面設置的默認座標系就是這種形式x向右, y向上, z向前, 之因此說是默是由於它能夠修改。編程

上圖中, 觀看這個三維座標系的目光實際上是在斜上方, 正常狀況下在咱們開發的時候z軸是正對着咱們的眼睛的, 因此你只能看到z軸是一個點,canvas

在開發與學習的時候, 最好先把座標系繪製到頁面上, 方便咱們更好的繪製。

五. 相機的概念

假設如今咱們的正前方有一個三維座標系的全息投影, 那麼此時你的眼睛就至關於一架相機, 你看到的 座標系景象取決於你站的位置。

three.js中就有這樣一個對象, 他就是負責從哪一個角度觀察咱們繪製的3d世界, 也就是相機這個概念的由來。

相機分爲兩種, 正投影相機和透視投影相機, 正投影相機就是你站的多遠你看到的物體的大小都不變, 透視投影相機就是物體會近大遠小, 下面是張引用圖 (圖片來自網絡)。

正投影相機能夠用在工程製圖上, 或者能夠作一些視覺欺騙小遊戲。

本文主要目的是繪製3d地球因此主要使用透視投影相機

六. 繪製座標系, 安放攝像機 (代碼安排上)

引入three.js, 能夠把包下載到本地, 也能夠直接獲取在cdn上的資源, 引入以後全局會出現THREE對象, 咱們就能夠開始編程之旅了。

<script src="https://cdn.bootcdn.net/ajax/libs/three.js/r122/three.min.js"></script>

一個普普統統的html空文件的script標籤裏面, 發生着這樣的故事: 讓咱們逐句解析

第一步:建立場景, 也就是虛擬的空間

咱們以後繪製的3d物體都要放入這個空間裏面, 你能夠把它當作一個鴻蒙空間神器, 裏面有一個小世界, 而咱們是掌控者(很中二)。

const scene = new THREE.Scene();
第二步:建立相機

相機的概念上面講述過了, PerspectiveCamera這個類就是透視投影相機, 咱們來逐個攻破他參數的意思。

  1. 35: 視角也就是咱們左眼與右眼能夠看到的橫向角度, 其越小物體則越大, 由於目光變狹窄會突出物體, 你能夠作一個實驗, 聚精會神的盯着看一個物體, 你就會發現此時你左右兩邊原本靠餘光能夠看到的物體你如今看不清, 這個就是你的視角變小了, 變小視角還可使目標物體比例變大, 咱們知道這些就夠理解這個數字了, 後期能夠利用這個原理作一些使人驚訝的動畫特效。
  2. window.innerWidth / window.innerHeight: 縱橫比 寬/高, 這裏寬高不會去寫 px這種單位, 座標系裏面是一種抽象的長度單位, 因此要告訴瀏覽器我們當前顯示圖像的區域的寬高比例(能夠當它是百分比佈局, 就像咱們寫css佈局時使用 vh vw爲單位)。
  3. 1: 近平面, 簡單理解就是當一個 圖像距離 相機的距離小於1的時候, 就不顯示這個圖像了。
  4. 1000: 遠平面, 簡單理解就是當一個 圖像距離 相機的距離大於1000的時候, 就不顯示這個圖像了。
  5. camera.position.z = 10; 相機的座標不設置的話, 默認就是(0, 0, 0)座標原點, 這樣相似腦殼在座標軸原點上看座標軸, 因此這裏要設置距離座標中心有必定距離, 也就是遠距離觀察這個座標系。
const camera = new THREE.PerspectiveCamera(35window.innerWidth / window.innerHeight, 11000);
camera.position.z = 10;
  • 無聊的知識: 咱們在玩 3d遊戲的時候, 是否是有時候與另外一個遊戲人物距離太近了就會出現 人物中空的效果, 這些極可能就是他的某些部分距離你相機的距離, 小於了 近平面的距離致使的。
  • 物體距離眼睛越近越大, 越遠越小, 由於一個物品無限大與無限遠沒有意義, 顯示起來浪費性能, 因此纔會設置近平面與遠平面。

第三步:生成渲染實例
  1. WebGLRenderer生成一個渲染實例, 用來渲染咱們全部的3d效果。
  2. setSize設置場景的寬高。
  3. setClearColor設置背景色, 這個背景色不是平面的, 是全方位的, 你能夠想一想成你在一個屋子裏, 這個顏色就是屋子牆壁、地板、天花板的顏色(.5是透明度)。
  4. renderer.domElement生成的渲染的實例, 這個要放到對應的dom容器裏面(是個canvas標籤)。
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x00FFFF.5)
document.body.appendChild(renderer.domElement);
  • 知識點: setClearColor不寫就是黑色
  • 知識點: setClearColor能夠直接寫"red"這種, 不用必須16進制。
第四步:插入座標系實例
  1. AxisHelper: 用於生成輔助座標實例, 2表明這個座標系的長度, 由於咱們不必定須要多長的輔助線。
  2. scene: 老朋友 場景, 它的 add方法就是把某某某加入到場景中來。
const axisHelper = new THREE.AxisHelper(2)
scene.add(axisHelper)
第五步:渲染出來
  1. 第一個參數是 場景, 第二個參數是 相機
renderer.render(scene, camera);

下面是效果圖, z軸正對着咱們因此看不到:

在斜上方看到是以下的效果, 以後的章節會說如何調整相機的位置與角度

完整的代碼以下

<html>
<body>
    <script src="https://cdn.bootcdn.net/ajax/libs/three.js/r122/three.min.js"></script>
    <script>
        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera(35window.innerWidth / window.innerHeight, 11000);
        camera.position.z = 10;
        const renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setClearColor(0x00FFFF.5)
        document.body.appendChild(renderer.domElement);
        const axisHelper = new THREE.AxisHelper(2)
        scene.add(axisHelper)
        renderer.render(scene, camera);
    </script>

</body>
</html>

七. 第一個立方體

不畫一個立方體感受對不起 第一篇這個題目, 要注意了在three.js中你能夠理解爲繪製一個幾何體須要兩部分, 一個是幾何體自己, 好比這個幾何體的長寬高, 另外一個就是材質能夠簡單理解爲表面的顏色樣式。     geometry這個單詞咱們會常常打交道的, 來一塊兒記下它吧。

BoxGeometry 長方體

const geometry = new THREE.BoxGeometry(1, 2, 3);

  1. 1: '長', 也能夠理解爲在不設置座標的時候在x軸上的長度。
  2. 2: '高', 也能夠理解爲在不設置座標的時候在y軸上的長度。
  3. 3: '寬', 也能夠理解爲在不設置座標的時候在z軸上的長度。

new出來的實例上面會有這個幾何體的點的信息, 面的信息等等, 這個後面再詳細說此次主要入門。

MeshBasicMaterial 材質

顏色與上面設置setClearColor同樣, 什麼寫法都行的, 下面是我設置了一個紅色的材質。const material = new THREE.MeshBasicMaterial({ color: 'red' });

生成'網格' Mesh

const cube = new THREE.Mesh(geometry, material);網格上含有位置信息、旋轉信息、縮放信息等等, 他須要用幾何體材質兩個參數, 但其實並不像網上說的必需要有材質, 不傳材質也能顯示。

放入場景

也就是場景對象scene自己有個add方法。scene.add(cube);

右上方視角

放入場景的幾種方式

1: 我直接放入geometryscene.add(geometry); 會報錯了, 能夠理解爲不是網格對象因此報錯了。之後遇到這類報錯必定要考慮類型問題。

2: 未設置材質

const cube = new THREE.Mesh(geometry);

scene.add(cube);

白白的一片, 而且控制檯沒有報錯。

八. 所有代碼

<html>
<body>
    <script src="https://cdn.bootcdn.net/ajax/libs/three.js/r122/three.min.js"></script>
    <script src="./utils/OrbitControls.js"></script>
    <script>
        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera(35window.innerWidth / window.innerHeight, 11000);
        camera.position.z = 10;
        const renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setClearColor(0x00FFFF.5)
        document.body.appendChild(renderer.domElement);
        const axisHelper = new THREE.AxisHelper(2)
        scene.add(axisHelper)

        const geometry = new THREE.BoxGeometry(123);
        const material = new THREE.MeshBasicMaterial({ color'red' });
        const cube = new THREE.Mesh(geometry, material);
        scene.add(cube);

        renderer.render(scene, camera);
    </script>

</body>

</html>

end

第一篇寫的內容並很少, 等基本知識儲備夠了就能夠開始編寫3d地球了, 那裏將會頗有意思。但願與你一塊兒進步。

最後

歡迎關注【前端瓶子君】✿✿ヽ(°▽°)ノ✿
回覆「 算法 」,加入前端算法源碼編程羣,每日一刷(工做日),每題瓶子君都會很認真的解答喲!
回覆「交流」,吹吹水、聊聊技術、吐吐槽!
回覆「 閱讀 」,每日刷刷高質量好文!
若是這篇文章對你有幫助,在看」是最大的支持
》》面試官也在看的算法資料《《
「在看和轉發」 就是最大的支持

本文分享自微信公衆號 - 前端瓶子君(pinzi_com)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索