creating dynamic shadow volumes

Started by
8 comments, last by shultays 14 years, 1 month ago
I found en example for creating shadow volumes, it works good but I am worried about its performance. My shadows are dynamic, light source is constantly moving I found that performance drop off is caused by DrawPrimitiveUP call, not actually calculating the shadow volume. probably the problem is transporting a very big data from ram to gpu in each frame. is there a better alternative? would filling a vertex buffer instead of using DrawPrimitiveUP help? [Edited by - shultays on February 25, 2010 9:59:45 AM]
taytay
Advertisement
Quote:Original post by shultays
probably the problem is transporting a very big data from ram to gpu in each frame.


Very big? How big? How many shadow volume triangles are you drawing per frame? Perhaps you are fillrate-limited and the GPU simply is slowing the application down as it struggles to draw your shadow volumes? Try setting the extrusion distance to something very small and see if it makes a difference.

Using a dynamic vertex buffer can make things faster, but for small data sizes, the difference is usually almost unnoticeable. I remember reading somewhere about some studio which used to use DPUP to draw all GUI elements and then had to switch to using dynamic VBs for compatibility reasons with some configurations and sited that no performance difference was noticed at all. I'm not so sure but I think internally the driver uses its own dynamic VB, so the only difference between using DPUP and using a dynamic VB is due to the additional step of copying the data, which brings us back to the question of how big the data is. Hope this helps.
What about using geometry shaders to generate the shadow volumes ?

http://http.developer.nvidia.com/GPUGems3/gpugems3_ch11.html
Amr0:

I tried with a rather complex model for testing. it is around ~1400 triangles. 3 floats per triangle so with 60 fps it is almost 1 mb per second.

is it too high? I am not sure what gpu is capable.

I thought vertex buffer could be better because instead of copying all data at once, it pushes new triangles to vb while computing other triangles. So gpu will not be idle while computing triangles. but this might be a stupid idea :)

and I think drawPrimitiveUP does not transfer triangles which are not visible on screen (behind the camera etc) because if I don't look at shadow volume fps is better. is it drawPrimitiveUP optimization or I screwed something?

nmi:

sorry, forgot to add. I am using directx 9. I wish I started to dx10, geometry shaders sound great.
taytay
You're supposed to find out which edges in the mesh are silhouette (outline) edges and then use those to construct and draw the shadow volume. Time for some layman math! For your 1400 triangle mesh, I imagine no more than 100 edges will be outline edges at any frame. 100 edges = 200 vertices. A shadow volume vertex is typically 12 bytes in size. So all in all you're looking at no more than 3KB worth of data, which is small, and using a dynamic VB for it will not produce any noticeable speed improvement.

Quote:and I think drawPrimitiveUP does not transfer triangles which are not visible on screen (behind the camera etc) because if I don't look at shadow volume fps is better.


The vertices are sent to the graphics card regardless of where they are in the world. Their visibility is determined only after they go through the vertex processing pipeline. This means that the slowness is not from calculating the shadow volume geometry or sending the data to the card, but from the card struggling to draw them. You either have quite the old card, or you're drawing triangles you shouldn't be drawing.
but my shader is pretty basic

float4x4 World;   float4x4 WorldViewProjection;struct A2V{     float4 Pos : POSITION;};struct V2P{    float4 Pos : POSITION;    };void VS_AMBIENT(in A2V IN, out V2P OUT){    OUT.Pos = mul(  IN.Pos , WorldViewProjection);  }float4 PS( in V2P IN) : COLOR0{    return float4(1.0, 1.0, 1.0, 1.0);}technique PointLight{        pass P2{        VertexShader = compile vs_1_1 VS_AMBIENT();        PixelShader  = compile ps_2_0 PS();                ZWRITEENABLE = FALSE;        ALPHABLENDENABLE = TRUE;        SRCBLEND = ZERO;        DESTBLEND = ONE;        STENCILENABLE = TRUE;        STENCILFUNC= ALWAYS;        STENCILPASS = KEEP;        CCW_STENCILPASS = KEEP;        STENCILZFAIL = INCR;        CCW_STENCILZFAIL = DECR;                        CULLMODE = NONE;        TWOSIDEDSTENCILMODE = TRUE;                STENCILFAIL = KEEP;        STENCILREF = 0x1;        STENCILMASK = 0xff;        STENCILWRITEMASK = 0xff;        CCW_STENCILFUNC = ALWAYS;        CCW_STENCILFAIL = KEEP;    }}


i am using two sided stencil test, if it is not supported it shouldn't draw at all right? or give some kind of error. maybe it is switching to software rendering?

how can I find the outline of the shape? is there a name for that technique?
taytay
Quote:i am using two sided stencil test, if it is not supported it shouldn't draw at all right? or give some kind of error. maybe it is switching to software rendering?

Direct3D will not automatically switch the rendering mode (HW/SW) regardless of the features you use.

Quote:how can I find the outline of the shape? is there a name for that technique?

Eh? That's at the center of the shadow volume technique, and if you're not doing that already, then what are you trying to render? I suggest you read up on the subject of shadow volumes or at least follow a tutorial or a sample application (though the sample that comes with the DirectX SDK is somewhat too complicated to start with). The shadow volume sample on codesampler.com may be a good start to get the basics going. Good luck.
What are your frame rates? Just curious.
can someone tells me what is wrong with shadow drawing? why it reduces my fps that much? my shader is attached in my previous post and my code for drawing shadows is
  Tools::D3DDevice->SetFVF( D3DFVF_XYZ );  D3DXMATRIX W1, W2;  D3DXMatrixScaling(&W1,size, size, size);  D3DXMatrixTranslation(&W2, coors.x, coors.y, coors.z);  W1 = W1*W2;  shadowEffect->SetMatrix( "World", &(W1));  shadowEffect->SetMatrix( "WorldViewProjection", &(W1 * (*View) * (*Proj)) );  shadowEffect->Begin(0, 0);  shadowEffect->BeginPass(0);  Tools::D3DDevice->DrawPrimitiveUP( D3DPT_TRIANGLELIST, m_dwNumVertices/3,                                        m_pVertices, sizeof(D3DXVECTOR3) );  shadowEffect->EndPass();  shadowEffect->End();



howie_007:

Actually it is not that bad, still playable. If I close vsync and render without shadows it is 70. with shadows it is 30-50 depending on how much of the shadow I see

Amr0:

I think I understood you wrong. for example lets say that there is a sphere with lots of triangles. What am I doing is finding every triangle that faces the light (which is =~half of the triangles) and using the edges of these triangles and create the rectangles that are used for shadowing. So there will be lots of rectangles, much more than the actual triangles in the sphere.

Didn't you mean finding the edges around the sphere? because in sphere example only a cylinder is enough for shadow volume, we don't need the triangles inside the sphere, just the ones that covers its edges.

I worked on finding the edges around the object. I am checking each triangle in the object, if its normal and dot of light is > 0 it is facing toward to light else it is facing backward. if a vertice is used in both forward facing and backward facing triangle then it is on the edge. if an edge's both vertices is like that I am converting it to a rectangle that goes to infinity and add it to shadow volume.

but it does not create a good closed volume and it gives lots of artifacts :/
taytay
whoops, my mistake. there is a much easier method for that. it simply removes the edges that are added more than once, which should be inside the object. Actually the example I was using implemented it but I understood that part wrong (I thought it was simply optimizing by removing extra edges) and removed it :D
taytay

This topic is closed to new replies.

Advertisement