Written: March 12, 2004
OK, so I have been aware of this problem/dilemma for years now but have not seen any head way being made. I am also writing this because I have been watching some of the GDC 2004 ATI presentations at ATI's web site, and they reiterate some thing I have heard on occasion. Things like not bothering to try and figure out what parts of a terrain are visible and render them, but rather to just passing the whole terrain and render the whole thing, because the typical card can handle it, etc etc.
See "Richard Huddy - Save The Nanosecond" under the "ATI Sponsored sessions" category at http://www.ati.com/developer/gdc_video.html (NOTE: link current as of May 12, 2004.)
So I am going to try to describe my idea to you as best I can. Hope fully my meaning will not be lost one you.
We all know DrawPrimitive calls, device state changes, render to texture, setting a new texture on the device etc etc, can be costly, And I don't have any real complaints about that whole process except this...
We have vertex buffers, we have index buffers, why not TexturedIndex buffers? Here is what I mean...
A TexturedIndex buffer contains...
1 integer = Index into a index buffer (IE: a triangle/mesh face)
2 integers or 1 long or 8 bytes = Each of the 8 bytes stores the index to a texture stage to use when we render.
Example 1:
FaceIndex as integer
TextureStage0 as byte
TextureStage1 as byte
TextureStage2 as byte
TextureStage3 as byte
TextureStage4 as byte
TextureStage5 as byte
TextureStage6 as byte
TextureStage7 as byte
or Example 2:
FaceIndex as integer
TextureStages03 as integer ' each byte = stages 0 to 3
TextureStages47 as integer ' each byte = stages 4 to 7
or Example 3:
FaceIndex as integer
TextureStages as long ' each byte = stages 0 to 7
For example if my vertexes in by vertex buffer contain 3 texture coordinates and if I want to render the face's that uses those 3 textures, a base texture set at stage 0, a bump texture set at stage 5, and a environment texture set at stage 6, a entry for a TexturedIndex for a face would look some thing like this when stored in a TexturedIndex buffer...
Code:
'Face 1
TexIndex(0).FaceIndex = 231 ' index to a face inside of the index buffer
TexIndex(0).TextureStage0 = 0 ' Specifies that the location of the stage 0 texture is actually stored in stage 0
TexIndex(0).TextureStage1 = 5 ' Specifies that the location of the stage 1 texture is actually stored in stage 5
TexIndex(0).TextureStage2 = 6 ' Specifies that the location of the stage 2 texture is actually stored in stage 6
'Face 2
TexIndex(1).FaceIndex = 179
TexIndex(2).TextureStage0 = 4 ' Specifies that the location of the stage 0 texture is actually stored in stage 4
TexIndex(3).TextureStage1 = 7 ' Specifies that the location of the stage 1 texture is actually stored in stage 7
TexIndex(4).TextureStage2 = 3 ' Specifies that the location of the stage 2 texture is actually stored in stage 3
... and so on ...
"TexIndex(2).TextureStage0 = 4" basically means that we are telling the video card that the texture stored in stage 0 is actually stored in stage 4. This is because our vertexes stored in our vertex buffer are stored as tU1, tV1, tU2, tV2, etc and they don't specify that tU1, tV1, refers to texture coordinates of a texture stored in texture stage 5, there just RAW texture coordinates.
Now I know generally we should render geometry sorted by texture, to reduce texture state changes, but instead of having to pass in a texture at stage 0 (Dirt.png) then render all parts of the terrain that use that texture, then set a new texture in stage 0 (Concrete.png) and render the building.
Instead of doing that we could set a texture for each of the 8 texture stages, and use in combination with index buffers, a TexturedIndex buffer to render the geometry. That way we can render more geometry in one draw call and we don't have to make as many texture state changes with the Device.SetTexture method.
The most commonly used textures could stay permanently stored in specific texture stage slots, and we only need to change out a texture in a specific stage when and as we need to. For example a environment map texture could be stored in stage 7, while a common detail texture could be stored in stage 6.
This would also allow us to batch groups of 8 textures together and create TexturedIndex buffers to render geometry in large groups.
By it's very nature I don't assume that there would be allot involved in adding this kind of functionality to DirectX or video cards, because it's is based on the IndexBuffer, and vertexbuffer paradigms.
The TexturedIndex buffer does produce some tantalizing ideas, but I'm no expert, so If you have heard of similar ideas that have been put fourth would you let me know? Also what do you think about this idea?