如何调试 android 上的 OpenglES 着色器错误?
How to debug OpenglES shader errors on android?
我正在为 android 构建一个 opengl es 应用程序,我在编译着色器时遇到了一些问题。有谁知道如何让 shaderInfoLog 显示在屏幕上?
这里有一些代码可以更好地理解:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
surfaceView=new GLSurfaceView(this);
Renderer renderer = new Renderer();
surfaceView.setEGLContextClientVersion(2);
surfaceView.setRenderer(renderer);
setContentView(surfaceView);
}
}
渲染器class
public class Renderer implements GLSurfaceView.Renderer{
private Object tri;
private int glError = 0;
Renderer(){
}
public void onSurfaceCreated(GL10 gl,EGLConfig config){
float[] positions = //simple quad vertices
{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[] index = {1,2,4,2,4,3}; //simple quad indices
ObjectLoader loader = new ObjectLoader();
tri = loader.makeObject(positions, index);
}
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); //here I debug opengl errors as different colored backgrounds
GLES20.glClearColor(1.0f,1.0f,1.0f,1.0f);
if(glError == GLES20.GL_NO_ERROR){
GLES20.glClearColor(1.0f,0.0f,0.0f,1.0f);
}else if(glError == GLES20.GL_INVALID_ENUM){
GLES20.glClearColor(0.0f,1.0f,0.0f,1.0f);
}else if(glError == GLES20.GL_INVALID_FRAMEBUFFER_OPERATION){
GLES20.glClearColor(0.0f,0.0f,1.0f,1.0f);
}else if(glError == GLES20.GL_INVALID_OPERATION){
GLES20.glClearColor(1.0f,1.0f,0.0f,1.0f);
}else if(glError == GLES20.GL_INVALID_VALUE){
GLES20.glClearColor(0.0f,1.0f,1.0f,1.0f);
}else if(glError == GLES20.GL_OUT_OF_MEMORY){
GLES20.glClearColor(1.0f,0.0f,1.0f,1.0f);
}
render(tri);
}
private void render(Object obj){
GLES30.glBindVertexArray(obj.vaoID);
GLES30.glEnableVertexAttribArray(0);
obj.shader.start();
GLES30.glDrawElements(GLES20.GL_TRIANGLES, obj.vertcount, GLES20.GL_UNSIGNED_INT, 0);
obj.shader.stop();
GLES30.glDisableVertexAttribArray(0);
GLES30.glBindVertexArray(0);
//get the errors for debug on the next frame
glError = GLES20.glGetError();
}
}
对象class
public class Object {
public int vaoID;
public int vertcount;
public StaticShader shader;
Object(int id, int count, StaticShader s){
vaoID = id;
vertcount = count;
shader = s;
}
}
ObjectLoader class
public class ObjectLoader {
ObjectLoader(){}
public Object makeObject(float[] positions,int[] indices){
int vaoID = CreateVAO();
bindIndicesBuffer(indices);
storeDataInVao(0,positions,vaoID);
unbindVao();
StaticShader shader = new StaticShader();
return new Object(vaoID,indices.length/3, shader);
}
private int CreateVAO(){
int[] vaoID = new int[1];
GLES30.glGenVertexArrays(1,vaoID,0);
GLES30.glBindVertexArray(vaoID[0]);
return vaoID[0];
}
private void storeDataInVao(int index,float[] data, int vaoID){
int[] vboID = new int[1];
GLES20.glGenBuffers(1,vboID,0);
GLES30.glBindBuffer(GLES20.GL_ARRAY_BUFFER,vboID[0]);
FloatBuffer floatbuffer = makeFloatBuffer(data);
GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER,data.length*4,floatbuffer,GLES30.GL_STATIC_DRAW);
GLES30.glVertexAttribPointer(index, 3, GLES30.GL_FLOAT,false,0,0);
GLES30.glBindBuffer(GLES20.GL_ARRAY_BUFFER,0);
}
private void bindIndicesBuffer(int[] indices){
int[] vboID = new int[1];
GLES20.glGenBuffers(1,vboID,0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER,vboID[0]);
IntBuffer buffer = makeIntBuffer(indices);
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER,indices.length,buffer,GLES20.GL_STATIC_DRAW);
}
private IntBuffer makeIntBuffer(int[] data){
IntBuffer buffer = ByteBuffer.allocateDirect(data.length*4).order(ByteOrder.nativeOrder()).asIntBuffer();
buffer.put(data);
buffer.flip();
return buffer;
}
private FloatBuffer makeFloatBuffer(float[] array){
FloatBuffer floatbuffer = ByteBuffer.allocateDirect(array.length*4).order(ByteOrder.nativeOrder()).asFloatBuffer();
floatbuffer.put(array);
floatbuffer.flip();
return floatbuffer;
}
private void unbindVao(){
GLES30.glBindVertexArray(0);
}
}
StaticShader只是调用了ShaderProgram的构造函数,所以我就把ShaderProgram
public abstract class ShaderProgram {
private int programID;
private int vertexShader;
private int fragmentShader;
public String shaderError = "none";
private String vertCode = "void main(){gl_Position = vec4(0.0,0.0,0.0,1.0);}";
private String fragCode = "void main(){gl_FragColor = vec4(1.0,1.0,1.0,1.0);}";
ShaderProgram(){
vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertCode);
fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragCode);
programID = GLES20.glCreateProgram();
GLES20.glAttachShader(programID, fragmentShader);
GLES20.glAttachShader(programID, vertexShader);
GLES20.glLinkProgram(programID);
GLES20.glValidateProgram(programID);
}
abstract void bindAttributes();
private int loadShader(int type, String code){
int shader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
if(shader == 0){
System.exit(-1);
}
GLES20.glShaderSource(shader, code);
if(GLES20.glGetError() == GLES20.GL_INVALID_OPERATION){
//System.exit(-1);
}
GLES20.glCompileShader(shader);
final int[] compileStatus = new int[1];
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
if (compileStatus[0] == 0)
{
shaderError = GLES20.glGetShaderInfoLog(shader);
GLES20.glDeleteShader(shader);
shader = 0;
//System.exit(-1);
}
return shader;
}
public void start(){
GLES20.glUseProgram(programID);
}
public void stop(){
GLES20.glUseProgram(0);
}
}
我的目标是通过任何方式在屏幕上显示 ShaderProgram.shaderError。
我想我还应该说 GLSurfaceView 在 MainActivity.onCreate() 完成之前不会启动,GLSurfaceView 与 MainActivity 在不同的线程上并且 GLSurfaceView 无法访问 MainActivity 的上下文,使得不可能使用 Toast.makeText().
对于那些不想阅读整个代码的人,这是层次结构:
MainActivity - 为 GLSurfaceView 创建一个在 MainActivity 完成之前未启动的线程 --> GLSurfaceView
GLSurfaceView
|
渲染器
|
对象加载器
|
静态着色器+对象
|
着色器程序
您总是创建类型为 GLES20.GL_FRAGMENT_SHADER
的着色器对象。使用 type
参数代替常量 GLES20.GL_FRAGMENT_SHADER
:
int shader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
int shader = GLES20.glCreateShader(type);
这是我的旧 post,但我最终找到了解决方案(在 Java 中):
//shader is the shader ID returned by GLES30.glCreateShader();
final int[] compileStatus = new int[1];
GLES30.glGetShaderiv(shader, GLES30.GL_COMPILE_STATUS, compileStatus, 0);
if(compileStatus[0] == 0){
System.err.println("[HERE ->] " + GLES30.glGetShaderInfoLog(shader));
Log.e("Shader Source : ", GLES30.glGetShaderSource(shader));
}
它会打印着色器错误和之后的源代码
我正在为 android 构建一个 opengl es 应用程序,我在编译着色器时遇到了一些问题。有谁知道如何让 shaderInfoLog 显示在屏幕上?
这里有一些代码可以更好地理解:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
surfaceView=new GLSurfaceView(this);
Renderer renderer = new Renderer();
surfaceView.setEGLContextClientVersion(2);
surfaceView.setRenderer(renderer);
setContentView(surfaceView);
}
}
渲染器class
public class Renderer implements GLSurfaceView.Renderer{
private Object tri;
private int glError = 0;
Renderer(){
}
public void onSurfaceCreated(GL10 gl,EGLConfig config){
float[] positions = //simple quad vertices
{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[] index = {1,2,4,2,4,3}; //simple quad indices
ObjectLoader loader = new ObjectLoader();
tri = loader.makeObject(positions, index);
}
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); //here I debug opengl errors as different colored backgrounds
GLES20.glClearColor(1.0f,1.0f,1.0f,1.0f);
if(glError == GLES20.GL_NO_ERROR){
GLES20.glClearColor(1.0f,0.0f,0.0f,1.0f);
}else if(glError == GLES20.GL_INVALID_ENUM){
GLES20.glClearColor(0.0f,1.0f,0.0f,1.0f);
}else if(glError == GLES20.GL_INVALID_FRAMEBUFFER_OPERATION){
GLES20.glClearColor(0.0f,0.0f,1.0f,1.0f);
}else if(glError == GLES20.GL_INVALID_OPERATION){
GLES20.glClearColor(1.0f,1.0f,0.0f,1.0f);
}else if(glError == GLES20.GL_INVALID_VALUE){
GLES20.glClearColor(0.0f,1.0f,1.0f,1.0f);
}else if(glError == GLES20.GL_OUT_OF_MEMORY){
GLES20.glClearColor(1.0f,0.0f,1.0f,1.0f);
}
render(tri);
}
private void render(Object obj){
GLES30.glBindVertexArray(obj.vaoID);
GLES30.glEnableVertexAttribArray(0);
obj.shader.start();
GLES30.glDrawElements(GLES20.GL_TRIANGLES, obj.vertcount, GLES20.GL_UNSIGNED_INT, 0);
obj.shader.stop();
GLES30.glDisableVertexAttribArray(0);
GLES30.glBindVertexArray(0);
//get the errors for debug on the next frame
glError = GLES20.glGetError();
}
}
对象class
public class Object {
public int vaoID;
public int vertcount;
public StaticShader shader;
Object(int id, int count, StaticShader s){
vaoID = id;
vertcount = count;
shader = s;
}
}
ObjectLoader class
public class ObjectLoader {
ObjectLoader(){}
public Object makeObject(float[] positions,int[] indices){
int vaoID = CreateVAO();
bindIndicesBuffer(indices);
storeDataInVao(0,positions,vaoID);
unbindVao();
StaticShader shader = new StaticShader();
return new Object(vaoID,indices.length/3, shader);
}
private int CreateVAO(){
int[] vaoID = new int[1];
GLES30.glGenVertexArrays(1,vaoID,0);
GLES30.glBindVertexArray(vaoID[0]);
return vaoID[0];
}
private void storeDataInVao(int index,float[] data, int vaoID){
int[] vboID = new int[1];
GLES20.glGenBuffers(1,vboID,0);
GLES30.glBindBuffer(GLES20.GL_ARRAY_BUFFER,vboID[0]);
FloatBuffer floatbuffer = makeFloatBuffer(data);
GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER,data.length*4,floatbuffer,GLES30.GL_STATIC_DRAW);
GLES30.glVertexAttribPointer(index, 3, GLES30.GL_FLOAT,false,0,0);
GLES30.glBindBuffer(GLES20.GL_ARRAY_BUFFER,0);
}
private void bindIndicesBuffer(int[] indices){
int[] vboID = new int[1];
GLES20.glGenBuffers(1,vboID,0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER,vboID[0]);
IntBuffer buffer = makeIntBuffer(indices);
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER,indices.length,buffer,GLES20.GL_STATIC_DRAW);
}
private IntBuffer makeIntBuffer(int[] data){
IntBuffer buffer = ByteBuffer.allocateDirect(data.length*4).order(ByteOrder.nativeOrder()).asIntBuffer();
buffer.put(data);
buffer.flip();
return buffer;
}
private FloatBuffer makeFloatBuffer(float[] array){
FloatBuffer floatbuffer = ByteBuffer.allocateDirect(array.length*4).order(ByteOrder.nativeOrder()).asFloatBuffer();
floatbuffer.put(array);
floatbuffer.flip();
return floatbuffer;
}
private void unbindVao(){
GLES30.glBindVertexArray(0);
}
}
StaticShader只是调用了ShaderProgram的构造函数,所以我就把ShaderProgram
public abstract class ShaderProgram {
private int programID;
private int vertexShader;
private int fragmentShader;
public String shaderError = "none";
private String vertCode = "void main(){gl_Position = vec4(0.0,0.0,0.0,1.0);}";
private String fragCode = "void main(){gl_FragColor = vec4(1.0,1.0,1.0,1.0);}";
ShaderProgram(){
vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertCode);
fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragCode);
programID = GLES20.glCreateProgram();
GLES20.glAttachShader(programID, fragmentShader);
GLES20.glAttachShader(programID, vertexShader);
GLES20.glLinkProgram(programID);
GLES20.glValidateProgram(programID);
}
abstract void bindAttributes();
private int loadShader(int type, String code){
int shader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
if(shader == 0){
System.exit(-1);
}
GLES20.glShaderSource(shader, code);
if(GLES20.glGetError() == GLES20.GL_INVALID_OPERATION){
//System.exit(-1);
}
GLES20.glCompileShader(shader);
final int[] compileStatus = new int[1];
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
if (compileStatus[0] == 0)
{
shaderError = GLES20.glGetShaderInfoLog(shader);
GLES20.glDeleteShader(shader);
shader = 0;
//System.exit(-1);
}
return shader;
}
public void start(){
GLES20.glUseProgram(programID);
}
public void stop(){
GLES20.glUseProgram(0);
}
}
我的目标是通过任何方式在屏幕上显示 ShaderProgram.shaderError。
我想我还应该说 GLSurfaceView 在 MainActivity.onCreate() 完成之前不会启动,GLSurfaceView 与 MainActivity 在不同的线程上并且 GLSurfaceView 无法访问 MainActivity 的上下文,使得不可能使用 Toast.makeText().
对于那些不想阅读整个代码的人,这是层次结构:
MainActivity - 为 GLSurfaceView 创建一个在 MainActivity 完成之前未启动的线程 --> GLSurfaceView
GLSurfaceView
|
渲染器
|
对象加载器
|
静态着色器+对象
|
着色器程序
您总是创建类型为 GLES20.GL_FRAGMENT_SHADER
的着色器对象。使用 type
参数代替常量 GLES20.GL_FRAGMENT_SHADER
:
int shader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
int shader = GLES20.glCreateShader(type);
这是我的旧 post,但我最终找到了解决方案(在 Java 中):
//shader is the shader ID returned by GLES30.glCreateShader();
final int[] compileStatus = new int[1];
GLES30.glGetShaderiv(shader, GLES30.GL_COMPILE_STATUS, compileStatus, 0);
if(compileStatus[0] == 0){
System.err.println("[HERE ->] " + GLES30.glGetShaderInfoLog(shader));
Log.e("Shader Source : ", GLES30.glGetShaderSource(shader));
}
它会打印着色器错误和之后的源代码