opengL ES _ 入门_05

学习是一件开心的额事情

展示图:

效果图

友情提示:

本文重在讲解一些游戏中灯光的类型和作用,明白原理就可以,代码看不懂没关系.之后会用大量时间,剖析OpenGL ES 代码,持续更新!

  • 学习目标:

1.理解OpenGL是如何模拟现实世界的光照条件 2.通过定义光源,材料和光照模型属性,渲染光照物体 3.定义光照物体的材料属性

  • 任务:

绘制一个被光照射的球体

  • 概念解释:

深度缓冲区原理:首先,把一个距离观察平面的深度值(距离) 与窗口中的每个像素相关联,一开始,使用glClear(GL_DEPTH_BUFFER_BIT) 把所有像素的深度值,设置为最大可能的距离,然后,在场景中绘制所有物体,硬件或者软件会把被绘制表面转回为像素集合,在这个时候,不考虑是否被遮挡,OpenGL 此时,还会计算,这些表面和观查着平面的距离,如果启动了深度缓冲区,OpenGL 会把它的深度值和已经存储在缓冲区中的深度值,进行比较,如果新像素比原先的像素更靠近观察平面,这个新像素的颜色和深度会取代原先那个像素,如果新像素的深度值大于原先像素的深度值,新像素就会被遮挡,他的颜色和深度会被丢弃。

如何使用?

首先需要启动它,启动一次即可,每次绘制场景时,需要在绘制之前清除深度缓冲区,然后以任意顺序绘制场景中的物体 glclear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) 理解OpenGL是如何模拟现实世界的光照条件

补充知识?

当观察一个物理表面时,眼睛对颜色的感知取决于到达刺激缀细胞的光子和能量分布,这些光子可能来自单个光源,也可能来自多个光源,有些光子被表面吸收,有些被反射出来。不同表面的属性可能存在非常大的区别,有些表面非常光滑,会把光线反射到某个方向,有些表面会把均匀的发散到所有地方,很多表面位于两者之间。

请认真阅读以上的内容,这个将影响到您对本文的理解。

OpenGL是怎么模拟光照的?

首先,假定光可以分解为红,绿,蓝成分,光源的特性是由它发射的红,绿和蓝的数量决定的,表面材料的特性,是由它向不同方向反射光的百分比决定的。OpenGL 有自己的一套光照方程式,计算效率相对来说,也很高,如果想要自己实现这样的一套光照方程式,也可以,可能你需要花费很大的精力,实在是太复杂了。 OpenGL 光照模型中,场景中的灯光,有来自固定方向的和不同方向的,可以单独打开和关闭,这个很简单,想一下我们的生活场景就可以了。 当光照射到物体上,能会体现出光照的意义。 OpenGL 光照模型,把光分为4种独立的成分:环境光,反射光,镜面光,发射光。

下面就来解释一下四种光的含义和作用。

环境光: 在环境中充分的散射,无法辨别其方向的光,似乎来自于所有的方向。当环境光撞击物体表面时,会向各个方向发散。 散射光:来自某个方向,如果它从正面照射,他可能看起来更亮一下,如果他斜着掠过表面,看其他则会暗一些,来自某个特性的位置或者方向的任何光很可能具有散射的成分。

朗伯体光照模型:

朗伯体光照模型

Id=kdIi cos(Θ)

ID是漫反射的强度,Ii是光的入射光的强度,和KD的漫反射,是对粗糙松散耦合对象材料。松散的意思是,在许多现实世界的材料,实际表面可能有点抛光,但半透明的,而层立即下执行散射。材料,如这可能有强烈的漫反射和镜面反射成分。此外,每个颜色带可能有自己的K值在现实生活中,所以会有一个红色,绿色和蓝色

镜面光:来自某个方向,如果物体表面光滑,这种光将充分反射,但是一般的物体表面不会绝对的光滑,所有不可能有真正的完美反射.

1594482-ab7c1ba7c2e68e10.png

I =W(q)I cosn Θ Ilight 入射光的轻度 W(q) 基于光线I的夹角是如何反射的 N是亮度因子 Θ是反射光线,光线射到眼睛的夹交 虽然W(q)是不能直接使用在OpenGL ES 1,它可以用来在一个版本的OpenGL ES 2着色器。它将是特别有用的,在做反射的水,例如。在它的位置是一个常数,是基于从材质设置的高光值。

发射光:材料自身可能具有一种发射颜色,可以模拟那些来自物体的光,它不受任何光源的影响,发射颜色没有作为一种额外的光源。 顶点颜色值: color=ambientworldmodel +ambientmaterial +emissivematerial +intensitylight 材料颜色:可以给物体设置材料颜色,通俗的解释一下,假设一个物体的材料颜色为红色,那么,用蓝光照射这个物体,我们看到的是一个黑色的球,因为他把蓝光吸收了,如果我们用红光照射他,我们看到的就是一个红球,如果用白光照射他,我们也看到的是红球,因为白光(R=1,G=1,B=1)中 用红光的成分 光照和材料RGB值 如果一束光线的成分为(LR,LG,LB) 一种材料具有的颜色成分为(MR,MG,MB) 那么,进入眼睛的光就是(LR*MR,LG*MG,LB*MB) 两个光源叠加原理(R1,G1,B1) 和 (R2,G2,B2) 叠加后 (R1+R2,G1+G2,B1+B2) 如果相加后任何一个值大于1,则会被截取1(因为设备能后现实的最大颜色亮度)。

提示:

如果使用光照RGBA 颜色索引模式优先选择

为每个物体的每个顶点定义法线向量?

物体的法线向量,决定了它相对于光源的方向,OpenGL 使用法线判断这个顶点从每个光源接受的光线数量,注意,为了正确计算光线,表面法线必须为单位长度,必须保证对物体所进行的模型转换,并没有对表面法线进行缩放,最终的法线仍然为单位长度。

如何创建光源?

glLightfv()函数指定光源的位置,如果使用不同颜色的光,使用glLight*()函数修改 场景中至少可以包含八个光源,除了GL_LIGHT0 之外的其他光源的颜色都为黑色。可以把光源放在很远的地方,模拟阳光,可以对光源进行控制,让它产生狭窄的聚焦光束和角度宽广的光束

如何启用光源?

glEnable() 参数GL_LIGHTING 光源的几个重要属性:颜色,位置,和方向 两个重要函数: glLight(GLenum light,Glenum pname,TYPE para), glLightv(GLenum light,Glenum pname,TYPE *param ) 参数1 light 指定光源 GL_LIGHT0…GL_LIGHT7 参数2 pname 具体的属性 参数3 para 属性值单值,param属性值,向量 根据属性的不同选择不同的函数

参考下面的表格

参数名称

默认值

含义

GL_AMBIENT

(0,0,0,1)

环境光强度

GL_DIFFUSE

(1,1,1,1)

光的散射强度

GL_SPECULAR

(1,1,1,1)

光的镜面强度

GL_POSITION

(0,0,1,0)

光源的位置坐标

GL_SPOT_DIRECTION

(0,0,-1,0)

聚光灯的方向

GL_SPOT_EXPONENT

0.0

聚光指数

GL_SPOT_CUTOFF

180

聚光灯的切角

GL_CONSTANT_ATTENUATION

1.0

常亮衰减因子

GL_LINEAR_ATTENUATION

0.0

线性衰减因子

GL_QUADRATIC_ATTENUATION

0.0

二次衰减因子

提示: 如果想要创建逼真的效果可以将GL_SPECULAR 和 GL_DIFFUSE 的参数值设置相同

选择光照模型我们应该思考的问题?

1.观察者应该在无限远处还是场景本地 2.确定场景中的物体的正面和背面是否应该执行不同的计算 glLightModel*()

为场景中的物体定义材料属性?

物体的材料属性决定他是如何反射光线的,因此也决定了它的颜色。可以指定材料的颜色,散射和镜面颜色以及它的光泽,这个例子只指定了最后两种材料属性,镜面材料颜色和光泽度。

提示: 当光照条件发生变化时,可以使用显示列表实现最大限度的效率

  • 光源类型

第一种,光源位于无限远处,这种光源被称为方向性光源,如果光源位于无限远处,当光线到达物体表面时,认为所有的光源都是平行的 第二种,被称为位置性光源,通俗的讲,它的位置决定它对场景产生的效果,具体来说,它决定光线的方向,台灯就是一个位置性光源,通常位置性光源是朝向每个方向发射光线的,但也可以把光源定义为聚光灯,把它的照明范围限制在一个锥体里

  • 衰减

随着光源的距离的增加,光的强度也随之衰减,由于方向性光源在无限远处,所以这个原则不适用于方向性光源,但是我们可以对位置性光源进行衰减,OpenGL将光源的强度乘以衰减因子。 衰减因子 = 1/(kc+kl*d+kq*d^2) d = 光源和顶点的位置 KC = GL_CONSTANT_ATTENUATION KL = GL_LINEAR_ATTENUATION KQ = GL_QUADRATIC_ATTENUATION 环境光,散射光,镜面光的强度都进行了衰减,只有发射光和全局环境光没有衰减,由于衰减需要在每种经过计算差生的颜色上再进行一次除法,所以衰减光可能会影响应用程序的性能。

创建聚光灯步骤?

1594482-34b63549fa30bdf8.png

设置光锥切角: glLightf(GL_LIGHT0,GL_SPOT_CUTOFF,45.0); 设置聚光灯的方向 默认方向为(0,0,-1) glLightfv(GL_LIGHT0,GL_SPOT_DORECTION,spot_direction); 可以设置衰减因子和光的集中度 GL_SPOT_EXPONENT 参数控制光的集中度

代码部分:

-(void)initLighting
{
// 创建灯光的位置
GLfloat posMain[]={5.0,4.0,6.0,1.0};
GLfloat posFill1[]={-15.0,15.0,0.0,1.0};
GLfloat posFill2[]={-10.0,-4.0,1.0,1.0};
GLfloat white[]={1.0,1.0,1.0,1.0};
// 定义几种颜色值
GLfloat dimblue[]={0.0,0.0,.2,1.0};
GLfloat cyan[]={0.0,1.0,1.0,1.0};
GLfloat yellow[]={1.0,1.0,0.0,1.0};
GLfloat dimmagenta[]={.75,0.0,.25,1.0};
GLfloat dimcyan[]={0.0,.5,.5,1.0};
//设置反射光的位置和颜色
glLightfv(GL_LIGHT0,GL_POSITION,posMain);
glLightfv(GL_LIGHT0,GL_DIFFUSE,white);
// 设置镜面光的颜色,它的光源和反射光是同一个光源
glLightfv(GL_LIGHT0,GL_SPECULAR,yellow);
// 设置光源2的位置和类型
glLightfv(GL_LIGHT1,GL_POSITION,posFill1);
glLightfv(GL_LIGHT1,GL_DIFFUSE,dimblue);
glLightfv(GL_LIGHT1,GL_SPECULAR,dimcyan);
// 设置光源3 的位置和类型以及
glLightfv(GL_LIGHT2,GL_POSITION,posFill2);
glLightfv(GL_LIGHT2,GL_SPECULAR,dimmagenta);
glLightfv(GL_LIGHT2,GL_DIFFUSE,dimblue);
//设置衰减因子
glLightf(GL_LIGHT2,GL_QUADRATIC_ATTENUATION,.005);
//设置材料在反射光下的颜色
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, cyan);
// 设置材料在镜面光下的颜色
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, white);
//
glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,25);
// 设置光照模式 GL_SMOOTH 代表均匀的颜色涂在表面上
glShadeModel(GL_SMOOTH);
glLightModelf(GL_LIGHT_MODEL_TWO_SIDE,0.0);
// 开启灯光模式
glEnable(GL_LIGHTING);
// 打开灯光123
glEnable(GL_LIGHT0);
glEnable(GL_LIGHT1);
glEnable(GL_LIGHT2);
}

参考完整代码:

完整代码下载地址:demo

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏专知

【读书笔记】基于知识库的问答:生成查询图进行语义分析

【导读】将DBPedia和Freebase这样的大规模知识库组织并存储在一个结构化的数据库,这已成为支持开放领域问题问答的重要资源。 KB-QA的大多数方法基于...

5087
来自专栏小石不识月

用粒子群优化算法求解旅行商问题

粒子群优化算法采用一种人工智能的形式来解决问题。这种算法对于求解那些使用了多个连续变化的值的函数来说,尤为有效。这篇文章将会介绍如何修改粒子群算法,以使用离散固...

4548
来自专栏数据魔术师

干货 | 变邻域搜索算法(VNS)求解TSP(附C++详细代码及注释)

上次变邻域搜索的推文发出来以后,看过的小伙伴纷纷叫好。小编大受鼓舞,连夜赶工,总算是完成了手头上的一份关于变邻域搜索算法解TSP问题的代码。今天,就在此...

1.4K2
来自专栏一心无二用,本人只专注于基础图像算法的实现与优化。

13行代码实现最快速最高效的积分图像算法。

  研究图像到一定程度的人,应该都对积分图像有所了解,大家在百度或者google中都可以搜索到大量的相关博客,我这里不做多介绍。用积分图也确实能解决很多实际的问...

4488
来自专栏数据科学与人工智能

【Python环境】Python语言下的机器学习库

Python是最好的编程语言之一,在科学计算中用途广泛:计算机视觉、人工智能、数学、天文等。它同样适用于机器学习也是意料之中的事。 当然,它也有些缺点;其中一个...

3056
来自专栏积累+成长

初识

具体处理方法是确定示踪剂的加入区域,如图 3 所示,选择柱体为加料区 A,柱体半径为 10 mm,然后把示踪剂在加料区内的初始浓度设为1,其他区域的初始浓度设为...

1073
来自专栏生信技能树

如何通过Google来使用ggplot2可视化

今天是大年初二,这篇文章我只想传达一点: 没有什么菜鸟级别的生物信息学数据处理是不能通过Google得到解决方案的,如果有,请换个关键词继续Google! 第一...

3328
来自专栏生信小驿站

生存分析①R语言

生存分析(Survival analysis)是指根据试验或调查得到的数据对生物或人的生存时间进行分析和推断,研究生存时间和结局与众多影响因素间关系及其程度大小...

2514
来自专栏Python小屋

Python计算电场中两点间的电势差

根据组合数定义,需要计算3个数的阶乘,在很多编程语言中都很难直接使用整型变量表示大数的阶乘结果,虽然Python并不存在这个问题,但是计算大数的阶乘仍需要相当多...

961
来自专栏PPV课数据科学社区

【学习】如何用SPSS和Clementine处理缺失值、离群值、极值?

一、什么是预处理、预分析? 高质量数据是数据分析的前提和分析结论可靠性的保障。尽管在获取数据源时数据分析师格外谨慎,耗费大量的时间,但数据质量仍然需持续关注。不...

1.1K5

扫码关注云+社区

领取腾讯云代金券