Android向けOpenGL ES2の孊習レッスン2。 䞉角圢を䜜成する

レッスン番号2。 䞉角圢を䜜成する

ここからコアコヌドずアむデアを入手したした。
1. Satia Komatineni、Dave Macklin、Said Hashimi。 プロフェッショナル向けのAndroid 3。 タブレットおよびスマヌトフォン甚のアプリケヌションを䜜成したす。 英語から -M。LLC "I.D. Williams。" 2012-1,024 p。
2. http://www.learnopengles.com/android-lesson-one-getting-started/

最初のレッスンこちらhttps://habrahabr.ru/post/278895/たたはこちらalbatrossgames.blogspot.com/2016/03/opengl-es-2-android-1-opengl.html#moreを ご芧ください  OpenGL ESを䜿甚しお1色で画面を塗り぀ぶす方法を孊びたした。 今床は䞉角圢を描くか、䞉角圢を䜿っお、巊から右に埪環するペットを描きたす。

image1

なぜ䞉角圢なのか 実際、OpenGLには、ドット、線、䞉角圢の3぀のグラフィックプリミティブしかありたせん。 ペットの船䜓台圢ず海長方圢も䞉角圢を䜿甚しお描画されたす。 ご存知のように、空間内のポむントは3぀の座暙x、y、zによっお決定されたす。 図面は平らであるため、図面のすべおのポむントで、0z軞に沿った1぀の座暙画面の平面に垂盎であり、私たちに向かっおいたすはれロになりたす。 たずえば、倧きな垆メむンセヌルの2぀の極点の0xおよび0y軞に沿った座暙を瀺したした。

image2

コヌドでは、掞窟の3぀のポむントの定矩は次のようになりたす。

// this triangle is white-blue. First sail is mainsail final float[] triangle1VerticesData = { // X, Y, Z, // R, G, B, A -0.5f, -0.25f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, -0.25f, 0.0f, 0.8f, 0.8f, 1.0f, 1.0f, 0.0f, 0.56f, 0.0f, 0.8f, 0.8f, 1.0f, 1.0f}; 


ご芧のずおり、浮動小数点デヌタ配列が䜜成されたす。 各ポむントに぀いお、その座暙ず配色が瀺されたす。 最初のポむントは癜なので、赀、緑、青の重み係数は同じで1に等しくなりたすが、他の2぀のピヌクは矎しさのために青になりたす。 ドットは反時蚈回りにバむパスしたす
OpenGLの座暙の次元は任意であり、実際にはデバむスの画面䞊の幅ず高さのピクセル数によっお決定されたす。
ここで、OpenGLのポむントデヌタを転送するバッファヌを䜜成する必芁がありたす。 これは、OpenGLがCに䌌た蚀語で曞かれおいるためです。 したがっお、OpenGLが理解できる別の圢匏にデヌタを倉換し、メモリを割り圓おたす。

 /** How many bytes per float. */ private final int mBytesPerFloat = 4; // Initialize the buffers. mTriangle1Vertices = ByteBuffer.allocateDirect(triangle1VerticesData.length * mBytesPerFloat) .order(ByteOrder.nativeOrder()).asFloatBuffer(); mTriangle1Vertices.put(triangle1VerticesData).position(0); 

画像

各郚分を芋おみたしょう。 たず、ByteBuffer.allocateDirectを䜿甚しおマシンメモリのブロックを割り圓おたした。 このメモリはガベヌゞコレクタヌによっお管理されたせんこれは重芁です。 メモリブロックのサむズをバむト単䜍でメ゜ッドに䌝える必芁がありたす。 頂点はfloat倉数ずしお配列に栌玍され、floatごずに4バむトを占有するため、triangle1VerticesData.length * mBytesPerFloatを枡したす。 プラむベヌト最終int mBytesPerFloat = 4;を思い出しおください。

次の行は、バむトバッファにマシンコヌドでバむトを敎理する方法を瀺しおいたす。 32ビット敎数など、耇数のバむトにたたがる倀になるず、たずえば最䞊䜍の倀から最䞋䜍の倀たで、バむトを異なる順序で曞き蟌むこずができたす。 これは、巊から右ぞ、たたは右から巊ぞず倧量のスペルを入力するようなものです。 気にしたせんが、重芁なこずは、システムず同じ順序を䜿甚するこずです。 泚文ByteOrder.nativeOrderを呌び出しおこれを敎理したす。 最埌に、個々のバむトを盎接凊理しないこずが最善です。 フロヌトを凊理したいので、FloatBufferを呌び出しおメむンバむトを含むFloatBufferを取埗したす。 次に、れロ䜍眮から開始しお、mTriangle1Vertices.puttriangle1VerticesData.position0;を呌び出しお、Dalvikメモリからマシンメモリにデヌタをコピヌしたす。

プロセスが停止するずメモリが解攟されるため、心配する必芁はありたせん。

行列を理解する
マトリックスを理解するための良いレッスンはwww.songho.ca/opengl/gl_transform.htmlです

マトリックスを理解するには、たずOpenGLでオブゞェクトを「芋る」方法を理解する必芁がありたす。
カメラを持っお、垆船の写真を撮りたいず想像しおください。

画像

カメラをT.K.に眮きた​​す。この点を芖点ず呌びたす。 コヌドで芖点を指定しない堎合、カメラはデフォルトで座暙0,0,0のT.O.になりたす。
コヌドでカメラの䜍眮がどのように蚭定されおいるかを芋おみたしょう。

 @Override public void onSurfaceCreated(GL10 glUnused, EGLConfig config) { // Set the background clear color to gray. GLES20.glClearColor(0.5f, 0.5f, 0.7f, 1.0f); // Position the eye behind the origin. final float eyeX = 0.0f; final float eyeY = 0.0f; final float eyeZ = 1.5f; // We are looking toward the distance final float lookX = 0.0f; final float lookY = 0.0f; final float lookZ = -5.0f; // Set our up vector. This is where our head would be pointing were we holding the camera. final float upX = 0.0f; final float upY = 1.0f; final float upZ = 0.0f; // Set the view matrix. This matrix can be said to represent the camera position. // NOTE: In OpenGL 1, a ModelView matrix is used, which is a combination of a model and // view matrix. In OpenGL 2, we can keep track of these matrices separately if we choose. Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ); 

最初は、最初のレッスンで行ったのず同様に、背景色を青灰色に蚭定したす。
 GLES20.glClearColor(0.5f, 0.5f, 0.7f, 1.0f); 

次に、カメラを配眮し、実際にT.Kの座暙を瀺したした。 ご芧のずおり、カメラは0z軞に沿っお1.5単䜍シフトしたす距離OK。
  final float eyeX = 0.0f; final float eyeY = 0.0f; final float eyeZ = 1.5f; 

次のコヌド行では、カメラが芋おいるポむントの座暙を瀺しおいたす。
 final float lookX = 0.0f; final float lookY = 0.0f; final float lookZ = -5.0f; 

次のコヌド行は、カメラの向きたたはベクトルの䜍眮アップを決定したす。 翻蚳が倱敗したため、さたざたな蚘事でこの問題が䞍正確になりたした。 今のコヌドでは
 final float upX = 0.0f; final float upY = 1.0f; final float upZ = 0.0f; 

これは、カメラが通垞配眮されるこずを意味したす。したがっお、氎平なテヌブルに眮いお、t.0でペットを芋る堎合。


T.O.からのように、カメラから3぀のベクトルが出おくるずしたす。 重み係数の最終フロヌトupY = 1.0fを蚭定したら、OpenGLに、0U軞が䞊向きになり、蚘事の冒頭のように画像が衚瀺されるこずを䌝えたす。
しかし、これらの芁玠を入れるず
 final float upX = 1.0f; final float upY = 1.0f; final float upZ = 0.0f; 

゚ミュレヌタで次のように衚瀺されたす。 垆船は䞊り坂に登りたす。

0z軞を芋るず、カメラは反時蚈回りに45床回転したした。 このような組み合わせを䜜成するず
 final float upX = 1.0f; final float upY = 0.0f; final float upZ = 0.0f; 

カメラの0x軞が芋䞊げられ、ボヌトが垂盎に䞊に向かっお航行したす。
すべおのデヌタをsetLookAtMメ゜ッドに枡したす。
Matrix.setLookAtMmViewMatrix、0、eyeX、eyeY、eyeZ、lookX、lookY、lookZ、upX、upY、upZ;

可芖カメラのボリュヌム

次のコヌドを怜蚎しおください。
 @Override public void onSurfaceChanged(GL10 glUnused, int width, int height) { // Set the OpenGL viewport to the same size as the surface. GLES20.glViewport(0, 0, width, height); // Create a new perspective projection matrix. The height will stay the same // while the width will vary as per aspect ratio. final float ratio = (float) width / height; final float left = -ratio; final float right = ratio; final float bottom = -1.0f; final float top = 1.0f; final float near = 1.0f; final float far = 10.0f; Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far); } 

onSurfaceChangedメ゜ッドを䜿甚するず、デバむス自䜓の向きの倉曎を緎習できたす。
゚ミュレヌタでガゞェットをオンにしお、そのような画像を芋おみたしょう
画像
あたり矎しくありたせんが、基本的には私たちが描いたものです。
次のコヌド行は画面サむズを蚭定したす。 たず、画面の巊䞋隅の座暙0,0を蚭定しおから、画面の幅ず高さを蚭定したす。
GLES20.glViewport0、0、幅、高さ;
もう䞀床図面を芋おみたしょう。

画像

カメラが芋る䜓積は、角錐台の䜓積A 1 、B 1 、C 1 、D 1 、A 2 、B 2 、C 2 、D 2 に囲たれおいたす。
最初に、デバむスの幅ず高さの比率比率を芋぀けたす。
最終フロヌト比=フロヌト幅/​​高さ;
次に、可芖の平行六面䜓A 1 、B 1 、C 1 、D 1 の巊偎ず右偎の0xに沿っお座暙を蚭定したす。
最終フロヌト巊= -ratio;
最終フロヌト右=比率;
ボックスの䞋偎ず䞊偎の0yに沿っお座暙を蚭定したすA 1 、B 1 、C 1 、D 1 。
最終フロヌト底= -1.0f;
最終フロヌトトップ= 1.0f;
カメラから前面たでの距離KO 1 
最終フロヌト= 1.0f付近;
カメラから背面たでの距離KO 2 
最終フロヌトfar = 10.0f;
マトリックス倉換を適甚する
Matrix.frustumMmProjectionMatrix、0、巊、右、䞋、䞊、近く、遠い;
䜿甚するマトリックスにはいく぀かの異なるタむプがありたす。
1.モデルのマトリックス。 このマトリックスは、モデルを「䞖界」のどこかに配眮するために䜿甚されたす。 たずえば、車のモデルがあり、それを東1000 mの距離に配眮する堎合、モデルマトリックスを䜿甚したす。
2.ビュヌマトリックス。 このマトリックスはカメラです。 東に1000 mに䜍眮する車を芋たい堎合は、1000 m東に移動する必芁がありたす。 たたは、動かずに残りの䞖界を1000 m西に移動できたす。 これを行うには、ビュヌマトリックスを䜿甚したす。
3.射圱行列。 画面はフラットなので、最終的に画面䞊のビュヌの「プロゞェクト」に倉換し、3Dパヌスペクティブを取埗する必芁がありたす。 これを行うには、射圱行列を䜿甚したす。

頂点シェヌダヌずフラグメントシェヌダヌの定矩
OpenGL ES 2.0の最も単玔な図面でも、シェヌダヌず呌ばれる゜フトりェアセグメントの䜜成が必芁です。 シェヌダヌはOpenGL ES 2.0のコアを圢成したす。 頂点は頂点シェヌダヌによっお凊理され、頂点ポむントのみを凊理したす。 頂点間のスペヌスはフラグメントシェヌダヌを䜿甚しお凊理され、画面䞊のすべおのピクセルを凊理したす。

シェヌダヌを蚘述するために、OpenGL Shading LanguageGLSLが䜿甚されたす。
各シェヌダヌは、䞻に入力、出力、およびプログラムで構成されおいたす。 たず、フォヌムを定矩したす。これは、すべおの倉換を含む結合行列です。 これはすべおの頂点に察しお䞀定であり、それらをスクリヌンに投圱するために䜿甚されたす。 次に、䜍眮ず色の2぀の属性を定矩したす。 これらの属性は、前に定矩したバッファヌから読み取られ、各頂点の䜍眮ず色を指定したす。 次に、䞉角圢党䜓の倀を補間しおフラグメントシェヌダヌに枡すバリ゚ヌション色の倉曎を定矩したす。 フラグメントシェヌダヌに関しおは、各ピクセルの補間倀が含たれたす。

頂点が赀、緑、青になり、画面䞊のサむズが10ピクセルを占める䞉角圢を特定したずしたす。 フラグメントシェヌダヌを実行するず、ピクセルごずに異なる倉化する色が含たれたす。 ある時点で、倉曎は赀になりたすが、赀ず青の䞭間では、マれンタ色になる堎合がありたす。

頂点シェヌダヌを怜蚎しおください
 final String vertexShader = "uniform mat4 u_MVPMatrix; \n" // A constant representing the combined model/view/projection matrix. + "attribute vec4 a_Position; \n" // Per-vertex position information we will pass in. + "attribute vec4 a_Color; \n" // Per-vertex color information we will pass in. + "varying vec4 v_Color; \n" // This will be passed into the fragment shader. + "void main() \n" // The entry point for our vertex shader. + "{ \n" + " v_Color = a_Color; \n" // Pass the color through to the fragment shader. // It will be interpolated across the triangle. + " gl_Position = u_MVPMatrix \n" // gl_Position is a special variable used to store the final position. + " * a_Position; \n" // Multiply the vertex by the matrix to get the final point in + "} \n"; // normalized screen coordinates. 


ナニフォヌムを介しお、蚈算に䜿甚できる倖郚デヌタがシェヌダヌに転送されたす。 ナニフォヌムは読み取り専甚で䜿甚できたす。 ナニフォヌムは、頂点シェヌダヌずフラグメントシェヌダヌの䞡方に枡すこずができたす。 この堎合、ナニフォヌムは1぀だけです。これは、model-view-projection u_MVPMatrixのマトリックスであり、頂点シェヌダヌに枡されたす。 mat4キヌワヌドは、浮動小数点数で構成される4x4マトリックスであるこずを意味したす。 ナニフォヌムは特定の頂点に決しお関連付けられおおらず、グロヌバル定数です。 ナニフォヌムの名前には、通垞、接頭蟞u_が䜿甚されたす。
属性は、頂点の属性です。 頂点にはさたざたな属性を蚭定できたす。 たずえば、空間内の䜍眮の座暙、法線ベクトルの座暙、色。 さらに、任意の属性を頂点シェヌダヌに枡すこずができたす。 属性は頂点のプロパティであるため、各頂点に指定する必芁があるこずを理解するこずが重芁です。 属性は頂点シェヌダヌにのみ枡されたす。 属性は、頂点シェヌダヌに察しお読み取り専甚です。 フラグメントシェヌダヌでは属性を定矩できたせん。 䟿宜䞊、プレフィックスa_で属性を瀺したす。

頂点シェヌダヌで3぀の属性を定矩したす。
属性vec4 a_Position;
倉数a_Positionは、頂点の䜍眮座暙を凊理する頂点属性です。これは4コンポヌネントベクトルvec4です。
頂点カラヌ属性
属性vec4 a_Color;
色補間属性
倉化するvec4 v_Color;
メむン関数コヌドをより詳现に怜蚎しおください。
v_Color = a_Color;
頂点の色に関する情報をフラグメントシェヌダヌに枡したす。
gl_Position = u_MVPMatrix * a_Position;
マトリックスを䜿甚しお頂点の䜍眮を倉換し、新しい倉数gl_Positionに曞き蟌みたす。
gl_Positionシステム倉数は、スクリヌンプレヌンに投圱される頂点の座暙を定矩する4コンポヌネントベクトルです。 gl_Position倉数は頂点シェヌダヌで定矩する必芁がありたす。そうしないず、画面に䜕も衚瀺されたせん。

フラグメントシェヌダヌから始めたしょう。
 final String fragmentShader = "precision mediump float; \n" // Set the default precision to medium. We don't need as high of a // precision in the fragment shader. + "varying vec4 v_Color; \n" // This is the color from the vertex shader interpolated across the // triangle per fragment. + "void main() \n" // The entry point for our fragment shader. + "{ \n" + " gl_FragColor = v_Color; \n" // Pass the color directly through the pipeline. + "} \n"; 

フラグメントシェヌダヌの堎合、高い粟床は必芁ないため、デフォルトの粟床は平均に蚭定されおいたす。 頂点シェヌダヌでは、デフォルトで粟床が高くなっおいたす。
粟密ミディアムフロヌト;
フラグメントシェヌダヌの最終的な目暙は、ピクセルの色を取埗するこずです。 蚈算されたピクセルカラヌはgl_FragColorシステム倉数に曞き蟌たれる必芁がありたす。 最も単玔な䟋では、フラグメントシェヌダヌでピクセルカラヌを蚈算せず、頂点の色から補間によっお取埗したカラヌv_colorの倀を単に割り圓おたす。
gl_FragColor = v_color;

OpenGLでのシェヌダヌのロヌド
 // Load in the vertex shader. int vertexShaderHandle = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER); if (vertexShaderHandle != 0) { // Pass in the shader source. GLES20.glShaderSource(vertexShaderHandle, vertexShader); // Compile the shader. GLES20.glCompileShader(vertexShaderHandle); // Get the compilation status. final int[] compileStatus = new int[1]; GLES20.glGetShaderiv(vertexShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0); // If the compilation failed, delete the shader. if (compileStatus[0] == 0) { GLES20.glDeleteShader(vertexShaderHandle); vertexShaderHandle = 0; } } if (vertexShaderHandle == 0) { throw new RuntimeException("Error creating vertex shader."); } 

プログラムで頂点シェヌダヌずフラグメントシェヌダヌをリンクする
 // Create a program object and store the handle to it. int programHandle = GLES20.glCreateProgram(); if (programHandle != 0) { // Bind the vertex shader to the program. GLES20.glAttachShader(programHandle, vertexShaderHandle); // Bind the fragment shader to the program. GLES20.glAttachShader(programHandle, fragmentShaderHandle); // Bind attributes GLES20.glBindAttribLocation(programHandle, 0, "a_Position"); GLES20.glBindAttribLocation(programHandle, 1, "a_Color"); // Link the two shaders together into a program. GLES20.glLinkProgram(programHandle); // Get the link status. final int[] linkStatus = new int[1]; GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0); // If the link failed, delete the program. if (linkStatus[0] == 0) { GLES20.glDeleteProgram(programHandle); programHandle = 0; } } if (programHandle == 0) { throw new RuntimeException("Error creating program."); } 


頂点シェヌダヌずフラグメントシェヌダヌを䜿甚する前に、プログラムでそれらをリンクする必芁がありたす。 これが、頂点シェヌダヌ出力をフラグメントシェヌダヌ入力に接続するものです。 これにより、プログラムからの入力を枡し、シェヌダヌを䜿甚しお図圢を描画できたす。

新しいプログラムオブゞェクトを䜜成し、成功した堎合は、シェヌダヌをアタッチしたす。 䜍眮ず色のデヌタを属性ずしお枡したいので、これらの属性を関連付ける必芁がありたす。 次に、シェヌダヌを接続したす。

 //New class members /** This will be used to pass in the transformation matrix. */ private int mMVPMatrixHandle; /** This will be used to pass in model position information. */ private int mPositionHandle; /** This will be used to pass in model color information. */ private int mColorHandle; @Override public void onSurfaceCreated(GL10 glUnused, EGLConfig config) { ... // Set program handles. These will later be used to pass in values to the program. mMVPMatrixHandle = GLES20.glGetUniformLocation(programHandle, "u_MVPMatrix"); mPositionHandle = GLES20.glGetAttribLocation(programHandle, "a_Position"); mColorHandle = GLES20.glGetAttribLocation(programHandle, "a_Color"); // Tell OpenGL to use this program when rendering. GLES20.glUseProgram(programHandle); } 

プログラムを正垞にリンクしたら、いく぀かの倧きなタスクを完了し、実際に䜿甚できるようになりたす。 最初のタスクはリンクを取埗するこずで、プログラムにデヌタを転送できたす。 次に、描画の進行䞭にこのプログラムを䜿甚するようOpenGLに指瀺したす。 このチュヌトリアルでは1぀のプログラムのみを䜿甚するため、onDrawFrameの代わりにonSurfaceCreatedに配眮できたす。

透芖投圱のむンストヌル
 // New class members /** Store the projection matrix. This is used to project the scene onto a 2D viewport. */ private float[] mProjectionMatrix = new float[16]; @Override public void onSurfaceChanged(GL10 glUnused, int width, int height) { // Set the OpenGL viewport to the same size as the surface. GLES20.glViewport(0, 0, width, height); // Create a new perspective projection matrix. The height will stay the same // while the width will vary as per aspect ratio. final float ratio = (float) width / height; final float left = -ratio; final float right = ratio; final float bottom = -1.0f; final float top = 1.0f; final float near = 1.0f; final float far = 10.0f; Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far); } 

onSurfaceChangedメ゜ッドは、少なくずも1回、およびサヌフェスが倉曎されるたびに呌び出されたす。 スクリヌン䞊で投圱が倉曎されるたびに投圱マトリックスをリセットする必芁があるため、onSurfaceChangedはこれを行うのに最適な堎所です。

画面にオブゞェクトを衚瀺する
出力はonDrawFrameメ゜ッドで生成されたすGL10 glUnused
䞉角圢が0x軞に沿っお移動するために、倉䜍行列を適甚し、各衚面の曎新に察しおx倉䜍の0.001増加を指定したす。 xが1たたは画面の右端に達したらすぐにれロにしたす。

Matrix.translateMmModelMatrix、0、x + 0.3f、0.0f、0.0f;
drawTrianglemTriangle2Vertices;
ifx <= 1{x =floatx + 0.001;}
その他{x = 0;}
2回目のレッスンでは十分すぎるず思いたす。 倚くの質問が芋萜ずされおおり、それらの理解は埌で来るでしょう。

Android Studioでレッスンを実行したす。

前のレッスンのプロゞェクトを䜿甚し、このコヌドを単玔にコピヌするこずをお勧めしたす。
持っおいない堎合は、最初のOpen GLプロゞェクトを䜜成したす
AndroidManifest.xml

 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.adc2017gmail.firstopenglproject"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <uses-feature android:glEsVersion="0x00020000" android:required="true" /> <activity android:name=".FirstOpenGLProjectActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> 


FirstOpenGLProjectActivity.java

 package com.adc2017gmail.firstopenglproject; import android.app.Activity; import android.app.ActivityManager; import android.content.Context; import android.content.pm.ConfigurationInfo; import android.opengl.GLSurfaceView; import android.os.Bundle; public class FirstOpenGLProjectActivity extends Activity { /** Hold a reference to our GLSurfaceView */ private GLSurfaceView mGLSurfaceView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mGLSurfaceView = new GLSurfaceView(this); // Check if the system supports OpenGL ES 2.0. final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo(); final boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000; if (supportsEs2) { // Request an OpenGL ES 2.0 compatible context. mGLSurfaceView.setEGLContextClientVersion(2); // Set the renderer to our demo renderer, defined below. mGLSurfaceView.setRenderer(new LessonOneRenderer()); } else { // This is where you could create an OpenGL ES 1.x compatible // renderer if you wanted to support both ES 1 and ES 2. return; } setContentView(mGLSurfaceView); } @Override protected void onResume() { // The activity must call the GL surface view's onResume() on activity onResume(). super.onResume(); mGLSurfaceView.onResume(); } @Override protected void onPause() { // The activity must call the GL surface view's onPause() on activity onPause(). super.onPause(); mGLSurfaceView.onPause(); } } 


LessonOneRenderer.java

 package com.adc2017gmail.firstopenglproject; import android.opengl.GLES20; import android.opengl.GLSurfaceView; import android.opengl.Matrix; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; /** * This class implements our custom renderer. Note that the GL10 parameter passed in is unused for OpenGL ES 2.0 * renderers -- the static class GLES20 is used instead. */ public class LessonOneRenderer implements GLSurfaceView.Renderer { /** * Store the model matrix. This matrix is used to move models from object space (where each model can be thought * of being located at the center of the universe) to world space. */ private float[] mModelMatrix = new float[16]; /** * Store the view matrix. This can be thought of as our camera. This matrix transforms world space to eye space; * it positions things relative to our eye. */ private float[] mViewMatrix = new float[16]; /** Store the projection matrix. This is used to project the scene onto a 2D viewport. */ private float[] mProjectionMatrix = new float[16]; /** Allocate storage for the final combined matrix. This will be passed into the shader program. */ private float[] mMVPMatrix = new float[16]; /** Store our model data in a float buffer. */ private final FloatBuffer mTriangle1Vertices; private final FloatBuffer mTriangle2Vertices; private final FloatBuffer mTriangle3Vertices; private final FloatBuffer mTriangle4Vertices; private final FloatBuffer mTriangle5Vertices; private final FloatBuffer mTriangle6Vertices; /** This will be used to pass in the transformation matrix. */ private int mMVPMatrixHandle; /** This will be used to pass in model position information. */ private int mPositionHandle; /** This will be used to pass in model color information. */ private int mColorHandle; /** How many bytes per float. */ private final int mBytesPerFloat = 4; /** How many elements per vertex. */ private final int mStrideBytes = 7 * mBytesPerFloat; /** Offset of the position data. */ private final int mPositionOffset = 0; /** Size of the position data in elements. */ private final int mPositionDataSize = 3; /** Offset of the color data. */ private final int mColorOffset = 3; /** Size of the color data in elements. */ private final int mColorDataSize = 4; private float x; /** * Initialize the model data. */ public LessonOneRenderer() { // Define points for equilateral triangles. // This triangle is white_blue.First sail is mainsail final float[] triangle1VerticesData = { // X, Y, Z, // R, G, B, A -0.5f, -0.25f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, -0.25f, 0.0f, 0.8f, 0.8f, 1.0f, 1.0f, 0.0f, 0.56f, 0.0f, 0.8f, 0.8f, 1.0f, 1.0f}; // This triangle is white_blue..The second is called the jib sail final float[] triangle2VerticesData = { // X, Y, Z, // R, G, B, A -0.25f, -0.25f, 0.0f, 0.8f, 0.8f, 1.0f, 1.0f, 0.03f, -0.25f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, -0.25f, 0.4f, 0.0f, 0.8f, 0.8f, 1.0f, 1.0f}; // This triangle3 is blue. final float[] triangle3VerticesData = { // X, Y, Z, // R, G, B, A -1.0f, -1.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, -0.35f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, -0.35f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f}; // This triangle4 is blue. final float[] triangle4VerticesData = { // X, Y, Z, // R, G, B, A -1.0f, -1.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, -1.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, -0.35f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f}; // This triangle5 is brown. final float[] triangle5VerticesData = { // X, Y, Z, // R, G, B, A -0.4f, -0.3f, 0.0f, 0.7f, 0.3f, 0.4f, 1.0f, -0.4f, -0.4f, 0.0f, 0.7f, 0.3f, 0.4f, 1.0f, 0.3f, -0.3f, 0.0f, 0.7f, 0.3f, 0.4f, 1.0f}; // This triangle6 is brown. final float[] triangle6VerticesData = { // X, Y, Z, // R, G, B, A -0.4f, -0.4f, 0.0f, 0.7f, 0.3f, 0.4f, 1.0f, 0.22f, -0.4f, 0.0f, 0.7f, 0.3f, 0.4f, 1.0f, 0.3f, -0.3f, 0.0f, 0.7f, 0.3f, 0.4f, 1.0f}; // Initialize the buffers. mTriangle1Vertices = ByteBuffer.allocateDirect(triangle1VerticesData.length * mBytesPerFloat) .order(ByteOrder.nativeOrder()).asFloatBuffer(); mTriangle2Vertices = ByteBuffer.allocateDirect(triangle2VerticesData.length * mBytesPerFloat) .order(ByteOrder.nativeOrder()).asFloatBuffer(); mTriangle3Vertices = ByteBuffer.allocateDirect(triangle3VerticesData.length * mBytesPerFloat) .order(ByteOrder.nativeOrder()).asFloatBuffer(); mTriangle4Vertices = ByteBuffer.allocateDirect(triangle4VerticesData.length * mBytesPerFloat) .order(ByteOrder.nativeOrder()).asFloatBuffer(); mTriangle5Vertices = ByteBuffer.allocateDirect(triangle5VerticesData.length * mBytesPerFloat) .order(ByteOrder.nativeOrder()).asFloatBuffer(); mTriangle6Vertices = ByteBuffer.allocateDirect(triangle6VerticesData.length * mBytesPerFloat) .order(ByteOrder.nativeOrder()).asFloatBuffer(); mTriangle1Vertices.put(triangle1VerticesData).position(0); mTriangle2Vertices.put(triangle2VerticesData).position(0); mTriangle3Vertices.put(triangle3VerticesData).position(0); mTriangle4Vertices.put(triangle4VerticesData).position(0); mTriangle5Vertices.put(triangle5VerticesData).position(0); mTriangle6Vertices.put(triangle6VerticesData).position(0); } @Override public void onSurfaceCreated(GL10 glUnused, EGLConfig config) { // Set the background clear color to gray. GLES20.glClearColor(0.5f, 0.5f, 0.7f, 1.0f); // Position the eye behind the origin. final float eyeX = 0.0f; final float eyeY = 0.0f; final float eyeZ = 1.5f; // We are looking toward the distance final float lookX = 0.0f; final float lookY = 0.0f; final float lookZ = -5.0f; // Set our up vector. This is where our head would be pointing were we holding the camera. final float upX = 0.0f; final float upY = 1.0f; final float upZ = 0.0f; // Set the view matrix. This matrix can be said to represent the camera position. // NOTE: In OpenGL 1, a ModelView matrix is used, which is a combination of a model and // view matrix. In OpenGL 2, we can keep track of these matrices separately if we choose. Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ); final String vertexShader = "uniform mat4 u_MVPMatrix; \n" // A constant representing the combined model/view/projection matrix. + "attribute vec4 a_Position; \n" // Per-vertex position information we will pass in. + "attribute vec4 a_Color; \n" // Per-vertex color information we will pass in. + "varying vec4 v_Color; \n" // This will be passed into the fragment shader. + "void main() \n" // The entry point for our vertex shader. + "{ \n" + " v_Color = a_Color; \n" // Pass the color through to the fragment shader. // It will be interpolated across the triangle. + " gl_Position = u_MVPMatrix \n" // gl_Position is a special variable used to store the final position. + " * a_Position; \n" // Multiply the vertex by the matrix to get the final point in + "} \n"; // normalized screen coordinates. final String fragmentShader = "precision mediump float; \n" // Set the default precision to medium. We don't need as high of a // precision in the fragment shader. + "varying vec4 v_Color; \n" // This is the color from the vertex shader interpolated across the // triangle per fragment. + "void main() \n" // The entry point for our fragment shader. + "{ \n" + " gl_FragColor = v_Color; \n" // Pass the color directly through the pipeline. + "} \n"; // Load in the vertex shader. int vertexShaderHandle = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER); if (vertexShaderHandle != 0) { // Pass in the shader source. GLES20.glShaderSource(vertexShaderHandle, vertexShader); // Compile the shader. GLES20.glCompileShader(vertexShaderHandle); // Get the compilation status. final int[] compileStatus = new int[1]; GLES20.glGetShaderiv(vertexShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0); // If the compilation failed, delete the shader. if (compileStatus[0] == 0) { GLES20.glDeleteShader(vertexShaderHandle); vertexShaderHandle = 0; } } if (vertexShaderHandle == 0) { throw new RuntimeException("Error creating vertex shader."); } // Load in the fragment shader shader. int fragmentShaderHandle = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER); if (fragmentShaderHandle != 0) { // Pass in the shader source. GLES20.glShaderSource(fragmentShaderHandle, fragmentShader); // Compile the shader. GLES20.glCompileShader(fragmentShaderHandle); // Get the compilation status. final int[] compileStatus = new int[1]; GLES20.glGetShaderiv(fragmentShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0); // If the compilation failed, delete the shader. if (compileStatus[0] == 0) { GLES20.glDeleteShader(fragmentShaderHandle); fragmentShaderHandle = 0; } } if (fragmentShaderHandle == 0) { throw new RuntimeException("Error creating fragment shader."); } // Create a program object and store the handle to it. int programHandle = GLES20.glCreateProgram(); if (programHandle != 0) { // Bind the vertex shader to the program. GLES20.glAttachShader(programHandle, vertexShaderHandle); // Bind the fragment shader to the program. GLES20.glAttachShader(programHandle, fragmentShaderHandle); // Bind attributes GLES20.glBindAttribLocation(programHandle, 0, "a_Position"); GLES20.glBindAttribLocation(programHandle, 1, "a_Color"); // Link the two shaders together into a program. GLES20.glLinkProgram(programHandle); // Get the link status. final int[] linkStatus = new int[1]; GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0); // If the link failed, delete the program. if (linkStatus[0] == 0) { GLES20.glDeleteProgram(programHandle); programHandle = 0; } } if (programHandle == 0) { throw new RuntimeException("Error creating program."); } // Set program handles. These will later be used to pass in values to the program. mMVPMatrixHandle = GLES20.glGetUniformLocation(programHandle, "u_MVPMatrix"); mPositionHandle = GLES20.glGetAttribLocation(programHandle, "a_Position"); mColorHandle = GLES20.glGetAttribLocation(programHandle, "a_Color"); // Tell OpenGL to use this program when rendering. GLES20.glUseProgram(programHandle); } @Override public void onSurfaceChanged(GL10 glUnused, int width, int height) { // Set the OpenGL viewport to the same size as the surface. GLES20.glViewport(0, 0, width, height); // Create a new perspective projection matrix. The height will stay the same // while the width will vary as per aspect ratio. final float ratio = (float) width / height; final float left = -ratio; final float right = ratio; final float bottom = -1.0f; final float top = 1.0f; final float near = 1.0f; final float far = 10.0f; Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far); } @Override public void onDrawFrame(GL10 glUnused) { GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT); // Draw the triangle facing straight on. Matrix.setIdentityM(mModelMatrix, 0); Matrix.translateM(mModelMatrix, 0, x, 0.0f, 0.0f); drawTriangle(mTriangle1Vertices); // Draw triangle_2. Matrix.setIdentityM(mModelMatrix, 0); Matrix.translateM(mModelMatrix, 0, x + 0.3f, 0.0f, 0.0f); drawTriangle(mTriangle2Vertices); if(x<=1){x = (float) (x + 0.001);} else {x=0;} // Draw triangle_3. Matrix.setIdentityM(mModelMatrix, 0); drawTriangle(mTriangle3Vertices); // Draw triangle_4. Matrix.setIdentityM(mModelMatrix, 0); drawTriangle(mTriangle4Vertices); // Draw triangle_5. Boat Matrix.setIdentityM(mModelMatrix, 0); Matrix.translateM(mModelMatrix, 0, x, 0.0f, 0.0f); //Matrix.rotateM(mModelMatrix, 0, 0, 0.0f, 0.0f, 1.0f); drawTriangle(mTriangle5Vertices); // Draw triangle_6. Boat Matrix.setIdentityM(mModelMatrix, 0); Matrix.translateM(mModelMatrix, 0, x, 0.0f, 0.0f); //Matrix.rotateM(mModelMatrix, 0, 0, 0.0f, 0.0f, 1.0f); drawTriangle(mTriangle6Vertices); } /** * Draws a triangle from the given vertex data. * * @param aTriangleBuffer The buffer containing the vertex data. */ private void drawTriangle(final FloatBuffer aTriangleBuffer) { // Pass in the position information aTriangleBuffer.position(mPositionOffset); GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false, mStrideBytes, aTriangleBuffer); GLES20.glEnableVertexAttribArray(mPositionHandle); // Pass in the color information aTriangleBuffer.position(mColorOffset); GLES20.glVertexAttribPointer(mColorHandle, mColorDataSize, GLES20.GL_FLOAT, false, mStrideBytes, aTriangleBuffer); GLES20.glEnableVertexAttribArray(mColorHandle); // This multiplies the view matrix by the model matrix, and stores the result in the MVP matrix // (which currently contains model * view). Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0); // This multiplies the modelview matrix by the projection matrix, and stores the result in the MVP matrix // (which now contains model * view * projection). Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0); GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0); GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3); } } 



1. , , . Android 3 . .: . . – .: «..». 2012 – 1024 .
2. http://www.learnopengles.com/android-lesson-one-getting-started/
3. http://andmonahov.blogspot.com/2012/10/opengl-es-20-1.html
4. https://www.opengl.org/sdk/docs/tutorials/ClockworkCoders/attributes.php
5. https://www.khronos.org/opengles/sdk/docs/reference_cards/OpenGL-ES-2_0-Reference-card.pdf

Source: https://habr.com/ru/post/J305796/


All Articles