XNA中的HLSL简单应用

以前一直没搞明白HLSL,最近两天苦下功夫,终于算是学到了HLSL入门了。

这里我将通过对一个矩形模型以BassicEffect贴图和通过HLSL贴图作对比,从而掌握在XNA中使用.fx效果文件,和初步了解HLSL。

下面先分析一下没有使用贴图时的代码:

 

  1    public class Game1 : Game
  2    {
  3        GraphicsDeviceManager graphics;
  4        SpriteBatch spriteBatch;
  5
  6        //投影矩阵 
  7        Matrix projection;
  8        //观察矩阵 
  9        Matrix view;
 10        //矩形的世界矩阵 
 11        Matrix world;
 12        //矩形模型 
 13        Model cub;
 14
 15        //定义贴图纹理和效果(先声明,暂时不使用) 
 16
 17        Texture2D text;
 18        Effect effe;
 19
 20        //是否在暂停状态 
 21        bool isPause = false;
 22
 23        KeyboardState preks = Keyboard.GetState();
 24
 25        public Game1()
 26        {
 27            graphics = new GraphicsDeviceManager(this);
 28            Content.RootDirectory = "Content";
 29        }

 30
 31        protected override void Initialize()
 32        {
 33            //初始化投影矩阵 
 34            projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio, 1f, 100000f);
 35
 36            //初始化观察矩阵 
 37            view = Matrix.CreateLookAt(Vector3.Forward * 500, Vector3.Zero, Vector3.Up);
 38
 39            //初始化矩形的世界矩阵 
 40            world = Matrix.Identity;
 41
 42            base.Initialize();
 43        }

 44
 45        protected override void LoadContent()
 46        {
 47            // Create a new SpriteBatch, which can be used to draw textures. 
 48            spriteBatch = new SpriteBatch(GraphicsDevice);
 49
 50
 51            //载入矩形模型 
 52            cub = Content.Load<Model>("cub");
 53
 54            //载入贴图纹理(暂时不使用) 
 55            text = Content.Load<Texture2D>("rocks");
 56
 57            //载入效果(暂时不使用) 
 58            effe = Content.Load<Effect>("effe");
 59
 60            //设置效果的Technique 
 61            effe.CurrentTechnique = effe.Techniques["Technique1"];
 62
 63        }

 64
 65        protected override void Update(GameTime gameTime)
 66        {
 67
 68            //当前按键状态 
 69            KeyboardState ks = Keyboard.GetState();
 70
 71            //按S镜头拉远,W镜头拉近 
 72            if (ks.IsKeyDown(Keys.S))
 73            {
 74                view *= Matrix.CreateTranslation(-10 * Vector3.UnitZ);
 75            }

 76
 77            if (ks.IsKeyDown(Keys.W))
 78            {
 79                view *= Matrix.CreateTranslation(10 * Vector3.UnitZ);
 80
 81            }

 82
 83            //通过空格键控制是否暂停 
 84            if (ks.IsKeyDown(Keys.Space) && preks.IsKeyUp(Keys.Space))
 85            {
 86                if (isPause)
 87                {
 88                    isPause = false;
 89                }

 90                else
 91                {
 92                    isPause = true;
 93                }

 94            }

 95
 96            //控制FillMode 
 97            if (ks.IsKeyDown(Keys.A) && preks.IsKeyUp(Keys.A))
 98            {
 99                GraphicsDevice.RenderState.FillMode = FillMode.WireFrame;
100            }

101
102            if (ks.IsKeyDown(Keys.Q) && preks.IsKeyUp(Keys.Q))
103            {
104                GraphicsDevice.RenderState.FillMode = FillMode.Solid;
105            }

106
107            preks = ks;
108
109            //如果不是暂停状态,自动旋转矩形的世界矩阵,实现旋转效果 
110            if (!isPause)
111            {
112                world *= Matrix.CreateFromAxisAngle(new Vector3(11-1), gameTime.ElapsedGameTime.Ticks * 0.0000001f);
113            }

114            base.Update(gameTime);
115        }

116
117        protected override void Draw(GameTime gameTime)
118        {
119            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
120
121            foreach (ModelMesh mesh in cub.Meshes)
122            {
123                foreach (BasicEffect effect in mesh.Effects)
124                {
125                    effect.World = world;
126                    effect.View = view;
127                    effect.Projection = projection;
128                    effect.EnableDefaultLighting();
129                }

130                mesh.Draw();
131            }

132            base.Draw(gameTime);
133        }

134    }
 

 

可以看到程序的高度效果如下:

现在我们为例子加入贴图(即前面声名的Texture),因为是使用的Basiceffect类的方法,所以很简单,只需要在foreach (BasicEffect effect in mesh.Effects)的循环体中插入以下代码,

 

 

effect.TextureEnabled = true
effect.Texture 
= text; 

 

再来看一下效果:

上面就是XNA中最简单的纹理贴图的方法,下面就将进入主要的部分——HLSL渲染。

首先看一段很经典的HLSL代码:

 

 1//声明一个4x4的矩阵。传入的参数是世界、观察、投影矩阵的积 
 2Float4x4 mWorldViewProjection; 
 3
 4//定义一个VertexShader函数,作为入口,并返回值的语义为POSITION 
 5float4 vs_main(float4 position:POSITION):POSITION 
 6
 7
 8    //将传入的坐标顶点与世界观察投影矩阵相乘,一交完成三个顶点的交换 
 9     return mul(position,mWorldViewProjection); 
10}
 
11
12//定义一个PixelShader函数,作为入口,并定义返回语义为COLOR0 
13Float4 ps_main():COLOR0 
14
15    //固定返回白色作为显示颜色 
16     Return float4(1,1,1,1); 
17}
 
18
19//开始定义Technique 
20technique technique1 
21
22    //一个pass 
23     pass pass0 
24     
25        //将VertexShader的版本设置为1.1,并将执行函数设置为vs_main 
26        VertexShader=compile vs_1_1 vs_main(); 
27        //将PixelShader的版本设置为1.1,并将执行函数设置为ps_main 
28        PixelShader=compile ps_1_1 ps_main(); 
29}
 
30
31}
 
32
33

  

这段代码中包含了一个全局变量,两个全局函数。这两个全局函数分别用于VertexShader和PixelShader,也直接作为VertexShader和PixelShader的入口函数。而全局变量则用在了VertexShader的计算中。代码中定义了一个technique并且包含了一个pass,在这个pass中VertexShader和PixelShader的版本都是1.1。

使用这段代码去渲染任何一个模型,得到的都是一个白色的物体。

在XNA中使用HLSL的代码如下:

 

 1        protected override void Draw(GameTime gameTime)
 2        {
 3            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
 4
 5            //设置HLSL参数 
 6            effe.Parameters["mWorldViewProjection"].SetValue(world * view * projection);
 7            effe.Begin();
 8            foreach (EffectPass pass in effe.CurrentTechnique.Passes)
 9            {
10                pass.Begin();
11                foreach (ModelMesh mesh in cub.Meshes)
12                {
13                    foreach (ModelMeshPart part in mesh.MeshParts)
14                    {
15                        GraphicsDevice.VertexDeclaration = part.VertexDeclaration;
16                        GraphicsDevice.Indices = mesh.IndexBuffer;
17                        GraphicsDevice.Vertices[0].SetSource(mesh.VertexBuffer, part.StartIndex, part.VertexStride);
18                        GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, part.BaseVertex, 0, part.NumVertices, part.StartIndex, part.PrimitiveCount);
19                    }

20                }

21                pass.End();
22            }

23            effe.End();
24
25            base.Draw(gameTime);
26        }

 

效果如下图:

让我们再近一步,用HLSL为我们的贴上纹理。

 

修改Draw方法如下:

 

 1        protected override void Draw(GameTime gameTime)
 2        {
 3            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
 4            
 5            effe.Parameters["World"].SetValue(world);
 6            effe.Parameters["View"].SetValue(view);
 7            effe.Parameters["Projection"].SetValue(projection);
 8            
 9            //下面的参数text类型为Texture 
10            effe.Parameters["diffuseTexture"].SetValue(text);
11
12            effe.Begin();
13            foreach (EffectPass pass in effe.CurrentTechnique.Passes)
14            {
15                pass.Begin();
16                foreach (ModelMesh mesh in cub.Meshes)
17                {
18                    foreach (ModelMeshPart part in mesh.MeshParts)
19                    {
20                        GraphicsDevice.VertexDeclaration = part.VertexDeclaration;
21                        GraphicsDevice.Indices = mesh.IndexBuffer;
22                        GraphicsDevice.Vertices[0].SetSource(mesh.VertexBuffer, part.StartIndex, part.VertexStride);
23                        GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, part.BaseVertex, 0, part.NumVertices, part.StartIndex, part.PrimitiveCount);
24                    }

25                }

26                pass.End();
27            }

28            effe.End();
29
30            base.Draw(gameTime);
31        }
 

 

HLSL代码如下:

 

 1float4x4 World; 
 2float4x4 View; 
 3float4x4 Projection; 
 4texture diffuseTexture:Diffuse; 
 5sampler DiffuseTextureSampler = sampler_state 
 6
 7    Texture = <diffuseTexture>
 8    MinFilter=linear; 
 9    MagFilter=linear; 
10    MipFilter=linear; 
11}

12
13struct VertexShaderInput 
14
15    float4 Position : POSITION0; 
16    float3 normal:NORMAL; 
17    float2 uv:TEXCOORD0; 
18}

19
20struct VertexShaderOutput 
21
22    float4 Position : POSITION0; 
23    float2 uv:TEXCOORD0; 
24}

25
26VertexShaderOutput VertexShaderFunction(VertexShaderInput input) 
27
28    VertexShaderOutput output; 
29
30    float4 worldPosition = mul(input.Position, World); 
31    float4 viewPosition = mul(worldPosition, View); 
32    output.Position = mul(viewPosition, Projection); 
33    output.uv=input.uv; 
34
35    return output; 
36}
 
37
38float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 
39
40    return tex2D(DiffuseTextureSampler,input.uv); 
41}
 
42
43technique Technique1 
44
45    pass Pass1 
46    
47        VertexShader = compile vs_1_1 VertexShaderFunction(); 
48        PixelShader = compile ps_1_1 PixelShaderFunction(); 
49    }
 
50}
         
51
52

 

渲染效果如下图所示:

就此,我也算对HLSL有了更近步的了解,以后在做的就是多多分析高手写好的HSLS代码。

posted @ 2008-08-31 02:11  齐.net  阅读(2805)  评论(3编辑  收藏