Skip to main content
GameDev.net gamedev.net
🔒 Locked

Multiple viewports and shadow maps -- overwriting or not initialised properly?

Started by Warwick Michael Dumas Jan 13, 2013 at 4:45 PM 1 replies 2.2k views
Original Post
Warwick Michael Dumas
Warwick Michael Dumas

Hi. N00b here.


I wrote a class to create a graph of a surface and this class includes a shadow map. With one object it works fine. With multiple objects, strange things are happening. See picture - for all six objects the same calls are made, only the viewport coordinates are different. Only one of them displays the shadow correctly. The rendering sequence of the objects makes a difference to the behaviour, so it seems to me it is a problem with the way the shadow maps get initialised.

For the attached picture, this was the way the objects were treated:


surfacegraph Graph3,  Graph4, Graph2, Graph5, Graph6,Graph;

.....

	Graph.Initialise(perRow,0,0,600,520,nscale,Eye);
	Graph2.Initialise(perRow,0,525,600,520,nscale,Eye);
	Graph3.Initialise(perRow,580,0,480,520,nscale,Eye);
	Graph4.Initialise(perRow,580,525,480,520,nscale,Eye);
	Graph5.Initialise(perRow,1050,0,600,520,nscale,Eye);
	Graph6.Initialise(perRow,1050,525,600,520,nscale,Eye);

.....

	Graph2.Render(); // the rendering sequence appears to make a big difference
	Graph4.Render(); // to the shadow maps that result
	Graph6.Render(); 
	Graph.Render();  
	Graph3.Render(); 
	Graph5.Render(); 

This creates the picture where Graph2 displays correctly, Graph displays with no shadow and all the rest display completely in shadow.

However I don't see why the objects are affecting each others' shadow maps.

This is some of the class definition:


class surfacegraph
{
public:
	static const int SHADOWMAPRESOLUTION = 4096;

	int perRow; int texWidth,texHeight; int numVertices, numTriangles;
	
	IDirect3DVertexBuffer9* TerrainVertexBuffer;
	IDirect3DIndexBuffer9* TerrainIndexBuffer;
	IDirect3DTexture9*  texture_grid;

	D3DVIEWPORT9  vp;
	D3DVIEWPORT9  shadow_vp;

	ID3DXEffect* mFX;

	D3DXMATRIXA16 matView;
	D3DXMATRIXA16 matProj;
	
	DirLight mLight;
	Mtrl     mWhiteMtrl;

	D3DXVECTOR3 Eye; // eye position
	
	// for shadow map:
	IDirect3DSurface9* pSurface;   // never gets used for anything though - not sure why this was here
	
	D3DXMATRIX  mLightVP;
	
	DrawableTex2D* mShadowMap;   
	
	D3DXHANDLE   mhTech;
	D3DXHANDLE   mhWVP;
	D3DXHANDLE   mhTex;
	D3DXHANDLE   mhEyePos;         // for specular
	D3DXHANDLE   mhDiffuseMtrl;
	D3DXHANDLE   mhAmbientMtrl;
	D3DXHANDLE   mhLightVector;
	D3DXHANDLE   mhLightDiffuseColour;
	D3DXHANDLE   mhLightAmbientColour;
	D3DXHANDLE   mhLightSpecularColour;
	D3DXHANDLE   mhSpecularMtrl;
	D3DXHANDLE   mhSpecularPower;
	
	D3DXHANDLE   mhBuildShadowMapTech;
	D3DXHANDLE   mhLightWVP;
	D3DXHANDLE   mhShadowMap;
	D3DXHANDLE   mhSwitch;

	float xyscale,nscale;

	surfacegraph();
	
	HRESULT Initialise(  parameters  );
	
          ...
	HRESULT SetxzDataAutomatic (float minimum, float maximum, float in_xyscale);
        HRESULT SetDataFromDoubleScaled(double **, double);
	HRESULT SetDataAgain(float **);
	HRESULT SetColourData(float **, float **, float **);

	VOID surfacegraph::Render(void);

	~surfacegraph();
};

The following is the start of the Render method for the class. See code comments.



VOID surfacegraph::Render()
{
	
	....
		
	// DRAW SHADOW MAP:	
	Direct3D.pd3dDevice->SetViewport(&vp); 
	// without this^^^, 5 graphs, all except the last rendered, appear as small shadows on white

	mShadowMap->beginScene();

	//Direct3D.pd3dDevice->SetViewport(&shadow_vp); 
	// completely whites out all but last-to-render graph. No idea why. 
	// That may suggest that Device->Clear is affecting the back buffer but we also know it is affecting the shadow map!
	
	Direct3D.pd3dDevice->Clear( 0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
				D3DCOLOR_XRGB( 255, 255, 255 ), 1.0f, 0 );   
                // this clearly does affect shadow map successfully...        

                    //    0x00000000, 1.0f, 0 );		
                    // because this^^^^^ leads to everything being in shadow
	
	DXChk(mFX->SetTechnique(mhBuildShadowMapTech));
	
	UINT numPasses = 0;
	DXChk(mFX->Begin(&numPasses, 0));
	
	DXChk(mFX->SetMatrix(mhLightWVP, &(mLightVP)));
	DXChk(mFX->CommitChanges());
	
     Direct3D.pd3dDevice->SetStreamSource(0, TerrainVertexBuffer, 0, sizeof(VertexPNT));
	Direct3D.pd3dDevice->SetIndices(TerrainIndexBuffer);
	Direct3D.pd3dDevice->SetVertexDeclaration(VertexPNT::Decl);
				
	for (UINT ii = 0; ii < numPasses; ++ii)
		{
			mFX->BeginPass(ii);
			
			Direct3D.pd3dDevice->DrawIndexedPrimitive(
				D3DPT_TRIANGLELIST,
				0,
				0,
				numVertices,
				0,
				numTriangles);
			mFX->EndPass();
		};
	DXChk(mFX->End());
	mShadowMap->endScene();
	
	
	// axis drawing in fixed function pipeline:
	Direct3D.pd3dDevice->SetViewport(&vp);
        ...

	

In case it is necessary background information, the "DrawableTex2D" class is


class DrawableTex2D
{
public:
	IDirect3DTexture9*    mTex;
	ID3DXRenderToSurface* mRTS;
	IDirect3DSurface9*    mTopSurf;

	UINT         mWidth;
	UINT         mHeight;
	UINT         mMipLevels;
	D3DFORMAT    mTexFormat;
	bool         mUseDepthBuffer;
	D3DFORMAT    mDepthFormat;
	D3DVIEWPORT9 mViewPort;
	bool         mAutoGenMips;

        DrawableTex2D(UINT width, UINT height, UINT mipLevels,
		D3DFORMAT texFormat, bool useDepthBuffer,
		D3DFORMAT depthFormat, D3DVIEWPORT9& viewport, bool autoGenMips);
	~DrawableTex2D();

	IDirect3DTexture9* d3dTex();

	void beginScene();
	void endScene();
	void onLostDevice();
	void onResetDevice();

	DrawableTex2D(const DrawableTex2D& rhs);
	DrawableTex2D& operator=(const DrawableTex2D& rhs);
};

IDirect3DTexture9* DrawableTex2D::d3dTex()
{
	return mTex;
}

void DrawableTex2D::onResetDevice()
{
	UINT usage = D3DUSAGE_RENDERTARGET;
	if(mAutoGenMips)
		usage |= D3DUSAGE_AUTOGENMIPMAP;

	DXChk(D3DXCreateTexture(Direct3D.pd3dDevice, mWidth, mHeight, mMipLevels, usage, mTexFormat, D3DPOOL_DEFAULT, &mTex));
	DXChk(D3DXCreateRenderToSurface(Direct3D.pd3dDevice, mWidth, mHeight, mTexFormat, mUseDepthBuffer, mDepthFormat, &mRTS));
	DXChk(mTex->GetSurfaceLevel(0, &mTopSurf));
}

void DrawableTex2D::beginScene()
{
	mRTS->BeginScene(mTopSurf, &mViewPort);
}
void DrawableTex2D::endScene()
{
	mRTS->EndScene(D3DX_FILTER_NONE);
}

The following method is called, once only, after the graph object has been declared.


HRESULT surfacegraph::Initialise(  parameters  )
{
         ...

	shadow_vp.X = 0; shadow_vp.Y = 0;
	shadow_vp.Width = SHADOWMAPRESOLUTION;
	shadow_vp.Height = SHADOWMAPRESOLUTION;
	shadow_vp.MinZ = 0.0f;
	shadow_vp.MaxZ = 1.0f;
	
	mShadowMap = new DrawableTex2D(SHADOWMAPRESOLUTION, SHADOWMAPRESOLUTION, 1, D3DFMT_R32F, true, D3DFMT_D24X8, shadow_vp, false);
	
	vp.X = left;
	vp.Y = top;
	vp.Width = width;
	vp.Height = height;
	vp.MinZ = 0.0f;
	vp.MaxZ = 0.0f;

	float GlobalAspectRatio = ((float)vp.Width)/(float)vp.Height;
	
	// Create the FX from a .fx file.
	ID3DXBuffer* errors = 0;
	D3DXCreateEffectFromFile(Direct3D.pd3dDevice, "test1.fx", 
		0, 0, D3DXSHADER_DEBUG, 0, &mFX, &errors);
	
	if( errors ) 
		MessageBox(0, (char*)errors->GetBufferPointer(), 0, 0);	
	
	// Obtain handles.
	
	mhTech = mFX->GetTechniqueByName("WarwickTech");

	........

	mShadowMap->onResetDevice();

	static D3DXVECTOR3 vLookatPt( 0.0f, 1.2f, 0.0f );
	static D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
    
	Eye = in_Eye;

	D3DXMatrixLookAtLH( &matView, &Eye, &vLookatPt, &vUpVec );	
	D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI / 4.0f, GlobalAspectRatio, 1.0f, 12.0f);
	
	mLight.dirW    = D3DXVECTOR3(-1.0f, -0.5f, 0.5f);// remember y is height
	D3DXVec3Normalize(&mLight.dirW, &mLight.dirW);
	mLight.ambient = D3DXCOLOR(0.4f, 0.4f, 0.4f, 1.0f);
	mLight.diffuse = D3DXCOLOR(0.6f, 0.6f, 0.6f, 1.0f);
	mLight.spec    = D3DXCOLOR(0.5f, 0.5f, 0.5f, 1.0f);
	mWhiteMtrl.ambient = WHITE*1.0f;
	mWhiteMtrl.diffuse = WHITE*1.0f;
	mWhiteMtrl.spec    = WHITE*1.0f;
	mWhiteMtrl.specPower = 8.0f;
	
	// Shadow mapping:
	
	D3DXMATRIX lightView;
	D3DXVECTOR3 lightPosW(20.0f, 10.0f, -10.0f);
	D3DXVECTOR3 lightTargetW(0.0f, 0.0f, 0.0f);
	D3DXVECTOR3 lightUpW(0.0f, 1.0f, 0.0f);	

	D3DXMatrixLookAtLH(&lightView, &lightPosW, &lightTargetW, &lightUpW);
		
	D3DXMATRIX lightLens;
	float lightFOV = D3DX_PI*0.25f;
	D3DXMatrixPerspectiveFovLH(&lightLens, lightFOV, 1.0f, 1.0f, 100.0f);
	
	mLightVP = lightView*lightLens;
	

        // graph data:
	perRow = nperRow;

	numVertices = perRow*perRow;
	numTriangles = 2*(perRow-1)*(perRow-1);
	
	texWidth = perRow;
	texHeight = perRow;
	definedindices = 0;
	
	if (
	DXChk(
	Direct3D.pd3dDevice->CreateVertexBuffer(numVertices*sizeof(VertexPNT),D3DUSAGE_WRITEONLY,0,D3DPOOL_MANAGED,&TerrainVertexBuffer,0),1)
		+ 
	DXChk( 
	Direct3D.pd3dDevice->CreateIndexBuffer(numTriangles*3*sizeof(DWORD),D3DUSAGE_WRITEONLY,	D3DFMT_INDEX32,	D3DPOOL_MANAGED,&TerrainIndexBuffer,0),2)
		+		
	DXChk(	D3DXCreateTexture( Direct3D.pd3dDevice, texWidth,texHeight, 0,0,D3DFMT_X8R8G8B8,D3DPOOL_MANAGED, &texture_grid),3)			
		)
		return E_FAIL;
	
	D3DSURFACE_DESC textureDesc;
	texture_grid->GetLevelDesc(0, &textureDesc);
	if ( textureDesc.Format != D3DFMT_X8R8G8B8 ) return E_FAIL;
	
	return S_OK;
}

Sorry to provide so much code, I'm not all that sure what is going on here. I have tried tinkering with what happens at the start of the Render method but I don't seem to know what I'm doing, the results (as described in the code comments) are hard for me to interpret.

Grateful for any suggestions.

I am happy to dropbox the whole source if anyone wishes to tinker with it.

Jason Z
Jason Z

Can you describe what the arguments are for your Graph.Initialize function? If they are the viewport coordinates, then it seems that they may be overlapping somehow - but that might just be because I'm not sure how they are interpreted.

Jason Zink :: DirectX MVP   Direct3D 11 engine on CodePlex: Hieroglyph 3 Direct3D Books: 
Warwick Michael Dumas
Warwick Michael Dumas

Sure here are the arguments



HRESULT surfacegraph::Initialise(int nperRow, // data points per row if square grid data to be supplied
int left, int top, int width, int height, float fscale, D3DXVECTOR3 in_Eye,
bool Polar = 0, 
int number_in_outermost = 0, // data points in outermost circle if radially distributed data
int number_circles = 0,    // number of circles              if radially distributed data
float radius_outermost = 0.0f    //  max radius              if radially distributed data
) 
The viewport coordinates are left,top,width,height. (And it's not radially distributed data). The calls to Initialise are in the top code box above. So yes, they are a bit overlapping. I think that should be OK though... the rendering of each object is meant to be independent.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.