| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
|
|
| #pragma once |
|
|
| #include <neural-graphics-primitives/common.h> |
| #include <neural-graphics-primitives/random_val.cuh> |
|
|
| #include <tiny-cuda-nn/common.h> |
| #include <tiny-cuda-nn/gpu_memory.h> |
|
|
| #include <Eigen/Dense> |
|
|
| NGP_NAMESPACE_BEGIN |
|
|
| using precision_t = tcnn::network_precision_t; |
|
|
|
|
| inline NGP_HOST_DEVICE float srgb_to_linear(float srgb) { |
| if (srgb <= 0.04045f) { |
| return srgb / 12.92f; |
| } else { |
| return std::pow((srgb + 0.055f) / 1.055f, 2.4f); |
| } |
| } |
|
|
| inline NGP_HOST_DEVICE Eigen::Array3f srgb_to_linear(const Eigen::Array3f& x) { |
| return {srgb_to_linear(x.x()), srgb_to_linear(x.y()), (srgb_to_linear(x.z()))}; |
| } |
|
|
| inline NGP_HOST_DEVICE float srgb_to_linear_derivative(float srgb) { |
| if (srgb <= 0.04045f) { |
| return 1.0f / 12.92f; |
| } else { |
| return 2.4f / 1.055f * std::pow((srgb + 0.055f) / 1.055f, 1.4f); |
| } |
| } |
|
|
| inline NGP_HOST_DEVICE Eigen::Array3f srgb_to_linear_derivative(const Eigen::Array3f& x) { |
| return {srgb_to_linear_derivative(x.x()), srgb_to_linear_derivative(x.y()), (srgb_to_linear_derivative(x.z()))}; |
| } |
|
|
| inline NGP_HOST_DEVICE float linear_to_srgb(float linear) { |
| if (linear < 0.0031308f) { |
| return 12.92f * linear; |
| } else { |
| return 1.055f * std::pow(linear, 0.41666f) - 0.055f; |
| } |
| } |
|
|
| inline NGP_HOST_DEVICE Eigen::Array3f linear_to_srgb(const Eigen::Array3f& x) { |
| return {linear_to_srgb(x.x()), linear_to_srgb(x.y()), (linear_to_srgb(x.z()))}; |
| } |
|
|
| inline NGP_HOST_DEVICE float linear_to_srgb_derivative(float linear) { |
| if (linear < 0.0031308f) { |
| return 12.92f; |
| } else { |
| return 1.055f * 0.41666f * std::pow(linear, 0.41666f - 1.0f); |
| } |
| } |
|
|
| inline NGP_HOST_DEVICE Eigen::Array3f linear_to_srgb_derivative(const Eigen::Array3f& x) { |
| return {linear_to_srgb_derivative(x.x()), linear_to_srgb_derivative(x.y()), (linear_to_srgb_derivative(x.z()))}; |
| } |
|
|
| template <uint32_t N_DIMS, typename T> |
| NGP_HOST_DEVICE Eigen::Matrix<float, N_DIMS, 1> read_image(const T* __restrict__ data, const Eigen::Vector2i& resolution, const Eigen::Vector2f& pos) { |
| const Eigen::Vector2f pos_float = Eigen::Vector2f{pos.x() * (float)(resolution.x()-1), pos.y() * (float)(resolution.y()-1)}; |
| const Eigen::Vector2i texel = pos_float.cast<int>(); |
|
|
| const Eigen::Vector2f weight = pos_float - texel.cast<float>(); |
|
|
| auto read_val = [&](Eigen::Vector2i pos) { |
| pos.x() = std::max(std::min(pos.x(), resolution.x()-1), 0); |
| pos.y() = std::max(std::min(pos.y(), resolution.y()-1), 0); |
|
|
| Eigen::Matrix<float, N_DIMS, 1> result; |
| if (std::is_same<T, float>::value) { |
| result = *(Eigen::Matrix<T, N_DIMS, 1>*)&data[(pos.x() + pos.y() * resolution.x()) * N_DIMS]; |
| } else { |
| auto val = *(tcnn::vector_t<T, N_DIMS>*)&data[(pos.x() + pos.y() * resolution.x()) * N_DIMS]; |
|
|
| NGP_PRAGMA_UNROLL |
| for (uint32_t i = 0; i < N_DIMS; ++i) { |
| result[i] = (float)val[i]; |
| } |
| } |
| return result; |
| }; |
|
|
| return ( |
| (1 - weight.x()) * (1 - weight.y()) * read_val({texel.x(), texel.y()}) + |
| (weight.x()) * (1 - weight.y()) * read_val({texel.x()+1, texel.y()}) + |
| (1 - weight.x()) * (weight.y()) * read_val({texel.x(), texel.y()+1}) + |
| (weight.x()) * (weight.y()) * read_val({texel.x()+1, texel.y()+1}) |
| ); |
| } |
|
|
| template <uint32_t N_DIMS, typename T> |
| __device__ void deposit_image_gradient(const Eigen::Matrix<float, N_DIMS, 1>& value, T* __restrict__ gradient, T* __restrict__ gradient_weight, const Eigen::Vector2i& resolution, const Eigen::Vector2f& pos) { |
| const Eigen::Vector2f pos_float = Eigen::Vector2f{pos.x() * (resolution.x()-1), pos.y() * (resolution.y()-1)}; |
| const Eigen::Vector2i texel = pos_float.cast<int>(); |
|
|
| const Eigen::Vector2f weight = pos_float - texel.cast<float>(); |
|
|
| auto deposit_val = [&](const Eigen::Matrix<float, N_DIMS, 1>& value, T weight, Eigen::Vector2i pos) { |
| pos.x() = std::max(std::min(pos.x(), resolution.x()-1), 0); |
| pos.y() = std::max(std::min(pos.y(), resolution.y()-1), 0); |
|
|
| #if TCNN_MIN_GPU_ARCH >= 60 |
| if (std::is_same<T, __half>::value) { |
| for (uint32_t c = 0; c < N_DIMS; c += 2) { |
| atomicAdd((__half2*)&gradient[(pos.x() + pos.y() * resolution.x()) * N_DIMS + c], {(T)value[c] * weight, (T)value[c+1] * weight}); |
| atomicAdd((__half2*)&gradient_weight[(pos.x() + pos.y() * resolution.x()) * N_DIMS + c], {weight, weight}); |
| } |
| } else |
| #endif |
| { |
| for (uint32_t c = 0; c < N_DIMS; ++c) { |
| atomicAdd(&gradient[(pos.x() + pos.y() * resolution.x()) * N_DIMS + c], (T)value[c] * weight); |
| atomicAdd(&gradient_weight[(pos.x() + pos.y() * resolution.x()) * N_DIMS + c], weight); |
| } |
| } |
| }; |
|
|
| deposit_val(value, (1 - weight.x()) * (1 - weight.y()), {texel.x(), texel.y()}); |
| deposit_val(value, (weight.x()) * (1 - weight.y()), {texel.x()+1, texel.y()}); |
| deposit_val(value, (1 - weight.x()) * (weight.y()), {texel.x(), texel.y()+1}); |
| deposit_val(value, (weight.x()) * (weight.y()), {texel.x()+1, texel.y()+1}); |
| } |
|
|
| template <typename T> |
| __device__ __host__ inline void apply_opencv_lens_distortion(const T* extra_params, const T u, const T v, T* du, T* dv) { |
| const T k1 = extra_params[0]; |
| const T k2 = extra_params[1]; |
| const T p1 = extra_params[2]; |
| const T p2 = extra_params[3]; |
|
|
| const T u2 = u * u; |
| const T uv = u * v; |
| const T v2 = v * v; |
| const T r2 = u2 + v2; |
| const T radial = k1 * r2 + k2 * r2 * r2; |
| *du = u * radial + T(2) * p1 * uv + p2 * (r2 + T(2) * u2); |
| *dv = v * radial + T(2) * p2 * uv + p1 * (r2 + T(2) * v2); |
| } |
|
|
| template <typename T> |
| __device__ __host__ inline void iterative_opencv_lens_undistortion(const T* params, T* u, T* v) { |
| |
| |
| |
| const uint32_t kNumIterations = 100; |
| const float kMaxStepNorm = 1e-10f; |
| const float kRelStepSize = 1e-6f; |
|
|
| Eigen::Matrix2f J; |
| const Eigen::Vector2f x0(*u, *v); |
| Eigen::Vector2f x(*u, *v); |
| Eigen::Vector2f dx; |
| Eigen::Vector2f dx_0b; |
| Eigen::Vector2f dx_0f; |
| Eigen::Vector2f dx_1b; |
| Eigen::Vector2f dx_1f; |
|
|
| for (uint32_t i = 0; i < kNumIterations; ++i) { |
| const float step0 = std::max(std::numeric_limits<float>::epsilon(), std::abs(kRelStepSize * x(0))); |
| const float step1 = std::max(std::numeric_limits<float>::epsilon(), std::abs(kRelStepSize * x(1))); |
| apply_opencv_lens_distortion(params, x(0), x(1), &dx(0), &dx(1)); |
| apply_opencv_lens_distortion(params, x(0) - step0, x(1), &dx_0b(0), &dx_0b(1)); |
| apply_opencv_lens_distortion(params, x(0) + step0, x(1), &dx_0f(0), &dx_0f(1)); |
| apply_opencv_lens_distortion(params, x(0), x(1) - step1, &dx_1b(0), &dx_1b(1)); |
| apply_opencv_lens_distortion(params, x(0), x(1) + step1, &dx_1f(0), &dx_1f(1)); |
| J(0, 0) = 1 + (dx_0f(0) - dx_0b(0)) / (2 * step0); |
| J(0, 1) = (dx_1f(0) - dx_1b(0)) / (2 * step1); |
| J(1, 0) = (dx_0f(1) - dx_0b(1)) / (2 * step0); |
| J(1, 1) = 1 + (dx_1f(1) - dx_1b(1)) / (2 * step1); |
| const Eigen::Vector2f step_x = J.inverse() * (x + dx - x0); |
| x -= step_x; |
| if (step_x.squaredNorm() < kMaxStepNorm) { |
| break; |
| } |
| } |
|
|
| *u = x(0); |
| *v = x(1); |
| } |
|
|
| inline NGP_HOST_DEVICE Ray pixel_to_ray_pinhole( |
| uint32_t spp, |
| const Eigen::Vector2i& pixel, |
| const Eigen::Vector2i& resolution, |
| const Eigen::Vector2f& focal_length, |
| const Eigen::Matrix<float, 3, 4>& camera_matrix, |
| const Eigen::Vector2f& screen_center |
| ) { |
| const Eigen::Vector2f uv = pixel.cast<float>().cwiseQuotient(resolution.cast<float>()); |
|
|
| Eigen::Vector3f dir = { |
| (uv.x() - screen_center.x()) * (float)resolution.x() / focal_length.x(), |
| (uv.y() - screen_center.y()) * (float)resolution.y() / focal_length.y(), |
| 1.0f |
| }; |
|
|
| dir = camera_matrix.block<3, 3>(0, 0) * dir; |
|
|
| Eigen::Vector3f origin = camera_matrix.col(3); |
| return {origin, dir}; |
| } |
|
|
| inline NGP_HOST_DEVICE Eigen::Matrix<float, 3, 4> get_xform_given_rolling_shutter(const TrainingXForm& training_xform, const Eigen::Vector4f& rolling_shutter, const Eigen::Vector2f& uv, float motionblur_time) { |
| float pixel_t = rolling_shutter.x() + rolling_shutter.y() * uv.x() + rolling_shutter.z() * uv.y() + rolling_shutter.w() * motionblur_time; |
|
|
| Eigen::Vector3f pos = training_xform.start.col(3) + (training_xform.end.col(3) - training_xform.start.col(3)) * pixel_t; |
| Eigen::Quaternionf rot = Eigen::Quaternionf(training_xform.start.block<3, 3>(0, 0)).slerp(pixel_t, Eigen::Quaternionf(training_xform.end.block<3, 3>(0, 0))); |
|
|
| Eigen::Matrix<float, 3, 4> rv; |
| rv.col(3) = pos; |
| rv.block<3, 3>(0, 0) = Eigen::Quaternionf(rot).normalized().toRotationMatrix(); |
| return rv; |
| } |
|
|
| inline NGP_HOST_DEVICE Eigen::Vector3f f_theta_undistortion(const Eigen::Vector2f& uv, const float* params, const Eigen::Vector3f& error_direction) { |
| |
| float xpix = uv.x() * params[5]; |
| float ypix = uv.y() * params[6]; |
| float norm = sqrtf(xpix*xpix + ypix*ypix); |
| float alpha = params[0] + norm * (params[1] + norm * (params[2] + norm * (params[3] + norm * params[4]))); |
| float sin_alpha, cos_alpha; |
| sincosf(alpha, &sin_alpha, &cos_alpha); |
| if (cos_alpha <= std::numeric_limits<float>::min() || norm == 0.f) { |
| return error_direction; |
| } |
| sin_alpha *= 1.f / norm; |
| return { sin_alpha * xpix, sin_alpha * ypix, cos_alpha }; |
| } |
|
|
| inline NGP_HOST_DEVICE Eigen::Vector3f latlong_to_dir(const Eigen::Vector2f& uv) { |
| float theta = (uv.y() - 0.5f) * PI(); |
| float phi = (uv.x() - 0.5f) * PI() * 2.0f; |
| float sp, cp, st, ct; |
| sincosf(theta, &st, &ct); |
| sincosf(phi, &sp, &cp); |
| return {sp * ct, st, cp * ct}; |
| } |
|
|
| inline NGP_HOST_DEVICE Ray pixel_to_ray( |
| uint32_t spp, |
| const Eigen::Vector2i& pixel, |
| const Eigen::Vector2i& resolution, |
| const Eigen::Vector2f& focal_length, |
| const Eigen::Matrix<float, 3, 4>& camera_matrix, |
| const Eigen::Vector2f& screen_center, |
| const Eigen::Vector3f& parallax_shift, |
| bool snap_to_pixel_centers = false, |
| float near_distance = 0.0f, |
| float focus_z = 1.0f, |
| float aperture_size = 0.0f, |
| const Lens& lens = {}, |
| const float* __restrict__ distortion_grid = nullptr, |
| const Eigen::Vector2i distortion_grid_resolution = Eigen::Vector2i::Zero() |
| ) { |
| Eigen::Vector2f offset = ld_random_pixel_offset(snap_to_pixel_centers ? 0 : spp); |
| Eigen::Vector2f uv = (pixel.cast<float>() + offset).cwiseQuotient(resolution.cast<float>()); |
|
|
| Eigen::Vector3f dir; |
| if (lens.mode == ELensMode::FTheta) { |
| dir = f_theta_undistortion(uv - screen_center, lens.params, {1000.f, 0.f, 0.f}); |
| if (dir.x() == 1000.f) { |
| return {{1000.f, 0.f, 0.f}, {0.f, 0.f, 1.f}}; |
| } |
| } else if (lens.mode == ELensMode::LatLong) { |
| dir = latlong_to_dir(uv); |
| } else { |
| dir = { |
| (uv.x() - screen_center.x()) * (float)resolution.x() / focal_length.x(), |
| (uv.y() - screen_center.y()) * (float)resolution.y() / focal_length.y(), |
| 1.0f |
| }; |
| if (lens.mode == ELensMode::OpenCV) { |
| iterative_opencv_lens_undistortion(lens.params, &dir.x(), &dir.y()); |
| } |
| } |
| if (distortion_grid) { |
| dir.head<2>() += read_image<2>(distortion_grid, distortion_grid_resolution, uv); |
| } |
|
|
| Eigen::Vector3f head_pos = {parallax_shift.x(), parallax_shift.y(), 0.f}; |
| dir -= head_pos * parallax_shift.z(); |
| dir = camera_matrix.block<3, 3>(0, 0) * dir; |
|
|
| Eigen::Vector3f origin = camera_matrix.block<3, 3>(0, 0) * head_pos + camera_matrix.col(3); |
| |
| if (aperture_size > 0.0f) { |
| Eigen::Vector3f lookat = origin + dir * focus_z; |
| Eigen::Vector2f blur = aperture_size * square2disk_shirley(ld_random_val_2d(spp, (uint32_t)pixel.x() * 19349663 + (uint32_t)pixel.y() * 96925573) * 2.0f - Eigen::Vector2f::Ones()); |
| origin += camera_matrix.block<3, 2>(0, 0) * blur; |
| dir = (lookat - origin) / focus_z; |
| } |
| |
| origin += dir * near_distance; |
|
|
| return {origin, dir}; |
| } |
|
|
| inline NGP_HOST_DEVICE Eigen::Vector2f pos_to_pixel( |
| const Eigen::Vector3f& pos, |
| const Eigen::Vector2i& resolution, |
| const Eigen::Vector2f& focal_length, |
| const Eigen::Matrix<float, 3, 4>& camera_matrix, |
| const Eigen::Vector2f& screen_center, |
| const Eigen::Vector3f& parallax_shift, |
| const Lens& lens = {} |
| ) { |
| |
| Eigen::Vector3f head_pos = {parallax_shift.x(), parallax_shift.y(), 0.f}; |
| Eigen::Vector3f origin = camera_matrix.block<3, 3>(0, 0) * head_pos + camera_matrix.col(3); |
|
|
| Eigen::Vector3f dir = pos - origin; |
| dir = camera_matrix.block<3, 3>(0, 0).inverse() * dir; |
| dir /= dir.z(); |
| dir += head_pos * parallax_shift.z(); |
|
|
| if (lens.mode == ELensMode::OpenCV) { |
| float du, dv; |
| apply_opencv_lens_distortion(lens.params, dir.x(), dir.y(), &du, &dv); |
| dir.x() += du; |
| dir.y() += dv; |
| } else if (lens.mode == ELensMode::FTheta) { |
| assert(false); |
| } else if (lens.mode == ELensMode::LatLong) { |
| assert(false); |
| } |
|
|
| return { |
| dir.x() * focal_length.x() + screen_center.x() * resolution.x(), |
| dir.y() * focal_length.y() + screen_center.y() * resolution.y(), |
| }; |
| } |
|
|
| inline NGP_HOST_DEVICE Eigen::Vector2f motion_vector_3d( |
| const uint32_t sample_index, |
| const Eigen::Vector2i& pixel, |
| const Eigen::Vector2i& resolution, |
| const Eigen::Vector2f& focal_length, |
| const Eigen::Matrix<float, 3, 4>& camera, |
| const Eigen::Matrix<float, 3, 4>& prev_camera, |
| const Eigen::Vector2f& screen_center, |
| const Eigen::Vector3f& parallax_shift, |
| const bool snap_to_pixel_centers, |
| const float depth, |
| const Lens& lens = {} |
| ) { |
| Ray ray = pixel_to_ray( |
| sample_index, |
| pixel, |
| resolution, |
| focal_length, |
| camera, |
| screen_center, |
| parallax_shift, |
| snap_to_pixel_centers, |
| 0.0f, |
| 1.0f, |
| 0.0f, |
| lens, |
| nullptr, |
| Eigen::Vector2i::Zero() |
| ); |
|
|
| Eigen::Vector2f prev_pixel = pos_to_pixel( |
| ray.o + ray.d * depth, |
| resolution, |
| focal_length, |
| prev_camera, |
| screen_center, |
| parallax_shift, |
| lens |
| ); |
|
|
| return prev_pixel - (pixel.cast<float>() + ld_random_pixel_offset(sample_index)); |
| } |
|
|
| inline NGP_HOST_DEVICE Eigen::Vector2f pixel_to_image_uv( |
| const uint32_t sample_index, |
| const Eigen::Vector2i& pixel, |
| const Eigen::Vector2i& resolution, |
| const Eigen::Vector2i& image_resolution, |
| const Eigen::Vector2f& screen_center, |
| const float view_dist, |
| const Eigen::Vector2f& image_pos, |
| const bool snap_to_pixel_centers |
| ) { |
| Eigen::Vector2f jit = ld_random_pixel_offset(snap_to_pixel_centers ? 0 : sample_index); |
| Eigen::Vector2f offset = screen_center.cwiseProduct(resolution.cast<float>()) + jit; |
|
|
| float y_scale = view_dist; |
| float x_scale = y_scale * resolution.x() / resolution.y(); |
|
|
| return { |
| ((x_scale * (pixel.x() + offset.x())) / resolution.x() - view_dist * image_pos.x()) / image_resolution.x() * image_resolution.y(), |
| (y_scale * (pixel.y() + offset.y())) / resolution.y() - view_dist * image_pos.y() |
| }; |
| } |
|
|
| inline NGP_HOST_DEVICE Eigen::Vector2f image_uv_to_pixel( |
| const Eigen::Vector2f& uv, |
| const Eigen::Vector2i& resolution, |
| const Eigen::Vector2i& image_resolution, |
| const Eigen::Vector2f& screen_center, |
| const float view_dist, |
| const Eigen::Vector2f& image_pos |
| ) { |
| Eigen::Vector2f offset = screen_center.cwiseProduct(resolution.cast<float>()); |
|
|
| float y_scale = view_dist; |
| float x_scale = y_scale * resolution.x() / resolution.y(); |
|
|
| return { |
| ((uv.x() / image_resolution.y() * image_resolution.x()) + view_dist * image_pos.x()) * resolution.x() / x_scale - offset.x(), |
| (uv.y() + view_dist * image_pos.y()) * resolution.y() / y_scale - offset.y() |
| }; |
| } |
|
|
| inline NGP_HOST_DEVICE Eigen::Vector2f motion_vector_2d( |
| const uint32_t sample_index, |
| const Eigen::Vector2i& pixel, |
| const Eigen::Vector2i& resolution, |
| const Eigen::Vector2i& image_resolution, |
| const Eigen::Vector2f& screen_center, |
| const float view_dist, |
| const float prev_view_dist, |
| const Eigen::Vector2f& image_pos, |
| const Eigen::Vector2f& prev_image_pos, |
| const bool snap_to_pixel_centers |
| ) { |
| Eigen::Vector2f uv = pixel_to_image_uv( |
| sample_index, |
| pixel, |
| resolution, |
| image_resolution, |
| screen_center, |
| view_dist, |
| image_pos, |
| snap_to_pixel_centers |
| ); |
|
|
| Eigen::Vector2f prev_pixel = image_uv_to_pixel( |
| uv, |
| resolution, |
| image_resolution, |
| screen_center, |
| prev_view_dist, |
| prev_image_pos |
| ); |
|
|
| return prev_pixel - (pixel.cast<float>() + ld_random_pixel_offset(sample_index)); |
| } |
|
|
| inline NGP_HOST_DEVICE float fov_to_focal_length(int resolution, float degrees) { |
| return 0.5f * (float)resolution / tanf(0.5f * degrees*(float)PI()/180); |
| } |
|
|
| inline NGP_HOST_DEVICE Eigen::Vector2f fov_to_focal_length(const Eigen::Vector2i& resolution, const Eigen::Vector2f& degrees) { |
| return 0.5f * resolution.cast<float>().cwiseQuotient((0.5f * degrees * (float)PI()/180).array().tan().matrix()); |
| } |
|
|
| inline NGP_HOST_DEVICE float focal_length_to_fov(int resolution, float focal_length) { |
| return 2.f * 180.f / PI() * atanf(float(resolution)/(focal_length*2.f)); |
| } |
|
|
| inline NGP_HOST_DEVICE Eigen::Vector2f focal_length_to_fov(const Eigen::Vector2i& resolution, const Eigen::Vector2f& focal_length) { |
| return 2.f * 180.f / PI() * resolution.cast<float>().cwiseQuotient(focal_length*2).array().atan().matrix(); |
| } |
|
|
| inline NGP_HOST_DEVICE float4 to_float4(const Eigen::Array4f& x) { |
| return {x.x(), x.y(), x.z(), x.w()}; |
| } |
|
|
| inline NGP_HOST_DEVICE float4 to_float4(const Eigen::Vector4f& x) { |
| return {x.x(), x.y(), x.z(), x.w()}; |
| } |
|
|
| inline NGP_HOST_DEVICE float3 to_float3(const Eigen::Array3f& x) { |
| return {x.x(), x.y(), x.z()}; |
| } |
|
|
| inline NGP_HOST_DEVICE float3 to_float3(const Eigen::Vector3f& x) { |
| return {x.x(), x.y(), x.z()}; |
| } |
|
|
| inline NGP_HOST_DEVICE float2 to_float2(const Eigen::Array2f& x) { |
| return {x.x(), x.y()}; |
| } |
|
|
| inline NGP_HOST_DEVICE float2 to_float2(const Eigen::Vector2f& x) { |
| return {x.x(), x.y()}; |
| } |
|
|
| inline NGP_HOST_DEVICE Eigen::Array4f to_array4(const float4& x) { |
| return {x.x, x.y, x.z, x.w}; |
| } |
|
|
| inline NGP_HOST_DEVICE Eigen::Vector4f to_vec4(const float4& x) { |
| return {x.x, x.y, x.z, x.w}; |
| } |
|
|
| inline NGP_HOST_DEVICE Eigen::Array3f to_array3(const float3& x) { |
| return {x.x, x.y, x.z}; |
| } |
|
|
| inline NGP_HOST_DEVICE Eigen::Vector3f to_vec3(const float3& x) { |
| return {x.x, x.y, x.z}; |
| } |
|
|
| inline NGP_HOST_DEVICE Eigen::Array2f to_array2(const float2& x) { |
| return {x.x, x.y}; |
| } |
|
|
| inline NGP_HOST_DEVICE Eigen::Vector2f to_vec2(const float2& x) { |
| return {x.x, x.y}; |
| } |
|
|
| inline NGP_HOST_DEVICE Eigen::Vector3f faceforward(const Eigen::Vector3f& n, const Eigen::Vector3f& i, const Eigen::Vector3f& nref) { |
| return n * copysignf(1.0f, i.dot(nref)); |
| } |
|
|
| inline NGP_HOST_DEVICE void apply_quilting(uint32_t* x, uint32_t* y, const Eigen::Vector2i& resolution, Eigen::Vector3f& parallax_shift, const Eigen::Vector2i& quilting_dims) { |
| float resx = float(resolution.x()) / quilting_dims.x(); |
| float resy = float(resolution.y()) / quilting_dims.y(); |
| int panelx = (int)floorf(*x/resx); |
| int panely = (int)floorf(*y/resy); |
| *x = (*x - panelx * resx); |
| *y = (*y - panely * resy); |
| int idx = panelx + quilting_dims.x() * panely; |
|
|
| if (quilting_dims == Eigen::Vector2i{2, 1}) { |
| |
| parallax_shift.x() = idx ? (-0.5f * parallax_shift.x()) : (0.5f * parallax_shift.x()); |
| } else { |
| |
| |
| const float max_parallax_angle = 17.5f; |
| float parallax_angle = max_parallax_angle * PI() / 180.f * ((idx+0.5f)*2.f / float(quilting_dims.y() * quilting_dims.x()) - 1.f); |
| parallax_shift.x() = atanf(parallax_angle) / parallax_shift.z(); |
| } |
| } |
|
|
| template <typename T> |
| __global__ void from_rgba32(const uint64_t num_pixels, const uint8_t* __restrict__ pixels, T* __restrict__ out, bool white_2_transparent = false, bool black_2_transparent = false, uint32_t mask_color = 0) { |
| const uint64_t i = threadIdx.x + blockIdx.x * blockDim.x; |
| if (i >= num_pixels) return; |
|
|
| uint8_t rgba[4]; |
| *((uint32_t*)&rgba[0]) = *((uint32_t*)&pixels[i*4]); |
|
|
| float alpha = rgba[3] * (1.0f/255.0f); |
| |
| if (white_2_transparent && rgba[0]==255 && rgba[1]==255 && rgba[2]==255) { |
| alpha = 0.f; |
| } |
| if (black_2_transparent && rgba[0]==0 && rgba[1]==0 && rgba[2]==0) { |
| alpha = 0.f; |
| } |
|
|
| tcnn::vector_t<T, 4> rgba_out; |
| rgba_out[0] = (T)(srgb_to_linear(rgba[0] * (1.0f/255.0f)) * alpha); |
| rgba_out[1] = (T)(srgb_to_linear(rgba[1] * (1.0f/255.0f)) * alpha); |
| rgba_out[2] = (T)(srgb_to_linear(rgba[2] * (1.0f/255.0f)) * alpha); |
| rgba_out[3] = (T)alpha; |
|
|
| if (mask_color != 0 && mask_color == *((uint32_t*)&rgba[0])) { |
| rgba_out[0] = rgba_out[1] = rgba_out[2] = rgba_out[3] = (T)-1.0f; |
| } |
|
|
| *((tcnn::vector_t<T, 4>*)&out[i*4]) = rgba_out; |
| } |
|
|
|
|
| |
| inline NGP_HOST_DEVICE Eigen::Array3f hsv_to_rgb(const Eigen::Array3f& hsv) { |
| float h = hsv.x(), s = hsv.y(), v = hsv.z(); |
| if (s == 0.0f) { |
| return Eigen::Array3f::Constant(v); |
| } |
|
|
| h = fmodf(h, 1.0f) * 6.0f; |
| int i = (int)h; |
| float f = h - (float)i; |
| float p = v * (1.0f - s); |
| float q = v * (1.0f - s * f); |
| float t = v * (1.0f - s * (1.0f - f)); |
|
|
| switch (i) { |
| case 0: return {v, t, p}; |
| case 1: return {q, v, p}; |
| case 2: return {p, v, t}; |
| case 3: return {p, q, v}; |
| case 4: return {t, p, v}; |
| case 5: default: return {v, p, q}; |
| } |
| } |
|
|
| inline NGP_HOST_DEVICE Eigen::Array3f to_rgb(const Eigen::Vector2f& dir) { |
| return hsv_to_rgb({atan2f(dir.y(), dir.x()) / (2.0f * PI()) + 0.5f, 1.0f, dir.norm()}); |
| } |
|
|
| enum class EImageDataType { |
| None, |
| Byte, |
| Half, |
| Float, |
| }; |
|
|
| enum class EDepthDataType { |
| UShort, |
| Float, |
| }; |
|
|
| inline NGP_HOST_DEVICE Eigen::Vector2i image_pos(const Eigen::Vector2f& pos, const Eigen::Vector2i& resolution) { |
| return pos.cwiseProduct(resolution.cast<float>()).cast<int>().cwiseMin(resolution - Eigen::Vector2i::Constant(1)).cwiseMax(0); |
| } |
|
|
| inline NGP_HOST_DEVICE uint64_t pixel_idx(const Eigen::Vector2i& pos, const Eigen::Vector2i& resolution, uint32_t img) { |
| return pos.x() + pos.y() * resolution.x() + img * (uint64_t)resolution.x() * resolution.y(); |
| } |
|
|
| inline NGP_HOST_DEVICE uint64_t pixel_idx(const Eigen::Vector2f& xy, const Eigen::Vector2i& resolution, uint32_t img) { |
| return pixel_idx(image_pos(xy, resolution), resolution, img); |
| } |
|
|
| |
| |
|
|
| |
| |
|
|
| |
|
|
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
|
|
| |
| |
|
|
| inline NGP_HOST_DEVICE Eigen::Array4f read_rgba(Eigen::Vector2i px, const Eigen::Vector2i& resolution, const void* pixels, EImageDataType image_data_type, uint32_t img = 0) { |
| switch (image_data_type) { |
| default: |
| |
| return Eigen::Array4f{5.0f, 0.0f, 0.0f, 1.0f}; |
| case EImageDataType::Byte: { |
| uint8_t val[4]; |
| *(uint32_t*)&val[0] = ((uint32_t*)pixels)[pixel_idx(px, resolution, img)]; |
| if (*(uint32_t*)&val[0] == 0x00FF00FF) { |
| return Eigen::Array4f::Constant(-1.0f); |
| } |
|
|
| float alpha = (float)val[3] * (1.0f/255.0f); |
| return Eigen::Array4f{ |
| srgb_to_linear((float)val[0] * (1.0f/255.0f)) * alpha, |
| srgb_to_linear((float)val[1] * (1.0f/255.0f)) * alpha, |
| srgb_to_linear((float)val[2] * (1.0f/255.0f)) * alpha, |
| alpha, |
| }; |
| } |
| case EImageDataType::Half: { |
| __half val[4]; |
| *(uint64_t*)&val[0] = ((uint64_t*)pixels)[pixel_idx(px, resolution, img)]; |
| return Eigen::Array4f{val[0], val[1], val[2], val[3]}; |
| } |
| case EImageDataType::Float: |
| return ((Eigen::Array4f*)pixels)[pixel_idx(px, resolution, img)]; |
| } |
| } |
|
|
| inline NGP_HOST_DEVICE Eigen::Array4f read_rgba(Eigen::Vector2f pos, const Eigen::Vector2i& resolution, const void* pixels, EImageDataType image_data_type, uint32_t img = 0) { |
| return read_rgba(image_pos(pos, resolution), resolution, pixels, image_data_type, img); |
| } |
|
|
| inline NGP_HOST_DEVICE float read_depth(Eigen::Vector2f pos, const Eigen::Vector2i& resolution, const float* depth, uint32_t img = 0) { |
| auto read_val = [&](const Eigen::Vector2i& p) { |
| return depth[pixel_idx(p, resolution, img)]; |
| }; |
|
|
| return read_val(image_pos(pos, resolution)); |
| } |
|
|
| Eigen::Matrix<float, 3, 4> log_space_lerp(const Eigen::Matrix<float, 3, 4>& begin, const Eigen::Matrix<float, 3, 4>& end, float t); |
|
|
| tcnn::GPUMemory<float> load_exr(const std::string& filename, int& width, int& height); |
| tcnn::GPUMemory<float> load_stbi(const std::string& filename, int& width, int& height); |
|
|
| NGP_NAMESPACE_END |
|
|