Jump to content

  • Log In with Google      Sign In   
  • Create Account


Member Since 17 Dec 2009
Offline Last Active Today, 01:07 PM

Posts I've Made

In Topic: How can I implement light beams with DirectX 9 or 11?

08 December 2014 - 05:42 AM

The simplest approach IMO would be to use a cone mesh for your flashlight, and use an inscattering pixel shader on it with additive blending - no culling or depth testing.


To get a correct result for your beam though, you only want the light accumulated from the front of the mesh to the back, not from the camera to the back (which is what you'll get if you use the inscatter shader on it's own). To fix this you'll need to subtract the front face results from the back face (you can use SV_IsFrontFace or VFACE to determine front faces and then multiply the output by -1 if it's a front face). This will remove the contribution from the front faces, giving you only the inscattering through the beam from the front to the back. You'll also need to use the depth buffer to avoid your beams going through surfaces (volumeDepth = min( sceneDepth, meshDepth )). smile.png


Essentially what I'm describing is this.


If you need something with a little more flexibility, you can ray march your light volume or voxelize it (in light space, view space or world space). All of the approaches come with their own benefits and tradeoffs, so it's really up to you to decide which will suit your needs. For a simple flashlight I'd go with the beam approach because it can be done at full resolution, is very fast, doesn't suffer from limited resolution or limited sampling and has perfect temporal stability since it's essentially just a cone mesh with a fancy shader on it.



Edit: Here's some pseudo-code. Make sure your winding order is correct when picking the front faces or this won't work properly!

float sceneDepth = tex2D( depthMap, IN.texCoord.xy ); // Linear depth, make sure it's 0-Far Plane and not 0-1 for this shader.
float meshDepth = IN.meshDepth; // Same as above, but from the vertex shader of this mesh.

float volumeDepth = min(meshDepth, sceneDepth); // Minimum of scene depth and mesh depth for the inscattering integral.

float3 viewDir = normalize( IN.viewDir.xyz ); // world position - camera position

float inscattering = InScatter(cameraPos, viewDir, lightPos, volumeDepth); // Function from Macklin's blog.
inscattering *= isFrontFace ? -1.0f : 1.0f; // isFrontFace = SV_IsFrontFace

return inscattering; // Output

In Topic: Voxel Cone Tracing Problem

01 December 2014 - 08:54 AM

Are you using point filtering? You should be using trilinear filtering (GL_LINEAR_MIPMAP_LINEAR).


Otherwise, are you rounding your coordinates to voxel? (floor(pos), etc.) - If so, you shouldn't be. :)

In Topic: Reconstructing Position From Depth Buffer

29 July 2014 - 04:32 AM

To go with the explanation above, here's some HLSL example code on how to construct the frustum corners in the vertex-shader. This is just quick pseudo-code, so it may have an issue or two. It's also better to compute this on CPU and pass it in as a constant to the shader instead of computing it per vertex (you can also reuse it for all quads in a frame).

float3 vFrustumCornersWS[8] =
	float3(-1.0,  1.0, 0.0),	// near top left
	float3( 1.0,  1.0, 0.0),	// near top right
	float3(-1.0, -1.0, 0.0),	// near bottom left
	float3( 1.0, -1.0, 0.0),	// near bottom right
	float3(-1.0,  1.0, 1.0),	// far top left
	float3( 1.0,  1.0, 1.0),	// far top right
	float3(-1.0, -1.0, 1.0),	// far bottom left
	float3( 1.0, -1.0, 1.0)		// far bottom right

for(int i = 0; i < 8; ++i)
	float4 vCornerWS = mul(mViewProjInv, float4(vFrustumCornersWS[i].xyz, 1.0));
	vFrustumCornersWS[i].xyz = vCornerWS.xyz / vCornerWS.w;

for(int i = 0; i < 4; ++i)
	vFrustumCornersWS[i + 4].xyz -= vFrustumCornersWS[i].xyz;

// Passes to the pixel shader - there are two ways to do this:
// 1. Pass the corner with the vertex of your quad as part of the input stage.
// 2. If you're quad is created dynamically with SV_VertexID, as in this example, just pick one from a constant array based on the position.
float3 vCamVecLerpT = (OUT.vPosition.x>0) ? vFrustumCornersWS[5].xyz : vFrustumCornersWS[4].xyz;
float3 vCamVecLerpB = (OUT.vPosition.x>0) ? vFrustumCornersWS[7].xyz : vFrustumCornersWS[6].xyz;	
OUT.vCamVec.xyz = (OUT.vPosition.y<0) ? vCamVecLerpB.xyz : vCamVecLerpT.xyz;

To get position in the pixel shader:

float3 vWorldPos = fLinearDepth * IN.vCamVec.xyz + vCameraPos;

In Topic: Parallax corrected cube maps

23 July 2014 - 12:52 PM

Your min and max need to be in world space. So add the cube position to the min and max to ensure it works when you move the object.

In Topic: Screen Space Reflection Optimization

15 May 2014 - 11:42 AM

A possible improvement is to swap from a fixed step march and instead use a depth hierarchy that you can traverse as you get further along your ray. You can use lower resolution depths for longer rays/distant steps and get away with some pretty good speed increases. You can also use the hierarchy for detecting invalid tiles on the screen that clearly wouldn't have an intersection (quad-tree style), allowing you to skip portions of the screen that a pixel will never hit.