1.聚光灯的实现

光线从某个点照亮所有方向,而聚光灯只选择其中一个方向,将其他光线方向与所选方向点乘并选择限定范围,判断光线是否在限定范围内,如果不在则不照亮。

首先给定一个点乘限定,如果与选定聚光灯方向的点乘大于这个点乘限定,则照亮,否则不照亮。

片段着色器:

  <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_lightDirection;uniform float u_limit;void main() {vec3 normal = normalize(v_normal);vec3 surfaceToLightDirection = normalize(v_surfaceToLight);vec3 surfaceToViewDirection = normalize(v_surfaceToView);vec3 halfVector = normalize(surfaceToLightDirection + surfaceToViewDirection);float light = 0.0;float specular = 0.0;float dotFromDirection = dot(surfaceToLightDirection,-u_lightDirection);if(dotFromDirection >= u_limit){light = dot(normal,surfaceToLightDirection);if(light>0.0){specular = pow(dot(normal,halfVector),u_shininess);}}gl_FragColor = u_color;gl_FragColor.rgb *= light;gl_FragColor.rgb += specular;} </script>

对u_lightDirection取负是因为我们希望两个方向匹配的时候能指向相同的方向,也可以传入时就直接传反方向(u_reverseLightDirection)

传参:

    var lightdUniformLocation = webgl.getUniformLocation(program, "u_lightDirection");var limitUniformLocation = webgl.getUniformLocation(program, "u_limit");//注意这段代码var lightPosition = [40, 60, 120];var lmat = m4.lookAt(lightPosition, targetPosition, up);lmat = m4.multiply(m4.xRotation(lightRotationX), lmat);lmat = m4.multiply(m4.yRotation(lightRotationY), lmat);lightDirection = [-lmat[8], -lmat[9], -lmat[10]]webgl.uniform3fv(lightdUniformLocation, lightDirection);webgl.uniform1f(limitUniformLocation, Math.cos(limit));

注意到我们的ligtDirection运用到了矩阵的计算,可以联想到之前说过的,如果需要实现视线跟随的效果,那么就需要利用到lookAt()方法。

结果如下:

左右上下移动可改变聚光灯的方向。

片段着色器的优化:

利用step()函数优化if语句,着色器中最好避免出现if语句

      float inlight = step(u_limit,dotFromDirection);float light = inlight * dot(normal,surfaceToLightDirection);float specular = inlight * pow(dot(normal,halfVector),u_shininess);

2.聚光灯的优化

将聚光灯的光做一个过渡。用一个内部限定和一个外部限定代替原来的一个限定值,如果在内部限定内就使用1,在外部限定外就用0,在二者之间就使用0-1之间的插值。

  <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_lightDirection;uniform float u_innerLimit;uniform float u_outerLimit;void main() {vec3 normal = normalize(v_normal);vec3 surfaceToLightDirection = normalize(v_surfaceToLight);vec3 surfaceToViewDirection = normalize(v_surfaceToView);vec3 halfVector = normalize(surfaceToLightDirection + surfaceToViewDirection);float dotFromDirection = dot(surfaceToLightDirection,-u_lightDirection);float limitRange = u_innerLimit - u_outerLimit;//插值float inlight = clamp((dotFromDirection - u_outerLimit)/limitRange,0.0,1.0);float light = inlight * dot(normal,surfaceToLightDirection);float specular = inlight * pow(dot(normal,halfVector),u_shininess);gl_FragColor = u_color;gl_FragColor.rgb *= light;gl_FragColor.rgb += specular;} </script>

注意:必须要保证传到u_innerLimit和u_outerLimit不能相等,否则着色器当中会出现undefined。

定义参数:

    var inlimitUniformLocation = webgl.getUniformLocation(program, "u_innerLimit");var outlimitUniformLocation = webgl.getUniformLocation(program, "u_outerLimit");webgl.uniform1f(inlimitUniformLocation, Math.cos(innerLimit));webgl.uniform1f(outlimitUniformLocation, Math.cos(outerLimit));

优化着色器代码(smoothstep代码相当于替代插值函数):

      float inlight = smoothstep(u_outerLimit,u_innerLimit,dotFromDirection);

结果如下:

smoothstep使用的时Hermite插值:

当lowBound大于或等于upperBound时,smoothstep方法会产生undefined,对于正常的聚光灯,这种情况永远不会出现。

WebGL实践篇(十)—— 光照:聚光灯相关推荐

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

    1.点光源的光照值 光照来源于点,太阳也算是一个点光源,光照射到物体的同一面上有明有暗(即光照值不同),将面上的每个点到光源的矢量与法向量点乘得到的值就是光照值. 顶点着色器: 主要添加了光照位置的参 ...

  2. [WebGL入门]十二,模型数据和顶点属性

    注:文章译自http://wgld.org/,原作者杉本雅広(doxas),文章中假设有我的额外说明,我会加上[lufy:].另外.鄙人webgl研究还不够深入,一些专业词语.假设翻译有误.欢迎大家指 ...

  3. WebGL 实践篇(三)—— 二维图形的平移、旋转、缩放

    一 平移 (1)平移直接体现在代码当中 在二维当中,平移相当于就是改变x,y的位置. function setRectangle(gl, x, y, width, height) {var x1 = ...

  4. WebGL入门(十九)-三维视图通过调整正射投影矩阵/盒状可视空间实现三角形的显示与消失

    三维视图正射投影矩阵 1.demo效果 2.相关知识点 2.1 正射投影 2.2 Matrix4.setOrtho()函数 3. demo代码 1.demo效果 如上,通过上下键调整正投影矩阵参数fa ...

  5. WebGL入门(十六)-三维视图模型原理,视点、视线、观察点、上方向

    三维视图模型原理 1.demo效果 2.相关知识点 2.1 视点.视线.观察点.上方向 2.2 创建视图矩阵 3. demo代码 1.demo效果 如上图,这个demo中三个不同颜色的三角形展示在三维 ...

  6. WebGL入门(十五)-使用多幅纹理/纹理叠加

    使用多幅纹理/纹理叠加 1.demo效果 2.实现要点 2.1 顶点着色器中声明varying变量v_TexCoord 2.2 片元着色器中多纹理处理 2.3 外部纹理图像加载 2.4 纹理叠加处理与 ...

  7. 日语语法实践篇十二——新编日语第一册第十三课之会话篇

    会話 李 :牧野さん.あなたは 何か欲しい物が ありますか. 李:牧野先生,你有什么想要的东西吗? 这里的「何か欲しい」可以进一步分解为: 何か 欲しい. 想要什么. 这里的「欲しい」表示的是第一人称 ...

  8. 日语语法实践篇十二——新编日语第一册第十三课之前文篇

    今天开始学习十三课,总觉得越学越不知道自己学了些什么了.但是我还是会继续下去的. 首先还是来看看前文部分. 第十三課 希望 前文 牧野さんは 日本人留学生で.いま 中国語の 慣用句の辞典を ほしがって ...

  9. 日语语法实践篇十四——新编日语第一册第十五课之前文篇

    前文 田さんは アルバイトを捜すために 学生センターに 来ました. 田先生为了找打工的工作来学生中心. 申込書の書き方が よく わからないので 職員に いろいろと 聞きました. 不怎么知道申请书的写法 ...

  10. threejs添加立方体_前端图形学(三十)——从源码去看threejs中的光照模型

    欢迎来到[畅哥聊技术]前端图形学相关技术文章,更多精彩内容持续更新中,敬请关注. 上章节回顾 熟悉了threejs中内置的几何图形的渲染原理就是通过顶点渲染 传入自定义顶点渲染自定义的几何图形 本章目 ...

最新文章

  1. 禁用页面缓存的几种方法(静态和动态)
  2. 【PHPWord】创建带样式表格的Word文档
  3. 下载 mysql 拖_mysql数据库托从
  4. 解决github push错误The requested URL returned error: 403 Forbidden while accessing(转)
  5. postgresql - mac 启动 关闭 postgresql
  6. 排序算法(一)--插入排序法折半插入排序法
  7. 20190825:(leetcode习题)最长公共前缀
  8. 使用Opencv分离图像通道/合并图像通道
  9. 文档碎片createDocumentFragment
  10. PowerDesigner建立数据库模型
  11. windows删mysql库代码_windows完全删除MySQL数据库
  12. 草蛋的Android studio 居然让我搞了好几天 真是智障啊non-zero exit value 2
  13. 关键词抽取工具-THUtag 个人使用心得
  14. SEO培训联盟排名掉的原因:宋星博客?
  15. 如何 接收消息服务器url,(读书笔记)网络是怎样连接的——浏览器生成消息...
  16. 计算机的利弊四级作文,2016年6月英语四级作文范文:网络的利弊
  17. jpa Specification fetch查询报错,query specified join fetching, but the owner of the fetched association
  18. 小米盒子显示服务器断开,【当贝市场】小米盒子4网络掉线怎么办?解决办法...
  19. 什么是内存对齐?如何计算内存对齐?为什么要内存对齐?
  20. java实现图片验证码_JAVA实现图片验证码

热门文章

  1. 在线制作微信跳转浏览器下载app源码
  2. 新蛋网通过WorldFirst注册账户并绑定WorldFirst收款教程!
  3. mysql算滚动率_建模滚动率计算
  4. 《用户故事与敏捷方法》读书笔记
  5. 量子计算机成果,【(新进展)量子理论方面的科技成果--量子计算机】
  6. python的内存机制_Python内存机制简介
  7. 二级建造师考试备考心得
  8. php 封装技巧,PHP 技巧 - 封装基本的数据类型
  9. VI编辑器的一些基础命令的使用
  10. 【深度学习与计算机视觉】12、迁移学习