Jump to content

  • Log In with Google      Sign In   
  • Create Account

DirectX9 Hardware Instancing. Draws only one instance?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
7 replies to this topic

#1 CptBonex   Members   -  Reputation: 162

Like
0Likes
Like

Posted 18 May 2012 - 03:42 PM

Hi

This is my first post on this site. I used to be at App Hub but I resently started working directly to DirectX and the DirectX activity there is close to none thats why I joined here so that I might have someone to talk to. But enoght about that and on to my question.

For a few days I have tried to get hardware instancing to work but with no luck. I have googled a lot and read everything on the topic that I can find. Everything compiles and It draws one of the instances where only one of the vertrices are affected by the world coordinate. I'm at the point where I want to throw the computer out the window so please have a look at this and help me if you can!

Here is the instancing parts of my code.

private int _instanceCount;

private InstanceFormat[] _instances;

private VertexBuffer _instanceBuffer;

private int _vertexCount;

private VertexFormat[] _vertices;

private VertexBuffer _vertexBuffer;

private int _indexCount;

private uint[] _indices;

private IndexBuffer _indexBuffer;

private D3D.Effect _instancingEffect;

private VertexDeclaration _vertexDeclaration;

int vertexSize;

int instanceSize;

struct VertexFormat

{

public Vector3 Position;

public Vector2 Texture;

public VertexFormat(Vector3 position, Vector2 texture)

{

Position = position;

Texture = texture;

}

}

struct InstanceFormat

{

public Vector3 World;

public InstanceFormat(Vector3 world)

{

World = world;

}

}


This is where I create my Declaration and fill the buffers:
#region Set up vertex declaration

vertexSize = 20;

instanceSize = 12;

VertexElement[] vertexElementsArray = new VertexElement[]

{

new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 0),

new VertexElement(0, 12, DeclarationType.Float2, DeclarationMethod.Default, DeclarationUsage.TextureCoordinate, 0),

new VertexElement(1, 0, DeclarationType.Float4, DeclarationMethod.Default, DeclarationUsage.TextureCoordinate, 1),

VertexElement.VertexDeclarationEnd

};

// Create a vertex declaration based on the vertex elements.

_vertexDeclaration = new VertexDeclaration(_device, vertexElementsArray);

#endregion

#region Set up vertex buffer for vertices

_vertexCount = 4;

_vertexBuffer = new VertexBuffer(_device, vertexSize*_vertexCount, Usage.Dynamic | Usage.WriteOnly, VertexFormats.Position | VertexFormats.Texture0, Pool.Default);



_vertices = new VertexFormat[_vertexCount];

_vertices[0] = new VertexFormat(new Vector3(0, 0, 0), new Vector2(0, 0));

_vertices[1] = new VertexFormat(new Vector3(0, 1, 0), new Vector2(0, 1));

_vertices[2] = new VertexFormat(new Vector3(1, 0, 0), new Vector2(1, 0));

_vertices[3] = new VertexFormat(new Vector3(1, 1, 0), new Vector2(1, 1));

_vertexBuffer.SetData(_vertices, 0, LockFlags.None);

#endregion

#region Set up index buffer

_indexCount = 6;

_indexBuffer = new IndexBuffer(_device, sizeof(uint)*_indexCount, Usage.WriteOnly, Pool.Default, false);

_indices = new uint[_indexCount];

_indices[0] = 0; _indices[1] = 1; _indices[2] = 2;

_indices[3] = 1; _indices[4] = 3; _indices[5] = 2;

_indexBuffer.SetData(_indices, 0, LockFlags.None);

#endregion

#region Set up vertex buffer for instances

_instanceCount = 10;

_instanceBuffer = new VertexBuffer(_device, instanceSize * _instanceCount, Usage.Dynamic | Usage.WriteOnly, VertexFormats.None, Pool.Default);



_instances = new InstanceFormat[_instanceCount];

for (int i = 0; i < _instanceCount; i++)

_instances[i] = new InstanceFormat(new Vector3(i, 0, i));

_instanceBuffer.SetData(_instances, 0, LockFlags.None);



#endregion


And this is my draw method:
_device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.DarkSlateBlue, 1.0f, 0);

_device.BeginScene();

_device.VertexDeclaration = _vertexDeclaration;

_device.Indices = _indexBuffer;

_device.SetStreamSource(0, _vertexBuffer, 0, vertexSize);

_device.SetStreamSource(1, _instanceBuffer, 0, instanceSize);

// Specify how many times the vertex stream source and the instance stream source should be rendered.

_device.SetStreamSourceFrequency(0, _instanceCount);

_device.SetStreamSourceFrequency(1, 1);

_instancingEffect.Technique = "Instancing";

_instancingEffect.SetValue("WVP", _camera.view * _camera.projection);

_instancingEffect.SetValue("cubeTexture", _textures[1]);

int numpasses = _instancingEffect.Begin(0);

for (int i = 0; i < numpasses; i++)

{

_instancingEffect.BeginPass(i);

_device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, _vertexCount, 0, _indexCount / 3);

_instancingEffect.EndPass();

}

_instancingEffect.End();

_device.SetStreamSourceFrequency(0, 1);

_device.SetStreamSourceFrequency(1, 1);

_device.EndScene();

_device.Present();



And here is my shader:
float4x4 WVP;

texture cubeTexture;

sampler TextureSampler = sampler_state

{

texture = <cubeTexture>;

mipfilter = LINEAR;

minfilter = LINEAR;

magfilter = LINEAR;

};

struct InstancingVSinput

{

float4 Position : POSITION0;

float2 TexCoord : TEXCOORD0;

float4 World : TEXCOORD1;

};



struct InstancingVSoutput

{

float4 Position : POSITION0;

float2 TexCoord : TEXCOORD0;

};



InstancingVSoutput InstancingVS(InstancingVSinput input)

{

InstancingVSoutput output;

// Transform the vertex into world coordinates.

float4 pos = input.Position + input.World;

// Transform the vertex from world coordinates into screen coordinates.

output.Position = mul(pos, WVP);

output.TexCoord = input.TexCoord;

return output;

}



float4 InstancingPS(InstancingVSoutput input) : COLOR0

{

return float4(1,1,1,1);// tex2D(TextureSampler, input.TexCoord);

}



technique Instancing

{

pass Pass0

{

VertexShader = compile vs_3_0 InstancingVS();

PixelShader = compile ps_3_0 InstancingPS();

}

}


Edit: I should probably mention that I have a Radeon HD 5770.

Sponsor:

#2 david w   Members   -  Reputation: 166

Like
0Likes
Like

Posted 18 May 2012 - 11:05 PM

I think i know what the issue is. In your vertex shader input you are defining you world matrix as your input.
This is an array that you build - for example it contains your position, scale, and rotation for each "instance" in your world.

What you need to do is input it like this.



float4 Position : POSITION;
float2 TexCoord : TEXCOORD0;
float4 W0 : TEXCOORD1;
float4 W1 : TEXCOORD2;
float4 W2 : TEXCOORD3;
float4 W3 : TEXCOORD4;


and of course you must have a compatable vertex declaration and you can construct the world positions like this

float4x4 object = float4x4(input.W0, input.W1, input.W2, float4(input.W3.xyz, 1.0f));
float4x4 objectworld = mul(object, world);
float4x4 WVP = mul(objectworld, mul(view, proj));
output.Position = mul(float4(input.Position.xyz, 1.0f), WVP);

This is probably the reason behind the reason its "working" but you only see the original mesh and not any of its children.

#3 kauna   Crossbones+   -  Reputation: 2570

Like
2Likes
Like

Posted 19 May 2012 - 01:31 AM

It's been a while that I have worked with D3D9 level stuff but here's another thing:


_device.SetStreamSourceFrequency(0, _instanceCount);
_device.SetStreamSourceFrequency(1, 1);

shouldn't this be

_device.SetStreamSourceFrequency(0, D3DSTREAMSOURCE_INDEXDATA | _instanceCount);
_device.SetStreamSourceFrequency(0, D3DSTREAMSOURCE_INSTANCEDATA | 1);


Remember to restore the correct values after using instancing as you are already doing.

Best regards!

Edited by kauna, 19 May 2012 - 01:31 AM.


#4 CptBonex   Members   -  Reputation: 162

Like
0Likes
Like

Posted 19 May 2012 - 03:18 AM

David w: I don't really have the need of a matrix because there is no scaling and rotation done to the model. I only want to place it on different coordinates and thats why I only input a vector3.

kauna: Well my program does not recognise D3DSTREAMSOURCE_INDEXDATA or D3DSTREAMSOURCE_INSTANCEDATA. What reference and using do I need for this?

Edited by CptBonex, 19 May 2012 - 03:18 AM.


#5 kauna   Crossbones+   -  Reputation: 2570

Like
0Likes
Like

Posted 19 May 2012 - 06:07 AM

Oh sorry, seems that XNA instancing works differently than instancing under D3D9.

Cheers!

#6 CptBonex   Members   -  Reputation: 162

Like
0Likes
Like

Posted 19 May 2012 - 06:56 AM

I have done Instancing in xna and I dont remember using them and I have seen a few examples where those are used but I cant access them.

#7 unbird   Crossbones+   -  Reputation: 5109

Like
1Likes
Like

Posted 19 May 2012 - 06:58 AM

Kauna's right, this is the way to enable instancing in D3D 9.
These constants are defined in d3dtypes.h:

#define D3DSTREAMSOURCE_INDEXEDDATA  (1<<30)
#define D3DSTREAMSOURCE_INSTANCEDATA (2<<30)

Whether Managed DirectX exposes these values somewhere eludes me. Other managed libraries like XNA/SharpDX/SlimDX either do or come with some convenience functions for instancing.

If you want to stick with Managed DirectX and don't find these constants you could as well define them yourself.
I think that should work then.

#8 CptBonex   Members   -  Reputation: 162

Like
0Likes
Like

Posted 19 May 2012 - 07:34 AM

Yes it worked!!! Thank you guys so mutch!

I did this:
static class Constants
    {
	    public const int D3DSTREAMSOURCE_INDEXEDDATA = (1 << 30);
	    public const int D3DSTREAMSOURCE_INSTANCEDATA = (2<<30);
    }

and used them like this:
_device.SetStreamSourceFrequency(0, Constants.D3DSTREAMSOURCE_INDEXEDDATA | _instanceCount);
		    _device.SetStreamSourceFrequency(1, Constants.D3DSTREAMSOURCE_INSTANCEDATA | 1);





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS