为什么 GLES20.glCreateShader 总是 returns 0?

Why does GLES20.glCreateShader always returns 0?

我正在尝试使用 java 在 android 中制作一个 OpenGL ES 应用程序并且我有 运行 一个主要问题:

GLES20.glCreateShader(type)(输入 beeing GLES20.GL_VERTEX_SHADER 或 GLES20.GL_FRAGMENT_SHADER)总是 returns 0.

为清楚起见,这是我的 glSurfaceView 的代码:

//Warning: I'm no where near finished 
//and cleanup needs to be made once I get it working.
//If something looks weird or makes no sense, it's part of debugging or testing

public class renderer implements GLSurfaceView.Renderer{
    
    private Object obj;
    public StaticShader shader;
    private Object ball;
    
    private int bytePerFloat = 4;
    private int stride = 3*bytePerFloat; //#of elements * bpf
    
    private int positionOffset = 0;
    private int positionSize = 3;
    
    //private int colorOffset = 3;
    //private int colorSize = 4;
    
    private ObjectLoader objectLoader;
    private AssetManager assets;
    private Context context;
    
    //The important part is from here...

    renderer(AssetManager a, Context b){
      assets = a;
      context = b;
    }
    
    public void onSurfaceCreated(GL10 gl, EGLConfig config){
        
        shader = new StaticShader(assets, context);
        
        float[] verts = 
        {
            //x,y,z
            //r,g,b,a
            0.5f,0.5f,0.0f,
            
            0.5f,-0.5f,0.0f,
            
            -0.5f,-0.5f,0.0f,
            
            -0.5f,0.5f,0.0f
        };
        
        int[] indices = {
          0,1,3,
          3,1,2
        };
        
        //obj = new Object(verts,indices,shader,bytePerFloat);
        //ball = objectLoader.LoadFromFile("ball.obj",shader, bytePerFloat);
    }
    
    //... To here
    
    public void onSurfaceChanged(GL10 gl, int width, int height){
        GLES20.glViewport(0,0,width,height);
    }
    
    public void onDrawFrame(GL10 gl){
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        if(shader.isCompiled && shader.hasFoundFile && shader.canReadFile){
            GLES20.glClearColor(0.0f,1.0f,0.0f,1.0f);
        }else{
            GLES20.glClearColor(1.0f,0.0f,0.0f,1.0f);
        }
        //render(obj);
        //render(ball);
    }
    
    private void render(Object object){
      try{
        object.getShader().start();
        
        GLES30.glBindVertexArray(object.getVaoID());
        GLES30.glEnableVertexAttribArray(0);
        
        GLES30.glDrawElements(GLES20.GL_TRIANGLES, object.getVertCount(), GLES30.GL_UNSIGNED_INT,0);
        
        GLES30.glDisableVertexAttribArray(0);
        GLES30.glBindVertexArray(0);
        
        object.getShader().stop();
      }catch(Exception e){
        
      }
    }
}

StaticShader 目前基本上实现了 ShaderProgram:

public abstract class ShaderProgram {
  
  private int programID;
  private int vertexShaderID;
  private int fragmentShaderID;
  
  public boolean hasFoundFile = true;
  public boolean isCompiled = true;
  public boolean canReadFile = true;
  
  public ShaderProgram (AssetManager assets, Context context, String vertexFile, String fragmentFile){
    
    //int shdID = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
    //Toast.makeText(context,Integer.toString(shdID),Toast.LENGTH_LONG).show();
    //Toast.makeText(context,EGL14.eglGetCurrentContext().toString(),Toast.LENGTH_LONG).show();
 
    //ShaderID = loadShader(assets, context, vertexFile, GLES20.GL_VERTEX_SHADER);
    //fragmentShaderID = loadShader(assets,context, fragmentFile, GLES20.GL_FRAGMENT_SHADER);
    
    programID = GLES20.glCreateProgram();
    GLES20.glAttachShader(programID, vertexShaderID);
    GLES20.glAttachShader(programID, fragmentShaderID);
    GLES20.glLinkProgram(programID);
    GLES20.glValidateProgram(programID);
  }
  
  public void start(){
    GLES20.glUseProgram(programID);
  }
  
  public void stop(){
    GLES20.glUseProgram(0);
  }
  
  protected abstract void bindAttributes();
  
  protected void bindAttribute(int attribute, String variableName){
    GLES20.glBindAttribLocation(programID, attribute, variableName);
  }
  
  private int loadShader(AssetManager assets, Context context,String fileName, int type){
    int shaderID = 0;
    try{
      InputStream file = assets.open(fileName);
      Scanner scan = new Scanner(file);
      String code = new String();
      while(scan.hasNext()){
        code = new String(code + scan.nextLine() + "/n");
      }
      
      shaderID = GLES20.glCreateShader(type);
      //GLES20.glShaderSource(shaderID, code);
      //Toast.makeText(context,Integer.toString(shaderID),Toast.LENGTH_LONG).show();
      //GLES20.glCompileShader(shaderID);
      int[] compileStatus = new int[1];
      GLES20.glGetShaderiv(shaderID,GLES20.GL_COMPILE_STATUS,compileStatus,0);
      if(compileStatus[0] == 0){
        //Toast.makeText(context,GLES20.glGetShaderInfoLog(),Toast.LENGTH_LONG).show();
        GLES20.glDeleteShader(shaderID);
        isCompiled = false;
      }
    }catch(FileNotFoundException e){
      hasFoundFile = false;
    }catch(IOException e){
      canReadFile = false;
    }catch(Exception e){
      isCompiled = false;
    }
   
    
    return shaderID;
    
  }
}

这是启动器 class:

public class MainActivity extends Activity {
    
    private renderer surface;
    private GLSurfaceView surfaceView;
    private int STORAGE_PERMISSION_CODE = 1;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        surfaceView = new GLSurfaceView(this);
        surfaceView.setEGLContextClientVersion(2);
        surface = new renderer(getAssets(),getApplicationContext());
        surfaceView.setRenderer(surface);
        setContentView(surfaceView);
    }
    
    protected void onPause(){
        super.onPause();
        surfaceView.onPause();
    }
    
    protected void onResume(){
        super.onResume();
        surfaceView.onResume();
    }

}

glGetError says GL_NO_ERROR and I call the the function in the initialisation of a class made in the initialisation of the glSurfaceView. I'm not using onSurfaceCreated, because I need the AssetManager and the Context of the app

我认为这是你的问题。 glSurfaceView 的 OpenGLES 上下文仅绑定到 GLThread。您确实需要将所有 OpenGLES 代码置于 glSurfaceView.Renderer 的一个函数的下游,例如onSurfaceCreatedonDrawFrame.

函数 eglGetCurrentContext 可以告诉您是否有 OpenGLES 上下文绑定到当前线程。在没有上下文的情况下调用任何 OpenGLES 函数将导致未通过 glGetError 报告的错误。在调试版本中,我在每个 OpenGLES 调用中检查上下文和 glGetError

我不知道在 GLThread 上使用 AssetManager 和 Context 有什么真正的障碍。