加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

OpenGL ES2学习笔记(3)-- 使用Shader

发布时间:2020-12-14 16:52:04 所属栏目:大数据 来源:网络整理
导读:渲染流水线 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来使用

渲染流水线

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.GL

def vertexShader = """
  void main() {
    gl_Position = vec4(0.0,0.0,1.0);
    gl_PointSize = 10.0;
  }
"""

def fragmentShader = """
  void main() {
    gl_FragColor = vec4(1.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在画布上画一个点。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读