opengl 不同光源下三种反射光的计算

光源种类

平行光源:如太阳光源,类似于灯源在无穷远处,照射物体的各个地方光照强度相同,光照方向也相同。

点光源:离物体有限距离,且灯光会随着距离衰减,物体表面光照方向不同。

聚光灯:如 手电筒照在一个圆圈上,周围衰减。(这里光照计算暂不介绍)

环境光ambient

上一篇给大家讲了,opengl光照模型得设置 灯源环境光  材质环境光。物体反射的环境光为这两者的乘积, 2种光源计算方法一

vec4 ambientColor=U_LightAmbient*U_AmbientMaterial;

漫反射光diffuse

1、平行光源

     

由图可见,太阳是平行光源,我们的反光照强度与入射光与法向量的夹角有关,因此可以利用向量AB 和 AN的乘积(绿色箭头向量,入射方向的反方向)来表示反射光大小,当然 最小值为0,即没有反射光。

unitform vec4 U_ligthtPos;
uniform vec4 u_diffuseLightColor;
uniform vec4 UdiffuseMaterial;

varying vec4 V_diffuseColor;

void main(){

vec3 L = U_lightPos.xyz;
L = normalize(L);

vec3 n = normalize(mat3(NM)*normal);

float diffuseIntensity = max(0.0 , dot(L,n));

V_diffuseColor = U_diffuseLightColor * UdiffuseMaterial * diffuseIndensity;

}

2、点光源

1、点光源与平行光源不同,它的L向量计算方法不同,是由平面上点 和 灯源位置组成L向量

 

 vec4 specularColor=vec4(0.0,0.0,0.0,0.0);
    if(diffuseIndensity>0.0){
        vec3 reflectDir=normalize(reflect(-L,n));// 反射方向
        vec3 viewDir=normalize(U_CameraPos.xyz-V_WorldPosition.xyz);// 观看方向
        // 计算镜面反射强度
        specularColor=U_LightSpecular*U_SpecularMaterial*pow(max(0.0,dot(viewDir,reflectDir)),32.0);
    }

2、衰减系数 有3个 constantFactor、linearFactor、expFactor这些是常量值,靠经验值来设置,后面2个常量分别与灯光的距离和距离的平方乘积构成衰减系数。

    float attenuation=1.0;
	//light attribute
	float constantFactor=0.5;
	float linearFactor=0.3;
	float expFactor=0.1;
    L=U_LightPos.xyz-V_WorldPos;
	distance=length(L);
	attenuation=1.0/(constantFactor+linearFactor*distance+expFactor*distance*distance);
    L=normalize(L);
	//N vector
	vec3 n=normalize(V_Normal);

	float diffuseIntensity=max(0.0,dot(L,n));
	vec4 diffuseColor=U_DiffuseLightColor*U_DiffuseMaterial*diffuseIntensity*attenuation;

镜面反射

平行光 和 点光源的计算方法除了上面L的计算法方法不一样外,其余的一样。计算方法在下面的blin-phong讲到了,就是反射光向量与点和眼睛的向量乘积作为底数,32为常量设置。见blin的图像 AC 和 AD的乘积

反射光线的向量利用reflect函数来计算得到,参数为入射光的方向向量 和 法向量 (都归一化了)。

// 计算镜面反射
    vec4 specularColor=vec4(0.0,0.0,0.0,0.0);
    if(diffuseIndensity>0.0){
        vec3 reflectDir=normalize(reflect(-L,n));// 反射方向
        vec3 viewDir=normalize(U_CameraPos.xyz-V_WorldPosition.xyz);// 观看方向
        // 计算镜面反射强度 第二个参数32 一般是2的指数次
         float specularColorIndensity=pow(max(0.0,dot(viewDir,reflectDir)),32.0);
        specularColor=U_LightSpecular*U_SpecularMaterial*specularColorIndensity;
    }

reflect 计算反射向量复杂度比较高,blin-phong模型就是针对这里进行的一个简化计算。

blin-phong

该模型主要是针对求镜面反射光线向量来简化,如下图

蓝色D为眼睛的位置,然后镜面反射的强度为 反射光纤 与 眼睛和点A的夹角来表示,越小强度越大,因此用向量AD与AC的乘机表示,但反射角计算量大,这里利用 AB 与 AN的和 计算得到 中间的AE, 用 AE乘以AN来代替 AC乘以AD。attenuation为衰减系数,跟上面的点光源的attenuation是一样的。

//reflection
	vec3 halfVector=L+viewDir;
	halfVector=normalize(halfVector);

    specularIntensity=pow(max(0.0,dot(n,halfVector)),128.0);
  vec4 specularColor=U_SpecularLightColor*U_SpecularMaterial*specularIntensity*attenuation;

这里给出一个完整的iblind-phone shader的模型,其中利用U_LightPos.w==0.0 来判断是否为平行光还是点光源的。



uniform vec4 U_LightPos;
uniform vec3 U_EyePos;
uniform vec4 U_AmbientLightColor;
uniform vec4 U_AmbientMaterial;
uniform vec4 U_DiffuseLightColor;
uniform vec4 U_DiffuseMaterial;
uniform vec4 U_SpecularLightColor;
uniform vec4 U_SpecularMaterial;

varying vec3 V_Normal;
varying vec3 V_WorldPos;

void main()
{
	//ambient
	vec4 ambientColor=U_AmbientLightColor*U_AmbientMaterial;

	//diffuse
	//L vector
	vec3 L=vec3(0.0);
	float distance=0.0;
	float attenuation=1.0;
	//light attribute
	float constantFactor=0.5;
	float linearFactor=0.3;
	float expFactor=0.1;

	if(U_LightPos.w==0.0)
	{
		//direction light
		L=U_LightPos.xyz;
	}
	else
	{
		//model point -> light pos
		//point light / spot light
		L=U_LightPos.xyz-V_WorldPos;
		distance=length(L);
		attenuation=1.0/(constantFactor+linearFactor*distance+expFactor*distance*distance);
	}
	L=normalize(L);
	//N vector
	vec3 n=normalize(V_Normal);

	float diffuseIntensity=max(0.0,dot(L,n));
	vec4 diffuseColor=U_DiffuseLightColor*U_DiffuseMaterial*diffuseIntensity*attenuation;

	
	//specular
	//inverse view direction : object->eye
	vec3 viewDir=U_EyePos-V_WorldPos;
	viewDir=normalize(viewDir);

	//reflection
	vec3 halfVector=L+viewDir;
	halfVector=normalize(halfVector);

	float specularIntensity=0.0;
	if(diffuseIntensity==0.0)
	{
		specularIntensity=0.0;
	}
	else
	{
		//shiness
		specularIntensity=pow(max(0.0,dot(n,halfVector)),128.0);
	}

	vec4 specularColor=U_SpecularLightColor*U_SpecularMaterial*specularIntensity*attenuation;

	gl_FragColor=ambientColor+diffuseColor+specularColor;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值