LOD 處理比較大的外部地面場景中比較有用, 通常用於繪製地形。 首先經過可視體的切割刪除不用的地形塊,接着經過LOD 對照相機不一樣距離的地形塊進行層次細節調整。函數
這裏採用最簡單的LOD 方法。this
首先地形有n*n 的塊構成, 這些塊共同構成一個大平面;prototype
首先根據每一個塊到照相機的距離 計算細節層次, code
例如假設由5*5 個塊構成地形, 每一個塊1*1大小, 有4個細節層次, 對象
當塊距離照相機 小於2 層次 0rem
距離小於4 層次 1get
小於6 層次 2it
其它層次 3io
首先構造一個Object3D 做爲整個地面的表明。console
myGame.Earth = function(){ THREE.Object3D.call(this); this.curPatches = []; this.patches = []; this.width = 5; this.height = 5; this.patch_width = 1; this.patch_height = 1; for(var i = 0; i < this.height; i++) { for(var j = 0; j < this.width; j++) { this.patches.push(1);//distance ---> detail 0 1*1 } } }; myGame.Earth.prototype = new THREE.Object3D();
var earth = new myGame.Earth();
curPatches 用於存放當前組成earth的塊, 當細節層次須要改變的時候這些塊將被丟棄,而從新構造新的塊。
patches用於存儲當前塊的細節層次。
關鍵的setDetails 函數用於調節塊的細節, 首先計算全部塊到照相機的距離 獲得細節層次; 接着刪除舊的全部平面, 接着再構建新的塊加入到場景中。
myGame.Earth.prototype.setDetails = function(camera){ var diff = new THREE.Vector3(); var standard = this.patch_width; var pos = new THREE.Vector3(); for(var i = 0; i < this.height; i++) { for(var j = 0; j < this.width; j++) { pos.set(-this.width/2*this.patch_width+j*this.patch_width+this.patch_width/2, 0, -this.height/2*this.patch_height+i*this.patch_height+this.patch_height/2); var dist = diff.sub(camera.position, pos).length(); if(dist < 2*standard) this.patches[i*this.width+j] = 0; else if(dist < 4*standard) this.patches[i*this.width+j] = 1; else if(dist < 6*standard) this.patches[i*this.width+j] = 2; else this.patches[i*this.width+j] = 3; } } for(var i = 0; i < this.curPatches.length; i++) { this.remove(this.curPatches[i]); } var mat = new THREE.MeshBasicMaterial({color:0xff0000, wireframe:true}); for(var i = 0; i < this.patches.length; i++) { var pl; var detail = this.patches[i]; console.log(detail); if(detail == 0) pl = new THREE.PlaneGeometry(this.patch_width, this.patch_height, 10, 10); else if(detail == 1) pl = new THREE.PlaneGeometry(this.patch_width, this.patch_height, 5, 5); else if(detail == 2) pl = new THREE.PlaneGeometry(this.patch_width, this.patch_height, 2, 2); else pl = new THREE.PlaneGeometry(this.patch_width, this.patch_height, 1, 1); var obj = new THREE.Mesh(pl, mat); obj.position.set(-this.width/2*this.patch_width+i%this.width*this.patch_width+this.patch_width/2, -this.height/2*this.patch_height+ (this.height-~~(i/this.width))*this.patch_height+this.patch_height/2, 0); this.curPatches.push(obj); this.add(obj); } };
在每幀更新的時候, 經過檢測照相機新舊位置的距離差, 若是足夠大 則更新整個場景的塊。
function animate() { requestAnimationFrame(animate); controls.update(clock.getDelta()); var vec = new THREE.Vector3(); var dist = vec.sub(camera.position, camera.oldPosition).length(); if(dist > earth.patch_width) { camera.oldPosition.copy(camera.position); earth.setDetails(camera); } render(); }