1. 程式人生 > >使用WebGL繪製地球

使用WebGL繪製地球

首先陳述——本篇內容基於《WebGL程式設計指南》書籍以及http://www.hiwebgl.com/?p=339

現在,在正式繪製地球前,我們先來了解下左右手座標系


定義:在空間直角座標系中,讓右手拇指指向X軸的正方向,食指指向Y軸正方向,如果中值能指向Z軸正方向,則稱這個座標系為右手直角座標系。反之稱為左手直角座標系(左手中指指向Z軸正方向)。


那麼在WebGL/OpenGL中使用的是左手還是右手座標系呢?

在釋出的OpenGL ES 2.0(也是WebGL的基礎)的官方手冊中,說明了“GL圖形語言不強制使用左手座標系或右手座標系”

        也就是說,WebGL對使用左手或右手座標系這個問題上是中立的,那為什麼諸多書籍和教程,都講WebGL的座標系統描述為右手的呢?

這是因為使用右手座標系是個傳統。當開發自己的程式時,你需要確定自己使用的座標系統,然後不再改變。這一點對你自己的程式成立,對那些已經開發出來的、幫助開發者使用WebGL(和OpenGL)的各種圖形庫也成立。早起圖形庫中的大部分都採用了右手座標系。時至今日,右手座標系統已經成為了傳統,以致似乎成了GL圖形語言的一部分,這就導致人們都認為GL圖形語言就是右手座標系的。


其實,WebGL的 預設行為,比如,在裁剪空間中使用左手座標系與右手座標系衝突,為了解決這個衝突,我們可以通過翻轉Z座標值進行補償,這樣就能夠繼續使用傳統的右手座標系了。但是,使用右手座標系只是一個傳統,只是大多數人遵守而已。


現在,我們可以明確指出,本次我們繪製的地球,使用的是右手座標系!

接下來,我們來了解一下經緯度,如果不按經緯度繪製地球,而採用WebGL預設的方式繪製地球,不符合我們正常思維邏輯!

這張圖非常清晰的指明瞭經緯度是如何指定的,綠色星星代表地面上的某個位置。

緯度(latitude)的計算是:連線地心與該點,形成的直線與赤道平面的夾角即為緯度。

經度(longitude)的計算是:該點投影到赤道平面上形成的點,這個點與地心連線成的線與本初子午線投影到赤道平面的直線形成的角即是經度。

赤道以北的緯度,叫北緯,習慣上用“N”作代號;赤道以南的緯度,叫南緯,習慣上用“S”作代號。北緯、南緯各有

90度。北極和南極分別是90N90S

        經度是地球上一個地點離一根被稱為本初子午線的南北方向走線以東或以西的度數。本初子午線的經度是0°,地球上其它地點的經度是向東到180°或向西到180°。


在此,緯度範圍是-90°~90°(其實應該是南極到赤道:90°~0°,然後從赤道到北極:0°~90°,但為了在座標軸上描述實際情況,我們表示-90°~90°),經度範圍是-180°~180°(同理)

於是,我們便可繪製地球了,根據人們思維習慣,我們將WebGL使用的右手座標系進行翻轉:


右邊的座標系是左邊座標系經過翻轉後得到的,其實兩個座標系都是一個座標系(右手座標系),只是從不同的角度來看待而已。因為翻轉後的座標系滿足大地座標系(地理座標系)的定義,此時便可通過經緯度座標來描述不同位置。


首先我們定義緯度方向是從南極到北極,也即是從-90°~90°,我們定義連線線與XY平面的夾角為θ,我們可以根據θ的值來計算出每條緯線。每個半圓的弧度是π,所以θ的取值應該是從-π/2一直到π/2。這樣我們就可以確保我們用緯線平均的將球體分割開來。假設定義有50個緯度帶,那麼我們可以將θ角表示為nπ/50 - π/2,n表示從0到50。於是便可表示從南極到北極。


在每個確定的緯線上的點,不管他們的經度如何,都有相同的Z座標。我們可以推出,在這個用50條緯線平均分割且半徑為1的球體上,第n條緯線的Z座標是sin(nπ/50 - π/2),範圍是從-1到1。

接下來定義經度方向是從西經到東經,也即是從-180°~180°,來計算X,Y座標,我們在第n條緯線上,水平將球體切開,可以看到圓的半徑是cos(nπ/50 - π/2),假設為k。如果我們用經線將這個圓平均分割一下,假設是50條經線,將本初子午線投影到這個水平面上,形成一條直線,假設這條直線和經線與圓的交點之間的夾角為φ,又有整個圓的弧度為2π,那麼φ的取值應該是0到2π,因為需要從-180°~180°,所以φ的取值應該為n2π/50 – π,n表示從0到50。於是便可表示從西經到東經。


此時將經線與圓的交點投影到X和Y座標上,已知φ,便可得到X為kcos(φ),Y為ksin(φ)。

由此,可知x,y,z的值為:

x = rcos(θ) cos(φ)

y = rcos(θ) sin(φ)

z = rsin(θ)

以上就是我們如何計算出頂點的過程。接下來是計算紋理座標,我們希望紋理貼圖的提供者,提供給我們的是一張矩形圖片。多說一句,WebGL(不是Javascript)會被其他形狀的貼圖搞暈。這樣,我們就可以放心的假定,這張紋理圖片的頂部和底部拉伸肯定是遵循墨卡託投影法則(Mercator Projection)的。這樣就是說,我們可以從左到右按照經線平均分割紋理圖片得出座標u,從上到下按照緯線平均分割紋理圖片得到座標v。


好了,這就是全部的工作原理。對於Javascript來說,理解並運算以上原理是如此難以置信得簡單方便!我們只需要迴圈遍歷所有的緯線切片,在迴圈內我們再遍歷所有的經線切片,之後我們就可以計算出紋理座標和頂點位置。唯一需要注意的是,在迴圈結束的條件中,迴圈變數必須大於經線或緯線的數量。所以這裡我們必須使用小於等於而不是小於。也就是說,比如有50條經線,在每條緯線上就會產生51個頂點。因為根據三角函式的迴圈,最後一個頂點和第一個頂點的位置其實是相同的,這樣的一個重疊讓我們把所有東西都連線到了一起。

var latitudeBands = 50;//緯度帶
var longitudeBands = 50;//經度帶
var positions = [];//儲存x,y,z座標
var indices = [];//三角形列表(索引值)
var textureCoordData = [];//儲存紋理座標u,v,紋理座標與頂點座標一一對應

for(var latNum = 0; latNum <= latitudeBands; latNum++){
    var lat = latNum * Math.PI / latitudeBands - Math.PI / 2;//緯度範圍從-π/2到π/2
    var sinLat = Math.sin(lat);
    var cosLat = Math.cos(lat);

    for(var longNum = 0; longNum <= longitudeBands; longNum++){
        var lon = longNum * 2 * Math.PI / longitudeBands - Math.PI;//經度範圍從-π到π
        var sinLon = Math.sin(lon);
        var cosLon = Math.cos(lon);

        var x = cosLat * cosLon;
        var y = cosLat * sinLon;
        var z = sinLat;
        var u = (longNum / longitudeBands);
        var v = (latNum / latitudeBands);

        positions.push(x);
        positions.push(y);
        positions.push(z);
        textureCoordData.push(u);
        textureCoordData.push(v);
    }
}

現在我們已經處理完頂點了,還需要把它們縫合到一起。我們生成一個頂點索引列表,將每個四邊形分成一對三角形。
for(var latNum = 0; latNum < latitudeBands; latNum++){
    for(var longNum = 0; longNum < longitudeBands; longNum++){
        var first = latNum * (longitudeBands + 1) + longNum;
        var second = first + longitudeBands + 1;

        indices.push(first);
        indices.push(first + 1);
        indices.push(second);

        indices.push(second);
        indices.push(second + 1);
        indices.push(first + 1);
    }
}

var vertices = new Float32Array(positions);
var indices = new Uint16Array(indices);
var texCoord = new Float32Array(textureCoordData);

我們通過迴圈遍歷了所有頂點,對於每個頂點,我們將其索引值儲存在first變數中,然後向前數longitudeBands + 1個頂點,找到和它配對的下一個緯線帶,儲存在second變數中(之所以+1是因為我們額外增加的那一個頂點會重疊)。這樣我們就生成了兩個三角形,如圖所示。


好了,以上就是我們的繪製地球的核心程式碼,包含了頂點座標和紋理座標,接下來就可以貼紋理,設定觀察點座標……,這些便不再陳述。

現在,讓我們驗證一下,

觀察北極,視點座標為0,0,5,觀察目標點座標為0,0,0,上方向座標為0,1,0

觀察南極,視點座標為0,0,-5,觀察目標點座標為0,0,0,上方向座標為0,1,0

觀察本初子午線,視點座標為5,0,0,觀察目標點座標為0,0,0,上方向座標為0,0,1

通過以上的描述,我們便可直接操作經緯度來對映到我們的座標系統中,這符合我們的思維,既然建立了可描述的地球模型,接下來便可對該模型進行各種操作……



相關推薦

使用WebGL繪製地球

首先陳述——本篇內容基於《WebGL程式設計指南》書籍以及http://www.hiwebgl.com/?p=339 現在,在正式繪製地球前,我們先來了解下左右手座標系 定義:在空間直角座標系中,讓右手拇指指向X軸的正方向,食指指向Y軸正方向,如果中值能指向Z軸正方向

WebGL自學課程(5):使用一張貼圖紋理繪製地球

注:轉載請註明出處 在《WebGL自學課程(3):原生WebGL+ArcGIS JS API繪製旋轉地球》一文中講述瞭如何利用地圖資料繪製地球的輪廓,但是缺少色彩。本文就是想通過貼圖的方式讓地球穿上一層靚麗的外衣,並可以通過滑鼠拖拽等對繪製的地球進行互動式操作。由於本人《

WebGL自學課程(10):通過OpenStreetMap獲取資料繪製地球

好久沒寫部落格了,今天再寫一篇。前幾天想通過OpenStreetMap訪問資料來繪製一個最最最最最簡單的WebGoogleEarth的雛形,這個Demo比較簡單,只是簡單的獲取OpenStreetMap某一個切片層級下面的所有的切片,然後按照正確的貼圖方式繪製在地球上,也就

webgl繪製球體

首先這裡要熟悉一下模型矩陣具體請參考https://blog.csdn.net/baidu_38766085/article/details/79722222 這裡給出一份演示 <!DOCTYPE html> <html> <head lang="en">

原生WebGL基礎學習(二) 用WebGL繪製一個三角形

在開始之前,需要知道著色器的相關知識,可以參考:webgl介紹裡面的著色器介紹,本文的demo 用到的著色器為: <script id="vertex-shader" type="x-shader/x-vertex"> attribu

原生webgl學習(四) WebGL繪製矩形

上節課筆者繪製了一個顏色隨頂點位置變化的三角形,實現平移、旋轉和縮放變換的矩陣計算,並提供了一個可供互動的選單欄工具:原生webgl學習(三) WebGL中的矩陣運算:平移、旋轉和縮放; 在前面我們已經畫了兩次三角形了,這次,改變一些套路,我們畫矩形。畫矩形的程式碼跟上

webgl繪製粗線段

  webgl1不支援設定線段寬度,這就只好通過shader來實現了,參考了踏得網的例子,引用地址:http://wow.techbrood.com/fiddle/43140。先在此感謝踏得網創始人之一 Ryan.chen 陳曉峰。介紹一下踏得網,這是一個推廣交流webgl的網站,同學們可以去學習交流。由於本

WebGL自學課程(3):原生WebGL+ArcGIS JS API繪製旋轉的地球

注:轉載請註明出處 通過ArcGIS JS API獲取地理資料,然後用原生WebGL將其繪製成旋轉的地球。一共需要241271個點,繪製了247個國家或地區。 截圖: 以下是程式碼: <!doctype html> <html> <h

WebGL樹形結構的模型渲染流程 原生WebGL場景中繪製多個圓錐圓柱 原生WebGL場景中繪製多個圓錐圓柱

  今天和大家分享的是webgl渲染樹形結構的流程。用過threejs,babylonjs的同學都知道,一個大模型都是由n個子模型拼裝而成的,那麼如何依次渲染子模型,以及渲染每個子模型在原生webgl中的流程是怎樣的呢,我就以osg框架為原本,為同學們展示出來。   首先介紹osg框架,該框架是基於open

WebGL---3.繪製紋理

一、例項程式碼 <html> <canvas id='c' width='480' height='320'></canvas> <script type="x-shader/x-vertex" id="vertex-shader">

WebGL切換著色器 繪製不同物體

WebGL切換著色器 繪製不同物體 1、為何切換著色器 WebGL繪製不同的物體需要使用不同的著色器,每個著色器中可能有非常負責的邏輯以實現各種不同的效果。我們可以準備多個著色器,然後根據需要來切換使用它們。 2、如何實現切換著色器 為了切換著色器,首先建立多個著色器程式物件

WebGL著色器繪製一個點

OpenGL ES著色器語言(GLSL ES) 1. 強型別語言 2. 內建變數 gl_Position(座標) gl_PointSize(尺寸) gl_FragColor(顏色) 3. gl_pointSize必須使用浮點型,gl_PointSize=10 會報錯,必須10.0這種格式

WebGl通過緩衝區繪製多個點

使用緩衝區物件向頂點著色器傳入多個點 1. 建立緩衝區物件gl.createBuffer() 2. 繫結緩衝區物件gl.bindBuffer() 3. 將資料寫入緩衝區物件gl.bufferData() 4. 將緩衝區物件分配給一個attribute物

webgl第七課-滑鼠分象限繪製不同顏色的點

需要原始碼可以Q群:828202939 或者點選這裡  希望可以和大家一起學習、一起進步!!純手打!! 書籍是PDF電子檔,也在Q群裡,所有的課程原始碼在我上傳的資源裡面,本來想設定開源,好像不行! 如有錯別字或有理解不到位的地方,可以留言或者加微信15250969798,在下

webgl第八課-繪製多個頂點的基礎知識

需要原始碼可以Q群:828202939 或者點選這裡  希望可以和大家一起學習、一起進步!!純手打!! 書籍是PDF電子檔,也在Q群裡,所有的課程原始碼在我上傳的資源裡面,本來想設定開源,好像不行! 如有錯別字或有理解不到位的地方,可以留言或者加微信15250969798,在下

webgl第九課-繪製多個頂點

需要原始碼可以Q群:828202939 或者點選這裡  希望可以和大家一起學習、一起進步!!純手打!! 書籍是PDF電子檔,也在Q群裡,所有的課程原始碼在我上傳的資源裡面,本來想設定開源,好像不行! 如有錯別字或有理解不到位的地方,可以留言或者加微信15250969798,在下

webgl第五課-繪製一個點的另外一種寫法

需要原始碼可以Q群:828202939 或者點選這裡  希望可以和大家一起學習、一起進步!!純手打!! 書籍是PDF電子檔,也在Q群裡,所有的課程原始碼在我上傳的資源裡面,本來想設定開源,好像不行! 如有錯別字或有理解不到位的地方,可以留言或者加微信15250969798,在下

webgl第二課-繪製一個點

需要原始碼可以Q群:828202939 或者點選這裡  希望可以和大家一起學習、一起進步!!純手打!! 書籍是PDF電子檔,也在Q群裡,所有的課程原始碼在我上傳的資源裡面,本來想設定開源,好像不行! 如有錯別字或有理解不到位的地方,可以留言或者加微信15250969798,在下

WebGL視覺化地球和地圖引擎:Cesium.js

Cesium介紹 Cesium是國外一個基於JavaScript編寫的使用WebGL的地圖引擎。Cesium支援3D,2D,2.5D形式的地圖展示,可以自行繪製圖形,高亮區域,並提供良好的觸控支援,且支援絕大多數的瀏覽器和mobile。 無需任何外掛。Ces

WebGL Earth 三維地球

<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf