Inverse-CDF sample: map (u, v) in [0,1]² to a pixel plus the per-pixel selection probability. The caller converts pixel ↔ direction and applies the solid-angle jacobian.
(&self, u1: f32, u2: f32)
| 1439 | /// per-pixel selection probability. The caller converts pixel ↔ |
| 1440 | /// direction and applies the solid-angle jacobian. |
| 1441 | fn sample_pixel(&self, u1: f32, u2: f32) -> (u32, u32, f32) { |
| 1442 | // Marginal → row. |
| 1443 | let y = upper_bound_index(&self.marginal, u1); |
| 1444 | let y = y.min(self.height as usize - 1); |
| 1445 | let row_base = y * (self.width as usize + 1); |
| 1446 | let row = &self.conditional[row_base..row_base + self.width as usize + 1]; |
| 1447 | // Conditional → column. |
| 1448 | let x = upper_bound_index(row, u2).min(self.width as usize - 1); |
| 1449 | |
| 1450 | // p_pixel = (row weight / total) × (pixel weight / row weight) |
| 1451 | // = pixel weight / total |
| 1452 | // But we only have CDFs, so reconstruct the pixel weight from |
| 1453 | // consecutive CDF deltas. |
| 1454 | let row_total = self.marginal[y + 1] - self.marginal[y]; |
| 1455 | let px_p_given_row = row[x + 1] - row[x]; |
| 1456 | let p_pixel = row_total * px_p_given_row; |
| 1457 | (x as u32, y as u32, p_pixel) |
| 1458 | } |
| 1459 | |
| 1460 | /// Probability (per pixel, NOT per solid angle) that this pixel |
| 1461 | /// would be chosen by `sample_pixel`. For MIS we need this in a |
no test coverage detected