By 何明桂(http://blog.csdn.net/hmg25) 转载请注明出处

继续我们的android 3D之旅,我们将讨论光效。从今天开始我们将逐渐添加光效。

光效三要素

在 OpenGL ES中,光由三个元素组成,分别是环境元素(ambient component),散射元素(diffuse component)和高光元素(specular component)。我们使用颜色来设定光线元素,这看上去有些奇怪,但是由于它允许你同时指定各光线元素的颜色和相对强度,这个方法工作得很好。明亮的白色光定义为白色 ({1.0, 1.0, 1.0, 1.0}),而暗白色可能定义为灰色 ({0.3, 0.3, 0.3 1.0})。 你还可以通过改变红,绿,蓝元素的百分比来调整色偏。

下图说明了各要素产生的效果。

高光元素定义了光线直接照射并反射到观察者从而形成了物体上的“热点”或光泽。光点的大小取决于一些因素,但是如果你看到如上图黄球所示一个区域明显的光斑,那通常就是来自于一个或多个光源的高光部分。

散射元素定义了比较平均的定向光源,在物体面向光线的一面具有光泽。

环境光则没有明显的光源。其光线折射与许多物体,因此无法确定其来源。环境元素平均作用于场景中的所有物体的所有面。

环境光

你的光效中有越多的环境元素,那么就越不会产生引入注目的效果。所有光线的环境元素会融合在一起产生效果,意思是场景中的总环境光效是由所有启动光源的环境光组合在一起所决定的。如果你使用了不止一个光源,那么最好是只指定一个光源的环境元素,而设定其他所有光源的环境因素为黑 ({0.0, 0.0, 0.0, 1.0}),从而很容易地调整场景的环境光效。

下面演示了怎样指定一个很暗的白色光源:

   float lightAmbient[] = new float[] { 0.2f, 0.3f, 0.6f, 1.0f }; //环境光 gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, lightAmbient, 0);

使用像这样的很低的环境元素值使场景看上去更引入注目,但同时也意味着物体没有面向光线的面或者有其他物体挡住的物体将在场景中看得不是很清楚。

散射光

在OpenGL ES中可以设定的第二个光线元素是散射元素(diffuse component)。在现实世界里,散射光线是诸如穿透光纤或从一堵白墙反射的光线。散射光线是发散的,因而参数较柔和的光,一般不会像直射光一样产生光斑。如果你曾经观察过职业摄影家使用摄影室灯光,你可能会看到他们使用柔光箱或者反光伞。两者都会穿透像白布之类的轻型材料并反射与轻型有色材料从而使光线发散以产生令人愉悦的照片。在OpenGL ES中,散射元素作用类似,它使光线均匀地散布到物体之上。然而,不像环境光,由于它是定向光,只有面向光线的物体面才会反射散射光,而场景中的所有多面体都会被环境光照射。

下面的例子演示了设定场景中的第一个散射元素:

    float lightDiffuse[] = new float[] { 0.2f, 0.3f, 0.6f, 1.0f };//漫反射光 gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, lightDiffuse, 0);
位置

还需要设定光效的另一个重要属性,即光源3D空间中的位置。这不会影响环境元素,但其他两个元素由于其本性,只有在OpenGL在知道了场景中物体与光的相对位置后才能计算。例如:

    float[] lightPos = new float[] {0,0,3,1}; //光源位置 gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightPos, 0)

关于光效的设置还有很多,大家有兴趣可以自己研究,这里有篇不错的文章,大家可以看看http://hsw625728.blog.163.com/blog/static/39570728200885104210400/

我们今天例子的效果:

实例代码:

public class CubeRenderer implements Renderer {float box[] = new float[] {// FRONT-0.5f, -0.5f,  0.5f, 0.5f, -0.5f,  0.5f,-0.5f,  0.5f,  0.5f, 0.5f,  0.5f,  0.5f,// BACK-0.5f, -0.5f, -0.5f,-0.5f,  0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f,  0.5f, -0.5f,// LEFT-0.5f, -0.5f,  0.5f,-0.5f,  0.5f,  0.5f,-0.5f, -0.5f, -0.5f,-0.5f,  0.5f, -0.5f,// RIGHT 0.5f, -0.5f, -0.5f, 0.5f,  0.5f, -0.5f, 0.5f, -0.5f,  0.5f, 0.5f,  0.5f,  0.5f,// TOP-0.5f,  0.5f,  0.5f, 0.5f,  0.5f,  0.5f, -0.5f,  0.5f, -0.5f, 0.5f,  0.5f, -0.5f,// BOTTOM-0.5f, -0.5f,  0.5f,-0.5f, -0.5f, -0.5f, 0.5f, -0.5f,  0.5f, 0.5f, -0.5f, -0.5f,};float lightAmbient[] = new float[] { 0.2f, 0.3f, 0.6f, 1.0f };  //环境光float lightDiffuse[] = new float[] { 0.2f, 0.3f, 0.6f, 1.0f };//漫反射光float[] lightPos = new float[] {0,0,3,1};  //光源位置/* * 因为进行光照处理,你必须告知系统你定义的模型各个面的方向,以便系统计算光影情况,方向的描述是通过向量点来描述的 */float norms[] = new float[] { //法向量数组,用于描述个顶点的方向,以此说明各个面的方向// FRONT0f,  0f,  1f, //方向为(0,0,0)至(0,0,1)即Z轴正方向0f,  0f,  1f,0f,  0f,  1f,0f,  0f,  1f,// BACK0f,  0f,  -1f,0f,  0f,  -1f,0f,  0f,  -1f,0f,  0f,  -1f,// LEFT-1f,  0f,  0f,-1f,  0f,  0f,-1f,  0f,  0f,-1f,  0f,  0f,// RIGHT1f, 0f, 0f,1f, 0f, 0f,1f, 0f, 0f,1f, 0f, 0f,// TOP0f,  1f, 0f,0f,  1f, 0f,0f,  1f, 0f,0f,  1f, 0f,// BOTTOM0f,  -1f, 0f,0f,  -1f, 0f,0f,  -1f, 0f,0f,  -1f, 0f};FloatBuffer cubeBuff;FloatBuffer normBuff;float xrot = 0.0f;float yrot = 0.0f;/** * 将float数组转换存储在字节缓冲数组 * @param arr * @return */public FloatBuffer makeFloatBuffer(float[] arr) {ByteBuffer bb = ByteBuffer.allocateDirect(arr.length * 4);//分配缓冲空间,一个float占4个字节bb.order(ByteOrder.nativeOrder()); //设置字节顺序, 其中ByteOrder.nativeOrder()是获取本机字节顺序FloatBuffer fb = bb.asFloatBuffer(); //转换为float型fb.put(arr);        //添加数据fb.position(0);      //设置数组的起始位置return fb;}public CubeRenderer() {// TODO Auto-generated constructor stubcubeBuff = makeFloatBuffer(box);//转换float数组normBuff = makeFloatBuffer(norms);}protected void init(GL10 gl) {gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);//设置清屏时背景的颜色,R,G,B,Agl.glEnable(GL10.GL_LIGHTING); //启用光照gl.glEnable(GL10.GL_LIGHT0);  //开启光源0,最多可以开启8个光源//设置光照参数,也可以使用默认的,不设置gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, lightAmbient,0);gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, lightDiffuse,0);gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightPos, 0);gl.glNormalPointer(GL10.GL_FLOAT, 0, normBuff);gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);gl.glEnable(GL10.GL_DEPTH_TEST); //启用深度缓存gl.glEnable(GL10.GL_CULL_FACE);  //启用背面剪裁gl.glClearDepthf(1.0f);    // 设置深度缓存值gl.glDepthFunc(GL10.GL_LEQUAL);  // 设置深度缓存比较函数,GL_LEQUAL表示新的像素的深度缓存值小于等于当前像素的深度缓存值(通过gl.glClearDepthf(1.0f)设置)时通过深度测试gl.glShadeModel(GL10.GL_SMOOTH);// 设置阴影模式GL_SMOOTH}@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {// TODO Auto-generated method stubinit(gl);}@Overridepublic void onSurfaceChanged(GL10 gl, int w, int h) {// TODO Auto-generated method stubgl.glViewport(0, 0, w, h); //设置视窗gl.glMatrixMode(GL10.GL_PROJECTION); // 设置投影矩阵gl.glLoadIdentity();  //设置矩阵为单位矩阵,相当于重置矩阵GLU.gluPerspective(gl, 45.0f, ((float) w) / h, 0.1f, 10f);//设置透视范围}@Overridepublic void onDrawFrame(GL10 gl) {// TODO Auto-generated method stubgl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);// 清除屏幕和深度缓存gl.glMatrixMode(GL10.GL_MODELVIEW);   //切换至模型观察矩阵gl.glLoadIdentity();// 重置当前的模型观察矩阵GLU.gluLookAt(gl, 0, 0, 3, 0, 0, 0, 0, 1, 0);//设置视点和模型中心位置gl.glVertexPointer(3, GL10.GL_FLOAT, 0, cubeBuff);//设置顶点数据gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);gl.glRotatef(xrot, 1, 0, 0);  //绕着(0,0,0)与(1,0,0)即x轴旋转gl.glRotatef(yrot, 0, 1, 0);gl.glColor4f(1.0f, 0, 0, 1.0f);   //设置颜色,红色gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);  //绘制正方型FRONT面gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 4, 4);gl.glColor4f(0, 1.0f, 0, 1.0f);gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 8, 4);gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 12, 4);gl.glColor4f(0, 0, 1.0f, 1.0f);gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 16, 4);gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 20, 4);xrot += 0.5f;yrot += 0.5f;}}

比较上次代码,可以看出,为一个3D模型添加光效,并不需要改动很大。只需要在之前实践篇代码基础上添加上述代码即可~~



更多相关文章

  1. Android入门笔记 - 网络通信 - HttpClient
  2. 模仿墨迹天气设置界面布局
  3. android style用法
  4. Android(安卓)图层引导帮助界面制作
  5. android Application Project目录结构
  6. android 基本布局(RelativeLayout、TableLayout等)使用方法及各种
  7. 弹窗之三:自定义Dialog
  8. Android(安卓)圆角矩形ProgressBar
  9. android中AlertDialog设置圆角

随机推荐

  1. Android(安卓)Gallery控件使用方法详解
  2. android课后作业
  3. Android中bitmap图片透明度的处理(以撕美
  4. 3.创建第一个android项目
  5. Android使用DOM方式解析XML
  6. Android应用程序使用Localsocket与Linux
  7. android自定义progressbar图片大小自适应
  8. 源码学习总结《1》Android(安卓)系统启动
  9. Android(安卓)应用程序开关GPS
  10. Android淘宝客链接自动跳转淘宝APP问题