October 6, 2006

[XNA] Wrap Your Shaders

One nice thing that the XNA team did was their BasicEffect class. Essentially, they're wrapping a shader in a class to prevent you from having to worry about setting effect parameters manually, and to keep you from having to pick the right technique.

You can do it yourself as well, but unfortunately, you can't inherit from Effect because it's a sealed class.

This sample class wraps the sample shader shown in "How to: Apply an Effect". Let me know if you have any problems with it.

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Components;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;

namespace Shaders
public class SimpleEffect
private Effect myEffect;
private Game myGame;

private const string effectSource = @"
uniform extern float4x4 WorldViewProj : WORLDVIEWPROJECTION;

struct VS_OUTPUT
float4 position : POSITION;
float4 color : COLOR0;

VS_OUTPUT Transform(
float4 Pos : POSITION,
float4 Color : COLOR0 )

Out.position = mul(Pos, WorldViewProj);
Out.color = Color;

return Out;

technique TransformTechnique
pass P0
vertexShader = compile vs_2_0 Transform();

private Matrix wvp;
private EffectParameter wvp_p;

public Matrix WorldViewProjection
get { return wvp; }
set {
// This check takes less time than it takes to set (and possibly recompile) the shader constant
if (value == wvp)

wvp = value;

public SimpleEffect(Game g)
CompiledEffect cfx = Effect.CompileEffectFromSource(effectSource, null, null,
CompilerOptions.None, TargetPlatform.Windows);
myGame = g;
IGraphicsDeviceService gfxSvc = myGame.GameServices.GetService<IGraphicsDeviceService>();
GraphicsDevice dvc = gfxSvc.GraphicsDevice;

if (dvc.GraphicsDeviceCapabilities.VertexShaderVersion.Major < 2)
throw new BadObjectException("This shader requires vertex shader 2 or above.");

myEffect = new Effect(dvc, cfx.GetShaderCode(), CompilerOptions.None, null);
wvp_p = myEffect.Parameters["WorldViewProj"];

public EffectPassCollection Passes
get { return myEffect.CurrentTechnique.Passes; }

public void Begin(EffectStateOptions flags)
// If you have multiple techniques in your shader, you'd pick the right one here.
myEffect.CurrentTechnique = myEffect.Techniques["TransformTechnique"];

public void CommitChanges()

public void End()

No comments: