zoukankan      html  css  js  c++  java
  • [翻译]XNA 3.0 Game Programming Recipes之twentyseven

    PS:自己翻译的,转载请著明出处格
                                                    5-2 应用纹理到你的三角形
    问题
            你可以绘制一个不错的颜色三角形靠把一个纹理放在三角形上。
    解决方案
            你的图形卡允许你指定一个2D图象,从它可以很简单为你的三角形着色。
            这意味着您必须导入二维图像到您的XNA项目,并将其交给了显卡在渲染三角形之前。对于每一个顶点,而不是指定的颜色,你得说明哪些位置的二维图像对应到顶点。
    它是如何工作的
             开始导入2D图象到你的工程中,3-1节可以作为例子。确保你连接它到一个变量在LoadContent方法中:
    1 myTexture=content.Load<Texture2D>("texture");
             接下来,你可以定义三角形的顶点。在先前的章节中,你必须指定每个顶点的3D位置。这次,你不用定义一个颜色除了在2D材质中的位置,它与顶点一致。保存2D纹理坐标在每一个顶点可以实现这个。如果每一个三角形的顶点对应一个2D纹理坐标,你的图形卡将会添满三角形的内部用你指定的2D部分图象。
             当指定纹理坐标,你必须记住,左上角的您的纹理具有(0,0)坐标,而右上角的(1,0)坐标。这个意思是第二次坐标表明垂直位置,所以右下角有在(1,1)坐标。图5-4显示三个纹理的区域对应于不同纹理坐标。

             这个意思是你现在必须存储一个2D纹理坐标而不是在每个顶点的颜色。相反保存一个矩阵包含VertexPositionColor元素,现在你可以创建一个数组包含有VertexPositionTexture元素,其中许多顾名思义,可以存储的三维位置和纹理坐标:
     1 private void InitVertices()
     2 {
     3     vertices=new VertexPositionTexture[9];
     4     int i=0;
     5     vertices[i++]=new VertexPositionTexture(new Vector3(-10,1,-5),new Vector2(0,0));
     6     vertices[i++]=new VertexPositionTexture(new Vector3(-7,7,-5),new Vector2(0.5f,1));
     7     vertices[i++]=new VertexPositionTexture(new Vector3(-4,1,-5),new Vector2(1,0));
     8 
     9     vertices[i++]=new VertexPositionTexture(new Vector3(-3,1,-5),new Vector2(0,0.5f));
    10     vertices[i++]=new VertexPositionTexture(new Vector3(0,5,-5),new Vector2(1,0));
    11     vertices[i++]=new VertexPositionTexture(new Vector3(-10,1,-5),new Vector2(1,1));
    12 
    13     vertices[i++]=new VertexPositionTexture(new Vector3(4,1,-5),new Vector2(0.25f,0.5f));
    14     vertices[i++]=new VertexPositionTexture(new Vector3(7,5,-5),new Vector2(0.5f,0));
    15     vertices[i++]=new VertexPositionTexture(new Vector3(10,1,-5),new Vector2(1,1));
    16     myVertexDeclaration=new VertexDeclaration(device,VertexPositionTexture.VertexElements);
    17 }
               这里你定义的这九个顶点有纹理坐标对应于三个三角形如图5-4所示。指定这些纹理坐标,指定这个三角形将会有相同的颜色作为三角形如图5-4。
    注意:重要的是记住,三角形在3D空间的实际位置是被Vector3定义。例如,图5-4的第一三角形将会被颠倒绘制在你的3D世界,因为两个顶点都有1作为Y坐标,中间的顶点有5作为Y纹理坐标。这将造成XNA一词在纹理的中间被颠倒绘制。
                你应该需要通知你的图形卡你的顶点现在包含一个纹理坐标而不是一个颜色。因此,你应该创建一个VertexDeclaration基于VertexPosition纹理的VertexElements中,在你绘制三角形之前传递到图形卡中。
                随着你的顶点被定义,您就可以使这三个三角形到屏幕使用一个小变量的代码在以前的章节中:
     1 device.RenderState.CullMode=CullMode.None;
     2 basicEffect.World=Matrix.Identity;
     3 basicEffect.View=fpsCam.ViewMatrix;
     4 basicEffect.Projection=fpsCam.ProjectionMatrix;
     5 basicEffect.Texture=myTexture;
     6 basicEffect.TextureEnable=true;
     7 basicEffect.Begin();
     8 foreach(EffectPass pass in basicEffect.CurrentTechnique.Passes)
     9 {
    10      pass.Begin();
    11      device.VertexDeclaration=myVertexDeclaration;
    12      device.DrawUserPrimitives<VertexPositionTexture>(PrimitiveType.TriangleList,vertices,0,3);
    13      pass.End();
    14 }
    15 basicEffect.End();
               你需要传递你的纹理到图形卡,设置纹理作为BasicEfect的积极的纹理,这个被实现。接下来,而不是使用颜色定义内部的顶点如前面章节所做的,你指定这个BasicEffect应该从纹理中取颜色的样品,设置TextureEnable为true.直到你使用一个不同的顶点格式,你需要传递新VertexDeclaration到图形卡中。
               最后,你造成你的图形卡去绘制三个粗糙的三角形。
    Texture Addressing Modes
               如前所述,(0,0)纹理坐标对应于左上角像素的纹理, 而(1,1)纹理坐标对应右下角的像素。
               这并不意味着您必须使用纹理坐标在[0,1]范围内。例如,这是完全正确指定(1.5f ,-0.5f)作为纹理坐标。在这种情况下,您只是让XNA知道如何处理这些坐标靠设定U和V纹理处理方式(如U是第一纹理协调和V是第二个) 。以下代码定义了一个三角形有U和V坐标以外的[0,1]区域:
    1 private void InitVertices()
    2 {
    3     vertices=new VertexPositionTexture[3];
    4     int i=0;
    5     vertices[i++]=new VertexPositionTexture(new Vector3(-3,-3,-1),new Vector2(-0.5f,1.5f));
    6     vertices[i++]=new VertexPositionTexture(new Vector3(0,5,-1),new Vector2(0.5f,-1.5f));
    7     vertices[i++]=new VertexPositionTexture(new Vector3(3,-3,-1),new Vector2(1.5f,1.5f));
    8     myVertexDeclaration=new VertexDeclaration(device,VertexPositionTexture.VertexElements);
    9 }
               接下来,您需要指示XNA应如何处理这些坐标,设定处理模式的纹理采样器中在图形卡里,被用来从纹理中取色。
    TextureAddressMode.Clamp
               用这段代码去设置U和V的地址模式到Clamp:
    1 device.SamplerStates[0].AddressU=TextureAddressMode.Clamp;
    2 device.SamplerStates[0].AddressV=TextureAddressMode.Clamp;
               这种处理方式会造成所有纹理坐标被钳制在[0,1]区域中。所有坐标小于0将钳位为0 ,而所有坐标大于1将钳制到1 。
               因此,所有三角形的像素有一个纹理坐标在[0,1]以外地区,将得到像素的颜色边缘的纹理,图5-5的左边 。 三角图中显示图象里对应的三角形具有纹理坐标为早些时候界定。
               这是你的图形卡如何第一次映射纹理坐标,在从图象中取样之前:
               (-0.5f,1.5f)->(0,1)
               (0.5f,-1.5f)->(0.5f,0)
               (1.5f,1.5f)->(1,1)


    TextureAddressMode.Wrap
               尽管这是默认的纹理寻址模式,在使用不同的一个,您可以重新包装使用此代码:

    1 device.SamplerStates[0].AddressU=TextureAddressMode.Wrap;
    2 device.SamplerStates[0].AddressV=TextureAddressMode.wrap;

               使用这个地址模式,图形卡将保留添加或减去1从坐标直到它在[0,1]区域内。
               Graphically,这将导致原始纹理被复制,如图5-5右部分所示。
               这里是一些纹理坐标映射的实例:
               (-0.5f,1.5f)->(0.5f,0.5f)
               (1.2f,-0.2f)->(0.2f,0.8f)
               (-0.7f,-1.2f)->(0.3f,0.8f)
    TextureAddressMode.Mirror

               使用这段代码去设置纹理地址模式到Mirror:
    1 device.SamplerStates[0].AddressU=TextureAddressMode.Mirror;
    2 device.SamplerStates[0].AddressV=TextureAddressMode.Mirror;
               这个地址模式将导致初始化纹理被复制。尽管,不象wrapping模式,副本被映射到邻近的一侧和初始纹理。因此,上面和下面的副本的原始纹理被垂直的镜像,而副本左翼和右翼的原始纹理被水平镜像。对角线副本镜像沿着两旁,导致原来的纹理旋转超过180度,显示的左边的图5-6 。
               这个模式是非常有用的,因为它允许你扩大你的纹理不用引入图形边缘,作为Wrap模型:
               这里有一些坐标映射:
               (-0.5f,1.5f)->(0.5f,0.5f)
               (0.5f,-1.5f)->(0.5f,0.5f)
               (1.2f,1.7f)->(0.8f,0.3f)

    TextureAddressMode.MirrorOnce
               另外,你可以选择指定MirrorOnce地址模式:
    1 device.SamplerStates[0].AddressU=TextureAddressMode.MirrorOnce;
    2 device.SamplerStates[0].AddressV=TextureAddressMode.MirrorOnce;
               这种模式反映了纹理坐标在[-1,1]区域成为[0,1]区域, 虽然所有坐标在[-1,1]区域以外,被钳位为-1(值小于-1)或1 (值大于1)所示,图5-6的右边所示 。
               以下是取色器坐标映射:
               (-0.5f,1.5f)->(0.5f,1f)
               (0.5f,-1.5f)->(0.5f,-1f)
               (1.2f,1.7f)->(1,1)

    TextureAddressMode.Border
               你同样也可以定义,你想要所有的象素有一个纹理坐标在[0,1]外面的区域,分配一个你指定的颜色。这个颜色被BorderColor调用,用下面的代码可以设置SamplerState:
    1 device.SamplerStates[0].BorderColor=Color.LightSeaGreen;
    2 device.SamplerStates[0].AddressU=TextureAddressMode.Border;
    3 device.SamplerStates[0].AddressV=TextureAddressMode.Border;
               这种模式是非常有用的当调试时,因为它清楚地表明所有纹理坐标以外的[0,1]区域。
               没有纹理映射被执行;所有的像素纹理坐标在[0,1]区域以外,用BorderColor来绘制。
    注意:Xbox360控制台只能用白色作为边框颜色。
    代码
               首先你需要定义你的顶点。知道他们需要包含他们在3D空间里位置,和他们在文理中相应位置,你想使用VertexPositionTexture元素。不要忘记去初始化相应的VertexDeclaration
     1 private void InitVertices()
     2 {
     3     vertices=new VertexPositionTexture[3];
     4     int i=0;
     5     vertices[i++]=new VertexPositionTexture(new Vector3(-3,-3,-1),new Vector2(-0.5f,1.5f));
     6     vertices[i++]=new VertexPositionTexture(new Vector3(0,5,-1),new Vector2(0.5f,-1.5f));
     7     vertices[i++]=new VertexPositionTexture(new Vector3(3,-3,-1),new Vector2(1.5f,1.5f));
     8     myVertexDeclaration=new VertexDeclaration(device,VertexPositionTexture.VertexElements);
     9 }
    10 //一旦你使你的顶点保存在一个数组中,一确定的VertexDeclaration,你设置一个纹理地址模式和绘制你的三角形:
    11 protected override void Draw(GameTime gameTime)
    12 {
    13     device.Clear(ClearOptions.Target|ClearOptions.DepthBuffer,Color.CornflowerBlue,1,0);
    14     //draw triangles
    15     device.RenderState.CullMode=CullMode.None;
    16     basicEffect.World=Matrix.Identity;
    17     basicEffect.View=fpsCam.ViewMatrix;
    18     basicEffect.Projection=fpsCam.ProjectionMatrix;
    19     basicEffect.Texture=myTexture;
    20     basicEffect.TextureEnable=true;
    21     device.SamplerStates[0].AddressU=TextureAddressMode.Mirror;
    22     device.SamplerStates[0].AddressV=TextureAddressMode.Mirror;
    23     basicEffect.Begin();
    24     foreach(EffectPass pass in basicEffect.CurrentTechnique.Passes)
    25     {
    26        pass.Begin();
    27        device.VertexDeclaration=myVertexDeclaration;
    28        device.DrawUserPrimitives<VertexPositionTexture>(PrimitiveType.TriangleList,vertices,0,3);
    29        pass.End();
    30     }
    31     basicEffect.End();
    32     base.Draw(gameTime);
    33 }
  • 相关阅读:
    LeetCode 150:逆波兰表达式求值 Evaluate Reverse Polish Notation
    LeetCode 20:有效的括号 Valid Parentheses
    LeetCode 155:最小栈 Min Stack
    rsync & sersync 实时同步
    rsync & inotify-tools 实时同步
    rsync 应用总结
    Linux 变量详解
    特殊权限
    Linux 三剑客之sed命令总结
    expect 分发ssh key脚本
  • 原文地址:https://www.cnblogs.com/315358525/p/1537396.html
Copyright © 2011-2022 走看看