Vertex Shader [SOLVED]

Started by
18 comments, last by RobM 15 years, 8 months ago
I thought I'd start a new post as my previous one got a bit confusing. I've hunted high and low on the net and still can't find a way to do what I'm trying to do. Here's what I'm using and trying to do: DirectX 9, vs_3_0, c++ I have a vertex buffer full of single floats (y values) and one full of single float pairs (x and z values). The second buffer, having pairs of floats is twice as big as the first. I'd like to combine these two buffers as input into the vertex shader in order to create the position vector. This is essentially to save memory for my terrain which has an overall size of 4096x4096 with about 5 levels of detail. Could someone please show me how the vertex declaration should look for this setup? I've tried loads of different configurations and DirectX complains at most of them. If I use D3DDECLUSAGE_POSITION, it complains that the D3DDECLTYPE_ should be a FLOAT3 which won't work in my case. If I don't use D3DDECLUSAGE_POSITION for the usage (e.g. using something like D3DDECLUSAGE_TEXCOORD), it complains with this error: "Declaration can't map to fixed function FVF because position field is missing. Usage: D3DDECLUSAGE_POSITION, with usage index 0 is required for fixed function" This is confusing for a start, because I thought I was trying to use the programmable pipleline - both my vertex buffers are created with zero as the FVF parameter specifying them to be NON-FVF buffers. If I were to use D3DDECLUSAGE_POSITION and D3DDECLTYPE_FLOAT3, is there some way that, for each vertex, I can some how only pass in one float for the first stream and 2 floats for the second stream? I don't mind if I get two FLOAT3s into my vertex shader like this: first stream input: FLOAT3 - x = <actual correct y value> y = 0 z = 0 second stream input: FLOAT3 - x = <actual correct x value> y = <actual correct z value> z = 0 I can then just extract the floats out and create a new vector in the vertex shader. I'm 100% sure I've heard of this being done before, but I can't seem to find a way to do it. If anyone can shed any more light, I'd be eternally grateful - I've been banging my head about this for over a week now. I did have a couple of useful replies about this before, but they didn't work. Thanks in advance [Edited by - RobMaddison on July 31, 2008 2:38:38 PM]
Advertisement
I've not seen/read your previous thread, but I've definitely implemented nearly this exact same code myself at some point in the distant past.

Quote:"Declaration can't map to fixed function FVF because position field is missing. Usage: D3DDECLUSAGE_POSITION, with usage index 0 is required for fixed function"

This is confusing for a start, because I thought I was trying to use the programmable pipleline
Yes, I wouldn't be expecting that message. Maybe dig into PIX to see what state the pipeline is in - it may well be that with your order of pipeline configuration that it thinks you're using FF and later tell it otherwise. Or something silly like that.

Off the top of my head (don't have my old code to hand) the trick was creating two streams, one with a <D3DDECLUSAGE_POSITION, usage=0, size=float> and a <D3DDECLUSAGE_POSITION, usage=1, size=float2> and then the declaration in the VS can be something like:

struct vsi{    float y : POSITION0;    float2 xz : POSITION1;    // ...};vso vs( in vsi vertex ){    float3 pos = float3( vertex.xz.x, vertex.y, vertex.xz.y );    // ... }



If that fragment doesn't yield anything, can you post your declarations - both app and shader side?

hth
Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

Just off the top of my head, have you tried setting stream zero as D3DDECLUSAGE_POSITION with a float3 type containing (x,z,0) and stream one as D3DDECLUSAGE_TEXCOORD with a float type containing (y)?
inherently interactive - my game design blog
Thanks for the quick responses guys.

Quote:
Off the top of my head (don't have my old code to hand) the trick was creating two streams, one with a <D3DDECLUSAGE_POSITION, usage=0, size=float> and a <D3DDECLUSAGE_POSITION, usage=1, size=float2> and then the declaration in the VS can be something like:


Jack, that doesn't quite work in my configuration as when using POSITION as a usage, it requires a size of FLOAT3. Here is my exact usage at the moment:

D3DVERTEXELEMENT9 declTerrainXYZ[]={  {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},  {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 1},  D3DECL_END()};


When I call the DrawIndexPrimitive method using this declaration, I get

"Declaration can't map to fixed function FVF because position must use D3DDECLTYPE_FLOAT3". Here is the very simple shader fx file I'm using:

struct V_To_P{  float4 Position : POSITION;  float4 Color : COLOR0;};float4x4 xViewProjection;V_To_P SimpleVertexShader( float1 y : POSITION0, float2 xz : POSITION1){  V_To_P Output = (V_To_P)0;  ....  return Output;}technique Simplest{  pass Pass0  {    VertexShader = compile vs_3_0 SimpleVertexShader();    PixelShader = NULL;  }}


Here is the code to draw the primitives:

D3DXHandle technique = effect->GetTechniqueByName("Simplest");D3DXHandle matrix = effect->GetParameterByName(0, "xViewProjection");hr = effect->SetTechnique(technique");hr = effect->SetMatrix(...);hr = DXUTGetD3DDevice()->SetVertexDeclaration(<as above>);hr = DXUTGetD3DDevice()->SetStreamSource(0, <vertexbufferwithsinglefloats>, 0, sizeof(float));hr = DXUTGetD3DDevice()->SetStreamSource(0, <vertexbufferwithfloatpairs>, 0, sizeof(float) * 2);hr = DXUTGetD3DDevice()->SetIndices(<regular indices>);// then simple beginpass, drawindexprimitive, endpass, etc


Tim, if I specify FLOAT3 for both elements and use usagetypes of POSITION, it doesn't error, but how would I specify that my first FLOAT3 is only (x, y, 0) and the second is only (x, 0 ,0)?

Thanks guys, I'd really love to get to the bottom of this.
When you create the VBs you need to fill them with 3 floats, either using three seperate floats or using a D3DXVECTOR3. Not quite sure how to describe it, this isn't my dev machine and I don't have any code here. I'm geussing you define a struct for your vertex data, fill an array of them and then memcopy into your VB. In this struct you need the three floats instead of one or two, when you fill in the instances of this struct in the array you set the unused values as 0.

Also you don't necessarily need to use FLOAT3 for texcoord, which is why i suggested it instead of position1, you can definately use FLOAT2, and i think you might be able to use just FLOAT.

Lastly, in your set stream source calls, the first parameter of the first call should be 1, not 0.
inherently interactive - my game design blog
Quote:Original post by RobMaddison
Jack, that doesn't quite work in my configuration as when using POSITION as a usage, it requires a size of FLOAT3.
I did a bit of reading around on MSDN and I must be remembering my code wrong for exactly the reason you state. I am left wondering whether I just used TEXCOORD fields instead - they're about the only 'free form' field you can use with D3D9 as the rest all have quite strictly defined semantics.

It's been quite a while since I did any D3D9 work, but can you try your code using TEXCOORD instead of POSITION? A straight up substitution should suffice and the test will be whether the runtime throws a wobbly over not having a POSITION...

Quote:if I specify FLOAT3 for both elements and use usagetypes of POSITION, it doesn't error, but how would I specify that my first FLOAT3 is only (x, y, 0) and the second is only (x, 0 ,0)?
I'm pretty sure you can't - the IA stage would just lump through two float3's and you'd just burn the extra storage and bandwidth.

hth
Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

Hi Tim

Thanks for spotting the error in the SetStreamSource line, although that was a typo as my code is on my dev machine.

I see what you're saying about putting FLOAT3's (or vectors) into the vertex buffer, but the whole point of this exercise for me is to cut down on memory by reusing the x and z coordinates of each terrain patch as they are regular grids. The heights are individual and need to be stored in a buffer on their own. If I store 3 float vectors in the buffer, then I may as well store the x and z too in the unused parts. This would take up too much memory though, as my terrain at the highest LOD level is made up of 4096 65x65 patches.

Using the method I'm aiming at, the y values for the entire terrain would take up:

65x65 (verts) = 4225 total verts per patch
4225 x 4 bytes (y value float) = 16,900 bytes
16,900 x 4096 (patches) = 69.2mb

the x and z coordinates would only need to be stored for one patch - when drawing, they'll just be translated to the correct positon.

This is a totally acceptable amount of memory for what I need, but if I have to add the x and z into the mix, my vertex buffer(s) grow to over 200mb which I can't afford. Does that help to explain what I'm trying to achieve better?

Thanks
Hi Jack

I tried using TEXCOORD instead of position and yes, it complains that it should have a POSITION:

"Declaration can't map to fixed function FVF because position field is missing. Usage: D3DDECLUSAGE_POSITION, with usage index 0 is required for fixed function"

(I had also changed the shader file to use TEXCOORD0 and TEXCOORD1 as the inputs).

It would appear to me that my engine somehow things I'm tryin to use the fixed function pipeline. Is there a way to tell which I'm using? I'm currently using the DXUT libraries just to get things up and running. If there's a "SetDeviceToUseFVF" or something similar I can just do a search for it in my code.

Thanks again for your input, it is much appreciated.
OK sorry about that then, I thought there was some other reason you needed them seperated over two buffers. In that case I think you might want to look into hw instancing, if your target hardware supports it. I can't remember how to do it without looking at my old code, but the DX SDK has some pretty good info about it. The basic premise would be to still use FLOAT3 for the position with an empty value, also still use texcoord for the y's. However, you should be able to send one patch of position data and multiple patches of height data and tell d3d to draw multiple copies of the position VB. I'm not 100% sure this will be possible in this case. The way I did it was to have stream 0 contain the position VB, stream one contain a second position which was an offset for the whole patch and then store the height information as a texture using VTF. The problem is you will need three streams, each with a different stride, one for (x,z,0), one for patcht offset and one for height data. I know its designed for two, but I'm not sure about three, the docs will probably mention it.
inherently interactive - my game design blog
Tim

I believe you might be onto something here. If I put the FLOAT3 POSITION value first, that satisfies DX's need for it and my repeated xz values can just have a dummy 0 value added for the y - I can then hopefully make the second stream just use TEXCOORD with FLOAT1.

I'll let you know how I get on, thanks.

Rob

This topic is closed to new replies.

Advertisement