本文主要是介绍OpenGL ES2学习笔记(3)-- 使用Shader,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
渲染流水线
OpenGL ES 1.0和1.1使用的渲染方式是Fixed Function Pipeline,从2.0版本开始,转而使用Programmable Shader Pipeline。要想使用OpenGL ES 2.0,必须使用一种语法很像C语言的语言GLSL来编写Shader程序。
封装OpenGL API
直接通过OpenGL API来使用GLSL太繁琐了,因此我进行了简单的抽象和封装。
GLWrapper
import javax.media.opengl.GL2ES2;public abstract class GLWrapper {protected GL2ES2 getGL() {return Glob.getInstance().getGL();}}
GLWrapper类只有一个方法getGL(),返回
javax.media.opengl.GL2ES2接口。关于GL2ES2接口的更多信息,请看
这个网页。Glob对象稍后介绍。
GLObject
public abstract class GLObject extends GLWrapper {protected int objectId;}
GLObject继承GLWrapper,用来抽象OpenGL管理的对象(应该在GPU内存里)。
ShaderCompiler和ShaderObject
import static javax.media.opengl.GL2ES2.GL_FRAGMENT_SHADER;
import static javax.media.opengl.GL2ES2.GL_VERTEX_SHADER;public class ShaderCompiler extends GLWrapper {public ShaderObject compileVertexShader(String shaderCode) {return compileShader(GL_VERTEX_SHADER, shaderCode);}public ShaderObject compileFragmentShader(String shaderCode) {return compileShader(GL_FRAGMENT_SHADER, shaderCode);}private ShaderObject compileShader(int shaderType, String shaderCode) {ShaderObject obj = new ShaderObject();obj.objectId = getGL().glCreateShader(shaderType);getGL().glShaderSource(obj.objectId, 1,new String[] {shaderCode}, new int[] {shaderCode.length()}, 0);getGL().glCompileShader(obj.objectId);return obj;}}
public class ShaderObject extends GLObject {}
前面说GLSL的语法和C语言很像,其实不光是语法,编译和链接过程也很像。ShaderCompiler抽象Shader编译器,ShaderObject抽象编译后的Shader对象。Vertex Shader和Fragment Shader的详细信息可以从OpenGL wiki上查到。
ShaderLinker和ShaderProgram
public class ShaderLinker extends GLWrapper {public ShaderProgram linkProgram(ShaderObject... shaders) {ShaderProgram program = new ShaderProgram();program.objectId = getGL().glCreateProgram();for (ShaderObject shader : shaders) {getGL().glAttachShader(program.objectId, shader.objectId);}getGL().glLinkProgram(program.objectId);return program;}}
public class ShaderProgram extends GLObject {public void use() {getGL().glUseProgram(objectId);}}
类似C语言的链接过程,ShaderLinker把编译好的ShaderObject链接成一个ShaderProgram,之后就可以使用这个ShaderProgram了。
Glob
Glob单例类定义了一个方法来编译和链接Shader程序:
import javax.media.opengl.GL2ES2;public class Glob {private static final Glob INSTANCE = new Glob();public static Glob getInstance() {return INSTANCE;}private GL2ES2 gl;private final ShaderCompiler shaderCompiler;private final ShaderLinker shaderLinker;private Glob() {shaderCompiler = new ShaderCompiler();shaderLinker = new ShaderLinker();}public ShaderProgram compileAndLink(String vertexShaderCode, String fragmentShaderCode) {ShaderObject vertexShader = shaderCompiler.compileVertexShader(vertexShaderCode);ShaderObject fragmentShader = shaderCompiler.compileFragmentShader(fragmentShaderCode);ShaderProgram program = shaderLinker.linkProgram(vertexShader, fragmentShader);getGL().glDeleteShader(vertexShader.objectId);getGL().glDeleteShader(fragmentShader.objectId);return program;}...}
类图
编译和链接过程示意图
在OpenGL Console里试验
打开OpenGL Console,运行下面的脚本:
import javax.media.opengl.GLdef vertexShader = """void main() {gl_Position = vec4(0.0, 0.0, 0.0, 1.0);gl_PointSize = 10.0;}
"""def fragmentShader = """void main() {gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);}
"""
def shaderProgram = glob.compileAndLink(vertexShader, fragmentShader)
shaderProgram.use()gl.glClearColor(0.8f, 0.6f, 0.4f, 1.0f)
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
画布应该被清除成像下面这样的淡黄色:
代码解释
上面的脚本只是定义了两个字符串,一个是Vertex Shader代码,一个是Fragment Shader代码,然后调用Glob对象的compileAndLink()方法编译和链接Shader,最后清屏。本篇文章里的Shader没有起任何作用,只是证明我们的代码可以工作。在下一篇文章中,我会用Shader在画布上画一个点。
这篇关于OpenGL ES2学习笔记(3)-- 使用Shader的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!