android 使用OPENGL ES实现纹理拉伸效果-纹理映射基础

时间:2024-03-15 18:41:59

效果图:

android 使用OPENGL ES实现纹理拉伸效果-纹理映射基础


编写dad.java文件

         *声明三个矩形,分别贴s,t的最大值为1X1、4X4、4X2的纹理涂,在场景中分别绘制1X1、4X4、4X2的纹理矩形

      *设置视窗的大小、矩阵类型、并设置投影模式为透视投影

      *定义封装方法initTexture()以获取纹理ID,该方法通过收取图片ID,生成一个纹理ID并返回


package com.scout.eeeeeee;

/**
 * Created by liuguodong on 2017/10/28.
 */
import java.io.IOException;
import java.io.InputStream;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;


import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView;
import android.opengl.GLUtils;

public class dad extends GLSurfaceView{
    private SceneRenderer mRenderer;//定义场景渲染器

    public dad(Context context) {
        super(context);
        mRenderer = new SceneRenderer();   //创建渲染器
        setRenderer(mRenderer);             //设置渲染器
        setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);//设置主动渲染模式
    }

    private class SceneRenderer implements GLSurfaceView.Renderer
    {
        int testTexId;//纹理

        laCH trOneXOne;//1*1贴图矩形
        laCH trFourXFour;//4*4贴图矩形
        laCH trFourXTwo;//4*2贴图矩形

        public void onDrawFrame(GL10 gl) {
            //打开背面剪裁
            gl.glEnable(GL10.GL_CULL_FACE);
            //着色模型为平滑着色
            gl.glShadeModel(GL10.GL_SMOOTH);
            //清除颜色缓存
            gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
            //模式矩阵
            gl.glMatrixMode(GL10.GL_MODELVIEW);
            //单位矩阵
            gl.glLoadIdentity();

            //推远场景
            gl.glTranslatef(0, 0, -3);
            //绘制1*1纹理矩形
            gl.glPushMatrix();
            gl.glTranslatef(-3.5f, 0, 0);
            trOneXOne.drawSelf(gl);
            gl.glPopMatrix();
            //绘制4*4纹理矩形
            gl.glPushMatrix();
            gl.glTranslatef(0, 0, 0);
            trFourXFour.drawSelf(gl);
            gl.glPopMatrix();
            //绘制4*4纹理矩形
            gl.glPushMatrix();
            gl.glTranslatef(3.5f, 0, 0);
            trFourXTwo.drawSelf(gl);
            gl.glPopMatrix();
        }

        public void onSurfaceChanged(GL10 gl, int width, int height) {
            //视窗大小及位置
            gl.glViewport(0, 0, width, height);
            //设置为为投影矩阵
            gl.glMatrixMode(GL10.GL_PROJECTION);
            //设置为单位矩阵
            gl.glLoadIdentity();
            //获取透视投影的比例
            float ratio = (float) width / height;
            //计算产生透视投影矩阵
            gl.glFrustumf(-ratio, ratio, -1, 1, 1, 100);
        }

        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            //抗抖动 关闭
            gl.glDisable(GL10.GL_DITHER);
            //设置使用快速模式
            gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,GL10.GL_FASTEST);
            //设置屏幕背景色黑色RGBA
            gl.glClearColor(0,0,0,0);
            //深度测试
            gl.glEnable(GL10.GL_DEPTH_TEST);
            //纹理初始化
            testTexId=initTexture(gl,R.drawable.lashen);
            //创建纹理矩形
            trOneXOne=new laCH(1.5f,1.5f,testTexId,1,1);//s-t  0-1
            trFourXFour=new laCH(1.5f,1.5f,testTexId,4,4);//s-t 4-4
            trFourXTwo=new laCH(1.5f,1.5f,testTexId,4,2);//s-t 4-2
        }
    }

    //初始化纹理
    public int initTexture(GL10 gl,int drawableId)//textureId
    {
        //生成纹理ID
        int[] textures = new int[1];
        gl.glGenTextures(1, textures, 0);
        int currTextureId=textures[0];
        gl.glBindTexture(GL10.GL_TEXTURE_2D, currTextureId);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_NEAREST);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MAG_FILTER,GL10.GL_LINEAR);
        //设置纹理拉伸方式为重复
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,GL10.GL_REPEAT);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,GL10.GL_REPEAT);

        InputStream is = this.getResources().openRawResource(drawableId);
        Bitmap bitmapTmp;
        try
        {
            bitmapTmp = BitmapFactory.decodeStream(is);
        }
        finally
        {
            try
            {
                is.close();
            }
            catch(IOException e)
            {
                e.printStackTrace();
            }
        }
        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmapTmp, 0);
        bitmapTmp.recycle();

        return currTextureId;
    }
}


编写laCH

    *初始化顶点坐标数据,冰川件顶点坐标数据缓冲
    *定义方法drawSelf()来开启纹理以绘制图形

 

package com.scout.eeeeeee;

/**
 * Created by liuguodong on 2017/10/29.
 */

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.opengles.GL10;

public class laCH {

    private FloatBuffer   mVertexBuffer;//缓冲顶点坐标
    private FloatBuffer mTextureBuffer;//缓冲顶点纹理
    int vCount=0;
    int texId;

    public laCH(float width,float height,int texId,float sRange,float tRange)
    {
        this.texId=texId;

        //开始初始化顶点坐标数据
        vCount=6;
        final float UNIT_SIZE=1.0f;
        float vertices[]=new float[]
                {
                        width*UNIT_SIZE,height*UNIT_SIZE,0,
                        -width*UNIT_SIZE,height*UNIT_SIZE,0,
                        -width*UNIT_SIZE,-height*UNIT_SIZE,0,

                        -width*UNIT_SIZE,-height*UNIT_SIZE,0,
                        width*UNIT_SIZE,-height*UNIT_SIZE,0,
                        width*UNIT_SIZE,height*UNIT_SIZE,0,
                };

        //创建顶点坐标数据缓冲
        ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);
        vbb.order(ByteOrder.nativeOrder());//字节顺序
        mVertexBuffer = vbb.asFloatBuffer();//转为Float型
        mVertexBuffer.put(vertices);//在缓冲区中放入顶点坐标数据
        mVertexBuffer.position(0);//设置缓冲区起始位置


        //初始化纹理 坐标
        float[] texST=
                {
                        sRange,0,
                        0,0,
                        0,tRange,
                        0,tRange,
                        sRange,tRange,
                        sRange,0
                };
        ByteBuffer tbb = ByteBuffer.allocateDirect(texST.length*4);
        tbb.order(ByteOrder.nativeOrder());//字节顺序
        mTextureBuffer = tbb.asFloatBuffer();//转换为int型
        mTextureBuffer.put(texST);//在缓冲区保存顶点着色数据
        mTextureBuffer.position(0);//缓冲区的起始位置

    }

    public void drawSelf(GL10 gl)
    {
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);//启用顶点坐标数组


        //设置画笔的顶点坐标
        gl.glVertexPointer
                (
                        3,
                        GL10.GL_FLOAT,
                        0,
                        mVertexBuffer
                );

        //打开纹理
        gl.glEnable(GL10.GL_TEXTURE_2D);
        //使用纹理ST坐标缓冲
        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        //用指定纹理设置画笔ST坐标
        gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTextureBuffer);
        //绑定当前纹理
        gl.glBindTexture(GL10.GL_TEXTURE_2D, texId);

        //绘制图形
        gl.glDrawArrays
                (
                        GL10.GL_TRIANGLES,        //用三角形方式填充
                        0,
                        vCount
                );
    }
}

MyActivity.java

package com.scout.eeeeeee;

import android.app.Activity;
import android.os.Bundle;
import android.app.Activity;
import android.os.Bundle;
import android.app.Activity;
import android.os.Bundle;

public class MyActivity extends Activity {
    /** Called when the activity is first created. */
    private dad mGLSurfaceView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mGLSurfaceView = new dad(this);
        mGLSurfaceView.requestFocus();//获取焦点
        mGLSurfaceView.setFocusableInTouchMode(true);//设置为可触控

        setContentView(mGLSurfaceView);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mGLSurfaceView.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mGLSurfaceView.onPause();
    }
}

注意:当在实现海洋或草原等较大纹理贴图时,使用纹理映射的拉伸方式既可以节省内存,又可以保证画面的真实性