WebGL自学教程——WebGL示例:12. 要有光
12. 要有光
WebGL没有光(没有像OpenGL中那样提供光方面的API)。要想有光,那就全靠我们自己进行计算了。
在http://learningwebgl.com上,有老外写的WebGL系列教程;国人的翻译在http://www.html5china.com/HTML5features/WebGL/上;其中有几课和光有关:《第七课 平行光和环境光》,《第十二章 点光照》,《第十三课 逐片段光照和多重program》等(还发现另外一个学习WebGL的网站:https://developer.mozilla.org/en/WebGL,顺便标记一下)。
所谓“光”就是通过一些方式、方法,根据片段的原始颜色和其他一些相关参数,计算出另一个相同或不同的颜色,并将之应用到片段。唯一要注意的是计算出的颜色要符合要求,要有一定的规律。真实世界中,某个光源中同样的两条光线照在同样的两个物体上,离光源近的比较亮;同样的两个物体,一个被一条光线照射,另外一个被两条同样的光线照射,后者会比前者亮;在全黑的封闭环境中,打开手电筒,不光可以看到手电筒前方的事物,连后方的事物也隐约可见;但无论是前方还是后方,只要距离够远,就看不到东西;手电筒照在箱子的前面,箱子前面很亮,侧面隐约可见,而箱子后面很暗、甚至不可见;...。根据这些现象,前人搞出了各种各样的光照模型、光照公式。对不同的光源类型,我们使用不同的光照模型、光照公式;并根据具体情况,使用不同的光照系数。
光源,可以分为四类。第一类,叫环境光。它照射出的光,无处不在,像雾、像烟,笼罩着场景中的所有物体。当然,很多人不把它当作光源的一个种类,因为它总是存在。第二类,是平行光,又叫方向光。这种光源,发出的光线是平行的。第三类,是聚光灯。它发出的是一束光,中间最亮,向外围逐渐衰减。第四类,是点光源。它以所在位置为中心,向西面八方发出光线。除了环境光,其他三类光源总是能表示为光线的集合。单条光线和物体表面,要么平行,要么相交。如果平行或交点和光线方向相反(在光的背面,注意,这种情况和用手电筒照射箱子前面,但还可以看到箱子后面的情况完全不同,后者借助了其他物体的反射光线),那么我们就可以说,这条光线和物体没有什么关系。在同向的交点处,物体对光线进行折射、反射、散射。此处要说的是,在不同的位置,对该交点进行观察,可能会看到完全不同的颜色;因为,折射和反射带有方向性,若不在特定的方向上进行观察,就不会看到折射光和反射光。
基于目的的不同,或要达到效果的不同,对这些光的定义和计算方法也会有很大的不同。比如环境光,我们可以用[0.0, 1.0]之间的数值来表示环境对物体原有颜色的反射比例。比如,在阴暗的环境下,物体看起来会比较暗,于是我们设置环境光为(0.5, 0.5, 0.5)。假设物体原色为(A,B,C),则物体的新色可以计算为(0.5*A, 0.5*B, 0.5*C)。假设另有一种神奇的环境,能让物体呈现出反色,那么,此时,环境光可以定义为一个标志,如果该标志打开,我们就这么计算新色:(1.0-A, 1.0-B, 1.0-C)。当然,还可能有更加神奇的环境,它能加强某种颜色、吸取某种颜色、替换某种颜色等等。
在本章示例中,仅对立方体表面计算光照(使用贴图颜色)。它模拟接受一个“环境光”和一个“点光源”的光照。其中,环境光表示为原色的比例;点光源处于产生阴影矩阵的光源的位置;立方体总是散射所有的光。为了方便对比各个参数造成的效果,我仿照网上的教程,增加了输入。另外,我对源码作了一下简单的整理,将部分函数放到了js文件中。js文件的内容如下(我会在以后不断完善它):
function ShaderSourceFromScript(scriptID)
{
var shaderScript = document.getElementById(scriptID);
if (shaderScript == null) return "";
var sourceCode = "";
var child = shaderScript.firstChild;
while (child)
{
if (child.nodeType == child.TEXT_NODE ) sourceCode += child.textContent;
child = child.nextSibling;
}
return sourceCode;
}
function CWebGLProgram(webgl, programObject, vertexShaderObject, fragmentShaderObject)
{
this.programObject = programObject;
this.vertexShaderObject = vertexShaderObject;
this.fragmentShaderObject = fragmentShaderObject;
this._webgl = webgl;
this.BindAttribLocation = function(index, name){this._webgl.bindAttribLocation(this.programObject, index, name);}
this.GetAttribLocation = function(name){return this._webgl.getAttribLocation(this.programObject, name);}
this.GetUniformLocation = function(name){return this._webgl.getUniformLocation(this.programObject, name);}
this.GetUniform = function(location){return this._webgl.getUniform(this.programObject, location);}
this.LoadLocations = function()
{
var n = this._webgl.getProgramParameter(this.programObject, this._webgl.ACTIVE_ATTRIBUTES);
for(var i=0; i<n; ++i)
{
var ai = this._webgl.getActiveAttrib(this.programObject, i);
this[ai.name] = this.GetAttribLocation(ai.name);
}
n = this._webgl.getProgramParameter(this.programObject, this._webgl.ACTIVE_UNIFORMS);
for(var i=0; i<n; ++i)
{
var ai = this._webgl.getActiveUniform(this.programObject, i);
this[ai.name] = this.GetUniformLocation (ai.name);
}
}
}
function CWebGL(canvasId)
{
this.canvas = document.getElementById(canvasId);
this.webgl = null;
this.error = '';
this.buffer = {};
this.UseProgram = function(oWebGLProgram)
{
this._oWebGLProgram = oWebGLProgram ;
this.webgl.useProgram(oWebGLProgram.programObject);
}
this.Viewport = function(){return [this.canvas.clientWidth, this.canvas.clientHeight];}
this.Init = function()
{
try
{
if(this.canvas == null) throw "error:canvasId";
this.webgl = this.canvas.getContext("experimental-webgl");
this.webgl.viewport(0, 0, this.canvas.clientWidth, this.canvas.clientHeight);
this._SetEvent(this.canvas, "onresize", this._OnResize);
return true;
}
catch(e)
{
this.error = "Init:\r\n" + e;
return false;
}
}
this.SetupShaderObject = function(program, type, scriptId)
{
var shaderObject = this.webgl.createShader(type);
this.webgl.shaderSource(shaderObject , ShaderSourceFromScript(scriptId));
this.webgl.compileShader(shaderObject );
if(!this.webgl.getShaderParameter(shaderObject , this.webgl.COMPILE_STATUS))
{
this.error = this.webgl.getShaderInfoLog(shaderObject);
this.webgl.deleteShader(shaderObject);
return null;
}
if(program) this.webgl.attachShader(program, shaderObject);
return shaderObject;
}
this.SetupProgramObject = function(vertexShaderScriptId, fragmentShaderScriptId, useProgram)//CWebGLProgram
{
var program = new CWebGLProgram(this.webgl, null, null, null);
try
{
program.programObject = this.webgl.createProgram();
program.vertexShaderObject = this.SetupShaderObject(program.programObject, this.webgl.VERTEX_SHADER, vertexShaderScriptId);
if(program.vertexShaderObject == null) throw "vertexShader("+vertexShaderScriptId+"):\r\n" + this.error;
program.fragmentShaderObject = this.SetupShaderObject(program.programObject, this.webgl.FRAGMENT_SHADER, fragmentShaderScriptId);
if(program.fragmentShaderObject == null) throw "fragmentShader("+fragmentShaderScriptId+"):\r\n" + this.error;
this.webgl.linkProgram(program.programObject);
if(!this.webgl.getProgramParameter(program.programObject, this.webgl.LINK_STATUS)) throw this.webgl.getProgramInfoLog(program.programObject);
if(useProgram) this.UseProgram(program);
program.LoadLocations();
return program;
}
catch(e)
{
this.error = "SetupProgramObject:\r\n" + e;
if(program.vertexShaderObject) this.webgl.deleteShader(program.vertexShaderObject);program.vertexShaderObject = null;
if(program.fragmentShaderObject) this.webgl.deleteShader(program.fragmentShaderObject);program.fragmentShaderObject = null;
if(program.programObject) this.webgl.deleteProgram(program.programObject);program.programObject = null;
program = null;
return null;
}
}
this.SetupArrayBuffer = function(typedArray, usage)
{
var buffer = this.webgl.createBuffer();
this.webgl.bindBuffer(this.webgl.ARRAY_BUFFER, buffer );
this.webgl.bufferData(this.webgl.ARRAY_BUFFER, typedArray, usage);
return buffer;
}
this.SetupElementArrayBuffer = function(typedArray, usage)
{
var buffer = this.webgl.createBuffer();
this.webgl.bindBuffer(this.webgl.ELEMENT_ARRAY_BUFFER, buffer );
this.webgl.bufferData(this.webgl.ELEMENT_ARRAY_BUFFER, typedArray, usage);
return buffer;
}
this.LoadArrayBuffer = function(bufferName, typedArray, usage)
{
this.buffer[bufferName] = this.SetupArrayBuffer(typedArray, usage);
}
this.LoadElementArrayBuffer = function(bufferName, typedArray, usage)
{
this.buffer[bufferName] = this.SetupElementArrayBuffer(typedArray, usage);
}
this.SetRender = function(onrender, interval)
{
if(this._interval)
{
window.clearInterval(this._interval);
this._interval = null;
}
if(onrender && interval && onrender != '')
{
this._eventOnRender = onrender;
window[this._id] = this;
this._interval = window.setIn
WebGL自学教程——WebGL示例:12. 要有光相关推荐
- WebGL自学教程——WebGL示例:开始
终于开始WebGL的示例了,...... 开始 使用WebGL的步骤,很简单: 1. 获得WebGL的渲染环境(也叫渲染上下文). 2. 发挥你的想象力,利用<WebGL参考手册>中的函数 ...
- WebGL简易教程——目录
文章目录 1. 绪论 2. 目录 3. 资源 1. 绪论 最近研究WebGL,看了<WebGL编程指南>这本书,结合自己的专业知识写的一系列教程.之前在看OpenGL/WebGL的时候总是 ...
- WebGL简易教程(十五):加载gltf模型
文章目录 1. 概述 2. 实例 2.1. 数据 2.2. 程序 2.2.1. 文件读取 2.2.2. glTF格式解析 2.2.2.1. 场景节点 2.2.2.2. 网格 2.2.2.3. 缓冲,缓 ...
- WebGL简易教程(十四):阴影
文章目录 1. 概述 2. 示例 2.1. 着色器部分 2.1.1. 帧缓存着色器 2.1.2. 颜色缓存着色器 2.2. 绘制部分 2.2.1. 整体结构 2.2.2. 具体改动 2.2.2.1. ...
- WebGL简易教程(十一):纹理
文章目录 1. 概述 2. 实例 2.1. 准备纹理 2.2. 配置纹理 2.3. 使用纹理 3. 结果 4. 参考 1. 概述 在之前的之前的教程<WebGL简易教程(九):综合实例:地形的绘 ...
- WebGL简易教程(十):光照
目录 1. 概述 2. 原理 2.1. 光源类型 2.2. 反射类型 2.2.1. 环境反射(enviroment/ambient reflection) 2.2.2. 漫反射(diffuse ref ...
- 站长在线零基础Python完全自学教程20:在Python中使用正则表达式完全解读
欢迎你来到站长学堂,学习站长在线出品的在线课程<零基础 Python完全自学教程>今天给大家分享的是第20课< 在Python中使用正则表达式完全解读>.本节课是一个大课,我分 ...
- 零基础Python完全自学教程15:Python中的列表
欢迎你来到站长学堂,学习站长在线出品的在线课程<零基础 Python完全自学教程>今天给大家分享的是第14课< Python中的列表 >.本节课是一个大课,我分了这些知识点进行 ...
- 零基础Python完全自学教程17:Python中的字典完全解读
欢迎你来到站长学堂,学习站长在线出品的在线课程<零基础 Python完全自学教程>今天给大家分享的是第17课< Python中的字典完全解读>.本节课是一个大课,我分了这些知识 ...
最新文章
- VS2008中Web Reference和Service Reference的区别
- 图像边缘检测--OpenCV之cvCanny函数
- HTML5会成为移动互联网应用开发的未来吗?
- 达梦数据库卡慢简单分析
- FIle类和递归方法的使用
- 通过链表深入理解Java的引用和对象
- java中如何使用jdk_java – 如何在JDK7中使用目录globbing
- python图书馆抢座_python模拟表单提交登录图书馆
- integer判断是否为null_面试常考题JavaScript用七种方式教你判断一个变量是否为数组类型...
- 期货软件公司排名_排行榜_五大品牌_口碑好的期货软件公司
- 基于HTTP协议的Java文件传输
- 借书表设计 mysql_请设计一套图书馆借书管理系统的数据库表结构
- flex java blazeds_Flex同Java通信--BlazeDS入门图文详解(上)
- UL 2849:2020 Standard for Electrical Systems for eBikes-电动自行车安规标准
- bm26 bm27 1
- A Weakly Supervised Convolutional Network for Change Segmentation and Classification
- bzoj1605 洛谷2905 [Usaco2008 Open]Crisis on the Farm 牧场危机(DP)
- TCP和UDP的区别有哪些
- 专访百度资深工程师孙源:代码强迫症的死实践派
- matlab 图像分割库,图像分割Matlab代码