• XNA中的Render State管理


    XNA中的Render State管理

    仅供个人学习使用,请勿转载,勿用于任何商业用途。

    The Problem:
           XNA中一个设计的非常不好的地方,就是把各种render state定义为RenderState类的成员,而不是枚举。在DX/MDX中,如果有一系列render state需要设置,只需要
    foreach state in renderStates
        gfxDevice.SetRenderState( stateName,stateValue);

        简单,明了。
        而同样的操作在XNA中,则要麻烦很多,你不得不”显式” 访问每一个render state成员来设置相应的值:
    gfxDevice.RenderState.XXXX = value;
    gfxDevice.RenderState.XXXX = value;
    ……

          这样的代码非糟糕,简直是在”hard code”。假如事先不确定有多少render state需要设置,如何编码呢?

    The Solution:
          解决这个问题并不困难,我希望仍然使用传统的老方法来设置状态。首先,自然是定义一系列常量,表示所有渲染状态,这里使用了一个静态类,当然替换为枚举也是一样的。

    public static class HaRenderStateId
    {
        
    //alpha state
        public const byte AlphaBlendEnable = 0;
        
    public const byte AlphaBlendOperation = 1;
        
    public const byte SourceBlend = 2;
        
    public const byte DestinationBlend = 3;
        
    public const byte AlphaDestinationBlend = 4;
        
    public const byte AlphaSourceBlend = 5;
        
    public const byte AlphaFunction = 6;
        
    public const byte AlphaTestEnable = 7;
        
    public const byte BlendFactor = 8;
        
    public const byte BlendFunction = 9;
        
    public const byte SaparateAlphaBlendEnable = 10;
        
    public const byte ReferenceAlpha = 11;

        
    //depth state
        public const byte DepthWriteEnable = 12;
        .
    }

     
          接下来,需要统一所有render state的值。这样,才能把每种render state作为相同的key-value对,放到同一个容器中。观察一下所有的render state,他们的值不外乎以下几种:枚举,int,float,bool,color. 非常幸运,他们都能用一个32位的值来表示。但是具体如何编码呢?这种情况下,C++程序员首先想到的一定是使用union。C#中虽然没有内置的union类型,但这并不妨碍我们用struct模拟union的行为:

    [StructLayout(LayoutKind.Explicit)]
    public struct HaRenderStateValue
    {
        [FieldOffset(
    0)]
        
    public int IntegerValue;

        [FieldOffset(
    0)]
        
    public float FloatValue;

        [FieldOffset(
    0)]
        
    public Color Color;

        [FieldOffset(
    0)]
        
    public bool BooleanValue;

        
    public void SetValue(int value)
        
    public void SetValue(Color value)
        
    public void SetValue(float value)
        
    public void SetValue(bool value)
    }

    public struct HaRenderState
    {
        
    public readonly byte Id;
        
    public HaRenderStateValue Value;
    }

     
        最后则是实际设置渲染状态的函数,这一步并没有什么技巧可言,只是用了一个非常长的switch把所有需要hard code的部分集中到这里。这是目前为止我能想到的最简单有效的方法,使用Dictionary也许能减少代码长度,但实际测试表明,switch有更好的性能:

     public static void SetRenderState(GraphicsDevice graphics, HaRenderState renderState)
     {
         
    switch (renderState.Id)
         {
             
    case HaRenderStateId.AlphaBlendEnable:
                 graphics.RenderState.AlphaBlendEnable 
    = renderState.Value.BooleanValue;
                 
    break;

             
    case HaRenderStateId.AlphaBlendOperation:
                 graphics.RenderState.AlphaBlendOperation 
    = (BlendFunction)renderState.Value.IntegerValue;
                 
    break;

             
    case HaRenderStateId.SourceBlend:
                 graphics.RenderState.SourceBlend 
    = (Blend)renderState.Value.IntegerValue;
                 
    break;
            
          }
    }


            扩展结束,现在可以像文章开头介绍的那样,使用循环设置所有render state,更重要的是可以随时添加或者删除集合中的render state,这样给为渲染器设计带来了非常大的便利和灵活性:

    material.AddRenderState(RenderState)
    material.RemoveRenderState(RenderState)
    ......
    material.ApplyRenderState()

    {
          foreach renderState in this.renderStates
               SetRenderState(gfxDevice,renderState)
    }

  • 相关阅读:
    C++ 算法03算法设计的常用思想
    C++ 算法02算法设计的基础
    C++ 算法01
    字符串Hash入门
    CSP2020总结
    关于树状数组的应用
    Cookies题解
    博客迁移
    斜率优化(转载)
    单调队列优化和决策单调性优化
  • 原文地址:https://www.cnblogs.com/clayman/p/1509707.html
Copyright © 2020-2023  润新知