WebGL笔记(二)_光

1.光源

1.1点光源
点光源通过 位置发射光颜色来定义。
  • 光辐射衰减 : 点光源在空间中传播,会随着光源的的距离进行衰减.
    f ( d ) = 1 a 0 + a 1 d + a 2 d 2 ( 局 部 光 辐 射 衰 减 公 式 ) f(d)=\frac{1}{a_0+a_1d+a_2d^2} (局部光辐射衰减公式) f(d)=a0+a1d+a2d21()
    如果点光源的位置在无穷远, f ( d ) = 1.0 ( 如 果 光 在 无 穷 远 位 置 , d = 正 无 穷 ) f(d) = 1.0 (如果光在无穷远位置,d=正无穷) f(d)=1.0(,d=)

  • 解释 : 实际上光源的距离为d时,它的振幅将按照因子 1 / d 2 1/d^2 1/d2进行衰减,但是对于接近光源的对象, 1 / d 2 1/d^2 1/d2会产生过大的强度变化,而d很大时变化又太小,造成这样的原因是实际的光源并不是无穷小的点,而是用点发光体照明一个场景是真实光照效果的简单近似.所以加上 a 0 , a 1 , a 2 三 个 参 数 a_0,a_1,a_2三个参数 a0,a1,a2,使用者可以通过调整这三个系数的值,以得到场景中不同的光照效果,例如,当d非常小的时候,可以赋予 a 0 a_0 a0一个大的值来防止 f ( d ) f(d) f(d)变得很大.

对应WebGl和Three.js里面的光 :

1 . 光的距离在无穷远时,d=正无穷时,对应WebGL里面的平行光, 对应Three.js里面的方向光

  • WebGL里需要给着色器传两个矢量,光色和光方向 : uniform vec3 u_LightCorlor和 uniform vec3 u_LightDirection.
  • Three.js里面定义方向光的构造器DirectionalLight( color, intensity ).
//Three.js定义方向光的WebGL源码.
var uniforms = lightCache.get( light );

uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
uniforms.direction.setFromMatrixPosition( light.matrixWorld );
_vector3.setFromMatrixPosition( light.target.matrixWorld );
uniforms.direction.sub( _vector3 );
uniforms.direction.transformDirection( viewMatrix );

2.光的位置在局部时,对应WebGL和Three.js里面的点光源.

  • WebGL编程指南并没有关于点光源定义的着色器代码.
  • Three.js里面定义点光源的构造器PointLight( color, intensity, distance, decay ).
//Three.js定义点光源的WebGL源码.
var uniforms = lightCache.get( light );

uniforms.position.setFromMatrixPosition( light.matrixWorld );
uniforms.position.applyMatrix4( viewMatrix );
uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
uniforms.distance = light.distance;
uniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay;
1.2方向光
一个方向光通过一个*方向向量*和*从该方向开始的角度范围$\theta$*来确定(类比成光锥). $$cos\alpha= V_{obj}• V_{light}$$ $V_{obj}$表示光源到光照对象的单位方向向量.
  • 角强度衰减 :
    f ( ϕ ) = c o s a ϕ ( a &gt; 0 , 0 &lt; ϕ &lt; θ ) f(\phi)=cos^{a}\phi(a&gt;0,0&lt;\phi&lt;\theta) f(ϕ)=cosaϕ(a>0,0<ϕ<θ)
    如果光源不是一个投影光源, f ( ϕ ) = 1.0 , f(\phi)=1.0, f(ϕ)=1.0,如果对象处于光锥之外, f ( ϕ ) = 0.0 f(\phi)=0.0 f(ϕ)=0.0

  • 解释 :衰减指数a是某个正值, ϕ \phi ϕ指圆锥轴到圆锥表面之间的夹角范围内的某个角度值.

  • 对应Three.js里面的聚光灯 :

  1. Three.js里面定义聚光灯的构造函数:SpotLight( color, intensity, distance, angle, penumbra, decay )
//Three.js定义聚光灯的源码.

var uniforms = lightCache.get( light );

uniforms.position.setFromMatrixPosition( light.matrixWorld );
uniforms.position.applyMatrix4( viewMatrix );

uniforms.color.copy( color ).multiplyScalar( intensity );

uniforms.distance = distance;

uniforms.direction.setFromMatrixPosition( light.matrixWorld );
_vector3.setFromMatrixPosition( light.target.matrixWorld );
uniforms.direction.sub( _vector3 );
uniforms.direction.transformDirection( viewMatrix );

uniforms.coneCos = Math.cos( light.angle );

uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );
uniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay;

1.3环境光
通过设定场景的亮度来定义环境光.所有对象都相同的一个环境光,并且近似的给出了各个光照表面的全局漫反射.

Three.js定义环境光的构造函数 : AmbientLight( color, intensity )

//Three.js里面定义环境光的源码.
r += color.r * intensity;
g += color.g * intensity;
b += color.b * intensity;
1.4Three.js里面的其他光
  • 半球光:构造函数HemisphereLight( skyColor, groundColor, intensity )
//Three.js里面定义半球光的源码
var uniforms = lightCache.get( light );

uniforms.direction.setFromMatrixPosition( light.matrixWorld );
uniforms.direction.transformDirection( viewMatrix );
uniforms.direction.normalize();

uniforms.skyColor.copy( light.color ).multiplyScalar( intensity );
uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity ); 
  • 长方形面光:构造函数RectAreaLight( color, intensity, width, height )
var uniforms = lightCache.get( light );
uniforms.color.copy( color ).multiplyScalar( intensity / ( light.width * light.height ) );
uniforms.position.setFromMatrixPosition( light.matrixWorld );
uniforms.position.applyMatrix4( viewMatrix );

_matrix42.identity();
_matrix4.copy( light.matrixWorld );
_matrix4.premultiply( viewMatrix );
_matrix42.extractRotation( _matrix4 );

uniforms.halfWidth.set( light.width * 0.5,0.0, 0.0 );
uniforms.halfHeight.set(0.0, light.height * 0.5, 0.0 );
uniforms.halfWidth.applyMatrix4( _matrix42 );
uniforms.halfHeight.applyMatrix4( _matrix42 );

2.对象表面光照效果

  • 物体的光学特性是影响光照效果的主要因素,这些特性包括透明度,颜色反射系数,表面纹理参数.
2.1漫反射
粗糙或颗粒状表面会将反射光向各个方向发散出去,这样的反射称为 漫反射.
  • 理想漫反射体 :假设入射光在各个方向以相同的强度发散而与观察者的位置无关 . 理想漫反射体表面上反射光能量由朗伯余弦定律来计算.因此也被称为朗伯反射体.对于朗伯反射,光强度在所有观察方向都相同.

如果每一个表面都按照理想漫反射体来对待,不同的光源在漫反射下的反射光强度如下:

  • 环境光下的漫反射 :
    I a m b = k d I a ( k d 为 漫 反 射 系 数 , I a 为 环 境 光 强 度 ) I_{amb}=k_dI_a(k_d为漫反射系数,I_a为环境光强度) Iamb=kdIa(kd,Ia)

  • 点光源下的漫反射 :
    I = k d I l c o s θ ( k d 为 漫 反 射 系 数 , I l 为 入 射 光 强 度 , θ 是 入 射 光 与 平 面 法 向 量 夹 角 , 必 须 在 0 − 90 度 之 间 才 会 有 效 果 ) I=k_dI_lcos\theta(k_d为漫反射系数,I_l为入射光强度,\theta是入射光与平面法向量夹角,必须在0-90度之间才会有效果) I=kdIlcosθ(kd,Il,θ,090)

  • 环境光和点光源同时存在下的漫反射 :
    I a m b , d i f f = k a I a + k d I l ( N • L ) ( k a 是 环 境 光 反 射 系 数 , k d 是 漫 反 射 系 数 ) I_{amb,diff}=k_aI_a+k_dI_l(N• L)(k_a是环境光反射系数,k_d是漫反射系数) Iamb,diff=kaIa+kdIl(NL)(ka,kd)
    k a 和 k d 都 由 表 面 的 材 质 决 定 , 对 于 单 色 光 而 言 其 值 都 介 于 0 到 1 之 间 . k_a和k_d都由表面的材质决定,对于单色光而言其值都介于0到1之间. kakd,01.

2.2镜面反射
反射光集中成醒目或明亮的一个点,成为**镜面反射**.假设现有一表面,法向量是N,L表示光源方向,R表示反射光方向,V表示视点方向,L与N的夹角=R与N的夹角=$\theta,$R与V的夹角是$\phi$.*理想的镜面反射材料*只有当$\theta=\phi$的时候,观察者才能看到反射光 .

非理想反射体系统系统的反射方向分布在向量R周围的有限范围内.较光滑的反射范围比较小,较粗糙的反射范围比较大.Phong Bui Tuong提出了一个计算镜面范围的经验公式,被成为Phong的反射模型.
(Phong) I s p e c = W ( θ ) I l c o s n s ϕ ( V • R &lt; = 0 或 者 N • L &lt; = 0 时 , I s p e c = 0 ) I_{spec}=W(\theta)I_lcos^{n_s}\phi(V• R&lt;=0 或者N• L&lt;=0时,I_{spec}=0)\tag{Phong} Ispec=W(θ)Ilcosnsϕ(VR<=0NL<=0,Ispec=0)(Phong)
( W ( θ ) 表 示 镜 面 反 射 系 数 , I l 表 示 光 源 强 度 , ϕ 表 示 观 察 方 向 V 与 反 射 方 向 R 的 夹 角 . N s 表 示 镜 面 反 射 参 数 , 由 材 料 决 定 ) (W(\theta)表示镜面反射系数,I_l表示光源强度,\phi表示观察方向V与反射方向R的夹角.N_s表示镜面反射参数,由材料决定) (W(θ),Il,ϕVR.Ns,)

简化版的Phong模型可以用N•H代替V•R,H表示L和V的半角向量.

2.3漫反射和镜面反射的合并

(1) I = I d i f f + I s p e c I=I_{diff}+I_{spec}\tag{1} I=Idiff+Ispec(1) (2) = k a I a + k d I l ( N • L ) + W ( θ ) I l c o s n s ϕ =k_aI_a+k_dI_l(N• L)+W(\theta)I_lcos^{n_s}\phi\tag{2} =kaIa+kdIl(NL)+W(θ)Ilcosnsϕ(2) (3) = k a I a + k d I l ( N • L ) + W ( θ ) I l ( N • H ) n s =k_aI_a+k_dI_l(N• L)+W(\theta)I_l(N• H)^{n_s}\tag{3} =kaIa+kdIl(NL)+W(θ)Il(NH)ns(3)

2.4多光源的漫反射和镜面反射的合并

(1) I = I a m b , d i f f + ∑ i = 0 n   [ I l , d i f f + I l , s p e c ] I=I_{amb,diff} +\sum_{i=0}^{n}\ [I_{l,diff}+I_{l,spec}]\tag{1} I=Iamb,diff+i=0n [Il,diff+Il,spec](1) (2) = k a I a + ∑ i = 0 n I l [ k d ( N • L ) + k s ( N • H ) n s ] =k_aI_a+\sum_{i=0}^{n}I_l[k_d(N• L)+k_s(N• H)^{n_s}]\tag{2} =kaIa+i=0nIl[kd(NL)+ks(NH)ns](2)

3.表面绘制算法

Gouraud明暗处理

  • 确定每个多边形顶点处的平均单位法向量.
  • 对于每个顶点根据光照模型来计算其光强度.
  • 在多边形投影区域对顶点强度进行线性插值.

缺点 : 表面上的高光有时会出现异常形状,线性光强度插值会造成表面上出现过亮或过暗的条纹,这被成为马赫带效应.

Phong明暗处理

  • 确定每个多边形顶点处的平均单位法向量.
  • 在多边形投影区域上对顶点法向量进行线性插值.
  • 根据光照模型,使用插值的法向量,沿每条扫描线计算投影像素的光强度.

缺点:需要比Gouraud方法更多的计算.

快速Phong明暗处理
(泰勒展式) I d i f f ( x , y ) = T 5 x 2 + T 4 x y + T 3 y 2 + T 2 x + T 1 y + T 0 I_diff(x,y) = T_5x^2+T_4xy+T_3y^2+T_2x+T_1y+T_0\tag{泰勒展式} Idiff(x,y)=T5x2+T4xy+T3y2+T2x+T1y+T0()
T k 为 光 照 方 向 和 各 个 顶 点 的 光 照 强 度 确 定 的 函 数 . T_k为光照方向和各个顶点的光照强度确定的函数. Tk.

缺点 : 虽然快速Phong的方法减少了Phong表面绘制算法的计算量,但它的计算量仍然相当于Gouraud表面绘制算法的两倍的时间.基本的Phong表面绘制算法比Gouraud绘制多耗时6到7倍.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值