转载:http://blog.csdn.net/hgl868/article/details/7872350

引言

在OpenGL中有三种类型的光:方向光(directional)、点光(point)、聚光(spotlight)。本教程将从方向光讲起,首先我们将使用GLSL来模仿OpenGL中的光。

我们将向shader中逐渐添加环境光、散射光和高光效果。

后面的教程中我们将使用逐像素光照以获得更好的效果。

接下来我们将实现逐像素的点光和聚光。这些内容与方向光很相近,大部分代码都是通用的。

在卡通着色的教程中我们接触过在GLSL中如何访问OpenGL状态中关于光源的部分,这些数据描述了每个光源的参数。

struct
gl_LightSourceParameters  
    {
 
       
vec4 ambient;  
       
vec4 diffuse;  
       
vec4 specular;  
       
vec4 position;  
       
vec4 halfVector;  
       
vec3 spotDirection;  
       
float spotExponent;  
       
float spotCutoff; // (range: [0.0,90.0], 180.0)
 
       
float spotCosCutoff; // (range: [1.0,0.0],-1.0)
 
       
float constantAttenuation;  
       
float linearAttenuation;  
       
float quadraticAttenuation;  
    };
 
    
 
    uniform
gl_LightSourceParameters gl_LightSource[gl_MaxLights];
 
    struct
gl_LightModelParameters  
    {
 
       
vec4 ambient;  
    };
 
    uniform
gl_LightModelParameters
gl_LightModel;  
在GLSL中也同样可以访问材质参数:

struct
gl_MaterialParameters  
    {
 
       
vec4 emission;  
       
vec4 ambient;  
       
vec4 diffuse;  
       
vec4 specular;  
       
float shininess;  
    };
 
    
 
    uniform
gl_MaterialParameters gl_FrontMaterial;  
    uniform
gl_MaterialParameters
gl_BackMaterial;

在OpenGL程序中,这些参数中的大部分,不论属于光源还是材质,用起来都是相似的。我们将使用这些参数实现自己的方向光。

方向光I
本节的公式来自《OpenGL编程指南》中“和光照有关的数学知识”这一章。
我们从散射光开始讨论。在OpenGL中假定,不管观察者的角度如何,得到的散射光强度总是相同的。散射光的强度与光源中散射光成分以及材质中散射光反射系数相关,此外也和入射光角度与物体表面法线的夹角相关。

OpenGL用下面的公式计算散射光成分:

I是反射光的强度,Ld是光源的散射成分(gl_LightSource[0].diffuse),Md是材质的散射系数(gl_FrontMaterial.diffuse)。

这个公式就是Lambert漫反射模型。Lambert余弦定律描述了平面散射光的亮度,正比于平面法线与入射光线夹角的余弦,这一理论提出已经超过200年了。

在顶点shader中要实现这个公式,需要用到光源参数中的方向、散射成分强度,还要用到材质中的散射成分值。因此使用此shader时,在OpenGL中需要像在平时一样设置好光源。注意:由于没有使用固定功能流水线,所以不需要对光源调用glEnable。

要计算余弦值,首先要确保光线方向向量(gl_LightSource[0].position)与法线向量都是归一化的,然后就可以使用点积得到余弦值。注意:对方向光,OpenGL中保存的方向是从顶点指向光源,与上面图中画的相反。

OpenGL将光源的方向保存在视点空间坐标系内,因此我们需要把法线也变换到视点空间。完成这个变换可以用预先定义的一致变量gl_NormalMatrix。这个矩阵是模型视图变换矩阵的左上3×3子矩阵的逆矩阵的转置。

以下就是上述内容的顶点shader代码:

void main()
 
    {
 
       
vec3 normal, lightDir;  
       
vec4 diffuse;  
       
float NdotL;  
    
 
       
 
       
normal = normalize(gl_NormalMatrix * gl_Normal);
 
       
 
       
lightDir = normalize(vec3(gl_LightSource[0].position));
 
       
 
       
NdotL = max(dot(normal, lightDir), 0.0);  
       
 
       
diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
 
       
gl_FrontColor =  NdotL * diffuse;
 
    
 
       
gl_Position = ftransform();  
   
}  
在片断shader中要做的就是使用易变变量gl_Color设置颜色。

void main()
 
    {
 
       
gl_FragColor = gl_Color;  
   
}  
下图显示了应用此shader的茶壶效果。注意茶壶的底部非常黑,这是因为还没有使用环境光的缘故。

加入环境光非常容易,只需要使用一个全局的环境光参数以及光源的环境光参数即可,公式如下所示:

前面的顶点shader中需要加入几条语句完成环境光的计算:

void main()
 
    {
 
       
vec3 normal, lightDir;  
       
vec4 diffuse, ambient, globalAmbient;  
       
float NdotL;  
    
 
       
normal = normalize(gl_NormalMatrix * gl_Normal);
 
       
lightDir = normalize(vec3(gl_LightSource[0].position));
 
       
NdotL = max(dot(normal, lightDir), 0.0);  
       
diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
 
       
 
       
ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;
 
       
globalAmbient = gl_FrontMaterial.ambient * gl_LightModel.ambient;
 
       
gl_FrontColor =  NdotL * diffuse + globalAmbient +
ambient;  
    
 
       
gl_Position = ftransform();  
   
}  
下图显示了最终效果。加入环境光后整个画面都变亮了,不过相对于应用了反射光效果的全局光照模型(global illumination
model),这种计算环境光的方式只能算廉价的解决方案。

方向光II
下面介绍OpenGL方向光中的镜面反射部分。我们使用称为Blin-Phong模型的光照模型,这是Phong模型的简化版。在这之前,我们有必要先看看Phong模型,以便于更好地理解Blin-Phong模型。

在Phong模型中,镜面反射成分和反射光线与视线夹角的余弦相关,如下图:

L表示入射光,N表示法线,Eye表示从顶点指向观察点的视线,R是L经镜面反射后的结果,镜面反射成分与α角的余弦相关。

如果视线正好和反射光重合,我们将接收到最大的反射强度。当视线与反射光相分离时,反射强度将随之下降,下降速率可以由一个称为shininess的因子
控制,shininess的值越大,下降速率越快。也就是说,shininess越大的话,镜面反射产生的亮点就越小。在OpenGL中这个值的范围是0
到128。

计算反射光向量的公式:

OpenGL中使用Phong模型计算镜面反射成分的公式:

式中指数s就是shininess因子,Ls是光源中镜面反射强度,Ms是材质中的镜面反射系数。

Blinn提出了一种简化的模型,也就是Blinn-Phong模型。它基于半向量(half-vector),也就是方向处在观察向量以及光线向量之间的一个向量:

现在可以利用半向量和法线之间夹角的余弦来计算镜面反射成分。OpenGL所使用的Blinn-Phong模型计算镜面反射的公式如下:

这个方法与显卡的固定流水线中使用的方法相同。因为我们要模拟OpenGL中的方

GLSL逐顶点光照[转]的更多相关文章

  1. GLSL逐像素光照 【转】

    转载:http://blog.csdn.net/hgl868/article/details/7872414 逐像素的方向光(Directional Light per Pixel) 这一节将把前面的 ...

  2. [Unity Shader] 逐顶点光照和逐片元漫反射光照

    书中的6.4节讲的是漫反射的逐顶点光照和逐片元光照. 前一种算法是根据漫反射公式计算顶点颜色(顶点着色器),对颜色插值(光栅化过程)返回每个像素的颜色值(片元着色器). 第二种算法是获得顶点的法线(顶 ...

  3. unity shader入门(二)语义,结构体,逐顶点光照

    下为一个逐顶点漫反射光照shader Shader "study/Chapter6/vertexShader"{ Properties{_Diffuse("Diffuse ...

  4. unity shader入门(三)逐像素光照,Blinn-Phong模型

    与上篇逐顶点光照很像,只是改为在片元着色器中计算光照,下为逐像素光照shader Shader "study/Chapter6/PixelShader"{ Properties{ ...

  5. 【GLSL教程】(六)逐顶点的光照 【转】

    引言 在OpenGL中有三种类型的光:方向光(directional).点光(point).聚光(spotlight).本教程将从方向光讲起,首先我们将使用GLSL来模仿OpenGL中的光. 我们将向 ...

  6. Vertex Lit 顶点光照

    http://blog.csdn.net/heyuchang666/article/details/51565102 顶点光照(Vertex Lit) 是最低保真度的光照.不支持实时阴影的渲染路径.最 ...

  7. 翻译:GLSL的顶点位移贴图

    翻译:GLSL的顶点位移贴图 翻译自: Vertex Displacement Mapping using GLSL 译者: FreeBlues 说明: 之所以选择这篇文档, 是因为现在但凡提到位移贴 ...

  8. Unity可编程管线的顶点光照Shader

    UnityCG.cginc有一个叫ShadeVertexLightsFull的函数可以用来计算顶点光照. 源码如下: // Used in Vertex pass: Calculates diffus ...

  9. GLSL 中的光照计算

    理论知识转载地址:http://blog.csdn.net/ym19860303/article/details/25545933 1.Lambert模型(漫反射) 环境光: Iambdiff = K ...

随机推荐

  1. Python-S9-Day116——Flask框架相关

    01 内容回顾 02 Flask框架:路由和视图(一) 03 Flask框架:路由和视图(二) 04 Flask框架:路由和视图(三) 05 Flask框架:路由和视图(四) 06 Flask框架:s ...

  2. 07 JVM 是如何实现反射的

    Java 中的反射 反射是 Java 语言的一个相当重要的特性,它允许正在运行的 Java 程序观测,甚至是修改程序的动态行为. 我们可以通过 Class 对象枚举该类中的所有方法,还可以通过 Met ...

  3. 深入学习之mysql(四)聚合函数

    聚合函数:COUNT统计记录的条数.SUM求和函数.AVG求平均值.MAX求最大值.MIN求最小值   一.COUNT练习: 1.统计学校一共有多少个学生: mysql> SELECT COUN ...

  4. 四则运算UI组结对作业报告

    Github提交地址: 小组成员:陈兆庭,陈昶金: 一.编程阶段 清明节开始接触和调研关于UI设计的方法.由于两人的各方面知识储备均不足,在各种东西C#.MFC.Qt中进行调查和讨论,最终因为网上说Q ...

  5. 玲珑杯”ACM比赛 Round #15

    手速狗从西安回来一只浑浑噩噩,好不容易迎来一场送饭比赛体验一把河南的优势,结果被高中生狂虐,无缘奖金..我的奖品梦就这样一次次被打破.... A -- Reverse the lights 最后半小时 ...

  6. springdata jpa

    (转自:http://www.cnblogs.com/ityouknow/p/5891443.html) 首先了解JPA是什么? JPA(Java Persistence API)是Sun官方提出的J ...

  7. [canvas入坑1]canvas 画布拖拽效果

    查看效果请到 http://philippica.github.io/  点击drag 和上一篇画图很像,所以有些部分做了省略 当鼠标按下时保存当前画布上的内容到ppImgData中,并且记录下初始点 ...

  8. BZOJ1901 Zju2112 Dynamic Rankings 【树状数组套主席树】

    题目 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]--a[j]中第k小的数是多少(1≤k≤j- ...

  9. Codeforces Round #364 (Div. 2) D 数学/公式

    D. As Fast As Possible time limit per test 1 second memory limit per test 256 megabytes input standa ...

  10. APK包与类更改分析

    360APK包与类更改分析 1 题目要求 这是360的全球招募无线攻防中的第二题,题目要求如下: 1)请以重打包的形式将qihootest2.apk的程序包名改为 "com.qihoo.cr ...