Archived

This topic is now archived and is closed to further replies.

Funkymunky

simple vertex shader stuff

Recommended Posts

Funkymunky    1413
Hey, I'm trying to get into this whole shader business, but I'm confused. All I want this one to do is set the diffuse color to green // setup shader DWORD dwDecl[] = { D3DVSD_STREAM(0), D3DVSD_REG(0, D3DVSDT_FLOAT3 ), //input register v0 D3DVSD_REG(5, D3DVSDT_D3DCOLOR ), // input register v5 D3DVSD_REG(7, D3DVSDT_FLOAT2 ), // input register v7 D3DVSD_REG(8, D3DVSDT_FLOAT2 ), // input register v7 D3DVSD_END() }; // the vertices im using use(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX2) // set constants FLOAT fMaterial[4] = {0,1,0,0}; d->SetVertexShaderConstant(5, fMaterial, 1); // define shader const char BasicVertexShader[] = "vs.1.1 \n""mov oD0, c5 \n"; // create shader ID3DXBuffer *pVs; DWORD shader; D3DXAssembleShader(BasicVertexShader, sizeof(BasicVertexShader) - 1, 0, NULL, &pVs, NULL); d->CreateVertexShader(dwDecl, (DWORD*)pVs->GetBufferPointer(), &shader, 0 ); d->SetVertexShader( shader ); // end I do all of that in the initialization function, if that helps. It doesn't change a damn thing. PS - there is a backslash in between the vs.1.1 and the mov instructions, but the forum erases it. Just so you know it's not that. [edited by - Funkymunky on January 5, 2004 10:22:23 AM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
SetVertexShaderConstant passes the color to an constant register (c5 in your case). You don''t need to hand-pass the color to the shader, if you want to use the color, stored in your vertex-buffer. Just map the color to an input-register of you choice. That''s at least, how it works in DX9.

Hope this helps. ;-)

Share this post


Link to post
Share on other sites
Funkymunky    1413
Ok, but shouldn't what I wrote work? And I don't necessarily want to use the color in the vertex buffer, because what would be the point of using a shader at all then? I'm just trying to get it to alter something.

quote:
Just map the color to an input-register of you choice

What's that, like since i called D3DVSD_REG(5, D3DVSDT_D3DCOLOR), use "mov oD0, v5" ?

Again, I'm just trying to get a grasp on them, and since the one I posted doesn't do anything even though I thought it would, I was hoping for some insight.

But thanks! any more help?



PS - if you guys think it should work too and that's why you aren't posting, then let me know that! Right now it seems like noone knows vertex shaders

[edited by - Funkymunky on January 5, 2004 10:15:53 AM]

Share this post


Link to post
Share on other sites
Your shader is too simple. Your shader must do everything the fixed pipe did that you want to replace.

You''ve set the color just fine, but you never set the output vertex position, or texture coordinates. Also if you''ve got blending enabled you might want to change the alpha from 0.

Take your world, view, and projection matrices, mutltiply them, transpose the result and put in into some constants.


D3DXMATRIX wvp, wvpt;
wvp = world * view * projection;
D3DXMatrixTranspose(&wvpt, &wvp);
dev->SetVertexShaderConstant(0, &wvpt, 4);


Ideally you''ll merge that set constant call with your color one, as this function actually runs incredibly slowly.

Now you''ll make some additions to your shader. We want to multiply your vertex by world, view, projection. We''ll move the color as you had it. We''ll move the texture coordinates down the pipeline too, without texture coordinate transforms, just simply passing them along.


"vs.1.1\n"
"dp4 oPos.x, v0, c0\n"
"dp4 oPos.y, v0, c1\n"
"dp4 oPos.z, v0, c2\n"
"dp4 oPos.w, v0, c3\n"
"mov oD0, c5\n"
"mov oT0, v7\n"
"mov oT1, v8\n"


Hope this helps.

Share this post


Link to post
Share on other sites
Funkymunky    1413
Damn, well at least it did something...now nothing is drawn. I figured out that I had a SetVertexShader call already, using my FVF flags. I hadn''t realized I''d been using this all along. That''s why nothing was being changed, i wasn''t even applying the vertex shader.

So, I have to keep track of my three matrices at all times if I want to use Vertex Shaders? Do I need to update the vertex shader each frame?

Thanks, that helps a lot, but i''m still quite confused!

Share this post


Link to post
Share on other sites
Yes, you need to keep track of your matrices at all times. You might have your view and projection matrices in a camera class, and you might have a global pointer to the current camera. You might also have view*projection already computed, once per frame (or camera move), do reduce the number of matrix multiplies you need. In more complex shaders you may want world, view, and projection as seperate matrices, for such things as lighting, and texture coordinate generation.

I don''t think you need to set the shader each frame if you haven''t changed shaders/fvfs, but it won''t hurt. Generally I treat a new frame as if it''s from scratch. I set textures, shaders, render states to some default known value each frame, or just mark my currently cached values as invalid. Then I skip redundant textures, shaders, and states for the rest of the frame. Nothing can get too screwed up that way.

The SDK has a some samples using shaders... Maybe it would be a good place to check for whatever else you''re missing.

Share this post


Link to post
Share on other sites
Funkymunky    1413
Damn. Alright that helps, but it still doesn''t draw anything!

now it''s like this:

first these are private variables in the class:


ID3DXBuffer *pVs;
DWORD shader;


and this is in the initialization function, called once


// setup shader

DWORD dwDecl[] = {
D3DVSD_STREAM(0),
D3DVSD_REG(0, D3DVSDT_FLOAT3 ), //input register v0
D3DVSD_REG(5, D3DVSDT_D3DCOLOR ), // input register v5
D3DVSD_REG(7, D3DVSDT_FLOAT2 ), // input register v7
D3DVSD_REG(8, D3DVSDT_FLOAT2 ), // input register v7
D3DVSD_END()
};

// transformation stuff

D3DXMATRIX w, v, p;
d->GetTransform(D3DTS_WORLD, &w);
d->GetTransform(D3DTS_VIEW, &v);
d->GetTransform(D3DTS_PROJECTION, &p);
D3DXMATRIX wvp, wvpt;
wvp = w * v * p;
D3DXMatrixTranspose(&wvpt, &wvp);

// set constants

FLOAT fMaterial[4] = {0,1,0,0};
d->SetVertexShaderConstant(5, fMaterial, 1);
d->SetVertexShaderConstant(0, &wvpt, 4);

// define shader

const char BasicVertexShader[] =
"vs.1.1 \n"\
"dp4 oPos.x, v0, c0\n"\
"dp4 oPos.y, v0, c1\n"\
"dp4 oPos.z, v0, c2\n"\
"dp4 oPos.w, v0, c3\n"\
"mov oD0, c5\n"\
"mov oT0, v7\n"\
"mov oT1, v8\n";

// create shader

if(D3DXAssembleShader(BasicVertexShader, sizeof(BasicVertexShader) - 1, 0, NULL, &pVs, NULL) != D3D_OK)
return false;
if(d->CreateVertexShader(dwDecl, (DWORD*)pVs->GetBufferPointer(), &shader, 0 ) != D3D_OK)
return false;



and here''s the basic render loop


d->SetStreamSource(0, vbuffer, sizeof(LandVertex));
d->SetVertexShader( shader );
d->SetIndices(ibuffer, 0);

d->SetTexture(0, texture);
d->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, numverts, 0, numtriangles);
d->SetTexture(0, NULL);





shouldn''t that work?!

Share this post


Link to post
Share on other sites
quote:
Original post by Funkymunky
Damn. Alright that helps, but it still doesn't draw anything!

now it's like this:

...
d->GetTransform(D3DTS_WORLD, &w);
d->GetTransform(D3DTS_VIEW, &v);
d->GetTransform(D3DTS_PROJECTION, &p);
...



Hmmm. Looks okay. Does you card support shaders? Do the creation calls succeed or fail? Are you using a pure device? The get functions above won't work if it's pure. Have you actually set all 3 matrices? Often, people set world in their render routine. Since you're replacing your render routine with a new one, do you still set the world matrix? And as I pointed out at the beginning, if you've got alphablending or alphatesting enabled you might have trouble since you set the alpha to 0.

Now this next part isn't going to solve your problem, but... D3D no longer needs the world or view matrices to be set using SetTransform(), only the shader needs them. D3D needs projection to be set only for fogging to work correctly. Again, it doesn't hurt to pass them to D3D, but it's not strictly necessary... As such, using GetTransform() is a bad way to code this, as it means you MUST give the transforms to D3D even though it doesn't need them, and it means you cannot use a pure device.

edit:

Noticed you're only building and setting the constants at init time. Are ANY of your 3 matrices set up at this point? Building and setting the matrices are both typically part of the render loop.

[edited by - namethatnobodyelsetook on January 5, 2004 2:38:28 PM]

Share this post


Link to post
Share on other sites
Funkymunky    1413
Yes my card supports shaders.
The calls succeed.
Whaddya mean a pure device? i created it with

d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &device);
(standard stuff)

yes I set all three matrices. I only make the projection and world matrices once in initialization (before initializing the object which uses the shader) and I update the view matrix each frame through my camera object.

No alpha blending.

Share this post


Link to post
Share on other sites
Ok, you''re not using a pure device (it would go where you have D3DCREATE_SOFTWARE_VERTEXPROCESSING).

I''ve never used a shader in software mode. Either create a hardware device, or try D3DUSAGE_SOFTWAREPROCESSING in your CreateVertexShader() call, and see if that fixes anything... Preferably changing your device to hardware, since I don''t know how the software shader emulation works.

Since you''re setting your view matrix per frame, you still need to move your "w*v*p calculation, transposing, and programming into constants" code, into the render loop.

Share this post


Link to post
Share on other sites
Funkymunky    1413
Alright, changed to a hardware processing device, still doesn''t display anything. I haven''t moved the code to the rendering loop yet because it should still work until I actually move the camera. Nothing is drawn.

Share this post


Link to post
Share on other sites