2016-09-28 13 views
0

OpenGL ES 2.0で四角形を描き、その上に動的テキストを挿入したいと考えました。私はthisポスト(これはOpenGL ES 2.0に移植しなければなりませんでした)とLearn OpenGL ES Tutorialという4つのレッスンの指示を組み合わせようとしています。AndroidとOpenGL ES 2.0で正方形にテキストを描画する方法

私はちょうどGLSurfaceViewを使用して活性を有する:

public class TexturedSquareDrawActivity extends Activity { 

    private GLSurfaceView mGLView; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     mGLView = new MyGLSurfaceViewTexture(this); 
     setContentView(mGLView); 
    } 
} 

マイGLSurfaceViewばかりレンダラを作成し、それを設定します。

public class MyGLSurfaceViewTexture extends GLSurfaceView { 
    private final MyGLRendererTexture mRenderer; 

    public MyGLSurfaceViewTexture(Context context){ 
     super(context); 

     // Create an OpenGL ES 2.0 context 
     setEGLContextClientVersion(2); 

     mRenderer = new MyGLRendererTexture(context); 

     // Set the Renderer for drawing on the GLSurfaceView 
     setRenderer(mRenderer); 
    } 
} 

それから私はこのようなTextureSquareクラスを定義します。

public class TexturedSquare { 

    private final Context mContext; 
    private FloatBuffer vertexBuffer; 
    private ShortBuffer drawListBuffer; 

    private int mProgram; 

    private final String vertexShaderCode = 
      // This matrix member variable provides a hook to manipulate 
      // the coordinates of the objects that use this vertex shader 
      "uniform mat4 uMVPMatrix;" + 
        "attribute vec4 vPosition;" + 
        "attribute vec2 a_TexCoordinate;" + 
        "varying vec2 v_TexCoordinate;" + 
        "void main() {" + 
        // the matrix must be included as a modifier of gl_Position 
        // Note that the uMVPMatrix factor *must be first* in order 
        // for the matrix multiplication product to be correct. 
        " gl_Position = uMVPMatrix * vPosition;" + 
        " v_TexCoordinate = a_TexCoordinate;" + 
        "}"; 

    private final String fragmentShaderCode = 
      "precision mediump float;" + 
        "uniform sampler2D u_Texture;" + 
        "uniform vec4 vColor;" + 
        "varying vec2 v_TexCoordinate;" + 
        "void main() {" + 
//     " gl_FragColor = vColor;" + 
        " gl_FragColor = vColor * texture2D(u_Texture, v_TexCoordinate);" + 
        "}"; 
    private int mMVPMatrixHandle; 


    private int mPositionHandle; 
    private int mColorHandle; 


    // number of coordinates per vertex in this array 
    static final int COORDS_PER_VERTEX = 3; 

    private short drawOrder[] = {0, 1, 2, 0, 2, 3}; // order to draw vertices 


    private final float[] mColor; 

    private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex 


    /** 
    * Store our model data in a float buffer. 
    */ 
    private final FloatBuffer mCubeTextureCoordinates; 

    /** 
    * This will be used to pass in the texture. 
    */ 
    private int mTextureUniformHandle; 

    /** 
    * This will be used to pass in model texture coordinate information. 
    */ 
    private int mTextureCoordinateHandle; 

    /** 
    * Size of the texture coordinate data in elements. 
    */ 
    private final int mTextureCoordinateDataSize = 2; 

    /** 
    * This is a handle to our texture data. 
    */ 
    private int mTextureDataHandle; 

    // S, T (or X, Y) 
    // Texture coordinate data. 
    // Because images have a Y axis pointing downward (values increase as you move down the image) while 
    // OpenGL has a Y axis pointing upward, we adjust for that here by flipping the Y axis. 
    // What's more is that the texture coordinates are the same for every face. 
    final float[] cubeTextureCoordinateData = 
      { 
        // Front face 
        0.0f, 0.0f, 
        0.0f, 1.0f, 
        1.0f, 0.0f, 
        0.0f, 1.0f, 
        1.0f, 1.0f, 
        1.0f, 0.0f, 
      }; 

    public TexturedSquare(Context context, final float[] squareCoords, final float[] color) { 
     mContext = context; 
     mColor = color; 

     // initialize vertex byte buffer for shape coordinates 
     ByteBuffer bb = ByteBuffer.allocateDirect(
       // (# of coordinate values * 4 bytes per float) 
       squareCoords.length * 4); 
     bb.order(ByteOrder.nativeOrder()); 
     vertexBuffer = bb.asFloatBuffer(); 
     vertexBuffer.put(squareCoords); 
     vertexBuffer.position(0); 

     // initialize byte buffer for the draw list 
     ByteBuffer dlb = ByteBuffer.allocateDirect(
       // (# of coordinate values * 2 bytes per short) 
       drawOrder.length * 2); 
     dlb.order(ByteOrder.nativeOrder()); 
     drawListBuffer = dlb.asShortBuffer(); 
     drawListBuffer.put(drawOrder); 
     drawListBuffer.position(0); 

     mCubeTextureCoordinates = ByteBuffer.allocateDirect(cubeTextureCoordinateData.length * 4) 
       .order(ByteOrder.nativeOrder()).asFloatBuffer(); 
     mCubeTextureCoordinates.put(cubeTextureCoordinateData).position(0); 

     linkShaderCode(); 
    } 

    private void linkShaderCode() { 
     int vertexShader = MyGLRendererTexture.loadShader(GLES20.GL_VERTEX_SHADER, 
       vertexShaderCode); 
     int fragmentShader = MyGLRendererTexture.loadShader(GLES20.GL_FRAGMENT_SHADER, 
       fragmentShaderCode); 

     // create empty OpenGL ES Program 
     mProgram = GLES20.glCreateProgram(); 

     // add the vertex shader to program 
     GLES20.glAttachShader(mProgram, vertexShader); 

     // add the fragment shader to program 
     GLES20.glAttachShader(mProgram, fragmentShader); 

     // creates OpenGL ES program executables 
     GLES20.glLinkProgram(mProgram); 
    } 

    public void draw(float[] mvpMatrix) { 
     // Add program to OpenGL ES environment 
     GLES20.glUseProgram(mProgram); 

     // get handle to vertex shader's vPosition member 
     mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition"); 

     // Enable a handle to the triangle vertices 
     GLES20.glEnableVertexAttribArray(mPositionHandle); 

     // Prepare the square coordinate data 
     // Tell OpenGL how to handle the data in the vertexBuffer 
     GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, 
       GLES20.GL_FLOAT, false, 
       vertexStride, vertexBuffer); 

     // get handle to fragment shader's vColor member 
     mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor"); 

     // Set color for drawing the square 
     // Pass the color to the shader 
     GLES20.glUniform4fv(mColorHandle, 1, mColor, 0); 

     // get handle to shape's transformation matrix 
     mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); 

     // Pass the projection and view transformation to the shader 
     GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0); 

     // Load the texture 
//  mTextureDataHandle = TextureHelper.loadTexture(mContext, R.drawable.background); 
     mTextureDataHandle = TextureHelper.loadText(mContext, ""); 

     mTextureUniformHandle = GLES20.glGetUniformLocation(mProgram, "u_Texture"); 
     mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgram, "a_TexCoordinate"); 


     GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle); 
     GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 
       0, mCubeTextureCoordinates); 

     // Set the active texture unit to texture unit 0. 
     GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 

     // Bind the texture to this unit. 
     GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle); 

     // Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0. 
     GLES20.glUniform1i(mTextureUniformHandle, 0); 

     GLES20.glDrawElements(
       GLES20.GL_TRIANGLES, drawOrder.length, 
       GLES20.GL_UNSIGNED_SHORT, drawListBuffer); 

     // Disable vertex array 
     GLES20.glDisableVertexAttribArray(mPositionHandle); 
    } 
} 

レンダラーは2つの四角形を描画します。

public class MyGLRendererTexture implements GLSurfaceView.Renderer { 

    // mMVPMatrix is an abbreviation for "Model View Projection Matrix" 
    private final float[] mMVPMatrix = new float[16]; 
    private final float[] mProjectionMatrix = new float[16]; 
    private final float[] mViewMatrix = new float[16]; 
    private final Context mContext; 

    private TexturedSquare mTexturedSquare; 
    private TexturedSquare mTexturedSquare2; 

    static float squareCoords[] = { 
      -0.5f, 0.5f, 0.0f, // top left 
      -0.5f, -0.5f, 0.0f, // bottom left 
      0.5f, -0.5f, 0.0f, // bottom right 
      0.5f, 0.5f, 0.0f}; // top right 
    // Set color with red, green, blue and alpha (opacity) values 
    float color[] = {0.63671875f, 0.76953125f, 0.22265625f, 1.0f}; 

    static float squareCoords2[] = { 
      -1.0f, 0.7f, 0.0f, // top left 
      -1.0f, 0.8f, 0.0f, // bottom left 
      -0.8f, 0.8f, 0.0f, // bottom right 
      -0.8f, 0.7f, 0.0f}; // top right 
    // Set color with red, green, blue and alpha (opacity) values 
    float color2[] = {0.11111111f, 0.26953125f, 0.52265625f, 1.0f}; 

    public MyGLRendererTexture(
      Context context) { 
     mContext = context; 
    } 


    public static int loadShader(int type, String shaderCode) { 

     // create a vertex shader type (GLES20.GL_VERTEX_SHADER) 
     // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER) 
     int shader = GLES20.glCreateShader(type); 

     // add the source code to the shader and compile it 
     GLES20.glShaderSource(shader, shaderCode); 
     GLES20.glCompileShader(shader); 

     return shader; 
    } 

    @Override 
    public void onSurfaceCreated(GL10 unused, EGLConfig config) { 
     // Set the background frame color 
     GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 
     // initialize a triangle 
     // initialize a square 
     mTexturedSquare = new TexturedSquare(mContext, squareCoords, color); 
     mTexturedSquare2 = new TexturedSquare(mContext, squareCoords2, color2); 
    } 


    @Override 
    public void onSurfaceChanged(GL10 unused, int width, int height) { 
     GLES20.glViewport(0, 0, width, height); 

     float ratio = (float) width/height; 

     // this projection matrix is applied to object coordinates 
     // in the onDrawFrame() method 
     Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7); 
    } 

    @Override 
    public void onDrawFrame(GL10 unused) { 
     // Redraw background color 
     GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 

     // Set the camera position (View matrix) 
     Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f); 

     // Calculate the projection and view transformation 
     Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0); 

     mTexturedSquare.draw(mMVPMatrix); 
     mTexturedSquare2.draw(mMVPMatrix); 
    } 
} 

そして最後に、私は、上のコードで使用していヘルパーメソッドを定義するヘルパークラスを持っている:最初のものは、テクスチャされなければなりません。

public class TextureHelper { 
    public static int loadTexture(final Context context, final int resourceId) { 
     final int[] textureHandle = new int[1]; 

     GLES20.glGenTextures(1, textureHandle, 0); 

     if (textureHandle[0] != 0) { 
      final BitmapFactory.Options options = new BitmapFactory.Options(); 
      options.inScaled = false; // No pre-scaling 

      // Read in the resource 
      final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options); 

      // Bind to the texture in OpenGL 
      GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]); 

      // Set filtering 
      GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); 
      GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); 

      // Load the bitmap into the bound texture. 
      GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); 

      // Recycle the bitmap, since its data has been loaded into OpenGL. 
      bitmap.recycle(); 
     } 

     if (textureHandle[0] == 0) { 
      throw new RuntimeException("Error loading texture."); 
     } 

     return textureHandle[0]; 
    } 

    public static int loadText(final Context context, String text) { 
     final int[] textureHandle = new int[1]; 

     GLES20.glGenTextures(1, textureHandle, 0); 

     if (textureHandle[0] != 0) { 

      // Create an empty, mutable bitmap 
      Bitmap bitmap = Bitmap.createBitmap(256, 256, Bitmap.Config.ARGB_4444); 
       // get a canvas to paint over the bitmap 
      Canvas canvas = new Canvas(bitmap); 
      bitmap.eraseColor(0); 

      // get a background image from resources 
      // note the image format must match the bitmap format 
      Drawable background = context.getResources().getDrawable(R.drawable.background); 
      background.setBounds(0, 0, 256, 256); 
      background.draw(canvas); // draw the background to our bitmap 

      // Draw the text 
      Paint textPaint = new Paint(); 
      textPaint.setTextSize(32); 
      textPaint.setAntiAlias(true); 
      textPaint.setARGB(0xff, 0x00, 0x00, 0x00); 
      // draw the text centered 
      canvas.drawText(text, 16,112, textPaint); 

      // Bind to the texture in OpenGL 
      GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]); 

      // Set filtering 
      GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); 
      GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); 

      // Load the bitmap into the bound texture. 
      GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); 

      // Recycle the bitmap, since its data has been loaded into OpenGL. 
      bitmap.recycle(); 
     } 

     if (textureHandle[0] == 0) { 
      throw new RuntimeException("Error loading texture."); 
     } 

     return textureHandle[0]; 
    } 
} 

しかし、両方の三角形についてテクスチャが描画されます。 テクスチャを一度描き、正方形内に水平に配置するにはどうすればよいですか?

私は、正方形が2つの三角形を描くことによって描かれていることを理解します。テクスチャは同じように配置されていることを理解しています。しかし、私はOpenGLにこのテクスチャを正方形内に一度だけ配置するように指示する方法はわかりません。

EDIT:

私は今、テクスチャ座標に編集した:

この結果として
final float[] cubeTextureCoordinateData = 
{ 
    -0.5f, 0.5f, 
    -0.5f, -0.5f, 
    0.5f, -0.5f, 
    0.5f, 0.5f 
} 

First

これらの座標:

-1.0f, 1.0f, 
-1.0f, -1.0f, 
1.0f, -1.0f, 
1.0f, 1.0f 
この内3210

結果:

Second

これらの座標:

0.5f, -0.5f, 
0.5f, 0.5f, 
-0.5f, 0.5f, 
-0.5f, -0.5f 

この中に結果:

Third

そして、これらの座標:

1.0f, -1.0f, 
1.0f, 1.0f, 
-1.0f, 1.0f, 
-1.0f, -1.0f 
この中

結果:

Fourth

だから第四のアプローチは、「最も正しいもの」のようです。右下にテキストが描かれています。私の広場は4つの小さな正方形に分けられているようです。テクスチャとして、私はこの写真を使用するので:

texture

これは4つの部分に分かれているのはなぜ?

+1

キューブのテクスチャ座標に問題があるかどうかはわかりませんが、キューブのテクスチャの座標は逆向きです。通常は、右手のルールに従います。あなたの最初のセットは右ではなく左に回転します。 – Ben

+0

はいそうかもしれません。私の編集を見てください。たぶん、どのテクスチャcoordiantesを正しく回転させるために使用しなければならないかを正確に教えてくれるでしょうか? – unlimited101

+1

なぜ-1対1か。私はあなたが0から1を使いたいと思います。だから{1、0}、{1,1}、{0,1}、{0、0}。 OpenGLのテクスチャ座標が0から1になることを覚えておくことが重要です。 – Ben

答えて

1

GLESは、デフォルトでテクスチャを繰り返すように設定しているため、パラメータを変更する必要があります。

GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); 
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); 

また、あなたが使用しているチュートリアルはかなり役に立ちました。ここではかなり役に立ちました。 https://www.khronos.org/opengles/sdk/docs/man/

+0

ありがとうございますが、私には新しい座標がありますが、このコードの実装と実装の間に違いはありません。しかし、繰り返し描かれていないのに、テクスチャのレンダリングが繰り返されているのでしょうか?パフォーマンスの問題については、これらのパラメータを保持しますか? – unlimited101

+0

私は2つのパフォーマンスの違いについて肯定的ではありませんが、テクスチャをラップしないつもりなら、これらを使用することをお勧めします。それは、あなたのデバイスのリピートは、ドキュメントが必要であると言われていても、デフォルトではないことがあります。モバイルでOpenGLを使うと、あなたが望む動作を定義し、デフォルトに依存しないことが常にベストであることがわかります。 – Ben

0

OpenGLに任意のUIコンポーネントを描画するには、キャンバスを作成してOpenGLに使用する必要があります。

Bitmap textedBitmap = drawTextToBitmap(); 
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, textedBitmap, 0); 



private Bitmap drawTextToBitmap() { 
    // TODO Auto-generated method stub 

    Bitmap bitmap = Bitmap.createBitmap(256, 256, Bitmap.Config.ARGB_4444); 
    // get a canvas to paint over the bitmap 
    Canvas canvas = new Canvas(bitmap); 
    bitmap.eraseColor(android.graphics.Color.TRANSPARENT); 

    canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); 



    TextPaint textPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); 
    Paint textPaint = new Paint(); 
    textPaint.setStyle(Paint.Style.FILL); 
    textPaint.setAntiAlias(true); 
    textPaint.setColor(Color.BLACK); 
    textPaint.setTextSize(10); 

    TextView tv = new TextView(context); 
    tv.setTextColor(Color.BLACK); 
    tv.setTextSize(10); 

    String text = "DEMO TEXT"; 

    tv.setText(text); 
    tv.setEllipsize(TextUtils.TruncateAt.END); 
    tv.setMaxLines(4); 
    tv.setGravity(Gravity.BOTTOM); 
    tv.setPadding(8, 8, 8, 50); 
    tv.setDrawingCacheEnabled(true); 
    tv.measure(MeasureSpec.makeMeasureSpec(canvas.getWidth(), 
      MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
      canvas.getHeight(), MeasureSpec.EXACTLY)); 
    tv.layout(0, 0, tv.getMeasuredWidth(), tv.getMeasuredHeight()); 



    LinearLayout parent = null; 
    if (bitmap != null && !bitmap.isRecycled()) { 
     parent = new LinearLayout(context); 

     parent.setDrawingCacheEnabled(true); 
     parent.measure(MeasureSpec.makeMeasureSpec(canvas.getWidth(), 
       MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
       canvas.getHeight(), MeasureSpec.EXACTLY)); 
     parent.layout(0, 0, parent.getMeasuredWidth(), 
       parent.getMeasuredHeight()); 

     parent.setLayoutParams(new LinearLayout.LayoutParams(
       LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); 
     parent.setOrientation(LinearLayout.VERTICAL); 

     parent.setBackgroundColor(context.getResources().getColor(R.color.transpernt)); 


     parent.addView(tv); 

    } else { 
     // write code to recreate bitmap from source 
     // Write code to show bitmap to canvas 
    } 

    canvas.drawBitmap(parent.getDrawingCache(), 0, 0, textPaint); 

    tv.setDrawingCacheEnabled(false); 
    iv.setDrawingCacheEnabled(false); 
    parent.setDrawingCacheEnabled(false); 

    return bitmap; 

} 
関連する問題