我正在用Android上的OpenGL ES 2.0製作2D遊戲,作爲學習一堆東西的藉口。我繪製了許多線條來製作網格,但設置所有內容需要時間,並且我希望在設置稍後將繪製的對象時呈現加載屏幕。爲什麼在渲染線程之外的線程上實例化線條時不會畫線?
在試圖解決這個問題時,我遇到了一個我無法理解的問題,所以我的問題是爲什麼我會看到這種行爲。
的代碼:
這是其實例將代表每行的類:
這僅僅是一個略微變形例我在網上找到。有一個調用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秒,然後繪製第二行。
我盤算了一下,線程忙於初始化代碼,因此它不是畫的第一線,所以允許它去的onDrawFrame方法,繪製的第一線,我決定把第二初始化在另一個線程())通過調用initializeLines(的代替initializeLinesSameThread(上onSurfaceCreated)線,但這樣做,我只看到第一行,我從來沒有看到第二個。
我的猜測是,在線程的draw方法被調用時,渲染器線程無法訪問其他線程中完成的某些事情。
我的問題是爲什麼會發生這種情況?
(我會很感激,如果你能給我如何實現我想要做一個建議)
感謝您的評論,我覺得我需要解釋一些事情:1.我在另一個線程中調用第二行的原因是允許渲染器的onDrawFrame()繪製第一行(類似於加載屏幕),而我加載所有實際的遊戲資產。 2.我解釋了Thread.sleep只是爲了顯示我面臨的問題,否則即使按照我的預期工作,我也不會看到第一行。 3. vertexCount始終是相同的(2),它是COORDS_PER_VERTEX和lineCoors長度的函數。這可能會更清楚,但我選擇了離開它,因爲它在我從它得到的教程中。 – Smig 2013-03-19 12:11:12
4.算法應該在渲染器的currentLineToRender變量中分配第一行的實例,然後將第二行分配給該變量。如果足夠的時間在兩者之間傳遞,並且如果可以在另一個線程中初始化第二行,則應在屏幕中繪製第一行。否則,我在初始化所有遊戲資產時看不到如何繪製加載屏幕。 – Smig 2013-03-19 12:13:57
對不起,我用線程睡眠重讀了部分,你對vertexCount的東西是正確的。但無論如何,你不能使用另一個線程來初始化第二行。 OpenGL不能在另一個線程中使用。所以所有的gl調用都必須在渲染器線程中完成。 – Dirk 2013-03-19 12:35:48