Android Opengl 学习笔记03——Opengl绘制流程

一、Opengl渲染流程

二、OpenGL加载shader

1、SamShader.h头文件中定义加载shader的方法:

#ifndef OPENGLDEMO_SAMSHADER_H
#define OPENGLDEMO_SAMSHADER_H

#include <GLES2/gl2.h>

static int loadShaders(int shaderType, const char *code)
{
    int shader = glCreateShader(shaderType);//创建shader-1
    glShaderSource(shader, 1, &code, 0);//创建shader-2
    glCompileShader(shader);//编译shader
    return  shader;
}

static int createProgrm(const char *vertex , const char * fragment)
{
    int vertexShader = loadShaders(GL_VERTEX_SHADER, vertex);//加载顶点shader
    int fragmentShader = loadShaders(GL_FRAGMENT_SHADER, fragment);//加载纹理shader
    int program = glCreateProgram();//创建shader程序-1
    glAttachShader(program, vertexShader);//创建vertexShader程序
    glAttachShader(program, fragmentShader);//创建fragmentShader程序
    glLinkProgram(program);//链接shader
    return program;//返回shader程序
}

#endif //OPENGLDEMO_SAMSHADER_H

2、在native-lib.cpp中测试:

const char *vertex = "attribute vec4 a_position;\n"
                     "\n"
                     "void main(){\n"
                     "    gl_Position = a_position;\n"
                     "}";
const char *fragment = "precision mediump float;\n"
                       "\n"
                       "void main(){\n"
                       "    gl_FragColor = vec4(1f,0f,0f,1f);\n"
                       "}";

extern "C"
JNIEXPORT void JNICALL
包名_NativeOpengl_surfaceCreate(JNIEnv *env, jobject instance, jobject surface) {

    //略...

    int program = createProgrm(vertex, fragment);
    LOGD("opengl program is %d", program);

}
//发生错误 call to OpenGL ES API with no current context ,program=0;
//将测试代码放至SamEglThread.cpp创建的线程中便可成功,在native-lib.cpp中运行时在主线程中,
//当开启SamEglThread线程后,无法获取current context,创建program失败,在SamEglThread线程中运行时
//能确定current context,所以创建program成功。

三、Opengl坐标系

四、Opengl绘制三角形

1、绘制三角形(在native-lib.cpp文件中通过在SamThread线程的回调函数中添加绘制代码来绘制):

const char *vertex = "attribute vec4 a_position;\n"
                     "\n"
                     "void main(){\n"
                     "    gl_Position = a_position;\n"
                     "}";
const char *fragment = "precision mediump float;\n"
                       "\n"
                       "void main(){\n"
                       "    gl_FragColor = vec4(1f,0f,0f,1f);\n"
                       "}";

int program;
GLint vPosition;

float vertexs[] = {
        -1,-1,
        1,-1,
        -1,1,

};

void callback_SurfaceCrete(void *ctx)
{
    LOGD("callback_SurfaceCrete");
    WlEglThread *wlEglThread = static_cast<WlEglThread *>(ctx);

    //创建绘制的program并初始化开始位置vPosition
    program = createProgrm(vertex, fragment);
    LOGD("opengl program is %d", program);
    vPosition = glGetAttribLocation(program, "a_position");



}

void callback_SurfacChange(int w, int h, void *ctx)
{
    LOGD("callback_SurfacChange");
    WlEglThread *wlEglThread = static_cast<WlEglThread *>(ctx);
    glViewport(0, 0, w, h);//设置窗口大小
}

void callback_SurfaceDraw(void *ctx)
{
    LOGD("callback_SurfaceDraw");
    WlEglThread *wlEglThread = static_cast<WlEglThread *>(ctx);
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);//清屏为黑色
    glClear(GL_COLOR_BUFFER_BIT);

    glUseProgram(program);//指定使用的program
    
    //进行三角形的绘制
    glEnableVertexAttribArray(vPosition);
    glVertexAttribPointer(vPosition, 2, GL_FLOAT, false, 8, vertexs);
    glDrawArrays(GL_TRIANGLES, 0, 3);
}

2、通过Opengl 绘制四边形(Opengl ES只能绘制三角形,绘制两个三角形来组成四边形):

const char *vertex = "attribute vec4 a_position;\n"
                     "\n"
                     "void main(){\n"
                     "    gl_Position = a_position;\n"
                     "}";
const char *fragment = "precision mediump float;\n"
                       "\n"
                       "void main(){\n"
                       "    gl_FragColor = vec4(1f,0f,0f,1f);\n"
                       "}";

int program;
GLint vPosition;

float vertexs[] = {
        -1,-1,
        1,-1,
        -1,1,
        1,1

};//设置四边形的四个顶点 两个三角形共用一条对角线为边

void callback_SurfaceCrete(void *ctx)
{
    LOGD("callback_SurfaceCrete");
    WlEglThread *wlEglThread = static_cast<WlEglThread *>(ctx);

    //创建绘制的program并初始化开始位置vPosition
    program = createProgrm(vertex, fragment);
    LOGD("opengl program is %d", program);
    vPosition = glGetAttribLocation(program, "a_position");



}

void callback_SurfacChange(int w, int h, void *ctx)
{
    LOGD("callback_SurfacChange");
    WlEglThread *wlEglThread = static_cast<WlEglThread *>(ctx);
    glViewport(0, 0, w, h);//设置窗口大小
}

void callback_SurfaceDraw(void *ctx)
{
    LOGD("callback_SurfaceDraw");
    WlEglThread *wlEglThread = static_cast<WlEglThread *>(ctx);
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);//清屏为黑色
    glClear(GL_COLOR_BUFFER_BIT);

    glUseProgram(program);//指定使用的program
    
    //进行三角形的绘制
    glEnableVertexAttribArray(vPosition);
    glVertexAttribPointer(vPosition, 2, GL_FLOAT, false, 8, vertexs);
    
    //绘制顶点带
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}

五、Opengl绘制纹理

1、纹理映射过程:

2、修改native-lib.cpp回调函数中绘制纹理的代码(加载shader与创建program不变):

//顶点Shader
const char *vertex = "attribute vec4 v_Position;\n"
                     "attribute vec2 f_Position;\n"
                     "varying vec2 ft_Position;\n"
                     "void main() {\n"
                     "    ft_Position = f_Position;\n"
                     "    gl_Position = v_Position;\n"
                     "}";

//纹理Shader
const char *fragment = "precision mediump float;\n"
                       "varying vec2 ft_Position;\n"
                       "uniform sampler2D sTexture;\n"
                       "void main() {\n"
                       "    gl_FragColor=texture2D(sTexture, ft_Position);\n"
                       "}";

int program;
GLint vPosition;
GLint fPosition;
GLint sampler;
GLuint textureId;

//java层传递过来的图片信息
int w;
int h;
void *pixels = NULL;

//顶点坐标
float vertexs[] = {
        1,-1,
        1,1,
        -1,-1,
        -1,1
};
//与之对应的纹理坐标
float fragments[] ={
        1,1,
        1,0,
        0,1,
        0,0
};

//实现EGL线程回调函数的实现
void callback_SurfaceCrete(void *ctx)
{

    LOGD("callback_SurfaceCrete");
    SamEglThread *samEglThread = static_cast<SamEglThread *>(ctx);

    program = createProgrm(vertex, fragment);//创建program
    LOGD("opengl program is %d", program);
    vPosition = glGetAttribLocation(program, "v_Position");//顶点坐标
    fPosition = glGetAttribLocation(program, "f_Position");//纹理坐标
    sampler = glGetUniformLocation(program, "sTexture");//2D纹理

    glGenTextures(1, &textureId);//创建纹理
    glBindTexture(GL_TEXTURE_2D, textureId);//绑定纹理

    //设置环绕(超出纹理坐标范围)方式(s==x t==y GL_REPEAT 重复)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    //设置过滤(纹理像素映射到坐标点)方式(缩小、放大:GL_LINEAR线性)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);

    if(pixels != NULL)
    {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
    }
    glBindTexture(GL_TEXTURE_2D, 0);//解绑纹理


}

void callback_SurfacChange(int w, int h, void *ctx)
{

    LOGD("callback_SurfacChange");
    SamEglThread *samEglThread = static_cast<SamEglThread *>(ctx);
    glViewport(0, 0, w, h);

}

void callback_SurfaceDraw(void *ctx)
{
    LOGD("callback_SurfaceDraw");
    SamEglThread *samEglThread = static_cast<SamEglThread *>(ctx);
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glUseProgram(program);

    //使用sampler
    glActiveTexture(GL_TEXTURE5);
    glUniform1i(sampler, 5);

    //绑定纹理
    glBindTexture(GL_TEXTURE_2D, textureId);

    //激活并加载顶点shader
    glEnableVertexAttribArray(vPosition);
    glVertexAttribPointer(vPosition, 2, GL_FLOAT, false, 8, vertexs);

    //激活并加载纹理shader
    glEnableVertexAttribArray(fPosition);
    glVertexAttribPointer(fPosition, 2, GL_FLOAT, false, 8, fragments);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);//绘制纹理

    glBindTexture(GL_TEXTURE_2D, 0);//解绑纹理
}

//略...

//添加获取java层传来的图片数据的方法 imgData方法
extern "C"
JNIEXPORT void JNICALL
包名_NativeOpengl_imgData(JNIEnv *env, jobject thiz, jint width, jint height, jint length,
                                         jbyteArray data_) {

    jbyte *data = env->GetByteArrayElements(data_, NULL);//将java层的数组转化为cpp数组


    w = width;
    h = height;
    pixels = malloc(length);
    memcpy(pixels, data, length);


    env->ReleaseByteArrayElements(data_, data, 0);//释放内存
}

3、在NativeOpengl.java中声明native方法imgData:

public class NativeOpengl {
    static {
        System.loadLibrary("native-lib");//加载native库
    }

    public native void surfaceCreate(Surface surface);//定义native层方法 对EGL环境进行测试
    public native void surfaceChange(int width, int height);//向native层传递surface的width,height
    public native void imgData(int w, int h, int length, byte[] data);//获取需要渲染的图片的数据

}

4、在MainActivity.java中获取要渲染的minren.png图片的数据:

public class MainActivity extends AppCompatActivity {
    private SamSurfaceView samSurfaceView;
    private NativeOpengl nativeOpengl;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        samSurfaceView=findViewById(R.id.id_samSurfaceView);
        nativeOpengl=new NativeOpengl();
        samSurfaceView.setNativeOpengl(nativeOpengl);

        //java层获取图片minren.png的数据,并调用native层的imgData方法传入native层
        final Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
                R.drawable.mingren);
        ByteBuffer fcbuffer = ByteBuffer.allocate(bitmap.getHeight() * bitmap.getWidth() * 4);
        bitmap.copyPixelsToBuffer(fcbuffer);
        fcbuffer.flip();
        byte[] pixels = fcbuffer.array();
        nativeOpengl.imgData(bitmap.getWidth(), bitmap.getHeight(), pixels.length, pixels);
    }
}
QKB
发布了5 篇原创文章 · 获赞 4 · 访问量 2181

猜你喜欢

转载自blog.csdn.net/caphpca/article/details/103996736