   Shadow Speed Issues, Test please? (screenshot)
  I''ve recently implemented stencil shadows in my game but the speed hit seems fairly harsh. So I was hoping that you guys could test my game for me and give some feedback.The program puts a model on the screen which casts a shadow onto a little terrain (see screenshot below). The model is 2500 triangles and untextured.My system is an 800mhz with a voodoo5500 and the program runs at 18-20 fps when the shadows are on. And 150+ fps when the shadows are off. Huge hit. On a geforce2 1.4ghz the frame rate was  between 29 and 40 fps with shadows.Requirments:To test my game you need a video card that supports a depth stencil format of D3DFMT_D24S8 and you need DirectX 8.1. The program runs at 1024x768.Keys:A=Move Camera LeftD=Move Camera RightF1-Fill SolidF2-WireframeF3-Shadows OnF4-Shadows OffHere''s the link:http://www.opticuslabs.com/gizmoshad.zipJust so you know what you expect to see:If you test it could you please tell me your system specs and the framerate you got with and without shadows? Also there''s a weird thing that when you start moving to the right side of the model you''ll hit a point where the framerate drops. Please mention what your framerate dropped from if there was any drop. Anyone know a reason for this or could make a guess?Thanks!~Wave 
  Without Shadows: 485 fpsWith: 75 fpsPentium 4, 2.4 GH, 512 RAM, ATI M9000 64MB graphics card.Definitely a huge hit with the shadows on.  I wish I knew more about shadowing so I could help you, but I haven''t dealt with that kind of stuff yet.  Oh, and the FPS does get lower as you move to the right.  I don''t know if this is because you are zooming in on the character a little bit, or if you''re able to see different (more?) polygons on the character at that angle, or what.  Hopefully someone who has done shadowing will come in here and help you out. ;  Geez that is a hefty hit. It must be the way I draw them is inefficient. I took my code from the shadow volume code that came with dx. They use DrawPrimitiveUP for the shadows. I'll change that to a dynamic vertex buffer and see if I can get an improvement. Thankyou so much for taking the time to test it.~Wave   [edited by - Wavewash on February 14, 2004 1:30:39 AM];  Changing the DrawPrimitiveUP to a vertex buffer did not seem to help my framerate at all.~Wave ;  If I run it and don''t move or do anything, I get about 23 fps.  If I turn shadows off I get 50 fps.  I''ve got a Celeron 766 with a GF4 Ti 4200.By "stencil shadows" do you mean shadow volumes using the stencil buffer?  It certainly does seem a bit of a harsh penalty.  I''m not entirely familiar with the mechanics of the algorithm yet either, unfortunately.  I''m also only just starting to learn D3D now, having been an OpenGL person for quite a while.  Perhaps if you don''t use a dynamic vertex buffer it might be better?  I think that''s just an option you specify when you create the vb, isn''t it?  It might mean that the vb is actually loaded into system memory rather than the card''s memory.cheerssam;  P4 2.66 w/ HTRadeon 9800 pro 128mb1gb o' the fast stuffShadows off:560fps with performance settings526fps with 16x AF & 6x AAShadows on:87fps with performance settings82fps with 16x AF & 6x AATowards the front of the model with shadows on the fps with 16x AF & 6x AA dropped to ~47fps. I didn't test it with the performance settings, but I expect it's similar.   [edited by - Vaalean on February 14, 2004 6:35:46 AM];  can you send a psoudo code may be I code help you accelarate the engine.I think there''s something that causes all this performance hit. ;  Here are the specs from my test :-Config :-AMD Athlon XP 2600+ (333MHz FSB)512 MB DDR400Radeon 9600 PROLosts of apps running in the background.Without Shadows :- 363 fpsWith shadows :- 64 fps (6x AA and 16x AF)Again, there was a significant drop in the framerate. ;  Yea sure here's pretty much what I'm doing:Everyframe callShadowVolman.Reset();ShadowVolman.BuildFromMesh();ShadowVolman.RenderShadow();ShadowVolman.DrawShadow();The following is for BuildFromMeshBGO is a linked list of objects I want to project shadowsBGOcurrptr is a pointer to the objects in that listLightPoint currptr is a pointer to lights in a linked list.    BGOElement* BGOcurrptr;BGOcurrptr=BGOman->rethead();LightPoint* currptr;currptr=head;HRESULT hr;while(currptr!=NULL){/*D3DXVECTOR3 vLight;D3DXMATRIX m;D3DXMatrixInverse( &m, NULL, &currptr->world );float Lx, Ly, Lz;Lx=currptr->position.x;Ly=currptr->position.y;Lz=currptr->position.z;vLight.x = Lx*m._11 + Ly*m._21 + Lz*m._31 + m._41;vLight.y = Lx*m._12 + Ly*m._22 + Lz*m._32 + m._42;vLight.z = Lx*m._13 + Ly*m._23 + Lz*m._33 + m._43;*/D3DXVECTOR3 vLight=currptr->position;while(BGOcurrptr!=NULL){D3DXMATRIX m,scale;AngleMatrix(&m,BGOcurrptr->rotation);D3DXMatrixScaling(&scale,BGOcurrptr->scale.x,BGOcurrptr->scale.y,BGOcurrptr->scale.z);m=scale*m;//3DXMatrixInverse(&invertme, NULL, &invertme);//D3DXVec3TransformCoord(&vLight,&vLight,&invertme);*/// Note: the MESHVERTEX format depends on the FVF of the meshDWORD dwFVF = D3DFVF_MODELVERTEX;MODELVERTEX* pVertices;WORD*  pIndices;for(int h=0; h<BGOcurrptr->object->model.partnum; h++){// Lock the geometry buffers//pMesh->LockVertexBuffer( 0L, (BYTE**)&pVertices );//pMesh->LockIndexBuffer( 0L, (BYTE**)&pIndices );MOKmodelcont* ModelCont;ModelCont=BGOcurrptr->object;int dwNumVertices = ModelCont->model.parts[h].numverts; //pMesh->GetNumVertices();int dwNumFaces    = ModelCont->model.parts[h].numtris; //pMesh->GetNumFaces();// Allocate a temporary edge listWORD* pEdges = new WORD[dwNumFaces*6];DWORD dwNumEdges = 0;int hitcount=0;// For each facefor( int j=0; j<dwNumFaces; j++ ){WORD wFace0 = ModelCont->model.parts[h].vlist[j*3+0];WORD wFace1 = ModelCont->model.parts[h].vlist[j*3+1];WORD wFace2 = ModelCont->model.parts[h].vlist[j*3+2];//animatevertex returns the transformed vertex for skinned meshesD3DXVECTOR3 v0 = ModelCont->AnimateVertex(h,wFace0); //ModelCont->model.parts[h].vertexs[wFace0];D3DXVec3TransformCoord(&v0,&v0,&m);D3DXVECTOR3 v1 = ModelCont->AnimateVertex(h,wFace1); //ModelCont->model.parts[h].vertexs[wFace1];D3DXVec3TransformCoord(&v1,&v1,&m);D3DXVECTOR3 v2 = ModelCont->AnimateVertex(h,wFace2); //ModelCont->model.parts[h].vertexs[wFace2];D3DXVec3TransformCoord(&v2,&v2,&m);// Transform vertices or transform light?D3DXVECTOR3 vNormal;D3DXVec3Cross( &vNormal, &(v2-v1), &(v1-v0) );D3DXVec3Normalize(&vNormal,&vNormal);float dot=D3DXVec3Dot( &vNormal, &vLight );if( dot >= 0.0f ){hitcount++;AddEdge( pEdges, dwNumEdges, wFace0, wFace1 );AddEdge( pEdges, dwNumEdges, wFace1, wFace2 );AddEdge( pEdges, dwNumEdges, wFace2, wFace0 );/*m_pVertices[m_dwNumVertices++] = ModelCont->model.parts[h].normals[wFace2]*0.003;m_pVertices[m_dwNumVertices++] = ModelCont->model.parts[h].normals[wFace1]*0.003;m_pVertices[m_dwNumVertices++] = ModelCont->model.parts[h].normals[wFace0]*0.003;//Reverse the normals for light back facing triangles and extend them in the light direction to form //the back cap of the shadow volume m_pVertices[m_dwNumVertices++] = v0-vLight*10;m_pVertices[m_dwNumVertices++] = v1-vLight*10;m_pVertices[m_dwNumVertices++] = v2-vLight*10;*/}}D3DXVECTOR3 *pVertices;if( FAILED( hr = m_pVerticesVB->Lock( 0 , dwNumEdges*sizeof(D3DXVECTOR3), (BYTE**)&pVertices, D3DLOCK_DISCARD  ) ) )return hr;for(int i=0; i<dwNumEdges; i++ ){D3DXVECTOR3 v1 = ModelCont->AnimateVertex(h,pEdges[2*i+0]); //ModelCont->model.parts[h].vertexs[pEdges[2*i+0]];D3DXVec3TransformCoord(&v1,&v1,&m);D3DXVECTOR3 v2 = ModelCont->AnimateVertex(h,pEdges[2*i+1]); //ModelCont->model.parts[h].vertexs[pEdges[2*i+1]];D3DXVec3TransformCoord(&v2,&v2,&m);D3DXVECTOR3 v3 = v1 - vLight*10;D3DXVECTOR3 v4 = v2 - vLight*10;// Add a quad (two triangles) to the vertex listif(m_dwNumVertices<32000-7){m_pVertices[m_dwNumVertices++] = v1;m_pVertices[m_dwNumVertices++] = v2;m_pVertices[m_dwNumVertices++] = v3;m_pVertices[m_dwNumVertices++] = v2;m_pVertices[m_dwNumVertices++] = v4;m_pVertices[m_dwNumVertices++] = v3;}}memcpy( pVertices, m_pVertices, sizeof(m_pVertices) );// Delete the temporary edge listdelete[] pEdges;if( FAILED( hr = m_pVerticesVB->Unlock() ) )return hr;// Unlock the geometry buffers//pMesh->UnlockVertexBuffer();//pMesh->UnlockIndexBuffer();}BGOcurrptr=BGOcurrptr->next;}currptr=currptr->next;}and then my rendershadow call look fairly standard from the sample code that came with the sdk like: / Disable z-buffer writes (note: z-testing still occurs), and enable the    // stencil-buffer    g_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE,  FALSE );    g_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE, TRUE );    // Dont bother with interpolating color    g_pd3dDevice->SetRenderState( D3DRS_SHADEMODE,D3DSHADE_FLAT );    // Set up stencil compare fuction, reference value, and masks.    // Stencil test passes if ((ref & mask) cmpfn (stencil & mask)) is true.    // Note: since we set up the stencil-test to always pass, the STENCILFAIL    // renderstate is really not needed.    g_pd3dDevice->SetRenderState( D3DRS_STENCILFUNC,  D3DCMP_ALWAYS );    g_pd3dDevice->SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP );    g_pd3dDevice->SetRenderState( D3DRS_STENCILFAIL,  D3DSTENCILOP_KEEP );    // If ztest passes, inc/decrement stencil buffer value    g_pd3dDevice->SetRenderState( D3DRS_STENCILREF,  0x1 );    g_pd3dDevice->SetRenderState( D3DRS_STENCILMASK, 0xffffffff );    g_pd3dDevice->SetRenderState( D3DRS_STENCILWRITEMASK, 0xffffffff );    g_pd3dDevice->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_INCR );    // Make sure that no pixels get drawn to the frame buffer    g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );    g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_ZERO );    g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );BGOElement* currptr;currptr=BGOman->rethead();while(currptr!=NULL){D3DXMATRIX m;D3DXMatrixTranslation(&m, currptr->position.x,currptr->position.y,currptr->position.z);// Draw front-side of shadow volume in stencil/z onlyg_pd3dDevice->SetTransform( D3DTS_WORLD, &m );Render();// Now reverse cull order so back sides of shadow volume are written.g_pd3dDevice->SetRenderState( D3DRS_CULLMODE,   D3DCULL_CW );// Decrement stencil buffer valueg_pd3dDevice->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_DECR );// Draw back-side of shadow volume in stencil/z onlyg_pd3dDevice->SetTransform( D3DTS_WORLD, &m );Render();currptr=currptr->next;}    // Restore render states    g_pd3dDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD );    g_pd3dDevice->SetRenderState( D3DRS_CULLMODE,  D3DCULL_CCW );    g_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE,TRUE );    g_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE,    FALSE );    g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );and the draw shadow function:    // Set renderstates (disable z-buffering, enable stencil, disable fog, and    // turn on alphablending)    g_pd3dDevice->SetRenderState( D3DRS_ZENABLE,FALSE );    g_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE,    TRUE );    g_pd3dDevice->SetRenderState( D3DRS_FOGENABLE,   FALSE );    g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );    g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA );    g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );    g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );    g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );    g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );    g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );    g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );    g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );    // Only write where stencil val >= 1 (count indicates # of shadows that    // overlap that pixel)    g_pd3dDevice->SetRenderState( D3DRS_STENCILREF,  0x1 );    g_pd3dDevice->SetRenderState( D3DRS_STENCILFUNC, D3DCMP_LESSEQUAL );    g_pd3dDevice->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_KEEP );    // Draw a big, gray square    g_pd3dDevice->SetVertexShader( D3DFVF_SHADOWVERTEX );    g_pd3dDevice->SetStreamSource( 0, m_pBigSquareVB, sizeof(SHADOWVERTEX) );    g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );    // Restore render states    g_pd3dDevice->SetRenderState( D3DRS_ZENABLE,TRUE );    g_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE,    FALSE );    g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );}RenderShadow() void ShadowVol::RenderShadow(){// Disable z-buffer writes (note: z-testing still occurs), and enable the    // stencil-buffer    g_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE,  FALSE );    g_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE, TRUE );    // Dont bother with interpolating color    g_pd3dDevice->SetRenderState( D3DRS_SHADEMODE,D3DSHADE_FLAT );    // Set up stencil compare fuction, reference value, and masks.    // Stencil test passes if ((ref & mask) cmpfn (stencil & mask)) is true.    // Note: since we set up the stencil-test to always pass, the STENCILFAIL    // renderstate is really not needed.    g_pd3dDevice->SetRenderState( D3DRS_STENCILFUNC,  D3DCMP_ALWAYS );    g_pd3dDevice->SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP );    g_pd3dDevice->SetRenderState( D3DRS_STENCILFAIL,  D3DSTENCILOP_KEEP );    // If ztest passes, inc/decrement stencil buffer value    g_pd3dDevice->SetRenderState( D3DRS_STENCILREF,  0x1 );    g_pd3dDevice->SetRenderState( D3DRS_STENCILMASK, 0xffffffff );    g_pd3dDevice->SetRenderState( D3DRS_STENCILWRITEMASK, 0xffffffff );    g_pd3dDevice->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_INCR );    // Make sure that no pixels get drawn to the frame buffer    g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );    g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_ZERO );    g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );BGOElement* currptr;currptr=BGOman->rethead();while(currptr!=NULL){D3DXMATRIX m;D3DXMatrixTranslation(&m, currptr->position.x,currptr->position.y,currptr->position.z);// Draw front-side of shadow volume in stencil/z onlyg_pd3dDevice->SetTransform( D3DTS_WORLD, &m );Render();// Now reverse cull order so back sides of shadow volume are written.g_pd3dDevice->SetRenderState( D3DRS_CULLMODE,   D3DCULL_CW );// Decrement stencil buffer valueg_pd3dDevice->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_DECR );// Draw back-side of shadow volume in stencil/z onlyg_pd3dDevice->SetTransform( D3DTS_WORLD, &m );Render();currptr=currptr->next;}    // Restore render states    g_pd3dDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD );    g_pd3dDevice->SetRenderState( D3DRS_CULLMODE,  D3DCULL_CCW );    g_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE,TRUE );    g_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE,    FALSE );    g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );Thankyou all for testing my program. Mohamed, all the code is pretty standard but when I comment out the rendershadow and drawshadow it speeds up. So the problem is somewhere in there... just in case you need it my setup function looks like: g_pd3dDevice->CreateVertexBuffer( 4*sizeof(SHADOWVERTEX),    D3DUSAGE_WRITEONLY, D3DFVF_SHADOWVERTEX,    D3DPOOL_DEFAULT, &m_pBigSquareVB );   g_pd3dDevice->CreateVertexBuffer( 32000*sizeof(D3DXVECTOR3),    D3DUSAGE_DYNAMIC, D3DFVF_XYZ,D3DPOOL_DEFAULT, &m_pVerticesVB);   SHADOWVERTEX* v;    FLOAT sx = x;    FLOAT sy = y;    m_pBigSquareVB->Lock( 0, 0, (BYTE**)&v, 0 );    v[0].p = D3DXVECTOR4(  0, sy, 0.0f, 1.0f );    v[1].p = D3DXVECTOR4(  0,  0, 0.0f, 1.0f );    v[2].p = D3DXVECTOR4( sx, sy, 0.0f, 1.0f );    v[3].p = D3DXVECTOR4( sx,  0, 0.0f, 1.0f );    v[0].color = 0x7f000000;    v[1].color = 0x7f000000;    v[2].color = 0x7f000000;    v[3].color = 0x7f000000;    m_pBigSquareVB->Unlock();[/source]Mohamed, you have already been a great help to me. I was reading your replys about capping the volumes in one of the other threads. You'll see some of that code commented in there also. Thankyou so much.~Wave    [edited by - Wavewash on February 14, 2004 1:06:40 PM];  Commenting out BuildFromMesh and leaving rendershadow and drawshadow, the frame rate goes up. Once BuildFromMesh is called and the geometry is created that''s when the slow down occurs.~Wave 