1. 程式人生 > >如何開發優秀的HTML5遊戲?-迪斯尼《尋找奧茲之路》遊戲技術詳解(二)

如何開發優秀的HTML5遊戲?-迪斯尼《尋找奧茲之路》遊戲技術詳解(二)

        (接上文)桌面遊戲通常創建於一個核心的物理引擎。因此,要在3D世界中模擬一個柔軟的物體,需要一個完整的物理模擬器,並且建立一種可信的行為。

        WebGL和JavaScript還不能奢華到可以執行一個完全成熟的物理模擬器。因此,在這個遊戲中我們必須找到一種方式來建立風的效果。

        我們在3D模型中為每一個物件嵌入“風敏度”的資訊。3D模型的每個頂點有一個“風屬性”,指定頂點應該要受到風速多大程度的影響。所以,這指定了3D物體的風敏度。然後,我們需要建立“風”本身。

        我們通過建立包含Perlin噪聲的影象來實現。此圖片意在覆蓋一塊確定區域的風。所以,一個考慮它的好方法是,想象3D場景中一個特定矩形區域中像噪音一樣覆蓋一個畫面的雲。這幅圖片每個畫素的灰度值指定在一個特定的時刻3D區域中風力有多強。

        為了建立風的效果,影象以恆定的速度和特定的方向即風的方向移動。並且為了確保“風的區域”不會影響場景中的任何內容,我們將風的影象環繞邊界,限制於效果的區域內。

        一個風的簡單3D教程

        現在,讓我們通過Three.js在簡單的3D場景建立一個風的效果。

        我們將在一個簡單的“程式草地”中建立風。

        首先,讓我們建立場景。我們將有一個簡單的、質感平坦的地面。然後每一根草將簡單地用倒立的圓錐展現。


佈滿小草的地面

        首先我們要設定Three.js,並把它與攝像頭、滑鼠,以及一些燈光結合在一起:

constructor: ->

   @clock =  new THREE.Clock()

   @container = document.createElement( 'div' );
   document.body.appendChild( @container );

   @renderer = new THREE.WebGLRenderer();
   @renderer.setSize( window.innerWidth, window.innerHeight );
   @renderer.setClearColorHex( 0x808080, 1 )
   @container.appendChild(@renderer.domElement);

   @camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 5000 );
   @camera.position.x = 5;
   @camera.position.y = 10;
   @camera.position.z = 40;

   @controls = new THREE.OrbitControls( @camera, @renderer.domElement );
   @controls.enabled = true

   @scene = new THREE.Scene();
   @scene.add( new THREE.AmbientLight 0xFFFFFF )

   directional = new THREE.DirectionalLight 0xFFFFFF
   directional.position.set( 10,10,10)
   @scene.add( directional )

   # Demo data
   @grassTex = THREE.ImageUtils.loadTexture("textures/grass.png");
   @initGrass()
   @initTerrain()

   # Stats
   @stats = new Stats();
   @stats.domElement.style.position = 'absolute';
   @stats.domElement.style.top = '0px';
   @container.appendChild( @stats.domElement );
   window.addEventListener( 'resize', @onWindowResize, false );
   @animate()

        initGrass和initTerrain函式呼叫分別用小草和地面填充場景:

initGrass:->
   mat = new THREE.MeshPhongMaterial( { map: @grassTex } )
   NUM = 15
   for i in [0..NUM] by 1
       for j in [0..NUM] by 1
           x = ((i/NUM) - 0.5) * 50 + THREE.Math.randFloat(-1,1)
           y = ((j/NUM) - 0.5) * 50 + THREE.Math.randFloat(-1,1)
           @scene.add( @instanceGrass( x, 2.5, y, 5.0, mat ) )

instanceGrass:(x,y,z,height,mat)->
   geometry = new THREE.CylinderGeometry( 0.9, 0.0, height, 3, 5 )
   mesh = new THREE.Mesh( geometry, mat )
   mesh.position.set( x, y, z )
   return mesh

        在此我們建立了一個格子,由15*15的小草組成。我們添加了一個隨機數到每根小草的位置,讓它們不會因為排列的太整齊而有些古怪。

        此地形僅僅是一個水平面,放置在這些小草的根部(Y = 2.5)。

initTerrain:->
  @plane = new THREE.Mesh( new THREE.PlaneGeometry(60, 60, 2, 2), new THREE.MeshPhongMaterial({ map: @grassTex }))
  @plane.rotation.x = -Math.PI/2
  @scene.add( @plane )

        所以到目前為止,我們所做的只是簡單地建立了一個Three.js場景,並且添加了一些小草,由程式生成的倒立圓錐建立,以及一個簡單的地面。

        到目前為止沒有任何特別之處。

演示頁面

        你可以在這裡下載這個示例的程式碼。

        現在是新增風的時候了。第一件事,我們希望把風敏度資訊嵌入到草的3D模型中。

        我們要把此資訊以自定義屬性嵌入到小草3D模型的每個頂點中。我們將要使用的規則是:每個小草模型的底部(圓錐體的頂)具有的風敏度為0,因為它貼在地面上。小草模型(圓錐體的底部)的頂部具有最大的風敏度,因為它遠離地面。

        下面是如何重寫instanceGrass函式來為小草的3D模型新增風敏度作為自定義引數。

instanceGrass:(x,y,z,height)->

  geometry = new THREE.CylinderGeometry( 0.9, 0.0, height, 3, 5 )

  for i in [0..geometry.vertices.length-1] by 1
      v = geometry.vertices[i]
      r = (v.y / height) + 0.5
      @windMaterial.attributes.windFactor.value[i] = r * r * r

  # Create mesh
  mesh = new THREE.Mesh( geometry, @windMaterial )
  mesh.position.set( x, y, z )
  return mesh

        (待續)

        轉載請註明:來自蔣宇捷的部落格(http://blog.csdn.net/hfahe)