This allows users to implement arbitrary camera models using OSL by writing shaders that take an image position as input and compute ray origin and direction. The obvious applications for this are e.g. panorama modes, lens distortion models and realistic lens simulation, but the possibilities are endless. Currently, this is only supported on devices with OSL support, so CPU and OptiX. However, it is independent from the shading model used, so custom cameras can be used without getting the performance hit of OSL shading. A few samples are provided as Text Editor templates. One notable current limitation (in addition to the limited device support) is that inverse mapping is not supported, so Window texture coordinates and the Vector pass will not work with custom cameras. Pull Request: https://projects.blender.org/blender/blender/pulls/129495
80 lines
2.4 KiB
Plaintext
80 lines
2.4 KiB
Plaintext
/* SPDX-FileCopyrightText: 2011-2025 Blender Foundation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 */
|
|
|
|
/* 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);
|
|
}
|
|
}
|