Sign in to follow this  
solenoidz

Rejecting triangles in vertex shader

Recommended Posts

Hi, I need to find a way to reject certain triangles in the vertex shader. For example if I find a vertex match a criteria I wish to reject it (and also the other 2 forming that triangle). Now I send the vertex far away from the camera like this
if (in.Position.y < 0.0f ) in. Position,xyz = 1000.0f ;


The problem is, that not all the verices of a triangle could have Position.y < 0.0 and if not all of the vertices arent moved away from the camera of course very long, streched and annoying triangles appear [pig] How can I reject a triangle in the vertex shader, if I find one of the verices match certain criteria ? As a side question, can I get a calculate a value in a shader program and send it back to the application ? I tried something like this :
   
float fmyGlobalShaderFloat ;
vertex shader (...)
{
  fmyGlobalShaderFloat = something ;
}

and in the application 
float f ;
effect->GetFloat("fmyGlobalShaderFloat" , &f ) ;



but that doesn't work obviously.

Share this post


Link to post
Share on other sites
What API are you using? DX9? DX10 and above? XNA?

You can't reject triangles in the vertex shader. You COULD in the geometry shader, though. What you can do is pass your criteria along to the pixel shader use clip() ... (anything under 0 means the pixel is rejected... say clip(-1)

I am not sure how things work in XNA, but in DX9, 10, etc. you have an interface for effect variable(s) that remains CPU side, but they're paired off with variables in the shader by either name, semantic, or index. Then you can use SetFloat() (or whatever) and it will set the value in the shader, and GetFloat() will retrieve the value, I believe.

Other ways to output data from shaders include writing to buffers and textures and then calling map or lock for the GPU to access it. These buffers / textures should have been created with the flags allowing CPU access.

Share this post


Link to post
Share on other sites
A vertex shader sees only one vertex at a time, so it cannot read any data from the other vertices of the primitive it belongs to. However, geometry shader does deal with primitives (assembled triangles, lines or points) and you can choose to either pass thru, amplify or reject said primitives.

Prior to shader model 5 (D3D11 hardware), you cannot modify constant buffer contents within a pixel shader. Therefore, setting a "global" (that you can read back from the GPU) within a shader won't work with just any hardware.

SM5 introduces a concept called Unordered Access buffers to which you can arbitrarily write from within pixel shaders or compute shaders. Actually, some SM4 hardware is also capable of this, but with very limited features compared to SM5 hw.

On older hardware, you have to render your data and read the rendered result to the system memory in order to access pixel shader results with the CPU.

It is conceivable that the UA writing is implemented similarly to rendering. However, direct UA writes can bypass a lot of sub-ops related to rendering, which gives better performance.

Share this post


Link to post
Share on other sites
I found a good example for the GeoShader method:

http://wiki.gamedev.net/index.php/D3DBook:Managing_Level_of_Detail

Its right in the middle of the page :)

Share this post


Link to post
Share on other sites
A long while back I implemented a technique for rejecting triangles based on some visual information. The method was used for generating silhouette geometry to outline an object in an NPR style rendering.

The key is to modify the position of one vertex with respect to the other two vertices in the triangle such that the triangle becomes back facing. In this sense you are not really rejecting the triangle, but instead making it not affect the output rendering. There are many ways to do this, but it will likely depend on how flexible your vertex format is. In your case, it sounds like you should put all three vertex positions into each vertex. Then label one of them as the 'flyer' with a vertex attribute as well. Then in the vertex shader, you can test for the 'flyer' attribute, and if that vertex is a 'flyer' then check each of the vertices positions for the condition you mentioned above. If it fails (and you want to remove it) then use the position of the other two vertices to flip the flyer to the other side of them.

That should get the job done, but it will come with a heavy memory cost as well as some additional computation. If your geometry is small then it should work alright. However, as Niko mentioned, the Geometry Shader is the proper way to do this - if your hardware is capable, then use it!

Share this post


Link to post
Share on other sites
Thanks for the help to everyone.

I'm using DX9.0c at the moment, so no geometry shaders for me..
I think I'll go with a "mark" the vertex, pass the parameter to pixel shader and clip() or set alpha=0 approach.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this