#1 Members - Reputation: 676
Posted 21 September 2012 - 10:43 AM
I want to make lens flare which soothly fades on the edges of 3d objects. Right now I am using OcclusionQuery, which works but not as I want. OcclusionQuery got a field PixelCount which tells me how many pixels are visible. I use a sphere for the test. But that makes a problem, because it's hard to say if sphere is fully visible that way.
The one solution I can think of is to find out how many pixels the whole sphere takes, then divide PixelCount by that number to get %.
Is there another easier or better way to check how much object is visible?
#2 Moderators - Reputation: 14313
Posted 21 September 2012 - 10:43 PM
First we calculate on the CPU the expected depth value of the light source, and it's screen space position:
N.B. all untested psuedo-code as example
Vector4 lightData = Vector4( light_position, 1 );//get the light's world position, make sure that 'w' is 1.0 lightData = ViewProjectionMatrix * lightData;//multiply with the view-projection matrix lightData = lightData / lightData.w;//perform perspective division lightData.x = lightData.x*0.5+0.5;//the x/y screen coordinates come out between -1 and 1, so lightData.y = lightData.y*0.5+0.5;//we need to rescale them to be 0 to 1 tex-coordsNext we render a quad that completely covers a small 16x16 pixel render-target. The quad should have UV's from [0,0] to [1,1] like a regular full-screen quad would. We also bind the depth-buffer as a texture, and put the above lightData in a shader constant.
In the vertex shader, assuming the input UV's are from [0,0] to [1,1], we can calculate the output UVs like:
float2 pixel = float2( 1/1280.0, 1/720.0 );//adjust depending on the resolution of your depth buffer! Out.UV = lightData.xy + (In.UV - 0.5) * pixel*16;//the quad will take depth samples in a 16x16px region of the depth buffer, centred around the light positionIn the pixel shader, we can then test each depth-buffer value against our predicted light depth, and output the result of the depth test as white or black.
float depth = tex2D( depthBuffer, In.UV ).r; float test = step( lightData.z, depth ); // test = lightData.z < depth ? 1.0 : 0.0 return test.xxxx;Now the 16x16 render-target contains 256 boolean values, indicating whether the light is in front or behind that pixel nearby it.
If we now generate mip-maps for this render-target, then mip-level #4 will be a 1x1 texture, containing the percentage of visible pixels.
In your actual lens flare shader, you can sample this texture to find out how much to scale/fade the flare effect, e.g.
float visibility = tex2Dlod( occlusionBuffer, float4(0.5,0.5,4,0) ).r;
Edited by Hodgman, 21 September 2012 - 10:45 PM.
#3 Moderators - Reputation: 5656
Posted 21 September 2012 - 11:22 PM
In my last game, we used an alternative to occlusion queries for this problem, but it requires that you're able to bind your depth-buffer as a readable texture -- I don't know if XNA allows that, but it's possible in D3D9, so maybe.
It doesn't. You'd have to manually render depth to a render target.
#4 Members - Reputation: 676
Posted 22 September 2012 - 01:07 PM
In my last game, we used an alternative to occlusion queries for this problem, but it requires that you're able to bind your depth-buffer as a readable texture -- I don't know if XNA allows that, but it's possible in D3D9, so maybe.
It doesn't. You'd have to manually render depth to a render target.
I have deferred shading so i got depth buffer ;)
First we calculate on the CPU the expected depth value of the light source, and it's screen space position:
I done that part already to show flare w/o occlusion test:)
Now the 16x16 render-target contains 256 boolean values, indicating whether the light is in front or behind that pixel nearby it.
If we now generate mip-maps for this render-target, then mip-level #4 will be a 1x1 texture, containing the percentage of visible pixels.
: O That's a very clever approach. I am going to work with this tomorrow.
EDIT:
It's kinda working. Just needs some tweaks. Thank You for help
Edited by Tasaq, 23 September 2012 - 12:36 PM.






