Android OpenGL(2)

OpenGL 3D 效果

这一次主要说说3D效果吧,主要是纹理映射、光照和事件、混合颜色。

通过上一次的介绍,3D空间创建对象的方法应该没问题啦。但是只有一些基本的集合体和一些颜色组成,大家看起来肯定不爽吧,所以我们可以将纹理映射到立方体上去,可以加上光照效果,也可以在纹理的基础上加上混合,使它看起来具有透明的效果。期待吧。。

首先来看看MainActivity,

/*MainActivity.java*/
public class MainActivity extends Activity {
    DRender drender = new DRender();    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);        
        GLImage.load(this.getResources());        
        GLSurfaceView glView = new GLSurfaceView(this);//GLSurfaceView
        glView.setRenderer(drender);      //serRender  
        setContentView(glView);
    }
    //光照效果的处理事件
    public boolean onKeyUp(int keyCode, KeyEvent event)
    {
        drender.onKeyUp(keyCode, event);
        return true;
    }
    public boolean onKeyDown(int keyCode, KeyEvent event)
    {
        drender.onKeyDown(keyCode, event);
        return super.onKeyDown(keyCode, event);
    }
}
class GLImage
{
    public static Bitmap mBitmap;
    public static void load(Resources resources)
    {
        mBitmap = BitmapFactory.decodeResource(resources, R.drawable.img);//在drawable里放一张图片img
    }
}

根据上一次的介绍,同样的我们需要构建一个自己的GLRender类,GLRender中也必须要实现下面的3个抽象方法:

public void onDrawFrame(GL10 gl){}
public void onSurfaceChanged(GL10 gl, int width, int height){}
public void onSurfaceCreated(GL10 gl, EGLConfig config){}

首先来讲讲纹理映射吧:
为立方体的每一个面都贴上一张图,要创建一个纹理,并使用图片来生成纹理。代码如下:
        IntBuffer textureBuffer = IntBuffer.allocate(1);
        // 创建纹理
        gl.glGenTextures(1, textureBuffer);
        texture = textureBuffer.get();
    //绑定要使用的纹理
    gl.glBindTexture(GL10.GL_TEXTURE_2D, texture);
    //生成纹理
    GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, GLImage.mBitmap, 0);
    //线性滤波
    gl.glTexParameterx(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MAG_FILTER,GL10.GL_LINEAR);
    gl.glTexParameterx(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_LINEAR);
    //开启or关闭纹理
    gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
    gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
然后就是对立方体的每一个面设置纹理数据(见后面详细代码),设置好后通过
gl.glTexCoordPointer(2, GL10.GL_FIXED, 0, texCoords); 将纹理映射到要绘制的物体上。
最后,和绘制多边形一样将其绘制到屏幕上即可。
    //绘制四边形
    gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, 24,  GL10.GL_UNSIGNED_BYTE, indices);

为了使效果更加美观,逼真,我就再加上了光照的效果。
步骤如下:
    //定义环境光(r,g,b,a)
    FloatBuffer lightAmbient = FloatBuffer.wrap(new float[]{0.5f,0.5f,0.5f,1.0f});
    //定义漫射光
    FloatBuffer lightDiffuse = FloatBuffer.wrap(new float[]{1.0f,1.0f,1.0f,1.0f});
    //光源的位置
    FloatBuffer lightPosition = FloatBuffer.wrap(new float[]{0.0f,0.0f,2.0f,1.0f});
        //设置环境光
        gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_AMBIENT, lightAmbient);
        //设置漫射光
        gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_DIFFUSE, lightDiffuse);
GL_AMBIENT为环境光,GL_DIFFUSE为漫射光,第三个参数为光源数组。
        //设置光源的位置
        gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_POSITION, lightPosition); 
设置光源的位置,只需把第二个参数改为POSITION,然后第三个参数改为光源数组lightPosition。
        //启用一号光源
        gl.glEnable(GL10.GL_LIGHT1);
不开启的话会看不到任何光源,所以一定要记得启用光源。当然,当不需要用光源的时候,也可以用关闭掉。
        //关闭一号光源
        gl.glDisable(GL10.GL_LIGHT1);
至于按键事件的处理,可以详细参照后面的详细代码分析,也可以在后面的代码下载链接中下载你所需要的代码。此处将不详细展开。

透明效果也是许多人喜欢的,下面就在纹理的基础上加上混合,使具有透明的效果。
前面都是用GL_RGB来制定颜色的3个分量,其实还有一个分量,那就是alpha,这个分量可以指定透明度。
当alpha为0.0时是完全透明的,1.0是完全不透明的。
首先,在onSurfaceCreated方法中加入设置光线的代码:
    //设置光线,,1.0f为全光线,a=50%
    gl.glColor4f(1.0f,1.0f,1.0f,0.5f);   
    // 基于源象素alpha通道值的半透明混合函数
    gl.glBlendFunc(GL10.GL_SRC_ALPHA,GL10.GL_ONE);
然后在程序中控制是否开启混合:
        //混合开关
        if (key)
        {
                gl.glEnable(GL10.GL_BLEND);        // 打开混合
                gl.glDisable(GL10.GL_DEPTH_TEST);    // 关闭深度测试
        }
        else
        {
                gl.glDisable(GL10.GL_BLEND);        // 关闭混合
                gl.glEnable(GL10.GL_DEPTH_TEST);    // 打开深度测试
        }

详细代码如下:(代码需要相应的修改,不想修改的可以去下载链接中去下载代码,嘿嘿,但是代码是没有错的哈。)

public class DRender implements Renderer
{
    float xrot, yrot, zrot=-5.0f;
    float xspeed, yspeed;//旋转的速度
    float step = 0.4f;
    boolean key = true , light = true;;
    int one = 0x10000;
    
    //定义环境光(r,g,b,a)
    FloatBuffer lightAmbient = FloatBuffer.wrap(new float[]{0.5f,0.5f,0.5f,1.0f}); 
    //定义漫射光
    FloatBuffer lightDiffuse = FloatBuffer.wrap(new float[]{1.0f,1.0f,1.0f,1.0f});
    //光源的位置
    FloatBuffer lightPosition = FloatBuffer.wrap(new float[]{0.0f,0.0f,2.0f,1.0f}); 
    
    //过滤的类型
    int filter = 1;
    //纹理效果
    int [] texture;
    
    IntBuffer vertices = IntBuffer.wrap(new int[]{
            -one,-one,one,
            one,-one,one,
            one,one,one,
            -one,one,one,
            
            -one,-one,-one,
            -one,one,-one,
            one,one,-one,
            one,-one,-one,
            
            -one,one,-one,
            -one,one,one,
            one,one,one,
            one,one,-one,
            
            -one,-one,-one,
            one,-one,-one,
            one,-one,one,
            -one,-one,one,
            
            one,-one,-one,
            one,one,-one,
            one,one,one,
            one,-one,one,
            
            -one,-one,-one,
            -one,-one,one,
            -one,one,one,
            -one,one,-one,
            
    });
    IntBuffer normals = IntBuffer.wrap(new int[]{
        0,0,one,
        0,0,one,
        0,0,one,
        0,0,one,
        
        0,0,one,
        0,0,one,
        0,0,one,
        0,0,one,
        
        0,one,0,
        0,one,0,
        0,one,0,
        0,one,0,
        
        0,-one,0,
        0,-one,0,
        0,-one,0,
        0,-one,0,
        
        one,0,0,
        one,0,0,
        one,0,0,
        one,0,0,
        
        -one,0,0,
        -one,0,0,
        -one,0,0,
        -one,0,0,
    });
    IntBuffer texCoords = IntBuffer.wrap(new int[]{
        one,0,0,0,0,one,one,one,    
        0,0,0,one,one,one,one,0,
        one,one,one,0,0,0,0,one,
        0,one,one,one,one,0,0,0,
        0,0,0,one,one,one,one,0,
        one,0,0,0,0,one,one,one,
    });
    
    ByteBuffer indices = ByteBuffer.wrap(new byte[]{
            0,1,3,2,
            4,5,7,6,
            8,9,11,10,
            12,13,15,14,
            16,17,19,18,
            20,21,23,22,
    });
    @Override
    public void onDrawFrame(GL10 gl)
    {
        // 清除屏幕和深度缓存
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        // 重置当前的模型观察矩阵
        gl.glLoadIdentity();
        //如果不启用GL_LIGHTING光就什么都看不见
        gl.glEnable(GL10.GL_LIGHTING);
        gl.glTranslatef(0.0f, 0.0f, zrot);
        
        //设置3个方向的旋转
        gl.glRotatef(xrot, 1.0f, 0.0f, 0.0f);
        gl.glRotatef(yrot, 0.0f, 1.0f, 0.0f);
        gl.glRotatef(zrot, 0.0f, 0.0f, 1.0f);
        // 绑定纹理
        gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[filter]);
        
        gl.glNormalPointer(GL10.GL_FIXED, 0, normals);
        gl.glVertexPointer(3, GL10.GL_FIXED, 0, vertices);
        gl.glTexCoordPointer(2, GL10.GL_FIXED, 0, texCoords);
        
        gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        
        //纹理和四边形对应的顶点
        gl.glVertexPointer(3, GL10.GL_FIXED, 0, vertices);
        gl.glTexCoordPointer(2, GL10.GL_FIXED, 0, texCoords);

        //绘制四边形
        gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, 24,  GL10.GL_UNSIGNED_BYTE, indices);

        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
        
        //旋转角度
        if ( key )
        {
            xrot+=xspeed; 
            yrot+=yspeed; 
        } 
        // 判断是否开始光源
        if (!light)                
        {
            gl.glDisable(GL10.GL_LIGHT1);        // 禁用一号光源
        }
        else                    // 否则
        {
            gl.glEnable(GL10.GL_LIGHT1);        // 启用一号光源
        }
        
        //混合开关
        if (key)
        {
            gl.glEnable(GL10.GL_BLEND);        // 打开混合
            gl.glDisable(GL10.GL_DEPTH_TEST);    // 关闭深度测试
        }
        else 
        {
            gl.glDisable(GL10.GL_BLEND);        // 关闭混合
            gl.glEnable(GL10.GL_DEPTH_TEST);    // 打开深度测试
        }
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height)
    {
        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)
    {
        // 黑色背景
        gl.glClearColor(0, 0, 0, 0);
        gl.glDisable(GL10.GL_DITHER);
        // 告诉系统对透视进行修正
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
        gl.glEnable(GL10.GL_CULL_FACE);
        // 启用阴影平滑
        gl.glShadeModel(GL10.GL_SMOOTH);
        // 启用深度测试
        gl.glEnable(GL10.GL_DEPTH_TEST);
        //设置光线,,1.0f为全光线,a=50%
        gl.glColor4f(1.0f,1.0f,1.0f,0.5f);    
        // 基于源象素alpha通道值的半透明混合函数
        gl.glBlendFunc(GL10.GL_SRC_ALPHA,GL10.GL_ONE);
        
        IntBuffer textureBuffer = IntBuffer.allocate(3);
        // 创建纹理
        gl.glGenTextures(3, textureBuffer);
        texture = textureBuffer.array();
        // 创建 Nearest 滤波贴图
        gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[0]);
        gl.glTexParameterx(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MAG_FILTER,GL10.GL_NEAREST); // ( NEW )
        gl.glTexParameterx(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_NEAREST); // ( NEW )
        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, GLImage.mBitmap, 0);
        
        // 创建线性滤波纹理
         gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[1]);
        gl.glTexParameterx(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MAG_FILTER,GL10.GL_LINEAR); // ( NEW )
        gl.glTexParameterx(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_LINEAR); // ( NEW )
        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, GLImage.mBitmap, 0);
        
        gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[2]);
        gl.glTexParameterx(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MAG_FILTER,GL10.GL_NEAREST); // ( NEW )
        gl.glTexParameterx(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_LINEAR); // ( NEW )
        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, GLImage.mBitmap, 0);
        
        //深度测试相关
        gl.glClearDepthf(1.0f);
        gl.glDepthFunc(GL10.GL_LEQUAL);
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
        gl.glEnable(GL10.GL_TEXTURE_2D);
        
        //启用纹理映射
        gl.glClearDepthf(1.0f);
        //深度测试的类型
        gl.glDepthFunc(GL10.GL_LEQUAL);
        //精细的透视修正
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
        //允许2D贴图,纹理
        gl.glEnable(GL10.GL_TEXTURE_2D);
        
        //设置环境光
        gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_AMBIENT, lightAmbient);
        //设置漫射光
        gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_DIFFUSE, lightDiffuse);
        //设置光源的位置
        gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_POSITION, lightPosition);  
        //启用一号光源
        gl.glEnable(GL10.GL_LIGHT1);
        //开启混合
        gl.glEnable(GL10.GL_BLEND);
    }
    
    public boolean onKeyDown(int keyCode, KeyEvent event)
    {
        switch ( keyCode )
        {
            case KeyEvent.KEYCODE_DPAD_UP:
                key = true;
                xspeed=-step;
                break;
            case KeyEvent.KEYCODE_DPAD_DOWN:
                key = true;
                xspeed=step;
                break;
            case KeyEvent.KEYCODE_DPAD_LEFT:
                key = true;
                yspeed=-step;
                break;
            case KeyEvent.KEYCODE_DPAD_RIGHT:
                key = true;
                yspeed=step;
                break;
            case KeyEvent.KEYCODE_DPAD_CENTER:
                    light = !light;
                break;
        }
        return false;
    }
    
    public boolean onKeyUp(int keyCode, KeyEvent event)
    {
        key = !key;
        return false;
    }
}

额。。就先写那么多吧。。还有一些更好的效果过几天才能够出来了。。

因为。。明后天是周末啦。。嘿嘿,你们懂的哈。。

代码下载链接:http://download.csdn.net/detail/klcf0220/5489181

http://www.apkbus.com/android-121456-1-1.html

喜欢开源,乐意分享的大神们,欢迎加入QQ群:176507146,你值的拥有哦!

作者:快乐出发0220 ;Android群:151319601 ; Linux群:96394158 ;转载请注明出处 http://klcf0220.cnblogs.com/ !!!
原文地址:https://www.cnblogs.com/klcf0220/p/3111567.html