飛船是離不了天空的,雖然上一節我們已經建好了飛船并試飛成功,但還是沒有給飛船更大的背景翱翔。在一個場景中,僅有主體還是不夠的,還需要有周圍環境的渲染。如果我們能為飛船增加藍天白云的高遠,峰巒疊嶂的蒼翠,那一定才是更貼近現實的。
在這個場景中,我們需要一個天空環境作為背景,不考慮地形地貌的特征,因此,典型的做法是實現天空盒(sky-box)。天空盒就是做一個大的立方體,為立方體內部的六個面貼上連續的天空和大地的紋理,將飛船置入這個立方體內部,這樣從飛船的角度看出去,周圍就被天空和大地所包圍。
下面,我們就來構造一個這樣的天空盒出來。
還是先定義一個SkyBox類,繼承自DrawableGameCompenent。
既然要使用貼圖和光線,那么就為類添加一個成員變量box,用于定義立方體的各個頂點:
VertexPositionNormalTexture[] box;
在Initialize()中以原點為中心,邊長為2個坐標單位構造box數據,雖然有12個三角形,但這些三角形都會用到立方體的8個頂點,因此,可以先定義好頂點的坐標。?
~~~
Vector3 topLeftFront=new Vector3(-1,1,1);
Vector3 topRightFront = new Vector3(1, 1, 1);
Vector3 bottomLeftFront = new Vector3(-1, -1, 1);
Vector3 bottomRightFront = new Vector3(1, -1, 1);
Vector3 topLeftBack = new Vector3(-1, 1, -1);
Vector3 topRightBack = new Vector3(1, 1, -1);
Vector3 bottomLeftBack = new Vector3(-1, -1, -1);
Vector3 bottomRightBack = new Vector3(1, -1, -1);
~~~
在這段代碼中,從變量名字上可以看出,這8個坐標分別是立方體z軸正方向和z軸負方向兩個面的頂點。以Front為后綴的變量代表z軸正方向上的前面,以Back為后綴的變量代表z軸負方向上的后面。如下圖所示。

然后,利用這8個坐標構造立方體各個面的三角形,每個面由兩個三角形拼接而成。?
~~~
box = new VertexPositionNormalTexture[]{
new VertexPositionNormalTexture(topLeftFront,new Vector3(0,0,-1),new Vector2(0.33f,0.25f)), //front
new VertexPositionNormalTexture(topRightFront,new Vector3(0,0,-1),new Vector2(0.66f,0.25f)),
new VertexPositionNormalTexture(bottomLeftFront,new Vector3(0,0,-1),new Vector2(0.33f,0.5f)),
new VertexPositionNormalTexture(bottomLeftFront,new Vector3(0,0,-1),new Vector2(0.33f,0.5f)),
new VertexPositionNormalTexture(topRightFront,new Vector3(0,0,-1),new Vector2(0.66f,0.25f)),
new VertexPositionNormalTexture(bottomRightFront,new Vector3(0,0,-1),new Vector2(0.66f,0.5f)),
new VertexPositionNormalTexture(bottomRightFront,new Vector3(0,0,-1),new Vector2(0.66f,0.5f)), //bottom
new VertexPositionNormalTexture(bottomRightBack,new Vector3(0,0,-1),new Vector2(0.66f,0.75f)),
new VertexPositionNormalTexture(bottomLeftBack,new Vector3(0,0,-1),new Vector2(0.33f,0.75f)),
new VertexPositionNormalTexture(bottomLeftBack,new Vector3(0,0,-1),new Vector2(0.33f,0.75f)),
new VertexPositionNormalTexture(bottomLeftFront,new Vector3(0,0,-1),new Vector2(0.33f,0.5f)),
new VertexPositionNormalTexture(bottomRightFront,new Vector3(0,0,-1),new Vector2(0.66f,0.5f)),
//..........
~~~
在上述代碼中,每個頂點的貼圖坐標是參照如下圖(圖片來源于網絡,分辨率低,僅用于示意)所示的貼圖文件確定的。

這個貼圖如果折疊起來正好構成一個立方體,所以各個面上三角形的UV坐標照此圖進行確定即可。
坐標準備好以后,在Draw()方法中進行繪制。?
~~~
basicEffect.TextureEnabled = true;
basicEffect.Texture = texture;
basicEffect.World = worldMatrix;
basicEffect.View = viewMatrix;
basicEffect.Projection = projectionMatrix;
foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
{
pass.Apply();
Game.GraphicsDevice.DrawUserPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList, box, 0, box.Length/3);
}
base.Draw(gameTime);
~~~
在這段代碼中,texture是Texture2D的實例變量,在Initialize()方法中從Context加載了貼圖文件。
basicEffect是BasicEffect的實例變量,用于設置渲染效果選項。
worldMatrix、viewMatrix、projectionMatrix是三個變換矩陣,像上一節Ship類的封裝一樣用于確定變換坐標,定義如下:?
~~~
public Matrix worldMatrix {set;get;}
public Matrix viewMatrix { set; get; }
public Matrix projectionMatrix { set; get; }
~~~
到這里,SkyBox類就封裝好了,我們在MainScene中對其進行一下測試,看看是否符合我們的預期。
在MainScene中加入SkyBox對象skyBox,并將其加入到Components中。?
~~~
skyBox = new SkyBox(this);
Components.Add(skyBox);
~~~
創建一個位于原點并指向z軸負方向的攝像機,并將skyBox的視圖矩陣和投影矩陣設置為攝像機的參數:?
~~~
camera = new Camera(this, new Vector3(100,100,100), new Vector3(0, 0, -1), Vector3.Up, MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio, 0.1f, 500);
skyBox.projectionMatrix = camera.projection;
skyBox.viewMatrix = Matrix.CreateWorld(new Vector3(0,0,0),new Vector3(0,0,-1),Vector3.Up);
~~~
最后,為了能看到效果,給天空盒一個旋轉變換,在Update()中加入如下代碼:?
~~~
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
TouchPanel.EnabledGestures = GestureType.Tap;
if (TouchPanel.IsGestureAvailable)
{
GestureSample gestureSample = TouchPanel.ReadGesture();
if (gestureSample.GestureType == GestureType.Tap)
{
skyBox.worldMatrix *= Matrix.CreateRotationY(MathHelper.ToRadians(5)); ;
}
}
base.Update(gameTime);
}
~~~
運行程序,點擊屏幕,效果如下圖所示(由于貼圖文件來源于網絡,分辨率低,所以有些模糊,僅用來示意吧)。真是一個廣袤的世界!

——歡迎轉載,請注明出處 [http://blog.csdn.net/caowenbin](http://blog.csdn.net/caowenbin) ——
- 前言
- Windows Phone 7開發環境初體驗
- Windows Phone 7 3D開發中使用紋理貼圖
- 在Windows Phone中進行3D開發之一坐標系
- 在Windows Phone中進行3D開發之二攝像機
- 在Windows Phone中進行3D開發之三空間
- 在Windows Phone中進行3D開發之四三角形
- 在Windows Phone中進行3D開發之五平移縮放
- 在Windows Phone中進行3D開發之六旋轉
- 在Windows Phone中進行3D開發之七紋理
- 在Windows Phone中進行3D開發之八光照
- 在Windows Phone中進行3D開發之九模型
- 在Windows Phone中進行3D開發之十組件
- 在Windows Phone中進行3D開發之十一天空
- 在Windows Phone中進行3D開發之十二飛行
- 在Windows Phone中進行3D開發之十三陽光
- 在Windows Phone中進行3D開發之后記(附源碼)