zoukankan      html  css  js  c++  java
  • WebGl点光、漫反射和汇总

    /**
        关键字:WebGL 模型矩阵 视图矩阵 逆转置矩阵    逐片元 
    **/
    
    //顶点着色器
    var VSHADER_SOURCE =
      'attribute vec4 a_Position;
    ' + //顶点数据
      'attribute vec4 a_Normal;
    ' +    //法线数据
      'uniform mat4 u_MvpMatrix;
    ' + //模型视图投影矩阵
      'uniform mat4 u_ModelMatrix;
    ' +    // 模型矩阵
      'uniform mat4 u_NormalMatrix;
    ' +   // 模型的逆转置矩阵,用于计算变化后的法线。
      'varying vec4 v_Color;
    ' + //顶点颜色
      'varying vec3 v_Normal;
    ' +    //变化之后的顶点的法线
      'varying vec3 v_Position;
    ' + //世界坐标系中的顶点位置
      'void main() {
    ' +
      '  vec4 color = vec4(1.0, 1.0, 1.0, 1.0);
    ' + // 球体颜色
      '  gl_Position = u_MvpMatrix * a_Position;
    ' + //球的位置
      '  v_Position = vec3(u_ModelMatrix * a_Position);
    ' + //计算顶点在世界坐标系中的位置。
      '  v_Normal = normalize(vec3(u_NormalMatrix * a_Normal));
    ' +//计算变化之后的顶点法线
      '  v_Color = color;
    ' + //顶点颜色
      '}
    ';
    
    // 片元着色器
    var FSHADER_SOURCE =
      '#ifdef GL_ES
    ' +
      'precision mediump float;
    ' +
      '#endif
    ' +
      'uniform vec3 u_LightColor;
    ' +     // 灯光颜色
      'uniform vec3 u_LightPosition;
    ' +  // 光源的位置
      'uniform vec3 u_AmbientLight;
    ' +   // 环境光颜色
      'varying vec3 v_Normal;
    ' +    //顶点法线
      'varying vec3 v_Position;
    ' + //顶点位置
      'varying vec4 v_Color;
    ' + //顶点颜色
      'void main() {
    ' +
         //再次对法线归一化,因为被插值了。
      '  vec3 normal = normalize(v_Normal);
    ' + 
         //计算光的方向并归一化
      '  vec3 lightDirection = normalize(u_LightPosition - v_Position);
    ' +//计算
         //用点积计算光与法线夹角的cos值。
      '  float nDotL = max(dot(lightDirection, normal), 0.0);
    ' +
         //计算漫反射光
      '  vec3 diffuse = u_LightColor * v_Color.rgb * nDotL;
    ' +
         //计算环境光
      '  vec3 ambient = u_AmbientLight * v_Color.rgb;
    ' +
         //最终的颜色
      '  gl_FragColor = vec4(diffuse + ambient, v_Color.a);
    ' +
      '}
    ';
    
    function main() {
      // Retrieve <canvas> element
      var canvas = document.getElementById('webgl');
    
      // Get the rendering context for WebGL
      var gl = getWebGLContext(canvas);
      if (!gl) {
        console.log('Failed to get the rendering context for WebGL');
        return;
      }
    
      // Initialize shaders
      if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
        console.log('Failed to intialize shaders.');
        return;
      }
    
      //创建球的顶点缓存
      var n = initVertexBuffers(gl);
      if (n < 0) {
        console.log('Failed to set the vertex information');
        return;
      }
    
      // Set the clear color and enable the depth test
      gl.clearColor(0.0, 0.0, 0.0, 1.0);
      gl.enable(gl.DEPTH_TEST);
    
      // Get the storage locations of uniform variables
      var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');
      var u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix');
      var u_NormalMatrix = gl.getUniformLocation(gl.program, 'u_NormalMatrix');
      var u_LightColor = gl.getUniformLocation(gl.program, 'u_LightColor');
      var u_LightPosition = gl.getUniformLocation(gl.program, 'u_LightPosition');
      var u_AmbientLight = gl.getUniformLocation(gl.program, 'u_AmbientLight');
      if (!u_ModelMatrix || !u_MvpMatrix || !u_NormalMatrix || !u_LightColor || !u_LightPosition || !u_AmbientLight) { 
        console.log('Failed to get the storage location');
        return;
      }
    
      // Set the light color (white)
      gl.uniform3f(u_LightColor, 0.8, 0.8, 0.8);
      // Set the light direction (in the world coordinate)
      gl.uniform3f(u_LightPosition, 5.0, 8.0, 7.0);
      // Set the ambient light
      gl.uniform3f(u_AmbientLight, 0.2, 0.2, 0.2);
    
      var modelMatrix = new Matrix4();  // Model matrix
      var mvpMatrix = new Matrix4();    // Model view projection matrix
      var normalMatrix = new Matrix4(); // Transformation matrix for normals
    
      // Calculate the model matrix
      modelMatrix.setRotate(90, 0, 1, 0); // Rotate around the y-axis
      // Calculate the view projection matrix
      mvpMatrix.setPerspective(30, canvas.width/canvas.height, 1, 100);
      mvpMatrix.lookAt(0, 0, 6, 0, 0, 0, 0, 1, 0);
      mvpMatrix.multiply(modelMatrix);//对球来说,旋转是多余的,没啥效果。
      // Calculate the matrix to transform the normal based on the model matrix
      normalMatrix.setInverseOf(modelMatrix);//求逆
      normalMatrix.transpose();//转置
    
      // Pass the model matrix to u_ModelMatrix
      gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);
    
      // Pass the model view projection matrix to u_mvpMatrix
      gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix.elements);
    
      // Pass the transformation matrix for normals to u_NormalMatrix
      gl.uniformMatrix4fv(u_NormalMatrix, false, normalMatrix.elements);
    
      // Clear color and depth buffer
      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    
      // 绘制三角形构成的立方体
      gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_SHORT, 0);
    }
    
    function initVertexBuffers(gl) { // Create a sphere
      var SPHERE_DIV = 13;
    
      var i, ai, si, ci;
      var j, aj, sj, cj;
      var p1, p2;
    
      var positions = [];
      var indices = [];
    
      // Generate coordinates
      for (j = 0; j <= SPHERE_DIV; j++) {
        aj = j * Math.PI / SPHERE_DIV;
        sj = Math.sin(aj);
        cj = Math.cos(aj);
        for (i = 0; i <= SPHERE_DIV; i++) {
          ai = i * 2 * Math.PI / SPHERE_DIV;
          si = Math.sin(ai);
          ci = Math.cos(ai);
    
          positions.push(si * sj);  // X
          positions.push(cj);       // Y
          positions.push(ci * sj);  // Z
        }
      }
    
      // Generate indices//产生上面这些数据的索引。
      for (j = 0; j < SPHERE_DIV; j++) {
        for (i = 0; i < SPHERE_DIV; i++) {
          p1 = j * (SPHERE_DIV+1) + i;
          p2 = p1 + (SPHERE_DIV+1);
    
          indices.push(p1);
          indices.push(p2);
          indices.push(p1 + 1);
    
          indices.push(p1 + 1);
          indices.push(p2);
          indices.push(p2 + 1);
        }
      }
    
      // Write the vertex property to buffers (coordinates and normals)
      // Same data can be used for vertex and normal
      // In order to make it intelligible, another buffer is prepared separately
      if (!initArrayBuffer(gl, 'a_Position', new Float32Array(positions), gl.FLOAT, 3)) return -1;
      if (!initArrayBuffer(gl, 'a_Normal', new Float32Array(positions), gl.FLOAT, 3))  return -1;
      
      // Unbind the buffer object
      gl.bindBuffer(gl.ARRAY_BUFFER, null);
    
      // Write the indices to the buffer object
      var indexBuffer = gl.createBuffer();
      if (!indexBuffer) {
        console.log('Failed to create the buffer object');
        return -1;
      }
      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
      gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
    
      return indices.length;
    }
    
    function initArrayBuffer(gl, attribute, data, type, num) {
      // Create a buffer object
      var buffer = gl.createBuffer();
      if (!buffer) {
        console.log('Failed to create the buffer object');
        return false;
      }
      // Write date into the buffer object
      gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
      gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
      // Assign the buffer object to the attribute variable
      var a_attribute = gl.getAttribLocation(gl.program, attribute);
      if (a_attribute < 0) {
        console.log('Failed to get the storage location of ' + attribute);
        return false;
      }
      gl.vertexAttribPointer(a_attribute, num, type, false, 0, 0);
      // Enable the assignment of the buffer object to the attribute variable
      gl.enableVertexAttribArray(a_attribute);
    
      return true;
    }


    相关资料

    相关资料:
    
    第二章
    
        零、顶点着色器:控制位置和大小。
            片元着色器:控制颜色。
    
        一、顶点着色器内置变量:
            1、gl_Position,
            2、gl_PointSize
    
        二、片元着色器内置变量
            FragColor(片元着色器唯一的变量)。
            
        三、gl.drawArrays(mode,first,count)
            mode:gl.POINTS,
                 gl.LINES,gl.LINE_STRIP((1,2),(2,3) ...),
                 gl.LINE_LOOP((1,2),(2,3) ...首尾相连),
                 gl.TRIANGLES,
                 gl.TRIANGLE_STRIP((0,1,2),(2,1,3),(2,3,4)...),
                 gl.TRIANGLE_FAN((1,2,3),(1,3,4),(1,4,5))。
            first:从哪个点开始。
            count:使用多少个点。
            注意:当该函数被执行时,顶点着色器被执行count次。每次处理一个点。
        四、webGL使用的是右手坐标系:x向右、y向上、z向屏幕外。
    
        五、从js向顶点着色器传变量的方式有两个:
            1、attribute(存储限定符) 传输那些和顶点相关的数据。(只有顶点着色器能使用)
                使用的过程:
                    a)在顶点着色器中声明attribute类型的变量,
                    b)赋值给gl_Position,c), 
                    c)在js变量中获取这个变量的存储地址: gl.getAttribLocation(gl.program, 'a_Position'),
                    d)在js中给这个变量赋值: gl.vertexAttrib3f(a_Position, 0.0, 0.5, 0.0)。
                    
            2、uniform(存储限定符)    传输哪些对于所有顶点都相同(和顶点无关)的数据。(顶点着色器和片元着色器都可以用)
                使用的过程和attribute的套路差不多。
    第三章 绘制和变换三角形
        一、创建缓存区对象的过程:
                1、准备好数据-> var vertices = new float32Array([0.0,0.5,-0.5,-0.5,0.5,-0.5]);  //三个点
                2、创建一个缓存区对象->  var vertexBuffer = gl.createBuffer();
                    3、[将缓存区绑定到目标]-> gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);
                4、将数据写到缓存区里-> gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);
                5、将缓存区的数据赋给顶点着色器-> gl.vertexAttribPointer(a_Position,2,gl.FLOAT,false,0,0);
                    6、[让分配的变量可用]。gl.enableVertexAttribArray(a_Position);
                    
        矩阵:每次变化,都是在顶点着色器中逐顶点改变图形的位置。
                每一次新的变换,都得求一个新的等式放到顶点着色器中实现,为了不这样来回更改顶点着色器,我们使用新的工具
                --变化矩阵。将多个变化矩阵一乘(变换效果叠加)得到一个总变化矩阵,再传入顶点着色器(矩阵*矢量特性)。
                变化矩阵非常适合操作计算机图形。
                
        二、旋转矩阵
                // Note: WebGL is column major order 列主序!!!!!
                var xformMatrix = new Float32Array([
                 cosB, sinB, 0.0, 0.0,
                -sinB, cosB, 0.0, 0.0,
                  0.0,  0.0, 1.0, 0.0,
                  0.0,  0.0, 0.0, 1.0
                ]);
                
                //行主序
                [
                    cosB, -sinB, 0.0, 0.0,
                    sinB, cosB,  0.0, 0.0,
                    0.0,  0.0,   1.0, 0.0,
                    0.0,  0.0,   0.0, 1.0
                
                ]
        三、平移矩阵
                var xformMatrix = new Float32Array([
                 1.0,  0.0,  0.0,  0.0,
                 0.0,  1.0,  0.0,  0.0,
                 0.0,  0.0,  1.0,  0.0,
                 Tx,    Ty,   Tz,  1.0
                ]);
                
                //行主序
                [
                    1.0, 0.0, 0.0, Tx,
                    0.0, 1.0, 0.0, Ty,
                    0.0, 0.0, 1.0, Tz,
                    0.0, 0.0, 0.0, 1.0
                ]
        四、缩放矩阵
                var xformMatrix = new Float32Array([
                 Sx,  0.0,  0.0,  0.0,
                 0.0,  Sy,  0.0,  0.0,
                 0.0,  0.0,  Sz,  0.0,
                 0.0,  0.0, 0.0,  1.0
                ]);
                
                //行主序
                [
                    Sx, 0.0, 0.0, 0.0,
                    0.0, Sy, 0.0, 0.0,
                    0.0, 0.0, Sz, 0.0,
                    0.0, 0.0,0.0,1.0
                ]
    第四章 高级变换与动画基础
        一、模型矩阵:一个模型可能经过多次变换,将这些变化全部复合成一个等效的变换(矩阵之间相乘)就得到了模型变换。
                    相应的,模型变化的矩阵称之为模型矩阵。
        二、一般情况下,平移旋转和旋转平移所得到的效果是不一样的(比如沿x轴平移和沿x旋转,效果应该是一样的)。
    
    第五章 颜色和纹理
    
        顶点着色器(逐顶点操作)-->装配(什么形状)-->光栅化(插值,什么颜色)-->片元着色器(逐片元操作)。
        一、多种顶点数据传入顶点着色器的方法:
            1、建立多个缓存区分别传入。
            2、建立一个缓存区,将数据交叉传入(利用gl.vertexAttribPointer
            (a_PointSize, 1, gl.FLOAT, false, FSIZE * 3, FSIZE * 2);)。
        二、varying(可变量):从顶点着色器向片元着色器传输数据。在WebGl中,如果顶点着色器和片元着色器中有类型和名称都相同的
                varying变量,那么顶点着色器赋值给该变量的值会被自动传入片元着色器。
                只能是float以及与之相关的顶点(vec2,vec3,vec4)矩阵(mat2,mat3,mat4)。
        三、片元坐标:光栅化的片元都带有坐标信息的,gl_FragCoord.x,gl_FragCoord.y。
        四、纹理映射的四个步骤:
            1、准备好纹理图像。(图片的坐标系左上角为原点,WebGL则是左下角为原点)
            2、为几何图形配置纹理映射方式。
            3、加载纹理图像,对其进行一些配置,以在webGl中用它。
            4、在片元着色器中将相应的纹素从纹理中抽取出来,并将纹素的颜色赋给片元。
            
        五、使用纹理的详细步骤
            1、设置纹理坐标
                将顶点坐标、纹理坐标都存到缓存区别开启。
            2、配置和加载纹理
                创建了纹理对象,绑定了onload事件。
            3、为WebGL配置纹理。
                开启0号纹理单元
                绑定纹理对象
                配置纹理对象的参数
                将纹理图像分配给纹理对象
                将0号纹理传递给片元着色器中的取样变量。
            4、从顶点着色器向片元着色器传递纹理坐标。
            5、从片元着色器中获取纹理像素颜色。
    第七章 进入三维世界
    
        "根据自定义观察者的状态,绘制观察者看到的景象"(将视图矩阵传入顶点着色器) 和 
        "使用默认观察者的状态,对三维对象进行变换(平移、旋转等),再绘制观察者看到的景象"(
        模型矩阵传入顶点着色器)效果是一样的。(反正都要在顶点着色器中乘一个矩阵)
        
        WebGL默认视点:在(0,0,0)点,看向Y轴负半轴,即朝屏幕里面。
        视图矩阵:视点、观察目标点、上方向。
            用视图矩阵乘以顶点坐标会把顶点变化到合适的位置,使得观察者(以默认的状态)观察新位置的顶点。就好像
            在观察者处在(视图矩阵描述的)视点上观察原始顶点一样。
            (最终的结果是 :视点还在原点,只是物体的为矩阵到合适的位置)
        模型矩阵:平移、缩放、旋转等基本变化矩阵或它们的组合。
        模型视图矩阵:视图矩阵*模型矩阵。
        
        正射投影矩阵:Matrix.setOrtho(left,right,bottom,top,near,far)。
        透视投影矩阵:Matrix.setPerspective(fov,aspect,near,far)
            fov:垂直视角,可视空间顶面与地面的夹角。
            aspect:近裁剪面的宽高比(宽度/高度)。
            near,far:近裁剪面和远裁剪面的位置(相对于视点,必须大于零)。
            
        世界物体-->裁剪(投影矩阵)  -->规范立方体-->降维-->屏幕上。
            
        模型视图投影矩阵:投影矩阵*视图矩阵*模型矩阵(投影矩阵的顺序位置不能移动,为什么?)
            
    第八章 光照
        看到的光(物体反射的光)取决于以下两个因素:
            入射光(方向和颜色)。
                
            物体表面的类型(基色和反射特性)。
            反射特性:
                漫反射:反射光在各方向上均匀的,是一种理想模型。
                    漫反射反射光的颜色:入射光颜色*表面基色*cosB,B是入射光与表面法线的夹角。
                                        =入射光颜色*表面基色*(光线方向.法线方向)
                环境反射:反射光在各方向上均匀的,强度相等的。
                    环境反射光颜色:入射光颜色*表面基色。
        看见的光 = 漫反射反射光的颜色 + 环境反射光颜色
        
        计算变化之后的法向量:之前的法向量*模型矩阵的逆转置矩阵。
        逆转置矩阵:逆矩阵的转置。
  • 相关阅读:
    手机端@media screen布局自适应
    JavaScript-判断语句(if...else)
    JavaScript-什么是变量
    网页上缺少标识符、字符串或数字怎么解决?
    jquery.qrcode.min.js生成二维码 通过前端实现二维码生成
    一步一回头撞在了南墙上
    C#中另类自定义公式计算 字符串转换为计算公式,并得出计算结果
    C#判断操作系统是32位还是64位(转)
    实现HTML调用打开本地软件文件
    记某图片下载器破解笔记之增加试用次数
  • 原文地址:https://www.cnblogs.com/airduce/p/11686138.html
Copyright © 2011-2022 走看看