scene/schema/camera.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // SPDX-License-Identifier: BSD-3-Clause | ||
| 2 | /// @file camera.h | ||
| 3 | /// @brief UsdGeomCamera: a view's projection, lens and exposure. | ||
| 4 | /// | ||
| 5 | /// References: | ||
| 6 | /// - Pixar, UsdGeomCamera, https://openusd.org/release/api/class_usd_geom_camera.html | ||
| 7 | #pragma once | ||
| 8 | |||
| 9 | #include "ernie/scene/schema/geom.h" | ||
| 10 | |||
| 11 | // clang-format off | ||
| 12 | // Lens lengths are metres, whatever a USD stage's scale: USD's tenths of a scene unit are | ||
| 13 | // converted on import and export. | ||
| 14 | #define ERNIE_LENS_LENGTH(X, Name, usdName, fallback, text) \ | ||
| 15 | X(double, Name, usdName, fallback, text ", metres.", ERNIE_NONNEGATIVE("Lens")) | ||
| 16 | |||
| 17 | #define ERNIE_CAMERA_ATTRIBUTES(X) \ | ||
| 18 | X(std::string, Projection, "projection", "perspective", "How it projects the scene.", \ | ||
| 19 | .group = "Lens", .options = {"perspective", "orthographic"}) \ | ||
| 20 | ERNIE_LENS_LENGTH(X, HorizontalAperture, "horizontalAperture", 0.020955, "Film width") \ | ||
| 21 | ERNIE_LENS_LENGTH(X, VerticalAperture, "verticalAperture", 0.0152908, "Film height") \ | ||
| 22 | X(double, HorizontalApertureOffset, "horizontalApertureOffset", 0.0, \ | ||
| 23 | "The film's offset from the lens axis along x, metres.", .group = "Lens", .finite = true) \ | ||
| 24 | X(double, VerticalApertureOffset, "verticalApertureOffset", 0.0, \ | ||
| 25 | "The film's offset from the lens axis along y, metres.", .group = "Lens", .finite = true) \ | ||
| 26 | ERNIE_LENS_LENGTH(X, FocalLength, "focalLength", 0.05, "The lens's focal length") \ | ||
| 27 | X(glm::dvec2, ClippingRange, "clippingRange", glm::dvec2(1.0, 1000000.0), \ | ||
| 28 | "Near and far distances in metres.", .group = "Lens", .lower = Above(0.0)) \ | ||
| 29 | X(Tensor, ClippingPlanes, "clippingPlanes", Tensor(), \ | ||
| 30 | "(n, 4) planes (a, b, c, d) keeping points where a x + b y + c z + d >= 0.", \ | ||
| 31 | .group = "Lens", .components = 4) \ | ||
| 32 | X(double, FStop, "fStop", 0.0, "The lens's f-number; 0 for a pinhole, all in focus.", \ | ||
| 33 | .group = "Lens", .lower = AtLeast(0.0)) \ | ||
| 34 | X(double, FocusDistance, "focusDistance", 0.0, "Metres to the plane in focus.", \ | ||
| 35 | .group = "Lens", .lower = AtLeast(0.0)) \ | ||
| 36 | X(std::string, StereoRole, "stereoRole", "mono", "Which eye it is.", .group = "Lens", \ | ||
| 37 | .options = {"mono", "left", "right"}) \ | ||
| 38 | X(double, ShutterOpen, "shutter:open", 0.0, "Frames from the time code the shutter opens.", \ | ||
| 39 | .group = "Shutter") \ | ||
| 40 | X(double, ShutterClose, "shutter:close", 0.0, "Frames from the time code it closes.", \ | ||
| 41 | .group = "Shutter") \ | ||
| 42 | X(double, Exposure, "exposure", 0.0, "Stops of exposure added to the image.", \ | ||
| 43 | .group = "Exposure", .finite = true) \ | ||
| 44 | X(double, ExposureIso, "exposure:iso", 100.0, "The sensor's ISO speed.", .group = "Exposure", \ | ||
| 45 | .lower = Above(0.0)) \ | ||
| 46 | X(double, ExposureTime, "exposure:time", 1.0, "Seconds of exposure.", .group = "Exposure", \ | ||
| 47 | .lower = AtLeast(0.0)) \ | ||
| 48 | X(double, ExposureFStop, "exposure:fStop", 1.0, "The f-number exposure is computed with.", \ | ||
| 49 | .group = "Exposure", .lower = Above(0.0)) \ | ||
| 50 | X(double, ExposureResponsivity, "exposure:responsivity", 1.0, "The sensor's responsivity.", \ | ||
| 51 | .group = "Exposure", .lower = AtLeast(0.0)) \ | ||
| 52 | X(std::string, ExposureMode, "ernie:exposure:mode", "manual", \ | ||
| 53 | "auto keys the image to middle grey from the metered scene, after the settings above.", \ | ||
| 54 | .group = "Exposure", .options = {"manual", "auto"}) \ | ||
| 55 | X(double, ExposureAdaptation, "ernie:exposure:adaptation", 0.0, \ | ||
| 56 | "Frames auto exposure takes to cover 63% of a change; 0 at once.", .group = "Exposure", \ | ||
| 57 | .lower = AtLeast(0.0)) \ | ||
| 58 | X(int, ShutterSamples, "ernie:shutter:samples", 8, "Sub-frames rendered across the shutter.", \ | ||
| 59 | .group = "Shutter", .lower = AtLeast(1.0)) \ | ||
| 60 | X(double, ShutterRolling, "ernie:shutter:rolling", 0.0, \ | ||
| 61 | "Frames between the top row's exposure and the bottom row's; 0 global.", .group = "Shutter", \ | ||
| 62 | .lower = AtLeast(0.0)) \ | ||
| 63 | X(std::string, Scan, "ernie:camera:scan", "frame", \ | ||
| 64 | "pushbroom: a line scanner whose rows run from the last frame's pose to this one's.", \ | ||
| 65 | .group = "Shutter", .options = {"frame", "pushbroom"}) \ | ||
| 66 | X(double, PushbroomLineOffset, "ernie:pushbroom:lineOffset", 0.0, \ | ||
| 67 | "Metres from the principal point to the pushbroom's detector line.", \ | ||
| 68 | .group = "Shutter", .finite = true) | ||
| 69 | |||
| 70 | #define ERNIE_LENS_API_ATTRIBUTES(X) \ | ||
| 71 | X(std::string, LensProjection, "ernie:lens:projection", "perspective", \ | ||
| 72 | "Rectilinear, or a Kannala-Brandt fisheye.", .group = "Lens", \ | ||
| 73 | .options = {"perspective", "fisheye"}) \ | ||
| 74 | X(std::vector<float>, LensDistortion, "ernie:lens:distortion", std::vector<float>{}, \ | ||
| 75 | "Brown-Conrady k1 k2 k3 p1 p2; missing ones are 0.", .group = "Lens") \ | ||
| 76 | X(std::vector<float>, LensFisheye, "ernie:lens:fisheye", std::vector<float>{}, \ | ||
| 77 | "Kannala-Brandt k1 k2 k3 k4 of a fisheye; none is equidistant.", .group = "Lens") \ | ||
| 78 | X(bool, LensVignetting, "ernie:lens:vignetting", false, "Natural falloff off axis.", \ | ||
| 79 | .group = "Lens") \ | ||
| 80 | X(double, LensTransmission, "ernie:lens:transmission", 1.0, "The fraction of light passed.", \ | ||
| 81 | ERNIE_FRACTION("Lens")) \ | ||
| 82 | X(std::vector<float>, LensChromaticScale, "ernie:lens:chromatic:scale", std::vector<float>{}, \ | ||
| 83 | "(nm, scale) pairs: lateral colour, the image's scale per wavelength.", .group = "Lens") \ | ||
| 84 | X(std::vector<float>, LensChromaticFocus, "ernie:lens:chromatic:focus", std::vector<float>{}, \ | ||
| 85 | "(nm, metres) pairs: axial colour, the focal length's shift per wavelength.", \ | ||
| 86 | .group = "Lens") \ | ||
| 87 | X(Tensor, LensRays, "ernie:lens:rays", Tensor(), \ | ||
| 88 | "float32 (rows, columns, 3) unit directions every rays step pixels, in place of the " \ | ||
| 89 | "projection and distortion.", \ | ||
| 90 | .group = "Lens", .ranks = {3}) \ | ||
| 91 | X(int, LensRaysStep, "ernie:lens:raysStep", 8, "Pixels between the lens's rays.", \ | ||
| 92 | .group = "Lens", .lower = AtLeast(1.0)) | ||
| 93 | |||
| 94 | #define ERNIE_POLARIZER_API_ATTRIBUTES(X) \ | ||
| 95 | X(std::string, PolarizerType, "ernie:polarizer:type", "linear", \ | ||
| 96 | "linear in front of the lens, or a mosaic of 90, 45 / 135, 0 degree polarizers over 2 x 2 " \ | ||
| 97 | "pixels, as a polarization sensor's.", \ | ||
| 98 | .group = "Polarizer", .options = {"linear", "mosaic"}) \ | ||
| 99 | X(double, PolarizerAngle, "ernie:polarizer:angle", 0.0, \ | ||
| 100 | "Degrees from the image's +x towards +y to a linear polarizer's axis.", .group = "Polarizer", \ | ||
| 101 | .finite = true) \ | ||
| 102 | X(double, PolarizerExtinction, "ernie:polarizer:extinction", 1000.0, \ | ||
| 103 | "Light passed along the axis over light passed across it.", .group = "Polarizer", \ | ||
| 104 | .lower = AtLeast(1.0)) \ | ||
| 105 | X(double, PolarizerTransmission, "ernie:polarizer:transmission", 0.85, \ | ||
| 106 | "The fraction of light polarized along the axis passed.", ERNIE_FRACTION("Polarizer")) | ||
| 107 | |||
| 108 | #define ERNIE_SENSOR_QE(X, Name, usdName, channel) \ | ||
| 109 | X(std::vector<float>, Name, usdName, std::vector<float>{}, \ | ||
| 110 | "(nm, electrons per photon) pairs of the " channel "; unset keeps the generic curve.", \ | ||
| 111 | .group = "Sensor") | ||
| 112 | |||
| 113 | #define ERNIE_SENSOR_API_ATTRIBUTES(X) \ | ||
| 114 | X(glm::dvec2, SpectralRange, "ernie:spectral:range", glm::dvec2(380.0, 780.0), \ | ||
| 115 | "Wavelengths in nm the sensor responds to; its products sample them in bands.", \ | ||
| 116 | .group = "Sensor", .lower = Above(0.0)) \ | ||
| 117 | X(std::string, SensorType, "ernie:sensor:type", "rgb", "A colour or a mono sensor.", \ | ||
| 118 | .group = "Sensor", .options = {"rgb", "mono"}) \ | ||
| 119 | X(bool, SensorNoise, "ernie:sensor:noise", true, "Whether it adds the noise below.", \ | ||
| 120 | .group = "Sensor") \ | ||
| 121 | X(double, SensorFullWell, "ernie:sensor:fullWell", 20000.0, "Electrons a pixel holds.", \ | ||
| 122 | .group = "Sensor", .lower = Above(0.0)) \ | ||
| 123 | X(double, SensorReadNoise, "ernie:sensor:readNoise", 3.0, "Electrons, standard deviation.", \ | ||
| 124 | .group = "Sensor", .lower = AtLeast(0.0)) \ | ||
| 125 | X(double, SensorDarkCurrent, "ernie:sensor:darkCurrent", 0.1, "Electrons per second.", \ | ||
| 126 | .group = "Sensor", .lower = AtLeast(0.0)) \ | ||
| 127 | X(double, SensorPrnu, "ernie:sensor:prnu", 0.005, \ | ||
| 128 | "Standard deviation of each pixel's relative gain.", .group = "Sensor", \ | ||
| 129 | .lower = AtLeast(0.0)) \ | ||
| 130 | X(double, SensorDsnu, "ernie:sensor:dsnu", 0.5, \ | ||
| 131 | "Electrons, standard deviation of each pixel's offset.", .group = "Sensor", \ | ||
| 132 | .lower = AtLeast(0.0)) \ | ||
| 133 | X(double, SensorElectronsPerDn, "ernie:sensor:electronsPerDn", 0.0, \ | ||
| 134 | "At ISO 100; 0 for the full well over the bit depth's range.", .group = "Sensor", \ | ||
| 135 | .lower = AtLeast(0.0)) \ | ||
| 136 | X(int, SensorBitDepth, "ernie:sensor:bitDepth", 12, \ | ||
| 137 | "Bits of each digital number the sensor's ADC makes, such as 8, 12 or 16.", \ | ||
| 138 | .group = "Sensor", .lower = AtLeast(1.0), .upper = AtMost(32.0)) \ | ||
| 139 | X(double, SensorBlackLevel, "ernie:sensor:blackLevel", 0.0, "DN added to every pixel.", \ | ||
| 140 | .group = "Sensor", .lower = AtLeast(0.0)) \ | ||
| 141 | X(double, SensorPixelPitch, "ernie:sensor:pixelPitch", 5.0, \ | ||
| 142 | "Micrometres, of orthographic cameras.", .group = "Sensor", .lower = Above(0.0)) \ | ||
| 143 | X(int, SensorSeed, "ernie:sensor:seed", 0, "The seed of the sensor's noise.", \ | ||
| 144 | .group = "Sensor") \ | ||
| 145 | ERNIE_SENSOR_QE(X, SensorQeR, "ernie:sensor:qe:r", "red channel") \ | ||
| 146 | ERNIE_SENSOR_QE(X, SensorQeG, "ernie:sensor:qe:g", "green channel") \ | ||
| 147 | ERNIE_SENSOR_QE(X, SensorQeB, "ernie:sensor:qe:b", "blue channel") \ | ||
| 148 | ERNIE_SENSOR_QE(X, SensorQeMono, "ernie:sensor:qe:mono", "mono channel") | ||
| 149 | // clang-format on | ||
| 150 | |||
| 151 | namespace ernie { | ||
| 152 | |||
| 153 | 24 | ERNIE_CONCRETE_SCHEMA(Camera, Xformable, ERNIE_CAMERA_ATTRIBUTES, | |
| 154 | "A view looking down -z, y up, with a lens and film."); | ||
| 155 | 4 | ERNIE_API_SCHEMA(ErnieLensAPI, ERNIE_LENS_API_ATTRIBUTES, | |
| 156 | "A camera's lens beyond USD's: fisheyes, distortion, vignetting and chromatic " | ||
| 157 | "aberration."); | ||
| 158 | 4 | ERNIE_API_SCHEMA(ErniePolarizerAPI, ERNIE_POLARIZER_API_ATTRIBUTES, | |
| 159 | "A polarizer in front of a camera's lens, or a polarization sensor's mosaic."); | ||
| 160 | 8 | ERNIE_API_SCHEMA(ErnieSensorAPI, ERNIE_SENSOR_API_ATTRIBUTES, | |
| 161 | "A camera's sensor: its spectral range, noise, ADC and quantum efficiency; its " | ||
| 162 | "products set how finely the range is sampled."); | ||
| 163 | |||
| 164 | } // namespace ernie | ||
| 165 |