読者です 読者をやめる 読者になる 読者になる

空飛ぶ気まぐれ雑記帳

主に趣味とかプログラミングについて扱います。

OpenGLでズームを実装する方法

C++ OpenGL

OpenGLでズームを実装する方法について。
最初、カメラの中心と距離をいじってやろうと思ってたんだけど、どうも上手くいかなかったから、ちょっと調べたら出てきたました。
元のネタはここの8.040、How do I implement a zoom operation?
https://www.opengl.org/archives/resources/faq/technical/viewing.htm

最も手っ取り早い方法としてModelView行列の対角要素をN倍する方法があるけど、それはスケールが大きく/小さくなりすぎると、Projection行列のNearかFarの影響で描画したいものが正確に表示されないという問題がある。そこで、ModelView行列ではなく、Projection行列を弄ってやればハッピーじゃないかという話です。

例えば、glFrustum、ここではもう少しモダンOpenGLということでglm::frustumですが、それを使ってズームを実装すると以下のようになります。

glm::frustum(left / scale, right / scale,
    bottom / scale, top / scale,
    z_near, z_far);

ただ、これだけだと常に画面中心にしかズームができないので、さらにx,y座標のどこにズームするかを指定できるように以下のように変更してやります。

glm::frustum((left + center_x) / scale, (right + center_x) / scale,
    (bottom + center_y) / scale, (top + center_y) / scale,
    z_near, z_far);

ただ、このコード、正確に動くかは検証していません。
なにせ、私の場合near平面のサイズが既知の条件で扱っているので、以下のようになっているかです。

glm::frustum(
  -0.5f * (this->WindowWidth  + this->Center.x) / this->Scale,
   0.5f * (this->WindowWidth  - this->Center.x) / this->Scale,
  -0.5f * (this->WindowHeight + this->Center.y) / this->Scale,
   0.5f * (this->WindowHeight - this->Center.y) / this->Scale,
  z_near, z_far
);

微妙にthisとかチラチラしてますが基本的な考え方は同じです。