[SlimDX] Instancing problems - It worked in XNA!

Started by
4 comments, last by Mathy 13 years, 11 months ago
I'm doing instancing in SlimDX now after I got it working all by myself in XNA Game Studio 3.1. I now understand how instancing works entirely, but after converting my working code from XNA to SlimDX, instancing no longer works as expected. My shader code (which worked in XNA) is pasted in here:

float4x4 View;
float4x4 Projection;

float3 LightDirection = normalize(float3(1, -1, 2));
float3 DiffuseLight = 0.5;
float3 AmbientLight = 0.1;

struct VertexShaderInput
{
    float4 position : POSITION0;
    float3 normal : NORMAL0;
    float4 color : COLOR0;
};


struct VertexShaderOutput
{
    float4 position : POSITION0;
    float4 color : COLOR0;
};


// Vertex shader helper function shared between the different instancing techniques.
VertexShaderOutput VertexShaderCommon(VertexShaderInput input, float4x4 instanceTransform)
{
    VertexShaderOutput output;

    // Apply the world and camera matrices to compute the output position.
    float4 worldPosition = mul(input.position, instanceTransform);
    float4 viewPosition = mul(worldPosition, View);
    
    output.position = mul(viewPosition, Projection);
    
    // Compute lighting, using a simple Lambert model.
    float3 worldNormal = mul(input.normal, instanceTransform);
    float diffuseAmount = max(-dot(worldNormal, LightDirection), 0);
    float3 lightingResult = saturate(diffuseAmount * DiffuseLight + AmbientLight);
    //output.color = float4(lightingResult, 1);
	output.color=1.0f;
    
    //output.textureCoordinate = input.textureCoordinate;


    return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
    //return input.color;
	return 1.0f;
}

// On Windows shader 3.0 cards, we can use hardware instancing, reading
// the per-instance world transform directly from a secondary vertex stream.
VertexShaderOutput HardwareInstancingVertexShader(VertexShaderInput input,
                                                float4x4 instanceTransform : TEXCOORD1)
{
    return VertexShaderCommon(input, transpose(instanceTransform));
}

technique HardwareInstancing
{
    pass Pass1
    {
        VertexShader = compile vs_3_0 HardwareInstancingVertexShader();
        PixelShader = compile ps_3_0 PixelShaderFunction();
    }
}
Now, the shader compiles correctly and gets loaded as an effect just fine, so that can't be the problem. Below you see my vertex declaration.

        private static VertexElement[] VertexElements =
             {
                 new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 0),
                 new VertexElement(0, sizeof(float)*3, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Normal, 0),
                 new VertexElement(0, sizeof(float)*6, DeclarationType.Color, DeclarationMethod.Default, DeclarationUsage.Color, 0),
                 new VertexElement(1, 0, DeclarationType.Float4, DeclarationMethod.Default, DeclarationUsage.TextureCoordinate, 1),
                 new VertexElement(1, 16, DeclarationType.Float4, DeclarationMethod.Default, DeclarationUsage.TextureCoordinate, 2),
                 new VertexElement(1, 32, DeclarationType.Float4, DeclarationMethod.Default, DeclarationUsage.TextureCoordinate, 3),
                 new VertexElement(1, 48, DeclarationType.Float4, DeclarationMethod.Default, DeclarationUsage.TextureCoordinate, 4),
                 VertexElement.VertexDeclarationEnd
             };
Now, here's my vertex structure:

    [StructLayout(LayoutKind.Sequential)]
    public struct PositionNormalColored
    {
        public Vector3 position;
        public int color;
        public Vector3 normal;
        public static readonly VertexFormat format = VertexFormat.Diffuse | VertexFormat.Position | VertexFormat.Normal;

        public PositionNormalColored(Vector3 position, int color) {
            this.position = position;
            this.color = color;
            this.normal = Vector3.Zero;
        }

        public static int SizeInBytes = sizeof(float) * (6 + 1);
    }
And finally, here's the code I use to render the objects. I believe that is the part that is not working (since it is converted from XNA).

        public static void performInstancing(Device device, Matrix view, Matrix projection, VertexBuffer vertexBuffer, IndexBuffer indexBuffer, VertexDeclaration vertexDeclaration, Matrix[] instancePositions, short vertexCount, short indexCount)
        {
            if (instancePositions==null || instancePositions.Length == 0)
            {
                return;
            }

            effect.Technique = new EffectHandle("HardwareInstancing");
            effect.SetValue(new EffectHandle("View"), view);
            effect.SetValue(new EffectHandle("Projection"), projection);

            device.SetStreamSource(0, vertexBuffer, 0, Vertices.PositionNormalColored.SizeInBytes);
            device.SetStreamSourceFrequency(0, instancePositions.Length, StreamSource.IndexedData);

            device.VertexDeclaration = vertexDeclaration;
            device.Indices = indexBuffer;

            int instanceDataSize = sizeOfMatrix * instancePositions.Length;
            if ((instanceDataStream == null) || (instanceDataStream.Description.SizeInBytes < instanceDataSize))
            {
                if (instanceDataStream != null)
                {
                    instanceDataStream.Dispose();
                }
                instanceDataStream = new VertexBuffer(device, instanceDataSize, Usage.WriteOnly, VertexFormat.Texture0, Pool.Default);
            }
            DataStream dataStream = instanceDataStream.Lock(0, instanceDataSize, LockFlags.None);
            dataStream.WriteRange(instancePositions);
            instanceDataStream.Unlock();

            device.SetStreamSource(1, instanceDataStream, 0, sizeOfMatrix);
            device.SetStreamSourceFrequency(1, 1, StreamSource.InstanceData);

            int passes = effect.Begin(FX.None);
            for(int i=0;i<passes;i++)
            {

                effect.BeginPass(i);
                device.DrawIndexedPrimitives(PrimitiveType.TriangleList,
                                                     0, 0, vertexCount,
                                                     0, indexCount / 3);
                effect.EndPass();

            }
            effect.End();

            device.SetStreamSource(0, null, 0, 0);
            device.SetStreamSource(1, null, 0, 0);
        }
Can anyone tell me what I am perhaps doing wrong? I tried changing this line: instanceDataStream = new VertexBuffer(device, instanceDataSize, Usage.WriteOnly, VertexFormat.Texture0, Pool.Default); Into: instanceDataStream = new VertexBuffer(device, instanceDataSize, Usage.WriteOnly, VertexFormat.Texture0 | VertexFormat.Texture1 | VertexFormat.Texture2 | VertexFormat.Texture3, Pool.Default); But without hope.
Advertisement
You shouldn't be using FVF codes if you're also using vertex declarations. Use VertexFormat.None to specify this.

Also, VertexFormat.Texture0 indicates that you have 0 texture coordinates in your declaration, which is obviously incorrect.
Mike Popoloski | Journal | SlimDX
I changed that, and it still doesn't work.
Nevermind, I got it all working! It turned out to be some coordinates being weird.
Your vertex declaration doesn't match your vertex structure.
Mike Popoloski | Journal | SlimDX
Quote:Original post by Mike.Popoloski
Your vertex declaration doesn't match your vertex structure.


I fixed that, and now the lighting effects work too! Thanks! Instancing worked with weird structures anyway though ;) Rating for you.

This topic is closed to new replies.

Advertisement