How to count the photons when Photon Mapping I wrote a rather elegant and compact Photon Mapper in CUDA. But I treat all my photons they same, and ignore their colour.
This simplicity has some nice properties: e.g. I can just count them with one integer value for each little subdivision patch on the surface.
However, to properly model the global illumination, I should take into account the colour, after a photon bounces from a surface. (A red carpet, reflects red light onto a nearby wall, not white light.)
An obvious approach would be to replace the single integer count with three floating point counters, for R, G and B.
But I feel there must be a more elegant solution to this? Russian roulette on the R/G/B channels perhaps? Although this would create more noise? But it would mean fewer data per photon, and thus better use of the cache?
I'm not sure if I understand your question correctly and don't know what you mean by &quot;counting&quot; and how you want to replace this by &quot;color&quot;. A simple photon mapper looks like this: 1) photon tracing: emit, scatter, store photons 2) path tracing: gather photons in a given radius and approximate radiance using this density.
To be more precise, in pseudocode (with russian roulette) this would look like:
xi is the position, wo the outgoing direction, W the photon power. All three are vectors of length 3. p is the probability of the Russian roulette. A photon is a struct that stores the power, direction, and position.
xi, wo, W = emitter.sample()
while(true)
   xi = traceRay(xi, wo)
   if(isDiffuse(xi))
      storePhoton(xi, wo, W)

   if(rand &lt; p)
      break
    W /= p;
    
    wo = bsdf.sample(xi)
    W *= bsdf(wo)/pdf(wo)*cos

You repeatedly call this function for a random emitter until you stored a predefined amount of photons (e.g. 500'000). After this, you build the photonmap, such as a k-d tree to make querying easy. As you can see, the &quot;color&quot; is stored in the power of the photon.
The next step is the gathering the photons, and it's normal path tracing but when you hit a diffuse surface, you gather all the photons in a fixed radius (other kernels can also be used). Here, t is the throughput, wi the incoming direction, the photon_map is the datastructure that we build before and populated with photons, and total_photons is the total amount of photons that we emitted.
...

if(isDiffuse(xi))
   for photon: photon_map.get(xi, radius)
      radiance *= t*bsdf(xi, wi, photon.wo) * photon.power / (pi*radius^2 * total_photons)
   break
...