6
\$\begingroup\$

I'm writing a game for the xbox360 using XNA. I would like to draw several models with a single DrawInstancedPrimitives call. Each model will use a different texture.

To do this, I would like to create a sampler array, and select which sampler to use in the array from a value passed into the shader from the instance vertex buffer.

So the shader code might look like:

void InstancingVertexShader(..., in float4x4 data : TEXCOORD0)
{
    output.TextureIndex = data._m00
}

void InstancingPixelShader(...)
{
    color = tex2Dlod(samplers[input.TextureIndex]);
}

Before I start trying to implement that, my question is:

Is it possible to do that, or will the HLSL complain?

Are there any cons to this method that I should know about?

\$\endgroup\$
1
  • \$\begingroup\$ What I am trying to accomplish exactly is: I have several hundred instances, and am CPU bound. Draw calls are very expensive on the XBOX360, so I am trying to reduce the number of draw calls that I need to make. \$\endgroup\$
    – Olhovsky
    Mar 22, 2011 at 1:52

4 Answers 4

6
\$\begingroup\$

Practical answer: No (in SM 3.0; apparently you can in SM 4.0, but I haven't checked.)

Technically the answer is yes, as it is legal HLSL. But if the sampler index cannot be determined at compile time, then compilation will fail because there is no way to express this as a GPU instruction.

So, you can only select a sampler by index if that index is constant at compile time.

Of course you can achieve a similar effect to indexing by using dynamic branching or simply doing multiple reads and selecting one. But this is only a good idea if you have lots of texture bandwidth to spare.

The best solution is probably a texture atlas. You can create your own mipmaps, if that is a concern.

(Here is a thread on GameDev.net that is the same as your question.)

\$\endgroup\$
4
\$\begingroup\$

With 3D textures you could use the 'w' component of the 3D texture co-ordinates to select a different texture to sample from.

What are you trying to achieve? Are you making big savings by rendering all 3 with a single call? You could also use a texture page/atlas to have all 3 textures in one larger texture (maybe with a little wastage) and then have the 3 set's of UV's pick the correct texture out of the right part of the image.

\$\endgroup\$
2
  • \$\begingroup\$ I never said anything about only 3 textures. The reason that I don't want to pack multiple textures into a single texture is because then I won't have the ability to use mipmapping, I believe. I don't think that 3D textures are available on the Xbox360 (which uses DX9 plus a few DX10 features). Sticking with your example of 3 textures, how else would I render 3 textures on each instance primitive? A separate pass per texture? \$\endgroup\$
    – Olhovsky
    Mar 22, 2011 at 1:40
  • \$\begingroup\$ Ok, I may have plucked the number 3 out of nowhere. There's a Texture3D class on the 360 and the number of layers is independant to the width/height. What might be a better approach for you is to render all models of a certain type together, you could have vertex/index buffers set up to render 4 in a single go, you could then have an index in the vertex buffer to select which matrix to use to render, that way you could set up the matrices for say 4 objects to render in a single call, all using the same texture/shader/state setup. \$\endgroup\$ Mar 22, 2011 at 11:17
2
\$\begingroup\$

This is posted as an answer because I don't have enough reputation to write a comment.

You mention that you cannot use texture atlas because then you can't use mipmapping. This is not true. Just generate the mipmap chain for texture atlas yourself (for example by generating mipmaps for individual textures first and then combining them into one big texture dynamically; this is relatively easy because Texture2D generated mipmaps automatically). In shader you can use tex2Dlod, tex2Dgrad, ddx and ddy functions to calculate preferred mipmap level.

Also, you could take a look about hardware instancing which is obviously available also on Xbox (http://dotnetkicks.com/csharp/Hardware_Instancing_in_XNA_on_the_XBOX_360)

\$\endgroup\$
1
  • \$\begingroup\$ Well, I am using instancing, which is the problem. +1 for pointing out that mipmapping is possible with texture atlases. I may go that route. \$\endgroup\$
    – Olhovsky
    Mar 22, 2011 at 15:57
1
\$\begingroup\$

I didn't have the time to actually read the entire thing, but judging by the synopsis, this might be for you:

There's a sample in the nVidia Direct3D SDK 10.5 that is described as follows:

This sample is a simple example using Texture Arrays in DX10. It uses a texture array as a palette of terrain textures to render a terrain mesh with many textures in a single draw call. A similar effect in previous APIs would require a texture atlas or multiple draw calls.

nVidia D3D SDK 10.5 samples page (it's at the bottom of the page)

nVidia White Paper on Texture Arrays and Terrain Rendering

nVidia Demo Project Download

I'm aware this is a) not directly regarding XNA and b) possibly not quite what you want but maybe you can gain get a hold of further leads there.

\$\endgroup\$
2
  • \$\begingroup\$ A good read but these techniques are not available in DX9, and therefore XNA/XBOX. \$\endgroup\$
    – Olhovsky
    Mar 24, 2011 at 3:10
  • \$\begingroup\$ Right, it was supposed to be for XNA. Sorry, my bad :) \$\endgroup\$
    – Koarl
    Mar 29, 2011 at 8:34

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .