diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2022-05-14 21:29:28 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2022-05-17 13:39:02 +0300 |
commit | 3ccdc362dad3ddfa8e4c752c58408a6b64c7b2f2 (patch) | |
tree | 381ddf8a18b11d9b39c7c00b4d3eb6e0b3087244 /source | |
parent | 46114f0a3633eead3b8178566427d96dd10c08e5 (diff) |
EEVEE-Next: Add camera module
Diffstat (limited to 'source')
7 files changed, 456 insertions, 6 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index dd06b888b41..e5aca26c43c 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -133,6 +133,7 @@ set(SRC engines/eevee/eevee_subsurface.c engines/eevee/eevee_temporal_sampling.c engines/eevee/eevee_volumes.c + engines/eevee_next/eevee_camera.cc engines/eevee_next/eevee_engine.cc engines/eevee_next/eevee_instance.cc engines/eevee_next/eevee_material.cc @@ -352,6 +353,7 @@ set(GLSL_SRC engines/eevee/shaders/world_vert.glsl engines/eevee_next/shaders/eevee_attributes_lib.glsl + engines/eevee_next/shaders/eevee_camera_lib.glsl engines/eevee_next/shaders/eevee_geom_curves_vert.glsl engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl diff --git a/source/blender/draw/engines/eevee_next/eevee_camera.cc b/source/blender/draw/engines/eevee_next/eevee_camera.cc new file mode 100644 index 00000000000..3a7c42cd018 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/eevee_camera.cc @@ -0,0 +1,146 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2021 Blender Foundation. + */ + +/** \file + * \ingroup eevee + */ + +#include <array> + +#include "DRW_render.h" + +#include "DNA_camera_types.h" +#include "DNA_view3d_types.h" + +#include "BKE_camera.h" +#include "DEG_depsgraph_query.h" +#include "RE_pipeline.h" + +#include "eevee_camera.hh" +#include "eevee_instance.hh" + +namespace blender::eevee { + +/* -------------------------------------------------------------------- */ +/** \name Camera + * \{ */ + +void Camera::init() +{ + const Object *camera_eval = inst_.camera_eval_object; + synced_ = false; + data_.swap(); + + CameraData &data = data_.current(); + + if (camera_eval) { + const ::Camera *cam = reinterpret_cast<const ::Camera *>(camera_eval->data); + switch (cam->type) { + default: + case CAM_PERSP: + data.type = CAMERA_PERSP; + case CAM_ORTHO: + data.type = CAMERA_ORTHO; +#if 0 /* TODO(fclem): Make fisheye properties inside blender. */ + case CAM_PANO: { + switch (cam->panorama_type) { + default: + case CAM_PANO_EQUIRECTANGULAR: + data.type = CAMERA_PANO_EQUIRECT; + case CAM_PANO_FISHEYE_EQUIDISTANT: + data.type = CAMERA_PANO_EQUIDISTANT; + case CAM_PANO_FISHEYE_EQUISOLID: + data.type = CAMERA_PANO_EQUISOLID; + case CAM_PANO_MIRRORBALL: + data.type = CAMERA_PANO_MIRROR; + } + } +#endif + } + } + else if (inst_.drw_view) { + data.type = DRW_view_is_persp_get(inst_.drw_view) ? CAMERA_PERSP : CAMERA_ORTHO; + } + else { + /* Lightprobe baking. */ + data.type = CAMERA_PERSP; + } +} + +void Camera::sync() +{ + const Object *camera_eval = inst_.camera_eval_object; + CameraData &data = data_.current(); + + data.filter_size = inst_.scene->r.gauss; + + if (inst_.drw_view) { + DRW_view_viewmat_get(inst_.drw_view, data.viewmat.ptr(), false); + DRW_view_viewmat_get(inst_.drw_view, data.viewinv.ptr(), true); + DRW_view_winmat_get(inst_.drw_view, data.winmat.ptr(), false); + DRW_view_winmat_get(inst_.drw_view, data.wininv.ptr(), true); + DRW_view_persmat_get(inst_.drw_view, data.persmat.ptr(), false); + DRW_view_persmat_get(inst_.drw_view, data.persinv.ptr(), true); + DRW_view_camtexco_get(inst_.drw_view, data.uv_scale); + } + else if (inst_.render) { + /* TODO(fclem) Overscan */ + // RE_GetCameraWindowWithOverscan(inst_.render->re, g_data->overscan, data.winmat); + RE_GetCameraWindow(inst_.render->re, camera_eval, data.winmat.ptr()); + RE_GetCameraModelMatrix(inst_.render->re, camera_eval, data.viewinv.ptr()); + invert_m4_m4(data.viewmat.ptr(), data.viewinv.ptr()); + invert_m4_m4(data.wininv.ptr(), data.winmat.ptr()); + mul_m4_m4m4(data.persmat.ptr(), data.winmat.ptr(), data.viewmat.ptr()); + invert_m4_m4(data.persinv.ptr(), data.persmat.ptr()); + data.uv_scale = float2(1.0f); + data.uv_bias = float2(0.0f); + } + else { + data.viewmat = float4x4::identity(); + data.viewinv = float4x4::identity(); + perspective_m4(data.winmat.ptr(), -0.1f, 0.1f, -0.1f, 0.1f, 0.1f, 1.0f); + data.wininv = data.winmat.inverted(); + data.persmat = data.winmat * data.viewmat; + data.persinv = data.persmat.inverted(); + } + + if (camera_eval) { + const ::Camera *cam = reinterpret_cast<const ::Camera *>(camera_eval->data); + data.clip_near = cam->clip_start; + data.clip_far = cam->clip_end; +#if 0 /* TODO(fclem): Make fisheye properties inside blender. */ + data.fisheye_fov = cam->fisheye_fov; + data.fisheye_lens = cam->fisheye_lens; + data.equirect_bias.x = -cam->longitude_min + M_PI_2; + data.equirect_bias.y = -cam->latitude_min + M_PI_2; + data.equirect_scale.x = cam->longitude_min - cam->longitude_max; + data.equirect_scale.y = cam->latitude_min - cam->latitude_max; + /* Combine with uv_scale/bias to avoid doing extra computation. */ + data.equirect_bias += data.uv_bias * data.equirect_scale; + data.equirect_scale *= data.uv_scale; + + data.equirect_scale_inv = 1.0f / data.equirect_scale; +#endif + } + else if (inst_.drw_view) { + data.clip_near = DRW_view_near_distance_get(inst_.drw_view); + data.clip_far = DRW_view_far_distance_get(inst_.drw_view); + data.fisheye_fov = data.fisheye_lens = -1.0f; + data.equirect_bias = float2(0.0f); + data.equirect_scale = float2(0.0f); + } + + data_.current().push_update(); + + synced_ = true; + + /* Detect changes in parameters. */ + if (data_.current() != data_.previous()) { + // inst_.sampling.reset(); + } +} + +/** \} */ + +} // namespace blender::eevee diff --git a/source/blender/draw/engines/eevee_next/eevee_camera.hh b/source/blender/draw/engines/eevee_next/eevee_camera.hh index 3db343703e0..dfec738b1f3 100644 --- a/source/blender/draw/engines/eevee_next/eevee_camera.hh +++ b/source/blender/draw/engines/eevee_next/eevee_camera.hh @@ -1,11 +1,14 @@ /* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2021 Blender Foundation. - */ + * Copyright 2021 Blender Foundation. */ + +#pragma once /** \file * \ingroup eevee */ +#include "eevee_shader_shared.hh" + namespace blender::eevee { class Instance; @@ -43,4 +46,85 @@ static const float cubeface_mat[6][4][4] = { {0.0f, 0.0f, 0.0f, 1.0f}}, }; +inline void cubeface_winmat_get(float4x4 &winmat, float near, float far) +{ + /* Simple 90° FOV projection. */ + perspective_m4(winmat.ptr(), -near, near, -near, near, near, far); +} + +/* -------------------------------------------------------------------- */ +/** \name CameraData operators + * \{ */ + +inline bool operator==(const CameraData &a, const CameraData &b) +{ + return compare_m4m4(a.persmat.ptr(), b.persmat.ptr(), FLT_MIN) && (a.uv_scale == b.uv_scale) && + (a.uv_bias == b.uv_bias) && (a.equirect_scale == b.equirect_scale) && + (a.equirect_bias == b.equirect_bias) && (a.fisheye_fov == b.fisheye_fov) && + (a.fisheye_lens == b.fisheye_lens) && (a.filter_size == b.filter_size) && + (a.type == b.type); +} + +inline bool operator!=(const CameraData &a, const CameraData &b) +{ + return !(a == b); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Camera + * \{ */ + +/** + * Point of view in the scene. Can be init from viewport or camera object. + */ +class Camera { + private: + Instance &inst_; + + /** Double buffered to detect changes and have history for re-projection. */ + SwapChain<CameraDataBuf, 2> data_; + /** Detects wrong usage. */ + bool synced_ = false; + + public: + Camera(Instance &inst) : inst_(inst){}; + ~Camera(){}; + + void init(); + void sync(); + + /** + * Getters + **/ + const CameraData &data_get() const + { + BLI_assert(synced_); + return data_.current(); + } + const GPUUniformBuf *ubo_get() const + { + return data_.current(); + } + bool is_panoramic() const + { + return eevee::is_panoramic(data_.current().type); + } + bool is_orthographic() const + { + return data_.current().type == CAMERA_ORTHO; + } + const float3 &position() const + { + return *reinterpret_cast<const float3 *>(data_.current().viewinv[3]); + } + const float3 &forward() const + { + return *reinterpret_cast<const float3 *>(data_.current().viewinv[2]); + } +}; + +/** \} */ + } // namespace blender::eevee diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.cc b/source/blender/draw/engines/eevee_next/eevee_instance.cc index 8fef1cf7fc5..f79b692018f 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.cc +++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc @@ -41,9 +41,10 @@ void Instance::init(const int2 &output_res, const View3D *v3d_, const RegionView3D *rv3d_) { - UNUSED_VARS(light_probe_, camera_object_, output_rect); + UNUSED_VARS(light_probe_, output_rect); render = render_; depsgraph = depsgraph_; + camera_orig_object = camera_object_; render_layer = render_layer_; drw_view = drw_view_; v3d = v3d_; @@ -58,9 +59,9 @@ void Instance::update_eval_members() { scene = DEG_get_evaluated_scene(depsgraph); view_layer = DEG_get_evaluated_view_layer(depsgraph); - // camera_eval_object = (camera_orig_object) ? - // DEG_get_evaluated_object(depsgraph, camera_orig_object) : - // nullptr; + camera_eval_object = (camera_orig_object) ? + DEG_get_evaluated_object(depsgraph, camera_orig_object) : + nullptr; } /** \} */ diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.hh b/source/blender/draw/engines/eevee_next/eevee_instance.hh index c3cf08c8390..47fa005d3d0 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.hh +++ b/source/blender/draw/engines/eevee_next/eevee_instance.hh @@ -42,6 +42,8 @@ class Instance { /** Evaluated IDs. */ Scene *scene; ViewLayer *view_layer; + Object *camera_eval_object; + Object *camera_orig_object; /** Only available when rendering for final render. */ const RenderLayer *render_layer; RenderEngine *render; diff --git a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh index 45b067d203e..97fc9c5a547 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh @@ -19,6 +19,7 @@ namespace blender::eevee { using draw::Framebuffer; +using draw::SwapChain; using draw::Texture; using draw::TextureFromPool; @@ -27,6 +28,52 @@ using draw::TextureFromPool; #define UBO_MIN_MAX_SUPPORTED_SIZE 1 << 14 /* -------------------------------------------------------------------- */ +/** \name Camera + * \{ */ + +enum eCameraType : uint32_t { + CAMERA_PERSP = 0u, + CAMERA_ORTHO = 1u, + CAMERA_PANO_EQUIRECT = 2u, + CAMERA_PANO_EQUISOLID = 3u, + CAMERA_PANO_EQUIDISTANT = 4u, + CAMERA_PANO_MIRROR = 5u +}; + +static inline bool is_panoramic(eCameraType type) +{ + return type > CAMERA_ORTHO; +} + +struct CameraData { + /* View Matrices of the camera, not from any view! */ + float4x4 persmat; + float4x4 persinv; + float4x4 viewmat; + float4x4 viewinv; + float4x4 winmat; + float4x4 wininv; + /** Camera UV scale and bias. Also known as viewcamtexcofac. */ + float2 uv_scale; + float2 uv_bias; + /** Panorama parameters. */ + float2 equirect_scale; + float2 equirect_scale_inv; + float2 equirect_bias; + float fisheye_fov; + float fisheye_lens; + /** Clipping distances. */ + float clip_near; + float clip_far; + /** Film pixel filter radius. */ + float filter_size; + eCameraType type; +}; +BLI_STATIC_ASSERT_ALIGN(CameraData, 16) + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Ray-Tracing * \{ */ @@ -83,5 +130,7 @@ float4 utility_tx_sample(sampler2DArray util_tx, float2 uv, float layer) #ifdef __cplusplus +using CameraDataBuf = draw::UniformBuffer<CameraData>; + } // namespace blender::eevee #endif diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_camera_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_camera_lib.glsl new file mode 100644 index 00000000000..f79e9102d76 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_camera_lib.glsl @@ -0,0 +1,166 @@ + +/** + * Camera projection / uv functions and utils. + **/ + +#pragma BLENDER_REQUIRE(common_math_lib.glsl) + +/* -------------------------------------------------------------------- */ +/** \name Panoramic Projections + * + * Adapted from Cycles to match EEVEE's coordinate system. + * \{ */ + +vec2 camera_equirectangular_from_direction(CameraData cam, vec3 dir) +{ + float phi = atan(-dir.z, dir.x); + float theta = acos(dir.y / length(dir)); + return (vec2(phi, theta) - cam.equirect_bias) * cam.equirect_scale_inv; +} + +vec3 camera_equirectangular_to_direction(CameraData cam, vec2 uv) +{ + uv = uv * cam.equirect_scale + cam.equirect_bias; + float phi = uv.x; + float theta = uv.y; + float sin_theta = sin(theta); + return vec3(sin_theta * cos(phi), cos(theta), -sin_theta * sin(phi)); +} + +vec2 camera_fisheye_from_direction(CameraData cam, vec3 dir) +{ + float r = atan(length(dir.xy), -dir.z) / cam.fisheye_fov; + float phi = atan(dir.y, dir.x); + vec2 uv = r * vec2(cos(phi), sin(phi)) + 0.5; + return (uv - cam.uv_bias) / cam.uv_scale; +} + +vec3 camera_fisheye_to_direction(CameraData cam, vec2 uv) +{ + uv = uv * cam.uv_scale + cam.uv_bias; + uv = (uv - 0.5) * 2.0; + float r = length(uv); + if (r > 1.0) { + return vec3(0.0); + } + float phi = safe_acos(uv.x * safe_rcp(r)); + float theta = r * cam.fisheye_fov * 0.5; + if (uv.y < 0.0) { + phi = -phi; + } + return vec3(cos(phi) * sin(theta), sin(phi) * sin(theta), -cos(theta)); +} + +vec2 camera_mirror_ball_from_direction(CameraData cam, vec3 dir) +{ + dir = normalize(dir); + dir.z -= 1.0; + dir *= safe_rcp(2.0 * safe_sqrt(-0.5 * dir.z)); + vec2 uv = 0.5 * dir.xy + 0.5; + return (uv - cam.uv_bias) / cam.uv_scale; +} + +vec3 camera_mirror_ball_to_direction(CameraData cam, vec2 uv) +{ + uv = uv * cam.uv_scale + cam.uv_bias; + vec3 dir; + dir.xy = uv * 2.0 - 1.0; + if (len_squared(dir.xy) > 1.0) { + return vec3(0.0); + } + dir.z = -safe_sqrt(1.0 - sqr(dir.x) - sqr(dir.y)); + const vec3 I = vec3(0.0, 0.0, 1.0); + return reflect(I, dir); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Regular projections + * \{ */ + +vec3 camera_view_from_uv(mat4 projmat, vec2 uv) +{ + return project_point(projmat, vec3(uv * 2.0 - 1.0, 0.0)); +} + +vec2 camera_uv_from_view(mat4 projmat, bool is_persp, vec3 vV) +{ + vec4 tmp = projmat * vec4(vV, 1.0); + if (is_persp && tmp.w <= 0.0) { + /* Return invalid coordinates for points behind the camera. + * This can happen with panoramic projections. */ + return vec2(-1.0); + } + return (tmp.xy / tmp.w) * 0.5 + 0.5; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name General functions handling all projections + * \{ */ + +vec3 camera_view_from_uv(CameraData cam, vec2 uv) +{ + vec3 vV; + switch (cam.type) { + default: + case CAMERA_ORTHO: + case CAMERA_PERSP: + return camera_view_from_uv(cam.wininv, uv); + case CAMERA_PANO_EQUIRECT: + vV = camera_equirectangular_to_direction(cam, uv); + break; + case CAMERA_PANO_EQUIDISTANT: + /* ATTR_FALLTHROUGH; */ + case CAMERA_PANO_EQUISOLID: + vV = camera_fisheye_to_direction(cam, uv); + break; + case CAMERA_PANO_MIRROR: + vV = camera_mirror_ball_to_direction(cam, uv); + break; + } + return vV; +} + +vec2 camera_uv_from_view(CameraData cam, vec3 vV) +{ + switch (cam.type) { + default: + case CAMERA_ORTHO: + return camera_uv_from_view(cam.winmat, false, vV); + case CAMERA_PERSP: + return camera_uv_from_view(cam.winmat, true, vV); + case CAMERA_PANO_EQUIRECT: + return camera_equirectangular_from_direction(cam, vV); + case CAMERA_PANO_EQUISOLID: + /* ATTR_FALLTHROUGH; */ + case CAMERA_PANO_EQUIDISTANT: + return camera_fisheye_from_direction(cam, vV); + case CAMERA_PANO_MIRROR: + return camera_mirror_ball_from_direction(cam, vV); + } +} + +vec2 camera_uv_from_world(CameraData cam, vec3 V) +{ + vec3 vV = transform_point(cam.viewmat, V); + switch (cam.type) { + default: + case CAMERA_ORTHO: + return camera_uv_from_view(cam.persmat, false, V); + case CAMERA_PERSP: + return camera_uv_from_view(cam.persmat, true, V); + case CAMERA_PANO_EQUIRECT: + return camera_equirectangular_from_direction(cam, vV); + case CAMERA_PANO_EQUISOLID: + /* ATTR_FALLTHROUGH; */ + case CAMERA_PANO_EQUIDISTANT: + return camera_fisheye_from_direction(cam, vV); + case CAMERA_PANO_MIRROR: + return camera_mirror_ball_from_direction(cam, vV); + } +} + +/** \} */ |