固定
现在一切正常!向下滚动以查看溶剂。
周长
我目前正在编写一个OpenGL引擎。 我为OpenGL着色器编写了一个包装器:
public abstract class Shader {
protected String name;
protected int type;
protected String code;
protected int shader;
protected boolean loaded;
public Shader(String name, String code) {
this.name = name;
this.code = code;
this.loaded = false;
this.type = -1;
}
public Shader(Shader s) {
this.name = s.name;
this.type = s.type;
this.code = s.code;
this.shader = -1;
this.loaded = false;
}
public String getName() {
return this.name;
}
public int getType() {
return this.type;
}
public boolean isVertexShader() {
return this.type == GLES20.GL_VERTEX_SHADER;
}
public boolean isFragmentShader() {
return this.type == GLES20.GL_FRAGMENT_SHADER;
}
public void unload() {
this.loaded = false;
}
public int load() {
if(!this.loaded) {
this.shader = GLES20.glCreateShader(this.type);
GLES20.glShaderSource(this.shader, this.code);
GLES20.glCompileShader(this.shader);
DrainEmEngine.checkGlError("glCompileShader");
this.loaded = true;
}
return this.shader;
}
}
我有一个程序包装器:
public class Program {
private String name;
private VertexShader vertexShader; // VertexShader and FragmentShader just
private FragmentShader fragmentShader; // extend the Shader class and set it's type
private int program;
private boolean loaded;
public Program(String name, VertexShader vertexShader, FragmentShader fragmentShader) {
this.name = name;
this.vertexShader = vertexShader;
this.fragmentShader = fragmentShader;
this.program = -1;
this.loaded = false;
}
public Program(Program p) {
this.name = p.name;
this.vertexShader = new VertexShader(p.vertexShader);
this.fragmentShader = new FragmentShader(p.fragmentShader);
this.program = -1;
this.loaded = false;
}
public String getName() {
return this.name;
}
public VertexShader getVertexShader() {
return this.vertexShader;
}
public FragmentShader getFragmentShader() {
return this.fragmentShader;
}
public void unload() {
this.vertexShader.unload();
this.fragmentShader.unload();
this.loaded = false;
}
public int load() {
if(!this.loaded) {
this.program = GLES20.glCreateProgram();
DrainEmEngine.checkGlError("glCreateProgram");
GLES20.glAttachShader(this.program, this.vertexShader.load());
DrainEmEngine.checkGlError("glAttachShader"); // this gives Error 1281
GLES20.glAttachShader(this.program, this.fragmentShader.load());
DrainEmEngine.checkGlError("glAttachShader");
GLES20.glLinkProgram(this.program);
DrainEmEngine.checkGlError("glLinkProgram");
}
return this.program;
}
}
我知道这远非完整,但我只是从这个项目开始......
我的引擎应该带有一些预定义的着色器,而3d对象可以从引擎获得着色器或程序。
// In constructor of the 3d object
this.program = DrainEmEngine.getInstance().getProgram("default");
// I also tried this, but same effect:
this.program = new Program(DrainEmEngine.getInstance().getProgram("default"));
默认程序初始化如下:
public void registerDefaultShaders() {
this.registerShader(new VertexShader("default_ver",
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = uMVPMatrix * vPosition;" +
"}"));
this.registerShader(new FragmentShader("default_frag",
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}"));
}
public void registerDefaultPrograms() {
this.registerProgram(new Program("default", (VertexShader)this.getShader("default_ver"), (FragmentShader)this.getShader("default_frag")));
}
这是我的渲染/绘制方法:
public void render(float[] mvpMatrix) {
// Add program to OpenGL ES environment
// this.program.unload(); // If this line is commented out it crashes!
int program = this.program.load();
GLES20.glUseProgram(program);
DrainEmEngine.checkGlError("glUseProgram");
// get handle to vertex shader's vPosition member
int positionHandle = GLES20.glGetAttribLocation(program, "vPosition");
DrainEmEngine.checkGlError("glGetAttribLocation");
// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(positionHandle);
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(positionHandle, Mesh.COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
Mesh.vertexStride, this.mesh.getVertexBuffer());
// get handle to fragment shader's vColor member
int colorHandle = GLES20.glGetUniformLocation(program, "vColor");
DrainEmEngine.checkGlError("glGetUniformLocation");
// Set color for drawing the triangle
GLES20.glUniform4fv(colorHandle, 1, color, 0);
DrainEmEngine.checkGlError("glUniform4fv");
// get handle to shape's transformation matrix
int MVPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
DrainEmEngine.checkGlError("glGetUniformLocation");
updateModelMatrix();
float[] tmp = mvpMatrix.clone();
Matrix.multiplyMM(tmp, 0, mvpMatrix, 0, modelMatrix, 0);
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(MVPMatrixHandle, 1, false, tmp, 0);
DrainEmEngine.checkGlError("glUniformMatrix4fv");
// Draw
GLES20.glDrawElements(
GLES20.GL_TRIANGLES, this.mesh.getDrawOrder().length,
GLES20.GL_UNSIGNED_SHORT, this.mesh.getDrawListBuffer());
// Disable vertex array
GLES20.glDisableVertexAttribArray(positionHandle);
}
我在启动时加载程序和着色器,之后它们应该可以正常工作。
问题
但是,如果我注释掉标记的行(应该是我猜),一切都会崩溃,并在调用Program.load()
后在glAttachShader
函数中得到OpenGL错误1281。
但是,由于Shader成功编译(如果调用DrainEmEngine.checkGlError("...")
足以验证)至少一次,它应该正常工作......
如果我强制着色器和程序在每个帧中重新编译(通过取消注释该行),它的工作正常,但是从我所知道的OpenGL不是那种方式。
由于我对OpenGL很陌生并且我的所有研究都没有帮助我解决问题,我希望你们中的一个发现我的错误或者能够以OpenGL的方式启发我并告诉我在哪里我的逻辑失败了。
解决方案
我不知道问题是什么,但感谢ExMix的帖子,我解决了它。
以下是我的Shader和Program类现在的样子:
(实际的修复方法是加载和卸载方法)
public abstract class Shader {
protected String name;
protected int type;
protected String code;
protected int shader;
protected boolean loaded;
public Shader(String name, String code) {
this.name = name;
this.code = code;
this.loaded = false;
this.type = -1;
}
public Shader(Shader s) {
this.name = s.name;
this.type = s.type;
this.code = s.code;
this.shader = -1;
this.loaded = false;
}
public String getName() {
return this.name;
}
public int getType() {
return this.type;
}
public boolean isVertexShader() {
return this.type == GLES20.GL_VERTEX_SHADER;
}
public boolean isFragmentShader() {
return this.type == GLES20.GL_FRAGMENT_SHADER;
}
public void unload() {
if(this.loaded) {
GLES20.glDeleteShader(this.shader);
DrainEmEngine.checkGlError("glDeleteShader");
this.loaded = false;
}
}
public int load() {
if(!this.loaded) {
this.shader = GLES20.glCreateShader(this.type);
GLES20.glShaderSource(this.shader, this.code);
GLES20.glCompileShader(this.shader);
DrainEmEngine.checkGlError("glCompileShader");
this.loaded = true;
}
return this.shader;
}
}
public class Program {
private String name;
private VertexShader vertexShader;
private FragmentShader fragmentShader;
private int program;
private boolean loaded;
public Program(String name, VertexShader vertexShader, FragmentShader fragmentShader) {
this.name = name;
this.vertexShader = vertexShader;
this.fragmentShader = fragmentShader;
this.program = -1;
this.loaded = false;
}
public Program(Program p) {
this.name = p.name;
this.vertexShader = new VertexShader(p.vertexShader);
this.fragmentShader = new FragmentShader(p.fragmentShader);
this.program = -1;
this.loaded = false;
}
public String getName() {
return this.name;
}
public VertexShader getVertexShader() {
return this.vertexShader;
}
public FragmentShader getFragmentShader() {
return this.fragmentShader;
}
public void unload() {
this.vertexShader.unload();
this.fragmentShader.unload();
this.loaded = false;
}
public int load() {
if(!this.loaded) {
this.program = GLES20.glCreateProgram();
DrainEmEngine.checkGlError("glCreateProgram");
int vert = this.vertexShader.load();
GLES20.glAttachShader(this.program, vert);
DrainEmEngine.checkGlError("glAttachShader");
int frag = this.fragmentShader.load();
GLES20.glAttachShader(this.program, frag);
DrainEmEngine.checkGlError("glAttachShader");
GLES20.glLinkProgram(this.program);
DrainEmEngine.checkGlError("glLinkProgram");
GLES20.glDetachShader(this.program, vert);
DrainEmEngine.checkGlError("glDetachShader");
GLES20.glDetachShader(this.program, frag);
DrainEmEngine.checkGlError("glDetachShader");
this.vertexShader.unload();
this.fragmentShader.unload();
}
return this.program;
}
}
答案 0 :(得分:1)
首先,您的代码实际上不会卸载着色器和程序。 您漏掉了OpenGL资源。
卸载你必须做: 1)顶点和片段着色器的glDetachShader(programID,shaderID) 2)顶点和片段着色器的glDeleteShader(shaderID) 3)glDeleteProgram(programID)
之后,您的着色器将完全卸载。
但如果你取消注释"卸载"行代码将在每个帧上创建新的gpu着色器对象和gpu程序对象(不是你的包装器)。
此外,在程序链接后,您可以分离着色器并将其删除。这个过程就像C ++编译一样。来自* .obj文件的程序链接,但在progran链接后。* .jj文件不需要。
关于崩溃。你确定它在第一帧崩溃了吗?你可以插入一些静态计数器,它会在崩溃前计算帧吗?它可能会崩溃,因为OpenGL在某些时刻无法为着色器和程序分配名称。
您还需要检查checkGlError函数。
http://www.khronos.org/opengles/sdk/docs/man/
为了允许分布式实现,可能存在多个错误标志。如果任何单个错误标志记录了错误,则返回该标志的值,并在调用glGetError时将该标志重置为GL_NO_ERROR。如果多个标志记录了错误,glGetError将返回并清除任意错误标志值。因此,如果要重置所有错误标志,则应始终在循环中调用glGetError,直到它返回GL_NO_ERROR。