Results 1 to 2 of 2

Thread: Shadow mapping

  1. #1
    Legendary Member NecroDOME's Avatar
    Join Date
    Mar 2004
    Location
    The Netherlands, Eindhoven
    Posts
    1,059

    Shadow mapping

    So, after a while reading tutorials n'stuff I deceided to update my engine so it will support shadow mapping.

    But now I'm a little stuck

    This code is NOT from me, but I want it to work with my engine
    [pascal]constructor TD3DMeshShadow.Create(C:IDirect3DDevice9; _mesh:TD3DXMesh; _light:TD3DXVector3);
    var i:integer;

    begin
    Canvas:=C;
    Mesh:=_Mesh;
    light:=_Light;

    mesh.Mesh.LockVertexBuffer(0, Pointer(pVertices));
    mesh.Mesh.LockIndexBuffer(0, Pointer(pIndices));
    numFaces:=mesh.Mesh.GetNumFaces;

    etLength(pEdges, NumFaces*3);
    NumEdges:=0;

    loclight:=light;

    for i:=0 to NumFaces-1 do begin

    wFace0:=pIndices[3*i+0];
    wFace1:=pIndices[3*i+1];
    wFace2:=pIndices[3*i+2];

    v0:=pVertices[wFace0].position;
    v1:=pVertices[wFace1].position;
    v2:=pVertices[wFace2].position;

    D3DXVec3Subtract(vCross1,v2,v1);
    D3DXVec3Subtract(vCross2,v1,v0);
    D3DXVec3Cross(vNormal,vCross1,vCross2);

    if D3DXVec3Dot(vNormal,loclight)>=0.0 then begin
    AddEdge(pEdges,NumEdges,wFace0,wFace1);
    AddEdge(pEdges,NumEdges,wFace1,wFace2);
    AddEdge(pEdges,NumEdges,wFace2,wFace0);
    end;
    end;

    NumVertices:=0;
    D3DXVec3Scale(v001,loclight,10);
    for i:=0 to NumEdges-1 do begin
    v1:=pVertices[pEdges[2*i+0]].position;
    v2:=pVertices[pEdges[2*i+1]].position;

    D3DXVec3Subtract(v3,v1,v001);
    D3DXVec3Subtract(v4,v2,v001);

    m_pVertices[NumVertices]:=v1; inc(NumVertices);
    m_pVertices[NumVertices]:=v2; inc(NumVertices);
    m_pVertices[NumVertices]:=v3; inc(NumVertices);

    m_pVertices[NumVertices]:=v2; inc(NumVertices);
    m_pVertices[NumVertices]:=v4; inc(NumVertices);
    m_pVertices[NumVertices]:=v3; inc(NumVertices);
    end;

    vb.Lock(0, NumVertices, zeiger, D3DLoCK_DISCARD);
    Move(m_pVertices, zeiger^, NumVertices*SizeOf(TD3DXVector3));
    vb.Unlock;

    setLength(pEdges, 0);

    mesh.Mesh.UnlockVertexBuffer;
    mesh.Mesh.UnlockIndexBuffer;
    end; [/pascal]

    This piece of code uses Lock/Unlock an Index buffer within a TD3DXMesh. My engine supports only my own mesh formats, so how can I adapt this code to work only with vertex buffers or where do the indices come from?

    Here are the resources I got it from:
    Delphi Code:
    http://www.delphidev.de/phpBB2/viewt...er=asc&start=0

    c++ code:
    http://www.codesampler.com/dx9src/dx..._shadow_volume
    NecroSOFT - End of line -

  2. #2
    Legendary Member NecroDOME's Avatar
    Join Date
    Mar 2004
    Location
    The Netherlands, Eindhoven
    Posts
    1,059

    Shadow mapping

    Still can't get it to work

    Here is the full source of my shadow mapper...

    [pascal]unit Necro3DShadowMapper;

    interface

    uses
    Windows, SysUtils,
    OmegaScreen,
    Direct3D9, D3DX9,
    Necro3DLight, Necro3DGeometry, Necro3DMesh, Necro3DVertexDefs, Necro3DMeshInfo;

    type
    TNecro3D_ShadowMapper = class
    private
    FScreen: TOmegaScreen;
    FGeometry : TNecro3D_Geometry;
    FMatrix : TD3DMatrix;
    FRenderEngine: Pointer;

    m_pVertices : array[0..32000] of TD3DVector;
    NumVertices : LongWord;
    NumFaces : LongWord;
    zeiger : Pointer;

    pEdges : array of Word;
    NumEdges : LongWord;

    vb : IDirect3DVertexBuffer9;

    public
    TwoSidedStencilsAvailable : boolean;
    constructor Create;
    procedure Init(Screen :TOmegaScreen; Geometry: TNecro3D_Geometry; RenderEngine: Pointer);
    procedure RenderShadowToStencilBuffer;
    procedure RenderShadowToScene;
    procedure RenderShadow(Light: TNecro3D_Light; Mesh: TNecro3D_MeshInfo);
    procedure BuildShadowVolume(Mesh: TNecro3D_Mesh; Lod: integer; Light: TD3DVector);
    procedure AddEdge(var _pEdges:array of Word; var _dwNumEdges:LongWord; _v0,_v1:Word);
    procedure Reset;
    procedure Render;
    end;

    implementation

    uses
    Necro3DUtils, Necro3DObject, Necro3DLog, Necro3DRender;

    { TNecro3D_ShadowMapper }

    //************************************************** ************
    // Adds an edge to a list of silohuette edges of a shadow volume.
    //************************************************** ************
    procedure TNecro3D_ShadowMapper.AddEdge(var _pEdges: array of Word;
    var _dwNumEdges: LongWord; _v0, _v1: Word);
    var i:integer;
    begin
    for i:=0 to _dwNumEdges-1 do
    begin
    if ((_pEdges[2*i+0]=_v0) and (_pEdges[2*i+1]=_v1)) or
    ((_pEdges[2*i+0]=_v1) and (_pEdges[2*i+1]=_v0)) then
    begin

    if (_dwNumEdges > 1) then
    begin
    _pEdges[2*i+0]:=_pEdges[2*(_dwNumEdges-1)+0];
    _pEdges[2*i+1]:=_pEdges[2*(_dwNumEdges-1)+1];
    end;

    Dec(_dwNumEdges);
    Exit;
    end;
    end;

    _pEdges[2*_dwNumEdges+0] := _v0;
    _pEdges[2*_dwNumEdges+1] := _v1;
    inc(_dwNumEdges);
    end;

    //************************************************** ************
    // Technique used considers each triangle of the mesh, and adds it's
    // edges to a temporary list. The edge list is maintained, such that
    // only silohuette edges are kept. Finally, the silohuette edges are
    // extruded to make the shadow volume vertex list.
    //************************************************** ************
    procedure TNecro3D_ShadowMapper.BuildShadowVolume(Mesh: TNecro3D_Mesh; Lod: integer;
    Light: TD3DVector);
    var i : integer;
    LocLight : TD3DVector;
    wface0, wface1, wface2 : Word;
    v0, v1, v2, v3, v4: TD3DVector;
    v001: TD3DVector;
    vNormal, vCross1, vCross2:TD3DVector;
    begin
    // Mesh.LockVertexBuffer(0, Pointer(pVertices));
    // Mesh.LockIndexBuffer(0, Pointer(pIndices));

    numFaces := Mesh.LOD[Lod].Necro3D_Object.GetTriangleCount;

    SetLength(pEdges, NumFaces*3);
    NumEdges := 0;

    LocLight := Light;

    for i := 0 to NumFaces-1 do
    begin
    with Mesh.LOD[Lod].Necro3D_Object do
    begin
    wFace0 := Triangles[i].Verticles[0].Vector;
    wFace1 := Triangles[i].Verticles[1].Vector;
    wFace2 := Triangles[i].Verticles[2].Vector;

    v0 := Vectors[ wFace0 ];
    v1 := Vectors[ wFace1 ];
    v2 := Vectors[ wFace2 ];
    end;
    {
    wFace0 := pIndices[3*i+0];
    wFace1 := pIndices[3*i+1];
    wFace2 := pIndices[3*i+2];

    v0 := MakeD3DVector(pVertices[wFace0].x, pVertices[wFace0].y, pVertices[wFace0].z);
    v1 := MakeD3DVector(pVertices[wFace1].x, pVertices[wFace1].y, pVertices[wFace1].z);
    v2 := MakeD3DVector(pVertices[wFace2].x, pVertices[wFace2].y, pVertices[wFace2].z);
    }

    D3DXVec3Subtract(vCross1, v2, v1);
    D3DXVec3Subtract(vCross2, v1, v0);
    D3DXVec3Cross(vNormal, vCross1, vCross2);

    if D3DXVec3Dot(vNormal, LocLight)>=0.0 then
    begin
    AddEdge(pEdges, NumEdges, wFace0, wFace1);
    AddEdge(pEdges, NumEdges, wFace1, wFace2);
    AddEdge(pEdges, NumEdges, wFace2, wFace0);
    end;
    end;

    NumVertices := 0;
    D3DXVec3Scale(v001, LocLight, 10);

    for i := 0 to NumEdges-1 do
    begin
    with Mesh.LOD[Lod].Necro3D_Object do
    begin
    v1 := Vectors[pEdges[2*i+0]];
    v2 := Vectors[pEdges[2*i+1]];
    end;
    {
    v1 := MakeD3DVector(pVertices[pEdges[2*i+0]].x, pVertices[pEdges[2*i+0]].y, pVertices[pEdges[2*i+0]].z);
    v2 := MakeD3DVector(pVertices[pEdges[2*i+1]].x, pVertices[pEdges[2*i+1]].y, pVertices[pEdges[2*i+1]].z);
    }
    D3DXVec3Subtract(v3, v1, v001);
    D3DXVec3Subtract(v4, v2, v001);

    m_pVertices[NumVertices] := v1; inc(NumVertices);
    m_pVertices[NumVertices] := v2; inc(NumVertices);
    m_pVertices[NumVertices] := v3; inc(NumVertices);

    m_pVertices[NumVertices] := v2; inc(NumVertices);
    m_pVertices[NumVertices] := v4; inc(NumVertices);
    m_pVertices[NumVertices] := v3; inc(NumVertices);
    end;

    FScreen.Device.CreateVertexBuffer(32000*SizeOf(TD3 DVector),
    D3DUSAGE_WRITEONLY,
    D3DFVF_XYZ,
    D3DPOOL_MANAGED,
    vb, nil);

    vb.Lock(0, NumVertices*3, zeiger, 0);
    Move(m_pVertices, zeiger^, NumVertices*SizeOf(TD3DVector));
    vb.Unlock;

    setLength(pEdges, 0);

    // mesh.Mesh.UnlockVertexBuffer;
    // mesh.Mesh.UnlockIndexBuffer;
    end;

    constructor TNecro3D_ShadowMapper.Create;
    begin
    TwoSidedStencilsAvailable := False;
    end;

    procedure TNecro3D_ShadowMapper.Init(Screen: TOmegaScreen; Geometry: TNecro3D_Geometry;
    RenderEngine: Pointer);
    begin
    FScreen := Screen;
    FGeometry := Geometry;
    FRenderEngine := RenderEngine;
    end;

    procedure TNecro3D_ShadowMapper.Render;
    begin
    FScreen.Device.SetFVF( D3DFVF_XYZ );
    FScreen.Device.SetStreamSource(0, vb, 0, SizeOf(TD3DVector));
    FScreen.Device.DrawPrimitive( D3DPT_TRIANGLELIST, 0, NumVertices);
    end;

    procedure TNecro3D_ShadowMapper.RenderShadow(Light: TNecro3D_Light; Mesh: TNecro3D_MeshInfo);
    var Matrix, MatInverse : TD3DMatrix;
    LightInWorldSpace, LightInObjectSpace : TD3DVector;
    begin
    // transform the light vector from world-space to object-space, so
    // the teapot and light will both be in the same frame of reference.
    Matrix := Mesh.GetMatrix;

    LightInWorldSpace := Maked3DVector( Light.Position.x, Light.Position.y, Light.Position.z );

    D3DXMatrixInverse( MatInverse, nil, Matrix );
    D3DXVec3TransformNormal( LightInObjectSpace, LightInWorldSpace, MatInverse );

    FMatrix := MatInverse;
    // Using the light's object-space position, build the shadow volume
    // from the teapot's DX9 mesh.

    // Reset;
    if Mesh.MeshIndex<>-1 then
    BuildShadowVolume(FGeometry.MeshList.Meshes[ Mesh.MeshIndex ], 0, LightInObjectSpace );

    FScreen.Device.Clear( 0, nil, D3DCLEAR_TARGET or D3DCLEAR_ZBUFFER or D3DCLEAR_STENCIL,
    D3DCOLOR_COLORVALUE(0.0, 0.0, 0.0, 1.0), 1.0, 0 );
    end;

    procedure TNecro3D_ShadowMapper.RenderShadowToScene;
    var RenderTextures, RenderLights: boolean;
    begin
    // Set render states
    FScreen.Device.SetRenderState( D3DRS_ZENABLE, 0 );
    FScreen.Device.SetRenderState( D3DRS_STENCILENABLE, 1 );
    FScreen.Device.SetRenderState( D3DRS_ALPHABLENDENABLE, 1 );
    FScreen.Device.SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
    FScreen.Device.SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );


    FScreen.Device.SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
    FScreen.Device.SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
    FScreen.Device.SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
    FScreen.Device.SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
    FScreen.Device.SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
    FScreen.Device.SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );

    // Only write where stencil value >= 1 (count indicates # of shadows that
    // overlap that pixel)
    FScreen.Device.SetRenderState( D3DRS_STENCILREF, 1 );
    FScreen.Device.SetRenderState( D3DRS_STENCILFUNC, D3DCMP_LESSEQUAL );
    FScreen.Device.SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_KEEP );

    // Render world ??
    // Draw a big, gray square
    {
    RenderTextures := TNecro3D_Render( FRenderEngine ).RenderTextures;
    RenderLights := TNecro3D_Render( FRenderEngine ).RenderLights;
    TNecro3D_Render( FRenderEngine ).RenderTextures := False;
    TNecro3D_Render( FRenderEngine ).RenderLights := False;
    TNecro3D_Render( FRenderEngine ).RenderGeometry;
    TNecro3D_Render( FRenderEngine ).RenderTextures := RenderTextures;
    TNecro3D_Render( FRenderEngine ).RenderLights := RenderLights;
    }

    // g_pd3dDevice->SetFVF( ShadowVertex::FVF_Flags );
    // g_pd3dDevice->SetStreamSource( 0, m_pBigSquareVB, 0, sizeof(ShadowVertex) );
    // g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );

    // Restore render states
    FScreen.Device.SetRenderState( D3DRS_ZENABLE, 1 );
    FScreen.Device.SetRenderState( D3DRS_STENCILENABLE, 0 );
    FScreen.Device.SetRenderState( D3DRS_ALPHABLENDENABLE, 0 );
    end;

    procedure TNecro3D_ShadowMapper.RenderShadowToStencilBuffer;
    begin
    // Disable z-buffer writes (note: z-testing still occurs), and enable the
    // stencil-buffer
    FScreen.Device.SetRenderState(D3DRS_ZWRITEENABLE, 0);
    FScreen.Device.SetRenderState(D3DRS_STENCILENABLE, 1);

    // Dont bother with interpolating color
    FScreen.Device.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.
    FScreen.Device.SetRenderState( D3DRS_STENCILFUNC, D3DCMP_ALWAYS );
    FScreen.Device.SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP );
    FScreen.Device.SetRenderState( D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP );

    // If z-test passes, inc/decrement stencil buffer value
    FScreen.Device.SetRenderState( D3DRS_STENCILREF, 1 );
    FScreen.Device.SetRenderState( D3DRS_STENCILMASK, $FFFFFFFF );
    FScreen.Device.SetRenderState( D3DRS_STENCILWRITEMASK, $FFFFFFFF );
    FScreen.Device.SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_INCR );

    // Make sure that no pixels get drawn to the frame buffer
    FScreen.Device.SetRenderState( D3DRS_ALPHABLENDENABLE, 1 );
    FScreen.Device.SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ZERO );
    FScreen.Device.SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );

    if TwoSidedStencilsAvailable then
    begin
    // With 2-sided stencil, we can avoid rendering twice:
    FScreen.Device.SetRenderState( D3DRS_TWOSIDEDSTENCILMODE, 1 );
    FScreen.Device.SetRenderState( D3DRS_CCW_STENCILFUNC, D3DCMP_ALWAYS );
    FScreen.Device.SetRenderState( D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_KEEP );
    FScreen.Device.SetRenderState( D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_KEEP );
    FScreen.Device.SetRenderState( D3DRS_CCW_STENCILPASS, D3DSTENCILOP_DECR );

    FScreen.Device.SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );

    // Draw both sides of shadow volume in stencil/z only
    FScreen.Device.SetTransform( D3DTS_WORLD, FMatrix );
    Render;

    FScreen.Device.SetRenderState( D3DRS_TWOSIDEDSTENCILMODE, 0 );
    end else
    begin
    // Draw front-side of shadow volume in stencil/z only
    FScreen.Device.SetTransform( D3DTS_WORLD, FMatrix );
    Render;

    // Now reverse cull order so back sides of shadow volume are written.
    FScreen.Device.SetRenderState( D3DRS_CULLMODE, D3DCULL_CW );

    // Decrement stencil buffer value
    FScreen.Device.SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_DECR );

    // Draw back-side of shadow volume in stencil/z only
    FScreen.Device.SetTransform( D3DTS_WORLD, FMatrix );
    Render;
    end;

    // Restore render states
    FScreen.Device.SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD );
    FScreen.Device.SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );
    FScreen.Device.SetRenderState( D3DRS_ZWRITEENABLE, 1 );
    FScreen.Device.SetRenderState( D3DRS_STENCILENABLE, 0 );
    FScreen.Device.SetRenderState( D3DRS_ALPHABLENDENABLE, 0 );
    end;

    procedure TNecro3D_ShadowMapper.Reset;
    begin
    NumVertices := 0;
    end;

    end.[/pascal]

    Hopefully I get it up and running soon!
    NecroSOFT - End of line -

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •