一、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);
}
}