OpenGL ES實現三棱錐紋理貼圖

這是老師佈置的課後作業,閒來無事分享出來,也加深一遍自己的印象~

自己定義一個MyRenderer.java類:

package com.example.shiyan3_2;


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

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

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


public class MyRenderer implements Renderer
{
    // 定義三棱椎的4個頂點
    float[] taperVertices = new float[] {
            0.0f, 0.5f, 0.0f,
            -0.5f, -0.5f, -0.2f,
            0.5f, -0.5f, -0.2f,
            0.0f, -0.2f, 0.2f
    };
    // 定義三棱椎的4個三角面(沒有使用)
    private byte[] taperFacets = new byte[]{
            0, 1, 2, // 0、1、2三個頂點組成一個面
            0, 1, 3, // 0、1、3三個頂點組成一個面
            1, 2, 3, // 1、2、3三個頂點組成一個面
            0, 2, 3 // 0、2、3三個頂點組成一個面
    };
    //定義紋理貼圖的座標數據
    private float[] taperTextures = {
            1.0000f,1.0000f,
            1.0000f,0.0000f,
            0.0000f,0.0000f,
            0.0000f,1.0000f

    };
    // 分別定義三棱椎的4個三角面
    ByteBuffer i1=ByteBuffer.wrap(new byte[]{
        0,1,2,
    });
    ByteBuffer i2=ByteBuffer.wrap(new byte[]{
            0,1,3,
    });
    ByteBuffer i3=ByteBuffer.wrap(new byte[]{
            1,2,3
    });
    ByteBuffer i4=ByteBuffer.wrap(new byte[]{
            0,2,3,
    });

    Context context;
    // 定義Open GL ES繪製所需要的Buffer對象
    FloatBuffer taperVerticesBuffer;
    //IntBuffer taperColorsBuffer;
    ByteBuffer taperFacetsBuffer;
    FloatBuffer taperTexturesBuffer;

    // 控制旋轉的角度
    private float rotate;

    //定義本程序所使用的紋理
    private int texture;

    public MyRenderer(Context main)
    {
        this.context = main;
        // 將三棱椎的頂點位置數據數組包裝成FloatBuffer
        taperVerticesBuffer = floatBufferUtil(taperVertices);
        // 將三棱椎的4個面的數組包裝成ByteBuffer
        taperFacetsBuffer = ByteBuffer.wrap(taperFacets);
        //將立方體的紋理貼圖的座標數據包裝成FLoatBuffer
        taperTexturesBuffer = floatBufferUtil(taperTextures);

    }
    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config)
    {
        // 關閉抗抖動
        gl.glDisable(GL10.GL_DITHER);
        // 設置系統對透視進行修正
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
        gl.glClearColor(0, 0, 0, 0);
        // 設置陰影平滑模式
        gl.glShadeModel(GL10.GL_SMOOTH);
        // 啓用深度測試
        gl.glEnable(GL10.GL_DEPTH_TEST);
        // 設置深度測試的類型
        gl.glDepthFunc(GL10.GL_LEQUAL);
        //啓用2D紋理貼圖
        gl.glEnable(GL10.GL_TEXTURE_2D);
        //裝載紋理
        loadTexture(gl);
    }
    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height)
    {
        // 設置3D視窗的大小及位置
        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, 10);
    }
    // 繪製圖形的方法
    int[] tex_id = new int[4];


    @Override
    public void onDrawFrame(GL10 gl)
    {

        // 清除屏幕緩存和深度緩存
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        // 啓用頂點座標數據
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        //啓用貼圖座標數組數據
        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);   // ①
        // 設置當前矩陣模式爲模型視圖。
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        // --------------------繪製圖形---------------------
        // 重置當前的模型視圖矩陣
        gl.glLoadIdentity();
        gl.glTranslatef(0.0f, 0.0f, -1.5f);
        // 沿着Y軸旋轉
        gl.glRotatef(rotate, 0f, 0.2f, 0f);
        // 設置頂點的位置數據
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, taperVerticesBuffer);
        //設置貼圖的座標數據
        gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, taperTexturesBuffer);  // ②
        //執行紋理貼圖
        gl.glBindTexture(GL10.GL_TEXTURE_2D, tex_id[0]);  // ③
        // 按taperFacetsBuffer指定的面繪製三角形
        gl.glDrawElements(GL10.GL_TRIANGLE_STRIP
                , i1.remaining(),
                GL10.GL_UNSIGNED_BYTE, i1);
        gl.glBindTexture(GL10.GL_TEXTURE_2D, tex_id[1]);  // ③
        // 按taperFacetsBuffer指定的面繪製三角形
        gl.glDrawElements(GL10.GL_TRIANGLE_STRIP
                , i2.remaining(),
                GL10.GL_UNSIGNED_BYTE, i2);
        gl.glBindTexture(GL10.GL_TEXTURE_2D, tex_id[2]);  // ③
        // 按taperFacetsBuffer指定的面繪製三角形
        gl.glDrawElements(GL10.GL_TRIANGLE_STRIP
                , i3.remaining(),
                GL10.GL_UNSIGNED_BYTE, i3);
        gl.glBindTexture(GL10.GL_TEXTURE_2D, tex_id[3]);  // ③
        // 按taperFacetsBuffer指定的面繪製三角形
        gl.glDrawElements(GL10.GL_TRIANGLE_STRIP
                , i4.remaining(),
                GL10.GL_UNSIGNED_BYTE, i4);


        // 繪製結束
        gl.glFinish();
        //禁用頂點、紋理座標數組
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        // 旋轉角度增加1
        rotate+=1;
    }
    private void loadTexture(GL10 gl){
        // 加載位圖
        Bitmap[] bm = new Bitmap[4];
        bm[0]=BitmapFactory.decodeResource(context.getResources(),
                R.drawable.img1);
        bm[1]=BitmapFactory.decodeResource(context.getResources(),
                R.drawable.img2);
        bm[2]=BitmapFactory.decodeResource(context.getResources(),
                R.drawable.img3);
        bm[3]=BitmapFactory.decodeResource(context.getResources(),
                R.drawable.img4);



        try{

            int[] textures = new int[1];
            // 指定生成N個紋理(第一個參數指定生成一個紋理)
            // textures數組將負責存儲所有紋理的代號
            IntBuffer textureBuffer = IntBuffer.allocate(4);
            gl.glGenTextures(4,textureBuffer);
            tex_id = textureBuffer.array();
            for(int i=0;i<4;i++){
                // 獲取textures紋理數組中的第一個紋理
                //texture = textures[i];
                // 通知OpenGL將texture紋理綁定到GL10.GL_TEXTURE_2D目標中
                gl.glBindTexture(GL10.GL_TEXTURE_2D, tex_id[i]);
                //gl.glBindTexture(GL10.GL_TEXTURE_2D, texture);
                // 設置紋理被縮小(距離視點很遠時被縮小)時的濾波方式
                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);
                // 加載位圖生成紋理
                GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bm[i], 0);
                if (bm[i] != null)
                    bm[i].recycle();
            }

        }
        finally {
            //生成紋理之後,回收位圖


        }
    }

    // 定義一個工具方法,將float[]數組轉換爲OpenGL ES所需的FloatBuffer
    private FloatBuffer floatBufferUtil(float[] arr)
    {
        FloatBuffer mBuffer;
        // 初始化ByteBuffer,長度爲arr數組的長度*4,因爲一個int佔4個字節
        ByteBuffer qbb = ByteBuffer.allocateDirect(arr.length * 4);
        // 數組排列用nativeOrder
        qbb.order(ByteOrder.nativeOrder());
        mBuffer = qbb.asFloatBuffer();
        mBuffer.put(arr);
        mBuffer.position(0);
        return mBuffer;
    }
}

接下來是MainActivity.java:

package com.example.shiyan3_2;


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


public class MainActivity extends Activity
{
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        // 創建一個GLSurfaceView,用於顯示OpenGL繪製的圖形
        GLSurfaceView glView = new GLSurfaceView(this);
        // 創建GLSurfaceView的內容繪製器
        MyRenderer myRender = new MyRenderer(this);
        // 爲GLSurfaceView設置繪製器
        glView.setRenderer(myRender);
        setContentView(glView);
    }
}

記得加入紋理貼圖,這裏圖片的格式是256x256的:

最後展示一下運行結果:

      

   

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章