OpenGL 3D 效果
这一次主要说说3D效果吧,主要是纹理映射、光照和事件、混合颜色。
通过上一次的介绍,3D空间创建对象的方法应该没问题啦。但是只有一些基本的集合体和一些颜色组成,大家看起来肯定不爽吧,所以我们可以将纹理映射到立方体上去,可以加上光照效果,也可以在纹理的基础上加上混合,使它看起来具有透明的效果。期待吧。。
首先来看看MainActivity,
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,你值的拥有哦!