WebGL笔记_光(二)

1.光源

1.1点光源

点光源通过位置发射光颜色来定义.

  • 光辐射衰减 : 点光源在空间中传播,会随着光源的的距离进行衰减.

    f ( d ) = 1 a 0 + a 1 d + a 2 d 2 ( )

    如果点光源的位置在无穷远,
    f ( d ) = 1.0 ( , d = )

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

一个方向光通过一个方向向量从该方向开始的角度范围 θ 来确定(类比成光锥).

c o s α = V o b j V l i g h t

V o b j 表示光源到光照对象的单位方向向量.

  • 角强度衰减 :

    f ( ϕ ) = c o s a ϕ ( a > 0 , 0 < ϕ < θ )

    如果光源不是一个投影光源, f ( ϕ ) = 1.0 , 如果对象处于光锥之外, f ( ϕ ) = 0.0

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

  • 对应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 = k d I l c o s θ ( k d , I l , θ , 0 90 )

  • 环境光和点光源同时存在下的漫反射 :

    I a m b , d i f f = k a I a + k d I l ( N L ) ( k a , k d )

    k a k d , 0 1 .

2.2镜面反射

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

非理想反射体系统系统的反射方向分布在向量R周围的有限范围内.较光滑的反射范围比较小,较粗糙的反射范围比较大.Phong Bui Tuong提出了一个计算镜面范围的经验公式,被成为Phong的反射模型.

(Phong) I s p e c = W ( θ ) I l c o s n s ϕ ( V R <= 0 N L <= 0 , I s p e c = 0 )

( W ( θ ) , I l , ϕ V R . N s , )

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

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

(1) I = I d i f f + I s p e c
(2) = k a I a + k d I l ( N L ) + W ( θ ) I l c o s n s ϕ
(3) = k a I a + k d I l ( N L ) + W ( θ ) I l ( N H ) n s

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 ]
(2) = k a I a + i = 0 n I l [ k d ( N L ) + k s ( N H ) n s ]

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

T k .

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

猜你喜欢

转载自blog.csdn.net/xyh930929/article/details/73195087