Okay, so it turns out that
1) My method is non-ideal for this specific problem, but that's what I needed to find out.
2) nufftn() can totally do a successful FFT on random points, which was the goal of my Question
3) The nufftn() documentation available at the time I posted this doesn't really tell the story, and I had to get help from @Chris Turnes at Mathworks to get this to work.
The code below displays a smooth function and my attempt to estimate it from random samples using nufftn(). The range and overall shape of the estimate comes out right on, but it's very noisy, becaue the random samples aren't uniform and therefore aren't great for estimating Fourier Transform coefficients. And it takes major oversampling to make up for the randomness. But with some serious smoothing, this estimate would be not-too-bad, and this approach might be viable-ish for certain problems.
dim1 = 21; % Dimensions of output grid. Make these odd.
dim2 = 23;
nsample = 200000; % Number of random samples
oversample = nsample / (dim1 *dim2);
xs = rand(nsample,1) - 1/(2*dim1); % Random sampling pts in 2D
ys = rand(nsample,1) - 1/(2*dim2);
v = exp(-xs.^2-ys.^2); % Values at sample points
% Wave numbers for Fourier Transform
kx = [0 [1:floor(dim1/2)] [-floor(dim1/2) : -1]];
ky = [0 [1:floor(dim2/2)] [-floor(dim2/2) : -1]]';
pfd2 = reshape(nufftn(v, [ys(:) xs(:)], { ky kx }), dim2, dim1) / oversample;
estimate = ifft2(pfd2); % Our attempt at estimating v
[Xq, Yq] = meshgrid(linspace(0,1-1/(dim1),dim1),linspace(0,1-1/(dim2),dim2));
figure(50); % Display our estimate of v
surf(Xq,Yq,estimate);
title_str = sprintf('ifft2 of nufftn()\n%d random data pts\noversampling = %.2f',nsample,oversample);
title(title_str);
figure(51);
surf(Xq,Yq,exp(-Xq.^2-Yq.^2)); % Display the actual v
title('The actual function, for comparison');