GUI改造5 camera path

「instantNeRFで遊ぶ Advent Calendar 2022」の19日目です。

今日はinstantNeRFのGUIのcamera pathを改造しました。

:::note
業務外の個人的な検討活動です。
:::

:::note alert
警告
環境や入力内容によっては現在使用できている状況が壊れることがあります。
あなたの責任と判断で試してください。私は責任を取りません。
:::

#### テストデータ
sketchfabのNefertiti statueを使用させていただきました。ありがとうございます。

https://sketchfab.com/3d-models/nefertiti-statue-d148f771c3f44225b56cb7ce8d3c5ce6

#### 改造前
再生位置と再生速度をスライダで調整するようになっています。
キーフレームの追加、分割、移動、複製、削除、設定をボタンで実行し、真ん中にあるREAD/STOPボタンを押すと画面にカメラの設定を反映させたり復帰させたりします。
個人的に使いにくかったのが再生と停止を再生速度を増やすかゼロにするか操作することでした。
![19-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/c973d30a-7ec9-55cc-291e-076ef6b135d9.png)

#### camera_path.cu
visual studioを使いcamera_path.cuの内容を変更しました。
再生ボタンを追加しました。
python用に準備されていたループ機能を操作できるようにしました。
```
	if (!m_keyframes.empty()) {
		if (ImGui::SliderFloat("camera path time", &m_playtime, 0.f, 1.f)) read=1;
		//ImGui::SliderFloat("auto play speed",&m_autoplayspeed, 0.f, 1.f);
		//if (m_autoplayspeed>0.f && m_playtime<1.f) {
		//	m_playtime+=m_autoplayspeed*(frame_milliseconds/1000.f);
		//	if (m_playtime>1.f) m_playtime=1.f;
		//	read=1;
		//}
	}

	if (!m_keyframes.empty()) {
		int i = (int)round(m_playtime * (float)n);
		//ImGui::Text("Current keyframe %d/%d:", i, n + 1);
		ImGui::Text("Current keyframe %d/%d:", i, n);
	}

	if (ImGui::Button("Add from cam")) {
		int i=(int)ceil(m_playtime*(float)n+0.001f);
		if (i>m_keyframes.size()) i=m_keyframes.size();
		if (i<0) i=0;
		m_keyframes.insert(m_keyframes.begin()+i, CameraKeyframe(camera, slice_plane_z, scale, fov, aperture_size, glow_mode, glow_y_cutoff));
		m_update_cam_from_path = false;
		int n=std::max(0,int(m_keyframes.size())-1);
		m_playtime = n ? float(i)/float(n) : 1.f;
		read = 2;
	}

	if (!m_keyframes.empty()) {
		ImGui::SameLine();
		if (ImGui::Button("split")) {
			m_update_cam_from_path = false;
			int i = (int)ceil(m_playtime * (float)n + 0.001f);
			if (i > m_keyframes.size()) i = (int)m_keyframes.size();
			if (i < 0) i = 0;
			m_keyframes.insert(m_keyframes.begin() + i, eval_camera_path(m_playtime));
			m_playtime = float(i) / float(n + 1);
			read = 2;
			m_autoplayspeed = 0;
		}
		ImGui::SameLine();
		int i = (int)round(m_playtime * (float)n);
		if (ImGui::Button("|<")) {
			m_playtime = 0.f;
			read = 2;
			m_autoplayspeed = 0;
		}	ImGui::SameLine();
		if (ImGui::Button("<")) {
			m_playtime = n ? std::max(0.f, floorf((m_playtime - 0.0001f) * (float)n) / (float)n) : 0.f;
			read = 2;
			m_autoplayspeed = 0;
		}	ImGui::SameLine();
		//if (ImGui::Button(m_update_cam_from_path ? "STOP" : "APPLY")) { m_update_cam_from_path = !m_update_cam_from_path; read = 2; }				ImGui::SameLine();
		if (ImGui::Button(">")) {
			m_playtime = n ? std::min(1.f, ceilf((m_playtime + 0.0001f) * (float)n) / (float)n) : 1.f;
			read = 2;
			m_autoplayspeed = 0;
		}	ImGui::SameLine();
		if (ImGui::Button(">|")) {
			m_playtime = 1.f;
			read = 2;
			m_autoplayspeed = 0;
		}	ImGui::SameLine();
		if (ImGui::Button("Dup")) {
			m_update_cam_from_path = false; m_keyframes.insert(m_keyframes.begin() + i, m_keyframes[i]); m_playtime = i / float(n + 1);
			read = 2;
			m_autoplayspeed = 0;
		}	ImGui::SameLine();
		if (ImGui::Button("Del")) {
			m_update_cam_from_path = false;
			m_keyframes.erase(m_keyframes.begin() + i);
			read = 2;
			m_autoplayspeed = 0;
		}	ImGui::SameLine();
		if (ImGui::Button("Set")) {
			m_keyframes[i] = CameraKeyframe(camera, slice_plane_z, scale, fov, aperture_size, glow_mode, glow_y_cutoff);
			read = 2;
			if (n) m_playtime = i / float(n);
			m_autoplayspeed = 0;
		}	ImGui::SameLine();

		if (ImGui::Button(m_update_cam_from_path ? "Back to Edit" : "Apply Main")) {
			m_update_cam_from_path = !m_update_cam_from_path;
			read = 2;
			m_autoplayspeed = 0;
		}
	}

	if (!m_keyframes.empty()) {
		if (ImGui::Button("[]"))	{
			m_autoplayspeed = 0.0f;
		}	ImGui::SameLine();
		if (ImGui::Button("[>"))		{
			m_autoplayspeed = 0.05f;
		}	ImGui::SameLine();
		if (ImGui::Button("[>[>"))	{
			m_autoplayspeed = 0.10f;
		}	ImGui::SameLine();
		if (ImGui::Button("[>[>[>"))	{
			m_autoplayspeed = 0.20f;
		}	ImGui::SameLine();
		//ImGui::SliderFloat("auto play speed", &m_autoplayspeed, 0.f, 1.f);
		//if (m_autoplayspeed > 0.f && m_playtime < 1.f) {
		//	m_playtime += m_autoplayspeed * (frame_milliseconds / 1000.f);
		//	if (m_playtime > 1.f) m_playtime = 1.f;
		//	read = 1;
		//}
		ImGui::Checkbox("loop", &m_loop);
		if (m_autoplayspeed > 0.f && m_playtime < 1.f) {
			m_playtime += m_autoplayspeed * (frame_milliseconds / 1000.f);
			if (m_playtime > 1.f) {
				if (m_loop) {
					m_playtime = 0.f;
				}
				else {
					m_playtime = 1.f;
				}
			}
			read = 1;
		}
	}
```

#### 改造後
変更後のGUIはこのようになりました。
![19-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/29fa304c-b1e3-9a76-fccb-b3d2adcccfa7.png)

使用時の様子はこちらです。
別の改造も進めていたので画面の様子が少し異なります。

<iframe width="560" height="315" src="https://www.youtube.com/embed/BdpLZaGSFx0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

#### ToDo
- 再生単位をフレームに変更する
- 静止画連番でスクリーンショットを保存する