zoukankan      html  css  js  c++  java
  • XNA Billboard(公告板技术)

      公告板技术是3D游戏中用的非常多的一种技术,主要是用于控制场景中的Texture的方向,让他始终以一定的角度对着我们的镜头(一般是垂直于镜头)。
    如我们在3D游戏中看到的怪物的蓝、红和怪物名字、一些花草树木等,无论我们在哪个方向看它总是对着我们。
    如下图所示:

          

    GraphicsDeviceManager graphics;
    Texture2D texRedPanda;
    
    //镜头信息参数
    Vector3 pos, lookat, up;
    //World,View,Project矩阵
    Matrix world,view, project;
    BasicEffect basicEffect;
    //顶点结构
    VertexPositionTexture[] vpt;
    VertexDeclaration vertexDec;
    
    public GameMain()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
    }
    
    protected override void Initialize()
    {
        //初始化镜头信息
        pos = new Vector3(0, 0,200);
        lookat = Vector3.Zero;
        up = Vector3.Up;
    
        //初始化变换矩阵
        world = Matrix.Identity;
        bbWorld = Matrix.Identity;
        view = Matrix.CreateLookAt(pos, lookat, up);
        project = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, 800f/600f, 1, 1000);
    
        vpt = new VertexPositionTexture[6];
        GraphicsDevice.RenderState.CullMode = CullMode.None;
        base.Initialize();
    }
    
    protected override void LoadContent()
    {
    
        texRedPanda = Content.Load<Texture2D>("RedPanda");
    
        basicEffect = new BasicEffect(GraphicsDevice, null);
        vertexDec = new VertexDeclaration(GraphicsDevice, VertexPositionTexture.VertexElements);
    
        //定义三角形的各顶点坐标和纹理坐标
        vpt[0] = new VertexPositionTexture(new Vector3(-25,-25, 0), new Vector2(0, 1));
        vpt[1] = new VertexPositionTexture(new Vector3(-25, 25, 0), new Vector2(0, 0));
        vpt[2] = new VertexPositionTexture(new Vector3(25,-25, 0), new Vector2(1, 1));
        vpt[3] = new VertexPositionTexture(new Vector3(-25, 25, 0), new Vector2(0, 0));
        vpt[4] = new VertexPositionTexture(new Vector3(25, 25, 0), new Vector2(1, 0));
        vpt[5] = new VertexPositionTexture(new Vector3(25,-25, 0), new Vector2(1, 1));
    }
    
    protected override void Update(GameTime gameTime)
    {
        // Allows the game to exit
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            this.Exit();
        base.Update(gameTime);
    }
    
    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.Black);
        //设置变换矩阵参数
        basicEffect.World = world;
        basicEffect.View = view;
        basicEffect.Projection = project;
        //设置绘制纹理
        basicEffect.TextureEnabled = true;
        basicEffect.Texture = texRedPanda;
        basicEffect.Begin();
        foreach (var pass in basicEffect.CurrentTechnique.Passes)
        {
            pass.Begin();
            GraphicsDevice.VertexDeclaration = vertexDec;
            GraphicsDevice.DrawUserPrimitives<VertexPositionTexture>(PrimitiveType.TriangleList, vpt,0, 2);
            pass.End();
        }
        basicEffect.End();
        base.Draw(gameTime);
    }
    
    

           texRedPanda的位置大概是在坐标原点,为了等会便于观察,将在Update加些内容。让镜头的位置通过键盘控制绕原点旋转(这里不是用World变换)。这里是在网上找的公式:
        x1 = x0 * cosB + y0 * sinB
        y1 = -x0 * sinB + y0 * cosB
     
           x0,y0表示镜头现在的位置,y1,y2表示绕原点旋转B弧度后的坐标。
           现在我们就呆以看到没有使用公告板技术时的效果了。把下面的代码加到Update方法的里:

    float x0, z0;
    x0=pos.X;
    z0=pos.Z;
    if (Keyboard.GetState().IsKeyDown(Keys.Left))
    {
        pos.X = x0 * (float)Math.Cos(0.1d) + z0 * (float)Math.Sin(0.1d);
        pos.Z = (-x0) * (float)Math.Sin(0.1d) + z0 * (float)Math.Cos(0.1d);
    }
    if (Keyboard.GetState().IsKeyDown(Keys.Right))
    {
        pos.X = x0 * (float)Math.Cos(-0.1d) + z0 * (float)Math.Sin(-0.1d);
        pos.Z = (-x0) * (float)Math.Sin(-0.1d) + z0 * (float)Math.Cos(-0.1d);
    }
    view = Matrix.CreateLookAt(pos, Vector3.Zero, Vector3.Up);
    
    //将视点 位置显示在标题栏
    Window.Title = pos.ToString();
    
    

           下面我们加一个用了公告板的World变换。主要代码如下,
        bbWorld = Matrix.CreateBillboard(Vector3.Zero, -pos, Vector3.Up, null);
           现在再来对比下 效果,发现无论我们控制镜头在哪个位置,小熊猫图片的下面始终对着我们。

    这里已经实现了一个初级的公告板。当然也可以不用XNA的现有方法,我们可以把代码放到HLSL里面去,这里有个实现,但我帮他是数学原理没有推算过。所以只有套着用了。

    float4x4 World;
    float4x4 View;
    float4x4 Projection;
    texture Texture;
    
    sampler textureSampler=sampler_state
    {
    	texture=<Texture>;
    	magfilter = LINEAR; 
    	minfilter = LINEAR;
    	mipfilter=LINEAR; 
    	AddressU = CLAMP; 
    	AddressV = CLAMP;
    };
    
    struct VertexShaderInput
    {
        float3 Pos:POSITION0;
    	float2 TexCoord:TEXCOORD0;
    };
    
    struct VertexShaderOutput
    {
        float4 Position : POSITION0;
    	float2 TexCoord:TEXCOORD0;
    };
    
    VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
    {
        VertexShaderOutput output;
    
        float4x4 worldViewMatrix = mul(World, View);   
    	float3 positionVS = input.Pos + float3(worldViewMatrix._41, worldViewMatrix._42, worldViewMatrix._43);
    	output.Position = mul(float4(positionVS, 1.0f), Projection);
        output.TexCoord=input.TexCoord;
    
        return output;
    }
    
    float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
    {
        return tex2D(textureSampler,input.TexCoord);
    }
    
    technique BillBoard
    {
        pass BillBoard
        {
            VertexShader = compile vs_1_0 VertexShaderFunction();
            PixelShader = compile ps_1_0 PixelShaderFunction();
        }
    }  
        
    
    

          这里就实现了比较常用的公告板技术。到底是用XNA现有方法,还是HLSL,自己视情况面定吧。

  • 相关阅读:
    vue中 key 值的作用
    v-on可以监听多个方法吗?
    vue常用的修饰符
    v-if和v-show的区别
    Vue和其他框架的区别
    Vue面试题总结——目录
    vue是一个渐进式的框架,我是这么理解的
    原生JS封装创建多级菜单函数
    如何使用mongodb(建立原型,连接数据库)
    Hive 的安装与配置
  • 原文地址:https://www.cnblogs.com/lm3515/p/1829995.html
Copyright © 2011-2022 走看看