/// <summary> /// Performs a VPT in a sphere medium with specific settings starting at center and returns the summary of the path traced. /// </summary> public static PathSummary GetVPTSampleInSphereOffcenter(MediumSettings settings, GRandom rnd) { float3 x = float3(0, 0, 0); float3 w = float3(0, 0, 1); float3 X = x; float3 W = w; int N = 0; float accum = 0; float importance = 1; // First flight from center float t = settings.Sigma < 0.00001 ? 10000000 : -log(max(0.000000001f, 1 - rnd.random())) / settings.Sigma; if (t >= 1.0f) // leaves the sphere before scattering { return(new PathSummary { N = N, x = w, w = w, X = x, // can not used but in any case... W = W }); } x += w * t; // move to first scatter offcenter while (true) { importance *= settings.Phi; accum += importance; if (rnd.random() < importance / accum) // replace the representative by this one { X = x; W = w; } w = SamplePhase(w, settings.G, rnd); N++; float d = DistanceToBoundary(x, w); t = settings.Sigma < 0.00001 ? 10000000 : -log(max(0.000000001f, 1 - rnd.random())) / settings.Sigma; if (t >= d || float.IsNaN(t) || float.IsInfinity(t)) { x += w * d; return(new PathSummary { N = N, x = x, w = w, X = X, W = W }); } x += w * t; } }
/// <summary> /// Performs a VPT in a sphere medium with specific settings starting at center and returns the summary of the path traced. /// </summary> static PathSummary GetVPTSampleInSphere(MediumSettings settings) { float3 x = float3(0, 0, 0); float3 w = float3(0, 0, 1); float3 X = x; float3 W = w; int N = 0; float accum = 0; float importance = 1; while (true) { importance *= settings.Phi; accum += importance; if (random() < importance / accum) // replace the representative by this one { X = x; W = w; } w = SamplePhase(w, settings.G); N++; float d = DistanceToBoundary(x, w); float t = settings.Sigma < 0.00001 ? 10000000 : -log(max(0.000000001f, 1 - random())) / settings.Sigma; if (t >= d || float.IsNaN(t) || float.IsInfinity(t)) { x += w * d; return(new PathSummary { N = N, x = x, w = w, X = X, W = W }); } x += w * t; } }
static void GenerateDatasetForTabulationMethod() { /* * This method generates data samples and builds a table using * the idea in Mueller et al 2016. */ float[] table = new float[BINS_G * BINS_SA * BINS_R * BINS_THETA]; float[,,] oneTimeScatteringAlbedo = new float[BINS_G, BINS_SA, BINS_R]; float[,,] multiTimeScatteringAlbedo = new float[BINS_G, BINS_SA, BINS_R]; int MAX_N = 200; int P = 1 << 18; // one quarter million photons per setting. Console.WriteLine("Process started."); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); int TOTAL_NUMBER_OF_SETTINGS = BINS_G * BINS_R; int solvedSettings = 0; Parallel.For(0, BINS_G, binG => { GRandom rnd = new GRandom(binG); float g = (binG + rnd.random()) * 2.0f * 0.99f / BINS_G - 0.99f; for (int binR = 0; binR < BINS_R; binR++) { float r = pow(2.0f, binR); Console.WriteLine("Solved {0}%.", solvedSettings * 100.0f / TOTAL_NUMBER_OF_SETTINGS); if (solvedSettings >= 1) { Console.WriteLine("ETA {0} ", stopwatch.Elapsed * (TOTAL_NUMBER_OF_SETTINGS / (float)solvedSettings - 1)); } MediumSettings settings = new MediumSettings(); settings.Sigma = r; settings.Phi = 1; settings.G = g; long[,] Hl = new long[BINS_THETA, MAX_N + 1]; for (int sample = 0; sample < P; sample++) { var summary = Scattering.GetVPTSampleInSphereOffcenter(settings, rnd); int thetaBin = (int)min(BINS_THETA - 1, BINS_THETA * (summary.x.z * 0.5f + 0.5f)); int nBin = (int)min(MAX_N, summary.N); Hl[thetaBin, nBin]++; } for (int binSA = 0; binSA < BINS_SA; binSA++) { float phi = binSA == BINS_SA - 1 ? 1.0f : 1 - exp(binSA * log(0.001f) / (BINS_SA - 1)); for (int binTheta = 0; binTheta < BINS_THETA; binTheta++) { int pos = STRIDE_G * binG + STRIDE_SA * binSA + STRIDE_R * binR + binTheta; for (int n = 2; n <= MAX_N; n++) { table[pos] += pow(phi, n) * Hl[binTheta, n]; multiTimeScatteringAlbedo[binG, binSA, binR] += pow(phi, n) * Hl[binTheta, n]; } oneTimeScatteringAlbedo[binG, binSA, binR] += phi * Hl[binTheta, 1]; } // Sum and normalize table slice to create an empirical cdf for (int binTheta = 0; binTheta < BINS_THETA; binTheta++) { int pos = STRIDE_G * binG + STRIDE_SA * binSA + STRIDE_R * binR + binTheta; if (binTheta > 0) { table[pos] += table[pos - 1]; } } } solvedSettings++; } }); Console.WriteLine("Finished generation in {0}", stopwatch.Elapsed); Console.WriteLine("Saving table"); BinaryWriter bw = new BinaryWriter(new FileStream("stf.bin", FileMode.Create)); for (int binG = 0; binG < BINS_G; binG++) { for (int binSA = 0; binSA < BINS_SA; binSA++) { for (int binR = 0; binR < BINS_R; binR++) { bw.Write(oneTimeScatteringAlbedo[binG, binSA, binR] / P); } } } for (int binG = 0; binG < BINS_G; binG++) { for (int binSA = 0; binSA < BINS_SA; binSA++) { for (int binR = 0; binR < BINS_R; binR++) { bw.Write(multiTimeScatteringAlbedo[binG, binSA, binR] / P); } } } int index = 0; for (int binG = 0; binG < BINS_G; binG++) { for (int binSA = 0; binSA < BINS_SA; binSA++) { for (int binR = 0; binR < BINS_R; binR++) { for (int binTheta = 0; binTheta < BINS_THETA; binTheta++) { bw.Write(table[index++] / P); } } } } bw.Close(); Console.WriteLine("Done."); }