Jump to content

  • Log In with Google      Sign In   
  • Create Account


#Actualphantom

Posted 29 September 2012 - 07:01 PM

Put simply; unless it is per-instance data the model shouldn't care.

When you create your model it gets a reference to a material structure (assuming C++ this could simply be a Material class pointer) and when the draw call is setup the pointer is placed into the structure.

Internally the material will hold all the data needed to work which isn't setup per-instance. (colour data, textures which are the same for all instances of the model etc).

So, for example, if you had a 'house' material all any object which uses it needs to do is indicate to the renderer it uses that material and thats all. It doesn't need to care about textures, parameters or any of that stuff. If you need a house which has a different texture then you'd create a different material (so you might have wood_house and brick_house materials) with the same shaders but different textures; internally you deal with not duplicating the shader setting and only change the textures between draw calls.

Per-instance data is a little tricker and it does depend somewhat on how your engine is setup.

For example if you have a simple update-draw loop on a single thread then you can get away with pass a chunk of memory along with the rest of the draw data which contains the per-instance data. This could be something as simple as an array of [handle, DataType] where 'handle' was something you asked for from the material for a per-instance parameter and 'DataType' could well be a union with a 'type' flag so that the same data could be used for float4 parameters and texture data. (or even a 'known' constant block layout if you wanted to expose it)

A solution for a threading setup would be more involved as you'd need a 'game' and 'renderer' side abstraction and then data gets passed across via a message queue from one to the other and stored locally.

The key points really is that the material needs to have a concept of 'per-instance' data and each mesh instance needs to store it's only copy of that data somehow. The handle based system is probably simplest.

[source lang="cpp"]struct InstanceData{ HandleType handle; DataType type; union { Float4 values; Texture * texture; }}class Model{Material * myMaterial;InstanceData myInstanceData[1];void Creation(){ // get all resources here somehow // including myMaterial myInstanceData[0].handle = myMaterial.getParameter("foo"); myInstanceData[0].type = DataType::TextureData; myInstanceData[0].texture = textureSystem.getNameTexture("cow");}DrawCall createDrawCall(){ DrawCall dc; // fill out general draw details dc.instanceDataPointer = myInstanceData; return dc;}[/source]

So when the object it created it gets a handle to the 'foo' parameter and set the data to a pointer to the texture named 'cow'.

Once the draw call is created this per-instance data is added to it and in the renderer it is checked and the resulting data set to the correct variables for the draw.
(Internally the material knows how much per-instance data to expect; in the create this would be queried to size the array correctly on creation instead of the hard coded example above.)

(Note: This is only a rough sketch of the idea. It needs fleshing out but I hope you get the idea).

#1phantom

Posted 29 September 2012 - 06:58 PM

Put simply; unless it is per-instance data the model shouldn't care.

When you create your model it gets a reference to a material structure (assuming C++ this could simply be a Material class pointer) and when the draw call is setup the pointer is placed into the structure.

Internally the material will hold all the data needed to work which isn't setup per-instance. (colour data, textures which are the same for all instances of the model etc).

So, for example, if you had a 'house' material all any object which uses it needs to do is indicate to the renderer it uses that material and thats all. It doesn't need to care about textures, parameters or any of that stuff. If you need a house which has a different texture then you'd create a different material (so you might have wood_house and brick_house materials) with the same shaders but different textures; internally you deal with not duplicating the shader setting and only change the textures between draw calls.

Per-instance data is a little tricker and it does depend somewhat on how your engine is setup.

For example if you have a simple update-draw loop on a single thread then you can get away with pass a chunk of memory along with the rest of the draw data which contains the per-instance data. This could be something as simple as an array of [handle, DataType] where 'handle' was something you asked for from the material for a per-instance parameter and 'DataType' could well be a union with a 'type' flag so that the same data could be used for float4 parameters and texture data. (or even a 'known' constant block layout if you wanted to expose it)

A solution for a threading setup would be more involved as you'd need a 'game' and 'renderer' side abstraction and then data gets passed across via a message queue from one to the other and stored locally.

The key points really is that the material needs to have a concept of 'per-instance' data and each mesh instance needs to store it's only copy of that data somehow. The handle based system is probably simplest.

[source lang="cpp"]struct InstanceData{ HandleType handle; DataType type; union { Float4 values; Texture * texture; }}Model {Material * myMaterial;InstanceData myInstanceData[1];void Creation(){ // get all resources here somehow // including myMaterial myInstanceData[0].handle = myMaterial.getParameter("foo"); myInstanceData[0].type = DataType::TextureData; myInstanceData[0].texture = textureSystem.getNameTexture("cow");}DrawCall createDrawCall(){ DrawCall dc; // fill out general draw details dc.instanceDataPointer = myInstanceData; return dc;}[/source]
So when the object it created it gets a handle to the 'foo' parameter and set the data to a pointer to the texture named 'cow'.

Once the draw call is created this per-instance data is added to it and in the renderer it is checked and the resulting data set to the correct variables for the draw.
(Internally the material knows how much per-instance data to expect; in the create this would be queried to size the array correctly on creation instead of the hard coded example above.)

(Note: This is only a rough sketch of the idea. It needs fleshing out but I hope you get the idea).

PARTNERS