PDA

View Full Version : Geometry-based cameras cannot render interpolated GI properly



Captain Obvious
01-26-2009, 08:14 AM
The geometry-based cameras (Baking & Advanced) cannot render interpolated GI properly. I've been doing some tests recently, in 9.6 and 9.3.1, and it seems that the GI solution generated is, well, pretty much rubbish. Basically, it seems to ignore the sampling settings and always interpolate over a very big radius. In my tests, a min/max spacing of 0.1/0.1 and an angular tolerance of 1 degree, produced the same results as a min/max of 100/1000 and a tolerance of 45 degrees. Same render time, and the results were the same aside from the fact that all the splotches moved around (simply because the random sampling was different). The problem occurs with all GI modes, as long as interpolation is turned on.

On my test scene, the perspective camera did the GI prepass in about 40 seconds, followed by about 10 seconds of normal rendering. When rendering roughly the same view using the surface baking camera, the prepass took less than ten seconds, and seemed to interpolate each sample over a radius of about 100 pixels. The only thing that seemed to stop the interpolation was the UV map borders.

Additionally, the baking geometry-based cameras still use the actual position of the camera for generating samples -- when the direction reference was set to the camera instead of smooth normal, the results were completely different. Still crap, but different crap.

The only workarounds I've been able to find is rendering with a really heavy bump map and "Use Bumps" turned on, which seems to force it to generate additional samples, and using brute force. Neither of which is a particularly elegant solution.

Could someone perhaps try using the surface baking camera with a low-poly mesh to bake a high-poly, high-detail mesh with GI, and share the results? I haven't been able to get it working at all, and it would be useful to see if it's just PEBKAC before I start filing bug reports and what have you...

Captain Obvious
01-27-2009, 08:36 AM
Oh, here's a suggestion to... whoever, for a fix:

Have an option to have world space-based placement of samples. I'm guessing the reason it breaks with the surface baking camera is that it no longer understands the concept of a pixel. If you could then use world space-based placement as an override, it should work fine again.

Sensei
01-27-2009, 11:47 PM
Have an option to have world space-based placement of samples.

They just removed it, and you want it back.. ;)
In LW v9.0 you didn't have spacing in pixels, but spacing in millimeters..
I guess so it required a lot of sqrt() calculations for each sample, that's why it has been changed..
With Angular Angle FPU has to to dot product (3 multiplications and 2 adds)..
Much faster than sqrt(dotproduct())..

Sensei
01-27-2009, 11:57 PM
In my tests, a min/max spacing of 0.1/0.1 and an angular tolerance of 1 degree, produced the same results as a min/max of 100/1000 and a tolerance of 45 degrees. Same render time, and the results were the same aside from the fact that all the splotches moved around (simply because the random sampling was different). The problem occurs with all GI modes, as long as interpolation is turned on.

I have no idea how can you have exactly the same results from 0.1 and 100...

On mine simple test they were completely different (I have used 1.0 as min/max because 0.1 has simply no sense).. and rendered 600% faster..

Captain Obvious
01-28-2009, 04:00 AM
I have no idea how can you have exactly the same results from 0.1 and 100...
You and me both. I'll do some more tests on stuff that's not under NDA and upload it, if I can replicate my problems.



I guess so it required a lot of sqrt() calculations for each sample, that's why it has been changed..
With Angular Angle FPU has to to dot product (3 multiplications and 2 adds)..
Much faster than sqrt(dotproduct())..
Provided that you've put the samples in a kd-tree or something, surely the time spent checking for existing samples must be smaller than the time spent taking new samples? So even though two dot products are much faster than two square roots, most of the time would be spent ray tracing anyway.

Besides, I don't think you get away from the sqrts anyway. When checking to see whether or not a "pixel-space" sample is within range, you still need to actually look at the world coordinates as well, because samples that are close by in pixels can be far away in world space (ie, samples seen through transparency/reflections, or with a different Z, etc). I suspect what's happening is that the renderer internally generates a world-space sample placement rate based on the distance to the camera, resolution, field of view, etc. That would certainly explain why the placement of the actual camera item when using geometry-based cameras changes the sample placement.

And even if you ONLY look at the pixel location, you still need to do one sqrt per sample, instead of the two required for checking world space. Two dot products and one sqrt instead of two dot products and two sqrts. I don't think it would make a huge difference.

Sensei
01-28-2009, 05:10 AM
Provided that you've put the samples in a kd-tree or something, surely the time spent checking for existing samples must be smaller than the time spent taking new samples? So even though two dot products are much faster than two square roots, most of the time would be spent ray tracing anyway.

In LW in interpolated GI mode ray-tracing is probably done only at GI pre-processing stage, and not done in regular rendering (GI samples ray-tracing - don't confuse with regular ray-tracing for reflections/refractions and other stuff). This would be saving on multi-threading synchronization, if GI interpolated cache is just read-only at full rendering stage.

It's not "two square roots".. but square root of dot product, compared to just dot product. Something like:

for( i = 0; i < sample_count; i++ )
{
if( DotProduct( samples[ i ].direction, direction ) < tolerance_angle )
{
// from f.e. 100 samples, there is just 5-10 with matching angle..
}
}

where DotProduct() is:

double DotProduct( vector a, vector b )
{
return( a[ 0 ] * b[ 0 ] + a[ 1 ] * b[ 1 ] + a[ 2 ] + b[ 2 ] );
}

and

for( i = 0; i < sample_count; i++ )
{
if( Distance( samples[ i ].position, position ) < tolerance_distance )
{
}
}

where Distance() is

double Distance( vector a, vector b )
{
return( sqrt(
( a[ 0 ] - b[ 0 ] ) * ( a[ 0 ] - b[ 0 ] ) +
( a[ 1 ] - b[ 1 ] ) * ( a[ 1 ] - b[ 1 ] ) +
( a[ 2 ] - b[ 2 ] ) * ( a[ 2 ] - b[ 2 ] ) ) );
}

If we will assume that sample_count is 100, and matching samples is 10%. It will be:
- 300 multiply, 200 adds in angle tolerance algorithm.
- 300 multiply, 200 adds, 600 subtracts, 100 sqrt in second algorithm.



Besides, I don't think you get away from the sqrts anyway. When checking to see whether or not a "pixel-space" sample is within range, you still need to actually look at the world coordinates as well, because samples that are close by in pixels can be far away in world space (ie, samples seen through transparency/reflections, or with a different Z, etc).

I don't think so there are samples seen through transparency/reflections.. That's handled by GI bounces..

Even if there is sqrt() done, it's much less than with, sqrt() based searching samples. Because first angle checking if() reduced number of processed samples to f.e. 5% of initial state.

dual-core 2.0 GHz computer can make 64 mln sqrt operations per second.
So quad-core 3.0 Ghz should make around 200 mln sqrt.
If it's not SSE2 accelerated routine (which requires hand made SSE2 programming, C/C++ compiler won't make it good).



I suspect what's happening is that the renderer internally generates a world-space sample placement rate based on the distance to the camera, resolution, field of view, etc. That would certainly explain why the placement of the actual camera item when using geometry-based cameras changes the sample placement.

I guess so placing or not placing sample is determined by there is some other sample made in that area matching tolerance.



And even if you ONLY look at the pixel location, you still need to do one sqrt per sample, instead of the two required for checking world space. Two dot products and one sqrt instead of two dot products and two sqrts. I don't think it would make a huge difference.

I am not quite getting your math here, but anyway.. ;)

GI is distance independent - see f.e. sunsky, it has sun 1000 km or more away, but still lightening up scene.. ;)

Lightwolf
01-28-2009, 05:27 AM
If we will assume that sample_count is 100, and matching samples is 10%. It will be:
- 300 multiply, 200 adds in angle tolerance algorithm.
- 300 multiply, 200 adds, 600 subtracts, 100 sqrt in second algorithm.

No need for the sqrt() if you just compare. You might as well just square the tolerance distance.

Cheers,
Mike

Captain Obvious
01-28-2009, 08:18 AM
The "screen-space" sample placement still requires actually checking the distance between samples. It doesn't just do a single dot product, as you need to check the distance, in pixels, between two samples. Ie, the square root of the squares of the X and Y pixel delta. Oh, I was a bit tired and distracted when I wrote the previous post, btw: I wrote "two dot products," when I really meant was the dot product of two vectors. D'oh!

Now, anyway, in order to check for samples within the tolerance DISTANCE, you need to somehow translate the pixel spacing information into world-space distance. This will obviously vary depending on how far away from the camera you are, what the resolution is, what the field of view is, etc, which I guess it does anyway for the spot size. I don't think Lightwave stores the pixel coordinates of IC samples. That wouldn't work with the "walkthrough" caching anyway -- you can reuse the same sample multiple times, even though the pixel coordinates change. This means Lightwave probably translates the pixel spacing information into world space. That means that you're doing the same exact operations when you're working in world space as you are when you're working in pixel space.



I don't think so there are samples seen through transparency/reflections.. That's handled by GI bounces.
Samples added to the IC as seen through reflection go into the same database as samples added by primary rays, and I would assume that they're handled the same way. The only thing I have no idea about here is how Lightwave determines the distance tolerance when samples are seen through reflections.

Sensei
01-28-2009, 08:36 AM
GI samples don't have to have screen-space coords as you suggest. New LightSDK v9.6 have samples without X and Y anywhere. Screen position in rendered image is used only as initial parameter to quad-tree/kd-tree, later when list of samples is found, they can be ignored.

I am guessing that there is similar operation made as particle blending in HyperVoxels - sample has position in world coord space, tolerance (size of virtual sphere) in meters also in world coord space, and color. If sample sphere is intersecting with ray line, the sample is used, otherwise ignored. How much it affects depend on distance between 3d line (ray) and sample position. The closer, the more influence of that sample. No need to have any screen-space variables in this routine..

Captain Obvious
01-28-2009, 02:44 PM
That seems like a fundamentally flawed method for finding samples in the IC. Surely it is the world space distance between the current spot and the sample in the IC that matters NOT whether or not the ray that hit the current spot ever came close enough to the sample. Otherwise you'll end up re-using IC samples that you really shouldn't be.