Three.js的繪製流程(三)----地形

最簡單的地形是單一的平面, 這個經過javascript

var geo = new THREE.PlaneGeometry(2, 2, 256, 256) 幾何體構建, 能夠設定平面的切分塊的數量。java

var pmesh = new THREE.Mesh(geo, material);數組

能夠爲平面提供紋理, 從而是地面看起來更真實一些,而紋理座標在geo中已經自動設定好了。 所以只須要寫材質就能夠了。dom

這裏使用ShaderMaterial 用於材質。函數

頂點shader:工具

varying vec2 vUV; //從定點shader 傳遞到 片斷shader的紋理座標spa

void main()code

{orm

      vUV = uv; //uv 是默認存在的頂點屬性, 用於作紋理座標圖片

      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1);// projectionMatrix 默認存在的投影矩陣 modelViewMatrix默認模型視圖矩陣 position定點座標 
}

 

片斷shader:

uniform sampler2D texture_grass;//紋理

varying vec2 vUV;

void main()

{

     gl_FragColor = texture2D(texture_grass, vUV);
}

材質則是:

var mat = new THREE.ShaderMaterial({

     uniforms:{

          texture_grass:{type:'t', value:0,  texture:TRHEE.ImageUtils.loadTexture("texture_grass.png")},//類型紋理, 紋理編號0, 加載圖片數據 

    },

     attributes:{},

     vertexShader:text,

     fragmentShader:text,

});

var pmesh = new THREE.Mesh(geo, mat);

 

這樣就獲得一個添加了紋理的平面, 平面在x,y 平面上, 平面的正方向指向z正向, 能夠調整平面x軸逆時針旋轉90度, 獲得x,z 方向的平面。

 

如今咱們指望可以調整地面的高度, 採用的方式是鼠標點擊屏幕位置, 計算實際的地面的位置, 接着調整地面上該點附近的全部定點的高度。

調整高度有兩種方式, 一是調整geo幾何體中的vertices 中的y值, 或者在修改shader程序 增長一個頂點屬性, displacement 用於記錄全部頂點的高度,這樣只須要修改這一個數據就能夠了,而不須要修改整個定點數組。

頂點shader調整:

attribute float displacement;

varying vec2 vUV;

void main()

{

       vUV = uv;

       gl_Position = projectionMatrix * modelViewMatrix * vec4(position.xy,  displacement, 1);
}

材質調整:

var mat = new THREE.ShaderMaterial({

      //其它部分相同

       attributes:{

     displacement:{type:'f',  value:[]},

   }

});

須要根據平面頂點個數 來初始化displacement值爲0

for(var i = 0; i < geo.vertices.length; i++)

      mat.attributes.displacement.value.push(0);

 

由於須要動態調整displacement的值 因此須要設定geo是動態更新的

geo.dynamic = true;

 

這樣如今仍只是看到一個平面;接下來須要設定鼠標點擊的時間處理函數。

var projector = new THREE.Projector(); //計算從屏幕座標到 世界座標的工具

 

renderer.domElement.onmousedown = function(e){

     var mx = e.offsetX;

     var my = e.offsetY;

     //計算相機近平面上的座標

      mx = 2*mx/SCREEN_WIDTH-1;

     my = 1 - 2*my/SCREEN_HEIGHT;

    var vec = new THREE.Vector3(mx, my, 0);//只有 x y 座標有意義

     var ray = project.pickingRay(vec, camera);//計算從相機發出的穿過近平面上mx my 點的射線

    var intersects = ray.intersectObject(pmesh); //計算射線和 平面的全部交點 0 或者 1個

     if(intersects.length > 0)

    {

            //存在交點

           updateDisplacement(intersects[0].point); //調整該點附近頂點的高度。

    }

}

 

function updateDisplacement(point)

{

//平面方位 -1, 1  -1, 1 x軸切分256份, WIDTH= 257,  y軸切分256份 , HEIGHT=257

//計算交點附近 0.1爲邊長的矩形框的上下左右範圍, 接着計算geo中相應的定點的行和列範圍。

//調整全部頂點的高度, 設定材質中的 mat.attributes.displacement.needsUpdate = true;  設定displacement須要更新

 

var radius = 0.05;     var left = point.x-radius;    var right = point.x+radius;    var bottom = point.z-radius;    var up = point.z + radius;    var rowGrid = 2/(HEIGHT-1);    var colGrid = 2/(WIDTH-1);        var rowBegin = ~~Math.max((bottom+1)/rowGrid, 0);    var rowEnd = ~~Math.min((up+1)/rowGrid, HEIGHT);    var colBegin = ~~Math.max((left+1)/colGrid, 0);    var colEnd = ~~Math.min((right+1)/colGrid, WIDTH);
for(var i = rowBegin; i <= rowEnd; i++)    {        for(var j = colBegin; j <= colEnd; j++)        {            var num = ~~(i*WIDTH+j);            //console.log(num);            pmesh.displacement.value[num] += 0.05;            //console.log("new", pmesh.displacement, pmesh.displacement.needsUpdate);        }    }    pmesh.displacement.needsUpdate = true;


}

 

結束:

   經過設定幾何體能夠動態更新,  設定 材質中的屬性須要更新, 則實現了調整displacement的目的。

相關文章
相關標籤/搜索