I am using slimDX and am having a problem with a shader. I have an instance Shader that works perfect but I needed one for drawing fonts manually. The idea is to create the plane and simple instance it with separate position color and texture coordinates for each char. I know this post is terribly long but any help would be appreciated. I tried to provide everything needed but if you need more I will be glad to post it.
This is the shader. the only difference between it and the working one is the instance texture coordinates. I was able to render 4,000 spheres with 30,000 faces with the original and still maintain a 100+ framerate. I don't know if that is a lot but it looked like it to me.
cbuffer cbVSPerFrame:register(b0)
{
row_major matrix world;
row_major matrix viewProj;
};
Texture2D g_Tex;
SamplerState g_Sampler;
struct VSInstance
{
float4 Pos : POSITION;
float3 Normal : NORMAL;
float2 Texcoord : TEXCOORD0;
float4 model_matrix0 : TEXCOORD1;
float4 model_matrix1 : TEXCOORD2;
float4 model_matrix2 : TEXCOORD3;
float4 model_matrix3 : TEXCOORD4;
// this is the only addition
float2 instanceCoord:TEXCOORD5;
float4 Color:COLOR;
};
struct PSInput
{
float4 Pos : SV_Position;
float3 Normal : NORMAL;
float4 Color:COLOR;
float2 Texcoord : TEXCOORD0;
};
PSInput Instancing(VSInstance In)
{
PSInput Out;
// construct the model matrix
row_major float4x4 modelMatrix =
{
In.model_matrix0,
In.model_matrix1,
In.model_matrix2,
In.model_matrix3
};
Out.Normal = mul(In.Normal, (row_major float3x3)modelMatrix);
float4 WorldPos = mul(In.Pos, modelMatrix);
Out.Pos = mul(WorldPos, viewProj);
Out.Texcoord = In.instanceCoord;
Out.Color = In.Color;
return Out;
}
float4 PS(PSInput In) : SV_Target
{
return g_Tex.Sample(g_Sampler, In.Texcoord);
}
technique11 HWInstancing
{
pass P0
{
SetGeometryShader(0);
SetVertexShader(CompileShader(vs_4_0, Instancing()));
SetPixelShader(CompileShader(ps_4_0, PS()));
}
}
this is the input elements for the 2 buffers
private static readonly InputElement[] TextInstance = {
new InputElement("POSITION", 0, Format.R32G32B32_Float, 0, 0, InputClassification.PerVertexData, 0),
new InputElement("NORMAL", 0, Format.R32G32B32_Float, InputElement.AppendAligned, 0, InputClassification.PerVertexData, 0),
new InputElement("TEXCOORD", 0, Format.R32G32_Float, InputElement.AppendAligned, 0, InputClassification.PerVertexData, 0),
new InputElement("TEXCOORD", 1, Format.R32G32B32A32_Float, 0, 1, InputClassification.PerInstanceData, 1 ),
new InputElement("TEXCOORD", 2, Format.R32G32B32A32_Float, InputElement.AppendAligned, 1, InputClassification.PerInstanceData, 1 ),
new InputElement("TEXCOORD", 3, Format.R32G32B32A32_Float, InputElement.AppendAligned, 1, InputClassification.PerInstanceData, 1 ),
new InputElement("TEXCOORD", 4, Format.R32G32B32A32_Float, InputElement.AppendAligned, 1, InputClassification.PerInstanceData, 1 ),
new InputElement("TEXCOORD", 5, Format.R32G32_Float, InputElement.AppendAligned, 1, InputClassification.PerInstanceData, 1 ),
new InputElement("COLOR", 0, Format.R32G32B32A32_Float, InputElement.AppendAligned, 1, InputClassification.PerInstanceData, 1 )
};
the struct for holding instance data.
[StructLayout(LayoutKind.Sequential)]
public struct InstancedText
{
public Matrix InstancePosition;
public Vector2 InstanceCoords;
public Color4 Color;
};
instanceData buffer creation. Instance Positions is a simple List<InstancedText> above
DataStream ds = new DataStream(InstancePositions.ToArray(), true, true);
BufferDescription vbDesc = new BufferDescription();
vbDesc.BindFlags = BindFlags.VertexBuffer;
vbDesc.CpuAccessFlags = CpuAccessFlags.None;
vbDesc.OptionFlags = ResourceOptionFlags.None;
vbDesc.Usage = ResourceUsage.Default;
vbDesc.SizeInBytes = InstancePositions.Count * Marshal.SizeOf<InstancedText>();
vbDesc.StructureByteStride = Marshal.SizeOf<InstancedText>();
ds.Position = 0;
instanceData = new Buffer(renderer.Device, vbDesc);
and finally the render code.
the mesh is a model class that contains the plane's data. PositionNormalTexture is just a struct for those elements.
renderer.Context.InputAssembler.InputLayout = new InputLayout(renderer.Device,
effect.GetTechniqueByName("HWInstancing").GetPassByIndex(0).Description.Signature, TextInstance);
renderer.Context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
renderer.Context.InputAssembler.SetVertexBuffers(0, new
VertexBufferBinding(mesh.VertexBuffer, Marshal.SizeOf<PositionNormalTexture>(), 0));
renderer.Context.InputAssembler.SetIndexBuffer(mesh.IndexBuffer, SlimDX.DXGI.Format.R32_UInt, 0);
renderer.Context.InputAssembler.SetVertexBuffers(1, new VertexBufferBinding(instanceData,
Marshal.SizeOf<InstancedText>(), 0));
effect.GetVariableByName("g_Tex").AsResource().SetResource(textures[fonts[name].Name]);
EffectTechnique currentTechnique = effect.GetTechniqueByName("HWInstancing");
for (int pass = 0; pass < currentTechnique.Description.PassCount; ++pass)
{
EffectPass Pass = currentTechnique.GetPassByIndex(pass);
System.Diagnostics.Debug.Assert(Pass.IsValid, "Invalid EffectPass");
Pass.Apply(renderer.Context);
renderer.Context.DrawIndexedInstanced(mesh.IndexCount, InstancePositions.Count, 0, 0, 0);
};
I have been over everything I can think of to find the problem but I can't seem to locate it.
my best guess is the instance data buffer is wrong somehow since VS graphics debugger shows no output from vertex shader stage
but I just can't see where.
↧