Formeln

Wednesday, April 17, 2013

Rendering a Wireframe over a Mesh

This tutorial is one part of a series of tutorials about generating procedural meshes. See here for an outline.

Rendering a wireframe over a given mesh is relatively simple and requires just a second pass in the shader and two states for the rasterizer.

So far we used an effect technique with one pass:

technique10 Render
{
  pass P0
  {
    SetVertexShader( CompileShader( vs_4_0, VShader() ));
    SetGeometryShader( NULL );
    SetPixelShader( CompileShader( ps_4_0, PShader() ));
  }
}



This is the shader code for rendering the wireframe over the mesh:


matrix gWVP;
float4 wireFrameColor;

struct VOut
{
  float4 position : SV_POSITION;
  float4 color : COLOR;
};

VOut VShader(float4 position : POSITION, float4 color : COLOR)
{
  VOut output;

  output.position = mul( position, gWVP);
  output.color = color;

  return output;
}

float4 PShader(float4 position : SV_POSITION, float4 color : COLOR) : SV_TARGET
{
  return color;
}

float4 PShaderWireframe(float4 position : SV_POSITION, float4 color : COLOR) : SV_TARGET
{
  return wireFrameColor;
}

RasterizerState WireframeState
{
  FillMode = Wireframe;
};

RasterizerState SolidState
{
  FillMode = Solid;
};

technique10 Render
{
  pass P0
  {
    SetVertexShader( CompileShader( vs_4_0, VShader() ));
    SetGeometryShader( NULL );
    SetPixelShader( CompileShader( ps_4_0, PShader() ));
    SetRasterizerState(SolidState);
  }

  pass P1
  {
    SetVertexShader( CompileShader( vs_4_0, VShader() ));
    SetGeometryShader( NULL );
    SetPixelShader( CompileShader( ps_4_0, PShaderWireframe() ));
    SetRasterizerState(WireframeState);
  }
}

In the first pass P0 I set the fillmode state to Solid, to render the mesh. In the second pass P1 the fillmode state is set to Wireframe. Observe, that while I use in P0 and P1 the same vertex shader (which is kind of obious, because the wireframe needs the same transformations as the solid mesh), but use a different pixel shader, called PShaderWireframe. In this second pixel shader I set the color of the wireframe pixels to the variable wireFrameColor, to render the wireframe in a given color.

The variable wireFrameColor is set via the effect framework in the renderable object. This way there is no need to recompile the shader in case I want to use a different color for the wireframe.

In the code for the renderable I have to declare a variable of the type EffectVectorVariable:

EffectVectorVariable wireFrameColor;

This variable is bound to the shader variable in the constructor of the renderable object with this statement:

wireFrameColor = effect.GetVariableByName("wireFrameColor").AsVector();
Vector4 col = new Vector4(0, 0, 0, 1);
wireFrameColor.Set(col);

I just need to set this variable once in the constructor. If you want to do things like changing the color at runtime, you need to put the asignment wireFrameColor.Set(col) into the render method to make sure, it gets called in every frame.

Result




You can download the source code for this tutorial here.

No comments:

Post a Comment