File size: 5,150 Bytes
7873319
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/*
 * Copyright (c) 2020-2022, NVIDIA CORPORATION.  All rights reserved.
 *
 * NVIDIA CORPORATION and its licensors retain all intellectual property
 * and proprietary rights in and to this software, related documentation
 * and any modifications thereto.  Any use, reproduction, disclosure or
 * distribution of this software and related documentation without an express
 * license agreement from NVIDIA CORPORATION is strictly prohibited.
 */

/** @file   camera_path.h
 *  @author Thomas Müller & Alex Evans, NVIDIA
 */

#pragma once

#include <neural-graphics-primitives/common.h>

#include <tiny-cuda-nn/common.h>

#include <imgui/imgui.h>
#include <imguizmo/ImGuizmo.h>

#include <vector>

struct ImDrawList;

NGP_NAMESPACE_BEGIN

struct CameraKeyframe {
	Eigen::Vector4f R;
	Eigen::Vector3f T;
	float slice;
	float scale; // not a scale factor as in scaling the world, but the value of m_scale (setting the focal plane along with slice)
	float fov;
	float aperture_size;
	int glow_mode;
	float glow_y_cutoff;
	Eigen::Matrix<float, 3, 4> m() const {
		Eigen::Matrix<float, 3, 4> rv;
		rv.col(3) = T;
		rv.block<3,3>(0,0) = Eigen::Quaternionf(R).normalized().toRotationMatrix();
		return rv;
	}

	void from_m(const Eigen::Matrix<float, 3, 4>& rv) {
		T = rv.col(3);
		// auto q = Eigen::Quaternionf(rv.block<3,3>(0,0));
		auto q = Eigen::Quaternionf(rv.block<3,3>(0,0));
		R = Eigen::Vector4f(q.x(), q.y(), q.z(), q.w());
	}

	CameraKeyframe() = default;
	CameraKeyframe(const Eigen::Vector4f &r, const Eigen::Vector3f &t, float sl, float sc, float fv, float df, int gm, float gyc) : R(r), T(t), slice(sl), scale(sc), fov(fv), aperture_size(df), glow_mode(gm), glow_y_cutoff(gyc) {}
	CameraKeyframe(Eigen::Matrix<float, 3, 4> m, float sl, float sc, float fv, float df, int gm, float gyc) : slice(sl), scale(sc), fov(fv), aperture_size(df), glow_mode(gm), glow_y_cutoff(gyc) { T=m.col(3); R=Eigen::Quaternionf(m.block<3,3>(0,0)).coeffs();  }
	CameraKeyframe operator*(float f) const { return {R*f, T*f, slice*f, scale*f, fov*f, aperture_size*f, glow_mode, glow_y_cutoff*f}; }
	CameraKeyframe operator+(const CameraKeyframe &rhs) const {
		Eigen::Vector4f Rr=rhs.R;
		if (Rr.dot(R)<0.f) Rr=-Rr;
		return {R+Rr, T+rhs.T, slice+rhs.slice, scale+rhs.scale, fov+rhs.fov, aperture_size+rhs.aperture_size, glow_mode, glow_y_cutoff+rhs.glow_y_cutoff};
	}
	bool SamePosAs(const CameraKeyframe &rhs) const {
		return (T-rhs.T).norm()<0.0001f && fabsf(R.dot(rhs.R))>=0.999f;
	}
};

CameraKeyframe lerp(const CameraKeyframe& p0, const CameraKeyframe& p1, float t, float t0, float t1);
CameraKeyframe spline(float t, const CameraKeyframe& p0, const CameraKeyframe& p1, const CameraKeyframe& p2, const CameraKeyframe& p3);

struct CameraPath {
	std::vector<CameraKeyframe> m_keyframes;
	bool m_update_cam_from_path = false;
	float m_playtime = 0.f;
	float m_autoplayspeed = 0.f;
	// If m_loop is set true, the last frame set will be more like "next to last,"
	// with animation then returning back to the first frame, making a continuous loop.
	// Note that the user does not have to (and should not normally) duplicate the first frame to be the last frame.
	bool m_loop = false;

	const CameraKeyframe& get_keyframe(int i) {
		if (m_loop) {
			int size = (int)m_keyframes.size();
			// add size to ensure no negative value is generated by modulo
			return m_keyframes[(i + size) % size];
		} else {
			return m_keyframes[tcnn::clamp(i, 0, (int)m_keyframes.size()-1)];
		}
	}
	CameraKeyframe eval_camera_path(float t) {
		if (m_keyframes.empty())
			return {};
		// make room for last frame == first frame when looping
		t *= (float)(m_loop ? m_keyframes.size() : m_keyframes.size()-1);
		int t1 = (int)floorf(t);
		return spline(t-floorf(t), get_keyframe(t1-1), get_keyframe(t1), get_keyframe(t1+1), get_keyframe(t1+2));
	}

	void save(const std::string& filepath_string);
	void load(const std::string& filepath_string, const Eigen::Matrix<float, 3, 4> &first_xform);

#ifdef NGP_GUI
	ImGuizmo::MODE m_gizmo_mode = ImGuizmo::LOCAL;
	ImGuizmo::OPERATION m_gizmo_op = ImGuizmo::TRANSLATE;
	int imgui(char path_filename_buf[128], float frame_milliseconds, Eigen::Matrix<float, 3, 4>& camera, float slice_plane_z, float scale, float fov, float aperture_size, float bounding_radius, const Eigen::Matrix<float, 3, 4>& first_xform, int glow_mode, float glow_y_cutoff);
	bool imgui_viz(ImDrawList* list, Eigen::Matrix<float, 4, 4>& view2proj, Eigen::Matrix<float, 4, 4>& world2proj, Eigen::Matrix<float, 4, 4>& world2view, Eigen::Vector2f focal, float aspect);
#endif
};

#ifdef NGP_GUI
void add_debug_line(ImDrawList* list, const Eigen::Matrix<float, 4, 4>&proj, Eigen::Vector3f a, Eigen::Vector3f b, uint32_t col = 0xffffffff, float thickness = 1.0f);
void visualize_unit_cube(ImDrawList* list, const Eigen::Matrix<float, 4, 4>& world2proj, const Eigen::Vector3f& a, const Eigen::Vector3f& b, const Eigen::Matrix3f& render_aabb_to_local);
void visualize_nerf_camera(ImDrawList* list, const Eigen::Matrix<float, 4, 4>& world2proj, const Eigen::Matrix<float, 3, 4>& xform, float aspect, uint32_t col = 0x80ffffff, float thickness = 1.0f);
#endif

NGP_NAMESPACE_END