立方体实现

这篇博客介绍了如何使用OpenGL ES实现3D立方体的绘制。通过分析`cube.java`、`CubeRenderer.java`和`MyCube.java`三个主要类的代码,展示了从初始化GLSurfaceView到设置顶点、颜色、索引和绘制的过程。博客提供了详细的代码注释,并强调了顶点坐标、颜色、索引和线段索引在缓冲区中的作用。
摘要由CSDN通过智能技术生成
其实写这篇之前,有做一些准备,所以想要更好了解的同学,我建议也看一下本人3D图形学基础的相关文章,应该有些用处,当然这些都会在不断更新中。

今天要做的是实现绘制立方体,这个算是我们做的第一个3D图,先看下效果吧。

这个实现的代码是我在网上找的,代码中也附加了很多注释,没有注释的地方也可以在我之前文章中的代码中找到相应注释,所以表面上完全可以看得懂,当然想要知道实现原理可以查看相应关键方法的实现方式以及图像学原理。方法实现在我的gl10方法解析中都可以找到,图形学原理可以在我的相关文章中可以找到,当然这些都在更新中。

下面是代码了:

cube.java

 

package test.cube;

 

import android.app.Activity;

import android.opengl.GLSurfaceView;

import android.os.Bundle;

 

public class cube extends Activity {

    private GLSurfaceView mGLSurfaceView;

    /** Calledwhen the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        mGLSurfaceView=new GLSurfaceView(this);

        mGLSurfaceView.setRenderer(new CubeRenderer());

        setContentView(mGLSurfaceView);

    }

    @Override

    protected void onResume() {

        // Ideally a game should implement onResume() andonPause()

        // to take appropriate action when the activity loosesfocus

        super.onResume();

        mGLSurfaceView.onResume();

    }

    @Override

    protected void onPause() {

        // Ideally a game should implement onResume() andonPause()

        // to take appropriate action when the activity loosesfocus

        super.onPause();

        mGLSurfaceView.onPause();

    }

 

}

 

CubeRenderer.java

 

package test.cube;

import javax.microedition.khronos.egl.EGLConfig;

import javax.microedition.khronos.opengles.GL10;

 

import android.opengl.GLSurfaceView;

import android.opengl.GLU;

public class CubeRenderer implements GLSurfaceView.Renderer{

    public void onDrawFrame(GL10 gl) {

        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

        //一般的opengl程序,首先要做的就是清屏

        gl.glMatrixMode(GL10.GL_MODELVIEW);//紧着这设置模型视图矩阵

        gl.glLoadIdentity();

        //视点变换,将相机位置设置为(0.0.3),同时指向(0.0.0)点,竖直向量为(0.1.0)指向正上方

        GLU.gluLookAt(gl, 0, 0, 3, 0, 0,0, 0, 1,0);

        //设置模型位置旋转及缩放信息

        gl.glTranslatef(0, 0.0f, -1.0f);//将模型位置设置为(0.0.-1)

        float angle=30.0f;

       gl.glRotatef(angle,0,1, 0);//绕模型自身y轴旋转30度。

       gl.glRotatef(angle,1,0, 0);//绕模型自身x轴旋转30度。

       gl.glScalef(1.2f, 1.2f, 1.2f);//设置三方向的缩放系数

       gl.glColor4f(0.0f,0.0f, 0.0f, 1.0f);

       mCube.draw(gl,gl.GL_LINES);//渲染立方体

       mCube.draw(gl,gl.GL_TRIANGLES);//渲染立方体

   }

     //当屏幕 改变时候,比如手机横着拿,变成竖着拿,先onSurfaceCreated在两次onSurfaceChanged 。

    public void onSurfaceChanged(GL10 gl, int width, int height) {

        //设置视口

        gl.glViewport(0,0, width, height);

    

        float ratio = (float) width / height;

        gl.glMatrixMode(GL10.GL_PROJECTION);//设置投影矩阵为透视投影

        gl.glLoadIdentity();

        gl.glFrustumf(-ratio, ratio, -1, 1, 1,10);//正交投影

 

    }

    private MyCube mCube;

    @Override

    public void onSurfaceCreated(GL10 gl, EGLConfig config) {     

        

        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,GL10.GL_FASTEST);

        gl.glClearColor(1,1,1,1);

        gl.glDisable(GL10.GL_CULL_FACE);

        //gl.glEnable(GL10.GL_CULL_FACE);

        gl.glShadeModel(GL10.GL_SMOOTH);

        //gl.glShadeModel(GL10.GL_FLAT);

        gl.glEnable(GL10.GL_DEPTH_TEST);

        gl.glLineWidth(4.0f);

        mCube=new MyCube();

    }

}

 

 

MyCube.java

 

package test.cube;

import java.nio.ByteBuffer;

import java.nio.ByteOrder;

import java.nio.FloatBuffer;

import javax.microedition.khronos.opengles.GL10;

 

public class MyCube {

    private FloatBuffer  mVertexBuffer;

    /**

     * 顶点颜色Buffer对象

     */

    privateFloatBuffer   mColorBuffer;

    /**

     * 实体模式下顶点索引对象

     */

    privateByteBuffer  mIndexBuffer;

    /**

     * 线框模式下顶点索引对象

     */

    private ByteBuffer mLineIndexBuffer;

 

    public MyCube()

    {

        float one = 1.0f;

        /**

         * 顶点位置坐标数组

         * 立方体有8个顶点

         */

        float vertices[]= {

                -one, -one, -one,//Vertex 0

                one, -one, -one,//1

                one,  one, -one,//2

                -one,  one, -one,//3

                -one, -one,  one,//4

                one, -one,  one,//5

                one,  one, one,//6

                -one,  one, one,//7

        };

        /**

         * 顶点颜色数组

         * 分别给8个顶点指定不同的颜色, RGBA 模式

         */

        float colors[] ={

                0,    0,   0,  one,//Vertex 0

                one,    0,   0,  one,//1

                one,  one,   0,  one,//2

                0,  one,   0,  one,//3

                0,    0, one,  one,//4

                one,    0, one,  one,//5

                one,  one, one,  one,//6

                0,  one, one,  one,//7

        };

        /**

         * 实体模式下,立方体有6个面,每个面由两个三角形组成

         * 这里分别指定每个面的索引。

         */

        byte indices[] ={

                0, 4, 5,    0, 5, 1,//Face 0

                1, 5, 6,    1, 6, 2,// 1

                2, 6, 7,    2, 7, 3,//2

                3, 7, 4,    3, 4, 0,//3

                4, 7, 6,    4, 6, 5,//4

                3, 0, 1,    3, 1, 2//5

        };

        /**

         * 线框模式下,立方体有8个顶点,12条边缘,

         * 这里指定画线模式所用到的12条线段

         */

        bytelineIndices[] = {

         0, 1,//Line 0

         0, 3,//1

         0, 4,//2

         1, 2,//3

         1, 5,//4

         2, 3,//5

         2, 6,//6

         3, 7,//7

         4, 5,//8

         4, 7,//9

         5, 6,//10

         6, 7//11

        };

        //根据数组来生成用于直接渲染的java.nio.Buffer

       

        //顶点位置Buffer

        ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);

        vbb.order(ByteOrder.nativeOrder());

        mVertexBuffer =vbb.asFloatBuffer();

        mVertexBuffer.put(vertices);

        mVertexBuffer.position(0);

        //顶点颜色Buffer

        ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length*4);

        cbb.order(ByteOrder.nativeOrder());

        mColorBuffer =cbb.asFloatBuffer();

        mColorBuffer.put(colors);

        mColorBuffer.position(0);

        //实体模式下顶点索引Buffer

        mIndexBuffer =ByteBuffer.allocateDirect(indices.length);

        mIndexBuffer.put(indices);

        mIndexBuffer.position(0);

        //线框模式下顶点索引Buffer

        mLineIndexBuffer =ByteBuffer.allocateDirect(lineIndices.length);

        mLineIndexBuffer.put(lineIndices);

        mLineIndexBuffer.position(0);

    }

    /**

     * 根据传入的模式来分别渲染实体模式立方体以及线框模式立方体

     * @param gl - OpenGL ES渲染对象

     * @param mode - 渲染模式,GL10.GL_TRIANGLES 表示实体模式,GL10.GL_LINES 表示线框模式

     */

    public void draw(GL10 gl, int mode) {

        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

       

        if(mode ==GL10.GL_TRIANGLES) {

         //如果是实体模式,则启用颜色,给每一个顶点指定一个颜色

            gl.glEnableClientState(GL10.GL_COLOR_ARRAY);

            gl.glVertexPointer(3,GL10.GL_FLOAT, 0, mVertexBuffer);

            gl.glColorPointer(4,GL10.GL_FLOAT, 0, mColorBuffer);

            gl.glDrawElements(GL10.GL_TRIANGLES, 36, GL10.GL_UNSIGNED_BYTE, mIndexBuffer);

        }

        else if(mode == GL10.GL_LINES) {

             gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);

             gl.glDrawElements(GL10.GL_LINES, 24, GL10.GL_UNSIGNED_BYTE, mLineIndexBuffer);

        }

    }

}

 

其实我觉的代码中的注释已经很好了,那我下面在简单解释一下。

这个程序中开了4个缓冲区,分别用来保存顶点坐标,顶点颜色,索引,线段索引。

顶点坐标其实就是这个立方体的8个顶点的坐标,顶点颜色是这8个顶点的颜色,值得注意的是,这个顶点的坐标与其颜色是相对应的,在绘制的时候,绘制一个顶点就会填涂相应的颜色了。而索引矩阵中的值是对应的顶点矩阵中的相应角标,线段所以中也是对应顶点矩阵中的相应角标。

还要注意的是glDrawElements是绘制三角形的,立方体的面都是由两个三角形,当然绘制顺序也是有讲究的,我的相关文章中有讲解,这里的代码是没有开启消隐功能的。



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值