【OpenGL ES】纹理贴图
ES OpenGL 纹理 贴图
2023-09-11 14:20:52 时间
1 前言
纹理贴图是指:将图片贴在模型的表面。
纹理贴图的本质是:将图片划分为一系列三角形,使得图片顶点序列与模型顶点序列中的顶点一一对应,对于模型中任意三角形内部的坐标和图片中对应三角形内部的坐标,可以通过插值,建立一一对应关系,模型中任意位置的颜色由其对应的图片位置的颜色填充。
本文完整代码资源见→【OpenGL ES】纹理贴图
项目目录如下:
2 案例
MainActivity.java
package com.zhyan8.texture;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private GLSurfaceView mGlSurfaceView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGlSurfaceView = new MyGLSurfaceView(this);
setContentView(mGlSurfaceView);
mGlSurfaceView.setRenderer(new MyRender(this));
}
@Override
protected void onResume() {
super.onResume();
mGlSurfaceView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mGlSurfaceView.onPause();
}
}
MyGLSurfaceView.java
package com.zhyan8.texture;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;
public class MyGLSurfaceView extends GLSurfaceView {
public MyGLSurfaceView(Context context) {
super(context);
setEGLContextClientVersion(3);
}
public MyGLSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
setEGLContextClientVersion(3);
}
}
MyRender.java
package com.zhyan8.texture;
import android.content.Context;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class MyRender implements GLSurfaceView.Renderer {
private FloatBuffer vertexBuffer;
private FloatBuffer textureBuffer;
private MyGLUtils mGLUtils;
private float[] mvpMatrix = new float[16];
private int mvpMatrixLocation;
private int mTextureId;
public MyRender(Context context) {
mGLUtils = new MyGLUtils(context);
getFloatBuffer();
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig eglConfig) {
//设置背景颜色
GLES30.glClearColor(0.1f, 0.2f, 0.3f, 0.4f);
//编译着色器
final int vertexShaderId = mGLUtils.compileShader(GLES30.GL_VERTEX_SHADER, R.raw.vertex_shader);
final int fragmentShaderId = mGLUtils.compileShader(GLES30.GL_FRAGMENT_SHADER, R.raw.fragment_shader);
//链接程序片段
int programId = mGLUtils.linkProgram(vertexShaderId, fragmentShaderId);
GLES30.glUseProgram(programId);
mvpMatrixLocation = GLES30.glGetUniformLocation(programId, "mvpMatrix");
mTextureId = mGLUtils.loadTexture(R.raw.xxx);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
//设置视图窗口
GLES30.glViewport(0, 0, width, height);
mGLUtils.transform(width, height, mvpMatrix);
}
@Override
public void onDrawFrame(GL10 gl) {
//将颜色缓冲区设置为预设的颜色
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
GLES30.glUniformMatrix4fv(mvpMatrixLocation, 1, false, mvpMatrix, 0);
//启用顶点的数组句柄
GLES30.glEnableVertexAttribArray(0);
GLES30.glEnableVertexAttribArray(1);
//准备顶点坐标和纹理坐标
GLES30.glVertexAttribPointer(0, 3, GLES30.GL_FLOAT, false, 0, vertexBuffer);
GLES30.glVertexAttribPointer(1, 2, GLES30.GL_FLOAT, false, 0, textureBuffer);
//激活纹理
GLES30.glActiveTexture(GLES30.GL_TEXTURE);
//绑定纹理
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mTextureId);
//绘制贴图
GLES30.glDrawArrays(GLES30.GL_TRIANGLE_FAN, 0, 4);
//禁止顶点数组句柄
GLES30.glDisableVertexAttribArray(0);
GLES30.glDisableVertexAttribArray(1);
}
private void getFloatBuffer() {
float[] vertex = new float[] {
1f, 1f, 0f, //V0
-1f, 1f, 0f, //V1
-1f, -1f, 0f, //V2
1f, -1f, 0f //V3
};
float[] texture = {
1f, 0f, //V0
0f, 0f, //V1
0f, 1.0f, //V2
1f, 1.0f //V3
};
vertexBuffer = mGLUtils.getFloatBuffer(vertex);
textureBuffer = mGLUtils.getFloatBuffer(texture);
}
}
MyGLUtils.java
package com.zhyan8.texture;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES30;
import android.opengl.GLUtils;
import android.opengl.Matrix;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
public class MyGLUtils {
private Context mContext;
private Bitmap mBitmap;
public MyGLUtils(Context context) {
mContext = context;
}
public FloatBuffer getFloatBuffer(float[] floatArr) {
FloatBuffer fb = ByteBuffer.allocateDirect(floatArr.length * Float.BYTES)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
fb.put(floatArr);
fb.position(0);
return fb;
}
//通过代码片段编译着色器
public int compileShader(int type, String shaderCode){
int shader = GLES30.glCreateShader(type);
GLES30.glShaderSource(shader, shaderCode);
GLES30.glCompileShader(shader);
return shader;
}
//通过外部资源编译着色器
public int compileShader(int type, int shaderId){
String shaderCode = readShaderFromResource(shaderId);
return compileShader(type, shaderCode);
}
//链接到着色器
public int linkProgram(int vertexShaderId, int fragmentShaderId) {
final int programId = GLES30.glCreateProgram();
//将顶点着色器加入到程序
GLES30.glAttachShader(programId, vertexShaderId);
//将片元着色器加入到程序
GLES30.glAttachShader(programId, fragmentShaderId);
//链接着色器程序
GLES30.glLinkProgram(programId);
return programId;
}
//从shader文件读出字符串
private String readShaderFromResource(int shaderId) {
InputStream is = mContext.getResources().openRawResource(shaderId);
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line;
StringBuilder sb = new StringBuilder();
try {
while ((line = br.readLine()) != null) {
sb.append(line);
sb.append("\n");
}
br.close();
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
//加载纹理贴图
public int loadTexture(int resourceId) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
mBitmap = BitmapFactory.decodeResource(mContext.getResources(), resourceId, options);
final int[] textureIds = new int[1];
// 生成纹理id
GLES30.glGenTextures(1, textureIds, 0);
// 绑定纹理到OpenGL
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureIds[0]);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR_MIPMAP_LINEAR);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
// 加载bitmap到纹理中
GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, 0, mBitmap, 0);
// 生成MIP贴图
GLES30.glGenerateMipmap(GLES30.GL_TEXTURE_2D);
// 取消绑定纹理
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);
return textureIds[0];
}
//调整图片宽高适配屏幕尺寸
public void transform(int width, int height, float[] matrix) {
int mapWidth = mBitmap.getWidth();
int mapHeight = mBitmap.getHeight();
float mapRatio = mapWidth / (float)mapHeight;
float ratio = width / (float)height;
float w = 1.0f;
float h = 1.0f;
if (mapRatio > ratio) { //宽度最大,高度适配
h = mapRatio / ratio;
} else { //高度最大,宽度适配
w = ratio / mapRatio;
}
Matrix.orthoM(matrix, 0, -w, w, -h, h,-1, 1);
}
}
vertex_shader.glsl
#version 300 es
layout (location = 0) in vec4 aPosition;
layout (location = 1) in vec2 aTextureCoord;
uniform mat4 mvpMatrix;
out vec2 vTexCoord;
void main() {
gl_Position = mvpMatrix * aPosition;
vTexCoord = aTextureCoord;
}
//attribute vec4 aPosition;
//attribute vec2 aTextureCoord;
//uniform mat4 mvpMatrix;
//varying vec2 vTexCoord;
//void main() {
// gl_Position = mvpMatrix * aPosition;
// vTexCoord = aTextureCoord;
//}
顶点着色器的作用:进行矩阵变换位置、根据光照公式计算顶点颜⾊、⽣成 / 变换纹理坐标,并且把位置和纹理坐标发送到片元着色器。
顶点着色器中,如果没有指定默认精度,则 int 和 float 的默认精度都为 highp。
fragment_shader.glsl
#version 300 es
precision mediump float;
uniform sampler2D uTextureUnit;
in vec2 vTexCoord;
out vec4 fragColor;
void main() {
fragColor = texture(uTextureUnit, vTexCoord);
}
//precision mediump float;
//uniform sampler2D uTextureUnit;
//varying vec2 vTexCoord;
//void main() {
// gl_FragColor = texture2D(uTextureUnit, vTexCoord);
//}
片元着色器的作用:处理经光栅化阶段生成的每个片元,计算每个像素的颜色和透明度。
在片元着色器中,浮点值没有默认的精度值,每个着色器必须声明一个默认的 float 精度。
运行结果:
相关文章
- elasticsearch es 索引重建
- elasticsearch es三种分页方式和对比
- ES 学习总结
- ES 集群上,业务单点如何优化升级?
- TextureView+SurfaceTexture+OpenGL ES来播放视频(一)
- OpenGL ES着色器语言之变量和数据类型(二)(官方文档第四章)
- OpenGL ES 详解纹理生成和纹理映射步骤以及函数
- Android OpenGL ES(十三)通用的矩阵变换指令 .
- Android OpenGL ES(七)基本几何图形定义 .
- 运用OpenGL ES 2.0实现各种各样图像滤镜(图像处理)效果,多达50多种效果。
- 第二章 你好三角形:一个OpenGL ES 2.0例子
- OpenGL ES着色器语言之变量和数据类型(一)(官方文档第四章)和varying,uniform,attribute修饰范围
- OpenGL ES着色器语言之静态使用(static use)和预处理
- Android OpenGL ES(八)绘制点Point ..
- Atitit it计算机应用体系图 大数据 爬虫 非结构数据 nosql redis mongodb 分布式存储 es搜索 可视化 多媒体与office 19.1. 14.3 计
- Atitit lucence es solr的各种query 与sql运算符的对比 目录 1.1. 等于运算 TermQuery1 1.2. 范围运算1 1.3. 大小运算1 1.4. Wi
- es 内存占用优化
- ElastaticSearch---- es聚合查询
- ES failed to notify ClusterStateListener java.lang.IllegalStateException: environment is not locked
- ES业界优秀实践案例汇总
- ES transport client底层是netty实现,netty本质上是异步方式,但是netty自身可以使用sync或者await(future超时机制)来实现类似同步调用!因此,ES transport client可以同步调用也可以异步(不过底层的socket必然是异步实现)
- ES盲点记录