DirectX Input Layout w/ Instancing Problem

Started by
21 comments, last by vinterberg 5 years, 7 months ago
3 hours ago, vinterberg said:

RGB32 + RGBA32 = 28 bytes, and your Vertex struct is probably defined as two float3s (which would give 24 bytes)..?
You set the stride yourself, at "strides[0] = sizeof(Vertex);"

 

Man you real programmers make me look bad ^_^

Advertisement

Dumb question guys, now that I have instancing set up, and my squares are getting drawn on the screen in a location determined by the instance, what role does my world matrix play?

 

Now I translate with my instance buffer, rather than the world constant buffer.

 

Also, I assumed it was possible to update my instance buffer during my update loop, do I need to create a new instance buffer each time an object moves, how do I go about updating my instance buffer during runtime?

After some googling, I found this little Q&A here:

https://gamedev.stackexchange.com/questions/48179/directx-instance-buffer-how-to-use-instance-buffers-to-enable-reuse-of-verte

 

Now, the guy is suggesting he use constant buffer updates to move his stuff around the world, but how do I use a constant buffer to change my world translation for each instance with one "drawinstanced" call... Maybe someone can help me piece things together.

 

I think i found my answer in that link:

Quote

@WindAndFlame yes, if you have to models in one vertex buffer (say, first one has 30, second one 50 vertices) you can draw them by Draw(30, 0) and Draw(50,30). This extends to DrawInstanced etc, and works the same with the instance buffers – user13213 Jan 26 '13 at 22:37

I can use this capability of the DrawInstanced function, to set the constant buffer between calls.

 

But then this defeats the purpose of passing position data via the instance?

 

I feel conflicted, can someone help me sort this logic out? Why pass an instance position if I'm going to be updating the constant buffer to translate my instances?

Unbind the instance buffer, and use Map()/Unmap() to update it once per frame - don't think there's much overhead in that :)

What he's talking about with Draw(30,0) and Draw(50,30) is when you have more than one model in your vertex buffer, by using offset into a vertex buffer (starting point).

 

.:vinterberg:.

From what I read so far it seems that you are passing a float3 per instance. It sounds like you ditched the world matrix approach to revert back to pass a pure translation as float3 instead. This is where your world matrix was supposed to go which is 4x R32G32B32A32 as instance in your vertex layout. When you draw with instancing your world matrix is part of the vertex layout instead of the constant buffer. You'll need 2 version of that same shader for drawinstance and for regular draw. In my case I use the same hlsl file with #if pre-compile instructions to generate both.

3 minutes ago, vinterberg said:

Unbind the instance buffer, and use Map()/Unmap() to update it once per frame - don't think there's much overhead in that :)

What he's talking about with Draw(30,0) and Draw(50,30) is when you have more than one model in your vertex buffer, by using offset into a vertex buffer (starting point).

 

Cool, so map, unmap, I've seen that before

So, maybe you can help me understand, I'm doing two seemingly different things to set data in my subresources...

 

For my vertex buffer, I'm doing a map and unmap like you're talking about:


	devcon->Map(pVBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms);    // map the buffer
	memcpy(ms.pData, OurVertices.data(), sizeof(Vertex) * OurVertices.size());                 // copy the data
	devcon->Unmap(pVBuffer, NULL);                                      // unmap the buffer

For my instance buffer, which was created by checking out the rastertek tutorial, I'm doing this:


	// Give the subresource structure a pointer to the instance data.
	instanceData.pSysMem = instances;
	instanceData.SysMemPitch = 0;
	instanceData.SysMemSlicePitch = 0;

 

The vertex buffer, I notice data is getting set AFTER the CreateBuffer call, for the instance buffer, the data is being set BEFORE.

 

Can I just map/unmap my buffer I created for my instance buffer after I have already set data like this?

4 minutes ago, ChuckNovice said:

From what I read so far it seems that you are passing a float3 per instance. It sounds like you ditched the world matrix approach to revert back to pass a pure translation as float3 instead. This is where your world matrix was supposed to go which is 4x R32G32B32A32 as instance in your vertex layout.

Chuck, you're correct, I did revert back to a float3, in the form of a D3DXVECTOR3 because I was having trouble getting things to work. Now that things are working, I'll give switching my per instance data back to a D3DXMATRIX. This should simplify my shader code.

 

So, on that note chuck, the world matrix in my constant buffer, should be a separate matrix from the one in my instances correct? In this respect, the constant buffer world matrix is a translation on a set of instances, rather than individually?

 

23 minutes ago, JWColeman said:

Can I just map/unmap my buffer I created for my instance buffer after I have already set data like this?

Yes, a buffer is a buffer. Doesn't matter if you use it as a vertex buffer / index buffer / constant buffer. Map/Unmap will work on that. Also I believe I've read somewhere that nvidia driver map the UpdateSubresource call to Map/Unmap. They essentially do the same thing and the real difference between the two remain a mystery to me.

 

23 minutes ago, JWColeman said:

So, on that note chuck, the world matrix in my constant buffer, should be a separate matrix from the one in my instances correct? In this respect, the constant buffer world matrix is a translation on a set of instances, rather than individually?

Yes they are separate, you will need to compile two version of the shader. One that work with Draw and one that work with DrawInstanced. In my project I simply pass a macro called "MESH_INSTANCE" when compiling the shader and let pre-compiler instructions adjust the constant buffer / vertex layout accordingly. That way I don't have to write 2 version of the same HLSL file. Looks something like this :

 


//---------------------------------------------------------------------------------------
//		Per object buffer.
//---------------------------------------------------------------------------------------
#ifndef MESH_INSTANCE
	cbuffer ObjectConstantBuffer : register(b1)
	{
		float4x4 WorldMatrix;
		float4x4 WorldInvertMatrix;
	}
#endif

//--------------------------------------------------------------------
//		Defines the vertex input structure.
//--------------------------------------------------------------------
struct VertexInput
{
	#include <VERTEX_INPUT_LAYOUT>

	// The world transform matrix if the mesh is an instance.
#ifdef MESH_INSTANCE
	float4x4 WorldMatrix : WORLDMATRIX;
	float4x4 WorldInvertMatrix : WORLDINVERTMATRIX;
	uint InstanceId : SV_InstanceID;
#endif
};

 

As you can see, if MESH_INSTANCE is defined my shader wont have a constant buffer and it will instead be part of the vertex layout.


//---------------------------------------------------------------------------------------
//		Main function of the vertex shader.
//---------------------------------------------------------------------------------------
VertexOutput VS(VertexInput input)
{

#ifdef MESH_INSTANCE
	float4x4 World = input.WorldMatrix;
	float4x4 WorldInvert = input.WorldInvertMatrix;
#else
	float4x4 World = WorldMatrix;
	float4x4 WorldInvert = WorldInvertMatrix;
#endif
	VertexOutput output;

	// generated code.
	#include <VERTEX_BODY>

	return output;
}

Looks fancy Chuck, for now, I'm going to leave my shader as a one trick pony and only use instanced drawing.

I think, using only 2d for now, most of my stuff is going to be instanced geometry, or a couple very small differences. Right now, I'm going to focus on getting this thing to work dynamically and take input,  I want to be able to move the instanced squares around using input.

That, along with generally scrubbing my code and adding in error handling and things of that nature. 

I also need to figure out how my Renderable_Object class will come into play now that there is only one copy of the vertices on hand at a given time due to instancing...

Right now I have a class renderable object that is storing vertex information, as well as other various bits of info, such as position, velocity, min and max values, etc.. Now with instancing, I only need 1 copy of vertex data and many copies of position and velocity data. I had this setup previously in opengl and have since lost it. Oh well, onward I go!

 


class Renderable_Object
{
public:

	Renderable_Object(float minX, float minY, float maxX, float maxY)
	{
		
		d_min.x = minX;
		d_min.y = minY;
		d_max.x = maxX;
		d_max.y = maxY;
		/*
		position.x = posX;
		position.y = posY;
		velocity.x = 0;
		velocity.y = 0;
		isVisible = visible;
		isPhysical = physical;
		*/
		Vertex OurVertices[] =
		{
			{ D3DXVECTOR2(maxX, maxY), D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f) },
			{ D3DXVECTOR2(maxX, minY), D3DXCOLOR(0.0f, 1.0f, 0.0f, 1.0f) },
			{ D3DXVECTOR2(minX, minY), D3DXCOLOR(0.0f, 0.0f, 1.0f, 1.0f) },
			{ D3DXVECTOR2(minX, minY), D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f) },
			{ D3DXVECTOR2(minX, maxY), D3DXCOLOR(0.0f, 1.0f, 0.0f, 1.0f) },
			{ D3DXVECTOR2(maxX, maxY), D3DXCOLOR(0.0f, 0.0f, 1.0f, 1.0f) }
		};

		for (int i = 0; i < 6; i++)
		{
			Vertices.push_back(OurVertices[i]);
		}
	}
	D3DXVECTOR2 & getVelocity()
	{
		return velocity;
	}
	void setVelocity(float x, float y)
	{
		velocity.x = x; velocity.y = y;
	}
	D3DXVECTOR2 & getLocation()
	{
		return position;
	}
	D3DXVECTOR2 & getMinimum()
	{
		return d_min;
	}
	D3DXVECTOR2 & getMaximum()
	{
		return d_max;
	}

	std::vector<Vertex> & getVertices()
	{
		return Vertices;
	}

private:

	
	D3DXVECTOR2 position;
	D3DXVECTOR2 velocity;
	D3DXVECTOR2 d_min;
	D3DXVECTOR2 d_max;

	std::vector<Vertex> Vertices;

	bool isPhysical;		// can you touch it?
	bool isVisible;			// render this object?
	bool AABB;				// compatible with AABB collision detection
};

 

It's all good. Be very careful tho because those square wont solve all your problems. Let's take this basic example of a mario bros level :

image.thumb.png.f6bf7d205380689f6229febeca503f31.png

 

In this case is it better to draw 46 squares or a big rectangle with different texture coordinates to make the texture repeat? The world of graphic programming never cease to paint us in a corner when we assume such things :P

 

9 minutes ago, ChuckNovice said:

It's all good. Be very careful tho because those square wont solve all your problems. Let's take this basic example of a mario bros level :

image.thumb.png.f6bf7d205380689f6229febeca503f31.png

 

In this case is it better to draw 46 squares or a big rectangle with different texture coordinates to make the texture repeat? The world of graphic programming never cease to paint us in a corner when we assume such things :P

 

Oh how shortsighted I am!

I know nothing!

 

1 hour ago, ChuckNovice said:

Yes, a buffer is a buffer. Doesn't matter if you use it as a vertex buffer / index buffer / constant buffer. Map/Unmap will work on that. Also I believe I've read somewhere that nvidia driver map the UpdateSubresource call to Map/Unmap. They essentially do the same thing and the real difference between the two remain a mystery to me.

Thanks for this tidbit, so as far as you know, theres no true difference to map/unmap and UpdateSubresource calls?

 

I could just use UpdateSubresource to peform my instance updates?

This topic is closed to new replies.

Advertisement