Android OpenGL ES学习笔记之材质概念和添加光照

来源:互联网 发布:热传导有限元软件 编辑:程序博客网 时间:2024/04/28 18:33

一、光照概念

观察一个真实的3D物体,在不同的部位必然有不同的光照效果,有的地方暗一点,有的地方亮一点。而这种视觉差异是由光源和材质(物体的材料)共同决定的。光源强度由红、绿、蓝三色光强度共同决定,最终的光照效果由4部分组成:

 - Emitted(光源) - diffuse(漫反射光) - specular(镜面反射光) - ambient(环境光) 

这里附上一张网上的图:

这里写图片描述


Emitted(光源)

物体本身所发射出的光,有的物体不发射光,那就没有这个属性


diffuse(漫反射光)

漫反射和镜面反射大家应该都知道,初中物理有讲过。 
漫反射,是投射在粗糙表面上的光向各个方向反射的现象。当一束平行的入射光线射到粗糙的表面时,表面会把光线向着四面八方反射,所以入射线虽然互相平行,由于各点的法线方向不一致,造成反射光线向不同的方向无规则地反射,这种反射称之为“漫反射”或“漫射”。

如下图:

这里写图片描述


specular(镜面反射光)

镜面反射是指若反射面比较光滑,当平行入射的光线射到这个反射面时,仍会平行地向一个方向反射出来,这种反射就属于镜面反射


ambient(环境光)

在环境中进行了多次散射的光,而最终无法分辨其方向的光。

二、材质概念

物体的材质属性通过反射不同方向的环境光,漫反射光,镜面光的RGB颜色来表示的。分为四种:

 - 泛射材质 - 漫反射材质 - 镜面反射材质 - 发射材质

三、光照模型

添加光照效果也就是使用OpenGL的光照模型需要以下步骤

  1. 打开光源
  2. 设置光源的种类、位置和方向(对于平行光源)
  3. 设置顶点的法向量
  4. 设置材质

1、打开光源

首先需要打开光源的总开关

    //打开光源总开关    gl.glEnable(GL10.GL_LIGHTING);
  • 1
  • 2

在OpenGL ES中,仅仅支持有限数量的光源。使用GL_LIGHT0表示第0号光源,GL_LIGHT1表示第1号光源,依次类推,OpenGL至少会支持8个光源 。GL_LIGHT0到GL_LIGHT7。

打开0号光源

    //打开0号光源    gl.glEnable(GL10.GL_LIGHT0);
  • 1
  • 2

2、设置光源的种类、位置和方向(对于平行光源)

设置光源的方法如下

 - glLightfv(int light, int pname, FloatBuffer params) - glLightfv(int light, int pname, float[] params, int offset)

各个参数含义如下

 - light—————— 光源的序号 - pname—————— 光源属性名称  - params—————— 光源属性的值(float 数组或是Buffer类型) - offset——————  偏移量

params有以下几种

 - GL_SPOT_EXPONENT————表示聚光的程度,为零时表示光照范围内向各方向发射的光线强度相同,为正数时表示光照向中央集中,正对发射方向的位置受到更多光照,其它位置受到较少光照。数值越大,聚光效果就越明显 - GL_SPOT_CUTOFF————表示一个角度,它是光源发射光线所覆盖角度的一半,其取值范围在0到90之间,也可以取180这个特殊值。取值为180时表示光源发射光线覆盖360度,即不使用聚光灯,向全周围发射 - GL_CONSTANT_ATTENUATION————表示光线按常量衰减 - GL_LINEAR_ATTENUATION————表示光线按距离线性衰减 - GL_QUADRATIC_ATTENUATION————表示光线按距离以二次函数衰减 - GL_AMBIENT————表示各种光线照射到该材质上,经过很多次反射后最终遗留在环境中的光线强度  - GL_DIFFUSE————表示光线照射到该材质上,经过漫反射后形成的光线强度  - GL_SPECULAR————表示光线照射到该材质上,经过镜面反射后形成的光线强度  - GL_SPOT_DIRECTION————表示一个向量,即光源发射的方向。默认方向是(0.0,0.0,-1.0) - GL_POSITION————表示光源所在的位置,由四个值(X, Y, Z, W)表示,W为0表示平行光源,表示该光源位于无限远处,类似太阳,W不为0表示位置性光源,(X/W, Y/W, Z/W)表示了光源的位置,可以设置各种衰减因子

上面说的与聚光强度、角度、衰减等有关的属性只适用于位置光源


3、设置顶点的法向量

设置法向量来确定图元的明暗程度,不过我的例子并没有用到。有两个方法可以为平面设置法线。

 - public void glNormal3f(float nx,float ny,float nz) ————为后续所有平面设置同样的方向,直到重新设置新的法线为止 - public void glNormalPointer(int type,int stride, Buffer pointer)————为某个顶点设置法线

4、设置材质

设置材质的方法如下

 - public void glMaterialf(int face,int pname,float param) - public void glMaterialfv(int face,int pname,float[] params,int offset) - public void glMaterialfv(int face,int pname,FloatBuffer params)

各参数含义如下:

 - face ———— 表示物体的前、后面,有GL_FRONT(正面),GL_BACK(反面),GL_FRONT_AND_BACK(正反两面) - pname ———— 材质属性类型 - param ———— 材质属性类型的对应的值(float 数组或者Buffer 类型) - offset ———— 偏移量

其中pname 有以下几种

 - GL_AMBIENT————表示各种光线照射到该材质上,经过很多次反射后最终遗留在环境中的光线强度 - GL_DIFFUSE ————表示光线照射到该材质上,经过漫反射后形成的光线强度 - GL_SPECULAR————表示光线照射到该材质上,经过镜面反射后形成的光线强度 - GL_SHININESS————“镜面指数”,取值范围是0到128。该值越小,表示材质越粗糙,点光源发射的光线照射到上面,也可以产生较大的亮点。该值越大,表示材质越类似于镜面,光源照射到上面后,产生较小的亮点  - GL_EMISSION————该属性由四个值组成,表示一种颜色。OpenGL认为材质本身就微微的向外发射光线,以至于眼睛感觉到它有这样的颜色,但这光线又比较微弱,以至于不会影响到其它物体的颜色  - GL_COLOR_INDEXES———— 颜色索引 

四、例子

以上一篇文章Android OpenGL ES学习笔记之绘制一个正方体的代码为基础,添加光照效果。

首先是新建关于光源属性的浮点数组

        //环境光强度        float[] amb_light = {1f, 1f, 1f, 1f };          //漫反射光强度        float[] diff_light = { 1f, 1f, 1f, 1f };        //镜面反射光强度        float[] spec_light = {1f, 1f, 1f, 1f };           //光源位置        float[] pos_light = {0f, 0.0f, 1f, 0.4f};        //光源方向        float[] spot_dir = { 0.0f, 0.0f,  -1f, };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

我设置了白色光,光源位置为{0f, 0.0f, 1f, 0.4f},参数w=0.4f,前面说了w不为0表示位置性光源,光源的位置为(X/W, Y/W, Z/W),即(0f,0f,2.5f)

设置光源方向为{ 0.0f, 0.0f, -1f, },沿着Z轴负方向

然后将它们转化为Buff类型

            //获取浮点型环境光数据            amb_light_buffer= Utils.getFloatBuffer(amb_light);            //获取浮点型漫反射光数据            diff_light_buffer= Utils.getFloatBuffer(diff_light);            //获取浮点型镜面反射光数据            spec_light_buffer= Utils.getFloatBuffer(spec_light);            //获取浮点型光源位置数据            pos_light_buffer= Utils.getFloatBuffer(pos_light);            //获取浮点型光源方向数据            spot_dir_buffer= Utils.getFloatBuffer(spot_dir);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

然后在onDrawFrame加上

            //打开光源总开关            gl.glEnable(GL10.GL_LIGHTING);            //打开0号光源            gl.glEnable(GL10.GL_LIGHT0);             //设置光源位置            gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, pos_light_buffer);           //设置光源方向            gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPOT_DIRECTION , spot_dir_buffer);            //设置光源种类            gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT ,  amb_light_buffer );            gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE , diff_light_buffer );            gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPECULAR, spec_light_buffer);            //设置聚光强度            gl.glLightf(GL10.GL_LIGHT0, GL10.GL_SPOT_EXPONENT, 64f);            //设置聚光角度            gl.glLightf(GL10.GL_LIGHT0, GL10.GL_SPOT_CUTOFF, 45f);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

先打开光源总开关,再打开0号光源,然后设置光源位置,方向,各种类强度,聚光强度,聚光角度。 
聚光强度取值范围为0~128f。

绘制出的效果如下:

这里写图片描述

可以加上材质

我设置了反射绿光的强度为0.3f,红、蓝为0f。

        //环境光材质        float amb_mat[]  = { 0f,  0.3f, 0f, 1f };        //漫反射光材质        float diff_mat[]  ={ 0f,  0.3f, 0f, 1f };        //镜面反射光材质        float spec_mat[] = { 0f,  0.3f, 0f, 1f };               //本身颜色        float emi_mat[] = { 0.0f, 0f, 0.0f, 1.0f };        //镜面指数         float shini_mat  =  0f; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

然后转化为Buffer

            //获取浮点型环境光材质数据            amb_mat_buffer= Utils.getFloatBuffer(amb_mat);            //获取浮点型漫反射光材质数据            diff_mat_buffer= Utils.getFloatBuffer(diff_mat);            //获取浮点型镜面反射光材质数据            spec_mat_buffer= Utils.getFloatBuffer(spec_mat);            //获取浮点型本身颜色数据            emi_mat_buffer= Utils.getFloatBuffer(emi_mat);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

然后设置材质各种类强度、镜面指数。

         //设置材质种类             gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, amb_mat_buffer);            gl.glMaterialfv(GL10.GL_FRONT_AND_BACK,GL10.GL_DIFFUSE, diff_mat_buffer);            gl.glMaterialfv(GL10.GL_FRONT_AND_BACK,GL10.GL_SPECULAR, spec_mat_buffer);            //设置镜面指数            gl.glMaterialf(GL10.GL_FRONT_AND_BACK, GL10.GL_SHININESS, shini_mat);  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

效果如下图:

这里写图片描述

最后附上Demo:打开 
密码:pw80

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 掌上品的钱怎么办 财务纠纷被起诉怎么办 牙齿补后疼痛怎么办 牙齿表面蛀了怎么办 虫牙全掉了怎么办 牙齿蛀光了怎么办 虫牙全部掉完了怎么办 不喜欢向人请教怎么办 单位不交公积金怎么办 电锯链条掉了怎么办 天津公积金怎么办外地转入 学籍档案涂抹了怎么办 气相点火失败怎么办 小米闹钟声音小怎么办 河北省监理员证怎么办 买的商铺烂尾了怎么办 钢表带被磨花了怎么办 资料员到期了怎么办 八大员挂靠社保怎么办 安许证三类人员不足了怎么办 考试准考证号写错了怎么办 科目一失约两次怎么办 钢筋送检两次不合格怎么办 公路原材料抽检不合格怎么办 混凝土回弹强度不合格怎么办 毕业证照片太丑怎么办 政审时找不到档案怎么办 劳动解除书开不出来怎么办 双流办健康证怎么办 户口本人数满了怎么办 二建有效期到了怎么办 二级建造师到期怎么办 网上选车牌号后怎么办 政府拖欠水利工程款怎么办 重庆造价员到期了怎么办 枕大神经发炎怎么办 塑钢推拉窗下沉怎么办 网上买东西数量不够怎么办 淘宝买东西数量不够怎么办 康佳遥控器坏了怎么办 电视机频幕脏了怎么办