For consistency with other templates, these can be used in new code without restrictions.
76 lines
2.3 KiB
Plaintext
76 lines
2.3 KiB
Plaintext
/* 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, 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);
|
|
|
|
point Pfocus = direction * focal_distance / direction.z;
|
|
direction = normalize(Pfocus - position);
|
|
}
|
|
}
|