WebGL编程指南-25 点光源使用,点光源照射下的立方体效果

1.demo效果

在这里插入图片描述
如上图,立方体在点光源照射下的效果,最右上角看上去更亮一些。

2.点光源方向计算

我们已经知道,在WebGL中,在使用平行光的时候需要知道平行光的方向,但是点光源只有一个位置属性,本身没有方向属性,但是我们可以用点光源的坐标减去顶点坐标的方向就得到了点光源的方向

点光源方向计算
<点光源方向> = <点光源坐标> - <顶点坐标>

3.demo代码

//Chapter 08
//temp 03

//绘制一个立方体
// => 运动中的光照效果
// 加上逆转置变化法向量

const VSHADER_SOURCE = `
    attribute vec4 a_Position;
    attribute vec4 a_Color;
    uniform mat4 u_VpMatrix; //view and range mat
    uniform mat4 u_ModelMatrix; //model mat
    uniform mat4 u_ReverseModelMat; //模型矩阵的逆转置
    attribute vec4 a_Normal; //法向量
    uniform vec3 u_LightColor; //平行光
    uniform vec3 u_LightPosition;//光源位置
    uniform vec3 u_LightDirection; //光照方向 //=归一化后的世界坐标
    uniform vec3 u_AmbientLight; // 环境光
    varying vec4 v_Color;
    void main() {
        gl_Position = u_VpMatrix * u_ModelMatrix * a_Position;

        //漫反射光颜色
        //法向量进行归一化
        vec3 normal = normalize(vec3(u_ReverseModelMat * a_Normal));
        //计算顶点的世界坐标
        vec4 vertexPosition = u_ModelMatrix*a_Position;
        //计算光线方向并归一化
        vec3 lightDirection = normalize(u_LightPosition - vec3(vertexPosition));
        //计算cos入射角 当角度大于90 说明光照在背面 赋值为0
        float nDotLight = max(dot(lightDirection, normal), 0.0);
        //计算反射光颜色
        vec3 diffuse = u_LightColor * vec3(a_Color) * nDotLight;

        // 环境反射光颜色
        vec3 ambient = u_AmbientLight * a_Color.rgb;

        v_Color = vec4(diffuse + ambient, a_Color.a);
    }
`;

const FSHADER_SOURCE = `
    precision mediump float;
    varying vec4 v_Color;
    void main() {
        gl_FragColor = v_Color;
        // gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    }
`;

ready(loadWEBGL);

function loadWEBGL() {
    const canvas = document.getElementById('webgl');
    const webgl = canvas.getContext('webgl');
    
    if ( !initShaders(webgl, VSHADER_SOURCE, FSHADER_SOURCE) ) {
        console.log(new Error('failed to init shaders!'));
        return ;
    }

    const viewMat = new Matrix4().setLookAt(7, 2.5, 6, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    const modelMat = new Matrix4().setIdentity();
    // var modelMat = new Matrix4().setTranslate(0, 1, 0).rotate(30, 0, 0, 1);

    const projMat = new Matrix4();
    projMat.setPerspective(30, canvas.width/canvas.height, 1.0, 100);

    const vpMat = new Matrix4().setIdentity().multiply(projMat).multiply(viewMat);
    const u_VpMatrix = webgl.getUniformLocation(webgl.program, 'u_VpMatrix');
    webgl.uniformMatrix4fv(u_VpMatrix, false, vpMat.elements);

    const u_ModelMatrix = webgl.getUniformLocation(webgl.program, 'u_ModelMatrix');
    webgl.uniformMatrix4fv(u_ModelMatrix, false, modelMat.elements);

    //************* */
    //model逆转置
    const reverseModelMat = new Matrix4().setInverseOf(modelMat); //求逆
    reverseModelMat.transpose(); //转置
    const u_ReverseModelMat = webgl.getUniformLocation(webgl.program, 'u_ReverseModelMat');
    webgl.uniformMatrix4fv(u_ReverseModelMat, false, reverseModelMat.elements);
    //************* */
    const u_LightPosition = webgl.getUniformLocation(webgl.program,'u_LightPosition');
    webgl.uniform3f(u_LightPosition,0.0,3.0,4.0);

    // data
    const vertexData = new Float32Array([
        1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, //front面 v0-4
        1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, //right v0345
        1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, //up v0561
        -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, //left 
        -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, //down
        1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0 //back
    ]);

    const colorData = new Float32Array([
        0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, //front
        0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, //right
        1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, //up
        1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, //left
        1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, //btm
        0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0 //back
    ]);

    const colorData_ALLWHITE = new Float32Array([
        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 
        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 
        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 
        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 
        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 
        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 
    ]);

    const indicesData = new Uint8Array([
        0, 1, 2, 0, 2, 3,
        4, 5, 6, 4, 6, 7,
        8, 9, 10, 8, 10, 11,
        12, 13, 14, 12, 14, 15,
        16, 17, 18, 16, 18, 19,
        20, 21, 22, 20, 22, 23
    ]);

    initArrayBuffer(webgl, vertexData, 'a_Position', 3, webgl.FLOAT);
    initArrayBuffer(webgl, colorData_ALLWHITE, 'a_Color', 3, webgl.FLOAT);
    initIndexBuffer(webgl, indicesData);
    const n = indicesData.length;

    //设置光照颜色
    const u_LightColor = webgl.getUniformLocation(webgl.program, 'u_LightColor');
    webgl.uniform3f(u_LightColor, 1.0, 1.0, 1.0);
    //设置光照方向
    const u_LightDirection = webgl.getUniformLocation(webgl.program,'u_LightDirection');
    const lightDirection = new Vector3([0.5, 3.0, 4.0]);
    lightDirection.normalize();
    webgl.uniform3fv(u_LightDirection, lightDirection.elements);
    //通过设置顶点的法向量 确定面的法向量
    const normalData = new Float32Array([
        0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0,
        1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 
        0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 
        -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, 
        0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 
        0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0
    ]);
    initArrayBuffer(webgl, normalData, 'a_Normal', 3, webgl.FLOAT);

    //设置环境光
    const u_AmbientLight = webgl.getUniformLocation(webgl.program, 'u_AmbientLight');
    webgl.uniform3f(u_AmbientLight, 0.2, 0.2, 0.2);

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

    const tempRMatrix = new Matrix4().setInverseOf(modelMat);
    const tick = () => {
        var modelMat = animateRotate(webgl, 30);

        //model逆转置
        tempRMatrix.setInverseOf(modelMat); //求逆
        tempRMatrix.transpose(); //转置
        webgl.uniformMatrix4fv(u_ReverseModelMat, false, tempRMatrix.elements);
        //mvp矩阵
        webgl.uniformMatrix4fv(u_ModelMatrix, false, modelMat.elements);
        //************* */
        webgl.clear(webgl.COLOR_BUFFER_BIT | webgl.DEPTH_BUFFER_BIT);
        webgl.drawElements(webgl.TRIANGLES, n, webgl.UNSIGNED_BYTE, 0);        
        requestAnimationFrame(tick);
    };
    // requestAnimationFrame(tick);
}

// 初始化顶点缓冲区
// 坐标值 或者 颜色值
function initArrayBuffer (webgl, data, name, num, type) {
    const vertexBuffer = webgl.createBuffer();
    webgl.bindBuffer(webgl.ARRAY_BUFFER, vertexBuffer);
    webgl.bufferData(webgl.ARRAY_BUFFER, data, webgl.STATIC_DRAW);
    const vertexLoction = webgl.getAttribLocation(webgl.program, name);
    webgl.vertexAttribPointer(vertexLoction, num, type, false, 0, 0);
    webgl.enableVertexAttribArray(vertexLoction);
    return true;
}

//=> 使用索引
function initIndexBuffer (webgl, indexData) {
    const indicesBuffer = webgl.createBuffer();

    webgl.bindBuffer(webgl.ELEMENT_ARRAY_BUFFER, indicesBuffer);
    webgl.bufferData(webgl.ELEMENT_ARRAY_BUFFER, indexData, webgl.STATIC_DRAW);

    return true;
}

//=> 添加一个动画
// return rotate 矩阵
let CURRENT_ANGLE = 0;
let CURRENT_MODEL_MATRIX = new Matrix4();
let CURRENT_TIMESTAMP = Date.now();
function animateRotate (webgl, speed) {
    const now = Date.now();
    const interval = Date.now() - CURRENT_TIMESTAMP;
    CURRENT_TIMESTAMP = now;
    CURRENT_ANGLE += (interval * speed /  1000);//累加
    CURRENT_MODEL_MATRIX.setRotate(CURRENT_ANGLE, 0, 0, 1);
    return CURRENT_MODEL_MATRIX;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《WebGL编程指南》是一本介绍WebGL技术的经典书籍,它详细阐述了WebGL的原理、应用和实践,是WebGL开发必备的参考书。本书附带的源代码是学习和实践WebGL的重要材料,它涵盖了WebGL的各个方面,从基础的三维图形绘制到高级的光影渲染和复杂的交互效果。 源代码包含了多个示例程序,各个示例程序围绕着一个主题展开。例如,有些示例程序演示了如何绘制简单的三维图形,如立方体和球体,还有些示例程序演示了如何添加纹理和材质,以及如何实现跨浏览器的兼容性。 此外,本书中的源代码还包括了一些高级的示例程序,如阴影、反射和抗锯齿等。这些示例程序可以帮助读者深入理解WebGL的工作原理和实现方法,并在实践中掌握WebGL技术。 值得一提的是,本书的源代码是经过精心设计和优化的,它压缩和合并了多个文件,以提高程序的性能和加载速度。因此,读者在使用本书源代码时,需要按照书中指导的步骤进行安装和部署,以获得最佳的开发体验。 总之,本书的源代码是WebGL学习和实践的重要资源,它提供了丰富的示例程序和实战经验,帮助读者快速掌握WebGL技术,开发出优秀的WebGL应用程序。 ### 回答2: WebGL编程指南是一本关于WebGL技术的教材,涵盖了从基础知识到高级应用的内容。其中提供了多个实例,结合源代码,帮助读者快速掌握WebGL编程技巧。 这本书的源代码非常有用,通过它可以理解WebGL的原理,并且快速搭建自己的WebGL应用程序。源代码中详细说明了各个组件的作用和用法,还提供了多种渲染器、着色器和纹理的实现方法,这些都对于初学者来说非常有价值。 WebGL编程指南源代码重点涵盖了三个方面:顶点缓冲对象、着色器和纹理。在顶点缓冲对象方面,它提供了多种创建和操作缓冲对象的实现方法,包括创建缓冲区、填充缓冲区、更新缓冲区等。在着色器方面,源代码中提供了包括简单着色器、光照着色器、Phong着色器在内的多种实现方法,这些着色器实现了不同的效果,读者可以根据需要自行选择。 最后是纹理,源代码提供了多种纹理类的实现方法,支持2D纹理、CubeMap纹理,以及多种纹理过滤和纹理映射方式。 总之,WebGL编程指南源代码提供了非常有价值的WebGL编程实践经验,对于从事WebGL开发的人员,特别是初学者,这是一份非常有意义的参考资料。 ### 回答3: 《WebGL编程指南》的源码是一本非常有用的资源,可以帮助读者更深入地理解WebGL编程技术。这本书的源码包括了许多有趣、实用的示例,可以帮助读者学会如何使用WebGL进行3D图形编程。 在掌握了基本的WebGL编程知识后,读者可以通过学习这些示例来深入了解WebGL技术,例如如何使用各种着色器、如何创建和渲染各种3D对象、如何进行照明和纹理映射等等。 同时,《WebGL编程指南》的源码也很容易上手。每个示例都有详细的注释和说明,使得读者可以很容易地理解代码的实现细节。读者可以将这些例子作为起点,自行修改和扩展,创造出更加有趣、独特的WebGL应用。 总之,《WebGL编程指南》的源码是非常有价值的,可以帮助广大编程爱好者、WebGL初学者甚至是资深的WebGL开发者,掌握更加深入的WebGL编程技术,为他们创造出更加精彩、创新的WebGL应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值