/* An advanced perspective camera, implementing several examples * of things you can do with custom cameras. */ float invertDistortionModel(float x, float y, float k1, float k2, float k3) { // Solves u = d*(1 + k1*d^2 + k2*d^4 + k3*d^6) for d. // Returns stretch factor. float u = sqrt(x * x + y * y); float d = u; for (int i = 0; i < 50; i++) { float d2 = d * d; float f = u - d * (1 + d2 * (k1 + d2 * (k2 + d2 * k3))); float fp = -(1 + d2 * (3 * k1 + d2 * (5 * k2 + d2 * 7 * k3))); float diff = f / fp; d -= diff; if (fabs(diff) < 1e-7) { // Iteration is converging, return result. return d / u; } if (d > 100.0) { // Iteration is diverging, give up. return -1.0; } } // Reached iteration limit, give up. return -1.0; } shader camera(float focal_length = 50.0 [[ float min = 0.0, string unit = "mm", float sensitivity = 0.2 ]], int do_distortion = 0 [[ string widget = "checkBox"]], int do_swirl = 0 [[ string widget = "checkBox"]], int do_dof = 0 [[ string widget = "checkBox"]], float distortion_k1 = -0.2, float distortion_k2 = 0.0, float distortion_k3 = 0.0, float swirl_scale = 100.0, float swirl_amplitude = 0.01, float swirl_w = 0.0 [[ float sensitivity = 1]], output point position = 0.0, output vector direction = 0.0, output color throughput = 1.0) { point Pcam = camera_shader_raster_position() - vector(0.5); if (do_distortion) { float distort = invertDistortionModel( Pcam.x, Pcam.y, distortion_k1, distortion_k2, distortion_k3); if (distort < 0.0) { // Distortion model failed, skip the path. throughput = color(0.0); return; } Pcam *= distort; } vector sensor_size; getattribute("cam:sensor_size", sensor_size); Pcam = Pcam * sensor_size / focal_length; if (do_swirl) { Pcam += swirl_amplitude * noise("perlin", Pcam * swirl_scale, swirl_w); } direction = normalize(vector(Pcam.x, Pcam.y, 1.0)); if (do_dof) { float focal_distance; getattribute("cam:focal_distance", focal_distance); getattribute("cam:aperture_position", position); position *= focal_length * 1e-3; point Pfocus = direction * focal_distance / direction.z; direction = normalize(Pfocus - position); } }