Rendering with dynamic U/V

Started by
11 comments, last by Khatharr 11 years, 7 months ago
I'm thinking about ways of creating a simple isometric map engine and I have an idea that I like but I'm not sure about one of the techniques I'd want to use. Basically I want to have 16 block 'shapes' stored in vertex buffers and a single texture containing multiple tile images that can be iterated through to render the map. The problem I'm seeing is that the U/V coords are contained in the vertex data, so I couldn't really change them dynamically as the rendering is going on. An alternative would be to just have a whole slew of small textures, but it seems like there ought to be some way to do this (that is to say, I don't think I'm the first person with this kind of idea). I think it would be cool if the single texture and the vertex data could already be cached on the device and then during rendering just quickly set the UV instead of potentially uploading a new texture.

Does anyone know if there's a way to decouple the UV coords from the rest of the vertex data? Maybe vertex shaders could do it, or some simpler method?

A link to or name of a relevant methodology would be a great help. Thank you for any replies.
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.
Advertisement

The problem I'm seeing is that the U/V coords are contained in the vertex data, so I couldn't really change them dynamically as the rendering is going on.


Why can't you use a dynamic vertex buffer and update the UVs before rendering?
Thank you for the advice - that is indeed my fallback plan - but my primary objective is to eliminate bus traffic. (I should have been more clear about that in the original post.) This 'feels' like something that the SDK should have, but MS documentation is "unhelpful".

I'm wanting to upload a pair of vertex buffers, one with position and the other with U/V. Along with those, a pair of index buffers, one for mapping positions and one for mapping U/V coord sets. Once those are up I can set a single texture with all the tiles on it and then render the entire landscape with virtually no bus traffic (just sending an index value for each of the index buffers).

While poking around in the SDK docs I found vertex declarations as the alternative to FVF, and that gets me most of the way there, but the last remaining hurdle is that even though I can upload split vertexes the render call functions only accept a single index. So I'm wondering if there's another render function that can accept an index value for each vertex stream or if this is something that I can do with a vertex shader.
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.
You can only set one index buffer for all bound streams. Though that shouldn't matter, you just need to make your UVs align with your vertices one-to-one, and it should work fine. Is there any reason why you would need the UVs in a different order than the vertices?
Perception is when one imagination clashes with another
The reason I want to spit the stream is...

Okay, I'll explain the whole thing.

In the position buffer I'll have a set of 16 vertexes. The first 8 vertexes will compose a cube with sides of length 3.0f. The second 8 vertexes will be the same cube, but elevated by 1.0f. In this way I can use an index buffer to render 15 distinct cube shapes (plus one quad shape for sprites) with different 'corners' of the cube raised by 1.0f. In this way I can draw moderately complex geometry using a sort of grid. All of the textures to be applied to sides of the individual blocks would be stored in a single texture composed of 32x64 tile pairs (one tile for the top of the cube and one for the sides). The U/V vertex buffer will basically be a set of texture coordinates at the corner points of each tile. The index buffer matched to this vertex buffer would cause a different tile to be drawn to the currently rendering brick based on the start index. In this way, at the start of the map scene, I can upload the texture, both vertex buffer parts, and both index buffers. They should be pretty small, so for the duration of the entire scene I can render any shape in any position using any tile from the texture by sending only:

*position buffer start index
*texture coord buffer start index
*primitive count

Basically since the data is so small I'm wanting to upload it manually to the device and then use it for the whole scene, avoiding having to continually send redundant data, since both the positions and coordinates can so easily be specified and ordered beforehand.

The docs on vertex declarations state that their intended use is to eliminate the need for sending redundant data over the bus, which is one of the reasons I have a feeling that there's some way to make this happen.

If it can't be done on the CPU then do you think I could write a vert shader for something like this? I've only messed with pixel shaders before.

Thank you for your response, also. :)
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.
You can create a vertex format any way you like, holding any data you want on the CPU then pass it each frame to the vertex / pixel shader. In the vertex shader set up a struc to hold the incoming data and manipulate it anyway you want. It's pretty simple.

Depending on what version of DX you're using you could also take advantage of geometry shaders.

I have a shader where I pass in one field for position and the uv's. Based off the uv I calculate the position for each vertex so the object faces the camera. Flexability is the reason for custom vertex fomating.

I'd also recomend pushing everything to the GPU you can. It's much faster than the CPU.
Okay, so a couple of questions:
1.) If you're trying to just the same geometry with the corner's raised, why don't you just translate the cube up by one and draw it again? Or have it scaled?
2.) If you're trying to get a different texture bound to the same cube, why don't you just set a new texture?


I know you're trying you're trying to save performance, if you're having a problem drawing sixteen cubes with sixteen different textures and a sprite quad with it's own texture, there may be a very big problem. Make sure you're not swapping textures when you don't need to and that you're not changing shaders too frequently, try caching them.

As for your actual question:
You could accomplish this if you make your index buffer large enough to contain all the possible permutations you're speaking of, then just offset the start index as needed. This will essentially create multiple index buffers, though you'd need to do multiple draw calls, but at least you wouldn't be sending redundant data (well not as much)
Perception is when one imagination clashes with another
A1) Sorry, I was unclear. If the cube is to be a literal cube then I would simply elevate it and use shape zero:
Shape Zero - All corners same height
Shapes One and Two - Opposite corners elevated (two corners elevated)
Shape Three - Billboard sprite?
Shapes Four thru Seven - A single corner raised
Shapes Eight thru Eleven - Two adjacent corners raised
Shapes Twelve through fifteen - Three corners raised

A2) It would defeat the purpose of the design. Every texture set is a possibility for re-uploading. If any re-upload occurs it means that there's going to be constant re-uploading, since it means that an upload is moving something else out of the way that will need put back next frame, etc.

As for whether or not I'm having performance problems - no. This isn't even implemented yet. I'm trying to figure out how to do it first. While it would indeed indicate a serious problem if a couple cubes and quads were lagging, I'm looking at establishing a base for scalability and also I'm considering building a system like this on a device-native SDK for a device that only has around 2MB of vram. (Now that I'm thinking about it I could do this so much more easily on that device's SDK that it's not even funny.)

As for using the product of the index buffers, that wouldn't work, since the index in the buffer must refer to a vertex in the vbuffer. Using the product of the vbuffers would cause exponential scalability.
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.
The index value in the index buffer must refer to a vertex yes, but the start index (the one you specify when you call DrawIndexedPrimitive), doesn't necessarily have to correspond to a vertex, it's the the starting point in the buffer.

So if you had a vertex buffer with vertices: A-B-C-D-E-F-G-H
And you had an index buffer with indices: 0-1-2-1-2-3 (quad represented by A-B-C-D) and 1-2-3-2-3-4 (quad represented by B-C-D-E) and 5-6-7-6-7-5 (quad represented by E-F-G-H) you could bind the vertex buffer only once, and the index buffer only once. Then as you draw your primitive you move your start index to the index that defines the beginning of the desired quad, and only draw as many verts as you need. This essentially culls out and draws as needed the verts you want.

Your index buffer can specify and very in the buffer, so you can choose raised or unraised verts as needed to draw, and you'd never have to set another resource. Sorry if I'm not explaining this correctly.
Perception is when one imagination clashes with another
I follow what you mean (sorry for the long delay, I have only occasional net access). What I'm saying is that the index sequence for all desired renders would have to be entered into the index buffer. Adding to one or the other vertex stream sets would cause multiplicative growth, etc. Looking at your earlier post I think you know what I mean by that. I'm just trying to theorycraft the system to determine whether or not it's possible to implement or if I should just stick with "old-fashioned" rendering.
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

This topic is closed to new replies.

Advertisement