Getting Pixel Depth

Started by
22 comments, last by Medo Mex 10 years, 8 months ago

Well I wouldn't consider it a 'cost', as it will enable you to draw the scene just once. (Well, not in a project, but for the normal, depth, position, etc... information)

I suggest that you try the suggested method, and then after we can optimize.

FastCall22: "I want to make the distinction that my laptop is a whore-box that connects to different network"

Blog about... stuff (GDNet, WordPress): www.gamedev.net/blog/1882-the-cuboid-zone/, cuboidzone.wordpress.com/

Advertisement

I did the following, now I'm getting a black screen:


void render()
{
IDirect3DSurface9*  oldBB;
device->GetRenderTarget(0, &oldBB);

device->SetRenderTarget(0, DepthSurface);
device->SetRenderTarget(1, ColorSurface);

// -- Render the scene
HRESULT hr = device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
assert(SUCCEEDED(hr));

device->BeginScene();

RenderScene();

device->SetRenderTarget(0, oldBB);
device->SetRenderTarget(1, NULL);
oldBB->Release();

d3ddev->EndScene();
d3ddev->Present(NULL, NULL, NULL, NULL);
}

If i understood d3d process correctly :

When you create the device there is a "main" backbuffer surface created for you implicitly so at last "step" you need to draw to that surface to be able to see something on screen:


void render()
{
IDirect3DSurface9*  oldBB;
device->GetRenderTarget(0, &oldBB); // grabs the last render target, and it happens to be main (backbuffer) since there is nothing set before

device->SetRenderTarget(0, DepthSurface);
device->SetRenderTarget(1, ColorSurface);

// -- Render the scene
HRESULT hr = device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
assert(SUCCEEDED(hr));

device->BeginScene();

RenderScene();

device->SetRenderTarget(0, oldBB); // backbuffer is set
device->SetRenderTarget(1, NULL);
oldBB->Release();
 
DrawSomethingThatUsesDepthAndColorTextureToBackbuffer();

d3ddev->EndScene();
d3ddev->Present(NULL, NULL, NULL, NULL); // "presents" content of the backbuffer to the screen
}


So that means I will have to return depth, color and normal with each Pixel Shader?

It is up you how many RTs you need, what do you want to store in them and when to switch to other RT...

@belfegor: There is something confuse me, I have already drawn everything when I called RenderScene();

Now what should I do in DrawSomethingThatUsesDepthAndColorTextureToBackbuffer()? Should I render the scene again?

Drawing a so-called fullscreen quad with that color render target as texture. Alternatively, switch that color and "depth" rendertarget, so that the color goes to your normal backbuffer - again.

You're now actually close to what is called deferred rendering so you might wanna read about that.

I have 2 problems:
1. I'm using D3DXSaveTextureToFile() in order to try to save the texture to the hard drive for testing purpose, the following line save a screenshot of the window:
HRESULT hr = D3DXSaveTextureToFile("depth.png", D3DXIFF_PNG, DepthTex, NULL);
The following line save pure black image file:
HRESULT hr = D3DXSaveTextureToFile("depth.png", D3DXIFF_PNG, ColorTex, NULL);
I think the first line should save the depth texture?
2. I tried switching between depth and color so I can see the scene as "unbird" suggested, but I see a black screen instead:

IDirect3DSurface9*  oldBB; // "old" backbuffer surface
device->GetRenderTarget(0, &oldBB); // store it, increments ref count

device->SetRenderTarget(0, DepthSurface);
device->SetRenderTarget(1, ColorSurface);

HRESULT hr = device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
assert(SUCCEEDED(hr));

device->BeginScene();

// Draw everything
RenderScene();

device->EndScene();

device->SetRenderTarget(0, ColorSurface); // *** Switch to color surface ***
device->SetRenderTarget(1, NULL);
oldBB->Release(); // decrement ref count

device->Present(NULL, NULL, NULL, NULL);
OMG Medo, you still don't get it. I don't know how to simplify it more.

There is something confuse me, I have already drawn everything when I called RenderScene();

Yes but you draw it to these surfaces:

void Render()
{
...
device->SetRenderTarget(0, DepthSurface);
device->SetRenderTarget(1, ColorSurface);

// -- Render the scene
HRESULT hr = device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
assert(SUCCEEDED(hr));

device->BeginScene();

RenderScene();
...
}

every draw call draws to the last render target set by SetRenderTarget function, but backbuffer surface is still empty so there is nothing to display on screen.

HRESULT hr = D3DXSaveTextureToFile("depth.png", D3DXIFF_PNG, DepthTex, NULL);

Be careful with this function:
1. Dont call it when texture you are about to save has its surface still bound as render target
2. Note the format of the texture you are about the save, as far as i know PNG cannot hold floating point texture, so better to use DDS as it is far more capable.

device->SetRenderTarget(0, ColorSurface); // *** Switch to color surface ***

This is not backbuffer surface so still nothing to display on screen!

Unbird suggested to draw "fullscreen quad" as last step.

EDIT:
Since i doubt that you will find decent tutorial for "fullscreen quad", and i wish that someone helped me at beginning like i do for you now, here is simple example to play with:
cpp
class FSQuad
{
private:
	LPDIRECT3DDEVICE9            device;
	LPDIRECT3DVERTEXBUFFER9      vBuffer;
	LPDIRECT3DINDEXBUFFER9       iBuffer;
	LPDIRECT3DVERTEXDECLARATION9 vDeclaration;

	struct FS_VERTEX
	{
		D3DXVECTOR3 position;
		D3DXVECTOR2 texcoord;
	};

public:

	FSQuad(LPDIRECT3DDEVICE9 _device)
		: device(_device), iBuffer(nullptr), vBuffer(nullptr), vDeclaration(nullptr)
	{
		device->AddRef();
	}

	~FSQuad()
	{
		if(nullptr != device)
		{
			device->Release();
			device = nullptr;
		}

		if(nullptr != iBuffer)
		{
			iBuffer->Release();
			iBuffer = nullptr;
		}

		if(nullptr != vBuffer)
		{
			vBuffer->Release();
			vBuffer = nullptr;
		}

		if(nullptr != vDeclaration)
		{
			vDeclaration->Release();
			vDeclaration = nullptr;
		}
	}

	bool init()
	{
		D3DVERTEXELEMENT9 fsVertexElements[] =
		{
			{0, 0,  D3DDECLTYPE_FLOAT3,  D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
			{0, 12, D3DDECLTYPE_FLOAT2,  D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
			D3DDECL_END()
		};

		HRESULT hr = D3D_OK;
		hr = device->CreateVertexBuffer(sizeof(FS_VERTEX) * 4, D3DUSAGE_WRITEONLY, 0, D3DPOOL_MANAGED, &vBuffer, nullptr);
		if(FAILED(hr))
		{
			MessageBox(0, "Failed to create FS VB!", 0, 0);
			return false;
		}

		hr = device->CreateIndexBuffer(sizeof(USHORT) * 6, D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &iBuffer, nullptr);
		if(FAILED(hr))
		{
			MessageBox(0, "Failed to create FS IB!", 0, 0);
			return false;
		}

		hr = device->CreateVertexDeclaration(fsVertexElements, &vDeclaration);
		if(FAILED(hr))
		{
			MessageBox(0, "Failed to create FS VD!", 0, 0);
			return false;
		}

		float c = 1.0f;
		float z = 1.0f;
		FS_VERTEX* pVertices = nullptr;
		vBuffer->Lock(0, 0, (void**)&pVertices, 0);
		pVertices[0].position = D3DXVECTOR3( -c,  c,  z); pVertices[0].texcoord = D3DXVECTOR2(0.0f, 0.0f);
		pVertices[1].position = D3DXVECTOR3(  c,  c,  z); pVertices[1].texcoord = D3DXVECTOR2(1.0f, 0.0f);
		pVertices[2].position = D3DXVECTOR3(  c, -c,  z); pVertices[2].texcoord = D3DXVECTOR2(1.0f, 1.0f);
		pVertices[3].position = D3DXVECTOR3( -c, -c,  z); pVertices[3].texcoord = D3DXVECTOR2(0.0f, 1.0f);
		vBuffer->Unlock();

		USHORT* pIndices = nullptr;
		iBuffer->Lock(0, 0, (void**)&pIndices, 0);
		pIndices[0]       = 0;
		pIndices[1]       = 1;
		pIndices[2]       = 2;
		pIndices[3]       = 0;
		pIndices[4]       = 2;
		pIndices[5]       = 3;
		iBuffer->Unlock();

		return true;
	}

	void draw()
	{
		device->SetStreamSource(0, vBuffer, 0, sizeof(FS_VERTEX));
		device->SetIndices(iBuffer);
		device->SetVertexDeclaration(vDeclaration);
		device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 4, 0, 2);
	}
};
then you have shader like this, here you could use your depth & color texture:
float4 ScreenParams; // xy width/height of screen

struct VERTEX
{
	float3 Position  : POSITION;
	float2 TexCoord0 : TEXCOORD0;
};

struct VS_OUTPUT
{
	float4 Position  : POSITION;
	float2 TexCoord0 : TEXCOORD0;
};

struct PS_OUTPUT
{
    float4 Color : COLOR0;
};

void VertexProgram(in VERTEX IN, out VS_OUTPUT OUT)
{
	float2 texelOffset = float2(-1.0f / ScreenParams.x, 1.0f / ScreenParams.y);
	float2 result      = IN.Position.xy;
    result.xy         += texelOffset;
	OUT.Position.x     = result.x;
	OUT.Position.y     = result.y;
	OUT.Position.z     = 1.0f;
	OUT.Position.w     = 1.0f;
	OUT.TexCoord0      = float2(0.5f, -0.5f) * IN.Position.xy + 0.5f.xx;
}

void PixelProgram(in VS_OUTPUT IN, out PS_OUTPUT OUT)
{
    ...
    OUT.Color = ...;
}

I'm still getting a window screenshot when I execute this line:


HRESULT hr = D3DXSaveTextureToFile("depth.dds", D3DXIFF_DDS, DepthTex, NULL);

It seems that the render target "DepthTex" is getting color instead of depth map.

1. Where do you call it?

2. Does the camera look at something "useful" at the time when you take the screenshot?

3. What is stored in DepthTex?

1. I'm calling it after device->Present()

2. The camera is looking at far and close mountains, so I think that's a good scene

3. I'm getting a screenshot of the scene instead of the depth texture

I'm sure that D3D9 is writing color to the first render target instead of depth map.

This topic is closed to new replies.

Advertisement