Project Description
WPF Meta-Effects makes it easier for shader effect developpers to develop and maintain shader code. You'll no longer have to write any HLSL, instead of that, you'll write typesafe, compile-time verified and intellisense capable C# code, and the runtime translates it for you !
Features
- C# 4.0 Lamda expression-based shader language
- Dynamic generation of GPU code (allows late optimization of shader effects)
Prerequisites to build the solution
- Visual Studio 2010 RTM
- DirectX SDK
Special thanks
The syntax is based on a presentation done by Mitsuru Furuta during TechDays France 2010 and explained on his blog:
http://blogs.msdn.com/mitsu/
Known issues
Only a limited subset of the structures avalable in Mitsu's project are implemented. Things like loops and conditional structures are not implemented in this initial work.
Examples
Simple invert color code:
private class ShaderVariables
{
[Register(0)]
public sampler2D Input { get; set; }
[Texcoord]
public float2 TexCoord { get; set; }
public float4 Color { get; set; }
}
private void CreateShader()
{
Expression<Action<ShaderVariables>> shaderSource = o =>
Block.Declare(new ShaderVariables(), vars =>
Block.Default
.Assign(vars.Color, vars.Input.tex2D(vars.TexCoord))
.Assign(vars.Color, new float4(new float3(1,1,1) - vars.Color.xyz, vars.Color.w))
._(()=>vars.Color.Return())
);
var hlsl = ExpressionToHlsl.TranslateToHLSL(shaderSource);
_shader = HlslCompiler.Compile(hlsl, ShaderProfile.ps_2_0);
}
PlaneProjectionEffect (see
http://slflow.codeplex.com for original code):
public class PlaneProjectionVariables
{
[Register(0)]
public float4x4 invertedMatrix { get; set; }
[Register(4)]
public float3 planeNormal { get; set; }
[Register(5)]
public float planeDistance { get; set; }
[Register(6)]
public float2 sourceSize { get; set; }
[Register(10)]
public float2 viewportOffset { get; set; }
[Register(0)]
public sampler2D implicitInputSampler { get; set; }
[Texcoord]
public float2 texCoords { get; set; }
public float3 sourceOfRay { get; set; }
public float3 rayVector { get; set; }
public float normalDotRayVector { get; set; }
public float normalDotSourceOfRay { get; set; }
public float distanceOfInterceptionPoint { get; set; }
public float3 intersectPointInWorldSpace { get; set; }
public float4 intersectPointInPlanSpace4 { get; set; }
public float3 intersectPointInPlanSpace { get; set; }
public float4 color { get; set; }
}
private void CreateShader()
{
Expression<Action<PlaneProjectionVariables>> expr = (PlaneProjectionVariables vs) =>
Block.Declare(new PlaneProjectionVariables(),
vars =>
Block.Default
.Assign(vars.sourceOfRay, new float3(vars.texCoords * 2.0f - 1.0f, 0))
.Assign(vars.sourceOfRay.x, vars.sourceOfRay.x + vars.viewportOffset.x)
.Assign(vars.sourceOfRay.y, vars.sourceOfRay.y + vars.viewportOffset.y)
.Assign(vars.rayVector, new float3(0, 0, -1))
.Assign(vars.normalDotRayVector, vars.planeNormal.dot(vars.rayVector))
.Assign(vars.normalDotSourceOfRay, vars.planeNormal.dot(vars.sourceOfRay))
.Assign(vars.distanceOfInterceptionPoint, 0.0f - (vars.normalDotSourceOfRay + vars.planeDistance) / vars.normalDotRayVector)
.Assign(vars.intersectPointInWorldSpace, vars.sourceOfRay + vars.distanceOfInterceptionPoint * vars.rayVector)
.Assign(vars.intersectPointInPlanSpace4, new float4(vars.intersectPointInWorldSpace, 1.0f).mul(vars.invertedMatrix.transpose()))
.Assign(vars.intersectPointInPlanSpace, vars.intersectPointInPlanSpace4.xyz / vars.intersectPointInPlanSpace4.w)
.Assign(vars.intersectPointInPlanSpace.x, vars.intersectPointInPlanSpace.x / vars.sourceSize.x * 0.5f)
.Assign(vars.intersectPointInPlanSpace.y, vars.intersectPointInPlanSpace.y / vars.sourceSize.y * 0.5f)
.Assign(vars.intersectPointInPlanSpace, vars.intersectPointInPlanSpace * 0.5f + 0.5f)
.Assign(vars.color, vars.implicitInputSampler.tex2D(vars.intersectPointInPlanSpace.xy))
._(() => vars.color.Return())
);
var hlsl = ExpressionToHlsl.TranslateToHLSL(expr);
_shader = HlslCompiler.Compile(hlsl, ShaderProfile.ps_2_0);
}
Composite effect:
public class CommonParameters
{
[Register(0)]
public sampler2D Input { get; set; }
[Texcoord]
public float2 TexCoord { get; set; }
public float4 Color { get; set; }
}
public class Parameters1 : CommonParameters
{
[Register(0)]
public float2 Offset { get; set; }
}
public class Parameters2 : CommonParameters
{
[Register(1)]
public float4 ColorMultiplier { get; set; }
}
private void CreateShader()
{
Expression<Action<Parameters1>> exp1 = o =>
Block.Declare(new Parameters1(), vars =>
Block.Default
.Assign(vars.TexCoord, vars.TexCoord + vars.Offset)
.Assign(vars.Color, vars.Input.tex2D(vars.TexCoord))
);
Expression<Action<Parameters2>> exp2 = o =>
Block.Declare(new Parameters2(), vars =>
Block.Default
.Assign(vars.Color, vars.Color * vars.ColorMultiplier)
._(() => vars.Color.Return())
);
var hlsl = ExpressionToHlsl.TranslateToHLSL(exp1, exp2);
_shader = HlslCompiler.Compile(hlsl, ShaderProfile.ps_2_0);
}