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);            
        }


Last edited Apr 27, 2010 at 1:58 PM by simonferquel, version 3