`
wo_deqing
  • 浏览: 59958 次
文章分类
社区版块
存档分类
最新评论

OpenGL ES 光照原理

 
阅读更多
为了能看出3D效果,给场景中添加光源。如果没有光照,绘出的球看上去和一个二维平面上圆没什么差别,如下图,左边为有光照效果的球体,右边为同一个球体但没有设置光源,看上去就没有立体效果,因此OpenGL 光照效果对显示3D效果非常明显。

在OpenGL 光照模型中光源和光照效果可以细分为红,绿,蓝三个部分,光源由红,绿,蓝强度来定义,而物体表面材料由其反射红,绿,蓝的程度和方向来定义。OpenGL 光照模型使用的计算公式是对于现实世界光照的一个近似但效果非常好并适合快速计算。

OpenGL 光照模型中定义的光源可以分别控制,打开或关闭,OpenGL ES支持最多八个光源。

OpenGL 光照模型中最终的光照效果可以分为四个组成部分:Emitted(光源), ambient(环境光),diffuse(漫射光)和specular(镜面反射光),最终结果由这四种光叠加而成。

Emitted : 一般只发光物体或者光源,这种光不受其它光源的影响。

ambient: 指光线经过多次反射后已经无法得知其方向(可以看作来自所有方向),可以成为环境光,该光源如果射到某个平面,其反射方向为所有方向。Ambient 不依赖于光源的方向。

diffuse:当一束平行的入射光线射到粗糙的表面时,因面上凹凸不平,所以入射线虽然互相平行,由于各点的法线方向不一致,造成反射光线向不同的方向无规则地反射,这种反射称之为“漫反射”或“漫射”。这个反射的光则称为漫射光。漫射光射到某个平面时,其反射方向也为所有方向。diffuse 只依赖于光源的方向和法线的方向。

specular : 一般指物体被光源直射的高亮区域,也可以成为镜面反射区,如金属。specular依赖于光源的方向,法线的方向和视角的方向。

尽管光源可能只发送某一频率的光线,但ambient,diffuse和specular可能不同。比如使用白光照射一堵红墙,散射的光线可能为红色。OpenGL允许为光源分别设置红,绿,蓝三个元素的值。

最终决定所看到物体的颜色除了光源的颜色和方向外,还取决于物体本身的颜色,比如红色的光照在红色的物体和蓝色的物体,最终看到的物体一个还是红色,一个为黑色。OpenGL 中对物体材料(Material)的颜色是通过其反射红,绿,蓝的比例来定义的。 和光源一样,物体的颜色也可以有不同的ambient,diffuse和specular,表现为反射这些光的比例。ambient,diffuse反射通常为同样的颜色,而specular常常表现为白色或灰色光,如使用白光照射一个红色的球,球的大部分区域显示为红色,而高亮区域为白色



,本篇结合OpenGL ES API说明如何使用光照效果:

  • 设置光源
  • 定义法线
  • 设置物体材料光学属性

光源

OpenGL ES中可以最多同时使用八个光源,分别使用0到7表示。

OpenGL ES光源可以分为

  • 平行光源(Parallel light source), 代表由位于无限远处均匀发光体,太阳可以近似控制平行光源。
  • 点光源(Spot light source) 如灯泡就是一个点光源,发出的光可以指向360度,可以为点光源设置光衰减属性(attenuation)或者让点光源只能射向某个方向(如射灯)。
  • 可以为图形的不同部分设置不同的光源。

下面方法可以打开某个光源,使用光源首先要开光源的总开关:

1 gl.glEnable(GL10.GL_LIGHTING);

然后可以再打开某个光源如0号光源:

1 gl.glEnable(GL10.GL_LIGHTI0);

设置光源方法如下:

  • public void glLightfv(int light,int pname, FloatBuffer params)
  • public void glLightfv(int light,int pname,float[] params,int offset)
  • public void glLightf(int light,int pname,float param)
  • light 指光源的序号,OpenGL ES可以设置从0到7共八个光源。
  • pname: 光源参数名称,可以有如下:GL_SPOT_EXPONENT, GL_SPOT_CUTOFF, GL_CONSTANT_ATTENUATION, GL_LINEAR_ATTENUATION, GL_QUADRATIC_ATTENUATION, GL_AMBIENT, GL_DIFFUSE,GL_SPECULAR, GL_SPOT_DIRECTION, GL_POSITION
  • params 参数的值(数组或是Buffer类型)。

其中为光源设置颜色的参数类型为GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,可以分别指定R,G,B,A 的值。

指定光源的位置的参数为GL_POSITION,值为(x,y,z,w):

平行光将w 设为0.0,(x,y,z)为平行光的方向:

对于点光源,将 w 设成非0值,通常设为1.0. (x,y,z)为点光源的坐标位置。

将点光源设置成聚光灯,需要同时设置GL_SPOT_DIRECTION,GL_SPOT_CUTOFF等 参数,GL_POSITION的设置和点光源类似:将 w 设成非0值,通常设为1.0. (x,y,z)为点光源的坐标位置。而对于GL_SPOT_DIRECTION 参数,设置聚光的方向(x,y,z)

GL_SPOT_CUTOFF 参数设置聚光等发散角度(0到90度)

GL_SPOT_EXPONENT 给出了聚光灯光源汇聚光的程度,值越大,则聚光区域越小(聚光能力更强)。

对应点光源(包括聚光灯),其它几个参数GL_CONSTANT_ATTENUATION, GL_LINEAR_ATTENUATION, GL_QUADRATIC_ATTENUATION 为点光源设置光线衰减参数,公式有如下形式,一般无需详细了解:

在场景中设置好光源后,下一步要为所绘制的图形设置法线(Normal),只有设置了法线,光源才能在所会物体上出现光照效果。三维平面的法线是垂直于该平面的三维向量。曲面在某点P处的法线为垂直于该点切平面的向量

和设置颜色类似,有两个方法可以为平面设置法线,一是

public void glNormal3f(float nx,float ny,float nz)

这个方法为后续所有平面设置同样的方向,直到重新设置新的法线为止。

为某个顶点设置法线:

public void glNormalPointer(int type,int stride, Buffer pointer)

  • type 为Buffer 的类型,可以为GL_BYTE, GL_SHORT, GL_FIXED,或 GL_FLOAT
  • stride: 每个参数之间的间隔,通常为0.
  • pointer: 法线值。

打开法线数组

1 gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);

用法和Color, Vertex 类似。参见Android OpenGL ES 开发教程(8):基本几何图形定义

规范化法向量,比如使用坐标变换(缩放),如果三个方向缩放比例不同的话,顶点或是平面的法线可能就有变好,此时需要打开规范化法线设置:

1 gl.glEnable(GL10.GL_NORMALIZE);

经过规范化后法向量为单位向量(长度为1)。同时可以打开缩放法线设置

1 gl.glEnable(GL10.GL_RESCALE_NORMAL);

设置好法线后,需要设置物体表面材料(Material)的反光属性(颜色和材质)。

将在下篇介绍设置物体表面材料(Material)的反光属性(颜色和材质)并给出一个光照的示例。

设置物体表面材料(Material)的反光属性(颜色和材质)的方法如下:

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 : 在OpenGL ES中只能使用GL_FRONT_AND_BACK,表示修改物体的前面和后面的材质光线属性。
  • pname: 参数类型,可以有GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_EMISSION, GL_SHININESS。这些参数用在光照方程。
  • param: 参数的值。

其中GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR ,GL_EMISSION为颜色RGBA值,GL_SHININESS 值可以从0到128,值越大,光的散射越小:

此外,方法glLightModleXX给出了光照模型的参数

public void glLightModelf(int pname,float param)
public void glLightModelfv(int pname,float[] params,int offset)
public void glLightModelfv(int pname,FloatBuffer params)

  • pname: 参数类型,可以为GL_LIGHT_MODEL_AMBIENT和GL_LIGHT_MODEL_TWO_SIDE
  • params: 参数的值。

最终顶点的颜色由这些参数(光源,材质光学属性,光照模型)综合决定(光照方程计算出)。

下面例子在场景中设置一个白色光源:

1 public void initScene(GL10 gl){
2 float[] amb = { 1.0f, 1.0f, 1.0f, 1.0f, };
3 float[] diff = { 1.0f, 1.0f, 1.0f, 1.0f, };
4 float[] spec = { 1.0f, 1.0f, 1.0f, 1.0f, };
5 float[] pos = { 0.0f, 5.0f, 5.0f, 1.0f, };
6 float[] spot_dir = { 0.0f, -1.0f, 0.0f, };
7 gl.glEnable(GL10.GL_DEPTH_TEST);
8 gl.glEnable(GL10.GL_CULL_FACE);
9
10 gl.glEnable(GL10.GL_LIGHTING);
11 gl.glEnable(GL10.GL_LIGHT0);
12 ByteBuffer abb
13 = ByteBuffer.allocateDirect(amb.length*4);
14 abb.order(ByteOrder.nativeOrder());
15 FloatBuffer ambBuf = abb.asFloatBuffer();
16 ambBuf.put(amb);
17 ambBuf.position(0);
18
19 ByteBuffer dbb
20 = ByteBuffer.allocateDirect(diff.length*4);
21 dbb.order(ByteOrder.nativeOrder());
22 FloatBuffer diffBuf = dbb.asFloatBuffer();
23 diffBuf.put(diff);
24 diffBuf.position(0);
25
26 ByteBuffer sbb
27 = ByteBuffer.allocateDirect(spec.length*4);
28 sbb.order(ByteOrder.nativeOrder());
29 FloatBuffer specBuf = sbb.asFloatBuffer();
30 specBuf.put(spec);
31 specBuf.position(0);
32
33 ByteBuffer pbb
34 = ByteBuffer.allocateDirect(pos.length*4);
35 pbb.order(ByteOrder.nativeOrder());
36 FloatBuffer posBuf = pbb.asFloatBuffer();
37 posBuf.put(pos);
38 posBuf.position(0);
39
40 ByteBuffer spbb
41 = ByteBuffer.allocateDirect(spot_dir.length*4);
42 spbb.order(ByteOrder.nativeOrder());
43 FloatBuffer spot_dirBuf = spbb.asFloatBuffer();
44 spot_dirBuf.put(spot_dir);
45 spot_dirBuf.position(0);
46
47
48 gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, ambBuf);
49 gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, diffBuf);
50 gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPECULAR, specBuf);
51 gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, posBuf);
52 gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPOT_DIRECTION,
53 spot_dirBuf);
54 gl.glLightf(GL10.GL_LIGHT0, GL10.GL_SPOT_EXPONENT, 0.0f);
55 gl.glLightf(GL10.GL_LIGHT0, GL10.GL_SPOT_CUTOFF, 45.0f);
56
57 gl.glLoadIdentity();
58 GLU.gluLookAt(gl,0.0f, 4.0f, 4.0f, 0.0f, 0.0f, 0.0f,
59 0.0f, 1.0f, 0.0f);
60
61 }

绘制一个球,并使用蓝色材质:

1 public void drawScene(GL10 gl) {
2 super.drawScene(gl);
3
4 float[] mat_amb = {0.2f * 0.4f, 0.2f * 0.4f,
5 0.2f * 1.0f, 1.0f,};
6 float[] mat_diff = {0.4f, 0.4f, 1.0f, 1.0f,};
7 float[] mat_spec = {1.0f, 1.0f, 1.0f, 1.0f,};
8
9
10 ByteBuffer mabb
11 = ByteBuffer.allocateDirect(mat_amb.length*4);
12 mabb.order(ByteOrder.nativeOrder());
13 FloatBuffer mat_ambBuf = mabb.asFloatBuffer();
14 mat_ambBuf.put(mat_amb);
15 mat_ambBuf.position(0);
16
17 ByteBuffer mdbb
18 = ByteBuffer.allocateDirect(mat_diff.length*4);
19 mdbb.order(ByteOrder.nativeOrder());
20 FloatBuffer mat_diffBuf = mdbb.asFloatBuffer();
21 mat_diffBuf.put(mat_diff);
22 mat_diffBuf.position(0);
23
24 ByteBuffer msbb
25 = ByteBuffer.allocateDirect(mat_spec.length*4);
26 msbb.order(ByteOrder.nativeOrder());
27 FloatBuffer mat_specBuf = msbb.asFloatBuffer();
28 mat_specBuf.put(mat_spec);
29 mat_specBuf.position(0);
30
31 gl.glMaterialfv(GL10.GL_FRONT_AND_BACK,
32 GL10.GL_AMBIENT, mat_ambBuf);
33 gl.glMaterialfv(GL10.GL_FRONT_AND_BACK,
34 GL10.GL_DIFFUSE, mat_diffBuf);
35 gl.glMaterialfv(GL10.GL_FRONT_AND_BACK,
36 GL10.GL_SPECULAR, mat_specBuf);
37 gl.glMaterialf(GL10.GL_FRONT_AND_BACK,
38 GL10.GL_SHININESS, 64.0f);
39
40 sphere.draw(gl);
41
42 }

分享到:
评论

相关推荐

    opengles绘制球体增加光照效果

    opengles光照

    opengles光照通道合成

    opengles光照通道合成

    OPENGL光照和纹理技术实例.rar

    OPENGL光照和纹理技术实例.rar OPENGL光照和纹理技术实例.rar

    【OpenGL ES】光影(光照与阴影)效果

    绘制阴影,需要用到深度纹理,即从光源角度看模型并绘制一张纹理图,纹理图的颜色代表了模型上的点离光源的深度,只有离光源较近的点才会... 本资源绘制了球、立方体和平面,添加了光照效果,并且给模型添加了阴影。

    opengles加载3d模型(纹理+光照)

    opengles加载3d模型(纹理+光照)

    OpenGL ES应用开发实践指南(Android卷).pdf

    由资深Android开发专家根据OpenGLES2.0版本撰写,不仅系统地讲解了OpenGLES的核心概念、技术,以及Android的图形机制,还通过大量案例讲解了在Android上进行OpenGLES开发的方法和技巧。  《OpenGL ES应用开发实践...

    opengles创建圆柱体(光照加纹理)

    opengles创建圆柱体(光照加纹理)

    OpenGL ES应用开发实践指南 Android卷

    由资深Android开发专家根据OpenGLES2.0版本撰写,不仅系统地讲解了OpenGLES的核心概念、技术,以及Android的图形机制,还通过大量案例讲解了在Android上进行OpenGLES开发的方法和技巧。  《OpenGL ES应用开发实践...

    OpenGL ES 3.x游戏开发 上卷 高清版

    ● 介绍了OpenGL ES 3.x中的光照、纹理映射、3 D 模型加载、混合和雾等基础特效, 以及常用的 3 D 开发技巧, 如标志板、天空盒、镜像绘制等。 ● 既介绍了Android下使用SDK基于Java进行开发,又介绍了Android下使用...

    OpenGL ES 3.x游戏开发 上卷 吴亚峰.pdf

    主要内容为:OpenGL ES 3.x的渲染管线介绍,OpenGL ES 3.x 可编程渲染管线着色器的着色语言介绍,3D 开发中投影、各种变换的原理与实现,介绍了OpenGL ES 3.x中光照的基本原理与实现、点法向量与面法向量的区别以及...

    android平台使用opengles2.0实现的翻书特效

    android平台利用opengles2.0技术实现的3D 翻书特效,带有完美阴影和光照技术;目前仅支持从右下角开始翻转,翻过一定角度松手后,自动翻转过去,否则的话,松手则还是翻回来;阴影是使用的阴影平面技术实现的,效果...

    OpenGL ES实现光照效果(六)

    主要为大家详细介绍了OpenGL ES实现光照效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

    OpenGL ES实现的超简单的地月日效果

    OpenGL ES实现的超简单的地月日效果,太阳只有自转,地球和月球都带有自转和公转,没有附加光照效果,只有纹理贴图

    【OpenGL ES】Blinn改进的冯氏光照模型

    光照元素主要有环境光(ambient)、漫反射光(diffuse)、镜面反射光(specular),光照模型主要有冯氏模型和 Blinn 改进的冯氏模型,两者区别在与镜面反射光的计算,冯氏模型根据反向量和观察向量计算镜面反射光,...

    opengles应用开发实践指南android卷

    在本书第一部分,会学习如何创建一个简单的空气曲棍球游戏,包括触控、纹理和基本原理。这个项目会教你如何成功地初始化OpenGL并将数据发送到屏幕上,以及如何使用基本的向量和矩阵数学创建三维世界。你也会学到...

    iPhone三维程序设计 基于OpenGL ES的图形应用程序设计

    《iphone三维程序设计基于opengl es的图形应用程序设计》详细阐述了基于opengl es的3d图形程序设计,主要包括顶点和触摸点、景深和现实感、纹理和图像捕捉、混合操作与增强现实感、精灵和文本、高级光照和纹理以及...

    opengles绘制圆锥体

    opengles绘制圆锥体 (光照+纹理)

    opengl es android demo 程序

    点、线、球休、多面体,光照效果等示例程序源码,想学opengl es android方面的,可以看看!!!

    OPENGL ES ios教程源码

    OPENGL ES ios教程源码,包括渲染管线、着色器、矩阵变换、模型视图投影、VBO、光照、深度缓存等内容。

Global site tag (gtag.js) - Google Analytics