为了能看出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);
|
10 |
gl.glEnable(GL10.GL_LIGHTING);
|
11 |
gl.glEnable(GL10.GL_LIGHT0);
|
13 |
= ByteBuffer.allocateDirect(amb.length* 4 );
|
14 |
abb.order(ByteOrder.nativeOrder());
|
15 |
FloatBuffer ambBuf = abb.asFloatBuffer();
|
20 |
= ByteBuffer.allocateDirect(diff.length* 4 );
|
21 |
dbb.order(ByteOrder.nativeOrder());
|
22 |
FloatBuffer diffBuf = dbb.asFloatBuffer();
|
27 |
= ByteBuffer.allocateDirect(spec.length* 4 );
|
28 |
sbb.order(ByteOrder.nativeOrder());
|
29 |
FloatBuffer specBuf = sbb.asFloatBuffer();
|
34 |
= ByteBuffer.allocateDirect(pos.length* 4 );
|
35 |
pbb.order(ByteOrder.nativeOrder());
|
36 |
FloatBuffer posBuf = pbb.asFloatBuffer();
|
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 );
|
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,
|
54 |
gl.glLightf(GL10.GL_LIGHT0, GL10.GL_SPOT_EXPONENT,
0 .0f);
|
55 |
gl.glLightf(GL10.GL_LIGHT0, GL10.GL_SPOT_CUTOFF,
45 .0f);
|
58 |
GLU.gluLookAt(gl, 0 .0f,
4 .0f, 4 .0f,
0 .0f, 0 .0f,
0 .0f,
|
绘制一个球,并使用蓝色材质:
1 |
public void
drawScene(GL10 gl) {
|
4 |
float [] mat_amb = { 0 .2f *
0 .4f, 0 .2f *
0 .4f,
|
6 |
float [] mat_diff = { 0 .4f,
0 .4f, 1 .0f,
1 .0f,};
|
7 |
float [] mat_spec = { 1 .0f,
1 .0f, 1 .0f,
1 .0f,};
|
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 );
|
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 );
|
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 );
|
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);
|
分享到:
相关推荐
"opengles绘制球体增加光照效果"这个主题旨在讨论如何在OpenGL ES环境下为3D球体添加真实的光照效果,使渲染出的模型更具有立体感和生动性。 光照模型在OpenGL ES中主要通过两种方式实现:固定管线(Fixed Pipeline...
在“opengles光照通道合成”这个主题中,我们将深入探讨OpenGL ES如何实现光照效果的组合与管理。 光照在3D图形中至关重要,它赋予场景真实感和深度。OpenGL ES提供了多种光照模型来模拟不同的光照效果,包括环境光...
这个"OPENGL光照和纹理技术实例.rar"压缩包包含了关于如何在OpenGL中应用光照和纹理的关键概念和技术的实例。以下是这些主题的详细解释: 光照在OpenGL中是通过一组称为光源(light sources)的对象来实现的,它们...
在OpenGLES中绘制圆锥体是一个典型的3D图形编程任务,它涉及到多个关键知识点,包括顶点坐标、几何形状构建、光照模型以及纹理映射。让我们深入探讨这些概念。 首先,OpenGLES(OpenGL for Embedded Systems)是...
它通常与OpenGL ES不直接交互,但在构建例如3D地理信息系统或可视化应用时,可能会利用Elasticsearch来检索和组织数据,然后通过OpenGL ES进行呈现。 总的来说,OpenGL ES 3.0编程指南涵盖了移动和嵌入式设备图形...
opengles加载3d模型(纹理+光照)
绘制阴影,需要用到深度纹理,即从光源角度看模型并绘制一张纹理图,纹理图的颜色代表了模型上的点离光源的深度,只有离光源较近的点才会... 本资源绘制了球、立方体和平面,添加了光照效果,并且给模型添加了阴影。
由资深Android开发专家根据OpenGLES2.0版本撰写,不仅系统地讲解了OpenGLES的核心概念、技术,以及Android的图形机制,还通过大量案例讲解了在Android上进行OpenGLES开发的方法和技巧。 《OpenGL ES应用开发实践...
由资深Android开发专家根据OpenGLES2.0版本撰写,不仅系统地讲解了OpenGLES的核心概念、技术,以及Android的图形机制,还通过大量案例讲解了在Android上进行OpenGLES开发的方法和技巧。 《OpenGL ES应用开发实践...
在本压缩包“OpenglES3.0完整环境.rar”中,你将找到搭建OpenGL ES 3.0开发环境所需的所有资源,包括仿真模拟器、示例代码和CMake构建工具。 首先,让我们详细了解一下OpenGL ES 3.0的新特性: 1. **增强的顶点...
在"opengles3.0游戏开发(上(1))"中,可能包含了一系列的实例项目,这些项目可能会涵盖上述知识点,如建立基本的游戏框架、创建3D模型、实现基本的交互功能等。每个案例都是一个具体的应用场景,通过实践来巩固...
通过阅读《OpenGL ES 2.0编程指南》,开发者可以深入理解图形编程的基本原理,并掌握在移动设备上实现复杂3D图形的方法。对于希望进入游戏开发、虚拟现实、增强现实等领域的人来说,这是一本不可或缺的参考书。
OpenGL ES 2.0 编程指南中文版详细介绍了OpenGL ES 2.0的编程技术和方法,这是专为移动和嵌入式系统设计的图形API的2.0版本,广泛应用于各种便携式设备和游戏机上。 ### OpenGL ES基础 OpenGL ES(Open Graphics ...
在OpenGLES中,这涉及到坐标系统转换、几何变换、光照模型、纹理映射、深度测试等多个概念。例如,顶点着色器和片段着色器是实现这些效果的关键,前者处理几何信息,后者处理像素颜色。 三、渲染流程 在OpenGLES中...
总的来说,OpenGL ES 1.1是移动和嵌入式设备3D图形编程的基础,虽然现在已经被更现代的OpenGL ES 2.0和3.0所取代,但对于理解图形学的基本原理和在旧设备上运行的应用程序,它仍然是不可或缺的一部分。
"opengles绘制灰度地形图"这个主题,主要涉及如何使用OpenGL ES来创建并渲染基于灰度值表示的3D地形。下面将详细讲解这个过程中的关键知识点。 1. **灰度图像**: 灰度图像是一种单通道图像,其中每个像素用一个...
最后,了解如何与硬件加速的OpenGLES API交互,以及熟悉GLSL语言(OpenGL Shading Language),是成为OpenGL ES 2.0专家的必经之路。通过编写高效、可读性强的着色器代码,可以创造出各种复杂的视觉效果,实现令人...
2. **浮点纹理支持**:OpenGL ES 3.0允许使用浮点格式的纹理,这对于科学可视化、后期处理和光照计算等应用非常有用。浮点纹理可以存储颜色、深度信息或者计算数据。 3. **多个绘制缓冲区(Multiple Draw Buffers)...
2. **基础概念**:深入浅出地讲解OpenGL ES 2的基本原理,包括顶点数据、纹理映射、着色器等核心概念。 3. **数学与矩阵运算**:这部分内容对于理解和操作3D图形至关重要。书中提供了大量实例来帮助理解如何使用...
OpenGLES的学习是一个由浅入深的过程,从基础概念开始,逐步掌握变换、光照、纹理等高级主题。通过不断的实践和实验,开发者可以创建出丰富多彩的3D图形界面,提升应用的用户体验。在Android和iOS平台上,OpenGLES的...