OpenSiv3D icon indicating copy to clipboard operation
OpenSiv3D copied to clipboard

DebugCamera3D がコンストラクタで指定した注視点と異なる位置を注視するバグ

Open Raclamusi opened this issue 6 months ago • 0 comments

DebugCamera3D がコンストラクタの引数 focusPosition で指定した注視点と異なる位置を注視します。

下のスクリーンショットは BasicCamera3DDebugCamera3D にそれぞれ赤い球を注目するようコンストラクタで指定したときの結果です。 BasicCamera3D の場合は赤い球が中心にあるのに対し、 DebugCamera3D の場合は赤い球が中心から外れています。

再現コード
# include <Siv3D.hpp>

void Main()
{
	Window::Resize(1280, 720);

	const ColorF backgroundColor = ColorF{ 0.4, 0.6, 0.8 }.removeSRGBCurve();
	const Texture uvChecker{ U"example/texture/uv.png", TextureDesc::MippedSRGB };
	const MSRenderTexture renderTexture{ Scene::Size(), TextureFormat::R8G8B8A8_Unorm_SRGB, HasDepth::Yes };

	// 同じパラメータを与えているが結果が異なる
	BasicCamera3D basicCamera{ renderTexture.size(), 30_deg, Vec3{ 10, 24, -32 }, Vec3{ 0, 2, 0 } };
	DebugCamera3D debugCamera{ renderTexture.size(), 30_deg, Vec3{ 10, 24, -32 }, Vec3{ 0, 2, 0 } };

	size_t index = 0;
	const Array<String> options{ U"BasicCamera3D", U"DebugCamera3D" };

	while (System::Update())
	{
		if (index == 0)
		{
			Graphics3D::SetCameraTransform(basicCamera);
		}
		else
		{
			debugCamera.update(2.0);
			Graphics3D::SetCameraTransform(debugCamera);
		}

		{
			const ScopedRenderTarget3D target{ renderTexture.clear(backgroundColor) };

			Plane{ 64 }.draw(uvChecker);

			Sphere{ 0, 2, 0, 2 }.draw(ColorF{ 1.0, 0.0, 0.0 }.removeSRGBCurve());
		}

		{
			Graphics3D::Flush();
			renderTexture.resolve();
			Shader::LinearToScreen(renderTexture);
		}

		{
			Line{ 630, 360, 650, 360 }.draw(2);
			Line{ 640, 350, 640, 370 }.draw(2);

			SimpleGUI::RadioButtons(index, options, Vec2{ 20, 20 });
		}
	}
}
BasicCamera3D の場合 DebugCamera3D の場合

原因の考察と解決策

原因は DebugCamera3D::m_focusY の初期化にあると考えられます。

https://github.com/Siv3D/OpenSiv3D/blob/9c77228c3f1642b1274f10be8a86379d37a0cfe1/Siv3D/include/Siv3D/DebugCamera3D.hpp#L35

DebugCamera3D の注視点は、カメラ位置を中心とする半径 1 の y 方向に無限に伸びる伸びる円筒上に正規化されます。 カメラ位置から注視点へのベクトルを正規化したベクトルを使って m_focusY を初期化していますが、このベクトルの y 成分が 0 でないとき、その指す位置は円筒上になく、その y 成分で m_focusY を初期化したとき本来指すべき位置より y 座標の絶対値が小さくなります。

つまり、カメラ位置から注視点へのベクトルを円筒上に来るように正規化し、 m_focusY を初期化することでこの問題は解決できます。 例えば、 m_focusY の初期化を次のように変更します。

double m_focusY = [this]
	{
		const auto focusVector = (BasicCamera3D::m_focusPosition - BasicCamera3D::m_eyePosition);
		return (focusVector.y / std::hypot(focusVector.x, focusVector.z));
	}();

Raclamusi avatar Aug 12 '24 17:08 Raclamusi