基础光照模型公式与源码【GLSL】
2016-07-20 19:20
471 查看
ADS 光照模型:
Ambient lignt (light that is always present at all points in a scene)Diffuse light (light that comes directly from a light source)
Specular light (light that is reflected in a "shiny" way from a light source by an object)
The setup for ADS (Ambient Diffuse Specular) lighting.
E:表示物体表面上一点到相机的单位向量
L:表示物体表面上一点到光源的单位向量
N:表示物体表面上一点的单位法线向量
R:表示物体表面上一点相对光源的反射单位向量
Ambient light 由 ambient light 自身 LA 和 材质被照的ambient light color MA 的乘积计算得到:
A = LA * MA
Diffuse light 由 diffuse light 自身 LD 和材质被照的 diffuse light color MD ,以及光线和法线夹角的cosin 的乘积计算得到:
D = LD * MD * (L dot N)
Specular light 由 specular light 自身 LS 和材质被照的 specular light color MS ,以及反射光线和视线夹角的cosin 的SH次幂的乘积计算得到:
S = LS * MS * (R dot E)^SH
R = 2*(N dot L)*N - L (注意图中L的方向与GLSL中的reflect相反)
最后物体表面上某点的光照为 A + D + S 。
ADS光照模型源码:
vec3 ADSLightModel(in vec3 myNormal, in vec3 myVertexPosition) { const vec3 myLightPosition = vec3(5., 5., 10.); const vec3 myLightAmbient = vec3(.2, .2, .2); const vec3 myLightDiffuse = vec3(1., 1., 1.); const vec3 myLightSpecular = vec3(1., 1., 1.); const vec3 myMaterialAmbient = vec3(1., .5, .0); const vec3 myMaterialDiffuse = vec3(1., .5, .0); const vec3 myMaterialSpecular = vec3(.6, .6, .6);; const float myMaterialShininess = 80.; // normal, light, view, and light reflection vectors vec3 norm = normalize(myNormal); vec3 lightv = normalize(myLightPosition - myVerexPosition); vec3 viewv = normalize(vec3(0., 0., 0.) - myVertexPosition);<span style="white-space:pre"> </span>// EyePosition = vec3(0, 0, 0) vec3 refl = reflect(vec3(0., 0., 0.) - lightv, norm); // ambient light computation vec3 ambient = myMaterialAmbient*myLightAmbient; // diffuse light computation vec3 diffuse = max(0., dot(lightv, norm)) * myMaterialDiffuse * myLightDiffuse; // Optionally you can add a diffuse attenuation term at this point // specular light computation vec3 specular = vec3(0., 0., 0.); if(dot(lightv, viewv)>0.) { specular = pow(max(0., dot(viewv, refl)), myMaterialShininess) * myMaterialSpecular * myLightSpecular; } return clamp(ambient + diffuse + specular, 0., 1.); }
如果考虑物体随着距离光源的远近进行衰减的情况
那么AT = 1 / (AC + AL*D + AQ*D^2)(其中AC表示常数衰减系数,AL表示线性衰减系数, AQ表示二次衰减系数,D表示eye space中物体某点到光源的距离)
然后,将AT乘上之前计算出的 diffuse 和 specular 即可。
如果光源是Spot light的类型
就既要考虑距离光源的距离,还要考虑视线和光源所成的角度的cosin,即dot(L, E),接着通过已知spot light的cos(angle),以及衰减范围,利用smoothstep进行插值即可。Phong 光照模型
其与ADL光照模型的区别是,它是一个逐片元的计算,通过对图元的顶点法线进行插值,并将ADS模型分别运用于每一个像素上。而且,它不再计算的单位反射向量,而是通过“half angle”——the vector H halfway between the light L and the eye E vectors(GLSL 通过 normalize(L + E) 计算),以及H和N的cosin来计算specular light。
S = LS * MS * (N dot H)^SH
两种不同计算方式的效果差别:左图为“half angle”右图为"full angle"
FULL ANGLE:
Vertex Shader:uniform vec3 fvLightPosition; uniform vec3 fvEyePosition; varying vec2 Texcoord; varying vec3 ViewDirection; varying vec3 LightDirection; varying vec3 Normal; void main( void ) { gl_Position = ftransform(); Texcoord = gl_MultiTexCoord0.xy; vec4 fvObjectPosition = gl_ModelViewMatrix * gl_Vertex; ViewDirection = fvEyePosition - fvObjectPosition.xyz; LightDirection = fvLightPosition - fvObjectPosition.xyz; Normal = gl_NormalMatrix * gl_Normal; }
注:gl_NormalMatrix 为 gl_ModelViewMatrix 的逆转置矩阵,用于将gl_Normal从模型空间转换到视图空间
Fragment Shader:
uniform vec4 fvAmbient; uniform vec4 fvSpecular; uniform vec4 fvDiffuse; uniform float fSpecularPower; uniform sampler2D baseMap; varying vec2 Texcoord; varying vec3 ViewDirection; varying vec3 LightDirection; varying vec3 Normal; void main( void ) { vec3 fvLightDirection = normalize( LightDirection ); vec3 fvNormal = normalize( Normal ); float fNDotL = dot( fvNormal, fvLightDirection ); vec3 fvReflection = normalize( ( ( 2.0 * fvNormal ) * fNDotL ) - fvLightDirection ); vec3 fvViewDirection = normalize( ViewDirection ); float fRDotV = max( 0.0, dot( fvReflection, fvViewDirection ) ); vec4 fvBaseColor = texture2D( baseMap, Texcoord ); vec4 fvTotalAmbient = fvAmbient * fvBaseColor; vec4 fvTotalDiffuse = fvDiffuse * fNDotL * fvBaseColor; vec4 fvTotalSpecular = fvSpecular * ( pow( fRDotV, fSpecularPower ) ); gl_FragColor = ( fvTotalAmbient + fvTotalDiffuse + fvTotalSpecular );
HALF ANGLE:
Fragment Shader:uniform vec4 fvAmbient; uniform vec4 fvSpecular; uniform vec4 fvDiffuse; uniform float fSpecularPower; uniform sampler2D baseMap; varying vec2 Texcoord; varying vec3 ViewDirection; varying vec3 LightDirection; varying vec3 Normal; void main( void ) { vec3 fvLightDirection = normalize( LightDirection ); vec3 fvNormal = normalize( Normal ); float fNDotL = dot( fvNormal, fvLightDirection ); vec3 fvReflection = normalize( ( ( 2.0 * fvNormal ) * fNDotL ) - fvLightDirection ); vec3 fvViewDirection = normalize( ViewDirection ); // ----------------------- vec3 fvHalf = normalize(fvLightDirection + fvViewDirection); // ----------------------- vec4 fvBaseColor = texture2D( baseMap, Texcoord ); vec4 fvTotalAmbient = fvAmbient * fvBaseColor; vec4 fvTotalDiffuse = fvDiffuse * fNDotL * fvBaseColor; // ----------------------- float fNDotH = max(0.0, dot(fvNormal, fvHalf)); vec4 fvTotalSpecular = fvSpecular * (pow(fNDotH, fSpecularPower)); // ----------------------- gl_FragColor = ( fvTotalAmbient + fvTotalDiffuse + fvTotalSpecular ); }
Anisotropic 光照模型
该模型也是逐片元计算的,但是它在物体表面的specular 在所有方向不是均匀变化的,所以,它的specular 公式改为了以下形式:dl = T dot L
de = T dot E
S = LS * MS * (dl * de + (1-dl*dl)^1/2 * (1-de*de)^1/2)^SH
其中,T表示tangent vector,即direction of the brushing or hair
Anisotroipc光照模型的效果
Vertex Shader:
uniform mat4 view_proj_matrix; attribute vec3 rm_Binormal; attribute vec3 rm_Tangent; varying vec3 vNormal; varying vec3 vTangent; varying vec3 vBinormal; varying vec3 vViewVec; varying vec3 vPos; void main(void) { gl_Position = ftransform(); // 从模型空间(不是切向空间)转换到视图空间 vTangent = gl_NormalMatrix * rm_Tangent; vNormal = gl_NormalMatrix * gl_Normal; vBinormal = gl_NormalMatrix * rm_Binormal; vViewVec.xyz = vec3( gl_ModelViewMatrix * gl_Vertex ); // OpenGL has a different handedness, so we need to flip the z. vViewVec.z = -vViewVec.z; //vPos = gl_Vertex.xyz * noiseRate; vPos = gl_Vertex.xyz; }
Fragment Shader:
uniform vec4 lightDir; uniform vec4 gloss; uniform vec4 color; uniform float noiseScale; varying vec3 vNormal; varying vec3 vTangent; varying vec3 vBinormal; varying vec3 vViewVec; varying vec3 vPos; void main(void) { vec3 viewVec = normalize(vViewVec); vec3 oglLightDir = vec3(lightDir.x, lightDir.y, -lightDir.z); float diffuse = clamp( dot( oglLightDir.xyz, vNormal ), 0.0, 1.0 ); float angle = 0.2 * 3.14159; float cosA, sinA; sinA = sin(angle); cosA = cos(angle); // 绕着法线方向旋转A弧度后的新切线方向, // 可以设想为vBinormal为x轴,vTangent为y轴,vNormal为z轴 vec3 tang = sinA * vTangent + cosA * vBinormal; float de = -dot(viewVec, tang); float sn = sqrt(1.0 - de * de); float dl = dot(oglLightDir.xyz, tang); float sl = sqrt(1.0 - dl * dl); float specular = pow( clamp( (de * dl + sn * sl), 0.0, 1.0 ), 32.0); gl_FragColor = diffuse * color + gloss * specular; }
相关文章推荐
- 解决Vista系统OpenGL驱动问题的方法整理
- Delphi下OpenGL2d绘图之画四边形的方法
- Delphi下OpenGL2d绘图之画点的方法
- Delphi下OpenGL2d绘图之初始化流程详解
- Delphi使用OpenGL2d绘图之画图片Bmp的方法
- 通过OpenGL ES混合模式缩放视频缓冲区来适应显示尺寸
- VC运用OPENGL加载BMP纹理图的实现方法汇总
- java实现OpenGL ES纹理映射的方法
- java基于OpenGL ES实现渲染实例
- android调用GLES20.glGenerateMipmap报错glError 1280
- OpenGL坐标系介绍
- 【翻译】安卓opengl ES教程之四——添加颜色
- linux下opengl的安装(with qt)
- OpenGL超级宝典笔记——显示列表
- OpenGL超级宝典笔记——顶点数组
- OpenGL生成轮廓
- OpenGL超级宝典笔记——性能比较
- OpenGL超级宝典笔记——顶点缓冲区对象
- OpenGL超级宝典笔记——选择
- OpenGL超级宝典笔记——反馈