-1

たくさんのことを学ぶ口実として、Android で OpenGL ES 2.0 を使用して 2D ゲームを作成しています。グリッドを作るためにたくさん線を引いているのですが、設定に時間がかかるので、後で描画するオブジェクトを設定している間にロード画面をレンダリングしたいです。

この問題に取り組もうとしているときに、理解できない問題に直面しているので、なぜこの動作が見られるのかという質問があります。

コード:

これは、インスタンスが各行を表すクラスです。

これは、Web で見つけたわずかに変更された例です。私が直面している問題を示すことができるように、それを作成するのにかかる時間を増やすことだけを意図した Thread.sleep への呼び出しがあります。

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import android.opengl.GLES20;

public class LineExample {

    private final String vertexShaderCode =
                "attribute vec4 vPosition;" +
                "void main() {" +
                "   gl_Position = vPosition;" +
                "}";

    private final String fragmentShaderCode =
                "precision mediump float;" +
                "void main() {" +
                "  gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);" +
                "}";

    private int mProgram;
    private FloatBuffer vertexBuffer;
    private ByteBuffer bb;



    // number of coordinates per vertex in this array
    static final int COORDS_PER_VERTEX = 2;
    private final int vertexStride = COORDS_PER_VERTEX * 4; // bytes per vertex
    private float lineCoords[] = new float[2*COORDS_PER_VERTEX];
    private int vertexCount = lineCoords.length / COORDS_PER_VERTEX;

    public LineExample(float[] lineCoords) {

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        this.lineCoords = lineCoords;

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

        // prepare shaders and OpenGL program
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,
                                                   vertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
                                                     fragmentShaderCode);

        mProgram = GLES20.glCreateProgram();             // create empty OpenGL Program
        GLES20.glAttachShader(mProgram, vertexShader);   // add the vertex shader to program
        GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
        GLES20.glLinkProgram(mProgram);                  // create OpenGL program executables

    }

    public void draw() {

        // Add program to OpenGL environment
        GLES20.glUseProgram(mProgram);

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

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

        // Prepare the triangle coordinate data
        GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
                                     GLES20.GL_FLOAT, false,
                                     vertexStride, vertexBuffer);

        // Draw
        GLES20.glDrawArrays(GLES20.GL_LINES, 0, vertexCount);

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

    private 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;
    }

}

レンダラーは次のとおりです。

public class MyRenderer2 implements Renderer {

    LineExample currentLineToRender = null;

    @Override
    public void onDrawFrame(GL10 unused) {
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        if (currentLineToRender!=null){
            currentLineToRender.draw();
        }
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        //initializeLines();
        initializeLinesSameThread();
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    }

    private void initializeLines(){
        float[] waitingLineVerts = {-0.5f,0.0f , 0.5f,0.0f};
        currentLineToRender = new LineExample(waitingLineVerts);
        new Thread(){
            public void run() {
                float[] doneLineVerts = {0.0f,-0.5f , 0.0f,0.5f};
                currentLineToRender = new LineExample(doneLineVerts);
            }
        }.start();
    }

    private void initializeLinesSameThread(){
        float[] waitingLineVerts = {-0.5f,0.0f , 0.5f,0.0f};
        currentLineToRender = new LineExample(waitingLineVerts);
        float[] doneLineVerts = {0.0f,-0.5f , 0.0f,0.5f};
        currentLineToRender = new LineExample(doneLineVerts);
    }

}

目標は、水平線を 5 秒間 (ロード画面に類似) 表示してから、垂直線 (実際のゲーム グリッドに類似) を表示することです。ただし、このコードでは、約 10 秒間暗い画面が表示され、2 番目の線が描画されます。

スレッドが初期化コードでビジーであるため、最初の行を描画していないと考えたので、onDrawFrameメソッドに到達して最初の行を描画できるようにするために、別のスレッドで 2 行目の初期化を呼び出すことにしました ( onSurfaceCreatedで initializeLinesSameThread ()の代わりにinitializeLines( )を呼び出しますが、それを行うと、最初の行しか表示されず、2 番目の行は表示されません。

私の推測では、線の描画メソッドが呼び出されたときに、他のスレッドで行われたいくつかのことはレンダラー スレッドからアクセスできないということです。

私の質問は、なぜこれが起こっているのですか?

(そして、私がやりたいことを達成する方法について提案をいただければ幸いです)

4

1 に答える 1

1

通常、すべての OpenGL 呼び出しを同じスレッドで実行する必要があります。そうしないと、予期しない動作が発生します。

于 2013-03-19T07:43:49.557 に答える