Skip to main content
GameDev.net gamedev.net
Using GameDev.net for your class this semester?
Learn more →
🔒 Locked

How to set depth value in pixel shader

Started by p4rse Jun 13, 2010 at 10:44 AM 8 replies 10k views
Original Post
p4rse
p4rse
I'm trying to replicate this really interesting rendering technique:
">


Basically what i'm trying to do is; render a 2D sprite with a depthmap, making it "2.5D" or pseudo-3D.

I'm using XNA and its built in SpriteBatch, but with a custom pixel shader. Here's a simplified version of my shader:
sampler TextureSampler : register(s0); sampler DepthSampler : register(s1);  void PS(in    float2 UV    : TEXCOORD0,         inout float4 Color : COLOR0,         out   float  Depth : DEPTH) {     Color.rgb = tex2D(TextureSampler, UV);     Depth = tex2D(DepthSampler, UV).r; // here the depth of each pixel is set (?) }  technique SpriteBatch {     pass     {         PixelShader  = compile ps_2_0 PS();     } }
Could this way of setting the depth value of each pixel do the trick? If so, how? I've tried fiddling around with DepthBufferWriteEnable settings, but i can't get it to work. I'm not entirely sure how the depth buffer works thou...
Any help will be very appreciated!
mind in a box
mind in a box
I don't know if that writes depth too, but you can try this:

void PS(in    float2 UV    : TEXCOORD0,         inout float4 Color : COLOR0,         inout   float4  Pos: POSITION) {     Color.rgb = tex2D(TextureSampler, UV);     Pos.z += SomeOffset; } 


Must not work, but it could. Just a little thinking of myself ;)
p4rse
p4rse
Quote:
Original post by mind in a box
void PS(in    float2 UV    : TEXCOORD0,         inout float4 Color : COLOR0,         inout   float4  Pos: POSITION) {     Color.rgb = tex2D(TextureSampler, UV);     Pos.z += SomeOffset; }
Thank you for your answer! I did try this, but got a compile error from the HLSL compiler. Apparently POSITION is an invalid input/output semantic for pixel shaders. I guess the POSITION semantic is used only for vertex shading or something.
Aqua Costa
Aqua Costa
Quote:
Original post by p4rse
Quote:
Original post by mind in a box
void PS(in    float2 UV    : TEXCOORD0,         inout float4 Color : COLOR0,         inout   float4  Pos: POSITION) {     Color.rgb = tex2D(TextureSampler, UV);     Pos.z += SomeOffset; }
Thank you for your answer! I did try this, but got a compile error from the HLSL compiler. Apparently POSITION is an invalid input/output semantic for pixel shaders. I guess the POSITION semantic is used only for vertex shading or something.


Try using SV_POSITION
MJP
MJP
You can't read from POSITION in a ps_2_0 pixel shader. In fact you can't do it in ps_3_0 either. In ps_2_0, your only option is to output the clip-space position to both POSITION and a TEXCOORD in your vertex shader. In ps_3_0 you can use the VPOS input semantic, which gives you the XY screen-space coordinates (which are in terms of your viewport width and height). In ps_4_0 and up you can use SV_POSITION, which is similar to VPOS except that it gives you the z value as well.
p4rse
p4rse
Ok thank you for clearing that up.

What i want is to write, not read. How would you go about writing the depth or z-value in a pixel shader?
MJP
MJP
Just use the DEPTH semantic, and give it a value between 0 and 1.
p4rse
p4rse
I'm doing that, but it doesn't seem to affect anything. Do i need to do something with depth buffers or set some other setting? I'm unsure how the depth buffer works.
unbird
unbird
The render state DepthBufferWriteEnable is not enough to achieve what you want, i.e. occlusion by depth (farther away object will be overdrawn, no matter in what order you draw).

I don't use XNA anymore so my sample code may be wrong, but it should give a direction for further insight.

1. Create a depth/stencil buffer (when you create your device or rendertarget). I suggest have a look at the presentation parameters.

2. Clear it in advance of your rendering:
graphicsDevice.Clear(ClearOptions.DepthBuffer | ClearOption.Target, Color.Black, 1f, 0);

3. Enable z-buffer write (what you have already done):
graphicsDevice.RenderState.DepthBufferWriteEnable = true;

4. Enable z-test (!):
graphicsDevice.RenderState.DepthBufferEnable = true;

5. Set your z-buffer compare function appropriately:
graphicsDevice.RenderState.DepthBufferFunction = CompareFunction.LessEqual;


This is one possible setup. Note that we cleared the depth to 1f and later use LessEqual to enable drawing pixels that are "nearer". If the pixel gets drawn, it's z-value will be written to the depth buffer, too (DepthBufferWriteEnable).

I had a look at the video, and yeah, he is probably using 2D tricks, but the scene looks rather 3D though: Later he puts solid geometry in there (spheres and the teapot). And the lighting is deferred, he gives once a glance at the g-buffer (normals).

So I think the 2D stuff there is some sort of billboarding, which has the advantage that you don't need to calculate the depth value yourself. Maybe transparency can give you trouble, though.

Topic Locked

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

Sign in to reply to this topic.