adnroid 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})。 你还可以通过改变红,绿,蓝元素的百分比来调整色偏。

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

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/

我们今天例子的效果:

实例代码:

001public 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模型添加光效,并不需要改动很大。只需要在之前实践篇代码基础上添加上述代码即可~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值