Sign in to follow this  
Kohaar

Simple Shadows

Recommended Posts

Hi. I would like to create a simple shadow for my character. What I do is just render the character twice where one is transparent. picture1 picture1 As you can see on picture 1, the characters arm is darker than the rest of the body which make sense because the arm is in front of the body. What I would like is to make it look like picture 2, so before I look into stencil buffers and so on I would like to know if there are some blend or depth functions I can use so I get the right effect? Right now I use: glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); Any help appreciated

Share this post


Link to post
Share on other sites
hi

1st thing i would try is this:

turn off the depth buffer and then render the shadow. After that turn it on again. (i did not try this)

2nd

1. render the shadow only into stencil buffer and set the values in the stencil to value 1, like this (and don't forget to turn off the depth buffer):

glStencilFunc (GL_ALWAYS, 1, 0xFFFFFFFF);
glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE);

2. now render the shadow to screen with depthbuffer off and use the stencil buffer like this:

glStencilFunc (GL_EQUAL, 1, 0xFFFFFFFF);
glStencilOp(GL_KEEP, GL_ZERO, GL_ZERO);

this means that the shadow will be rendered only where stencil is 1 and after that it will be set to 0. So next time when som other polygon is rendered, that causes us trouble, there will be a zero in the stencil buffer. So it should not render and do the trouble. (but i did not try this).

3rd

i am working right now on shadows too. I need it, so if i won't have any problems i would like to finish it in one or two weeks and then i will put in public on my homepage http://xormultiplexus.googlepages.com/home. Maybe this could help you.

4th - trick
if the background on the picture is only a big polygon, then render the shadow to the stencil buffer and then render the shadow on the screen not with the mesh of the shadow but with the big polygon using stencil buffer.

Hope i helped somehow.

XorMultiPleXus

Share this post


Link to post
Share on other sites
I have tried both to set depth mask to false and disabling depth test, but neither seem to work/change anything. The reason I would like to use this approach with just rendering another model transparent is that it so much easier since the background only consists of a texture :-)
Also I have to finish the project in 2 weeks, and there is a lot to be done besides shadows, so it shouldn’t take to long.

Your fourth idea seems interesting. Could you explain this further, maybe with some pseudo code?

What I do now is:

Draw Background
Enable Light
Draw Character 1
Draw Character 2
Disable Light
Draw Character 1 transparent
Draw Character 2 transparent
...

Share this post


Link to post
Share on other sites
ok

here's the code:

//we enable stencil test
glEnable(GL_STENCIL_TEST);

//now we turn off the depth and color buffer, so we can render only to stencil buffer
glDepthMask(GL_FALSE);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

//we set this to render the mesh into the stencil buffer
glStencilFunc (GL_ALWAYS, 1, 0xFFFFFFFF);
glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE);

//RENDER THE SHADOW

//now we turn on the depth and color buffer
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);


//here I render only the shadow
glStencilFunc (GL_EQUAL, 1, 0xFFFFFFFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glColor4f(.5,.5,.5,0.5);
glBegin(GL_TRIANGLES);
glVertex3f(-300, -100, 0);
glVertex3f(300, -100, 0);
glVertex3f(0, 300, 0);
glEnd();

//and here the polygon
glStencilFunc (GL_NOTEQUAL, 1, 0xFFFFFFFF);
glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
glColor4f(.5,.5,.5,1);
glBegin(GL_TRIANGLES);
glVertex3f(-300, -100, 0);
glVertex3f(300, -100, 0);
glVertex3f(0, 300, 0);
glEnd();

glDisable(GL_STENCIL_TEST);

Here's the explanation:
1. render the shadow to the stencil buffer == easy
2. render the polygon to render the shadow with help of stecil buffer
3. render the polygon itself

My advice for you:
0. render background
1. place the shadow mesh in front of the background polygon
1. render the shadow to the stencil buffer == easy
2. render the the shadow with help of stecil buffer

That should work for you.

XorMultiPleXus

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
As I understand it you actually render the model 3 times.

One for the stencil buffer one for the shadow and one for the character?

The characters are bone animated and some of them have up to 20k polygons. I think this would be a little too expensive in computational power?

Hope you will bear with me if my questions seem extremely stupid :-)

Share this post


Link to post
Share on other sites
well, not.

You have to render the character and it's shadow. The shadow must be rendered into the stencil buffer. Then you render only the background polygon. Now you must render the shadow. Not with the character mesh, but with only one polygon. Take the background polygon. Translate it in front of the background (which is already rendered) and render it with stencil on. That will render the shadow.

Yes it is a little bit computational expensive. But today we have fast computers and even if you play today's games you can see, that they don't bother with effiecienci ;-D.

XorMultiPleXus

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Ok, So I do e.g. the following

Render the Shadow to stencil buffer
Render a "square" from stencil buffer on top of background
Render the Character.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Thanks. Your the greatest!

Now we are on the subject. Any easy way to create soft shadows this way :-)

Share this post


Link to post
Share on other sites
i haven't been working with soft shadows, but that does not means i won't in the future (in one or two months). I know only one way to do soft shadows - througth shaders. Look on www.nvidia.com. I have downloaded their sdk and there is a lot of shaders (in cg and hlsl) to create soft shadows and other kind of shadows and a lot of effects.

XorMultiPleXus

Share this post


Link to post
Share on other sites
well it's because i have an nvidia card in my computer and they have so many things for free to download. So i've decided to try it. I have also read the spec for OGSL, but i did not find there anything about shader model 3.0. I want to use shader 3 so i have decided to use cg instead of GLSL. But you know i could miss something. You can use whatever you want. Cg is not perfect. But i have a little practive with it so i use it. And HLSL only in the worst case, because i dont wont to use directx. So it depends on what you need and what you like.

XorMultiPleXus

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
As I understand it you actually render the model 3 times.

One for the stencil buffer one for the shadow and one for the character?

The characters are bone animated and some of them have up to 20k polygons. I think this would be a little too expensive in computational power?

Hope you will bear with me if my questions seem extremely stupid :-)


No twice....

Once you rendered into the stencil buffer you can use a quad that covers the entire screen to fill in the shading.

Share this post


Link to post
Share on other sites
Quote:
Original post by Kohaar
Just implemented it today, and the shadows work great. Thanks!

Now I just have to draw them in the correct perspective (from the light source).



No what you need to do is extrude each edge into infinite from the light's point of view, this gives you volume shadows which are more than simple. Problem with this is the complexity of finding which edges to extrude.

Ofcourse if you plan on rendering the scene into a texture from the light source and then using the technique of depth lookup for shadowing you will be fine. All though kinda doesn't make sense to have stencil buffer then.

Share this post


Link to post
Share on other sites
Couldn't you do it in one draw with something like:


// before frame
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

// draw shadow
glDisable(GL_DEPTH_TEST);
// setup normal blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// render only where stencil is 0 (all of it, initially), but as the character
// renders, pixels that render cause the stencil value to increment, thus
// future attempts to render over that pixel fail
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 0, 0xFFFFFFFF);
glStencilOp(GL_KEEP, GL_INCR, GL_INCR);

renderShadow();

glDisable(GL_STENCIL_TEST);
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);


I tested it briefly and it seemed to work, though I stayed up the whole night and I'm really tired, so perhaps I made an error.

Share this post


Link to post
Share on other sites
Here is an example of the shadows



As you can see the shadows look odd because they don’t match the lighting. Otherwise I'm satisfied with the result. Any idea to how this could be accomplished.

I don’t have the time to start learning about advanced shadowing techniques, but if there are other methods of shadowing that are rather simple, I’m of course open for suggestions.

I would of course prefer that it could be implemented in my current code (using stencils) :-)

Share this post


Link to post
Share on other sites
Is the background still one quad? If yes, then use projected shadows. I you don't have time to play with it i can put on my homepage some simple code (http://xormultiplexus.googlepages.com/home), but i need a few time to put it in one piece. If you want it, then you must decide where to render the shadow. On that mortal kombat picture i would say you want the shadow to be on the ground. So make the ground one quad and the rest is not important. The problem is that, if the ground is not one polygon it wont be possible to do the shadow. One other solution could be to create a quad that would represent the ground. But you will not render that quad, but insted you will use it to make projection on it and to achieve more realistic look for you shadow. This way you don't need to do any changes to the background polygon.

decide ;-D

XorMultiPleXus

btw. that game of yours look good ;-D

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I tried to adjust the shadows matrix to the light source with some code I found on the Nvidia website.



It only works if I tweak the lightsource to a specific point (not the original position of my light) which is kind of strange. The code requires me to specify the normal of the ground, but I don't think I'm doing that right although I have tried a lot of different settings.

Share this post


Link to post
Share on other sites
Ok

download the geom.h and geom.cpp from my page (http://xormultiplexus.googlepages.com/downloads).

It is easy high school math which will help us.

Now the code (the explanation is after the code listing):

/* CODE BEGIN */

//part 1
double * a = new double[3];
double * b = new double[3];
double * c = new double[3];
double * n;

a[0] = -300;
a[1] = -100;
a[2] = 0;

b[0] = 300;
b[1] = -100;
b[2] = 0;

c[0] = 0;
c[1] = 300;
c[2] = 0;

n = normal(a, b, c);

//part 2
glEnable(GL_STENCIL_TEST);

glDepthMask(GL_FALSE);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

glStencilFunc (GL_ALWAYS, 1, 0xFFFFFFFF);
glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE);

//part 3
glBegin(GL_TRIANGLES);

//part 4
double * r = new double[3];
double * u = new double[3];

Plane * rov = createPlane(a, b, c, n);

delete [] a;
delete [] b;
delete [] c;
delete [] n;

//part 5
Light * l = new Light;
l->position = new double[3];
l->position[0] = -20;
l->position[1] = -50;
l->position[2] = 40;

Line * p;

//part 6
for (unsigned int i = 0; i < ceruzka->fc; i++)
{

getVertex(i, 0, ceruzka, r);
p = createLine(l->position, r);
double * x = pointOfIntersection(rov, p);
glVertex3dv(x);
delete [] x;
delete [] p->A;
delete [] p->s;
delete p;

getVertex(i, 1, ceruzka, r);
p = createLine(l->position, r);
x = pointOfIntersection(rov, p);
glVertex3dv(x);
delete [] x;
delete [] p->A;
delete [] p->s;
delete p;

getVertex(i, 2, ceruzka, r);
p = createLine(l->position, r);
x = pointOfIntersection(rov, p);
glVertex3dv(x);
delete [] x;
delete [] p->A;
delete [] p->s;
delete p;

}

//part 7
glEnd();

delete [] r;
delete [] u;

glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);

/* CODE END */

Explanation:

part 1: i have declared and defined point A, B, C and a normal verctor n which is computed via the normal(A, B, C) function

part 2: we will start stencil test

part 3: we will start rendering our shadow mesh

part 4: the rov variable is the plane which in your case represents the ground and we will compute it with the createPlane(A, B, C, n) function. Don't forget to delete the variables a, b, c and n because you don't need them anymore.

part 5: we will create our light, only it's position

part 6: the variable ceruzka->fc is how much triangles we will render. The getVertex(...) gets the vertex from the ceruzka structure (IT IS NOT a part of the files geom.h and geom.cpp; it is my own structure which i use for keeping the geometry). The createLine is used to create a line from the light to the vertex and with the pointOfIntersection(...) we will aquire where the vertex lies on the plane (your ground). So in one iteration of the for cycle we will project one triangle of some mesh onto the plane and render it into the stencil buffer. So the whole for-cycle will render the shadow where it should be.

part 7: end the rendering, clean the memory and turn off stencil test ;-D

Hope it helped, this technique is old and lame but it is enougth for your project. It is called planar shadows (http://www.opengl.org/resources/features/StencilTalk/sld020.htm).

XorMultiPleXus

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