はじめに
OpenSiv3Dでは、BasicCamera3Dを使って、カメラの位置を変更することができます。
しかし、このカメラには致命的な欠点があります。
それは、カメラがどの位置からどっち向きに表示しているのか分からない! ということです。
これを解決するために、この記事ではOpenSiv3Dで視錐台をデバッグ表示します。
2025-06-26
OpenSiv3Dでは、BasicCamera3Dを使って、カメラの位置を変更することができます。
しかし、このカメラには致命的な欠点があります。
それは、カメラがどの位置からどっち向きに表示しているのか分からない! ということです。
これを解決するために、この記事ではOpenSiv3Dで視錐台をデバッグ表示します。
デバッグ表示の前に、視錐台について説明します。
視錐台とは「カメラの見える範囲」のことです。
Unityとかのゲームエンジンでカメラを配置すると、カメラの向きと範囲が線で描画されるあれのことです。
視錐台についての記事は、探せばたくさんあるので、ここでは深く説明しません。
もっと詳しく知りたい!という方は調べてみてください。
個人的にオススメの記事です。
数学的にも分かりやすく説明されています。
【Unity】【数学】視錐台(Frustum)について(第1回)とりあえずこの記事を見る上では、視錐台がどんな形なのか、ということが分かっていれば問題ありません。
視錐台を描画するコードです。
CalculateCorner関数が面の四隅を求め、それをもとにMainループの中で描画します。
# include <Siv3D.hpp>
Array<Vec3> CalculateCorner(const Vec3& center, const Vec3& right, const Vec3& up, double width, double height)
{
Vec3 halfRight = right * (width / 2);
Vec3 halfUp = up * (height / 2);
Vec3 topLeft = center + halfUp - halfRight;
Vec3 topRight = center + halfUp + halfRight;
Vec3 bottomLeft = center - halfUp - halfRight;
Vec3 bottomRight = center - halfUp + halfRight;
// 格納順は左上→右上→右下→左下にする(描画時にループで使いやすいから)
return Array<Vec3>{topLeft, topRight, bottomRight, bottomLeft};
}
void Main()
{
// BasicCamera3D を使って自由な視点操作を可能に
BasicCamera3D battleCamera{ { 0, 3, -10 }, 10.0 };
// 必要な情報
double fovDegree = 60.0; // 視野角
double nearClip = 0.2; // Near面までの距離
double farClip = 50.0; // Far面までの距離
while(System::Update())
{
// カメラの情報を取得
Vec3 eye = battleCamera.getEyePosition(); // カメラの位置
Vec3 focus = battleCamera.getFocusPosition(); // 注視点
Vec3 up = battleCamera.getUpDirection(); // 上方向
// カメラの軸を求める
Vec3 forward = (focus - eye).normalized(); // 前方向
Vec3 right = forward.cross(up).normalized(); // 右方向
Vec3 newUp = right.cross(forward).normalized(); // 上方向(計算でしっかり求めたバージョン)
// アスペクト比
Size sceneSize = Scene::Size();
double aspect = static_cast<double>(sceneSize.x) / static_cast<double>(sceneSize.y);
// Near・Far面の高さと幅を計算する
double nearHeight = 2.0 * Math::Tan(fovDegree / 2.0) * nearClip;
double nearWidth = nearHeight * aspect;
double farHeight = 2.0 * Math::Tan(fovDegree / 2.0) * farClip;
double farWidth = farHeight * aspect;
// Near・Far面の中心点を計算する
const Vec3 nearCenter = eye + forward * nearClip;
const Vec3 farCenter = eye + forward * farClip;
// Nar・Far面の角(四隅)を配列で格納する
Array<Vec3> nearCorners = CalculateCorner(nearCenter, right, newUp, nearWidth, nearHeight);
Array<Vec3> farCorners = CalculateCorner(farCenter, right, newUp, nearWidth, nearHeight);
// 視錐台を線で描画
for (int i = 0; i < 4; i++)
{
// Eye → NearCorner の線
Line3D{ eye, nearCorners[i] }.draw(Palette::Orange);
// NearCorner → FarCorner の線
Line3D{ nearCorners[i], farCorners[i] }.draw(Palette::Orange);
Line3D{ nearCorners[i], nearCorners[(i + 1) % 4] }.draw(Palette::Red);
Line3D{ farCorners[i], farCorners[(i + 1) % 4] }.draw(Palette::Cyan);
}
// カメラの位置に赤い球を描画
Sphere{ eye, 0.5 }.draw(ColorF{ 1.0, 0.0, 0.0, 0.5 });
// カメラの注視点に青い球を描画
Sphere{ focus, 0.3 }.draw(ColorF{ 0.0, 0.0, 1.0, 0.5 });
}
}
// Near・Far面の高さと幅を計算する
double nearHeight = 2.0 * Math::Tan(fovDegree / 2.0) * nearClip;
double nearWidth = nearHeight * aspect;
double farHeight = 2.0 * Math::Tan(fovDegree / 2.0) * farClip;
double farWidth = farHeight * aspect;
この式は、Near面・Far面の高さを求めています。
カメラの位置・Near面の中心・Near面の高さの半分を結ぶ3つの辺を使うと、三角形ができます。
これらの情報を元にtanθを求める公式を使って高さを割り出します。
少し難しい式なので、この説明で分からないという方はこちらの記事をご覧ください!
今回は、OpenSiv3DのBasicCamera3Dで視錐台をデバッグ表示する方法を紹介しました。
視錐台を可視化すると、「カメラがどこを向いていると、どこまで描画されるか」が明確に分かるようになります。
もしOpenSiv3Dのカメラ表示に困っている方がいたら、参考にしてみてください!