OpenGL ES (4): 绘制3D图形-及进行表面贴图

1.简介


其实绘制3D图形跟之前绘制平面是一样的,只不过需要绘制的顶点变多了,平面变多了,且平面不在同一个平面中,这样绘制出来自然就组成了一个3D图形。

这次我们绘制一个4面体,用到的纹理贴图还是上一篇的图片,4面体坐标数据如下:

所以顶点数据 float[]{

0f,0.5f,0f , -0.5f,0f,0f , 0.5f,0f,0f ,

0f,0.5f,0f , 0.5f,0f,0f , 0f,0f,0.2f ,

0f,0.5f,0f , 0f,0f,0.2f , -0.5f,0f,0f ,

0f,0f,0.2f , 0.5f,0f,0f , -0.5f,0f,0f

};

4个面。12个顶点

注意:都是以逆时针顺序,这样进行贴图才是正面的。

面数据 byte[]{

0,1,2,

3,4,5,

6,7,8,

9,10,11

};

纹理坐标数据 float[]{

0f,0f , 0f,1f , 1f,1f,

0f,0f , 0f,1f , 1f,1f,

0f,0f , 1f,1f , 1f,0f,

0f,0f , 0f,1f , 1f,1f,

};

这样纹理和图形就一一映射上。

2.代码


public class OtherShader implements GLSurfaceView.Renderer{
    FloatBuffer vertextBuffer;
    FloatBuffer textureBuffer;
    ByteBuffer faceBuffer;
    private float roate;
    int texture;
    Context context;

    public OtherShader(Context context) {
        this.context = context;
        vertextBuffer = floatArray2Buffer(vertex);
        faceBuffer = ByteBuffer.wrap(face);
        textureBuffer = floatArray2Buffer(text);
    }

    float[] vertex = new float[]{
            0f,0.5f,0f , -0.5f,0f,0f , 0.5f,0f,0f ,
            0f,0.5f,0f , 0.5f,0f,0f , 0f,0f,0.2f ,
            0f,0.5f,0f , 0f,0f,0.2f , -0.5f,0f,0f ,
            0f,0f,0.2f , 0.5f,0f,0f , -0.5f,0f,0f
    };

    byte[] face = new byte[]{
            0,1,2,
            3,4,5,
            6,7,8,
            9,10,11
    };

    float[] text = {
            0f,0f , 0f,1f , 1f,1f,
            0f,0f , 0f,1f , 1f,1f,
            0f,0f , 1f,1f , 1f,0f,
            0f,0f , 0f,1f , 1f,1f,
    };

    //将顶点位置数组转换为FloatBuffer,是OpenGl ES所需要的
    private FloatBuffer floatArray2Buffer(float[] rect1) {
        FloatBuffer floatBuffer;
        //不用该方法得到FloatBuffer,因为Android平台限制,Buffer必须为native Buffer,所以要通过allocateDirect()创建
        //并且该Buffer必须是排序的,所以要order()方法进行排序
        //floatBuffer = FloatBuffer.wrap(rect1);
        //因为一个int=4字节
        ByteBuffer bb = ByteBuffer.allocateDirect(rect1.length * 4);
        bb.order(ByteOrder.nativeOrder());
        floatBuffer = bb.asFloatBuffer();
        floatBuffer.put(rect1);
        floatBuffer.position(0); //移到第一个点的数据
        return floatBuffer;
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        //关闭抗抖动
        gl.glDisable(GL10.GL_DITHER);
        //修正系统透视
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT , GL10.GL_FASTEST);
        //设置阴影平滑模式
        gl.glShadeModel(GL10.GL_SMOOTH);
        //启用深度测试 记录Z轴深度
        gl.glEnable(GL10.GL_DEPTH_TEST);
        //设置深度测试的类型
        gl.glDepthFunc(GL10.GL_LEQUAL);

        //*******启用2D纹理*************
        gl.glEnable(GL10.GL_TEXTURE_2D);
        //加载纹理
        loadTexture(gl);
    }

    private void loadTexture(GL10 gl) {
        Bitmap bitmap = null;
        bitmap = BitmapFactory.decodeResource(context.getResources() , R.drawable.bj);
        int[] textures = new int[1];
        gl.glGenTextures(1 , textures , 0);
        texture = textures[0];
        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 , bitmap , 0);
        if (bitmap != null){
            bitmap.recycle();
        }
    }

    @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;
        //设置透视视窗的空间大小 默认为 -1,1,-1,1,-1,1
        //gl.glFrustumf(-ratio , ratio , -1 , 1  ,1 , 10);
    }

    @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.glMatrixMode(GL10.GL_MODELVIEW);

        //启用纹理贴图坐标数组
        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        //重置当前的模型视图矩阵
        gl.glLoadIdentity();
       //如果需要用颜色填充平面,还需要禁用顶点颜色数据
        gl.glColor4f(0.2f , 1.0f , 0.2f , 0.0f);
        gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
        //绕y轴旋转
        gl.glRotatef(roate , 0f , 1f , 0f);
        //设置顶点位置数据
        gl.glVertexPointer(3 , GL10.GL_FLOAT , 0 , vertextBuffer);
        //设置贴图数组
        gl.glTexCoordPointer(2 , GL10.GL_FLOAT , 0 , textureBuffer);
        //根据顶点绘制平面 //执行贴图

        gl.glBindTexture(GL10.GL_TEXTURE_2D , texture);
        gl.glDrawElements(GL10.GL_TRIANGLES, faceBuffer.remaining() , GL10.GL_UNSIGNED_BYTE , faceBuffer);


        //停止绘制
        gl.glFinish();
        //停用坐标数据
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        //禁用纹理数组
        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

        roate+=1;
        if (roate == 360){
            roate = 0;
        }
    }


}

猜你喜欢

转载自blog.csdn.net/qq_38261174/article/details/83045355