Sign in to follow this  
genesys

Stencil Shadows - please help me..

Recommended Posts

genesys    133
Hi! i implemented stencil shadows in my little engine and they're finaly working... now i have two problems: 1.) it's slooooooooow! :( my process is the following: on startup, i store for every edge of a triangle its neighbour triangles on runtime, i do in every frame (since the light source is moving): -step1: loop through all faces and calculate, wether they are lit by the lightsource -step2: loop through all lit faces { loop through all three edges of the current lit face { if there is no neighbourface or the neighbourface isn't lit{ take the two vertices of the edge and calculate two more vertices by adding the lightvector to these two points; store all four points as quad in a list;}}} -step3: loop throug all quads and draw them to the stencil buffer (incr) using glBegin(GL_QUADS) and cull_face set to GL_BACK -step4: loop again through all quads and draw them to the stencil buffer (decr) using glBegin(GL_QUADS) and cull_face set to GL_FRONT -step5: draw a big black quad to the screen using the stencilbuffer as mask ... this i do in every frame . . . it's really slow - i'm already using shadow LOD (each shadow LOD model has between 30 and 50 triangles) is there anything i can improve or do differently to improve the performance?? result: http://neo.cycovery.com/stencil_problem1.gif 2.) the shadow shape is visible at this place, where the shadow volumes end: http://neo.cycovery.com/stencil_problem2.gif i understand why this effect appears, but i don't really know, what i could do against it (without decreasing the performance even more...) If somebody could help me on that or give me some hints, i'd really appreciate it! thanks a lot! [Edited by - genesys on November 27, 2006 12:46:47 PM]

Share this post


Link to post
Share on other sites
CyberSlag5k    514
Quote:
2.)
the shadow shape is visible at this place, where the shadow volumes end:
http://neo.cycovery.com/stencil_problem2.gif
i understand why this effect appears, but i don't really know, what i could do against it (without decreasing the performance even more...)


Just a shot in the dark here, but couldn't you just clip the shadow ends out down there? It looks like they're being rendered far below your map...

Share this post


Link to post
Share on other sites
genesys    133
by caping you mean to trace for every quad the distance to the next object in lightvector direction and use this distance to calculate the length of the quad?

i'm afraid that this decreases my performance even more . . .

Share this post


Link to post
Share on other sites
paulshady    100
Quote:

by caping you mean to trace for every quad the distance to the next object in lightvector direction and use this distance to calculate the length of the quad?


whooooa, that sentence just blew my mind....

take a look at this page:
http://www.codesampler.com/oglsrc/oglsrc_8.htm#ogl_shadow_volume

maybe youve already been there, maybe not, itll probably give you some insight anyways

Share this post


Link to post
Share on other sites
genesys    133
thanks for the link - but this sample is way too basic . . . my stencil shadows work - they'r just terribly slow :(

would it maybe make sense to use Vertex Arrays for the shadow volume? the vertices have to be calculated in every frame again and the count of vertices can change from frame to frame, that's why i think vertex arrays won't help me here. the same thing for display lists... since the shadow volume changes in every frame i'd have to compile the display list once per frame - i don't think this would increase the performance although i have to draw the shadowvolume twice per frame and could call the compiled displaylist when drawing it the secound time . . . or do you think a display list would help me?

Share this post


Link to post
Share on other sites
paulshady    100
maybe the answer is actually in your question...

it's slow.....why could it be slow?

judging by your second image the lightsource appears to be the sun.
you say "the light source is moving".....but shadows that the sun casts dont typically move noticeably all the time. Maybe you should do all these "COMPLEX" calculations once every 1000 frames or maybe 10,000 frames.

...

Another possible solution would be to consider another method besides shadow volumes to create shadows for buildings and other static objects. I doubt that commercial games with big citys employ a method like the one your using to shadow TONS of buildings in a city.



not trying to bash your idea or anything because i actually think the images you posted look pretty good. i would like to hear your thoughts on my feedback too.

good luck

Share this post


Link to post
Share on other sites
genesys    133
Hi paulshady

The sun is moving verry fast.. 1 minute = 1 day.

You are right, that an image based shadow approach will create faster results and maybe is more clever for a big city...

But i'm writing an engine and this city is only one application for it - i want to make it able to serve for different needs, so i want to implement stencil shadows as performant as possible. That's why i'm asking...

at the moment it's running at 15 frames... i think one big problem is, that i have to send single GL_QUADS calls to openGL... maybe an idea how i could achieve it with less calls?

Share this post


Link to post
Share on other sites
Digitalfragment    1504
Quote:
i think one big problem is, that i have to send single GL_QUADS calls to openGL... maybe an idea how i could achieve it with less calls?


You're not using immediate rendering are you? That would be pure evil.

Either way, you might find it faster to batch up your geometry into a single buffer, and then push that buffer as a quad vertex-array in a single shot when its full, or when you are finished. This way you wont be sending individual quads, but instead a single stream of data which the GPU will be able to consume much quicker.

Share this post


Link to post
Share on other sites
paulshady    100
ive done something like this before:

struct VERTEX_BUFFER
{
VECTOR3 position; //VECTOR3 is 3 floats
} * VertexBuffer;

For shadow volumes i think youll probably only need the position, otherwise you can fill up your struct with whatever else you want (UV Coords, Normals, etc...)

Anyways, put your entire list of shadow volume data in the VERTEX_BUFFER thingy.

Once you do that OGL allows this:

glInterleavedArrays( GL_V3F, 0, myMesh.VertexBuffer );
glDrawElements( GL_TRIANGLES, listSize, GL_UNSIGNED_INT, &VertexBuffer );


I definitely prefer these calls over the GlBegin() glEnd() stuff.
Let me know if youve used them before. also please don't correct my OGL syntax, i realize it might not be entirely accurate because i mainly use DirectX.


Share this post


Link to post
Share on other sites
RAZORUNREAL    567
I'll tell you what I do. It's not the fastest, but it's fairly quick (as in runs ok on a 1ghz pc with a geforce 2 mx). Memory usage wasn't really a problem in my case, I just tried to keep the cpu and gpu usage down.

Firstly, I used a better algorithm to generate the shadow volumes. Not really a performance thing, more of a robustness thing, but here's a paper.

Secondly, you mentiond GL_QUADS. If that's how you're constructing your shadow volumes, then that may be your problem right there. What I do is create a vertex array for twice as many vertices as my object actually has. In the first half I put the objects vertices, and in the second half I put them in extruded in the light direction. It would probably be better to work out which vertices need extruding, but I'm not sure if that would be faster or not, and memory wasn't an issue.

Next, you construct an index array for rendering your shadow volumes. I'll assume depth fail here. First thing is the front cap. Just find every triangle in the model that faces the light and add it into the index array. Then the back cap (should fix your artifacts). Add them all in again, but this time swap the winding and offset the indices so that they point to the second half of the vertex array. Finally, the hard part, the sides of the volume. Go through all the edges that need extruding, and add a couple of triangles that make up a quad between those two vertices and the corresponding vertices in the second half of the array. Make sure the winding is such that they face "outwards".

Finally, we can draw the shadow in just two calls, once to draw front faces and once to draw backfaces. Your graphics card will thank you.

If you're actually fillrate limited, then that's a bit trickier. See if you can reliably get the shadow volumes to only go just through the ground. If you have a ground plane that's always at the same height that shouldn't be tooo hard. Also, make sure your volumes are actually optimal, and you're not treating every edge as an extruded edge or something.

Share this post


Link to post
Share on other sites
genesys    133
Thanks a lot for all your suggestions!!

@Exorcist: yes - at the moment i'm using emmediate rendering - that's why i told that it meight be a problem. I just was afraid that building a vertex array in every frame would be more consuming than sending each quad. but it seems that i was wrong! So your suggestion is, that i build the vertex array in every frame and then send it (somehow - i have to learn how first) to openGL? this leads me to another (for me) important question: For my static objects (buildings) i use display lists. When i compile them, i use immediate render calls (glBegin-glEnd) between glNewList(name, GL_COMPILE) - glEndList. Would it make sense here too to create a vertex array within this glNewList-glEndList call?

@paulshady: Till now i tried to avoid Vertex Buffer Objects because i heard that they are verry hardware dependant - and my job is to make an engine which is cross-platform and works on as many computers as possible... one limitation is, that i shouldn't go beyond openGL 1.5.. i think VBO's are part of 1.5 - so do you think my doubts are without any reasons? if it's really no problem and VBO's will do the trick then i'll stick to them...

@RAZORUNREAL: aaaah! now i understand what 'capping' is :) thanks a lot for this article! do you also think that it would be best to build a vertex array

Share this post


Link to post
Share on other sites
esr_ever    130
Just forget using vertex arrays in display lists, read a tutorial for both, their differences & their uses, & you will see why..You're better off using VBOs for static objects, as long you don't have enormous amounts of data! Also nvidia has a very nice tutorial about stencil shadows & reflection, check(google) it out!!

Share this post


Link to post
Share on other sites
genesys    133
I don't think that VBOs help me at all, since the vertex data changes in every frame (not only position, also count) so I have to upload it to VRAM again and then it's speed is the same (or maybe even less?) as with vertex arrays . . .

Share this post


Link to post
Share on other sites
paulshady    100
genesys - you mention that you don't want to use VBO's....I could be wrong, but i don't think these calls use Vertex Buffer Objects

glInterleavedArrays( GL_V3F, 0, myMesh.VertexBuffer );
glDrawElements( GL_TRIANGLES, listSize, GL_UNSIGNED_INT, &VertexBuffer );


you should prefer calls like these over sending hundreds of vertex3f calls over and over anyways.....i think that style is just for really new opengl users.....again, i could wrong

Share this post


Link to post
Share on other sites
genesys    133
paulshady:

yes - i do it that way now . . . at least i think so - i'm using glVertexPointer instead of glinterleavedarrays and then i use glDrawArrays - and the performance is better now . . .
thanks!

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