现在的位置: 首页 > 综合 > 正文

在Windows Phone中进行3D开发之十一天空

2013年08月09日 ⁄ 综合 ⁄ 共 3949字 ⁄ 字号 评论关闭

        飞船是离不了天空的,虽然上一节我们已经建好了飞船并试飞成功,但还是没有给飞船更大的背景翱翔。在一个场景中,仅有主体还是不够的,还需要有周围环境的渲染。如果我们能为飞船增加蓝天白云的高远,峰峦叠嶂的苍翠,那一定才是更贴近现实的。

        在这个场景中,我们需要一个天空环境作为背景,不考虑地形地貌的特征,因此,典型的做法是实现天空盒(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 ——

 

抱歉!评论已关闭.