您的位置:首页 > 其它

Windows Phone 7 3D开发中使用纹理贴图

2011-03-14 23:47 459 查看
Windows Phone 7对3D的支持还是不错的,据说是用OpenGL/ES做的,使用起来倒是也有点那种感觉。另外,写本文的另一个原因是我的第一个3D试验竟然遇到了问题,花了1个小时才搞定,所以也一并记录下来,供遇到和我同样的问题的朋友参考。
本文就不讲XNA 4.0的游戏框架了,直接上一段代码,该代码使用VertexPositionColor渲染了一个三角形,程序运行一切正常。
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;

namespace WindowsPhoneGame1
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Texture2D image;
        VertexPositionColor[] trangle;
        VertexBuffer vertexBuffer;
        BasicEffect basicEffect;
        Camera camera;
        Matrix world = Matrix.Identity;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.IsFullScreen = true;
            Content.RootDirectory = "Content";
            camera = new Camera(this, new Vector3(0, 0, 5), Vector3.Zero, new Vector3(0, 1, 0));

            // Frame rate is 30 fps by default for Windows Phone.
            TargetElapsedTime = TimeSpan.FromTicks(333333);
        }

        protected override void Initialize()
        {
            base.Initialize();
        }

        protected override void LoadContent()
        {
             spriteBatch = new SpriteBatch(GraphicsDevice);

            image = Content.Load<Texture2D>(@"Images/Tulips");
            trangle = new VertexPositionColor[]{
                new VertexPositionColor(new Vector3(0, 1, 0), Color.Red),
                new VertexPositionColor(new Vector3(1, -1, 0), Color.Green),
                new VertexPositionColor(new Vector3(-1,-1, 0), Color.Blue)
            };
            vertexBuffer = new VertexBuffer(graphics.GraphicsDevice, typeof(VertexPositionColor), 3, BufferUsage.None);
            vertexBuffer.SetData<VertexPositionColor>(trangle);

            basicEffect = new BasicEffect(GraphicsDevice);

            GraphicsDevice.SetVertexBuffer(vertexBuffer);
        }

        protected override void UnloadContent()
        {
        }

        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            basicEffect.World = world;
            basicEffect.View = camera.view;
            basicEffect.Projection = camera.projection;
            basicEffect.VertexColorEnabled = true;

            foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
            {
                pass.Apply();
                GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleStrip, trangle, 0, 1);
            }
            base.Draw(gameTime);
        }
    }
}

运行结果如下:



在确认了3D开发的这种代码结构以后,用VertexPositionTexture渲染同样的三角形,只是这次采用纹理贴图,代码如下:
VertexPositionTexture[] trangleTexture;

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            image = Content.Load<Texture2D>(@"Images/Tulips");
            trangleTexture = new VertexPositionTexture[]{
                new VertexPositionTexture(new Vector3(0, 1, 0),new Vector2(0.5f,0) ),
                new VertexPositionTexture(new Vector3(1, -1, 0),new Vector2(1,1f) ),
                new VertexPositionTexture(new Vector3(-1,-1, 0),new Vector2(0,1f) )
            };

            vertexBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionTexture), trangleTexture.Length, BufferUsage.None);
            vertexBuffer.SetData<VertexPositionTexture>(trangleTexture);

            basicEffect = new BasicEffect(GraphicsDevice);

            GraphicsDevice.SetVertexBuffer(vertexBuffer);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            basicEffect.World = world;
            basicEffect.View = camera.view;
            basicEffect.Projection = camera.projection;
            basicEffect.Texture = image;
            basicEffect.TextureEnabled = true;

            foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
            {
                pass.Apply();
                GraphicsDevice.DrawUserPrimitives<VertexPositionTexture>(PrimitiveType.TriangleStrip, trangleTexture, 0, 1);
            }
            base.Draw(gameTime);
        }

啰嗦一句,在此代码中VertexPositionTexture的第二个Vetex2代表的是UV坐标,对应的含义是(0,0)点对应了纹理图片的左上角,(1,1)点对应了纹理图片的右下角。
上述代码在运行的时候会在VS2010的输出窗口中显示:
A first chance exception of type 'System.NotSupportedException' occurred in Microsoft.Xna.Framework.Graphics.dll
A first chance exception of type 'System.Threading.ThreadAbortException' occurred in Microsoft.Xna.Framework.dll
同时模拟器里的程序直接退出,看不到结果。原因是什么呢?疑惑并仔细检视代码中……
与前一个彩色三角形对比,顶点顺序没变,摄像机位置没变,投影矩阵没变,按说是不可能出现这种问题的,而且程序直接崩了,没有信息抛出,真是很郁闷。
经过不断的试错,在宣布放弃之前,忽然想起来关于纹理方面的一个注意事项。有过3D开发经验的朋友都知道,纹理是要求符合2的整数次方对齐的,而我所加载的来自于外部任意图片的纹理不符合这一要求,所以程序挂了。
又查了一些资料,找到了准确的原因。原来是Windows Phone 7 的XNA中默认的纹理寻址模式使用了Wrap,造成了与GPU的不兼容,如果改成Clamp就好了。
看来在这个地方微软得要有文档说明才好,否则还真是难找问题所在。修改后的代码如下:
protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            image = Content.Load<Texture2D>(@"Images/Tulips");

            trangleTexture = new VertexPositionTexture[]{
                new VertexPositionTexture(new Vector3(0, 1, 0),new Vector2(0.5f,0) ),
                new VertexPositionTexture(new Vector3(1, -1, 0),new Vector2(1,1f) ),
                new VertexPositionTexture(new Vector3(-1,-1, 0),new Vector2(0,1f) )
            };

            vertexBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionTexture), trangleTexture.Length, BufferUsage.None);
            vertexBuffer.SetData<VertexPositionTexture>(trangleTexture);

            basicEffect = new BasicEffect(GraphicsDevice);

            GraphicsDevice.SetVertexBuffer(vertexBuffer);
            GraphicsDevice.SamplerStates[0] = SamplerState.PointClamp;
        }

最终的模拟器结果是:



不管怎么说,Windows Phone 7的XNA游戏开发框架以及3D方面的开发接口还是很出色的,顶一下微软,并希望这个平台能尽快发展起来。
附Camera的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace WindowsPhoneGame1
{
    public class Camera : Microsoft.Xna.Framework.GameComponent
    {
        public Matrix view{get;protected set;}
        public Matrix projection { get; protected set; }

        public Camera(Game game,Vector3 pos,Vector3 target,Vector3 up)
            : base(game)
        {
            view = Matrix.CreateLookAt(pos, target, up);
            projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, (float)game.Window.ClientBounds.Width / (float)game.Window.ClientBounds.Height, 1, 100);
        }

        public override void Initialize()
        {
            base.Initialize();
        }

        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
        }
    }
}


——欢迎转载,请注明出处 http://blog.csdn.net/caowenbin ——
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: