现在的位置: 首页 > 综合 > 正文

adnroid 3D 系列之光效篇

2013年09月06日 ⁄ 综合 ⁄ 共 7162字 ⁄ 字号 评论关闭

 

光效三要素

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

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

component

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

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

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

环境光

你的光效中有越多的环境元素,那么就越不会产生引入注目的效果。所有光线的环境元素会融合在一起产生效果,意思是场景中的总环境光效是由所有启动光源的环境光组合在一起所决定的。如果你使用了不止一个光源,那么最好是只指定一个光源的环境元素,而设定其他所有光源的环境因素为黑 ({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/

我们今天例子的效果:

实例代码:

001 public
class
CubeRenderer implements
Renderer {
002   
003     float
box[] = new
float
[] {
004             // FRONT
005             -0.5f, -0.5f, 
0.5f,
006              0.5f, -0.5f, 
0.5f,
007             -0.5f, 
0.5f,  0.5f,
008              0.5f, 
0.5f,  0.5f,
009             // BACK
010             -0.5f, -0.5f, -0.5f,
011             -0.5f, 
0.5f, -0.5f,
012              0.5f, -0.5f, -0.5f,
013              0.5f, 
0.5f, -0.5f,
014             // LEFT
015             -0.5f, -0.5f, 
0.5f,
016             -0.5f, 
0.5f,  0.5f,
017             -0.5f, -0.5f, -0.5f,
018             -0.5f, 
0.5f, -0.5f,
019             // RIGHT
020              0.5f, -0.5f, -0.5f,
021              0.5f, 
0.5f, -0.5f,
022              0.5f, -0.5f, 
0.5f,
023              0.5f, 
0.5f,  0.5f,
024             // TOP
025             -0.5f, 
0.5f,  0.5f,
026              0.5f, 
0.5f,  0.5f,
027              -0.5f, 
0.5f, -0.5f,
028              0.5f, 
0.5f, -0.5f,
029             // BOTTOM
030             -0.5f, -0.5f, 
0.5f,
031             -0.5f, -0.5f, -0.5f,
032              0.5f, -0.5f, 
0.5f,
033              0.5f, -0.5f, -0.5f,
034         };
035     float
lightAmbient[] = new
float[] { 0.2f,
0.3f, 0.6f,
1.0f };  //环境光
036     float
lightDiffuse[] = new
float[] { 0.2f,
0.3f, 0.6f,
1.0f };//漫反射光
037     float[] lightPos =
new float[] {0,0,3,1}; 
//光源位置
038 /**
039  * 因为进行光照处理,你必须告知系统你定义的模型各个面的方向,以便系统计算光影情况,方向的描述是通过向量点来描述的
040  */ 
041     float
norms[] = new
float
[] { //法向量数组,用于描述个顶点的方向,以此说明各个面的方向
042             // FRONT
043             0f,  0f,  1f,
//方向为(0,0,0)至(0,0,1)即Z轴正方向
044             0f,  0f,  1f,
045             0f,  0f,  1f,
046             0f,  0f,  1f,
047             // BACK
048             0f,  0f,  -1f,
049             0f,  0f,  -1f,
050             0f,  0f,  -1f,
051             0f,  0f,  -1f,
052             // LEFT
053             -1f,  0f,  0f,
054             -1f,  0f,  0f,
055             -1f,  0f,  0f,
056             -1f,  0f,  0f,
057             // RIGHT
058             1f, 0f, 0f,
059             1f, 0f, 0f,
060             1f, 0f, 0f,
061             1f, 0f, 0f,
062             // TOP
063             0f,  1f, 0f,
064             0f,  1f, 0f,
065             0f,  1f, 0f,
066             0f,  1f, 0f,
067             // BOTTOM
068             0f,  -1f, 0f,
069             0f,  -1f, 0f,
070             0f,  -1f, 0f,
071             0f,  -1f, 0f
072         };
073   
074       
075     FloatBuffer cubeBuff;
076     FloatBuffer normBuff;
077       
078     float
xrot = 0.0f;
079     float
yrot = 0.0f;
080       
081     /**
082      * 将float数组转换存储在字节缓冲数组
083      * @param arr
084      * @return
085      */
086     public
FloatBuffer makeFloatBuffer(float[] arr) {
087         ByteBuffer bb = ByteBuffer.allocateDirect(arr.length *
4);//分配缓冲空间,一个float占4个字节
088         bb.order(ByteOrder.nativeOrder());
//设置字节顺序, 其中ByteOrder.nativeOrder()是获取本机字节顺序
089         FloatBuffer fb = bb.asFloatBuffer();
//转换为float型
090         fb.put(arr);       
//添加数据
091         fb.position(0);     
//设置数组的起始位置
092         return
fb;
093     }
094       
095     public
CubeRenderer() {
096         // TODO Auto-generated constructor stub
097         cubeBuff = makeFloatBuffer(box);//转换float数组
098         normBuff = makeFloatBuffer(norms);
099     }
100       
101       
102     protected
void init(GL10 gl) {
103         gl.glClearColor(0.0f,
0.0f, 0.0f,
1.0f);//设置清屏时背景的颜色,R,G,B,A
104           
105         gl.glEnable(GL10.GL_LIGHTING);
//启用光照
106         gl.glEnable(GL10.GL_LIGHT0); 
//开启光源0,最多可以开启8个光源
107         //设置光照参数,也可以使用默认的,不设置
108         gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, lightAmbient,
0);
109         gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, lightDiffuse,
0);
110         gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightPos,
0);
111           
112         gl.glNormalPointer(GL10.GL_FLOAT,
0, normBuff);
113         gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
114           
115         gl.glEnable(GL10.GL_DEPTH_TEST);
//启用深度缓存
116         gl.glEnable(GL10.GL_CULL_FACE); 
//启用背面剪裁
117         gl.glClearDepthf(1.0f);   
// 设置深度缓存值
118         gl.glDepthFunc(GL10.GL_LEQUAL); 
// 设置深度缓存比较函数,GL_LEQUAL表示新的像素的深度缓存值小于等于当前像素的深度缓存值(通过gl.glClearDepthf(1.0f)设置)时通过深度测试   
119         gl.glShadeModel(GL10.GL_SMOOTH);// 设置阴影模式GL_SMOOTH
120     }
121       
122     @Override
123     public
void onSurfaceCreated(GL10 gl, EGLConfig config) {
124         // TODO Auto-generated method stub
125         init(gl);
126     }
127       
128     @Override
129     public
void onSurfaceChanged(GL10 gl,
int w, int
h) {
130         // TODO Auto-generated method stub
131         gl.glViewport(0,
0, w, h);
//设置视窗
132         gl.glMatrixMode(GL10.GL_PROJECTION);
// 设置投影矩阵
133         gl.glLoadIdentity(); 
//设置矩阵为单位矩阵,相当于重置矩阵       
134         GLU.gluPerspective(gl,
45.0f, ((float) w) / h,
0.1f, 10f);//设置透视范围  
135     }
136       
137     @Override
138     public
void onDrawFrame(GL10 gl) {
139         // TODO Auto-generated method stub
140         gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);// 清除屏幕和深度缓存
141           
142         gl.glMatrixMode(GL10.GL_MODELVIEW);  
//切换至模型观察矩阵
143         gl.glLoadIdentity();// 重置当前的模型观察矩阵
144         GLU.gluLookAt(gl,
0, 0,
3, 0,
0, 0,
0, 1,
0);//设置视点和模型中心位置
145       
146         gl.glVertexPointer(3, GL10.GL_FLOAT,
0, cubeBuff);//设置顶点数据
147         gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
148       
149         gl.glRotatef(xrot,
1, 0,
0);  //绕着(0,0,0)与(1,0,0)即x轴旋转
150         gl.glRotatef(yrot,
0, 1,
0);
151           
152         gl.glColor4f(1.0f,
0, 0,
1.0f);   //设置颜色,红色
153         gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,
0, 4); 
//绘制正方型FRONT面
154         gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,
4, 4);
155       
156         gl.glColor4f(0,
1.0f, 0,
1.0f);
157         gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,
8, 4);
158         gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,
12, 4);
159           
160         gl.glColor4f(0,
0, 1.0f,
1.0f);
161         gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,
16, 4);
162         gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,
20, 4);
163       
164         xrot +=
0.5f;
165         yrot +=
0.5f;
166     }
167   
168 }

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

【上篇】
【下篇】

抱歉!评论已关闭.