WebGL实践篇(十)—— 光照:聚光灯
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实践篇(十)—— 光照:聚光灯相关推荐
- WebGL实践篇(九)—— 光照:点光源
1.点光源的光照值 光照来源于点,太阳也算是一个点光源,光照射到物体的同一面上有明有暗(即光照值不同),将面上的每个点到光源的矢量与法向量点乘得到的值就是光照值. 顶点着色器: 主要添加了光照位置的参 ...
- [WebGL入门]十二,模型数据和顶点属性
注:文章译自http://wgld.org/,原作者杉本雅広(doxas),文章中假设有我的额外说明,我会加上[lufy:].另外.鄙人webgl研究还不够深入,一些专业词语.假设翻译有误.欢迎大家指 ...
- WebGL 实践篇(三)—— 二维图形的平移、旋转、缩放
一 平移 (1)平移直接体现在代码当中 在二维当中,平移相当于就是改变x,y的位置. function setRectangle(gl, x, y, width, height) {var x1 = ...
- WebGL入门(十九)-三维视图通过调整正射投影矩阵/盒状可视空间实现三角形的显示与消失
三维视图正射投影矩阵 1.demo效果 2.相关知识点 2.1 正射投影 2.2 Matrix4.setOrtho()函数 3. demo代码 1.demo效果 如上,通过上下键调整正投影矩阵参数fa ...
- WebGL入门(十六)-三维视图模型原理,视点、视线、观察点、上方向
三维视图模型原理 1.demo效果 2.相关知识点 2.1 视点.视线.观察点.上方向 2.2 创建视图矩阵 3. demo代码 1.demo效果 如上图,这个demo中三个不同颜色的三角形展示在三维 ...
- WebGL入门(十五)-使用多幅纹理/纹理叠加
使用多幅纹理/纹理叠加 1.demo效果 2.实现要点 2.1 顶点着色器中声明varying变量v_TexCoord 2.2 片元着色器中多纹理处理 2.3 外部纹理图像加载 2.4 纹理叠加处理与 ...
- 日语语法实践篇十二——新编日语第一册第十三课之会话篇
会話 李 :牧野さん.あなたは 何か欲しい物が ありますか. 李:牧野先生,你有什么想要的东西吗? 这里的「何か欲しい」可以进一步分解为: 何か 欲しい. 想要什么. 这里的「欲しい」表示的是第一人称 ...
- 日语语法实践篇十二——新编日语第一册第十三课之前文篇
今天开始学习十三课,总觉得越学越不知道自己学了些什么了.但是我还是会继续下去的. 首先还是来看看前文部分. 第十三課 希望 前文 牧野さんは 日本人留学生で.いま 中国語の 慣用句の辞典を ほしがって ...
- 日语语法实践篇十四——新编日语第一册第十五课之前文篇
前文 田さんは アルバイトを捜すために 学生センターに 来ました. 田先生为了找打工的工作来学生中心. 申込書の書き方が よく わからないので 職員に いろいろと 聞きました. 不怎么知道申请书的写法 ...
- threejs添加立方体_前端图形学(三十)——从源码去看threejs中的光照模型
欢迎来到[畅哥聊技术]前端图形学相关技术文章,更多精彩内容持续更新中,敬请关注. 上章节回顾 熟悉了threejs中内置的几何图形的渲染原理就是通过顶点渲染 传入自定义顶点渲染自定义的几何图形 本章目 ...
最新文章
- 禁用页面缓存的几种方法(静态和动态)
- 【PHPWord】创建带样式表格的Word文档
- 下载 mysql 拖_mysql数据库托从
- 解决github push错误The requested URL returned error: 403 Forbidden while accessing(转)
- postgresql - mac 启动 关闭 postgresql
- 排序算法(一)--插入排序法折半插入排序法
- 20190825:(leetcode习题)最长公共前缀
- 使用Opencv分离图像通道/合并图像通道
- 文档碎片createDocumentFragment
- PowerDesigner建立数据库模型
- windows删mysql库代码_windows完全删除MySQL数据库
- 草蛋的Android studio 居然让我搞了好几天 真是智障啊non-zero exit value 2
- 关键词抽取工具-THUtag 个人使用心得
- SEO培训联盟排名掉的原因:宋星博客?
- 如何 接收消息服务器url,(读书笔记)网络是怎样连接的——浏览器生成消息...
- 计算机的利弊四级作文,2016年6月英语四级作文范文:网络的利弊
- jpa Specification fetch查询报错,query specified join fetching, but the owner of the fetched association
- 小米盒子显示服务器断开,【当贝市场】小米盒子4网络掉线怎么办?解决办法...
- 什么是内存对齐?如何计算内存对齐?为什么要内存对齐?
- java实现图片验证码_JAVA实现图片验证码