LearnOpenGL

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit 9e304410c3dac0c4f95b4e611ce778c745824713
parent ceb019b1bae9abec018178a5c1874eaa833bde1e
Author: Matsuda Kenji <ftvda283@gmail.com>
Date:   Fri, 10 Sep 2021 19:47:47 +0900

progress in hello triangle

Diffstat:
Mtranslation/Getting-started/Hello-Triangle.html | 32+++++++++++++++++++++++++++++++-
1 file changed, 31 insertions(+), 1 deletion(-)

diff --git a/translation/Getting-started/Hello-Triangle.html b/translation/Getting-started/Hello-Triangle.html @@ -106,10 +106,12 @@ OpenGLにおいてあらゆることは三次元空間上でおこります。 <h2>頂点の入力</h2> <p> To start drawing something we have to first give OpenGL some input vertex data. OpenGL is a 3D graphics library so all coordinates that we specify in OpenGL are in 3D (<code>x</code>, <code>y</code> and <code>z</code> coordinate). OpenGL doesn't simply transform <strong>all</strong> your 3D coordinates to 2D pixels on your screen; OpenGL only processes 3D coordinates when they're in a specific range between <code>-1.0</code> and <code>1.0</code> on all 3 axes (<code>x</code>, <code>y</code> and <code>z</code>). All coordinates within this so called <def>normalized device coordinates</def> range will end up visible on your screen (and all coordinates outside this region won't). +描画するためにはまずOpenGLに頂点のデータを入力として与えなければなりません。OpenGLは三次元のグラフィックライブラリなので、すべての座標は三次元です(<code>x</code>座標、<code>y</code>座標、そして<code>z</code>座標です)。OpenGLは<strong>すべて</strong>の三次元座標を単に二次元のピクセルに変換するわけではありません。<code>x</code>、<code>y</code>、<code>z</code>のすべての座標が<code>-1.0</code>と<code>1.0</code>のあいだにあるものだけを処理します。この範囲にある座標は<def>正規化デバイス座標系</def>と呼ばれます。この範囲にあるものだけが最終的にスクリーンに表示され、この外側のものは表示されません。 </p> <p> Because we want to render a single triangle we want to specify a total of three vertices with each vertex having a 3D position. We define them in normalized device coordinates (the visible region of OpenGL) in a <code>float</code> array: +ここでは三角形を表示したいので、三次元空間上のみっつの頂点を指定します。<code>float</code>の配列として、正規化デバイス座標系(OpenGLにおいて可視の領域)中に定義しましょう: </p> <pre><code> @@ -122,32 +124,40 @@ float vertices[] = { <p> Because OpenGL works in 3D space we render a 2D triangle with each vertex having a <code>z</code> coordinate of <code>0.0</code>. This way the <em>depth</em> of the triangle remains the same making it look like it's 2D. +OpenGLは三次元空間上で動作するので、二次元の三角形を描画する場合は各頂点の<code>z</code>座標を<code>0.0</code>にします。こうすることで各頂点の<em>深度</em>が同じになり、二次元であるように見えます。 </p> <note> <strong>Normalized Device Coordinates (NDC)</strong><br/> + <strong>正規化デバイス座標系(NDC)</strong><br/> <p> Once your vertex coordinates have been processed in the vertex shader, they should be in <def>normalized device coordinates</def> which is a small space where the <code>x</code>, <code>y</code> and <code>z</code> values vary from <code>-1.0</code> to <code>1.0</code>. Any coordinates that fall outside this range will be discarded/clipped and won't be visible on your screen. Below you can see the triangle we specified within normalized device coordinates (ignoring the <code>z</code> axis): + 頂点シェーダーで処理された頂点の座標は<def>正規化デバイス座標系</def>の中におさまらなければいけません。正規化デバイス座標系とは、<code>x</code>、<code>y</code>、<code>z</code>座標がすべて<code>-1.0</code>と<code>1.0</code>のあいだにあるような小さな立方体の空間です。この座標の外にあるものはすべて切り捨てられ、スクリーン上では見えなくなります。下の画像は先程正規化デバイス座標系におさまるように指定した三角形です(<code>z</code>軸は無視しています)。 </p> <img src="/img/getting-started/ndc.png" class="clean" alt="2D Normalized Device Coordinates as shown in a graph"/> <p> Unlike usual screen coordinates the positive y-axis points in the up-direction and the <code>(0,0)</code> coordinates are at the center of the graph, instead of top-left. Eventually you want all the (transformed) coordinates to end up in this coordinate space, otherwise they won't be visible. + 通常のスクリーンの座標系とは違い、y軸は上を指し、原点は左上ではなく中央に位置します。最終的に変換後のすべての座標がこの中におさまるようにしましょう。さもなければ表示されません。 </p> <p> Your NDC coordinates will then be transformed to <def>screen-space coordinates</def> via the <def>viewport transform</def> using the data you provided with <fun><function id='22'>glViewport</function></fun>. The resulting screen-space coordinates are then transformed to fragments as inputs to your fragment shader. +NDCにおとしこんだ座標は<def>ビューポート変換</def>により<def>スクリーン座標系</def>に変換されます。ビューポート変換は<fun><function id='22'>glViewport</function></fun>で設定した情報を利用します。スクリーン座標系の座標はフラグメントシェーダーの入力となるフラグメントに変換されます。 </p> </note> <p> With the vertex data defined we'd like to send it as input to the first process of the graphics pipeline: the vertex shader. This is done by creating memory on the GPU where we store the vertex data, configure how OpenGL should interpret the memory and specify how to send the data to the graphics card. The vertex shader then processes as much vertices as we tell it to from its memory. +先程定義した頂点のデータを、グラフィックスパイプラインの最初の処理である頂点シェーダーに入力として送りましょう。そのためにまず頂点データを格納する上のメモリを確保し、OpenGLにそのメモリ中にどんなデータが入っているのか、およびどのようにデータをグラフィックカードに送信するのかを設定します。そうすることで頂点シェーダーがGPUのメモリを読み、指定した分だけ頂点のデータを処理してくれます。 </p> <p> We manage this memory via so called <def>vertex buffer objects</def> (<def>VBO</def>) that can store a large number of vertices in the GPU's memory. The advantage of using those buffer objects is that we can send large batches of data all at once to the graphics card, and keep it there if there's enough memory left, without having to send data one vertex at a time. Sending data to the graphics card from the CPU is relatively slow, so wherever we can we try to send as much data as possible at once. Once the data is in the graphics card's memory the vertex shader has almost instant access to the vertices making it extremely fast +このメモリはGPUのメモリに大量の頂点を保持できる<def>頂点バッファオブジェクト</def>(<def>VBO</def>)を通して管理されます。このバッファの利点は大きなかたまりになったデータをいっぺんにグラフィックカードに送信し、メモリに十分な空きがなくてもそのデータを保持し続けてくれることです。頂点データをひとつずつ送信しなくてすむのです。CPUからグラフィックカードへのデータの送信は比較的遅いので、可能な限り多くのデータを一度に送りたいのです。いったん頂点データがグラフィックカードのメモリに置かれると、頂点シェーダーが即座にデータを参照できるので高速な処理が可能になります。 </p> <p> A vertex buffer object is our first occurrence of an OpenGL object as we've discussed in the <a href="https://learnopengl.com/Getting-Started/OpenGL" target="_blank">OpenGL</a> chapter. Just like any object in OpenGL, this buffer has a unique ID corresponding to that buffer, so we can generate one with a buffer ID using the <fun><function id='12'>glGenBuffers</function></fun> function: +<a href="https://learnopengl.com/Getting-Started/OpenGL" target="_blank">OpenGL</a>の章で議論したように、頂点バッファオブジェクトはわれわれが最初に遭遇したOpenGLオブジェクトです。このバッファもOpenGLの他のオブジェクトと同様、一意のIDを割り当てられるので、<fun><function id='12'>glGenBuffers</function></fun>を使ってオブジェクトを作成すると同時にバッファIDを取得できます: </p> <pre class="cpp"><code> @@ -157,6 +167,7 @@ unsigned int VBO; <p> OpenGL has many types of buffer objects and the buffer type of a vertex buffer object is <var>GL_ARRAY_BUFFER</var>. OpenGL allows us to bind to several buffers at once as long as they have a different buffer type. We can bind the newly created buffer to the <var>GL_ARRAY_BUFFER</var> target with the <fun><function id='32'>glBindBuffer</function></fun> function: +OpenGLにはさまざまな型のバッファオブジェクトがあります。頂点バッファオブジェクトの型は<var>GL_ARRAY_BUFFER</var>です。型が異なる限り、同時に複数のバッファを紐付けすることができます。新しく作ったバッファは<fun><function id='32'>glBindBuffer</function></fun>により<var>GL_ARRAY_BUFFER</var>に紐付けできます: </p> <pre><code> @@ -166,6 +177,7 @@ unsigned int VBO; <p> From that point on any buffer calls we make (on the <var>GL_ARRAY_BUFFER</var> target) will be used to configure the currently bound buffer, which is <var>VBO</var>. Then we can make a call to the <fun><function id='31'>glBufferData</function></fun> function that copies the previously defined vertex data into the buffer's memory: +上記のようにバッファを紐付けすることで、以降われわれが行うバッファの操作(<var>GL_ARRAY_BUFFER</var>をターゲットとするもの)は現在紐付いているもの(ここでは<var>VBO</var>)にたいして行われます。バッファの紐付けができたら、<fun><function id='31'>glBufferData</function></fun>を呼び、先程定義した頂点データをバッファのメモリにコピーしましょう: </p> <pre><code> @@ -174,34 +186,45 @@ unsigned int VBO; <p> <fun><function id='31'>glBufferData</function></fun> is a function specifically targeted to copy user-defined data into the currently bound buffer. Its first argument is the type of the buffer we want to copy data into: the vertex buffer object currently bound to the <var>GL_ARRAY_BUFFER</var> target. The second argument specifies the size of the data (in bytes) we want to pass to the buffer; a simple <code>sizeof</code> of the vertex data suffices. The third parameter is the actual data we want to send. +<fun><function id='31'>glBufferData</function></fun>は現在紐付いているバッファに、ユーザーが独自に定義したデータをコピーするための関数です。最初の引数はデータをコピーしたいバッファの型です。この例において現在頂点バッファオブジェクトは<var>GL_ARRAY_BUFFER</var>に紐付いています。二番目の引数はバッファに渡したいデータのサイズ(バイト単位)です。頂点データに<code>sizeof</code>を適応したもので十分です。三番目はコピーするデータです。 </p> <p> The fourth parameter specifies how we want the graphics card to manage the given data. This can take 3 forms: +四番目の引数ではコピーしたデータをグラフィックカードがどのように管理するかを指定します。管理方法は以下の三つから選びます: </p> <ul> <li><var>GL_STREAM_DRAW</var>: the data is set only once and used by the GPU at most a few times.</li> <li><var>GL_STATIC_DRAW</var>: the data is set only once and used many times.</li> <li><var>GL_DYNAMIC_DRAW</var>: the data is changed a lot and used many times.</li> - + </ul> + <ul> + <li><var>GL_STREAM_DRAW</var>: データは一度だけセットされ、GPUは最大でも数回程度しか利用しない。</li> + <li><var>GL_STATIC_DRAW</var>: データは一度だけセットされ、繰り返し利用される。</li> + <li><var>GL_DYNAMIC_DRAW</var>: データは頻繁に変更され、繰り返し利用される。</li> </ul> <p> The position data of the triangle does not change, is used a lot, and stays the same for every render call so its usage type should best be <var>GL_STATIC_DRAW</var>. If, for instance, one would have a buffer with data that is likely to change frequently, a usage type of <var>GL_DYNAMIC_DRAW</var> ensures the graphics card will place the data in memory that allows for faster writes. +三角形の位置のデータは変更されることはなく、何度も利用されるので、<var>GL_STATIC_DRAW</var>を指定します。これが例えば頻繁にデータの書き換えがおこるバッファであれば、<var>GL_DYNAMIC_DRAW</var>を選ぶことでグラフィックカードはメモリにおいてより高速に書き換えられる場所にデータを配置します。 </p> <p> As of now we stored the vertex data within memory on the graphics card as managed by a vertex buffer object named <var>VBO</var>. Next we want to create a vertex and fragment shader that actually processes this data, so let's start building those. +これで<var>VBO</var>と呼ばれる頂点バッファオブジェクトによって管理されているグラフィックカードのメモリ上に頂点データを配置できました。続いて頂点シェーダーとフラグメントシェーダーを作成し、このデータを実際に処理していきましょう。 </p> <h2>Vertex shader</h2> +<h2>頂点シェーダー</h2> <p> The vertex shader is one of the shaders that are programmable by people like us. Modern OpenGL requires that we at least set up a vertex and fragment shader if we want to do some rendering so we will briefly introduce shaders and configure two very simple shaders for drawing our first triangle. In the next chapter we'll discuss shaders in more detail. +頂点シェーダーはわれわれがプログラミングできるシェーダーです。現行のOpenGLにおいて、描画のためには少なくとも頂点シェーダーとフラグメントシェーダーを自分達で用意する必要があります。ここでは簡単にシェーダーについて紹介し、最初の三角形を描画するための簡単なシェーダーを作成します。次の節ではシェーダーについてもっと詳しく見ていきます。 </p> <p> The first thing we need to do is write the vertex shader in the shader language GLSL (OpenGL Shading Language) and then compile this shader so we can use it in our application. Below you'll find the source code of a very basic vertex shader in GLSL: +最初に必要なのはGLSL(OpenGL Shading Language)というシェーダー言語により、頂点シェーダーを書き、アプリケーションで利用できるようにコンパイルすることです。以下にGLSLで記述された最も基本的な頂点シェーダーを示します: </p> <pre><code> @@ -216,26 +239,33 @@ void main() <p> As you can see, GLSL looks similar to C. Each shader begins with a declaration of its version. Since OpenGL 3.3 and higher the version numbers of GLSL match the version of OpenGL (GLSL version 420 corresponds to OpenGL version 4.2 for example). We also explicitly mention we're using core profile functionality. +ご覧のようにGLSLはC言語に近いです。シェーダーはバージョンの宣言から記述します。OpenGL 3.3以降ではGLSLのバージョンはOpenGLのバージョンと呼応します(例えばGLSLバージョン420はOpenGLのバージョン4.2に対応します)。加えてコアプロファイルを仕様することを明記します。 </p> <p> Next we declare all the input vertex attributes in the vertex shader with the <code>in</code> keyword. Right now we only care about position data so we only need a single vertex attribute. GLSL has a vector datatype that contains 1 to 4 floats based on its postfix digit. Since each vertex has a 3D coordinate we create a <code>vec3</code> input variable with the name <var>aPos</var>. We also specifically set the location of the input variable via <code>layout (location = 0)</code> and you'll later see that why we're going to need that location. +続いて<code>in</code>というキーワードで、入力となる頂点属性をすべて宣言します。とりあえず位置のデータだけを処理するので、必要な頂点属性はひとつだけです。GLSLは<code>float</code>の1から4つ持つベクトルのデータ型をもちます。ベクトルの次元はデータ型の後ろに付いている数字に対応しています。頂点の座標は三次元なので<code>vec3</code>型の入力を<var>aPos</var>という名前で作成します。<code>layout (location = 0)</code>という記述により、入力となる変数の位置も指定します。なぜこのような場所の指定が必要になるのかは後ほど説明します。 </p> <note> <strong>Vector</strong><br/> + <strong>ベクトル</strong><br/> In graphics programming we use the mathematical concept of a vector quite often, since it neatly represents positions/directions in any space and has useful mathematical properties. A vector in GLSL has a maximum size of 4 and each of its values can be retrieved via <code>vec.x</code>, <code>vec.y</code>, <code>vec.z</code> and <code>vec.w</code> respectively where each of them represents a coordinate in space. Note that the <code>vec.w</code> component is not used as a position in space (we're dealing with 3D, not 4D) but is used for something called <def>perspective division</def>. We'll discuss vectors in much greater depth in a later chapter. +グラフィックプログラミングにおいて、数学の概念であるベクトルがよく利用されます。空間上での位置や方向をうまく記述でき、その数学的な性質が有用だからです。GLSLにおけるベクトルのサイズは最大で4です。要素は<code>vec.x</code>、<code>vec.y</code>、<code>vec.z</code>、<code>vec.w</code>により利用でき、空間上でのそれぞれの座標をあらわします。ただしわれわれが扱っているのは三次元空間であり四次元ではないので、<code>vec.w</code>は空間上の位置をあらわしていないことに注意してください。これは<def>パースペクティブディビジョン</def>を行うために利用されるものです。あとの節でベクトルについてさらに深掘りします。 </note> <p> To set the output of the vertex shader we have to assign the position data to the predefined <var>gl_Position</var> variable which is a <code>vec4</code> behind the scenes. At the end of the <fun>main</fun> function, whatever we set <var>gl_Position</var> to will be used as the output of the vertex shader. Since our input is a vector of size 3 we have to cast this to a vector of size 4. We can do this by inserting the <code>vec3</code> values inside the constructor of <code>vec4</code> and set its <code>w</code> component to <code>1.0f</code> (we will explain why in a later chapter). +頂点シェーダーの出力を設定するためには、あらかじめ定義された四次元ベクトルである<var>gl_Position</var>という変数に位置のデータを割り当てる必要があります。<fun>main</fun>関数の終了時点で<var>gl_Position</var>に割り当てられているものが、頂点シェーダーの出力となります。入力のベクトルは三次元なので、これを四次元に変換する必要があります。ここでは<code>vec3</code>の値を<code>vec4</code>のコンストラクタ内にさしこみ、<code>w</code>の値は<code>1.0f</code>としておきましょう(あとで詳しく説明します)。 </p> <p> The current vertex shader is probably the most simple vertex shader we can imagine because we did no processing whatsoever on the input data and simply forwarded it to the shader's output. In real applications the input data is usually not already in normalized device coordinates so we first have to transform the input data to coordinates that fall within OpenGL's visible region. +こうして構成した頂点シェーダーはなんの処理も行わずに入力値をそのまま出力しているだけなので、おそらく最も単純なものです。実際のアプリケーションでは通常入力データは正規化されていないのでまずはOpenGLの可視領域におさまるように変換しないといけません。 </p> <h2>Compiling a shader</h2> +<h2>シェーダーのコンパイル</h2> <p> We take the source code for the vertex shader and store it in a const C string at the top of the code file for now: </p>