iT邦幫忙

DAY 21
0

30 天實戰跨平台行動APP系列 第 21

Day 21 地球圖資

  • 分享至 

  • xImage
  •  

今天想想昨天可能找錯方向了,GIS資料應該是用來顯示特殊的資訊,例如湖泊港口的位置,國家的邊界等。

但是我想要的是地球的材質效果。所以換個方向找馬上就找到了celestia這個open source的專案。

celestia 是一個OpenGL開發的天文軟體,使用者可以在這個虛擬的宇宙自由地觀看各種星體唷。

[http://www.shatters.net/celestia/](http://www.shatters.net/celestia/" style="line-height: 1.6;) 這個是主站

http://www.celestiamotherlode.net/ 這裡有各式各樣的擴充包可以下載,包含太陽~人造衛星~月球~其它星體等

我們就在第二個站抓到了地球的天然景觀大圖!

下載下來的圖有分等級,等級越高的越細緻。例如level 0 的將整個世界地圖分成兩張1024 X 1024的圖,而level 1 分成八張!

將來可以看你要有幾張圖就分別做成幾個材質,或是先把圖組合起來做成一個材質,都是可以的。

接下來就要回到我們做出來的圓球模型,然後算出材質坐標了,這意味著又要進入數學時間!

這邊的數學是使用 Mercator projection

http://en.wikipedia.org/wiki/Mercator_projection

請看這個圓柱投影,我們最終的目標就是要從左邊的P點坐標,到右邊的P' 坐標,在轉換成0~1的材質坐標喲

右邊的P'點 X就是從-180度~180度(或是0~360度)但是重點就在於P'的y坐標,詳細推導請看維基百科,

直接節錄結果:

在之前的sphere物件中加入vertexTextureCoords屬性,

然後再計算點坐標的函式中加入以下:

var firstStep = -Math.PI/2 + Math.PI*1*latPace;

var tanRes = Math.tan(firstStep/2+Math.PI/4);

var totalLength = Math.log(tanRes)*2;



for(var i=0;i<this.latitudinalNum;i++){

for(var j=0;j<this.longitudinalNum;j++){



var texX = j*longPace;



var phi=0;



if(i==0)

phi = -Math.PI/2 + Math.PI*1*latPace;

else if(i==(this.latitudinalNum-1))

phi = -Math.PI/2 + Math.PI*(i-1)*latPace;

else

phi = -Math.PI/2 + Math.PI*(i)*latPace;



tanRes = Math.tan(phi/2+Math.PI/4);



var texY = (Math.log(tanRes)+totalLength/2)/totalLength;

this.vertexTextureCoords.push(texX);

this.vertexTextureCoords.push(texY);



}

}

首先,x 的值就是j*longPace,本來就是0~1,這沒問題。

然後phi的值,因為若是正負九十度帶入公式,y的值是會發散的。

所以這兩個角度我們要取近似,分別是第二個及倒數第二個phi代入公式的值

然後因為要mapping為0~1 所以一開始要先計算全部的長度totalLength,最後要代入公式

           var texY  =  (Math.log(tanRes)+totalLength/2)/totalLength;

此效果相當于

           var texY  =  Math.log(tanRes)/totalLength+0.5

如此一來就材質坐標就計算好了!

接下來再主程式中

var EARTH_TEXTURE = 0;
var earthFieldTextureCoordBuffer = null;
加入地球的材質索引,跟地球的材質坐標buffer!

loadTexture中加入

	textureImage[EARTH_TEXTURE] = new Image();
	
	textureImage[EARTH_TEXTURE].onload = function() {
		setupTexture(EARTH_TEXTURE);
		
		glProgram.samplerUniform5 =  gl.getUniformLocation(glProgram, "uSampler6");
		
		gl.uniform1i(glProgram.samplerUniform5, EARTH_TEXTURE);
	}
	
	textureImage[EARTH_TEXTURE].src = "./images/earth_level_0.png";

setupBuffer 中建立地球材質坐標buffer

	earthFieldTextureCoordBuffer = gl.createBuffer();
	gl.bindBuffer(gl.ARRAY_BUFFER,earthFieldTextureCoordBuffer);
	gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(sphere.vertexTextureCoords),gl.STATIC_DRAW);

然後再fragment shader加入

uniform sampler2D uSampler6;
main(){
...
    }
    else if(textureSwitch==6){
        gl_FragColor = texture2D(uSampler6, vec2(vTextureCoord.s, vTextureCoord.t));

    }
...
}

如此一來就準備就緒,最後再drawScene中的地球繪圖部分改成

	gl.bindTexture(gl.TEXTURE_2D, texture[EARTH_TEXTURE]);

	glProgram.textureSwitch = gl.getUniformLocation(glProgram,"textureSwitch"); 
	gl.uniform1i(glProgram.textureSwitch,EARTH_TEXTURE+1);

    gl.bindBuffer(gl.ARRAY_BUFFER, sphereVerticeBuffer);
    gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
    
	gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, sphereIndexBuffer);  
	gl.drawElements(gl.TRIANGLES, sphereIndexBuffer.number_vertex_points, gl.UNSIGNED_SHORT, 0);	

這樣就完成了!

看看結果

好像不錯,但是板塊的位置怎麼怪怪的,明天再研究哪裡出了問題!


上一篇
Day 20 地球圖資
下一篇
Day 22 檢視目標
系列文
30 天實戰跨平台行動APP26
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言