webgl 25.用点光源为正方体添加光照

前面两节我们用平行光为正方体添加了光照,这节我们用一个点光源来为正方体添加光照。

point lighted cube.png

平行光只需要一个光线方向和光线颜色就可以描述。而点光源的光线方向是不确定的,取决于点光源的位置和照射到物体上的位置。所以这里的重点是针对每个顶点重新计算光线方向。

我们要把点光源位置和 model matrix 传进去来计算每个顶点的光线方向

uniform vec3 u_LightPosition;
uniform mat4 u_ModelMatrix;

之后就可以计算出每个顶点的光线方向了

// 针对每个顶点计算光线方向
vec4 vertexPosition = u_ModelMatrix * a_Position;
vec3 lightDirection = normalize(u_LightPosition - vec3(vertexPosition));
现在的正方体看起来其实还不是特别的真实,因为只针对每个顶点计算了光线方向,最终的颜色在各个顶点之间进行了插值,而实际上正方体上每一个点上的光线方向都是不同的。要更加逼真的光照效果下节我们来看针对每个 fragment 计算光照。

完整代码

<script id="vertex-shader" type="glsl">
    attribute vec4 a_Position;
    attribute vec4 a_Color;
    attribute vec3 a_Normal;
    uniform vec3 u_LightColor;
    uniform vec3 u_LightPosition;
    uniform vec3 u_AmbientLight;
    uniform mat4 u_mvpMatrix;
    uniform mat4 u_ModelMatrix;
    uniform mat4 u_NormalMatrix;
    varying vec4 v_Color;

    void main() {
        gl_Position = u_mvpMatrix * a_Position;
        // 标准化(把长度变为 1 )
        vec3 normal = normalize(vec3(u_NormalMatrix * vec4(a_Normal,1.0)));

        // 针对每个顶点计算光线方向
        vec4 vertexPosition = u_ModelMatrix * a_Position;
        vec3 lightDirection = normalize(u_LightPosition - vec3(vertexPosition));

        float nDotL = max(dot(lightDirection, normal), 0.0);
        vec3 diffuse = u_LightColor * a_Color.rgb * nDotL;
        vec3 ambient = u_AmbientLight * a_Color.rgb;
        v_Color = vec4(diffuse + ambient, a_Color.a);
    }
</script>

<script id="fragment-shader" type="glsl">
    precision mediump float;
    varying vec4 v_Color;
    void main() {
       gl_FragColor = v_Color;
    }
</script>

<script src="lib/cuon-matrix.js"></script>
<script src="lib/myutils.js"></script>

<script>
    var VERTEX_SHADER_SOURCE = document.getElementById('vertex-shader').text;
    var FRAGMENT_SHADER_SOURCE = document.getElementById('fragment-shader').text;

    var canvas = document.getElementById("canvas");
    var gl = canvas.getContext('webgl');

    if (!initShaders(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)) {
        alert('Failed to init shaders');
    }

    var n = initVertexBuffers(gl);

    var u_mvpMatrix = gl.getUniformLocation(gl.program, 'u_mvpMatrix');
    var u_LightColor = gl.getUniformLocation(gl.program, 'u_LightColor');
    var u_AmbientLight = gl.getUniformLocation(gl.program, 'u_AmbientLight');
    var u_NormalMatrix = gl.getUniformLocation(gl.program, 'u_NormalMatrix');
    var u_LightPosition = gl.getUniformLocation(gl.program, 'u_LightPosition');
    var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');

    // 设置光源颜色
    gl.uniform3f(u_LightColor, 1.0, 1.0, 1.0);
    // 设置点光源位置
    gl.uniform3f(u_LightPosition, 2.3, 4.0, 3.5);
    // 设置环境光颜色
    gl.uniform3f(u_AmbientLight, 0.2, 0.2, 0.2);

    // <projection matrix> * <view matrix>
    var mvpMatrix = new Matrix4();
    mvpMatrix.setPerspective(30, 1, 1, 100);
    mvpMatrix.lookAt(6, 6, 14, 0, 0, 0, 0, 1, 0);

    var modelMatrix = new Matrix4();
    modelMatrix.rotate(90, 0, 1, 0);
    gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);

    mvpMatrix.multiply(modelMatrix);
    gl.uniformMatrix4fv(u_mvpMatrix, false, mvpMatrix.elements);

    // 计算法向量变换矩阵
    var normalMatrix = new Matrix4();
    normalMatrix.setInverseOf(modelMatrix);
    normalMatrix.transpose();
    gl.uniformMatrix4fv(u_NormalMatrix, false, normalMatrix.elements);

    gl.enable(gl.DEPTH_TEST);
    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);

    function initVertexBuffers(gl) {
        // Create a cube
        //    v6----- v5
        //   /|      /|
        //  v1------v0|
        //  | |     | |
        //  | |v7---|-|v4
        //  |/      |/
        //  v2------v3

        var vertices = new Float32Array([
            2.0, 2.0, 2.0, -2.0, 2.0, 2.0, -2.0, -2.0, 2.0, 2.0, -2.0, 2.0, // v0-v1-v2-v3 front
            2.0, 2.0, 2.0, 2.0, -2.0, 2.0, 2.0, -2.0, -2.0, 2.0, 2.0, -2.0, // v0-v3-v4-v5 right
            2.0, 2.0, 2.0, 2.0, 2.0, -2.0, -2.0, 2.0, -2.0, -2.0, 2.0, 2.0, // v0-v5-v6-v1 up
            -2.0, 2.0, 2.0, -2.0, 2.0, -2.0, -2.0, -2.0, -2.0, -2.0, -2.0, 2.0, // v1-v6-v7-v2 left
            -2.0, -2.0, -2.0, 2.0, -2.0, -2.0, 2.0, -2.0, 2.0, -2.0, -2.0, 2.0, // v7-v4-v3-v2 down
            2.0, -2.0, -2.0, -2.0, -2.0, -2.0, -2.0, 2.0, -2.0, 2.0, 2.0, -2.0  // v4-v7-v6-v5 back
        ]);

        var colors = new Float32Array([    // Colors
            1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,     // v0-v1-v2-v3 front
            1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,     // v0-v3-v4-v5 right
            1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,     // v0-v5-v6-v1 up
            1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,     // v1-v6-v7-v2 left
            1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,     // v7-v4-v3-v2 down
            1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0     // v4-v7-v6-v5 back
        ]);

        var normals = new Float32Array([    // Normal
            0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0,  // v0-v1-v2-v3 front
            1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0,  // v0-v3-v4-v5 right
            0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,  // v0-v5-v6-v1 up
            -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0,  // v1-v6-v7-v2 left
            0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0,  // v7-v4-v3-v2 down
            0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0   // v4-v7-v6-v5 back
        ]);

        var indices = new Uint8Array([       // Indices of the vertices
            0, 1, 2, 0, 2, 3,    // front
            4, 5, 6, 4, 6, 7,    // right
            8, 9, 10, 8, 10, 11,    // up
            12, 13, 14, 12, 14, 15,    // left
            16, 17, 18, 16, 18, 19,    // down
            20, 21, 22, 20, 22, 23     // back
        ]);

        if (!initArrayBuffer(gl, vertices, 3, gl.FLOAT, 'a_Position')) {
            return -1;
        }
        if (!initArrayBuffer(gl, colors, 3, gl.FLOAT, 'a_Color')) {
            return -1;
        }
        if (!initArrayBuffer(gl, normals, 3, gl.FLOAT, 'a_Normal')) {
            return -1;
        }

        var indexBuffer = gl.createBuffer();
        if (!indexBuffer) {
            console.log('Failed to create index buffer');
            return -1;
        }
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);

        return indices.length;
    }

    function initArrayBuffer(gl, data, numOfComponents, dataType, attributeName) {
        var buffer = gl.createBuffer();
        if (!buffer) {
            console.log('Failed to create buffer object');
            return false;
        }

        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
        gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);

        var attribute = gl.getAttribLocation(gl.program, attributeName);
        gl.vertexAttribPointer(attribute, numOfComponents, dataType, false, 0, 0);
        gl.enableVertexAttribArray(attribute);

        return true;
    }
</script>

查看源码

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容

  • 一、四大光照类型1.环境光(Ambient Light) 一个物体即使没有直接被光源照射,但是只要有光线通过其他物...
    CarlDonitz阅读 1,382评论 0 0
  • 下面来看一下光照先来看一下光源的类型 光源大体可分为 Directional light (平行光),Point ...
    lesliefang阅读 1,954评论 0 0
  • 现实世界的光照是极其复杂的,而且会受到诸多因素的影响,这是以目前我们所拥有的处理能力无法模拟的。因此OpenGL的...
    IceMJ阅读 1,871评论 1 6
  • 小学的时候,我的梦想是当中国第一名诺贝尔奖获得者。 初中的时候,我的愿望是当一名科学院院士,能够有震惊世界的发明...
    melongod1阅读 269评论 1 1
  • 有些时候我们把它做好了(如果单看它的话),但如果和高端的比档次就会觉得没有那么好了。这个理论可以用于各个领域比如服...
    美虑子阅读 166评论 0 0