文章预览
大家好,接下来将为大家介绍OpenGL ES 3. 纹理映射。
1、纹理映射原理
启用纹理映射功能后,如果想把纹理应用到相应的几何图元,就必须告知渲染系统如何进行纹理的映射。告知的方式就是为图元中的顶点指定恰当的纹理坐标,纹理坐标用浮点数来表 示,范围一般从 0.0 到 1.0 。
在 OpenGLES 中,纹理映射就是
通过为图元的顶点坐标指定恰当的纹理坐标,通过纹理坐标在纹理图中选定特定的纹理区域,最后通过纹理坐标与顶点的映射关系,将选定的纹理区域映射到指定图元上
。
纹理映射也称为纹理贴图,简单地说就是将纹理坐标(纹理坐标系)所指定的纹理区域,映射到顶点坐标(渲染坐标系或OpenGLES 坐标系)对应的渲染区域。
如下图所示,要想将正三角形纹理正确的显示出来,需要告诉OpenGL,三角形中每个顶点的纹理坐标是多少(左下角顶点(0,0);右下角顶点(1,0);上中顶点(0.5,1))。
2、一个简单的例子
本案例基于前面小节内容所介绍的GLSurfaceView来实现的。
2.1 如下MySurfaceView类,用于创建OpenGL ES 相关的渲染器Render,创建纹理对象,指定OpenGL的投影方式等。
import android.graphics.BitmapFactory;
class MySurfaceView extends GLSurfaceView
{
private SceneRenderer mRenderer;
int textureId;
public MySurfaceView(Context context) {
super(context);
this.setEGLContextClientVersion(3);
mRenderer = new SceneRenderer();
setRenderer(mRenderer);
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
}
private class SceneRenderer implements GLSurfaceView.Renderer
{
Triangle texRect;
public void onDrawFrame(GL10 gl)
{
GLES30.glClear( GLES30.GL_DEPTH_BUFFER_BIT |
GLES30.GL_COLOR_BUFFER_BIT);
texRect.drawSelf(textureId);
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES30.glViewport(0, 0, width, height);
float ratio = (float) width / height;
MatrixState.setProjectFrustum(-ratio, ratio, -1, 1, 1, 10);
MatrixState.setCamera(0,0,3,0f,0f,0f,0f,1.0f,0.0f);
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLES30.glClearColor(0.5f,0.5f,0.5f, 1.0f);
texRect=new Triangle(MySurfaceView.this);
GLES30.glEnable(GLES30.GL_DEPTH_TEST);
initTexture();
GLES30.glDisable(GLES30.GL_CULL_FACE);
}
}
}
2.2 生成纹理并加载图像数据到纹理:initTexture()方法是非常常用的,用于创建OpenGL ES 纹理的方法。
public void initTexture()
{
int[] textures = new int[1];
GLES30.glGenTextures(
1,
textures,
0
);
textureId=textures[0];
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureId);
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);
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D,
GLES30.GL_TEXTURE_WRAP_S,GLES30.GL_CLAMP_TO_EDGE);
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D,
GLES30.GL_TEXTURE_WRAP_T,GLES30.GL_CLAMP_TO_EDGE);
InputStream is = this.getResources().openRawResource(R.drawable.wall);
Bitmap bitmapTmp;
try {
bitmapTmp = BitmapFactory.decodeStream(is);
}
finally {
try {
is.close();
}
catch(IOException e) {
e.printStackTrace();
}
}
GLUtils.texImage2D(
GLES30.GL_TEXTURE_2D,
0,
bitmapTmp,
0
);
bitmapTmp.recycle();
}
2.3 如下Triangle是三角形的操作封装。
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import android.opengl.GLES30;
public class Triangle
{
int mProgram;
int muMVPMatrixHandle;
int maPositionHandle;
int maTexCoorHandle;
String mVertexShader;
String mFragmentShader;
FloatBuffer mVertexBuffer;
FloatBuffer mTexCoorBuffer;
int vCount=0;
float xAngle=0;
float yAngle=0;
float zAngle=0;
public Triangle(MySurfaceView mv)
{
initVertexData();
initShader(mv);
}
public void initVertexData()
{
vCount=3;
float vertices[]=new float[]
{
0, 1, 0,
-1, -1, 0,
1, -1, 0
};
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);
vbb.order(ByteOrder.nativeOrder());
mVertexBuffer = vbb.asFloatBuffer();
mVertexBuffer.put(vertices);
mVertexBuffer.position(0);
float texCoor[]=new float[]
{
0.5f, 0,
0, 1,
1, 1
};
ByteBuffer cbb = ByteBuffer.allocateDirect(texCoor.length*4);
cbb.order(ByteOrder.nativeOrder());
mTexCoorBuffer = cbb.asFloatBuffer();
mTexCoorBuffer.put(texCoor);
mTexCoorBuffer.position(0);
}
public void initShader(MySurfaceView mv)
{
mVertexShader=ShaderUtil.loadFromAssetsFile("vertex.sh", mv.getResources());
mFragmentShader=ShaderUtil.loadFromAssetsFile("frag.sh", mv.getResources());
mProgram = createProgram(mVertexShader, mFragmentShader);
maPositionHandle = GLES30.glGetAttribLocation(mProgram, "aPosition");
maTexCoorHandle= GLES30.glGetAttribLocation(mProgram, "aTexCoor");
muMVPMatrixHandle = GLES30.glGetUniformLocation(mProgram, "uMVPMatrix");
}
public void drawSelf(int texId)
{
GLES30.glUseProgram(mProgram);
MatrixState.setInitStack();
MatrixState.translate(0, 0, 1);
MatrixState.rotate(yAngle, 0, 1, 0);
MatrixState.rotate(zAngle, 0, 0, 1);
MatrixState.rotate(xAngle, 1, 0, 0);
GLES30.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, MatrixState.getFinalMatrix(), 0);
GLES30.glVertexAttribPointer (maPositionHandle, 3, GLES30.GL_FLOAT,
false, 3*4, mVertexBuffer);
GLES30.glVertexAttribPointer (maTexCoorHandle, 2, GLES30.GL_FLOAT,
false, 2*4, mTexCoorBuffer);
GLES30.glEnableVertexAttribArray(maPositionHandle);
GLES30.glEnableVertexAttribArray(maTexCoorHandle);
GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, texId);
GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, vCount);
}
}
3、值得注意的是:三角形的纹理坐标,其Y坐标相对于开篇图示,做了Y方向的翻转。
float vertices[]=new float[]
{
0, 1, 0,
-1, -1, 0,
1, -1, 0
};
float texCoor[]=new float[]
{
0.5f, 0,
0, 1,
1, 1
};
4、纹理映射的shader
#version 300 es
uniform mat4 uMVPMatrix;
in vec3 aPosition;
in vec2 aTexCoor;
out vec2 vTextureCoord;
void main()
{
gl_Position = uMVPMatrix * vec4(aPosition,1);
vTextureCoord = aTexCoor;
}
#version 300 es
precision mediump float;
uniform sampler2D sTexture;
in vec2 vTextureCoord;
out vec4 fragColor;
void main()
{
fragColor = texture(sTexture, vTextureCoord);
}
5、原图与渲染结果
待渲染图片如下:
渲染结果如下:
最后,欢迎大家一起交流学习:微信:liaosy666 ; QQ:
2209115372
。
………………………………