飞船是离不了天空的,虽然上一节我们已经建好了飞船并试飞成功,但还是没有给飞船更大的背景翱翔。在一个场景中,仅有主体还是不够的,还需要有周围环境的渲染。如果我们能为飞船增加蓝天白云的高远,峰峦叠嶂的苍翠,那一定才是更贴近现实的。
在这个场景中,我们需要一个天空环境作为背景,不考虑地形地貌的特征,因此,典型的做法是实现天空盒(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轴负方向上的后面。如下图所示。
![](https://box.kancloud.cn/2016-04-08_570727fb6e816.gif)
然后,利用这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)),
//..........
~~~
在上述代码中,每个顶点的贴图坐标是参照如下图(图片来源于网络,分辨率低,仅用于示意)所示的贴图文件确定的。
![](https://box.kancloud.cn/2016-04-08_570727fb822dc.gif)
这个贴图如果折叠起来正好构成一个立方体,所以各个面上三角形的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);
}
~~~
运行程序,点击屏幕,效果如下图所示(由于贴图文件来源于网络,分辨率低,所以有些模糊,仅用来示意吧)。真是一个广袤的世界!
![](https://box.kancloud.cn/2016-04-08_570727fb995ae.gif)
——欢迎转载,请注明出处 [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开发之后记(附源码)