• WebGL 计算点光源下的漫反射光颜色


    目录

    点光源光

    逐顶点光照(插值)

    示例程序(PointLightedCube.js)  

    代码详解

    示例效果

    逐顶点处理点光源光照效果时出现的不自然现象

    更逼真:逐片元光照

    示例程序(PointLightedCube_perFragment.js)

    代码详解


    点光源光

    与平行光相比,点光源光发出的光,在三维空间的不同位置上其方向也不同,如下图所示。所以,在对点光源光下的物体进行着色时,需要在每个入射点计算点光源光在该处的方向。

    点光源光的方向随位置变化

    平行光漫反射https://blog.csdn.net/dabaooooq/article/details/132942385?spm=1001.2014.3001.5502WebGL 计算平行光、环境光下的漫反射光颜色_山楂树の的博客-CSDN博客https://blog.csdn.net/dabaooooq/article/details/132942385?spm=1001.2014.3001.5502根据每个顶点的法向量和平行光入射方向来计算反射光的颜色。这一节还是采用该方法,只不过点光源光的方向不再是恒定不变的,而要根据每个顶点的位置逐一计算。着色器需要知道点光源光自身的所在位置,而不是光的方向。 

    示例程序PointLightedCubeWebGL 计算平行光、环境光下的漫反射光颜色_山楂树の的博客-CSDN博客LightedCube_ambient示例程序的点光源光版本,显示了一个点光源下的红色立方体。立方体表面仍然是漫反射,环境光保持不变,程序的效果如下图所示。

     

    逐顶点光照(插值)

    示例程序(PointLightedCube.js)  

    如下显示了示例程序的代码,与WebGL 计算平行光、环境光下的漫反射光颜色_山楂树の的博客-CSDN博客LightedCube_ambient相比,顶点着色器中新增加了u_ModelMatrix变量和u_LightPosition变量,前者表示模型矩阵,后者表示点光源的位置。本例中的光是点光源光而非平行光,所以我们需要用到点光源光的位置,而不是光线方向。为了让你看得更清楚,本例将立方体稍做放大。

    1. var VSHADER_SOURCE =
    2. 'attribute vec4 a_Position;\n' +
    3. 'attribute vec4 a_Color;\n' +
    4. 'attribute vec4 a_Normal;\n' +
    5. 'uniform mat4 u_MvpMatrix;\n' +
    6. 'uniform mat4 u_ModelMatrix;\n' + // 模型矩阵
    7. 'uniform mat4 u_NormalMatrix;\n' + // 用来变换法向量的矩阵
    8. 'uniform vec3 u_LightColor;\n' + // 光的颜色
    9. 'uniform vec3 u_LightPosition;\n' + // 光源位置(世界坐标系)
    10. 'uniform vec3 u_AmbientLight;\n' + // 环境光颜色
    11. 'varying vec4 v_Color;\n' +
    12. 'void main() {\n' +
    13. ' gl_Position = u_MvpMatrix * a_Position;\n' +
    14. //计算变换后的法向量并归一化
    15. ' vec3 normal = normalize(vec3(u_NormalMatrix * a_Normal));\n' +
    16. // 计算顶点的世界坐标(模型矩阵变换后的世界坐标)
    17. ' vec4 vertexPosition = u_ModelMatrix * a_Position;\n' +
    18. // 计算点光源方向并归一化(用点光源的世界坐标 - 物体顶点坐标)
    19. ' vec3 lightDirection = normalize(u_LightPosition - vec3(vertexPosition));\n' +
    20. // 计算光线方向和法向量的点积 cosθ
    21. ' float nDotL = max(dot(lightDirection, normal), 0.0);\n' +
    22. // 计算点光源漫反射光的颜色
    23. ' vec3 diffuse = u_LightColor * a_Color.rgb * nDotL;\n' +
    24. // 计算环境光产生的反射光的颜色
    25. ' vec3 ambient = u_AmbientLight * a_Color.rgb;\n' +
    26. // 将以上两者相加作为最终的颜色(物体表面的反射光颜色 = 漫反射光颜色(这里是点光源) + 环境反射光颜色)
    27. ' v_Color = vec4(diffuse + ambient, a_Color.a);\n' +
    28. '}\n';
    29. var FSHADER_SOURCE =
    30. '#ifdef GL_ES\n' +
    31. 'precision mediump float;\n' +
    32. '#endif\n' +
    33. 'varying vec4 v_Color;\n' +
    34. 'void main() {\n' +
    35. ' gl_FragColor = v_Color;\n' +
    36. '}\n';
    37. function main() {
    38. var canvas = document.getElementById('webgl');
    39. var gl = getWebGLContext(canvas);
    40. if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) return
    41. var n = initVertexBuffers(gl);
    42. gl.clearColor(0.0, 0.0, 0.0, 1.0);
    43. gl.enable(gl.DEPTH_TEST);
    44. // 获取统一变量的存储位置等等
    45. var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');
    46. var u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix');
    47. var u_NormalMatrix = gl.getUniformLocation(gl.program, 'u_NormalMatrix');
    48. var u_LightColor = gl.getUniformLocation(gl.program, 'u_LightColor');
    49. var u_LightPosition = gl.getUniformLocation(gl.program, 'u_LightPosition');
    50. var u_AmbientLight = gl.getUniformLocation(gl.program, 'u_AmbientLight');
    51. // 设置点光源的颜色为白色
    52. gl.uniform3f(u_LightColor, 1.0, 1.0, 1.0);
    53. // 设置点光源的位置(世界坐标下)
    54. gl.uniform3f(u_LightPosition, 2.3, 4.0, 3.5);
    55. // 设置环境光的颜色
    56. gl.uniform3f(u_AmbientLight, 0.2, 0.2, 0.2);
    57. var modelMatrix = new Matrix4(); // 模型矩阵
    58. var mvpMatrix = new Matrix4(); // 模型视图投影矩阵
    59. var normalMatrix = new Matrix4(); // 用于计算变换后的法向量的矩阵
    60. // 旋转90度,计算模型矩阵
    61. modelMatrix.setRotate(90, 0, 1, 0);
    62. // 将模型矩阵传递给u_ModelMatrix
    63. gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);
    64. // 计算模型视图投影矩阵
    65. mvpMatrix.setPerspective(30, canvas.width/canvas.height, 1, 100);
    66. mvpMatrix.lookAt(6, 6, 14, 0, 0, 0, 0, 1, 0);
    67. mvpMatrix.multiply(modelMatrix); // 模型 视图投影 相乘得到最终矩阵
    68. gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix.elements); // 将模型视图投影矩阵传给u_MvpMatrix变量
    69. /* 根据模型矩阵计算逆转置矩阵以变换法线 */
    70. normalMatrix.setInverseOf(modelMatrix); // 求原矩阵的逆矩阵
    71. normalMatrix.transpose(); // 将上一步求得的逆矩阵进行转置,并将自己设为转置后的结果
    72. gl.uniformMatrix4fv(u_NormalMatrix, false, normalMatrix.elements); // 将用来变换法向量的矩阵传给u_NormalMatrix变量
    73. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    74. gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
    75. }
    76. function initVertexBuffers(gl) {
    77. // Create a cube
    78. // v6----- v5
    79. // /| /|
    80. // v1------v0|
    81. // | | | |
    82. // | |v7---|-|v4
    83. // |/ |/
    84. // v2------v3
    85. // Coordinates
    86. var vertices = new Float32Array([
    87. 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
    88. 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
    89. 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
    90. -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
    91. -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
    92. 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
    93. ]);
    94. // Colors
    95. var colors = new Float32Array([
    96. 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v1-v2-v3 front
    97. 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v3-v4-v5 right
    98. 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v5-v6-v1 up
    99. 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v1-v6-v7-v2 left
    100. 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v7-v4-v3-v2 down
    101. 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0  // v4-v7-v6-v5 back
    102. ]);
    103. // Normal
    104. var normals = new Float32Array([
    105. 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
    106. 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
    107. 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
    108. -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
    109. 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
    110. 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
    111. ]);
    112. // Indices of the vertices
    113. var indices = new Uint8Array([
    114. 0, 1, 2, 0, 2, 3, // front
    115. 4, 5, 6, 4, 6, 7, // right
    116. 8, 9,10, 8,10,11, // up
    117. 12,13,14, 12,14,15, // left
    118. 16,17,18, 16,18,19, // down
    119. 20,21,22, 20,22,23 // back
    120. ]);
    121. // 将顶点属性写入缓冲区(坐标、颜色和法线)
    122. if (!initArrayBuffer(gl, 'a_Position', vertices, 3, gl.FLOAT)) return -1;
    123. if (!initArrayBuffer(gl, 'a_Color', colors, 3, gl.FLOAT)) return -1;
    124. if (!initArrayBuffer(gl, 'a_Normal', normals, 3, gl.FLOAT)) return -1;
    125. gl.bindBuffer(gl.ARRAY_BUFFER, null);
    126. var indexBuffer = gl.createBuffer();
    127. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
    128. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
    129. return indices.length;
    130. }
    131. function initArrayBuffer(gl, attribute, data, num, type) {
    132. var buffer = gl.createBuffer();
    133. gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    134. gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
    135. var a_attribute = gl.getAttribLocation(gl.program, attribute);
    136. gl.vertexAttribPointer(a_attribute, num, type, false, 0, 0);
    137. gl.enableVertexAttribArray(a_attribute);
    138. return true;
    139. }

    代码详解

    最关键的变化发生在顶点着色器中。首先使用模型矩阵变换顶点坐标,获得顶点在世界坐标系中的坐标(即变换后的坐标),以便计算点光源光在顶点处的方向。点光源向四周放射光线,所以顶点处的光线方向是由点光源光坐标减去顶点坐标而得到的矢量。点光源在世界坐标系中的坐标已经传给了着色器中的u_LightPosition(第9行),而前面也已经算出了顶点在世界坐标系中的坐标,这样就计算出了光线方向矢量lightDirection(第19行)。注意,需要使用normalize()函数进行归一化,以保证光线方向矢量的长度为1.0。最后,计算光线方向矢量与法向量的点积(第21行),从而算出每个顶点的颜色。

    运行程序,你会发现效果更加逼真了,如下图所示。但是,如果仔细观察还是能发现一个问题:立方体表面上有不自然的线条

    示例效果

    逐顶点处理点光源光照效果时出现的不自然现象

    出现该现象的原因:你应该还记得,WebGL系统会根据顶点的颜色,内插出表面上每个片元的颜色。实际上,点光源光照射到一个表面上,所产生的效果(即每个片元获得的颜色)与简单使用4个顶点颜色(虽然这4个顶点的颜色也是由点光源产生)内插出的效果并不完全相同(在某些极端情况下甚至很不一样),所以为了使效果更加逼真,我们需要对表面的每一点(而不仅仅是4个顶点)计算光照效果。如果使用一个球体,二者的差异可能会更明显,如下图所示。

    点光源下的球体

    如你所见,左图中球体暗部与亮部的分界不是很自然,而右侧的就自然多了。

    更逼真:逐片元光照

    乍一听,要在表面的每一点上计算光照产生的颜色,似乎是个不可能完成的任务。但实际上,我们只需要逐片元地进行计算。片元着色器总算要派上用场了。

    示例程序(PointLightedCube_perFragment.js)

    如下显示了示例程序的代码,与PointLightedCube.js相比,只有着色器部分被修改了,计算光照效果的逻辑从顶点着色器移到了片元着色器中。

    1. var VSHADER_SOURCE = // 309
    2. 'attribute vec4 a_Position;\n' +
    3. 'attribute vec4 a_Color;\n' +
    4. 'attribute vec4 a_Normal;\n' +
    5. 'uniform mat4 u_MvpMatrix;\n' +
    6. 'uniform mat4 u_ModelMatrix;\n' + // 模型矩阵
    7. 'uniform mat4 u_NormalMatrix;\n' + // 用来变换法向量的矩阵
    8. 'varying vec4 v_Color;\n' +
    9. 'varying vec3 v_Normal;\n' +
    10. 'varying vec3 v_Position;\n' +
    11. 'void main() {\n' +
    12. ' gl_Position = u_MvpMatrix * a_Position;\n' +
    13. // 计算顶点的世界坐标
    14. ' v_Position = vec3(u_ModelMatrix * a_Position);\n' +
    15. ' v_Normal = normalize(vec3(u_NormalMatrix * a_Normal));\n' +
    16. ' v_Color = a_Color;\n' +
    17. '}\n';
    18. var FSHADER_SOURCE =
    19. '#ifdef GL_ES\n' +
    20. 'precision mediump float;\n' +
    21. '#endif\n' +
    22. 'uniform vec3 u_LightColor;\n' + // 点光源颜色
    23. 'uniform vec3 u_LightPosition;\n' + // 点光源位置
    24. 'uniform vec3 u_AmbientLight;\n' + // 环境光颜色
    25. 'varying vec3 v_Normal;\n' +
    26. 'varying vec3 v_Position;\n' +
    27. 'varying vec4 v_Color;\n' +
    28. 'void main() {\n' +
    29. // 对法线进行归一化,因为其内插之后长度不一定是1.0
    30. ' vec3 normal = normalize(v_Normal);\n' +
    31. // 计算点光源光线方向并归一化
    32. ' vec3 lightDirection = normalize(u_LightPosition - v_Position);\n' +
    33. // 计算光线方向和法向量的点积(余弦角度值)
    34. ' float nDotL = max(dot(lightDirection, normal), 0.0);\n' +
    35. // 计算diffuse,ambient以及最终的颜色
    36. ' vec3 diffuse = u_LightColor * v_Color.rgb * nDotL;\n' +
    37. ' vec3 ambient = u_AmbientLight * v_Color.rgb;\n' +
    38. ' gl_FragColor = vec4(diffuse + ambient, v_Color.a);\n' +
    39. '}\n';
    40. function main() {
    41. var canvas = document.getElementById('webgl');
    42. var gl = getWebGLContext(canvas);
    43. if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) return
    44. var n = initVertexBuffers(gl);
    45. gl.clearColor(0.0, 0.0, 0.0, 1.0);
    46. gl.enable(gl.DEPTH_TEST);
    47. // Get the storage locations of uniform variables
    48. var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');
    49. var u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix');
    50. var u_NormalMatrix = gl.getUniformLocation(gl.program, 'u_NormalMatrix');
    51. var u_LightColor = gl.getUniformLocation(gl.program, 'u_LightColor');
    52. var u_LightPosition = gl.getUniformLocation(gl.program, 'u_LightPosition');
    53. var u_AmbientLight = gl.getUniformLocation(gl.program, 'u_AmbientLight');
    54. // Set the light color (white)
    55. gl.uniform3f(u_LightColor, 1.0, 1.0, 1.0);
    56. // Set the light direction (in the world coordinate)
    57. gl.uniform3f(u_LightPosition, 2.3, 4.0, 3.5);
    58. // Set the ambient light
    59. gl.uniform3f(u_AmbientLight, 0.2, 0.2, 0.2);
    60. var modelMatrix = new Matrix4(); // Model matrix
    61. var mvpMatrix = new Matrix4(); // Model view projection matrix
    62. var normalMatrix = new Matrix4(); // Transformation matrix for normals
    63. // Calculate the model matrix
    64. modelMatrix.setRotate(90, 0, 1, 0); // Rotate around the y-axis
    65. // Calculate the view projection matrix
    66. mvpMatrix.setPerspective(30, canvas.width/canvas.height, 1, 100);
    67. mvpMatrix.lookAt(6, 6, 14, 0, 0, 0, 0, 1, 0);
    68. mvpMatrix.multiply(modelMatrix);
    69. // Calculate the matrix to transform the normal based on the model matrix
    70. normalMatrix.setInverseOf(modelMatrix);
    71. normalMatrix.transpose();
    72. // Pass the model matrix to u_ModelMatrix
    73. gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);
    74. // Pass the model view projection matrix to u_mvpMatrix
    75. gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix.elements);
    76. // Pass the transformation matrix for normals to u_NormalMatrix
    77. gl.uniformMatrix4fv(u_NormalMatrix, false, normalMatrix.elements);
    78. // Clear color and depth buffer
    79. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    80. // Draw the cube
    81. gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
    82. }
    83. function initVertexBuffers(gl) {
    84. // Create a cube
    85. // v6----- v5
    86. // /| /|
    87. // v1------v0|
    88. // | | | |
    89. // | |v7---|-|v4
    90. // |/ |/
    91. // v2------v3
    92. // Coordinates
    93. var vertices = new Float32Array([
    94. 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
    95. 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
    96. 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
    97. -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
    98. -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
    99. 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
    100. ]);
    101. // Colors
    102. var colors = new Float32Array([
    103. 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v1-v2-v3 front
    104. 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v3-v4-v5 right
    105. 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v5-v6-v1 up
    106. 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v1-v6-v7-v2 left
    107. 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v7-v4-v3-v2 down
    108. 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0  // v4-v7-v6-v5 back
    109. ]);
    110. // Normal
    111. var normals = new Float32Array([
    112. 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
    113. 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
    114. 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
    115. -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
    116. 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
    117. 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
    118. ]);
    119. // Indices of the vertices
    120. var indices = new Uint8Array([
    121. 0, 1, 2, 0, 2, 3, // front
    122. 4, 5, 6, 4, 6, 7, // right
    123. 8, 9,10, 8,10,11, // up
    124. 12,13,14, 12,14,15, // left
    125. 16,17,18, 16,18,19, // down
    126. 20,21,22, 20,22,23 // back
    127. ]);
    128. // Write the vertex property to buffers (coordinates, colors and normals)
    129. if (!initArrayBuffer(gl, 'a_Position', vertices, 3)) return -1;
    130. if (!initArrayBuffer(gl, 'a_Color', colors, 3)) return -1;
    131. if (!initArrayBuffer(gl, 'a_Normal', normals, 3)) return -1;
    132. gl.bindBuffer(gl.ARRAY_BUFFER, null);
    133. var indexBuffer = gl.createBuffer();
    134. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
    135. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
    136. return indices.length;
    137. }
    138. function initArrayBuffer(gl, attribute, data, num) {
    139. var buffer = gl.createBuffer();
    140. gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    141. gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
    142. var a_attribute = gl.getAttribLocation(gl.program, attribute);
    143. gl.vertexAttribPointer(a_attribute, num, gl.FLOAT, false, 0, 0);
    144. gl.enableVertexAttribArray(a_attribute);
    145. return true;
    146. }

    代码详解

    为了逐片元地计算光照,你需要知道:(1)片元在世界坐标系下的坐标,(2)片元处表面的法向量。可以在顶点着色器中,将顶点的世界坐标和法向量以varying变量的形式传入片元着色器,片元着色器中的同名变量就已经是内插后的逐片元值了。

    顶点着色器使用模型矩阵乘以顶点坐标计算出顶点的世界坐标(第14行),将其赋值给v_Position变量。经过内插过程后,片元着色器就获得了逐片元的v_Position变量,也就是片元的世界坐标。类似地,顶点着色器将顶点的法向量赋值给v_Normal变量(第15行),经过内插,片元着色器就获得了逐片元的v_Normal变量,即片元的法向量。

    片元着色器计算光照效果的方法与PointLightedCube.js相同。首先对法向量v_Normal进行归一化(第31行),因为内插之后法向量可能不再是1.0了;然后,计算片元处的光线方向并对其归一化(第33行);接着计算法向量与光线方向的点积(第35行);最后分别计算点光源光和环境光产生的反射光颜色,并将两个结果加起来,赋值给gl_FragColor,片元就会显示为这个颜色。

    如果场景中有超过一个点光源,那么就需要在片元着色器中计算每一个点光源(当然还有环境光)对片元的颜色贡献,并将它们全部加起来。换句话说,有几个点光源,就得按照表面反射光颜色(漫反射+环境反射)公式计算几次。

  • 相关阅读:
    计算机网络 第3 章 数据链路层
    EasyGBS如何解决大屏播放时出现数据未推送情况?
    【有源码】基于asp.net的旅游度假村管理系统C#度假村美食住宿一体化平台源码调试 开题 lw ppt
    Scratch软件编程等级考试一级——20220619
    HDFS学习笔记(三):HDFS 分布式文件系统原理
    用商场媒体信息发布系统解决方案,让大家时刻关注你
    混凝土搅拌站预拌厂数字孪生可视化管理系统,三维可视化数据监控平台
    数码打印流程【方向不干胶、纸卡、瓦楞、单张 {不涉及画册}】
    ren域名有价值吗?值不值得投资?ren域名的应用范围有哪些?
    优质笔记软件评测(二)Logseq、Obsidian、思源笔记、FlowUs
  • 原文地址:https://blog.csdn.net/dabaooooq/article/details/132994498