Render state management in xNa
For personal use only, do not reprint, do not use for any commercial purposes.
the problem:
A poor design in xNa is to define various render States as members of the renderstate class, rather than enumeration. In dx/MDX, if you need to set a series of render states, you only need to
foreach state in renderstates
gfxdevice. setrenderstate (statename, statevalue);
simple and clear.
the same operation in xNa requires a lot of trouble, you have to access each render State member explicitly to set the value:
gfxdevice. renderstate. XXXX = value;
gfxdevice. renderstate. XXXX = value;
......
Such Code is not bad, it is in "hard code ". If you are not sure how many render states need to be set in advance, how can we encode them?
The solution:
It is not difficult to solve this problem. I hope to still use the traditional method to set the status. First, define a series of constants to indicate all rendering States. Here a static class is used, and replacement with enumeration is the same.
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 ;< br>.
}
Next, you need to unify the values of all render states. In this way, each render state can be put into the same container as the same key-value pair. Observe all render states. Their values are similar to the following: enumeration, Int, float, bool, color. Very lucky. They can all be expressed with a 32-bit value. But how to encode it? In this case, C ++ProgramFirst of all, the clerk must think of union. Although there is no built-in union type in C #, this does not prevent us from using struct to simulate Union behavior:
[Structlayout (layoutkind. explicit)]
Public Struct Harenderstatevalue
{
[Fieldoffset ( 0 )]
Public Int Integervalue;
[Fieldoffset (0)]
Public FloatFloatvalue;
[Fieldoffset (0)]
PublicColor color;
[Fieldoffset (0)]
Public BoolBooleanvalue;
Public Void Setvalue ( Int Value)
Public Void Setvalue (color value)
Public Void Setvalue ( Float Value)
Public Void Setvalue ( Bool Value)
}
Public StructHarenderstate
{
Public Readonly ByteID;
PublicHarenderstatevalue value;
}
The last step is the function that actually sets the rendering State. There is no skill in this step, but a very long switch is used to concentrate all the hard code parts here. This is the simplest and most effective method I can think of so far. Using a dictionary may reduce the code length, but actual tests show that the switch has better performance:
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 ;
CaseHarenderstateid. sourceblend:
Graphics. renderstate. sourceblend=(Blend) renderstate. value. integervalue;
Break;
}
}
Expansion ends. Now it can be likeArticleAs described at the beginning, you can set all render states using loops. More importantly, you can add or delete render states in the set at any time, which brings great convenience and flexibility to the Renderer design:
Material. addrenderstate (renderstate)
Material. removerenderstate (renderstate)
......
Material. applyrenderstate ()
{
Foreach renderstate in this. renderstates
Setrenderstate (gfxdevice, renderstate)
}