The Persistence of Vision Raytracer (POV-Ray).

This is the legacy Bug Tracking System for the POV-Ray project. Bugs listed here are being migrated to our github issue tracker. Please refer to that for new reports or updates to existing ones on this system.

Attached to Project: POV-Ray

Opened by Christoph Lipka - 2013-01-04

Last edited by William F Pokorny - 2017-04-25

Opened by Christoph Lipka - 2013-01-04

Last edited by William F Pokorny - 2017-04-25

## FS#264 - Improve precision of photon direction information

In the photons map, the direction of each photon is stored as separate latitude & longitude angles (encoded in one byte each), causing the longitudinal direction component’s precision to be unnecessarily high for directions close to the “poles” (Y axis); in addition, encoded value -128 is never used. For better overall precision as well as precision homogenity, the following scheme could be used instead:

- Encode the latitude (-pi/2 to +pi/2) into LatCount=226 distinct values (= 256*sqrt(pi)/2) rounded to the next even number) from 0 to LatCount-1 using

latCode = (int)((LatCount-1) * (lat/M_PI + 0.5) + 0.5)

- For each latitude code, define a specific number of encodable longitude values, LngCount[latCode] = approx. cos(lat)*pi*65536/(2*LatCount); this can be a pre-computed table, and may need slight tweaking for optimum use of the code space. Encode the longitude (-pi to +pi) into a value from 0 to (LngCount[lat]-1) using

LC = LngCount[latCode]; lngCode = (int)(LC * (lng/(2*M_PI) + 0.5) + 0.5) % LC;

- Besides LngCount[latCode], also store the sum of LngCount[i] with i < latCode as LatBase[latCode]; encode the direction as

dirCode = LatBase[latCode] + lngCode;

- For decoding, a simple lookup from a precomputed list of directions could be used (2^15 entries, i.e. one hemisphere, will suffice). To conserve space, direction vectors could be scaled by (2^N-1) and stored as (N+1)-bit signed integer triples rather than floating point values; due to the limited precision of the lat/long information, 8 bits per coordinate might be enough, giving a table size of 96k. A full double-precision table would require 786k instead.

A relevant paper for this task:

http://faculty.cs.tamu.edu/schaefer/research/normalCompression.pdf

Thanks for the reference, Simon. Looks like exactly the same basic idea, except that they used a more precise formula for LngCount[] (which they call N[Theta]), and add a few more ideas on top of that. Unfortunately their main focus appears to be variable-length encoding into a bit stream, while our problem is fixed-length encoding, so the actual steps of encoding latCode and lngCode into a single fixed-width value, and decoding that value into latCode and lngCode again, are not addressed by the paper.

I was thinking a bit about this, and came to the following conclusion:

If you encode the precomputed map in 8-bit precision, there is no reason to encode at all. You don't save any space with that. A look at the code shows that the photon structure is

float[3] #location (12 bytes)

char[4] #color (4 bytes)

char #info (1 byte)

char[2] #direction information (2 bytes)

On all modern architectures, the memory alignment is at least 4, if not 8 bytes, so the entire structure is packed into 20 bytes (sizeof(Photon) on gcc 4.7.2, x86_64). Having char[3] for location would have the same precision as a 8-bit precomputed list, and would take no more space in the structure. Encoding only makes sense if you save space or increase precision by using it. I think that having simply char[3]=(x,y,z) for direction is just fine if you decide for 8-bit precomputation - simplicity over obfuscation :)

For our specific case, the location data takes much more space than the direction anyway, and it cannot really be reduced, because you need sharp location for accurate caustics.

Edit: for 8-bit encoded components, you need normalization after conversion to float (so this precomputation does not help increase speed). So:

if you keep it as is, you have precomputed sin/cos values (fast)

if you make the encoding more complicated (more accuracy), you can either have built-in char[3] (simple but slow because of required renormalization) or 16-bit encoding with global float[3] lookup table (fast and more precision).

Or, of course, you can ignore that 8-bit precision can result in vector length a bit different than 1 and live with the consequences.

Now tracked on github as issue #283.