WebGL实践篇(九)—— 光照:点光源

1.点光源的光照值

光照来源于点,太阳也算是一个点光源,光照射到物体的同一面上有明有暗(即光照值不同),将面上的每个点到光源的矢量与法向量点乘得到的值就是光照值。

顶点着色器:

主要添加了光照位置的参数,并将顶点着色器中求出来的光照向量传值给着色器进行渲染。

  <script id="vertex-shader-3D" type="x-shader/x-vertex">
    attribute vec4 a_position;
    attribute vec3 a_normal;

    //光源位置
    uniform vec3 u_lightWorldPosition;

    uniform mat4 u_world;
    uniform mat4 u_worldViewProjection;
    uniform mat4 u_worldInverseTranspose;

    varying vec3 v_normal;

    varying vec3 v_surfaceToLight;

    void main(){
      gl_Position = u_worldViewProjection * a_position;
      v_normal = mat3(u_worldInverseTranspose) * a_normal;

      vec3 surfaceWorldPosition = (u_world * a_position).xyz;
      v_surfaceToLight = u_lightWorldPosition - surfaceWorldPosition;
    }
  </script>

片段着色器(比较重要的就是点乘获取光照值进行渲染): 

  <script id="fragment-shader-3D" type="x-shader/x-fragment">
    precision mediump float;

    varying vec3 v_normal;
    varying vec3 v_surfaceToLight;
    
    uniform vec4 u_color;
    
    void main() {
      vec3 normal = normalize(v_normal);

      vec3 surfaceToLightDirection = normalize(v_surfaceToLight);
    
      float light = dot(normal, surfaceToLightDirection);
    
      gl_FragColor = u_color;
    
      gl_FragColor.rgb *= light;
    } 
   </script>

获取参数以及设定

    var MVPUniformLocation = webgl.getUniformLocation(program, "u_worldViewProjection");
    var worldUniformLocation = webgl.getUniformLocation(program, "u_world");
    var worldITUniformLocation = webgl.getUniformLocation(program, "u_worldInverseTranspose");
    var lightPUniformLocation = webgl.getUniformLocation(program, "u_lightWorldPosition");

      //投影矩阵
      var projectionMatrix = m4.perspective(fieldofViewInRadians, webgl.canvas.clientWidth / webgl.canvas.clientHeight, 1, 2000);

      var cameraPosition = [100, 150, 200];
      var targetPosition = [0, 35, 0];
      var up = [0, 1, 0];

      //相机矩阵
      var cameraMatrix = m4.lookAt(cameraPosition, targetPosition, up);

      //视图矩阵
      var viewMatrix = m4.inverse(cameraMatrix);

      //视图投影矩阵
      var viewProjectionMatrix = m4.multiply(projectionMatrix, viewMatrix);

      //模型矩阵
      var worldMatrix = m4.yRotation(fRotationRadians);
      var worldInverseMatrix = m4.inverse(worldMatrix);
      var worldInverseTransposeMatrix = m4.transpose(worldInverseMatrix);

      //模型视图投影矩阵
      var worldViewProjectionMatrix = m4.multiply(viewProjectionMatrix, worldMatrix);

      webgl.uniformMatrix4fv(MVPUniformLocation, false, worldViewProjectionMatrix);

      webgl.uniformMatrix4fv(worldITUniformLocation, false, worldInverseTransposeMatrix);

      webgl.uniformMatrix4fv(worldUniformLocation, false, worldMatrix);

      //设置光照方向,光源来源
      webgl.uniform3fv(lightPUniformLocation, [20, 30, 60]);

结果如下:

2.镜面反射

如果入射角和反射角恰好与眼睛和光源的夹角相同,那么光线就会反射到眼前且会特别亮,就如镜子一般。将halfVector向量与物体表面法向量点乘,+1表示方向一致,0表示垂直,-1表示方向相反;方向一致时,光就会进入人眼。

 顶点着色器(加了个相机位置跟物体表面到相机的向量):

  <script id="vertex-shader-3D" type="x-shader/x-vertex">
    attribute vec4 a_position;
    attribute vec3 a_normal;

    //光源位置
    uniform vec3 u_lightWorldPosition;
    //相机位置
    uniform vec3 u_viewWorldPosition;

    uniform mat4 u_world;
    uniform mat4 u_worldViewProjection;
    uniform mat4 u_worldInverseTranspose;

    varying vec3 v_normal;

    varying vec3 v_surfaceToLight;
    varying vec3 v_surfaceToView;

    void main(){
      gl_Position = u_worldViewProjection * a_position;
      v_normal = mat3(u_worldInverseTranspose) * a_normal;

      vec3 surfaceWorldPosition = (u_world * a_position).xyz;

      v_surfaceToLight = u_lightWorldPosition - surfaceWorldPosition;

      v_surfaceToView = u_viewWorldPosition - surfaceWorldPosition;
    }
  </script>

片段着色器(主要是halfVector和specular):

  <script id="fragment-shader-3D" type="x-shader/x-fragment">
    precision mediump float;

    varying vec3 v_normal;
    varying vec3 v_surfaceToLight;
    varying vec3 v_surfaceToView;
    
    uniform vec4 u_color;
    
    void main() {
      vec3 normal = normalize(v_normal);

      vec3 surfaceToLightDirection = normalize(v_surfaceToLight);
      vec3 surfaceToViewDirection = normalize(v_surfaceToView);
      vec3 halfVector = normalize(surfaceToLightDirection + surfaceToViewDirection);
    
      float light = dot(normal, surfaceToLightDirection);
      float specular = dot(normal,halfVector);
    
      gl_FragColor = u_color;
    
      gl_FragColor.rgb *= light;

      //加上高光
      gl_FragColor.rgb += specular;
    } 
   </script>

参数设置:

    var viewPUniformLocation = webgl.getUniformLocation(program, "u_viewWorldPosition");

    webgl.uniform3fv(viewPUniformLocation, cameraPosition);

结果如下:

 太亮啦!那我们调整一下吧

3. 镜面光的优化

将高光从线性变换变成指数变换,即 y = pow(x,a),a越大,图中阴影面积就越小,越接近指数变换,a越小阴影面积就越接近整个矩形,这样光照就变强了。 

只用修改片段着色器:

light的点乘结果有可能为赋值,这里只取正值做高光的计算,如果为负的话,高光设为0

  <script id="fragment-shader-3D" type="x-shader/x-fragment">
    precision mediump float;

    varying vec3 v_normal;
    varying vec3 v_surfaceToLight;
    varying vec3 v_surfaceToView;
    
    uniform vec4 u_color;
    uniform float u_shininess;
    
    void main() {
      vec3 normal = normalize(v_normal);

      vec3 surfaceToLightDirection = normalize(v_surfaceToLight);
      vec3 surfaceToViewDirection = normalize(v_surfaceToView);
      vec3 halfVector = normalize(surfaceToLightDirection + surfaceToViewDirection);
    
      float light = dot(normal, surfaceToLightDirection);
      //float specular = dot(normal,halfVector);
      float specular = 0.0;
      if(light>0.0){
        specular = pow(dot(normal,halfVector),u_shininess);
      }
    
      gl_FragColor = u_color;
    
      gl_FragColor.rgb *= light;

      gl_FragColor.rgb += specular;
    } 
   </script>

设置参数:

    var shininessUniformLocation = webgl.getUniformLocation(program, "u_shininess");

    var shininess = 150;

    webgl.uniform1f(shininessUniformLocation, shininess);

结果如下:

 看 仿佛一个小灯。

4. 光源颜色的修改

片段着色器(加了光源颜色和高光颜色):

  <script id="fragment-shader-3D" type="x-shader/x-fragment">
    precision mediump float;

    varying vec3 v_normal;
    varying vec3 v_surfaceToLight;
    varying vec3 v_surfaceToView;
    
    uniform vec4 u_color;
    uniform float u_shininess;

    uniform vec3 u_lightColor;
    uniform vec3 u_specularColor;
    
    void main() {
      vec3 normal = normalize(v_normal);

      vec3 surfaceToLightDirection = normalize(v_surfaceToLight);
      vec3 surfaceToViewDirection = normalize(v_surfaceToView);
      vec3 halfVector = normalize(surfaceToLightDirection + surfaceToViewDirection);
    
      float light = dot(normal, surfaceToLightDirection);
      //float specular = dot(normal,halfVector);
      float specular = 0.0;
      if(light>0.0){
        specular = pow(dot(normal,halfVector),u_shininess);
      }
    
      gl_FragColor = u_color;
    
      gl_FragColor.rgb *= light * u_lightColor;

      gl_FragColor.rgb += specular * u_specularColor;
    } 
   </script>

参数设置:

    var lightColorUnifromLoation = webgl.getUniformLocation(program, "u_lightColor");
    var specularColorUniformLocation = webgl.getUniformLocation(program, "u_specularColor");

    webgl.uniform3fv(lightColorUnifromLoation, m4.normalize([1, 0.6, 0.6]));
    webgl.uniform3fv(specularColorUniformLocation, m4.normalize([1, 0.2, 0.2]));

结果如下:

 将~暖光来了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值