|
|
@@ -0,0 +1,215 @@
|
|
|
+# ShaderGen
|
|
|
+
|
|
|
+A proof-of-concept library which generates shader code from C#. Currently, the project can generate HLSL (D3D11), GLSL-330 (core-GL-compatible) and GLSL-450 (Vulkan-compatible) shader code from a single shader source specified in C#.
|
|
|
+
|
|
|
+## Shaders in C#
|
|
|
+
|
|
|
+Writing shader code in C# could have quite a few benefits:
|
|
|
+
|
|
|
+* Easily share type definitions between graphics code in C# and shaders.
|
|
|
+ * For example, one could re-use the same structure to describe the input to a vertex shader, as well as to store the actual vertex data in your C# program.
|
|
|
+ * Shader uniforms ("constant buffers") can be shared as well.
|
|
|
+* Analysis done at code-generation time can be used to build extra metadata about the shaders, enabling reflection-like capabilities.
|
|
|
+ * The full vertex input specification can be generated when doing the C# analysis for code generation.
|
|
|
+ * The layouts and order for all global shader resources can be captured.
|
|
|
+ * Validation can be performed to ensure, for example, uniforms are multiples of 16-bytes in size, etc.
|
|
|
+* C# refactoring tools can be used.
|
|
|
+* C# niceties like inheritance, composition, partial declarations, etc. can be leveraged for easier shader writing (speculative).
|
|
|
+
|
|
|
+## Example Shader
|
|
|
+
|
|
|
+Here is an example vertex and fragment shader, written in C# with ShaderGen:
|
|
|
+
|
|
|
+```C#
|
|
|
+public class MinExample
|
|
|
+{
|
|
|
+ [Resource] public Matrix4x4 Projection;
|
|
|
+ [Resource] public Matrix4x4 View;
|
|
|
+ [Resource] public Matrix4x4 World;
|
|
|
+ [Resource] public Texture2DResource SurfaceTexture;
|
|
|
+ [Resource] public SamplerResource Sampler;
|
|
|
+
|
|
|
+ public struct VertexInput
|
|
|
+ {
|
|
|
+ [VertexSemantic(SemanticType.Position)] public Vector3 Position;
|
|
|
+ [VertexSemantic(SemanticType.TextureCoordinate)] public Vector2 TextureCoord;
|
|
|
+ }
|
|
|
+
|
|
|
+ public struct FragmentInput
|
|
|
+ {
|
|
|
+ [VertexSemantic(SemanticType.Position)] public Vector4 Position;
|
|
|
+ [VertexSemantic(SemanticType.TextureCoordinate)] public Vector2 TextureCoord;
|
|
|
+ }
|
|
|
+
|
|
|
+ [VertexShader]
|
|
|
+ public FragmentInput VertexShaderFunc(VertexInput input)
|
|
|
+ {
|
|
|
+ FragmentInput output;
|
|
|
+ Vector4 worldPosition = Mul(World, new Vector4(input.Position, 1));
|
|
|
+ Vector4 viewPosition = Mul(View, worldPosition);
|
|
|
+ output.Position = Mul(Projection, viewPosition);
|
|
|
+ output.TextureCoord = input.TextureCoord;
|
|
|
+ return output;
|
|
|
+ }
|
|
|
+
|
|
|
+ [FragmentShader]
|
|
|
+ public Vector4 FragmentShaderFunc(FragmentInput input)
|
|
|
+ {
|
|
|
+ return Sample(SurfaceTexture, Sampler, input.TextureCoord);
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+Here is some representative output from the library (subject to change, etc.):
|
|
|
+
|
|
|
+HLSL Vertex Shader
|
|
|
+```HLSL
|
|
|
+struct MinExample_VertexInput
|
|
|
+{
|
|
|
+ float3 Position : POSITION0;
|
|
|
+ float2 TextureCoord : TEXCOORD0;
|
|
|
+};
|
|
|
+
|
|
|
+struct MinExample_FragmentInput
|
|
|
+{
|
|
|
+ float4 Position : POSITION0;
|
|
|
+ float2 TextureCoord : TEXCOORD0;
|
|
|
+};
|
|
|
+
|
|
|
+struct MinExample_FragmentInput__FRAGSEMANTICS
|
|
|
+{
|
|
|
+ float4 Position : SV_POSITION;
|
|
|
+ float2 TextureCoord : TEXCOORD0;
|
|
|
+};
|
|
|
+
|
|
|
+cbuffer ProjectionBuffer : register(b0)
|
|
|
+{
|
|
|
+ float4x4 Projection;
|
|
|
+}
|
|
|
+
|
|
|
+cbuffer ViewBuffer : register(b1)
|
|
|
+{
|
|
|
+ float4x4 View;
|
|
|
+}
|
|
|
+
|
|
|
+cbuffer WorldBuffer : register(b2)
|
|
|
+{
|
|
|
+ float4x4 World;
|
|
|
+}
|
|
|
+
|
|
|
+MinExample_FragmentInput__FRAGSEMANTICS VertexShaderFunc(MinExample_VertexInput input)
|
|
|
+{
|
|
|
+ MinExample_FragmentInput output;
|
|
|
+ float4 worldPosition = mul(World, float4(input.Position, 1));
|
|
|
+ float4 viewPosition = mul(View, worldPosition);
|
|
|
+ output.Position = mul(Projection, viewPosition);
|
|
|
+ output.TextureCoord = input.TextureCoord;
|
|
|
+ return output;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+HLSL Fragment Shader
|
|
|
+```HLSL
|
|
|
+struct MinExample_FragmentInput__FRAGSEMANTICS
|
|
|
+{
|
|
|
+ float4 Position : SV_POSITION;
|
|
|
+ float2 TextureCoord : TEXCOORD0;
|
|
|
+};
|
|
|
+
|
|
|
+Texture2D SurfaceTexture : register(t0);
|
|
|
+SamplerState Sampler : register(s0);
|
|
|
+
|
|
|
+float4 FragmentShaderFunc(MinExample_FragmentInput__FRAGSEMANTICS input) : SV_Target
|
|
|
+{
|
|
|
+ return SurfaceTexture.Sample(Sampler, input.TextureCoord);
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+GLSL (450) Vertex Shader
|
|
|
+```GLSL
|
|
|
+#version 450
|
|
|
+#extension GL_ARB_separate_shader_objects : enable
|
|
|
+#extension GL_ARB_shading_language_420pack : enable
|
|
|
+struct MinExample_VertexInput
|
|
|
+{
|
|
|
+ vec3 Position;
|
|
|
+ vec2 TextureCoord;
|
|
|
+};
|
|
|
+
|
|
|
+struct MinExample_FragmentInput
|
|
|
+{
|
|
|
+ vec4 Position;
|
|
|
+ vec2 TextureCoord;
|
|
|
+};
|
|
|
+
|
|
|
+layout(binding = 0) uniform ProjectionBuffer
|
|
|
+{
|
|
|
+ mat4 Projection;
|
|
|
+};
|
|
|
+layout(binding = 1) uniform ViewBuffer
|
|
|
+{
|
|
|
+ mat4 View;
|
|
|
+};
|
|
|
+layout(binding = 2) uniform WorldBuffer
|
|
|
+{
|
|
|
+ mat4 World;
|
|
|
+};
|
|
|
+
|
|
|
+MinExample_FragmentInput VertexShaderFunc(MinExample_VertexInput input_)
|
|
|
+{
|
|
|
+ MinExample_FragmentInput output_;
|
|
|
+ vec4 worldPosition = World * vec4(input_.Position, 1);
|
|
|
+ vec4 viewPosition = View * worldPosition;
|
|
|
+ output_.Position = Projection * viewPosition;
|
|
|
+ output_.TextureCoord = input_.TextureCoord;
|
|
|
+ return output_;
|
|
|
+}
|
|
|
+
|
|
|
+layout(location = 0) in vec3 Position;
|
|
|
+layout(location = 1) in vec2 TextureCoord;
|
|
|
+layout(location = 0) out vec2 out_TextureCoord;
|
|
|
+
|
|
|
+void main()
|
|
|
+{
|
|
|
+ MinExample_VertexInput input_;
|
|
|
+ input_.Position = Position;
|
|
|
+ input_.TextureCoord = TextureCoord;
|
|
|
+ MinExample_FragmentInput output_ = VertexShaderFunc(input_);
|
|
|
+ out_TextureCoord = output_.TextureCoord;
|
|
|
+ gl_Position = output_.Position;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+GLSL (450) Fragment Shader
|
|
|
+```GLSL
|
|
|
+#version 450
|
|
|
+#extension GL_ARB_separate_shader_objects : enable
|
|
|
+#extension GL_ARB_shading_language_420pack : enable
|
|
|
+
|
|
|
+struct MinExample_FragmentInput
|
|
|
+{
|
|
|
+ vec4 Position;
|
|
|
+ vec2 TextureCoord;
|
|
|
+};
|
|
|
+
|
|
|
+layout(binding = 3) uniform texture2D SurfaceTexture;
|
|
|
+layout(binding = 4) uniform sampler Sampler;
|
|
|
+
|
|
|
+vec4 FragmentShaderFunc(MinExample_FragmentInput input_)
|
|
|
+{
|
|
|
+ return texture(sampler2D(SurfaceTexture, Sampler), input_.TextureCoord);
|
|
|
+}
|
|
|
+
|
|
|
+layout(location = 0) in vec4 Position;
|
|
|
+layout(location = 1) in vec2 TextureCoord;
|
|
|
+layout(location = 0) out vec4 _outputColor_;
|
|
|
+
|
|
|
+void main()
|
|
|
+{
|
|
|
+ MinExample_FragmentInput input_;
|
|
|
+ input_.Position = Position;
|
|
|
+ input_.TextureCoord = TextureCoord;
|
|
|
+ vec4 output_ = FragmentShaderFunc(input_);
|
|
|
+ _outputColor_ = output_;
|
|
|
+}
|
|
|
+```
|