2008-03-19 | 20:37
以前作成した地形データの自動生成のメッシュ版
(地形データを自動生成するアルゴリズム自体は全く同じです)
マウスクリックで新しい地形データを生成し直します。
Click to generate new landform.
(地形データを自動生成するアルゴリズム自体は全く同じです)
マウスクリックで新しい地形データを生成し直します。
Click to generate new landform.
package { import flash.display.*; import flash.events.*; import org.papervision3d.view.BasicView; import org.papervision3d.core.geom.TriangleMesh3D; import org.papervision3d.core.geom.renderables.Triangle3D; import org.papervision3d.core.geom.renderables.Vertex3D; import org.papervision3d.core.math.NumberUV; import org.papervision3d.lights.*; import org.papervision3d.materials.*; import org.papervision3d.materials.special.*; import org.papervision3d.materials.shadematerials.* ; import org.papervision3d.materials.utils.*; [SWF(width=600, height=500, backgroundColor=0x111111)] public class Mesh extends BasicView { private var mesh:TriangleMesh3D=null; private var landForm:LandForm; private var pointLight:PointLight3D; private var f:Number = 0; public function Mesh() { stage.frameRate = 10; stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; stage.quality = StageQuality.MEDIUM; super (0,0,true,false,"CAMERA3D"); init3D(); stage.addEventListener(MouseEvent.MOUSE_DOWN, buildMesh); buildMesh(); } public function init3D():void { camera.y = 100; camera.z = -300; camera.focus = 500; camera.zoom = 8; pointLight = new PointLight3D(true); pointLight.y = 300; startRendering(); } override protected function onRenderTick(event:Event=null):void { f += 0.02; pointLight.x = 100*Math.cos(f); pointLight.z = 100*Math.cos(f); mesh.rotationY += 0.1; super.onRenderTick(event); } private function buildMesh(e:* = null):void { if(mesh) scene.removeChild(mesh); var mat:PhongMaterial = new PhongMaterial(pointLight, 0xcc5555, 0x111111, 1); mesh = new TriangleMesh3D( mat, [], [], null ); scene.addChild(mesh); landForm = new LandForm(128); for(var i:int = 0 ; i < 6 ; i++) landForm.split(); mesh.geometry.vertices = []; mesh.geometry.faces = []; for(var z:int = 0 ; z < landForm.length ; z++){ var vertices:Array = []; for(var x:int = 0 ; x < landForm.length ; x++){ mesh.geometry.vertices.push( new Vertex3D(landForm.scale*(x - ( landForm.length - 1)/2), landForm.value(x,z), landForm.scale*(z - (landForm.length - 1)/2))); } } for(z = 0 ; z < landForm.length - 1; z++){ for(x = 0 ; x < landForm.length - 1; x++){ var uvA:NumberUV = new NumberUV( 0, 0 ); var uvC:NumberUV = new NumberUV( 1, 0 ); var uvB:NumberUV = new NumberUV( 0, 1 ); mesh.geometry.faces.push( new Triangle3D( mesh, new Array(mesh.geometry.vertices[x * landForm.length + z], mesh.geometry.vertices[x * landForm.length + z + 1], mesh.geometry.vertices[(x+1) * landForm.length + z]), null, new Array(uvC,uvB,uvA) )); mesh.geometry.faces.push( new Triangle3D( mesh, new Array(mesh.geometry.vertices[x * landForm.length + z + 1], mesh.geometry.vertices[(x+1) * landForm.length + z + 1], mesh.geometry.vertices[(x+1) * landForm.length + z]), null, new Array(uvA,uvB,uvC) )); } } mesh.geometry.ready = true; } } } internal class LandForm{ private var buffer:Array = new Array(); private var range:int ; private var splitCnt:int = 0; private var base:Number = 10; // range は2の乗数であること public function LandForm(range:int){ this.range = range; clear(); } public function clear():void{ buffer = []; // 変位が格納される2次元配列(w*h) for(var j:int = 0 ; j < range+1; j++){ var aa:Array = new Array(); for(var k:int = 0 ; k < range+1; k++) aa.push(0); buffer.push(aa); } buffer[0][0] = base*Math.random(); buffer[range][0] = base*2*Math.random(); buffer[0][range] = base*3*Math.random(); buffer[range][range] = base*4*Math.random(); //trace(buffer[128][128]); } public function split():void{ if(Math.pow(2,splitCnt) >= range){ splitCnt=0; clear(); } splitCnt++; for(var x:int = 1 ; x < length ; x+=2){ for(var y:int = 1 ; y < length ; y+=2){ splitMidPoint(x, y); } } } private function splitMidPoint(x:int, y:int):void{ midPoint(x,y,true); midPoint(x-1,y); midPoint(x+1,y); midPoint(x,y-1); midPoint(x,y+1); } private function midPoint(x:int, y:int, squere:Boolean=false):void{ //trace(x.toString() + ":" + y.toString()); var sum:Array = []; if(squere){ if(x > 0 && y > 0 && value(x-1,y-1) != 0 ) sum.push(value(x-1, y-1)); if(x > 0 && y < length-1 && value(x-1,y+1) != 0) sum.push(value(x-1, y+1)); if(x < length - 1 && y > 0 && value(x+1,y-1) != 0) sum.push(value(x+1, y-1)); if(x < length - 1 && y < length - 1 && value(x+1,y+1) != 0) sum.push(value(x+1, y+1)); }else{ // diamonds if(y > 0 && value(x,y-1) != 0) sum.push(value(x, y-1)); if(x > 0 && value(x-1,y) != 0) sum.push(value(x-1, y)); if(y < length - 1 && value(x,y+1) != 0) sum.push(value(x, y+1)); if(x < length - 1 && value(x+1,y) != 0) sum.push(value(x+1, y)); } var sumOfHeight:Number = 0; for each(var v:Number in sum) sumOfHeight += v; var avg:Number = sumOfHeight / sum.length ; setValue(x,y, newHeight(avg)); } private function newHeight(avg:Number):Number{ // return avg + (Math.random()*(Math.pow(2, - 0.3*splitCnt))); return avg*(1 + (Math.random ()*2 - 1) * scale * 0.019); } public function get length():int{ return Math.pow(2, splitCnt) + 1; } public function get scale():int{ return range / Math.pow(2,splitCnt); } public function value(x:int, z:int):Number{ return buffer[x*scale][z*scale]; } private function setValue(x:int, z:int, value:Number):void{ buffer[x*scale][z*scale] = value; } }
スポンサーサイト