• Advertisement
Sign in to follow this  

Getting Pixel Depth

This topic is 1651 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Advertisement

You render depth into texture (or to depth stencil that can be read as textures but it is vendor specific), so for examaple you could use MRT to do this in one pass:

 

1. Create MRTs (check all functions for failure, i didn't do that for readability) :

d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
D3DFORMAT fmt = D3DFMT_A32B32G32R32F;
device->CreateTexture(SIZE_X, SIZE_Y, 1, D3DUSAGE_RENDERTARGET, fmt, D3DPOOL_DEFAULT, &DepthTex, NULL); // use for depth/position
DepthTex->GetSurfaceLevel(0, &DepthSurface);
if(caps.PrimitiveMiscCaps & D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS) // if device supports independent bit depth for each RT you can save some space
{
            fmt = D3DFMT_A8R8G8B8;
}
device->CreateTexture(SIZE_X, SIZE_Y, 1, D3DUSAGE_RENDERTARGET, fmt D3DPOOL_DEFAULT, &ColorTex, NULL); // use for color/diffuse
ColorTex->GetSurfaceLevel(0, &ColorSurface);

 

2. While rendering:

void DrawAll()
{
...
IDirect3DSurface9*  oldBB; // "old" backbuffer surface
device->GetRenderTarget(0, &oldBB); // store it, increments ref count
 
device->SetRenderTarger(0, DepthSurface);
device->SetRenderTarger(1, ColorSurface);
 
DrawStuff();
 
device->SetRenderTarger(0, oldBB);
device->SetRenderTarger(1, NULL);
oldBB->Release(); // decrement ref count
 
... // here you must use above color and depth to draw to backbuffer
 

}

 

3. In DrawStuff you'll have shader something like this:

...
struct VS_OUTPUT
{
    float4 Position : POSITION;
    float3 DepthWorldPos : TEXCOORD0;
    float2 TexCoord : TEXCOORD1;
    ...// and rest of the stuff you need
}
void VertexProgram(...)
{
    OUT.Position = mul( IN.Position, WorldViewProj );
    // let say we want to store world space xyz position
    // i wrote this because there is multiple ways/spaces to store "depth", and you must choose what is what you want
   OUT.DepthWorldPos = mul( IN.Position, World ).xyz;
    OUT.TexCoord = IN.TexCoord;
}
 
struct PS_OUTPUT
{
    float4 DepthPos : COLOR0; // first render target
    float4 Color : COLOR1; // second render target
};
 
void PixelProgram(...)
{
   float4 diffuse = tex2D( diffuseSamp, IN.TexCoord );
   ...// rest of the stuff you need
 
    OUT.DepthPos = float4(IN.DepthWorldPos.xyz, 1.0f);
    OUT.Color = diffuse;
}

 

and now you have it.

Share this post


Link to post
Share on other sites

No, I meant the depth of the particles, not the depth of the entire scene.

 

How do I get the depth of the particles in my Particles Pixel Shader?

Share this post


Link to post
Share on other sites

like the depth of a pixel on a particle?

 

Well... I actually do agree with belfegor.

 

But if you don't want to write it to any texture, you can just access it in the same shader, so you could do the following:

VS
output.DepthPos.xyz = mul(float4(input.position.xyz,1), mul(worldMatrix, viewMatrix)).xyz;

PS
float pixelDepth = input.DepthPos.z; // Tada!

About this:

... not the depth of the entire scene.

 

Well you need to compare the particle depth to the scene depth at some point. biggrin.png

Edited by Migi0027

Share this post


Link to post
Share on other sites

Hodgman recommended to create INTZ depth texture and pass it to Pixel Shader:

http://www.gamedev.net/topic/641964-smoke-environment/

 

He said that MRT requires editing all our shaders, I'm not sure what editing all shaders means.

 

Creating INTZ depth texture fail when I have anti-analyzing enabled.

 

So I'm looking for alternatives for creating depth texture and at the same time having anti-analyzing enabled.

Share this post


Link to post
Share on other sites

He said that MRT requires editing all our shaders, I'm not sure what editing all shaders means.

Usually you output to one render target from pixel shader:

cpp:

device->SetRenderTarget(0, someSurface);

shader:

struct PS_OUTPUT
{
    float4 Color0 : COLOR0;
};
 
void PixelProgram( out PS_OUTPUT OUT )
{
    ...
    OUT.Color0 = ...// something
}

With MRTs (to avoid multiple passes) you can output to multiple render targets (up to 4 is maximum i think):

cpp:

device->SetRenderTarget(0, rt0Surface);
device->SetRenderTarget(1, rt1Surface);
device->SetRenderTarget(2, rt2Surface);
device->SetRenderTarget(3, rt3Surface);

shader:

struct PS_OUTPUT
{
    float4 Depth : COLOR0;
    float4 Color : COLOR1;
    float4 Normal : COLOR2;
    float4 FooBar : COLOR3;
};
 
void PixelProgram( out PS_OUTPUT OUT )
{
    ...
    OUT.Depth = ...// something
    OUT.Color = ...// something
    OUT.Normal = ...// something
    OUT.FooBar = ...// something
}

Do you get it now?

Edited by belfegor

Share this post


Link to post
Share on other sites

I actually use 5 render targets now ph34r.png I have secretly packed the depth and the view space positions into two different textures.

 

Hmm. I thought the D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT was 8, at least in mine it is. tongue.png

 

EDIT: Whoops, this is dx9...

Edited by Migi0027

Share this post


Link to post
Share on other sites

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

 

If yes, is there is anyway without that cost?

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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);
}

Share this post


Link to post
Share on other sites

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...

Edited by belfegor

Share this post


Link to post
Share on other sites

@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?

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites
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);

Share this post


Link to post
Share on other sites
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 = ...;
}
Edited by belfegor

Share this post


Link to post
Share on other sites

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.

Edited by Medo3337

Share this post


Link to post
Share on other sites

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?

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites
When you set:

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

Note in shader to match:

struct PS_OUTPUT
{
float4 Depth : COLOR0;
float4 Color : COLOR1;
};

void PixelProgram( ..., out PS_OUTPUT )
{
OUT.Depth = ...// first render target
OUT.Color = ...// second render target
}


also check to make sure when you create textures that you don't have possible typos:

device->CreateTexture(...., &DepthTex);
DepthTex->GetSurfaceLevel(0, &DepthSurface);

device->CreateTexture(...., &ColorTex);
ColorTex->GetSurfaceLevel(0, &ColorSurface);

to not be something like this:

device->CreateTexture(...., &DepthTex);
DepthTex->GetSurfaceLevel(0, &ColorSurface);

device->CreateTexture(...., &ColorTex);
ColorTex->GetSurfaceLevel(0, &DepthSurface);

Edited by belfegor

Share this post


Link to post
Share on other sites

I'm not doing anything in the shader yet, I'm just trying to create depth texture and save it to the hard drive.

 

Still same problem even after I checked for typos, here is the code:

Init:

LPDIRECT3DTEXTURE9 DepthTex;
LPDIRECT3DTEXTURE9 ColorTex;

LPDIRECT3DSURFACE9 DepthSurface;
LPDIRECT3DSURFACE9 ColorSurface;

void init()
{
    D3DCAPS9 caps;
    d3d->GetDeviceCaps(D3DADAPTER_DEFAULT, deviceTYPE_HAL, &caps);
    D3DFORMAT fmt = D3DFMT_A32B32G32R32F;
    device->CreateTexture(WindowWidth, WindowHeight, 1, D3DUSAGE_RENDERTARGET, fmt, D3DPOOL_DEFAULT, &DepthTex, NULL); // use for depth/position
    DepthTex->GetSurfaceLevel(0, &DepthSurface);
    if(caps.PrimitiveMiscCaps & D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS) // if device supports independent bit depth for each RT you can save some space
    {
        fmt = D3DFMT_A8R8G8B8;
    }
    device->CreateTexture(WindowWidth, WindowHeight, 1, D3DUSAGE_RENDERTARGET, fmt, D3DPOOL_DEFAULT, &ColorTex, NULL); // use for color/diffuse
    ColorTex->GetSurfaceLevel(0, &ColorSurface);
}

Rendering:

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();
RenderScene();

device->SetRenderTarget(0, oldBB);
device->SetRenderTarget(1, NULL);
oldBB->Release(); // decrement ref count

RenderScene();
device->EndScene();

hr = device->Present(NULL, NULL, NULL, NULL);

static bool bSaved = false;
if (GetAsyncKeyState(VK_SPACE) != 0 && !bSaved)
{
HRESULT hr = D3DXSaveTextureToFile("depth.dds", D3DXIFF_DDS, DepthTex, NULL);
assert(SUCCEEDED(hr));
bSaved = true;
}

 

Edited by Medo3337

Share this post


Link to post
Share on other sites

Here is the complete sample project in attachment. Press F2 to save both Depth and Color textures.

 

I am usin ACDSee for image viewing with dds plugin:

 

This is Color saved:

color.jpg

 

This is Depth saved:

depth.jpg

 

This is actual screen (backbuffer content):

terrain2013-08-1321-31-0.jpg

Edited by belfegor

Share this post


Link to post
Share on other sites

@belfegor: I think I created the depth texture.

 

I have attached 2 DDS image files one for color texture and the other the depth (I saved both using D3DXSaveTextureToFile() from color surface and depth surface)

 

I'm not sure if this is a valid depth texture, let me know if this is a VALID depth texture:

http://www.2shared.com/file/iEoxpmdd/depth_dds.html

 

The file is about 5 MB so I had to upload it outside GameDev since here 2 MB per file is the maximum file size allowed.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement