OpenGL ES 纹理实践

这篇博客介绍了一位开发者如何在Android环境下使用OpenGL ES进行纹理实践,包括绘制6个矩形,每个矩形使用不同的纹理显示方式,如重复、拉伸和clamp,并展示了如何实现两个纹理的混合效果。内容涵盖了纹理图像的加载、纹理参数设置、顶点坐标与UV坐标、以及如何通过Shader实现多重纹理混合。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

环境 基于 Android GLSurfaceView 

实践内容 :

绘制6个矩形。
1.指定2个纹理图像。每3个矩形使用同一纹理。
2.对同一纹理的两个矩形,分别按照:重复显示部分图像、拉伸、clamp方式显示。
3.再绘制一个矩形,其纹理为2个纹理的混合。(混合方式由用户指定)

最终效果如下 :
   



以下是 GLSurfaceView的绘图,
读取Bitmap 和绑定Texture 在 OnCreat中进行

摄像机使用的是投影矩阵,注意这里画矩形的时候,因为卷绕方向为背面,所以把背面剔除关了~~,
分别画了 7个矩矩形
package com.talentgame.openglestexture;
 
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.GLUtils;
 
import java.io.InputStream;
 
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL;
import javax.microedition.khronos.opengles.GL10;
 
import utils.MatrixState;
 
/**
 * Created by 54560 on 2016/10/11.
 */
public class MyGLSurfaceView extends GLSurfaceView {
    int[] textures = new int[7];
    DrawRect[] rect = new DrawRect[6];
    DrawRect mutRect;
    public MyGLSurfaceView(Context context) {
        super(context);
        this.setEGLContextClientVersion(2);
        ZjRenderer zjRenderer = new ZjRenderer();
 
        this.setRenderer(zjRenderer);
        setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
    }
    private  class ZjRenderer implements GLSurfaceView.Renderer
    {
        @Override
        public void onDrawFrame(GL10 gl) {
 
            GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
            MatrixState.PushMatrix();
            MatrixState.scale(1.1f,1.1f,1.1f);
            MatrixState.translate(0,0.4f,0);
 
            MatrixState.PushMatrix();
            MatrixState.translate(0,0.8f,0);
            rect[0].DrawSelf();
            MatrixState.PopMatrix();
 
            MatrixState.PushMatrix();
            MatrixState.translate(0,0.4f,0);
            rect[1].DrawSelf();
            MatrixState.PopMatrix();
 
            MatrixState.PushMatrix();
            MatrixState.translate(0,0.0f,0);
            rect[2].DrawSelf();
            MatrixState.PopMatrix();
 
            MatrixState.PushMatrix();
            MatrixState.translate(0,-0.4f,0);
            rect[3].DrawSelf();
            MatrixState.PopMatrix();
 
            MatrixState.PushMatrix();
            MatrixState.translate(0,-0.8f,0);
            rect[4].DrawSelf();
            MatrixState.PopMatrix();
 
            MatrixState.PushMatrix();
            MatrixState.translate(0,-1.2f,0);
            rect[5].DrawMutSelf();
            MatrixState.PopMatrix();
 
            MatrixState.PushMatrix();
            MatrixState.translate(0,-1.6f,0);
            mutRect.DrawMutSelf();
            MatrixState.PopMatrix();
            MatrixState.PopMatrix();
        }
 
        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
 
            InitTexture();
            GLES20.glClearColor(0,0,0,1.0f);
            //开启深度测试
            GLES20.glEnable(GLES20.GL_DEPTH_TEST);
            //开启背面剔除
            //GLES20.glEnable(GLES20.GL_CULL_FACE);
 
            rect[0] = new DrawRect(MyGLSurfaceView.this,textures[0]);
            rect[1] = new DrawRect(MyGLSurfaceView.this,textures[0]);
            rect[1].SetBigUv();
            rect[2] = new DrawRect(MyGLSurfaceView.this,textures[1]);
            rect[2].SetBigUv();
 
            rect[3] = new DrawRect(MyGLSurfaceView.this,textures[2]);
            rect[4] = new DrawRect(MyGLSurfaceView.this,textures[2]);
            rect[4].SetBigUv();
            rect[5] = new DrawRect(MyGLSurfaceView.this,textures[3]);
            rect[5].SetBigUv();
            mutRect = new DrawRect(MyGLSurfaceView.this,textures[0],textures[2]);
            //初始化成单位矩阵
            MatrixState.SetInit();
        }
 
        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
            GLES20.glViewport(0,0,width,height);
            float ratio = (float)width/height; //计算宽高比
            MatrixState.setProjectFrustum(-ratio,ratio, -1, 1, 1, 100);
            MatrixState.SetCamera(0, 0, 1.5f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
        }
 
 
        public void InitTexture()
        {
            //文件中加载图片
            Bitmap bitmap1 =  LoadImageFromAsset("myTex.jpg");
            Bitmap bitmap2 = LoadImageFromAsset("myTex2.jpg");
 
            //生成7张贴图
            GLES20.glGenTextures(
                    4,
                    textures,
                    0
            );
 
 
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,textures[0]);
            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST);
            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);
            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE);
            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);
 
            GLUtils.texImage2D(
                    GLES20.GL_TEXTURE_2D,
                    0,
                    bitmap1,
                    0
            );
 
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,textures[1]);
            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST);
            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);
            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_REPEAT);
            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_REPEAT);
            GLUtils.texImage2D(
                    GLES20.GL_TEXTURE_2D,
                    0,
                    bitmap1,
                    0
            );
 
            //第二张图片
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,textures[2]);
            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST);
            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);
            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE);
            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);
            GLUtils.texImage2D(
                    GLES20.GL_TEXTURE_2D,
                    0,
                    bitmap2,
                    0
            );
 
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,textures[3]);
            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST);
            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);
            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_REPEAT);
            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_REPEAT);
            GLUtils.texImage2D(
                    GLES20.GL_TEXTURE_2D,
                    0,
                    bitmap2,
                    0
            );
            if(bitmap1 != null)
                    bitmap1.recycle();
            if(bitmap2 != null)
                bitmap2.recycle();
        }
 
        public  Bitmap LoadImageFromAsset(String file)
        {
            Bitmap bitmap = null;
            try{
                InputStream is = getResources().getAssets().open(file);
                bitmap = BitmapFactory.decodeStream(is);
                //加载贴图进显存
                is.close();
            }catch (Exception e)
            {
                e.printStackTrace();
            }
            return bitmap;
        }
    }
}



矩形的绘制比较简单,但要记住,OpenGL任何的面都是三角形,所以这里有6个顶点。

为了让 贴图可以展示出 Repeat,Clamp,和原图,需要2份Uv坐标 ,因为只有Uv坐标大于 1,才可以体现出来

注意:
    Uv坐标系 从 左上角开始 S-T , S相当于X轴,T相当于Y轴,范围是 0~1. 

多重纹理:
    多重纹理使用了 另一份Shader,注意,这里为了让2张贴图不混乱,需要对Shader 里 Uniform 中 Sampler2D 进行赋值,且使int值,0,1。。怎么赋值就不说了

以下是2个贴图的 片元着色器
varying vec2 vTexCoor;
 
uniform sampler2D tex1;
uniform sampler2D tex2;
void main() {
//正片叠底
gl_FragColor = texture2D(tex1,vTexCoor) + texture2D(tex2,vTexCoor);
}

以下是DrawRect 画矩形,顶点是6个,因为矩形是2个三角形~
package com.talentgame.openglestexture;
 
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLUtils;
 
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
 
import utils.MatrixState;
import utils.ShaderUtls;
 
/**
 * Created by 54560 on 2016/10/11.
 */
public class DrawRect {
 
    private MyGLSurfaceView myGLSurfaceView;
 
    public float UnitSize = 1.5f;
    public FloatBuffer vertBuffer;
    public FloatBuffer uvBuffer;
    //顶点指针
    public int mVertPosHandle;
    public int mUvHandle;
    public  int mMvpMatrixHandle;
 
    public int mTex1Handle;
    public int mTex2Handle;
 
    public int mProgram;
 
    public String mVertShader;
    public String mFragShader;
 
    //顶点数量
    public int vCount;
    //贴图Id
    public int[] texIds = new int[2];
 
 
    public DrawRect(MyGLSurfaceView myGLSurfaceView,int texId)
    {
        this.myGLSurfaceView = myGLSurfaceView;
        InitVertex();
        InitShader();
        texIds[0] = texId;
    }
    public DrawRect(MyGLSurfaceView myGLSurfaceView,int texId0,int texId1)
    {
        this.myGLSurfaceView = myGLSurfaceView;
        InitVertex();
        InitMutShader();
        texIds[0] = texId0;
        texIds[1] = texId1;
 
    }
 
    public void SetBigUv()
    {
        uvBuffer.clear();
        float[] uv = new float[]{
                0,0,
                2,0,
                2,1,
 
                2,1,
                0,1,
                0,0,
        };
 
        ByteBuffer byteBuffer1 = ByteBuffer.allocateDirect(uv.length * 4);
        uvBuffer = byteBuffer1.order(ByteOrder.nativeOrder()).asFloatBuffer();
        uvBuffer.put(uv);
        uvBuffer.position(0);
    }
    public  void InitVertex()
    {
        //初始化顶点数据
        float[] vertexs = new float[]{
                -0.2f,0.1f,0,
                0.2f,0.1f,0,
                0.2f,-0.1f,0,
 
                0.2f,-0.1f,0f,
                -0.2f,-0.1f,0f,
                -0.2f,0.1f,0f
        };
        //乘与单位
        for (int i=0;i<vertexs.length;i++)
            vertexs[i]*= UnitSize;
 
        vCount = vertexs.length /3;
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertexs.length * 4);
        vertBuffer = byteBuffer.order(ByteOrder.nativeOrder()).asFloatBuffer();
        vertBuffer.put(vertexs);
        vertBuffer.position(0);
 
        float[] uv = new float[]{
                0,0,
                1,0,
                1,1,
 
                1,1,
                0,1,
                0,0,
        };
 
        ByteBuffer byteBuffer1 = ByteBuffer.allocateDirect(uv.length * 4);
        uvBuffer = byteBuffer1.order(ByteOrder.nativeOrder()).asFloatBuffer();
        uvBuffer.put(uv);
        uvBuffer.position(0);
    }
    public void InitShader()
    {
        mVertShader = ShaderUtls.LoadShaderFromAsset("rectVert.glsl",myGLSurfaceView.getResources());
        mFragShader = ShaderUtls.LoadShaderFromAsset("rectFrag.glsl",myGLSurfaceView.getResources());
 
        mProgram = ShaderUtls.CreatProgram(mVertShader,mFragShader);
 
        mVertPosHandle = GLES20.glGetAttribLocation(mProgram,"aPosition");
        mUvHandle = GLES20.glGetAttribLocation(mProgram,"aUv");
        mMvpMatrixHandle = GLES20.glGetUniformLocation(mProgram,"uMvpMatirx");
    }
 
    public void InitMutShader()
    {
        mVertShader = ShaderUtls.LoadShaderFromAsset("rectVert.glsl",myGLSurfaceView.getResources());
        mFragShader = ShaderUtls.LoadShaderFromAsset("mutTextureFrag.glsl",myGLSurfaceView.getResources());
 
        mProgram = ShaderUtls.CreatProgram(mVertShader,mFragShader);
 
        mVertPosHandle = GLES20.glGetAttribLocation(mProgram,"aPosition");
        mUvHandle = GLES20.glGetAttribLocation(mProgram,"aUv");
        mTex1Handle = GLES20.glGetUniformLocation(mProgram,"tex1");
        mTex2Handle = GLES20.glGetUniformLocation(mProgram,"tex2");
 
        mMvpMatrixHandle = GLES20.glGetUniformLocation(mProgram,"uMvpMatirx");
    }
 
    public void DrawSelf() {
        GLES20.glUseProgram(mProgram);
 
        GLES20.glVertexAttribPointer(mVertPosHandle, 3, GLES20.GL_FLOAT, false, 3 * 4, vertBuffer);
        GLES20.glVertexAttribPointer(mUvHandle, 2, GLES20.GL_FLOAT, false, 2 * 4, uvBuffer);
        GLES20.glUniformMatrix4fv(mMvpMatrixHandle, 1, false, MatrixState.GetMVPMatrix(), 0);
 
        GLES20.glEnableVertexAttribArray(mVertPosHandle);
        GLES20.glEnableVertexAttribArray(mUvHandle);
 
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texIds[0]);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
    }
 
    public void DrawMutSelf() {
        GLES20.glUseProgram(mProgram);
 
        GLES20.glVertexAttribPointer(mVertPosHandle, 3, GLES20.GL_FLOAT, false, 3 * 4, vertBuffer);
        GLES20.glVertexAttribPointer(mUvHandle, 2, GLES20.GL_FLOAT, false, 2 * 4, uvBuffer);
        GLES20.glUniformMatrix4fv(mMvpMatrixHandle, 1, false, MatrixState.GetMVPMatrix(), 0);
 
        GLES20.glEnableVertexAttribArray(mVertPosHandle);
        GLES20.glEnableVertexAttribArray(mUvHandle);
 
        GLES20.glUniform1i(mTex1Handle,0);
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texIds[0]);
 
        GLES20.glUniform1i(mTex1Handle,1);
        GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texIds[1]);
 
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值