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. 要有光相关推荐

  1. WebGL自学教程——WebGL示例:开始

    终于开始WebGL的示例了,...... 开始 使用WebGL的步骤,很简单: 1. 获得WebGL的渲染环境(也叫渲染上下文). 2. 发挥你的想象力,利用<WebGL参考手册>中的函数 ...

  2. WebGL简易教程——目录

    文章目录 1. 绪论 2. 目录 3. 资源 1. 绪论 最近研究WebGL,看了<WebGL编程指南>这本书,结合自己的专业知识写的一系列教程.之前在看OpenGL/WebGL的时候总是 ...

  3. 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. 缓冲,缓 ...

  4. WebGL简易教程(十四):阴影

    文章目录 1. 概述 2. 示例 2.1. 着色器部分 2.1.1. 帧缓存着色器 2.1.2. 颜色缓存着色器 2.2. 绘制部分 2.2.1. 整体结构 2.2.2. 具体改动 2.2.2.1. ...

  5. WebGL简易教程(十一):纹理

    文章目录 1. 概述 2. 实例 2.1. 准备纹理 2.2. 配置纹理 2.3. 使用纹理 3. 结果 4. 参考 1. 概述 在之前的之前的教程<WebGL简易教程(九):综合实例:地形的绘 ...

  6. WebGL简易教程(十):光照

    目录 1. 概述 2. 原理 2.1. 光源类型 2.2. 反射类型 2.2.1. 环境反射(enviroment/ambient reflection) 2.2.2. 漫反射(diffuse ref ...

  7. 站长在线零基础Python完全自学教程20:在Python中使用正则表达式完全解读

    欢迎你来到站长学堂,学习站长在线出品的在线课程<零基础 Python完全自学教程>今天给大家分享的是第20课< 在Python中使用正则表达式完全解读>.本节课是一个大课,我分 ...

  8. 零基础Python完全自学教程15:Python中的列表

    欢迎你来到站长学堂,学习站长在线出品的在线课程<零基础 Python完全自学教程>今天给大家分享的是第14课< Python中的列表 >.本节课是一个大课,我分了这些知识点进行 ...

  9. 零基础Python完全自学教程17:Python中的字典完全解读

    欢迎你来到站长学堂,学习站长在线出品的在线课程<零基础 Python完全自学教程>今天给大家分享的是第17课< Python中的字典完全解读>.本节课是一个大课,我分了这些知识 ...

最新文章

  1. VS2008中Web Reference和Service Reference的区别
  2. 图像边缘检测--OpenCV之cvCanny函数
  3. HTML5会成为移动互联网应用开发的未来吗?
  4. 达梦数据库卡慢简单分析
  5. FIle类和递归方法的使用
  6. 通过链表深入理解Java的引用和对象
  7. java中如何使用jdk_java – 如何在JDK7中使用目录globbing
  8. python图书馆抢座_python模拟表单提交登录图书馆
  9. integer判断是否为null_面试常考题JavaScript用七种方式教你判断一个变量是否为数组类型...
  10. 期货软件公司排名_排行榜_五大品牌_口碑好的期货软件公司
  11. 基于HTTP协议的Java文件传输
  12. 借书表设计 mysql_请设计一套图书馆借书管理系统的数据库表结构
  13. flex java blazeds_Flex同Java通信--BlazeDS入门图文详解(上)
  14. UL 2849:2020 Standard for Electrical Systems for eBikes-电动自行车安规标准
  15. bm26 bm27 1
  16. A Weakly Supervised Convolutional Network for Change Segmentation and Classification
  17. bzoj1605 洛谷2905 [Usaco2008 Open]Crisis on the Farm 牧场危机(DP)
  18. TCP和UDP的区别有哪些
  19. 专访百度资深工程师孙源:代码强迫症的死实践派
  20. matlab 图像分割库,图像分割Matlab代码

热门文章

  1. 20160805_Win7x64刻录CentOS6.4x64启动光盘
  2. MySQL实现递归查询
  3. java工程师个人简历模板
  4. 100行Android代码自定义一个流式布局-FlowLayout
  5. BASH脚本基础:环境变量PROMPT_COMMAND介绍
  6. Linux 开发环境搭建与使用——Linux 常用编辑器之vim
  7. Z-stack 协议栈基础知识
  8. 读取MP3文件内的ID3V2专辑图片并显示
  9. Linux —— 权限
  10. 啪的一下就进来了,很快哦