LearnOpenGL

Translation in progress of learnopengl.com.
git clone https://git.mtkn.jp/LearnOpenGL
Log | Files | Refs

Camera.html (58652B)


      1     <h1 id="content-title">Camera</h1>
      2     <h1 id="content-title">カメラ</h1>
      3 <h1 id="content-url" style='display:none;'>Getting-started/Camera</h1>
      4 <p>
      5   In the previous chapter we discussed the view matrix and how we can use the view matrix to move around the scene (we moved backwards a little). OpenGL by itself is not familiar with the concept of a <em>camera</em>, but we can try to simulate one by moving all objects in the scene in the reverse direction, giving the illusion that <strong>we</strong> are moving.
      6   前章において視野行列を用いて空間上を移動する方法を学びました(少しだけ後ろに下りました)。OpenGL自体にカメラの概念はありませんが、空間中の全ての物体を反対方向に動かすことでカメラを再現でき、<strong>自分自身</strong>が動いているように見せかけることができます。
      7 </p>
      8 
      9 <p>
     10   In this chapter we'll discuss how we can set up a camera in OpenGL. We will discuss a fly style camera that allows you to freely move around in a 3D scene. We'll also discuss keyboard and mouse input and finish with a custom camera class.
     11   本章ではどのようにしてカメラを設定するかを見て行きます。ここでは3次元空間上を自由に動き回れるような飛行型のカメラについて議論します。キーボードやマウスからの入力についても議論し、最後に独自のカメラクラスを作成します。
     12 </p>
     13 
     14 <h2>Camera/View space</h2>
     15 <h2>カメラ空間(視野空間)</h2>
     16 <p>
     17   When we're talking about camera/view space we're talking about all the vertex coordinates as seen from the camera's perspective as the origin of the scene: the view matrix transforms all the world coordinates into view coordinates that are relative to the camera's position and direction. To define a camera we need its position in world space, the direction it's looking at, a vector pointing to the right and a vector pointing upwards from the camera. A careful reader may notice that we're actually going to create a coordinate system with 3 perpendicular unit axes with the camera's position as the origin.
     18   カメラ空間あるいは視野空間というのは全ての頂点の座標がカメラの位置を原点とし、カメラから見ているような空間です。視野行列が世界全体の座標を視野座標に変換します。この視野座標がカメラの位置と向いている方向に対する座標です。カメラを定義する為には大域空間におけるカメラの位置、向いている方向、カメラの右側を指すベクトル、そしてカメラの上側を指すベクトルが必要です。注意深い読者は、3つの互いに直交する単位ベクトルを用いてカメラの位置を原点とした座標空間を作成しようとしていることに気付くでしょう。
     19 </p>
     20 
     21 <img src="/img/getting-started/camera_axes.png" class="clean"/>
     22 
     23 <h3>1. Camera position</h3>
     24 <h3>1. カメラの位置</h3>
     25 <p>
     26   Getting the camera position is easy. The camera position is a vector in world space that points to the camera's position. We set the camera at the same position we've set the camera in the previous chapter:
     27   カメラの位置を取得するのは簡単です。カメラの位置は大域空間におけるカメラの位置を表わすベクトルです。今回カメラの位置は前章で設定したものと同じにしましょう:
     28 </p>
     29 
     30 <pre><code>
     31 glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);  
     32 </code></pre>
     33 
     34 <note>
     35   Don't forget that the positive z-axis is going through your screen towards you so if we want the camera to move backwards, we move along the positive z-axis.
     36   z軸は画面の手前に伸びているので、カメラを手前に動かす場合、z軸正の方向を指定します。
     37 </note>
     38 
     39 <h3>2. Camera direction</h3>
     40 <h2>2. カメラの方向</h2>
     41 <p>
     42   The next vector required is the camera's direction e.g. at what direction it is pointing at. For now we let the camera point to the origin of our scene: <code>(0,0,0)</code>. Remember that if we subtract two vectors from each other we get a vector that's the difference of these two vectors? Subtracting the camera position vector from the scene's origin vector thus results in the direction vector we want. For the view matrix's coordinate system we want its z-axis to be positive and because by convention (in OpenGL) the camera points towards the negative z-axis we want to negate the direction vector. If we switch the subtraction order around we now get a vector pointing towards the camera's positive z-axis:
     43   次に必要なのはカメラの向き、つまりカメラがどの点を見ているかです。とりあえずカメラが原点<code>(0, 0, 0)</code>を見ているとしましょう。ベクトルの引き算により、それらのベクトルの差が得られるのを覚えているでしょうか。カメラの位置を世界の原点から引き算すれば、カメラの向きを表わすベクトルが得られます。視野行列の座標系においてカメラの位置のz座標は正で、OpenGLの慣例によりカメラはz軸の負の方を向いているので、方向ベクトルの正負を反転させます。引き算の順序を反対にした場合、原点からカメラを向いた、z座標が正のベクトルが得られます:
     44 </p>
     45 
     46 <pre><code>
     47 glm::vec3 cameraTarget = glm::vec3(0.0f, 0.0f, 0.0f);
     48 glm::vec3 cameraDirection = glm::normalize(cameraPos - cameraTarget);
     49 </code></pre>
     50 
     51 <warning>
     52   The name <em>direction</em> vector is not the best chosen name, since it is actually pointing in the reverse direction of what it is targeting.
     53   <em>direction(方向)</em>というのは最良の名前とは言えません。このベクトルは実際にはカメラの向いているのと逆方向のベクトルだからです。
     54 </warning>
     55 
     56 <h3>3. Right axis</h3>
     57 <h3>3. 右方向の軸</h3>
     58 <p>
     59   The next vector that we need is a <em>right</em> vector that represents the positive x-axis of the camera space. To get the <em>right</em> vector we use a little trick by first specifying an <em>up</em> vector that points upwards (in world space). Then we do a cross product on the up vector and the direction vector from step 2. Since the result of a cross product is a vector perpendicular to both vectors, we will get a vector that points in the positive x-axis's direction (if we would switch the cross product order we'd get a vector that points in the negative x-axis): 
     60   次に必要なベクトルは<em>右方向</em>のベクトルです。このベクトルはカメラ空間のx軸正の方向を表わすものです。<em>右方向</em>のベクトルを得る為に少し技巧的なことをします。まず大域空間において<em>上向き</em>のベクトルを取り、このベクトルと、2段階目に作成した方向ベクトルの外積を取ります。外積の結果得られるベクトルは両方のベクトルに直交するので、この計算によりx軸正の方向を向いたベクトルが得られるのです(外積の掛ける順番を逆にするとベクトルはx軸負の方向を向きます)。
     61 </p>
     62 
     63 <pre><code>
     64 glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f); 
     65 glm::vec3 cameraRight = glm::normalize(<function id='61'>glm::cross</function>(up, cameraDirection));
     66 </code></pre>
     67 
     68 <h3>4. Up axis</h3>
     69 <h3>4. 上方向の軸</h3>
     70 <p>
     71   Now that we have both the x-axis vector and the z-axis vector, retrieving the vector that points to the camera's positive y-axis is relatively easy: we take the cross product of the right and direction vector:
     72   ここまででx軸とz軸のベクトルが得られたので、カメラの座標系におけるy軸正の方向のベクトルを計算するのは簡単です。右方向のベクトルとカメラの向いている方向のベクトルの外積を取ればいいのです:
     73 </p>
     74 
     75 <pre><code>
     76 glm::vec3 cameraUp = <function id='61'>glm::cross</function>(cameraDirection, cameraRight);
     77 </code></pre>
     78 
     79 <p>
     80 	With the help of the cross product and a few tricks we were able to create all the vectors that form the view/camera space. For the more mathematically inclined readers, this process is known as the <a href="http://en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process" target="_blank">Gram-Schmidt</a> process in linear algebra. Using these camera vectors we can now create a <def>LookAt</def> matrix that proves very useful for creating a camera.
     81 	外積により視野空間を形成するベクトルを全て取得できました。この手法は<a href="http://en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process" target="_blank">グラム・シュミットの正規直交化法</a>と言います。数学に傾倒した人はご自身で調べてみて下さい。これらのカメラに関するベクトルを利用することで、<def>視点行列(LookAt Matrix)</def>を作成できます。この行列はカメラを作成する上で非常に便利なものです。
     82 </p>
     83 
     84 <h2>Look At</h2>
     85 <h2>視点</h2>
     86 <p>
     87   A great thing about matrices is that if you define a coordinate space using 3 perpendicular (or non-linear) axes you can create a matrix with those 3 axes plus a translation vector and you can  transform any vector to that coordinate space by multiplying it with this matrix. This is exactly what the <em>LookAt</em> matrix does and now that we have 3 perpendicular axes and a position vector to define the camera space we can create our own LookAt matrix:
     88   互いに直交する(あるいは一次独立な)3つのベクトルにより座標空間を定義し、その3つの座標軸と平行移動ベクトルを用いると、任意のベクトルにその変換行列を掛けることで、その座標空間に変換できます。これはまさに<em>視点</em>行列が行なうことです。先程カメラ空間を定義する為に3つの直交するベクトルとカメラの位置ベクトルを作成しました。これらを用いて以下のように視点行列を作成できます:
     89   
     90   \[LookAt = \begin{bmatrix} \color{red}{R_x} & \color{red}{R_y} & \color{red}{R_z} & 0 \\ \color{green}{U_x} & \color{green}{U_y} & \color{green}{U_z} & 0 \\ \color{blue}{D_x} & \color{blue}{D_y} & \color{blue}{D_z} & 0 \\ 0 & 0 & 0  & 1 \end{bmatrix} * \begin{bmatrix} 1 & 0 & 0 & -\color{purple}{P_x} \\ 0 & 1 & 0 & -\color{purple}{P_y} \\ 0 & 0 & 1 & -\color{purple}{P_z} \\ 0 & 0 & 0  & 1 \end{bmatrix} \]
     91   
     92   Where \({\color{red}R}\) is the right vector, \({\color{green}U}\) is the up vector, \({\color{blue}D}\) is the direction vector and \({\color{purple}P}\) is the camera's position vector. Note that the rotation (left matrix) and translation (right matrix) parts are inverted (transposed and negated respectively) since we want to rotate and translate the world in the opposite direction of where we want the camera to move. Using this LookAt matrix as our view matrix effectively transforms all the world coordinates to the view space we just defined. The LookAt matrix then does exactly what it says: it creates a view matrix that <em>looks</em> at a given target.
     93   ここで、\({\color{red}R}\)はカメラの右方向のベクトル、\({\color{green}U}\)は上方向のベクトル、\({\color{blue}D}\)はカメラの方向ベクトル、そして\({\color{purple}P}\)はカメラの位置ベクトルです。左側の行列の回転と、右側の行列の平行移動がそれぞれ逆向きになっていることに注意して下さい。転置行列による回転と、符号が反転した平行移動にそれぞれなっています。カメラを移動させるのと反対方向に世界全体を回転、平行移動する為です。この視点行列を視野行列として用いることで、大域座標全体を今しがた定義した視野空間に変換できます。視点行列は与えられた位置を<em>見る</em>ような視野行列を作成します。視点行列は名前の通りの仕事をするのです。
     94 </p>
     95 
     96 <p>
     97   Luckily for us, GLM already does all this work for us. We only have to specify a camera position, a target position and a vector that represents the up vector in world space (the up vector we used for calculating the right vector). GLM then creates the LookAt matrix that we can use as our view matrix:
     98   有り難いことにGLMが必要な仕事を全て行ってくれます。カメラの位置、視点の位置そして大域空間の上を示すベクトル(カメラの右を示すベクトルを作成するのに必要です)を指定するだけでいいのです。そうすると視野行列の作成に必要な視点行列をGLMが作成してくれます:
     99 </p>
    100 
    101 <pre><code>
    102 glm::mat4 view;
    103 view = <function id='62'>glm::lookAt</function>(glm::vec3(0.0f, 0.0f, 3.0f), 
    104   		   glm::vec3(0.0f, 0.0f, 0.0f), 
    105   		   glm::vec3(0.0f, 1.0f, 0.0f));
    106 </code></pre>
    107 
    108 <p>
    109   The <fun><function id='62'>glm::LookAt</function></fun> function requires a position, target and up vector respectively. This example creates a view matrix that is the same as the one we created in the previous chapter.
    110 <fun><function id='62'>glm::LookAt</function></fun>には位置、視点、上のベクトルを渡します。この例では前章で作成したものと同じ視野行列を作成しています。
    111 </p>
    112 
    113 <p>
    114   Before delving into user input, let's get a little funky first by rotating the camera around our scene. We keep the target of the scene at <code>(0,0,0)</code>. We use a little bit of trigonometry to create an <code>x</code> and <code>z</code> coordinate each frame that represents a point on a circle and we'll use these for our camera position. By re-calculating the <code>x</code> and <code>y</code> coordinate over time we're traversing all the points in a circle and thus the camera rotates around the scene. We enlarge this circle by a pre-defined <var>radius</var> and create a new view matrix each frame using GLFW's <fun><function id='47'>glfwGetTime</function></fun> function:
    115   ユーザーからの入力に話を進める前に、少しイケたことをしてみましょう。カメラの視点を<code>(0, 0, 0)</code>に固定して、その周りで回転させてみます。三角関数を利用して各フレームに対してxz平面における円周上の点を求め、それをカメラの位置として利用します。<code>x</code>座標と<code>z</code>座標をフレーム毎に計算しなおすことで円周上をカメラが移動して行き、回転しているように見えます。あらかじめ定義しておいた<var>radius</var>という変数を用いてこの円周を大きくし、<fun><function id='47'>glfwGetTime</function></fun>を用いてフレーム毎に新しい視野行列を作成します:
    116 </p>
    117 
    118 <pre><code>
    119 const float radius = 10.0f;
    120 float camX = sin(<function id='47'>glfwGetTime</function>()) * radius;
    121 float camZ = cos(<function id='47'>glfwGetTime</function>()) * radius;
    122 glm::mat4 view;
    123 view = <function id='62'>glm::lookAt</function>(glm::vec3(camX, 0.0, camZ), glm::vec3(0.0, 0.0, 0.0), glm::vec3(0.0, 1.0, 0.0));  
    124 </code></pre>
    125 
    126 <p>
    127   If you run this code you should get something like this:
    128   このコードを実行すると以下のようなものが得られます:
    129 </p>
    130 
    131 <div class="video paused" onclick="ClickVideo(this)">
    132   <video width="600" height="450" loop>
    133     <source src="/video/getting-started/camera_circle.mp4" type="video/mp4"/>
    134     <img src="/img/getting-started/camera_circle.png" class="clean"/>
    135   </video>
    136 </div>
    137 
    138 <p>
    139   With this little snippet of code the camera now circles around the scene over time. Feel free to experiment with the radius and position/direction parameters to get the feel of how this <em>LookAt</em> matrix works. Also, check the  <a href="/code_viewer_gh.php?code=src/1.getting_started/7.1.camera_circle/camera_circle.cpp" target="_blank">source code</a> if you're stuck.
    140   このちょっとしたコードで、時間と共にカメラを回転させることができました。半径や位置、方向等の変数を変化させてみて下さい。<em>視点行列</em>の働きが掴めるはずです。また、どこかで詰まった場合は<a href="/code_viewer_gh.php?code=src/1.getting_started/7.1.camera_circle/camera_circle.cpp" target="_blank">ソースコード</a>を確認して下さい。
    141 </p>
    142 
    143 <h1>Walk around</h1>
    144 <h1>歩き回る</h1>
    145 <p>
    146   Swinging the camera around a scene is fun, but it's more fun to do all the movement ourselves! First we need to set up a camera system, so it is useful to define some camera variables at the top of our program:
    147   カメラが動くのは楽しいものですが、それを自分自身で行なえたらもっと楽しいでしょう。まずカメラの座標系を設定しなければなりませんが、その為にカメラに関する変数をいくつかプログラムの冒頭に定義しておくのが便利です:
    148 </p>
    149 
    150 <pre><code>
    151 glm::vec3 cameraPos   = glm::vec3(0.0f, 0.0f,  3.0f);
    152 glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
    153 glm::vec3 cameraUp    = glm::vec3(0.0f, 1.0f,  0.0f);
    154 </code></pre>
    155 
    156 <p>
    157   The <code>LookAt</code> function now becomes:
    158   これらを用いると<code>LookAt</code>関数は以下のようになります:
    159 </p>
    160 
    161 <pre><code>
    162 view = <function id='62'>glm::lookAt</function>(cameraPos, cameraPos + cameraFront, cameraUp);
    163 </code></pre>
    164 
    165 <p>
    166   First we set the camera position to the previously defined <var>cameraPos</var>. The direction is the current position + the direction vector we just defined. This ensures that however we move, the camera keeps looking at the target direction. Let's play a bit with these variables by updating the <var>cameraPos</var> vector when we press some keys.
    167   まず初めに先程定義した<var>cameraPos</var>を用いてカメラの位置を設定します。方向は現在の位置ベクトルにカメラの方向ベクトルを足したものです。こうすることでカメラがどのように動いても同じ点を見続けるようになります。これを少し面白くするために、特定のキーを押下した時に<var>cameraPos</var>を変更するようにしてみましょう:
    168 </p>
    169 
    170 <p>
    171   We already defined a <fun>processInput</fun> function to manage GLFW's keyboard input so let's add a few extra key commands:
    172   GLFWのキーボーッド入力を処理する為に<fun>processInput</fun>という関数を既に定義していました。これに他のキーの処理を追加します:
    173 </p>
    174 
    175 <pre><code>
    176 void processInput(GLFWwindow *window)
    177 {
    178     ...
    179     const float cameraSpeed = 0.05f; // adjust accordingly
    180     if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
    181         cameraPos += cameraSpeed * cameraFront;
    182     if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
    183         cameraPos -= cameraSpeed * cameraFront;
    184     if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
    185         cameraPos -= glm::normalize(<function id='61'>glm::cross</function>(cameraFront, cameraUp)) * cameraSpeed;
    186     if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
    187         cameraPos += glm::normalize(<function id='61'>glm::cross</function>(cameraFront, cameraUp)) * cameraSpeed;
    188 }
    189 </code></pre>
    190 
    191 <p>
    192   Whenever we press one of the <code>WASD</code> keys, the camera's position is updated accordingly. If we want to move forward or backwards we add or subtract the direction vector from the position vector scaled by some speed value. If we want to move sideways we do a cross product to create a <em>right</em> vector and we move along the right vector accordingly. This creates the familiar <def>strafe</def> effect when using the camera. 
    193   <code>WASD</code>のいずれかのキーを押すと、押したキーに応じてカメラの位置が更新されます。前進あるいは後退したい時はカメラの向きのベクトルに速度の値を掛けたものをカメラの位置ベクトルに加え、あるいは引きます。横に移動したければ外積を取って<em>右方向</em>のベクトルを作り、その方向に移動します。この処理により、<def>機銃掃射(strafe)</def>効果が得られます。これは一点を見つめたまま横に移動するというもののようです。
    194 </p>
    195 
    196 <note>
    197   Note that we normalize the resulting <em>right</em> vector. If we wouldn't normalize this vector, the resulting cross product may return differently sized vectors based on the <var>cameraFront</var> variable. If we would not normalize the vector we would move slow or fast based on the camera's orientation instead of at a consistent movement speed.
    198   <em>右方向</em>のベクトルを正規化していることに注意して下さい。こうしないと外積の結果得られるベクトルの大きさが違ってしまします。カメラの向きによって移動速度が大きくなったり小さくなったりして一定しません。
    199 </note>
    200 
    201 <p>
    202   By now, you should already be able to move the camera somewhat, albeit at a speed that's system-specific so you may need to adjust <var>cameraSpeed</var>.
    203   ここまでで既にカメラを移動することはできるようになりました。とは言えその速度はシステムによって異なりますので、<var>cameraSpeed</var>を調整しないといけません。
    204 </p>
    205 
    206 <h2>Movement speed</h2>
    207 <h2>移動速度</h2>
    208 <p>
    209   Currently we used a constant value for movement speed when walking around. In theory this seems fine, but in practice people's machines have different processing powers and the result of that is that some people are able to render much more frames than others each second. Whenever a user renders more frames than another user he also calls <fun>processInput</fun> more often. The result is that some people move really fast and some really slow depending on their setup. When shipping your application you want to make sure it runs the same on all kinds of hardware.
    210   現状移動速度は定数です。これでも良いように思われますが、実際はコンピュータの処理能力により1秒間に描画できるフレーム数が異なり、多くのフレームを描画できるコンピュータではそれだけ多く<fun>processInput</fun>が呼ばれるので、移動速度がコンピュータによりまちまちになってしまいます。アプリケーションを配布するなら、どのようなハードウェアにおいても同じように実行されるのが好ましいでしょう。
    211 </p>
    212 
    213 <p>
    214   Graphics applications and games usually keep track of a <def>deltatime</def> variable that stores the time it took to render the last frame. We then multiply all velocities with this <var>deltaTime</var> value. The result is that when we have a large <var>deltaTime</var> in a frame, meaning that the last frame took longer than average, the velocity for that frame will also be a bit higher to balance it all out. When using this approach it does not matter if you have a very fast or slow pc, the velocity of the camera will be balanced out accordingly so each user will have the same experience.
    215   グラフィックスを利用するアプリケーションやゲームは、通常直前のフレームの描画にかかった時間である<def>差分時間(deltatime)</def>という変数を追跡しています。ここではこの<var>deltaTime</var>の値を速度に掛け合せます。そうすることで直前のフレームの描画に長い時間かかり、<var>deltaTime</var>が大きくなった場合、そのフレームでの速度も大きくなり、描画時間の差が均されます。この方法によりPCの処理速度に関わらずカメラの速度が一定に保たれ、同じような体験が得られます。
    216 </p>
    217 
    218 <p>
    219   To calculate the <var>deltaTime</var> value we keep track of 2 global variables:
    220   <var>deltaTime</var>の値を計算する為に2つの大域変数を追跡します:
    221 </p>
    222 
    223 <pre><code>
    224 float deltaTime = 0.0f;	// Time between current frame and last frame
    225 float deltaTime = 0.0f;	// 直前のフレームと現在のフレームの間の時間
    226 float lastFrame = 0.0f; // Time of last frame
    227 float lastFrame = 0.0f; // 直前のフレームの時刻
    228 </code></pre>
    229 
    230 <p>
    231   Within each frame we then calculate the new <var>deltaTime</var> value for later use:
    232   各フレームにおいて<var>deltaTime</var>を計算して後の利用に備えます:
    233 </p>
    234 
    235 <pre><code>
    236 float currentFrame = <function id='47'>glfwGetTime</function>();
    237 deltaTime = currentFrame - lastFrame;
    238 lastFrame = currentFrame;  
    239 </code></pre>
    240 
    241 <p>
    242   Now that we have <var>deltaTime</var> we can take it into account when calculating the velocities:
    243   <var>deltaTime</var>が得られたので速度の計算に組込みます:
    244 </p>
    245 
    246 <pre><code>
    247 void processInput(GLFWwindow *window)
    248 {
    249     float cameraSpeed = 2.5f * deltaTime;
    250     [...]
    251 }
    252 </code></pre>
    253 
    254 <p>
    255   Since we're using <var>deltaTime</var> the camera will now move at a constant speed of <code>2.5</code> units per second. Together with the previous section we should now have a much smoother and more consistent camera system for moving around the scene:
    256   <var>deltaTime</var>を使っているのでカメラは秒速<code>2.5</code>というような一定の速度では動きません。前節で作成したものと合わせると、よりなめらかで一定の動きでカメラを移動できるようになります:
    257 </p>
    258 
    259 <div class="video paused" onclick="ClickVideo(this)">
    260   <video width="600" height="450" loop>
    261     <source src="/video/getting-started/camera_smooth.mp4" type="video/mp4" />
    262     <img src="/img/getting-started/camera_smooth.png" class="clean"/>    
    263   </video>
    264 </div>
    265 
    266 <p>
    267   And now we have a camera that walks and looks equally fast on any system. Again, check the  <a href="/code_viewer_gh.php?code=src/1.getting_started/7.2.camera_keyboard_dt/camera_keyboard_dt.cpp" target="_blank">source code</a> if you're stuck. We'll see the <var>deltaTime</var> value frequently return with anything movement related.
    268   これにてどんなシステム上でも同じように動き回れるカメラの実装が完了しました。どこかで詰まったら<a href="/code_viewer_gh.php?code=src/1.getting_started/7.2.camera_keyboard_dt/camera_keyboard_dt.cpp" target="_blank">ソースコード</a>を確認して下さい。以降においてもなんらかの動きを作成する場合、<var>deltaTime</var>をしばしば利用することになります。
    269 </p>
    270 
    271 <h1>Look around</h1>
    272 <h1>視点の移動</h1>
    273 <p>
    274   Only using the keyboard keys to move around isn't that interesting. Especially since we can't turn around making the movement rather restricted. That's where the mouse comes in!
    275   キーボードの入力により動き回るだけではそんなに面白くありません。カメラの向きを変更できない為に動きが制限されているからです。そこでマウスの登場です。
    276 </p>
    277 
    278 <p>
    279   To look around the scene we have to change the <var>cameraFront</var> vector based on the input of the mouse. However, changing the direction vector based on mouse rotations is a little complicated and requires some trigonometry. If you do not understand the trigonometry, don't worry, you can just skip to the code sections and paste them in your code; you can always come back later if you want to know more.
    280   あちこち見て回るにはマウスからの入力に応じて<var>cameraFront</var>を変更する必要があります。しかしマウスの回転に応じて方向ベクトルを変化させるのは少し煩雑で、三角関数が必要です。三角関数を知らない人も心配は不要です。コードの章まで読み飛してコピペして下さい。内容を知りたくなった時に戻って来れば結構です。
    281 </p>
    282 
    283 <h2>Euler angles</h2>
    284 <h2>オイラー角</h2>
    285 <p>
    286   Euler angles are 3 values that can represent any rotation in 3D, defined by Leonhard Euler somewhere in the 1700s. There are 3 Euler angles: <em>pitch</em>, <em>yaw</em> and <em>roll</em>. The following image gives them a visual meaning:
    287   オイラー角は3次元空間における任意の角度を表わすことができる3つの値です。1700年代にレオンハルト・オイラーによって定義されました。オイラー角を構成する3つの角はそれぞれ<em>仰角</em>、<em>方位角</em>、<em>傾斜角</em>です。これらの角を図示すると以下のようになります:
    288 </p>
    289 
    290 <img src="/img/getting-started/camera_pitch_yaw_roll.png" alt="Euler angles yaw pitch and roll" class="clean"/>
    291 
    292 <p>
    293   The <def>pitch</def> is the angle that depicts how much we're looking up or down as seen in the first image. The second image shows the <def>yaw</def> value which represents the magnitude we're looking to the left or to the right. The <def>roll</def> represents how much we <em>roll</em> as mostly used in space-flight cameras. Each of the Euler angles are represented by a single value and with the combination of all 3 of them we can calculate any rotation vector in 3D.
    294   <def>仰角(pitch)</def>は1つ目の図の通り、どのくらい見上げているか、あるいは見下げているかを表わします。<def>方位角</def>は2つ目の図の通り、左右の角度です。<def>傾斜角</def>はどのくらい<em>傾いている</em>かを表わし、特に空間中を飛んでいるカメラのようなものに利用されます。これら3つの角の組み合わせにより3次元空間上の任意の回転を表わせます。
    295 </p>
    296 
    297 <p>
    298   For our camera system we only care about the yaw and pitch values so we won't discuss the roll value here. Given a pitch and a yaw value we can convert them into a 3D vector that represents a new direction vector. The process of converting yaw and pitch values to a direction vector requires a bit of trigonometry. and we start with a basic case:
    299   これから作成するカメラにおいては仰角と方位角のみを考えますので、傾斜角については議論しません。仰角と方位角が与えられると、その方向を向いた3次元のベクトルを作成できます。仰角と方位角の値を方向ベクトルに変換するために、三角関数の知識が必要です。まずは基本的な場合から始めましょう:
    300 </p>
    301   
    302 <p>
    303   Let's start with a bit of a refresher and check the general right triangle case (with one side at a 90 degree angle):
    304   復習の意味も兼ねて、一般的な直角三角形を用いて説明します:
    305 
    306 <img src="/img/getting-started/camera_triangle.png" class="clean"/>
    307 
    308 <p>
    309   If we define the hypotenuse to be of length <code>1</code> we know from trigonometry (soh cah toa) that the adjacant side's length is \(\cos \ {\color{red}x}/{\color{purple}h} = \cos \ {\color{red}x}/{\color{purple}1} = \cos\ {\color{red}x}\) and that the opposing side's length is \(\sin \ {\color{green}y}/{\color{purple}h} = \sin \ {\color{green}y}/{\color{purple}1} = \sin\ {\color{green}y.}\)  This gives us some general formulas for retrieving the length in both the <code>x</code> and <code>y</code> sides on right triangles, depending on the given angle. Let's use this to calculate the components of the direction vector.
    310   斜辺の長さを<code>1</code>とした場合、三角関数を使うと、底辺の長さは\(\cos \ {\color{red}x}/{\color{purple}h} = \cos \ {\color{red}x}/{\color{purple}1} = \cos \ {\color{red}x}\)、高さは\(\sin \ {\color{green}y}/{\color{purple}h} = \sin \ {\color{green}y}/{\color{purple}1} = \sin \ {\color{green}y}\)となります。
    311 </p>
    312   
    313 <p>
    314   Let's imagine this same triangle, but now looking at it from a top perspective with the adjacent and opposite sides being parallel to the scene's x and z axis (as if looking down the y-axis). 
    315   これと同じ三角形を空間上で考えましょう。座標空間を上から見下ろし、三角形の底辺と対辺をそれぞれ空間のx軸とz軸に平行になるように置きます。
    316 </p>
    317   
    318 <img src="/img/getting-started/camera_yaw.png" class="clean"/>
    319 
    320 <p>
    321   If we visualize the yaw angle to be the counter-clockwise angle starting from the <code>x</code> side we can see that the length of the <code>x</code> side relates to <code>cos(yaw)</code>. And similarly how the length of the <code>z</code> side relates to <code>sin(yaw)</code>. 
    322   方位角を<code>x</code>軸から反時計回りの角度として定義すると、<code>x</code>軸の辺の長さは<code>cos(yaw)</code>となり、同様に<code>z</code>軸の辺は<code>sin(yaw)</code>となります。
    323 </p>  
    324   
    325 <p>
    326   If we take this knowledge and a given <code>yaw</code> value we can use it to create a camera direction vector:
    327   このことを用いると、<code>yaw</code>の値から以下のようにカメラの方向ベクトルを作成できます:
    328 </p>
    329   
    330 <pre><code>
    331 glm::vec3 direction;
    332 direction.x = cos(<function id='63'>glm::radians</function>(yaw)); // Note that we convert the angle to radians first
    333 direction.x = cos(<function id='63'>glm::radians</function>(yaw)); // 角度の値をラジアンに変換していることに注意
    334 direction.z = sin(<function id='63'>glm::radians</function>(yaw));
    335 </code></pre>
    336   
    337 <p>
    338   This solves how we can get a 3D direction vector from a yaw value, but pitch needs to be included as well. Let's now look at the <code>y</code> axis side as if we're sitting on the <code>xz</code> plane: 
    339   これで方位角から3次元の方向ベクトルを得られますが、これに加えて仰角も考慮する必要があります。今度は<code>xz</code>平面から<code>y</code>軸を眺めてみましょう:
    340 </p>
    341   
    342 
    343 <img src="/img/getting-started/camera_pitch.png" class="clean"/>
    344 
    345 <p>
    346   Similarly, from this triangle we can see that the direction's y component equals <code>sin(pitch)</code> so let's fill that in:
    347   同様にしてこの三角形から、方向ベクトルのy要素は<code>sin(pitch)</code>となります:
    348 </p>
    349   
    350   
    351 <pre><code>
    352 direction.y = sin(<function id='63'>glm::radians</function>(pitch));  
    353 </code></pre>
    354     
    355 <p>
    356   However, from the pitch triangle we can also see the <code>xz</code> sides are influenced by <code>cos(pitch)</code> so we need to make sure this is also part of the direction vector. With this included we get the final direction vector as translated from yaw and pitch Euler angles:
    357   加えてこの仰角を表わす三角形から<code>xz</code>平面の成分は<code>cos(pitch)</code>となるので、これを方向ベクトルに組込む必要があります。以上を踏まえると方向ベクトルは以下のようになります:
    358 </p>
    359   
    360 <pre><code>
    361 direction.x = cos(<function id='63'>glm::radians</function>(yaw)) * cos(<function id='63'>glm::radians</function>(pitch));
    362 direction.y = sin(<function id='63'>glm::radians</function>(pitch));
    363 direction.z = sin(<function id='63'>glm::radians</function>(yaw)) * cos(<function id='63'>glm::radians</function>(pitch));
    364 </code></pre>
    365   
    366 <p>
    367   This gives us a formula to convert yaw and pitch values to a 3-dimensional direction vector that we can use for looking around. 
    368   これが仰角と方位角を、3次元の方向ベクトルに変換する公式です。このベクトルをカメラの視線として利用できます。
    369 </p>
    370   
    371 <p>
    372   We've set up the scene world so everything's positioned in the direction of the negative z-axis. However, if we look at the <code>x</code> and <code>z</code> yaw triangle we see that a \(\theta\) of <code>0</code> results in the camera's <code>direction</code> vector to point towards the positive x-axis. To make sure the camera points towards the negative z-axis by default we can give the <code>yaw</code> a default value of a 90 degree clockwise rotation. Positive degrees rotate counter-clockwise so we set the default <code>yaw</code> value to:
    373   以前設定した空間において、全ての物体はz軸が負の位置に置かれていました。しかし<code>xz</code>平面における方位角を表わす三角形を見ると、\(\theta\)が<code>0</code>である場合カメラの<code>direction</code>ベクトルがx軸正の方向を向くことが分かります。初期段階においてカメラがz軸負の方向を見るようにするために、<code>yaw</code>の初期値を時計回りに90度回転させるべきです。正の値は反時計回りの回転を表わすので、<code>yaw</code>の初期値は以下のように設定します:
    374 </p>
    375   
    376 <pre><code>
    377 yaw = -90.0f;
    378 </code></pre>
    379   
    380 <p>
    381     You've probably wondered by now: how do we set and modify these yaw and pitch values?
    382 	それではどのようにしてこの仰角と方位角を更新すればよいでしょうか。
    383 </p>
    384 
    385 
    386 <h2>Mouse input</h2>
    387 <h2>マウスからの入力</h2>
    388 <p>
    389   The yaw and pitch values are obtained from mouse (or controller/joystick) movement where horizontal mouse-movement affects the yaw and vertical mouse-movement affects the pitch. The idea is to store the last frame's mouse positions and calculate in the current frame how much the mouse values changed. The higher the horizontal or vertical difference, the more we update the pitch or yaw value and thus the more the camera should move. 
    390   方位角と仰角の値はマウス(あるいはコントローラ、ジョイスティック等)の動きから得ます。マウスの水平方向の移動により方位角を、垂直方向の移動により仰角を変更するようにします。直前のフレームにおけるマウスの位置を保存しておいて、現在のフレームにおけるマウスの位置との差を計算します。水平方向や垂直方向の動きが大きいほど、方位角や仰角の変化量も大きくなるようにし、カメラも大きく動かされるようにしましょう。
    391 </p>
    392 
    393 <p>
    394   First we will tell GLFW that it should hide the cursor and <def>capture</def> it. Capturing a cursor means that, once the application has focus, the mouse cursor stays within the center of the window (unless the application loses focus or quits). We can do this with one simple configuration call:
    395   まずはGLFWがカーソルを<def>キャプチャ</def>し非表示にするようにします。カーソルのキャプチャとはアプリケーションにフォーカスしたらマウスのカーソルを(別のアプリケーションにフォーカスが移るか、このアプリケーションが終了するまで)ウィンドウの中央に固定しておくことを言います。これは1つの簡単な設定により実行できます:
    396 </p>
    397 
    398 <pre><code>
    399 glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);  
    400 </code></pre>
    401 
    402 <p>
    403   After this call, wherever we move the mouse it won't be visible and it should not leave the window. This is perfect for an FPS camera system.
    404   この関数を実行することで、マウスを動かしても表示されず、ウィンドウの外に出ることもなくなります。FPSのカメラには最適です。
    405 </p>
    406 
    407 <p>
    408 To calculate the pitch and yaw values we need to tell GLFW to listen to mouse-movement events. We do this by creating a callback function with the following prototype:
    409 仰角と方位角を計算する為、GLFWにマウスのイベントを監視させる必要があります。その為に以下のようなプロトタイプのコールバック関数を定義します:
    410 </p>
    411 
    412 <pre><code>
    413 void mouse_callback(GLFWwindow* window, double xpos, double ypos);
    414 </code></pre>
    415 
    416 <p>
    417   Here <var>xpos</var> and <var>ypos</var> represent the current mouse positions. As soon as we register the callback function with GLFW each time the mouse moves, the <fun>mouse_callback</fun> function is called:
    418   ここで、<var>xpos</var>と<var>ypos</var>は現在のマウスの位置を表わします。この関数をGLFWにコールバックとして登録すれば、マウスが動く度に<fun>mouse_callback</fun>が呼ばれます:
    419 </p>
    420 
    421 <pre><code>
    422 glfwSetCursorPosCallback(window, mouse_callback);  
    423 </code></pre>
    424 
    425 <p>
    426   When handling mouse input for a fly style camera there are several steps we have to take  before we're able to fully calculate the camera's direction vector:
    427   マウスの入力により飛行型のカメラを操作する場合、実際にカメラの方向ベクトルを計算する上で以下の手順を踏まなければいけません:
    428   
    429   <ol>
    430     <li>Calculate the mouse's offset since the last frame.</li>
    431 	<li>直前のフレームからのマウスの移動量を計算。</li>
    432     <li>Add the offset values to the camera's yaw and pitch values.</li>
    433 	<li>その移動量をカメラの方位角と仰角に加算。</li>
    434     <li>Add some constraints to the minimum/maximum pitch values.</li>
    435 	<li>仰角をある範囲に制限。</li>
    436     <li>Calculate the direction vector.</li>
    437 	<li>方向ベクトルを計算。</li>
    438   </ol>
    439 </p>
    440 
    441 <p>
    442   The first step is to calculate the offset of the mouse since last frame. We first have to store the last mouse positions in the application, which we initialize to be in the center of the screen (screen size is <code>800</code> by <code>600</code>) initially:
    443   最初の作業は直近のフレームからのマウスの移動量を計算することです。まず直前のマウスの位置をアプリケーションに保存します。この変数の初期値は画面の中心にしておきます(画面の大きさは<code>800x600</code>です)。
    444 </p>
    445 
    446 <pre class="cpp"><code>
    447 float lastX = 400, lastY = 300;
    448 </code></pre>
    449 
    450 <p>
    451   Then in the mouse's callback function we calculate the offset movement between the last and current frame:
    452   次にマウスのコールバック関数内で直前のフレームからの移動量を計算します:
    453 </p>
    454 
    455 <pre><code>
    456 float xoffset = xpos - lastX;
    457 float yoffset = lastY - ypos; // reversed since y-coordinates range from bottom to top
    458 float yoffset = lastY - ypos; // y座標は下から上へ増加するのでx座標とは逆
    459 lastX = xpos;
    460 lastY = ypos;
    461 
    462 const float sensitivity = 0.1f;
    463 xoffset *= sensitivity;
    464 yoffset *= sensitivity;
    465 </code></pre>
    466 
    467 <p>
    468   Note that we multiply the offset values by a <var>sensitivity</var> value. If we omit this multiplication the mouse movement would be way too strong; fiddle around with the sensitivity value to your liking.
    469 	<var>sensitivity</var>(感度)を移動量の値に掛けていることに注意して下さい。これをしないとマウスによる動きが速すぎるかと思います。感度を変化させて好みの値を探って下さい。
    470 </p>
    471 
    472 <p>
    473   Next we add the offset values to the globally declared <var>pitch</var> and <var>yaw</var> values:
    474   続いて大域的に宣言されている<var>pitch</var>と<var>yaw</var>に加算します:
    475 </p>
    476 
    477 <pre><code>
    478 yaw   += xoffset;
    479 pitch += yoffset;  
    480 </code></pre>
    481 
    482 <p>
    483   In the third step we'd like to add some constraints to the camera so users won't be able to make weird camera movements (also causes a LookAt flip once direction vector is parallel to the world up direction). The pitch needs to be constrained in such a way that users won't be able to look higher than <code>89</code> degrees (at <code>90</code> degrees we get the LookAt flip) and also not below <code>-89</code> degrees. This ensures the user will be able to look up to the sky or below to his feet but not further. The constraints work by replacing the Euler value with its constraint value whenever it breaches the constraint:
    484   3つ目の作業はカメラの動く範囲に制限を加え、ユーザーがおかしなカメラの動きをできないようにすることです。カメラの方向ベクトルが大域空間の上向きのベクトルと平行になった時に視線がひっくり返るのです。すなわち仰角が<code>90</code>度になると視線の反転が起こるので、この角を<code>89</code>度以下、そして<code>-89</code>度以上に制限します。こうすることでユーザーは空を見上げたり足元を見下げたりはできますがそれ以上はできなくなります。このような制限は、この角が制限を越えたときに制限の最大値あるいは最小値に置き換えることで実現できます:
    485 </p>
    486 
    487 <pre><code>
    488 if(pitch &gt; 89.0f)
    489   pitch =  89.0f;
    490 if(pitch &lt; -89.0f)
    491   pitch = -89.0f;
    492 </code></pre>
    493 
    494 <p>
    495   Note that we set no constraint on the yaw value since we don't want to constrain the user in horizontal rotation. However, it's just as easy to add a constraint to the yaw as well if you feel like it.
    496   ここでは水平方向のカメラの動きに制限を設けたくないので、方位角の値には制限をかけません。しかし必要であれば仰角と同様の方法で制限することができます。
    497 </p>
    498 
    499 <p>
    500   The fourth and last step is to calculate the actual direction vector using the formula from the previous section:
    501   最後の作業は方向ベクトルを前章の公式から計算することです:
    502 </p>
    503 
    504 <pre><code>
    505 glm::vec3 direction;
    506 direction.x = cos(<function id='63'>glm::radians</function>(yaw)) * cos(<function id='63'>glm::radians</function>(pitch));
    507 direction.y = sin(<function id='63'>glm::radians</function>(pitch));
    508 direction.z = sin(<function id='63'>glm::radians</function>(yaw)) * cos(<function id='63'>glm::radians</function>(pitch));
    509 cameraFront = glm::normalize(direction);
    510 </code></pre>
    511   
    512   <p>
    513     This computed direction vector then contains all the rotations calculated from the mouse's movement. Since the <var>cameraFront</var> vector is already included in glm's <fun>lookAt</fun> function we're set to go.
    514 	この計算によりマウスの動きを加味した方向ベクトルが得られます。<var>cameraFront</var>ベクトルは既にglmの<fun>lookAt</fun>関数に含まれているので、これで準備完了です。
    515 </p>
    516 
    517 <p>
    518   If you'd now run the code you'll notice the camera makes a large sudden jump whenever the window first receives focus of your mouse cursor. The cause for this sudden jump is that as soon as your cursor enters the window the mouse callback function is called with an <var>xpos</var> and <var>ypos</var> position equal to the location your mouse entered the screen from. This is often a position that is significantly far away from the center of the screen, resulting in large offsets and thus a large movement jump. We can circumvent this issue by defining a global <code>bool</code> variable to check if this is the first time we receive mouse input. If it is the first time, we update the initial mouse positions to the new <var>xpos</var> and <code>ypos</code> values. The resulting mouse movements will then use the newly entered mouse's position coordinates to calculate the offsets:
    519   現段階でのコードを実行すると最初にウィンドウにマウスのカーソルでフォーカスした際にカメラの視点が大きく移動することに気付くでしょう。マウスのカーソルがウィンドウに入った時にマウスのコールバック関数が呼ばれますがこの時引数として渡される<var>xpos</var>と<var>ypos</var>がその時のカーソルの位置であり、ウィンドウの中心からは大きく離れているため、中心から大きく移動したものと見做され、結果としてカメラの大きな移動になります。この問題に対処する為に、マウスからの入力を受けとるのが初めてかどうかを保存した大域的な真偽値の変数を定義します。マウスからの最初の入力があった場合、マウスの初期位置を引数として渡された<var>xpos</var>と<var>ypos</var>に変更します。そうするとマウスの移動量の計算に新しく入力されたマウスの位置が利用されるようになります:
    520 </p>
    521 
    522 <pre><code>
    523 if (firstMouse) // initially set to true
    524 {
    525     lastX = xpos;
    526     lastY = ypos;
    527     firstMouse = false;
    528 }
    529 </code></pre>
    530 
    531 <p>
    532   The final code then becomes:
    533 </p>
    534 
    535 <pre><code>
    536 void mouse_callback(GLFWwindow* window, double xpos, double ypos)
    537 {
    538     if (firstMouse)
    539     {
    540         lastX = xpos;
    541         lastY = ypos;
    542         firstMouse = false;
    543     }
    544   
    545     float xoffset = xpos - lastX;
    546     float yoffset = lastY - ypos; 
    547     lastX = xpos;
    548     lastY = ypos;
    549 
    550     float sensitivity = 0.1f;
    551     xoffset *= sensitivity;
    552     yoffset *= sensitivity;
    553 
    554     yaw   += xoffset;
    555     pitch += yoffset;
    556 
    557     if(pitch &gt; 89.0f)
    558         pitch = 89.0f;
    559     if(pitch &lt; -89.0f)
    560         pitch = -89.0f;
    561 
    562     glm::vec3 direction;
    563     direction.x = cos(<function id='63'>glm::radians</function>(yaw)) * cos(<function id='63'>glm::radians</function>(pitch));
    564     direction.y = sin(<function id='63'>glm::radians</function>(pitch));
    565     direction.z = sin(<function id='63'>glm::radians</function>(yaw)) * cos(<function id='63'>glm::radians</function>(pitch));
    566     cameraFront = glm::normalize(direction);
    567 }  
    568 </code></pre>
    569 
    570 <p>
    571   There we go! Give it a spin and you'll see that we can now freely move through our 3D scene! 
    572 これで完成です。コードを実行して3次元空間を自由に動き回れるか確認してみましょう。
    573 </p>
    574 
    575 
    576 <h2>Zoom</h2>
    577 <h2>拡大</h2>
    578 <p>
    579   As a little extra to the camera system we'll also implement a zooming interface. In the previous chapter we said the <em>Field of view</em> or <em>fov</em> largely defines how much we can see of the scene. When the field of view becomes smaller, the scene's projected space gets smaller. This smaller space is projected over the same NDC, giving the illusion of zooming in. To zoom in, we're going to use the mouse's scroll wheel. Similar to mouse movement and keyboard input we have a callback function for mouse scrolling:
    580   最後におまけとしてカメラに拡大機能を実装してみましょう。前章において、<em>視野角(fov)</em>が画面上で見える範囲を主に規定することをお話ししました。視野角が小さくなると空間の中で射影される範囲が小さくなります。範囲が狭くなった空間もそれまでと同じ大きさのNDCに投影されるので、結果として拡大したように見えます。ここでは拡大の操作をするためにマウスのホイールを利用しましょう。マウスの動きやキーボードの入力の時と同様に、マウスのスクロールに対してもコールバック関数を定義します。
    581 </p>
    582 
    583 <pre><code>
    584 void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
    585 {
    586     fov -= (float)yoffset;
    587     if (fov &lt 1.0f)
    588         fov = 1.0f;
    589     if (fov &gt; 45.0f)
    590         fov = 45.0f; 
    591 }
    592 </code></pre>
    593 
    594 <p>
    595   When scrolling, the <var>yoffset</var> value tells us the amount we scrolled vertically. When the <fun>scroll_callback</fun> function is called we change the content of the globally declared <var>fov</var> variable. Since <code>45.0</code> is the default fov value we want to constrain the zoom level between <code>1.0</code> and <code> 45.0</code>.
    596   スクロールすると<var>yoffset</var>の値がその時のスクロール量を保持します。<fun>scroll_callback</fun>関数が呼ばれた時に、大域的に宣言されている<var>fov</var>の値を変更するようにします。<code>45.0</code>が視野角の既定値ですが、これを<code>1.0</code>から<code>45.0</code>の間で動かせるようにしましょう。
    597 </p>
    598 
    599 <p>
    600   We now have to upload the perspective projection matrix to the GPU each frame, but this time with the <var>fov</var> variable as its field of view:
    601   透視投影行列をフレーム毎に更新する必要がありますが、この時に視野角の値として<var>fov</var>を利用するようにします:
    602 </p>
    603 
    604 <pre><code>
    605 projection = <function id='58'>glm::perspective</function>(<function id='63'>glm::radians</function>(fov), 800.0f / 600.0f, 0.1f, 100.0f);  
    606 </code></pre>
    607 
    608 <p>
    609   And lastly don't forget to register the scroll callback function:
    610   最後にスクロールのコールバック関数を登録するのを忘れないようにしましょう:
    611 </p>
    612 
    613 <pre><code>
    614 <function id='64'>glfwSetScrollCallback</function>(window, scroll_callback); 
    615 </code></pre>
    616 
    617 <p>
    618   And there you have it. We implemented a simple camera system that allows for free movement in a 3D environment.
    619   これで完成です。3次元空間上を自由に動き回れるカメラが実装できました。
    620 </p>
    621 
    622 <div class="video paused" onclick="ClickVideo(this)">
    623   <video width="600" height="450" loop>
    624     <source src="/video/getting-started/camera_mouse.mp4" type="video/mp4" />
    625     <img src="/img/getting-started/camera_mouse.png" class="clean"/>    
    626   </video>
    627 </div>
    628 
    629 <p>
    630   Feel free to experiment a little and if you're stuck compare your code with the  <a href="/code_viewer_gh.php?code=src/1.getting_started/7.3.camera_mouse_zoom/camera_mouse_zoom.cpp" target="_blank">source code</a>.
    631   いろいろ変更して好きに実験してみて下さい。どこかで分からなくなったらご自分のコードとこの<a href="/code_viewer_gh.php?code=src/1.getting_started/7.3.camera_mouse_zoom/camera_mouse_zoom.cpp" target="_blank">ソースコード</a>を比較して下さい。
    632 </p>
    633 
    634 <h1>Camera class</h1>
    635 <h1>カメラのクラス</h1>
    636 <p>
    637   In the upcoming chapters we'll always use a camera to easily look around the scenes and see the results from all angles. However, since the camera code can take up a significant amount of space on each chapter we'll abstract its details a little and create our own camera object that does most of the work for us with some neat little extras. Unlike the Shader chapter we won't walk you through creating the camera class, but provide you with the (fully commented) source code if you want to know the inner workings. 
    638   以降の章では作成したものを様々な角度から確認するためにカメラを利用します。しかしカメラのコードは場所をとるので細かい部分を少し抽象化するためにカメラオブジェクトを作成し、コードをすっきりさせるようにします。シェーダーの章においては細かく解説しましたが今回は(コメントをたくさん付けた)ソースコードをご自身で見て内容を確認していただくことにします。
    639 </p>
    640 
    641 <p>
    642   Like the <code>Shader</code> object, we define the camera class entirely in a single header file. You can find the camera class <a href="/code_viewer_gh.php?code=includes/learnopengl/camera.h" target="_blank">here</a>; you should be able to understand the code after this chapter. It is advised to at least check the class out once as an example on how you could create your own camera system.
    643   <code>Shader</code>オブジェクトと同様、カメラのクラスはひとつのヘッダファイルに記述します。<a href="/code_viewer_gh.php?code=includes/learnopengl/camera.h" target="_blank">ここ</a>でカメラクラスを確認して下さい。ここまで読み終えた方には十分理解できるはずです。一度はこのクラスの中身にさっと目を通してカメラのシステムの作成方法を確認して下さい。
    644 </p>
    645 
    646 <warning>
    647   The camera system we introduced is a fly like camera that suits most purposes and works well with Euler angles, but be careful when creating different camera systems like an FPS camera, or a flight simulation camera. Each camera system has its own tricks and quirks so be sure to read up on them. For example, this fly camera doesn't allow for pitch values higher than or equal to <code>90</code> degrees and a static up vector of <code>(0,1,0)</code> doesn't work when we take roll values into account. 
    648   ここで作成したカメラは飛んでいるようなカメラで、オイラー角と共にほとんどの目的に利用できます。しかしFPSのカメラやフライトシミュレーションのカメラのような別のカメラを作成する場合は注意が必要です。角カメラにはそれぞれ独特の手法が必要なので、利用する場合はそのカメラについての解説を読むようにして下さい。例えばここで作ったカメラは仰角を<code>90</code>度以上にできませんし、また傾斜角を考慮したい場合はカメラの上方向のベクトルを<code>(0, 1, 0)</code>に保っているのは間違いです。
    649 </warning>
    650 
    651 <p>
    652   The updated version of the source code using the new camera object can be found  <a href="/code_viewer_gh.php?code=src/1.getting_started/7.4.camera_class/camera_class.cpp" target="_blank">here</a>.
    653   カメラオブジェクトを利用したコードは<a href="/code_viewer_gh.php?code=src/1.getting_started/7.4.camera_class/camera_class.cpp" target="_blank">こちら</a>です。
    654 </p>
    655 
    656 <h2>Exercises</h2>
    657 <h2>演習</h2>
    658 <p>
    659   <ul>
    660     <li>See if you can transform the camera class in such a way that it becomes a <strong>true</strong> fps camera where you cannot fly; you can only look around while staying on the <code>xz</code> plane: <a href="/code_viewer_gh.php?code=src/1.getting_started/7.5.camera_exercise1/camera_exercise1.cpp" target="_blank">solution</a>.</li>
    661 	<li>カメラクラスを変更して<strong>本当の</strong>FPSのカメラを実装して下さい。すなわち周囲を見回せても<code>xz</code>平面を離れられないようにして下さい: <a href="/code_viewer_gh.php?code=src/1.getting_started/7.5.camera_exercise1/camera_exercise1.cpp" target="_blank">解答</a>。</li>
    662     <li>Try to create your own LookAt function where you manually create a view matrix as discussed at the start of this chapter. Replace glm's LookAt function with your own implementation and see if it still acts the same: <a href="/code_viewer_gh.php?code=src/1.getting_started/7.6.camera_exercise2/camera_exercise2.cpp" target="_blank">solution</a>.</li>
    663 	<li>この章の初めに紹介した視野行列を自身で作成し、それを利用してLookAt関数を実装して下さい。glmのLookAt関数を自身で作成したものに置き換え、同じように機能するか確認して下さい: <a href="/code_viewer_gh.php?code=src/1.getting_started/7.6.camera_exercise2/camera_exercise2.cpp" target="_blank">解答</a>。</li>
    664   </ul>
    665 </p>
    666     </div>
    667 </body>
    668 </html>