Thursday, September 27, 2018

Unity: cg fragment shader processing array of points


I need to write a fragment shader which would somehow be aware of N points that are in the scene and darken pixels based on their world coord distance to the points. I'm looking for a method that would be still suitable for mobile devices. I image I could pass the points as a texture but i'm stuck in figuring out how to effectively evaluate if a pixel is close enough to any of the N points (I know how to do this for 1 point, but for N without a loop?). Any ideas if this is doable in a performance efficient manner? All ideas are welcome. Thanks!


enter image description here



Answer



As discussed in the comments above, it may be easier to get this effect (and scale better to large values of N) by flipping the request around.


Rather than the shader for the scene geometry checking - in every rendered fragment - its distance to each of the N points, we can instead draw the scene geometry normally, then "stamp" the effects onto it by rendering some triangles for each of the N points.



This is effectively the same flip in thinking we do when moving from forward lighting to deferred. If each light/point's effect area is small (ie. less than the full screen) and there are many of them, we can reduce redundant work this way.


So, that leaves a few choices for how to render your points' effects:


1. Shadow quads


The images you've shown look a lot like blob shadows in older 3D games. If this is representative, that the blobs will always fall on some plane in a defined direction ("down"), we can do this very cheaply with no depth tricks:


In a CPU-side (C#/UnityScript) script, raycast down from each of your N points to find the nearest surface in that direction. Then position a quad at that position, scaled appropriately for how wide your effect is meant to be at that distance. Use a shader on the quad that will decal your desired effect onto the surface.


2. Deferred decals/ screen-space decals


This is the way to go if you want either an omni-directional effect, or one that shines "though" the first surface it encounters so it can affect multiple at once, or if the surfaces it's affecting are bumpy & irregular, hard to cover with a single quad. But it's much more complicated, so if you're not in one of these situations, you're probably better off using a quad.


The idea is to position a mesh representing the bounding volume of the point's effect. When your fragment shader goes to render the surface of the volume, it looks up into the depth buffer for the scene already rendered, to figure out what point in the scene has already been rendered to that pixel of the render target. It then shades the fragment as though it was located at that position. In your case, that means calculating the distance from this projected scene point to the source point for the volume.


schematic diagram of deferred decal technique


The particulars will depend on the details of your use case (are your bounds cubes, spheres, cylinders? Can the camera get inside them? What type of shading effect needs to be applied within the bounds? Etc), but this type of technique is now pretty standard, so you should be able to find lots of references to get you started. Here's a sampling:




No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...