I am learning ray tracing and the mathematics behind it. I have a working monte-carlo raytracer I am experimenting on. I have gotten past pure diffuse BRDFS, area lights, acceleration structures, etc, and now I'm working on properly sampling the next ray direction from an anisotropic distribution. I believe I have interpreted the D,G,F factors correctly, and have working tests that verify those function's outputs.
I am having trouble with drawing a "wi" sample from the half vector distribution function. The purpose of the function is to give you a randomized half vector in shading space based on the "incoming" wo ray, which is the eye ray, and a roughness parameter. As I graph out the function outputs, it seems like the half-vector sampling function begins to rotate the spherical coordinates about the wrong axis (I know this makes no sense, but I'm just observing the graphed results).
Knowing that situation, I was hoping some people could post some pointers to good academic articles, open source code examples, or other educational material that could help me investigate and educate myself on the behavior of functions that generate half-vectors from distributions. I have found plenty of the original source papers from Cook-Torrence, etc that explain their algorithms, but I cannot find any that explain in plain language HOW to generate the half vector for the eye ray to reflect about.
Note: I have also extensively explored PBRT and its source code, all of which has been incredibly enlightening, and I have seen their sample_wi function, i even went so far as to directly copy and translate it to webgl for troubleshooting my functions. I know i must be doing or interpreting something wrong - I just can't find enough material out there to help me figure out what.
Here is a visualization of only the half vector normals. They have been put into a range of [0,1] for viewing in the RGB spectrum. I have also boosted the contrast of the image to make the error more easily visible. You can clearly see that instead of randomly orienting themselves about the surface normal, they are instead correlating themselves radially about the camera eye-vector.
UPDATE:
here is a webgl "proof" i put together to isolate and illustrate my problem. What should happen is the color should be fairly blended together, interpolated rather nicely. Instead I get this obvious hard shift in the distribution throughout the 4 quadrants: http://rdtests.ml3ds-test.com/microfacettesting.html
The functions referenced by main function here can all be viewed directly in the source code of the page I linked to:
vec3 finalColor = vec3(0.);
// create a changing "wo" vector across screen space (simulates perspective ray change)
vec2 screenUv = gl_FragCoord.xy / u_resolution;
// fire rays into positive z (forward) space from "camera"s
float z = 1.;
vec3 rd = normalize(vec3(screenUv, z));
// remap 0,1 to -1,1
vec3 wo = (rd * 2.) - 1.;
// wo is outward facing
wo *= -wo;
// convert wo to spherical coordinates
vec3 Nt, Nb;
// simulate hitting an infinite plane, facing us like a wall
vec3 normal = vec3(0., 0.,-1.);
CoordinateSystem(normal, Nt, Nb);
// put wo into the shading space coordinate system of the "wall" normal
vec3 shadingWo = WorldToShading(wo, Nt, Nb, normal);
// sample half vector distribution from trowbridge-reitz
// make random input a constant to allow error to be more clearly seen
vec3 wh = Dist_TR_Sample_wh(shadingWo, vec2(.2,.1), .5, .5);
// Reflect wo about the half vector normal
vec3 wi = Reflect(shadingWo, wh);
// put wi back into cartesian coordinate system
vec3 wiWorld = ShadingToWorld(wi, Nt, Nb, normal);
// now remap wi to a viewable color: 0,1
finalColor = normalize((wiWorld + 1.) / 2.);
gl_FragColor = vec4(finalColor, 1.);