问:学OpenGL能干吗? 答: 随心所欲。
编程
提及
OpenGLES
,你们可能都敬而远之,其实它并无想象中的那么可怕
,固然也并无那么容易
都0202年了,本系列使用OpenGLES3.0
,这是一次有预谋的计划:数组
这是正文的第二篇,在上一篇讲述了OpenGLES的基本使用
如今你已经可以操做着色器绘制点线了,若是你还不会,请先看第一集缓存
三角形是OpenGL中最重要的一种图形,能够说全部的体和面都是由三角形拼组而成
全部这一节是很是重要的。bash
GL_TRIANGLES
目前的坐标系以下: 三个点从右上角开始逆时针,白、红、绿微信
//顶点数组
private final float vertexes[] = {//以逆时针顺序
1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
};
// 颜色数组
private final float colors[] = new float[]{
1.0f, 1.0f, 1.0f, 1.0f,//白色
1.0f, 0.0f, 0.0f, 1.0f,//红色
0.0f, 1.0f, 0.0f, 1.0f,//绿色
};
复制代码
由三点进行绘制三角形,绘制时使用
GLES30.GL_TRIANGLES
便可函数
GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, vertexes.length / VERTEX_DIMENSION);
复制代码
绘制三角形有三种模式,另外两个是:
GL_TRIANGLE_STRIP
和GL_TRIANGLE_STRIP
下面经过四个点进行对比演示工具
//顶点数组
private final float vertexes[] = { //以逆时针顺序
1.0f, 1.0f, 0.0f,//原点
-1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
};
// 颜色数组
private final float colors[] = new float[]{
1.0f, 1.0f, 1.0f, 1.0f,//白色
1.0f, 0.0f, 0.0f, 1.0f,//红色
0.0f, 1.0f, 0.0f, 1.0f,//绿色
0.0f, 0.0f, 1.0f, 1.0f,//蓝色
};
复制代码
glDrawArrays:
---->[绘制点线]-------
GLES20.GL_POINTS 绘制点
GLES20.GL_LINES 两点一线
GLES20.GL_LINE_STRIP 相邻两点一线(不连首尾)
GLES20.GL_LINE_LOOP 相邻两点一线(连首尾)
---->[绘制三角形]-------
GLES20.GL_TRIANGLES 三点一个(不够三个,被忽略)
GLES20.GL_TRIANGLE_STRIP 相邻三点一个
GLES20.GL_TRIANGLE_FAN 第一点中心,散射到其余点
复制代码
矩形也就是两个三角形拼成的,因此如今绘制面的技能你已经get了。post
如今你应该有所体会,OpenGL中最重要的是处理顶点和颜色的数据
圆形的绘制无非就是找到那些顶点在哪里,根据三角函数很容易求得测试
下面的图很好的体现了这些点的坐标是如何肯定的ui
private void initData() {
//顶点坐标数据的初始化
int verticeCount = splitCount + 2;
vertexes = new float[verticeCount * 3];//坐标数据
colors = new float[verticeCount * 4];//颜色数据
float thta = 360.f / splitCount;
vertexes[0] = 0;
vertexes[1] = 0;
vertexes[2] = 0;
colors[0] = 1;
colors[1] = 1;
colors[2] = 1;
colors[3] = 1;
for (int n = 1; n <= verticeCount - 1; n++) {
vertexes[n * 3] = r * cos((n - 1) * thta);//x
vertexes[n * 3 + 1] = r * sin((n - 1) * thta);//y
vertexes[n * 3 + 2] = 0;//z
colors[4 * n] = 1;
colors[4 * n + 1] = 0;
colors[4 * n + 2] = 0;
colors[4 * n + 3] = 1.0f;
}
}
复制代码
没有贴图,就像肉包里没有肉馅。以前咱们都是自定义颜色去给顶点着色
而贴图就是使用图形象的像素信息来给顶点着色,get贴图技能以后,
你就能够用OpenGLES 对图片进行处理和展现,甚至保存。这也是支线1的基础
要注意,贴图的纹理坐标系是一个二维系,原点在左上角,注意和顶点系区分
下面是顶点系xoy面
和纹理系
的示意图,咱们须要给出纹理坐标,就能够把图片贴起来:
//顶点数组
private final float vertexes[] = { //以逆时针顺序
1.0f, 1.0f, 0.0f,//原点
-1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
};
// 贴图坐标
private final float textureCoo[] = new float[]{
1.0f,0.0f,
0.0f,0.0f,
0.0f,1.0f,
1.0f,1.0f,
};
private static final int VERTEX_DIMENSION = 3;
private static final int TEXTURE_DIMENSION = 2;
复制代码
这里给出一个图片加载成贴图的工具类
//贴图工具类
public class GLTexture {
/**
* 资源id 加载纹理,默认重复方式:RepeatType.REPEAT
*
* @param ctx 上下文
* @param resId 资源id
* @return 纹理id
*/
public static int loadTexture(Context ctx, int resId) {
return loadTexture(ctx, resId, RepeatType.REPEAT);
}
/**
* 图片加载纹理,默认重复方式:RepeatType.REPEAT
* @param bitmap 图片
* @return 纹理id
*/
public static int loadTexture(Bitmap bitmap) {
return loadTexture(bitmap, RepeatType.REPEAT);
}
/**
* 资源id 加载纹理
*
* @param ctx 上下文
* @param resId 资源id
* @param repeatType 重复方式 {@link RepeatType}
* @return 纹理id
*/
public static int loadTexture(Context ctx, int resId, RepeatType repeatType) {
Bitmap bitmap = BitmapFactory.decodeResource(ctx.getResources(), resId);
return loadTexture(bitmap, repeatType);
}
/**
* bitmap 加载纹理
*
* @param bitmap bitmap
* @param repeatType 重复方式 {@link RepeatType}
* @return 纹理id
*/
public static int loadTexture(Bitmap bitmap, RepeatType repeatType) {
//生成纹理ID
int[] textures = new int[1];
//(产生的纹理id的数量,纹理id的数组,偏移量)
GLES30.glGenTextures(1, textures, 0);
int textureId = textures[0];
//绑定纹理id
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureId);
//采样方式MIN
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_NEAREST);
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
int wrapS = 0;
int wrapT = 0;
switch (repeatType) {
case NONE:
wrapS = GLES30.GL_CLAMP_TO_EDGE;
wrapT = GLES30.GL_CLAMP_TO_EDGE;
break;
case REPEAT_X:
wrapS = GLES30.GL_REPEAT;
wrapT = GLES30.GL_CLAMP_TO_EDGE;
break;
case REPEAT_Y:
wrapS = GLES30.GL_CLAMP_TO_EDGE;
wrapT = GLES30.GL_REPEAT;
break;
case REPEAT:
wrapS = GLES30.GL_REPEAT;
wrapT = GLES30.GL_REPEAT;
break;
}
//设置s轴拉伸方式---重复
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, wrapS);
//设置t轴拉伸方式---重复
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, wrapT);
//实际加载纹理(纹理类型,纹理的层次,纹理图像,纹理边框尺寸)
GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle(); //纹理加载成功后释放图片
return textureId;
}
}
enum RepeatType {
NONE,//不重复
REPEAT_X,//仅x轴重复
REPEAT_Y,//仅y轴重复
REPEAT//x,y重复
}
复制代码
主要将vsh中颜色的输入变量缓存坐标变量,在fsh中经过texture函数获取色值
---->[texture.vsh]----
#version 300 es
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec2 aTexCoord;
uniform mat4 uMVPMatrix;
out vec2 vTexCoord;
void main(){
gl_Position = uMVPMatrix*vec4(aPosition.x, aPosition.y, aPosition.z, 1.0);
vTexCoord = aTexCoord;
}
---->[texture.fsh]----
#version 300 es
precision mediump float;
out vec4 outColor;
in vec2 vTexCoord;
uniform sampler2D sTexture;
void main(){
outColor = texture(sTexture, vTexCoord);
}
复制代码
主体和前面同样,这里用GLTextureTriangle类进行贴图测试
public class GLTextureTriangle {
//顶点数组
private final float vertexes[] = { //以逆时针顺序
1.0f, 1.0f, 0.0f,//原点
-1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
};
// 贴图坐标
private final float textureCoo[] = new float[]{
1.0f,0.0f,
0.0f,0.0f,
0.0f,1.0f,
1.0f,1.0f,
};
private int program;
private static final int VERTEX_DIMENSION = 3;
private static final int TEXTURE_DIMENSION = 2;
private FloatBuffer vertBuffer;
private FloatBuffer textureCooBuffer;
private int aPosition = 0;//位置的句柄
private int aTexCoord = 1;//颜色的句柄
private int uMVPMatrix;//顶点变换矩阵句柄
private int textureId;//贴图id
public GLTextureTriangle(Context context) {
textureId= GLTexture.loadTexture(context, R.mipmap.chaos);
program = GLLoader.initProgramByAssets(context, "texture.vsh", "texture.fsh");
vertBuffer = GLBuffer.getFloatBuffer(vertexes);
textureCooBuffer = GLBuffer.getFloatBuffer(textureCoo);
uMVPMatrix = GLES30.glGetUniformLocation(program, "uMVPMatrix");
}
public void draw(float[] mvpMatrix) {
//清除颜色缓存和深度缓存
GLES30.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
// 将程序添加到OpenGL ES环境中
GLES30.glUseProgram(program);
GLES30.glUniformMatrix4fv(uMVPMatrix, 1, false, mvpMatrix, 0);
//启用三角形顶点的句柄
GLES30.glEnableVertexAttribArray(aPosition);
//启用三角形顶点颜色的句柄
GLES30.glEnableVertexAttribArray(aTexCoord);
//准备三角坐标数据
GLES30.glVertexAttribPointer(
aPosition, VERTEX_DIMENSION,
GLES30.GL_FLOAT, false,
VERTEX_DIMENSION * 4, vertBuffer);
//准备顶点颜色数据
GLES30.glVertexAttribPointer(
aTexCoord, TEXTURE_DIMENSION,
GLES30.GL_FLOAT, false,
TEXTURE_DIMENSION * 4, textureCooBuffer);
//绑定纹理
GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureId);
//绘制点
GLES30.glLineWidth(10);
GLES30.glDrawArrays(GLES30.GL_TRIANGLE_FAN, 0, vertexes.length / VERTEX_DIMENSION);
//禁用顶点数组
GLES30.glDisableVertexAttribArray(aPosition);
GLES30.glDisableVertexAttribArray(aTexCoord);
}
}
复制代码
也许你会以为,废了这么大半天的劲就展现了一个图片,有什么意义?
这就像你给一个不懂编程的人用计算机算出10+10=20同样,他也会以为没什么意义
但当你演示34564*9894=341976216他就会以为很厉害。其实本质并无什么区别
经过着色器的编写,你就能够完成你须要的特效,好比OpenGLES3.0 接入视频实现特效 - 引言
理论上你能够经过shader完成一切图片特效。下一篇将会详细介绍着色器代码的使用,你将会了解如何经过着色器的代码控制像素值以及像素的位置。本片就这样,相信你已经能够完成贴图了。
@张风捷特烈 2020.01.11 未允禁转
个人公众号:编程之王
联系我--邮箱:1981462002@qq.com --微信:zdl1994328
~ END ~