#141827 - Ishi - Sun Sep 30, 2007 5:06 pm
Hi everyone,
I'm currently trying to get shadows working on the DS. I've had a look at silent_code's shadow code ( http://forum.gbadev.org/viewtopic.php?t=12873 ) and I can't see anything in there that I'm obviously missing.
I draw my normal meshes, which work fine (I'm just drawing an object and a simple floor plane). Then I use this function:
Code: |
void CGraphics::drawShadow(CMesh *mesh, float x, float y, float z) const
{
glBindTexture(0, 0);
glEnable(GL_BLEND);
glPushMatrix();
glTranslatef(x, y, z);
glPolyFmt(POLY_ID(0) | POLY_ALPHA(1) | POLY_CULL_FRONT | POLY_SHADOW);
mesh->drawSimple();
glPolyFmt(POLY_ID(1) | POLY_ALPHA(20) | POLY_CULL_BACK | POLY_SHADOW);
mesh->drawSimple();
glPopMatrix(1);
glDisable(GL_BLEND);
} |
(drawSimple just draws all the mesh's triangles.)
It's partially working, instead of the proper shadow I get some white flickering bits where the shadow should be. If anyone can shed some light on something I might be missing, that'd be much appreciated.
Last edited by Ishi on Sun Sep 30, 2007 9:20 pm; edited 1 time in total
#141833 - M3d10n - Sun Sep 30, 2007 5:56 pm
The demo I saw uses BIT(4) | BIT(5) instead of POLY_SHADOW, did you try that?
Also, is your shadow geometry convex (like a box, cylinder, sphere, etc)? If its a plane I think the shadow won't work.
#141835 - Ishi - Sun Sep 30, 2007 6:18 pm
I think the demo was before POLY_SHADOW was put in libnds, it's just 48 which is 110000 (bits 4 and 5) :)
For the shadow geometry at the moment I'm just using the mesh that I'm doing the shadow for, but placed half way into the floor. It's an enclosed mesh. (The shadow will be the wrong shape, and it's hideously inefficient, but at the moment I'm just trying to get it working right)
edit-
I've figured out that glColor changes the shadow colour, which was pretty obvious.
The shadow itself is still glitchy, it looks like z-fighting which is odd. The shadow's also a solid colour rather than transparent.
#141842 - M3d10n - Sun Sep 30, 2007 8:25 pm
I tried it and I also got the same bug. The shadow is drawn only on the geometry intersecting it, which is correct, but it is flickering in typical z-fighting fashion instead of properly covering the intersecting geometry.
Feels like we're both missing to turn something on somewhere.
#141844 - Ishi - Sun Sep 30, 2007 8:42 pm
Awesome, good to know it's not just me :) Thanks for trying that.
I'm gonna comb through the demo code nice and carefully now I think.
#141850 - Ishi - Sun Sep 30, 2007 9:09 pm
Sorry for the double post, I've got it working now.
Passing 1 or 3 to glFlush fixes the z-fighting, something to do with how it sorts the vertices.
And for the transparency, I had to leave GL_BLEND on all the time - as the 3D doesn't actually get rendered until the end of the frame, so disabling it at the end of the function means it doesn't apply.
Thanks a lot for the help, M3d10n :)
#141872 - M3d10n - Mon Oct 01, 2007 12:06 am
Ah, I'll try that.
I also had a problem with GL_BLEND recently and found that its better to keep it always on (opaque geometry is unaffected). Unlike the OpenGl equivalent, it is either on or off for the whole frame.
#141889 - zeruda - Mon Oct 01, 2007 9:15 am
What's the performance costs of using the hardware shadows? Does it eat into the vertex limit?
#141890 - silent_code - Mon Oct 01, 2007 9:44 am
yes, shadow polys count as normal polys (and vertices). the z-fighting is caused by the z-sorting algo: as you already found out, one needs to set it to w-sorting, z-sorting won't work. and manual sort might be needed, too, iirc.
it's nice to see someone working with hardware shadows, after all this time the shadow volume demo is online. ;^D it's sort of a pitty i've never got around writing a tutorial for it (maybe because i didn't see much developer interest - who knows?). on the other hand, it's just as easy as setting a few bits. ;^p
please post some images of the results you're getting (if you fell like it ;^) ).
happy coding!
ps: sorry i couldn't help, i've no inet @home, so i'm rarely online. :^C thoug one could always pm me. ;^)
#141922 - Ishi - Mon Oct 01, 2007 6:29 pm
Good to know that the shadow polies do just count as normal polies towards the limit, I'd assumed they would do.
Don't really have anything to show at the moment, I just wanted to get shadows working in my engine for when I need them.
An interesting side note, Mario Kart DS uses non-convex shadow volumes for some of the karts (Bowser's airplane is most noticeable). Never noticed before, but now I know what to look for I can see where they break. ^_^
#141973 - silent_code - Tue Oct 02, 2007 6:01 pm
;^D
#142098 - a128 - Thu Oct 04, 2007 10:14 am
Here is a code (which works) to project a shadow on a plane ...based on
http://www.devmaster.net/articles/shadowprojection/
THis is not for hadrware shadows..but good for translucent shadows
Code: |
/*
*
* Multiply the current ModelView-Matrix with a shadow-projetion
* matrix.
*
* Everything that is drawn after this call is "squashed" down
* to the plane.
* */
static void glShadowProjection(Vec3 plane_normal,Vec3 point_plane,Vec3 light_pos=Vec3(0,100,0))
{
FixedPointNum d, c;
int32 mat[16];
//Vec3 is a fixpoint vector
Vec3 &n=plane_normal;
Vec3 &l=light_pos;
// Create the matrix.
if(light_pos.x!=0&&light_pos.z!=0){
// l is the position of the light source
d = n.x*l.x + n.y*l.y + n.z*l.z;
c = (point_plane|plane_normal) - d;
mat[0] = (l.x*n.x+c).getInt32();
mat[4] = (n.y*l.x).getInt32();
mat[8] = (n.z*l.x).getInt32();
mat[12] = (-l.x*c-l.x*d).getInt32();
mat[1] = (n.x*l.y).getInt32();
mat[5] = (l.y*n.y+c).getInt32();
mat[9] = (n.z*l.y).getInt32();
mat[13] = (-l.y*c-l.y*d).getInt32();
mat[2] = (n.x*l.z).getInt32();
mat[6] = (n.y*l.z).getInt32();
mat[10] = (l.z*n.z+c).getInt32();
mat[14] = (-l.z*c-l.z*d).getInt32();
}else{
//special case where light position is Vec3(0,y,0)
d=plane_normal.y*light_pos.y;
c = (point_plane|plane_normal) - d;
mat[0] = c.getInt32();
mat[4] = 0;
mat[8] = 0;
mat[12] = 0;
mat[1] = (n.x*l.y).getInt32();
mat[5] = (l.y*n.y+c).getInt32();
mat[9] = (n.z*l.y).getInt32();
mat[13] = (-l.y*c-l.y*d).getInt32();
mat[2] = 0;
mat[6] = 0;
mat[10] = c.getInt32();
mat[14] = 0;
}
mat[3] = n.X();
mat[7] = n.Y();
mat[11] = n.Z();
mat[15] = -d.getInt32();
// Finally multiply the matrices together *plonk*
glMultMatrix4x4((m4x4*)&mat);
}
|
use this like this
Code: |
glPushMatrix();
pos.y+=0.045f;//add y offset to reduce Y depth errors
//note: the normal is (0,-1,0) !!!
glShadowProjection(Vec3(0,-1,0),Vec3(0,pos.y,0),Vec3(0,50,0));
TranslateRotateY(pos, heading);
DRAW_SHADOW(); // just a translucent mesh which you only have to render once:-)
glPopMatrix(1);
|
#142228 - Ishi - Sat Oct 06, 2007 5:45 pm
Coolio. Probably a bit poly-heavy for most in-game usage, but it could be used for some really nice effects. Might give it a shot sometime. :)
#146399 - Noda - Mon Dec 03, 2007 6:24 pm
a128:
what does this part: c = (point_plane|plane_normal) - d;
I don't get what the operator '|' do here?
#146402 - tepples - Mon Dec 03, 2007 8:25 pm
The | operator in C performs a bitwise or operation.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#146409 - Noda - Mon Dec 03, 2007 9:58 pm
Yeah I know this but here the "|" is applied on two vector objects!
From what I undertstand of the document pointed, I think it should does the "." product between the vectors, but that's a strange (and confusing) way to redefine an operator function in my opinion...
#146447 - a128 - Tue Dec 04, 2007 9:24 am
Noda wrote: |
a128:
what does this part: c = (point_plane|plane_normal) - d;
I don't get what the operator '|' do here? |
"|" is the vector Dot product, "|" is used often by various developers for the "dot" because "." can`t be redefined and "*" is multiplication with a scalar
a|b := a*a+b*b
#146448 - a128 - Tue Dec 04, 2007 9:41 am
Ishi wrote: |
Coolio. Probably a bit poly-heavy for most in-game usage, but it could be used for some really nice effects. Might give it a shot sometime. :) |
The 3d model of the shadow is just a subset from the real 3d model.
so it depends how mutch poly does the shadow have..
Render the shadow only if the camera is near the model
I use this code to the the cameraposition (Z is my depth coordinate)
Code: |
Fixed Mathtools::CameraDistance(const Vec3 &pos)
{
glPushMatrix();
//1) translate to position
MATRIX_TRANSLATE = pos.X();
MATRIX_TRANSLATE = pos.Y();
MATRIX_TRANSLATE = pos.Z();
//2) test against pos now at origin
PosTest(0, 0, 0);
Fixed closeZ = _FixedNum(PosTestZresult());
glPopMatrix(1);
return closeZ;
};
|
#146577 - Noda - Thu Dec 06, 2007 5:08 am
I've got to work those projected shadows properly, but now I have a little problem, common with this method: the shadow are drawn outside of the receiver object.
I thought I could use the stencil buffer to cut out the undesired parts of the shadows, but I don't get it to work :(
Any idea on how to cut out the shadow so it only fits the receiver?
#146584 - a128 - Thu Dec 06, 2007 9:10 am
Noda wrote: |
I've got to work those projected shadows properly, but now I have a little problem, common with this method: the shadow are drawn outside of the receiver object.
I thought I could use the stencil buffer to cut out the undesired parts of the shadows, but I don't get it to work :(
Any idea on how to cut out the shadow so it only fits the receiver? |
This technique has nothing to do with stencil/hardware shadows
The shadow is just a translucent 3d model..the shadow matrix scales the shadow model so it looks like a shadow casted by a light source
#146593 - Noda - Thu Dec 06, 2007 4:26 pm
Yeah, I know, but your know, one of the problems of this technique is that the shadow is drawn on an infinite plane, and the receiver may not be infinite (like in my case, where it's just a board).
Using the stencil buffer should work by drawing the shadow only on the receiver's pixel, if used correctly.
I managed to get it somewhat working, it's working great on iDeas, but on DS the undesired parts goes on/off depending on the rotation of my board.
It's likely a z-buffer resolution problem here, but I don't know how to tweak this :(
I tried using the W-Buffer, but if I activate the W-Buffer the transparent shadow are not shown at all! Is there something special to do when the W-Buffer is activated? I tried to activate bit 11 when drawing my shadows, without success...
#146596 - a128 - Thu Dec 06, 2007 4:54 pm
Noda wrote: |
I tried using the W-Buffer, but if I activate the W-Buffer the transparent shadow are not shown at all! |
Yes I also saw this if you use W-Buffer; GFX_FLUSH with bit1=1
so GFX_FLUSH >=2 just does not show the translucent polys...I DO NOT KNOW WHY
#146597 - Lino - Thu Dec 06, 2007 5:49 pm
Noda can you send your program? (if its possible with source). Thanks.
#146612 - Noda - Thu Dec 06, 2007 9:02 pm
Lino> done ;)
By the way, I noticed an error in the gbatek specification considering the stencil buffer: the stencil buffer is not cleared after being checked, which does make more sense (and I use it that way, so ;)
Something strange I noticed also, that may be a bug in the libnds: using either z-buffer or w-buffer results in the exactly same z-fighting, and changing the z close/far planes doesnt affect the z-buffer precision, which is really strange... any idea for this?
#146641 - Lino - Fri Dec 07, 2007 4:50 am
ok thanks ill try if I find something I make you know.
#146652 - a128 - Fri Dec 07, 2007 9:28 am
Lino wrote: |
ok thanks ill try if I find something I make you know. |
and please report to this thread :-)
#146654 - Lino - Fri Dec 07, 2007 9:46 am
#146664 - a128 - Fri Dec 07, 2007 12:30 pm
Impressive. The shadows are done be the hardware?
Did you fixed the GFX_FLUSH=2 problem...?
Or is this (only) working on Ideas emu?
#146687 - Noda - Fri Dec 07, 2007 5:49 pm
The shadows are done using a projection matrix combined with the stencil buffer to cut the part of shadows that are out of the board.
But still, the I didn(t get the w-buffer to work correctly and I'm having weird problem with the stencil things, as depending of the view point, the cut shadows parts somewhat flickers and become visible, like if there was some sort of z-fighting (but works well on emu).
EDIT: BTW, what you call "hardware shadows" are not really "hardware", as it's just a classic use of the stencil buffer to draw shadow volumes. Still, projected shadows are faster and eats less polygons than shadow volumes, as I only need to draw once the board in the stencil buffer the 1 time each object to cast shadow, instead of 2 times each shadows.
#146699 - Lino - Fri Dec 07, 2007 9:40 pm
a128 wrote: |
Impressive. The shadows are done be the hardware?
Did you fixed the GFX_FLUSH=2 problem...?
Or is this (only) working on Ideas emu? |
The demo works on iDeaS as the real hardware. I only fixed a bug on autosort for traslucent polygons.