Opengl es光照

1. OpenGL 里面的光照基本由   环境光、散射光、镜面光。

    其中涉及的基本公式如下:

   A.环境光:  

     环境光照射结果 = 材质的反射系数 X 环境光强度

    例如:  

        

   vAmbient = vec4(0.5,0.5,0.5,0);

         gl_FragColor=finalColor*vAmbient;

  

   B. 散射光:

     上面介绍的环境光是没有位置概念的。但是散射光有位置。

      散射光代表的是显示世界中粗糙的物体表面被光照射时,反射光在各个方向上基本均匀(也称漫反射),

      当光源的位置发生变化时,散射光的效果会发生明显变化。主要体现为当光垂直照射物体表面比斜照时要亮。

      公式为:

          散射光照射结果 = 材质的反射系数 X 散射光强度 X max(cos(入射角),0);

          实际开发中,一般分为两步计算,

                散射光最终强度 = 散射光强度 X max(cos(入射角),0);

                散射光照射结果 = 材质的反射系数 X 散射光最终强度;

                例如:在顶点着色器里面,对球面上的点进行计算散射光可以如下:

               

void pointLight (								//散射光光照计算的方法
  in vec3 normal,								//法向量
  inout vec4 diffuse,								//散射光计算结果
  in vec3 lightLocation,							//光源位置
  in vec4 lightDiffuse							//散射光强度
){  

vec4 realp = uMMatrix * vec4(aPosition,1);

vec4 pl = vec4(lightLocation,1) - realp;

vec4 normalizepl = normalize(pl);
vec4 normalizenor = normalize(vec4(normal,1));

float nd  = max(0.0,dot(normalizepl,normalizenor));

diffuse = lightDiffuse * nd;

}

  C.镜面光:

        现实生活中,当光滑的表面被照射时,会有方向很集中的发射光,这就是镜面光.

        其中,镜面光 不仅依赖光源的位置,还依赖观察者的位置。如果从摄像机到被照射点的向量不在反射光方向集中的范围内,观察者将不会看到镜面光。

        具体公式为:

             镜面光照射结果 = 材质的反射系数 X 镜面光强度 X max(0,(cos(半向量与法向量的夹角))粗糙度);

            实际开发中,一般分两步进行计算:

                镜面光最终强度 = 镜面光强度 X max(0,(cos(半向量与法向量的夹角))粗糙度);

               镜面光照射结果  = 材质的反射系数 X  镜面光最终强度;

         其中,半向量指的是 从被照射点到光源的向量 与 被照射点与观察点 向量的平均向量 。

         例如:

         

void pointLight(				//定位光光照计算的方法
  in vec3 normal,			//法向量
  inout vec4 specular,		//镜面反射光分量  
  in vec3 lightLocation,		//光源位置
  in vec4 lightSpecular		//镜面光强度
){ 

	vec4 realp = uMMatrix * vec4(aPosition,1);
	
	vec4 pl = vec4(lightLocation,1) - realp;

	vec4 pv = vec4(uCamera,1) - realp;
	
	vec4 normalize_pl = normalize(pl);
	vec4 normalize_pv = normalize(pv);
	
	vec4 halfv = normalize_pl + normalize_pv;
	vec4 normalize_halfv = normalize(halfv);
	
	//粗糙度,越小越光滑 
	float shininess=50.0;	
	
//	vec3 nn = normalize(aNormal);
//	vec4 normalize_nor = vec4(nn,1);
	
	// 需要注意向量和点
	vec4 normalize_nor = normalize(vec4(aNormal,0));
	
	float nDotViewHalfVector = dot(normalize_nor , normalize_halfv);
	
	float 	powerFactor = max(0.0,pow(nDotViewHalfVector,shininess));  
	
	specular=lightSpecular*powerFactor;    //最终的镜面光强度

}

---------------------------------------

 

如果将三种光合成起来,就是:

gl_FragColor=finalColor*vAmbient + finalColor*vDiffuse + finalColor*vSpecular;

  

2.定位光与定向光

   上面介绍的  散射光  和 镜面光都是属于定位光,光源有固定的位置, 但是现实生活中的阳光,则是平行光,即场景中不同位置的物体反映出的光照效果完全一致。

    象太阳这样的光,就是定向光,与光源位置无关,只与方向有关.

void directionalLight(			//定向光光照计算的方法
  in vec3 normal,				//法向量
  inout vec4 ambient,			//环境光最终强度
  inout vec4 diffuse,				//散射光最终强度
  inout vec4 specular,			//镜面光最终强度
  in vec3 lightDirection,			//定向光方向
  in vec4 lightAmbient,			//环境光强度
  in vec4 lightDiffuse,			//散射光强度
  in vec4 lightSpecular			//镜面光强度
){
  ambient=lightAmbient;			//直接得出环境光的最终强度  
  
  vec3 normalTarget=aPosition+normal;	//计算变换后的法向量
  
  vec3 newNormal=(uMMatrix*vec4(normalTarget,1)).xyz-(uMMatrix*vec4(aPosition,1)).xyz;
  
  newNormal=normalize(newNormal); 	//对法向量规格化
  
  //计算从表面点到摄像机的向量
  vec3 eye= normalize(uCamera-(uMMatrix*vec4(aPosition,1)).xyz); 
     
  vec3 vp= normalize(lightDirection);  //规格化定向光方向向量
  
  vec3 halfVector=normalize(vp+eye);	//求视线与光线的半向量    
  
  float shininess=50.0;				//粗糙度,越小越光滑
  
  float nDotViewPosition=max(0.0,dot(newNormal,vp)); 	//求法向量与vp的点积与0的最大值
  
  diffuse=lightDiffuse*nDotViewPosition;				//计算散射光的最终强度
  
  float nDotViewHalfVector=dot(newNormal,halfVector);	//法线与半向量的点积 
  
  float powerFactor=max(0.0,pow(nDotViewHalfVector,shininess)); 	//镜面反射光强度因子
  
  specular=lightSpecular*powerFactor;    			//计算镜面光的最终强度
}

  对于上面需要说明的是,   对于定向光的计算 和 定位光的计算类似,只需将定位光的位置,换成 定向光的方向,由于定向光方向一定,所以不需要和被照射点计算。直接将方向规格化即可。

      对于定向光,也是包含 环境光、散射光、镜面光三个通道。计算方式类似。

 

   注意:以上的计算都是在顶点着色器里面进行计算的光照,如果想要更加细腻的效果,可以将其在片元着色器里面进行计算。

 

            

       

 

posted @ 2013-10-31 23:43  Dai Hanlong  阅读(447)  评论(0)    收藏  举报