[<Struct; StructLayout(LayoutKind.Explicit, Size=48)>] type SceneConstants_IfYouDontHavePostSharp = [<FieldOffset(0)>] val Eye : float3 [<FieldOffset(16)>] val Light : float3 [<FieldOffset(32)>] val AmbientLight : float3 [<FieldOffset(44)>] val LightRangeSquared : float32 with new(eye, light, ambientLight, lightRange) = { Eye = eye Light = light AmbientLight = ambientLight LightRangeSquared = lightRange }
To avoid having to write all this boilerplate code every time we create a new shader, we can turn to aspect oriented programming.
Using the PostSharp framework, one could create an aspect that will enforce the HLSL constant packing rules at compile time. It will actually weave in the necessary code into your existing class. For instance, the ConstantPacking aspect would be used as follows:[<Struct;ConstantPacking>] type SceneConstants(eye:float3, light:float3, ambientLight:float3, lightRangeSquared:float32) = member m.Eye = eye member m.Light = light member m.AmbientLight = ambientLight member m.LightRangeSquared = lightRangeSquaredIsn't that neat? By just adding the magic ConstantPacking attribute, all the packing rules are enforced! The source code for this magic class can be found here.
There is one downside to using PostSharp as your AOP framework. It is not free. However, its uses stretch far beyond enforcing layout rules. As programmers we put up with writing repetitive boilerplate code far more often than we need to. AOP helps to keep things DRY, not only when writing shaders. Considering how powerful this tool is and how much time it can save you, it is a small investment.
No comments:
Post a Comment