We decided that it would be fun to attempt to use the gather() function to detect objects above a surface and displace that object based on the shape of the above surface. We began our experimentations with a surface shader to get the hang of the gather() function.

gather_Cs(float samples = 64,
                tint = 0.15,
                blur = 15,
                falloff = 5,
                Kd = 0.8)
normal n = normalize(N);
// Simple use of the gather function
float spread = radians(blur);
color hitC = 0;
color totalC = 0;
float hits = 0;
float len = 0;
float totalLen = 0;
gather("illuminance", P, n, spread, samples, 
            "surface:Cs", hitC,
            "ray:length", len)
    hits = hits + 1;
    totalC = totalC + hitC;
    totalLen = totalLen + len;
// Average the colors we have gathered
color gColor = (totalC/hits) * tint;
float gLen = totalLen/hits;
gColor = gColor * (1 - smoothstep(0,falloff,gLen));
// Real simple lighting ??    
color diffusecolor = diffuse(n) * Kd;
Oi = Os;
Ci = Oi * Cs * (diffusecolor + gColor);

We then approached the problem of using the same technique on a displacement shader. It was decided to use a point cloud to store the information about the accumulated displacements. However, some difficulties arose when trying to ascertain the distance from the displacing object to the displaced surface. Originally I was arbitrarily inputing the distance between these two objects because it seemed the only solution at the time, however many artifacts appear around the edges of the displacement:

This method proved unsatisfactory because the object was unable to move without animating that attribute on the shader, which would be extremely cumbersome. So instead, I found that by using the max() function I was able to get the correct distance between the objects and displace them properly without animating any variables:
This method also produced cleaner edges around the displacement. We also wanted to add the functionality of being able to calculate the updated positions of the surface if the displacing surface was displaced (haha, a little confusing). Here is my solution using the max() function inside the gather() function as well as the displacement update:
accumDisplace(float Km = -0.1, /* [-1 1] */
                maxHump = 1, /* [0 5] */
                spread = 0,
                samples = 1;
         string traceset = "";
         string    bakename = "")
normal n = normalize(N);
vector     diff = n - normalize(Ng) ;
float hump = 0;
float blur = radians(spread);
float len = 0;
float totalLen = 0;
float hits = 0;
float gLen = 0;
float currDisp = 0;
point displaceP = 0;
float prevDisp = 0;
if(bakename != "")
    if(texture3d(bakename, P, N, "_prevDisp", prevDisp) == 0) {
        prevDisp = 0;
gather("illuminance", P, n, blur, samples,
         "subset", traceset, "displacement:P", displaceP,
         "ray:length", len)
    float trueLen = distance(displaceP, P);
    hits = hits + 1;
    totalLen = totalLen + trueLen;    
    gLen = totalLen/hits;
    gLen = gLen - max(gLen,maxHump);    
    gLen = 0;
currDisp = gLen;
if(abs(currDisp) < abs(prevDisp))
    currDisp = prevDisp;
if(bakename != "")
    bake3d(bakename, "_prevDisp", P, N, "interpolate", 0,
        "_prevDisp", currDisp);
P = P - currDisp * n * Km;
N = normalize(calculatenormal(P)) + diff;
It was then time to render out some cool stuff! Because the point cloud that is being generated that stores the displacement data is fixed in space, moving the displaced object produces some interesting effects:


1) If the objects get too close to the displaced surface, the distance between the surface and the object is considered much higher than expected due to the gather ray firing in front of the object (say, inside the sphere for example).

2) Increased control would need to be given to the user within Maya to constrain the point cloud position to the movements of the displaced object.

3) Right now, the shader requires the objects to have a displacement attached. A modified version of the shader should include both options.


These caveats among others may be worth fixing if the time presents itself later in the quarter.