"Shadow Volume" Problem...

Started by
6 comments, last by Christian Johansson 18 years, 5 months ago
Okey as my engine is becoming better and better i'm also running into problems. ANd this time it's Shadow Volume Problems. My problem is (what i think) the buildShadowVolume() part. When i place a Cube on a plane and adds a light source (in this case a point light) the light "casts" a shadow on the ground, however the shadow it's not correct. Here's what happens: [PIC]http://xtian.no-ip.org/sprob.jpg[/PIC] And here's the code

class ShadowVolume
{
public:

    void    reset() { m_dwNumVertices = 0L; }
    HRESULT buildShadowVolume( LPD3DXMESH pObject, D3DXVECTOR3 vLight );
    HRESULT render( LPDIRECT3DDEVICE9 pd3dDevice );

private:

	void addEdge( WORD* pEdges, DWORD& dwNumEdges, WORD v0, WORD v1 );

	D3DXVECTOR3 m_pVertices[32000]; // Vertex data for rendering shadow volume
    DWORD       m_dwNumVertices;
};

struct ShadowVertex
{
	D3DXVECTOR4 p;
	 //D3DXVECTOR4 n;
    D3DCOLOR    color;

	enum FVF
	{
		FVF_Flags = D3DFVF_XYZRHW | D3DFVF_DIFFUSE
	};
};

HRESULT ShadowVolume::render( LPDIRECT3DDEVICE9 pd3dDevice )
{
    pd3dDevice->SetFVF( D3DFVF_XYZ );

    return pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLELIST, m_dwNumVertices/3,
                                        m_pVertices, sizeof(D3DXVECTOR3) );
}

HRESULT ShadowVolume::buildShadowVolume( LPD3DXMESH pMesh, D3DXVECTOR3 vLight )
{
	// Note: the MeshVertex format depends on the FVF of the mesh
	struct MeshVertex { D3DXVECTOR3 p, n; }; // Works fine for teapot, but won't do for all meshes!

    MeshVertex *pVertices;
    WORD       *pIndices;

    // Lock the geometry buffers
    pMesh->LockVertexBuffer( 0L, (LPVOID*)&pVertices );
    pMesh->LockIndexBuffer( 0L, (LPVOID*)&pIndices );
    DWORD dwNumFaces    = pMesh->GetNumFaces();

    // Allocate a temporary edge list
    WORD *pEdges = new WORD[dwNumFaces*6];

    if( pEdges == NULL )
    {
        pMesh->UnlockVertexBuffer();
        pMesh->UnlockIndexBuffer();
        return E_OUTOFMEMORY;
    }
	
    DWORD dwNumEdges = 0;

    // For each face
    for( DWORD i = 0; i < dwNumFaces; ++i )
    {
        WORD wFace0 = pIndices[3*i+0];
        WORD wFace1 = pIndices[3*i+1];
        WORD wFace2 = pIndices[3*i+2];

        D3DXVECTOR3 v0 = pVertices[wFace0].p;
        D3DXVECTOR3 v1 = pVertices[wFace1].p;
        D3DXVECTOR3 v2 = pVertices[wFace2].p;

        // Transform vertices or transform light?
        D3DXVECTOR3 vCross1(v2-v1);
        D3DXVECTOR3 vCross2(v1-v0);
        D3DXVECTOR3 vNormal;
        D3DXVec3Cross( &vNormal, &vCross1, &vCross2 );

        if( D3DXVec3Dot( &vNormal, &vLight ) >= 0.0f )
        {
            addEdge( pEdges, dwNumEdges, wFace0, wFace1 );
            addEdge( pEdges, dwNumEdges, wFace1, wFace2 );
            addEdge( pEdges, dwNumEdges, wFace2, wFace0 );
        }
    }

    for( i = 0; i < dwNumEdges; ++i )
    {
        D3DXVECTOR3 v1 = pVertices[pEdges[2*i+0]].p;
        D3DXVECTOR3 v2 = pVertices[pEdges[2*i+1]].p;
        D3DXVECTOR3 v3 = v1 - vLight*10;
        D3DXVECTOR3 v4 = v2 - vLight*10;

        // Add a quad (two triangles) to the vertex list
        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;
    }

    // Delete the temporary edge list
    delete[] pEdges;

    // Unlock the geometry buffers
    pMesh->UnlockVertexBuffer();
    pMesh->UnlockIndexBuffer();

    return S_OK;
}
[/SOURCE]
[/source] The other part of the code is correct i can say for sure... So the prob MUST be in the code i've posted... =/ And YES i've searched around with no result! Kind regards Christian
Q: How does a UNIX Guru do sex? A: unzip; strip; touch; finger; mount; fschk; more; yes; umount; sleep " -- Martin Kahlert
Advertisement
Please post the definition of addEdge(...).

What is the meaning of vLight? It seems me to be the direction against the light source, where the light source is a parallel one?

It is also not clear what rendering settings are activated. I assume you do a blending of a shadow color on top of the formerly rendered geometry? However, the posted image is _very_ dark, so it may be you don't have set-up the blending correctly?!
From the code snippet I don't understand the way of shadow volume computation you are about to implement. The algorithms I know do a computation of the _outline_ of the model's shape as seen from the light. Your algorithm does a computation of all (front) _faces_ to the light. However, this may work if using a stencil buffer temporarily to unify all shadow quads, but, as already mentioned, the rendering pipeline set-up isn't known by me.

However, several algorithms of shadow volumes are thinkable, and possibly I think into the wrong direction. So I need a hint of what kind of algorithm you are thinking about.
I think it's the calculation of v1,v2,v3 and v4...

D3DXVECTOR3 v1 = pVertices[pEdges[2*i+0]].p;
D3DXVECTOR3 v2 = pVertices[pEdges[2*i+1]].p;
D3DXVECTOR3 v3 = v1 - vLight*10;
D3DXVECTOR3 v4 = v2 - vLight*10;

Here's the addEdge()
void ShadowVolume::addEdge( WORD* pEdges, DWORD& dwNumEdges, WORD v0, WORD v1 ){    // Remove interior edges (which appear in the list twice)    for( DWORD i = 0; i < dwNumEdges; ++i )    {        if( ( pEdges[2*i+0] == v0 && pEdges[2*i+1] == v1 ) ||            ( pEdges[2*i+0] == v1 && pEdges[2*i+1] == v0 ) )        {            if( dwNumEdges > 1 )            {                pEdges[2*i+0] = pEdges[2*(dwNumEdges-1)+0];                pEdges[2*i+1] = pEdges[2*(dwNumEdges-1)+1];            }            --dwNumEdges;            return;        }    }    pEdges[2*dwNumEdges+0] = v0;    pEdges[2*dwNumEdges+1] = v1;    dwNumEdges++;}


It might also be that the stencl buffer does a copy of the vertex lines rather then the vertex points...
Q: How does a UNIX Guru do sex? A: unzip; strip; touch; finger; mount; fschk; more; yes; umount; sleep " -- Martin Kahlert
I DID it AGAIN! ;)

It was the calculation of the MESHVERTEX that was wrong...

I added FLOAT tu, tv; like this:

struct MESHVERTEX { D3DXVECTOR3 p, n; FLOAT tu, tv; };

And VÓILA it works! ;) I think that the Mesh got to have more faces then a normal TEAPOT that was used in the former example from Microsoft...

Well it works now... =D

Q: How does a UNIX Guru do sex? A: unzip; strip; touch; finger; mount; fschk; more; yes; umount; sleep " -- Martin Kahlert
Ok: addEdge(...) computes in co-op w/ "only front faces will be processed" the silhouette edges. That was the part I've missed formerly ...

Nevertheless the question remains what meaning and definition vLight has. Looking at the computation of the shadow quad
        D3DXVECTOR3 v1 = pVertices[pEdges[2*i+0]].p;        D3DXVECTOR3 v2 = pVertices[pEdges[2*i+1]].p;        D3DXVECTOR3 v3 = v1 - vLight*10;        D3DXVECTOR3 v4 = v2 - vLight*10;

lets me assume that vLight must be
(1) given in the same co-ordinate system as the mesh, and
(2) is the direction from the face to the light (and not from the light to the face!), and
(3) is a parallel light (like the sun)
or else simply subtracting vLight from v1/v2 "as is" would not be correct.

The decomposition of the quads into the 2 tris is done in CCW order. Is the rendering pipeline set-up done considering this?
My prevous post has become obsolete during typing. That's life ...

But the code was already earlier aware of the count of faces. So it seems that the vertex structure itself was the problem, possibly because you are using additional per vertex data than just the position?!
Quote:Original post by haegarr
My prevous post has become obsolete during typing. That's life ...

But the code was already earlier aware of the count of faces. So it seems that the vertex structure itself was the problem, possibly because you are using additional per vertex data than just the position?!


Exactly! :D

Thx for the help! i appriciate it MUCH! =D

Kind regards

Christian.
Q: How does a UNIX Guru do sex? A: unzip; strip; touch; finger; mount; fschk; more; yes; umount; sleep " -- Martin Kahlert

This topic is closed to new replies.

Advertisement