使用openGl创建3d效果

1 篇文章 0 订阅
1 篇文章 0 订阅
package com.the9.opencldemo;


import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.Properties;


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


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


public class OpenGLDemoActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        GLSurfaceView glSurfaceView = new GLSurfaceView(this);//使用openGL view
        glSurfaceView.setRenderer(new GLRender());//必须先创建渲染器
        setContentView(glSurfaceView);
    }
}


class GLRender implements Renderer{


    float rotateTri,rotateQuad;
    int one=0x10000;
    
//    //三角形的一个顶点
//    private IntBuffer triggerBuffer=IntBuffer.wrap(new int[]{
//            0,one,0,     //上顶点
//            -one,-one,0,    //左顶点
//            one,-one,0    //右下点
//    });
//    
//    //正方形的四个顶点
//    private IntBuffer quateBuffer=IntBuffer.wrap(new int[]{
//            one,one,0,
//            -one,-one,0,
//            one,-one,0,
//            -one,-one,0
//    });
//    
//    
//    private IntBuffer colorBuffer=IntBuffer.wrap(new int[]{
//            one,0,0,one,
//            0,one,0,one,
//            0,0,one,one
//    });
    
    int [] colorArray = {  
            one,0,0,one,  
            0,one,0,one,  
            0,0,one,one,  
    };  
    int [] triggerArray ={  
            0,one,0,  //第0个点的x,y,z坐标
            -one,-one,0,  
            one,-one,0,
            0,-one,one,};
 
    int []  quaterArray = {  
            one,one,0,  
            -one,one,0,  
            one,-one,0,  
            -one,-one,0  
    }; 
    
    
    
    @Override
    public void onDrawFrame(GL10 gl) {
        // TODO Auto-generated method stub
       
    //前两行代码必须写
        // 清除屏幕和深度缓存
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        // 重置当前的模型观察矩阵
        gl.glLoadIdentity();




        // 左移 1.5 单位,并移入屏幕 6.0
        gl.glTranslatef(-1.5f, 0.0f, -6.0f);
         //设置旋转
        gl.glRotatef(rotateTri, 0.0f, 1.0f, 0.0f);
        
        //设置定点数组
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        //设置颜色数组
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
        
        gl.glColorPointer(4, GL10.GL_FIXED, 0, bufferUtil(colorArray));
        // 设置三角形顶点
        gl.glVertexPointer(3, GL10.GL_FIXED, 0, bufferUtil(triggerArray));
        //绘制三角形
        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
        
        gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
        
        //绘制三角形结束
        gl.glFinish();
        
        /***********************/
        /* 渲染正方形 */
        // 重置当前的模型观察矩阵
        gl.glLoadIdentity();
        
        // 左移 1.5 单位,并移入屏幕 6.0
        gl.glTranslatef(1.5f, 0.0f, -6.0f);
        
        // 设置当前色为蓝色
        gl.glColor4f(0.5f, 0.5f, 1.0f, 1.0f);
        //设置旋转
        gl.glRotatef(rotateQuad, 1.0f, 0.0f, 0.0f);
        
        //设置和绘制正方形
        gl.glVertexPointer(3, GL10.GL_FIXED, 0, bufferUtil(quaterArray));
        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
        
        //绘制正方形结束
        gl.glFinish();
        
        /***********************/
        /* 渲染立体三角形 */
        // 重置当前的模型观察矩阵
        gl.glLoadIdentity();
        
        // 左移 1.5 单位,并移入屏幕 6.0
        gl.glTranslatef(0.0f, 2.5f, -6.0f);
        //设置旋转
        gl.glRotatef(rotateQuad, 0.0f, 1.0f, 0.0f);
        //设置颜色数组
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
        gl.glColorPointer(4, GL10.GL_FIXED, 0, bufferUtil(colorArray));
        
        // 设置三角形顶点
        gl.glVertexPointer(3, GL10.GL_FIXED, 0, bufferUtil(triggerArray));
        //第二个array是告诉opengl 你要怎样组织这些点:
        //这里我要画三角形,所以每三个点是一组。
        ByteBuffer ffe = getIndices();
        //绘制三角形
        gl.glDrawElements(GL10.GL_TRIANGLES, 3*4, GL10.GL_UNSIGNED_BYTE, ffe);
        
        //绘制立体三角形结束
        gl.glFinish();
        
        //取消顶点数组
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        
        //改变旋转的角度(速度)
        rotateTri += 0.5f;
        rotateQuad -= 0.5f;
    }
    
    /**
     * 第二个array是告诉opengl 你要怎样组织这些点:
     * 这里我要画三角形,所以每三个点是一组。
     */
    public ByteBuffer getIndices()
    {
    byte[] edge={
    0,1,2,
    1,2,3,
    2,3,0,
    3,0,1
    };
    ByteBuffer ffe=ByteBuffer.allocateDirect(edge.length);


    ffe.put(edge);


    ffe.position(0);
    return ffe;
    }


    /**
     * 必须这样写(基本设置)
     */
    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        // TODO Auto-generated method stub
        
        float ratio = (float) width / height;
        //设置OpenGL场景的大小
        gl.glViewport(0, 0, width, height);
        //设置投影矩阵
        gl.glMatrixMode(GL10.GL_PROJECTION);
        //重置投影矩阵
        gl.glLoadIdentity();
        // 设置视口的大小
        gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
        // 选择模型观察矩阵
        gl.glMatrixMode(GL10.GL_MODELVIEW);    
        // 重置模型观察矩阵
        gl.glLoadIdentity();    
        
    }


    /**
     * 必须这样写(基本设置)
     */
    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        // TODO Auto-generated method stub
//        // 启用阴影平滑
//        gl.glShadeModel(GL10.GL_SMOOTH);
//        
//        // 黑色背景
//        gl.glClearColor(0, 0, 0, 0);
//        
//        // 设置深度缓存
//        gl.glClearDepthf(1.0f);                            
//        // 启用深度测试
//        gl.glEnable(GL10.GL_DEPTH_TEST);                        
//        // 所作深度测试的类型
//        gl.glDepthFunc(GL10.GL_LEQUAL);                            
//        
//        // 告诉系统对透视进行修正
//        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
    }
    
    /* 
     * OpenGL 是一个非常底层的画图接口,它所使用的缓冲区存储结构是和我们的 java 程序中不相同的。 
     * Java 是大端字节序(BigEdian),而 OpenGL 所需要的数据是小端字节序(LittleEdian)。 
     * 所以,我们在将 Java 的缓冲区转化为 OpenGL 可用的缓冲区时需要作一些工作。建立buff的方法如下 
     * */  
    public Buffer bufferUtil(int []arr){  
         IntBuffer mBuffer ;  
           
         //先初始化buffer,数组的长度*4,因为一个int占4个字节  
        ByteBuffer qbb = ByteBuffer.allocateDirect(arr.length * 4);  
        //数组排列用nativeOrder  
         qbb.order(ByteOrder.nativeOrder());  
          
         mBuffer = qbb.asIntBuffer();  
         mBuffer.put(arr);  
         mBuffer.position(0);  
           
         return mBuffer;  
    }  


}


参考http://wenku.baidu.com/view/ced5e536a32d7375a41780f1.html


android是用OpenGL来实现3d的。OpenGL的处理机制是把所有的数据都用代码传递给opengl service,如果用户(这里是应用程序)想要画什么东西,就用告诉opengl 什么东西是可用的,然后在开始画。

这个例子一共分三步:
1."画"一个3d的图形(这里画的是菱形),把它传递给opengl service 端,然后建立一个画自己的方法。
2.创建这个图形运行的环境。
3.把这个环境,加载到android 的界面上去。

下面是具体的实现方法:
首先需要建两个array,第一array是用来告诉opengl这个图形有哪些顶点:
画一个三维的坐标轴,然后把你要画的点都算出来,然后放在这个array里。

float l=1.5f;
float[] vertex={

0.0f,l,0.0f,

l,0.0f,0.0f,

0.0f,0.0f,l,

-l,0.0f,0.0f,

0.0f,0.0f,-l,

0.0f,-l,0.0f

};
第二个array是告诉opengl 你要怎样组织这些点:
这里我要画三角形,所以每三个点是一组。
byte[] edge=

{

0,1,2,

1,2,5,



0,2,3,

5,2,3,



0,3,4,

5,3,4,



0,4,1,

5,4,1

};

这里的数字,是第一个array的index。
下面你要建立两个Buffer它们是用来存放这两个array的。


ByteBuffer bb = ByteBuffer.allocateDirect(vertex.length*4);

bb.order(ByteOrder.nativeOrder());

fbv=bb.asFloatBuffer();

fbv.put(vertex);

fbv.position(0);




ffe=ByteBuffer.allocateDirect(edge.length);

ffe.put(edge);

ffe.position(0);
这样一个三维的菱形就画好了。

下面你要写一个方法能让它自己把自己画出来!
public void draw(GL10 gl)

{

gl.glFrontFace(GL10.GL_CW);

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

gl.glDrawElements(GL10.GL_TRIANGLES, 24, GL10.GL_UNSIGNED_BYTE, ffe);

}
这几句话费了我好大力气去理解。
先说第一个glFrontFace,物体都有一个正面一个反面,这里告诉opengl显示这个物体按顺时针方向(CW=> clockwise)

gl.glVertexPointer(3, GL10.GL_FLOAT, 0, fbv);这个方法是把本程序所用的点都传递个opengl。opengl需要知道什么哪?首先是 这个点是几维的(opengl 支持2,3,4 维),这里是3所以是三维的,第二个参数告诉opengl,这个点是用什么样类型的变量来储存的,这里是float类型。第三个是步长(stride),这个我还没弄明白,不过我看的例子都为0. 最后把你建立好的三维坐标点都传给opengl

gl.glDrawElements。 这个方法是告诉opengl如果要画这个图形,应该怎么画。第一个参数,告诉opengl用画三角形(这样opengl就以三个点为一组),然后告诉opengl你要用到多少个点(注意这个点是在第二个array里的点数)。 第三个是告诉opengl这些点(其实是三维坐标点的reference)的类型。这里是unsigned byte。最后把你排列点的array 放进去!

这样一个三维的图形就建立完成了!


第二个大的步骤是创建一个让这个三维坐标运行的环境(Renderer)。
这是一个interface类
首先,在onDrawFrame里,我们告诉本程序这个三维图形的行为:
在做任何事情之前,我们要清空所有以前内存里的东西,这个内存包括:Color 和Depth
gl.glClear(GL10.GL_COLOR_BUFFER_BIT|GL10.GL_DEPTH_BUFFER_BIT);
然后告诉opengl你要用那个MatrixMode 这个就比较难解释了。
如果写程序 只要记住 GL_MODELVIEW 是管理图形的 缩放,移动,和转动就行了.

gl.glTranslatef(0, 0, -3.0f);
这个方法告诉opengl把图形沿z轴迁移3个unit。这三个值分别是x,y,z轴。
gl.glRotatef(angle,0, 1, 0);
这个方法告诉我们以y为轴。 转angle个度数。注意这里的1和0是告诉沿着那个轴转,别的值应该没有意义。
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
还记得上边说的opengl分client side和service side吗。 这个是告诉opengl如果client side调用draw什么的时候,这个vertex array是可用的。opengl有很多这样的可选项,所以需要告诉opengl,因为我们已经设置了vertex array(我们的第一个array),所以告诉opengl 它是可用的(如果不告诉,opengl会忽略)!

trian.draw(gl);
这个方法是把图形画出来。

angle++;
为了达到动态的效果,我们让每一个frame 的angle,比上一个多一度。

当显示空间大小发生变化的时候,我们应该告诉opengl一下信息:

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

{

// TODO Auto-generated method stub

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);



}
首先是opengl可用的空间 :
gl.glViewport(0, 0, width, height);
想象一下用这四个点画出来的四边形,就是opengl所能用的空间。

gl.glMatrixMode(GL10.GL_PROJECTION);
这个matrix是如何把三维坐标转换为二维坐标并把它放在显示器上。
gl.glLoadIdentity
是告诉opengl初始化这个matrix。

gl.glFrustumf
要把三维的东西用二维显示出来,需要知道几个东西,第一是这个显示平面有多大,你可以看多近和多远。这里的头四个参数,建立了一个四边形,告诉opengl把图形显示在这个范围了。后两个参数告诉opengl这里显示平面里可以显示三维空间里最近和最远的位置。


当这个三维图形建立的是时候,我们可以告诉opengl一些基本参数。这里把能省略的都省略了(其实什么都没有也可以运行!)
public void onSurfaceCreated(GL10 gl, EGLConfig arg1) 

{

gl.glEnable(GL10.GL_DEPTH_TEST);

gl.glClearColor(0,0, 0, 0);

}

gl.glEnable(GL10.GL_DEPTH_TEST); 告诉opengl要检查depth,为什么哪。在三维空间里一个物体A在另一个物体B后面,那么这个A被B挡住里,所以你是看不见的。我们要告诉 opengl,我们不想看见被挡住的东西。这个GL_DEPTH_TEST 就是这个功能。
gl.glClearColor(0,0, 0, 0);
设置这个背景颜色为黑色,应为我们没有给我们的三维图形设置颜色(为了简单),它的初始化颜色是白色。

这样这个环境就建立起来了!

下面该把它放进,android里了
public class Triangle extends Activity {
    /** Called when the activity is first created. */

private GLSurfaceView my_view;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        my_view = new GLSurfaceView(this);
        my_view.setRenderer(new MySimpleRendered());
        this.setContentView(my_view);
    }
    public void onResume()
    {
    
super.onResume();
    
my_view.onResume();
    }
    public void onPause()
    {
    
super.onPause();
    
my_view.onPause();
    }
}

这就是我的第一个3D例子。希望能给初学者一点点提示!

源代码:
package Beta.ThreeD;

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

import javax.microedition.khronos.opengles.GL10;

public class TriangleShape 
{

private final float l=1.5f;

private FloatBuffer fbv;

private ByteBuffer ffe;

public TriangleShape()

{

float[] vertex={

0.0f,l,0.0f,

l,0.0f,0.0f,

0.0f,0.0f,l,

-l,0.0f,0.0f,

0.0f,0.0f,-l,

0.0f,-l,0.0f

};


byte[] edge=

{

0,1,2,

1,2,5,



0,2,3,

5,2,3,



0,3,4,

5,3,4,



0,4,1,

5,4,1

};

ByteBuffer bb = ByteBuffer.allocateDirect(vertex.length*4);

bb.order(ByteOrder.nativeOrder());

fbv=bb.asFloatBuffer();

fbv.put(vertex);

fbv.position(0);




ffe=ByteBuffer.allocateDirect(edge.length);

ffe.put(edge);

ffe.position(0);

}

public void draw(GL10 gl)

{

gl.glFrontFace(GL10.GL_CW);

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

gl.glDrawElements(GL10.GL_TRIANGLES, 24, GL10.GL_UNSIGNED_BYTE, ffe);

}
}


package Beta.ThreeD;

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

import android.opengl.GLSurfaceView.Renderer;

public class MySimpleRendered implements Renderer
{

private int angle=50;

private TriangleShape trian;

public MySimpleRendered()

{

trian = new TriangleShape();

}

@Override

public void onDrawFrame(GL10 gl) 

{

// TODO Auto-generated method stub

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

gl.glMatrixMode(GL10.GL_MODELVIEW);

gl.glLoadIdentity();

gl.glTranslatef(0, 0, -3.0f);

gl.glRotatef(angle,0, 1, 0);

gl.glRotatef(angle, 1, 0, 0);

gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

trian.draw(gl);

angle++;

}


@Override

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

{

// TODO Auto-generated method stub

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);



}


@Override

public void onSurfaceCreated(GL10 gl, EGLConfig arg1) 

{

gl.glEnable(GL10.GL_DEPTH_TEST);

gl.glClearColor(0,0, 0, 0);

}

}
package Beta.ThreeD;

import android.app.Activity;
import android.os.Bundle;
import android.opengl.GLSurfaceView;
public class Triangle extends Activity {
    /** Called when the activity is first created. */

private GLSurfaceView my_view;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        my_view = new GLSurfaceView(this);
        my_view.setRenderer(new MySimpleRendered());
        this.setContentView(my_view);
    }
    public void onResume()
    {
    
super.onResume();
    
my_view.onResume();
    }
    public void onPause()
    {
    
super.onPause();
    
my_view.onPause();
    }
}

 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值