光照模型的计算在着色器程序中是如何工作的? [英] How does the calculation of the light model work in a shader program?

查看:15
本文介绍了光照模型的计算在着色器程序中是如何工作的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试阅读本教程:

如果我们看一下角度 -90° 和 90° 之间的 cos(x) 函数,那么我们可以看到它在角度为 0° 处的最大值为 1,并且它在 90° 和 -90° 的角度下降到 0.

这种行为正是我们想要的反射模型.当表面的正常向量和光源的方向在同一方向(之间的角度为 0°)时,我们需要最大的反射.相比之下,如果向量被正交化(两者之间的角度为 90°),那么我们需要最小的反射,并且我们需要在 0° 和 90° 的两个边界之间平滑且连续的函数运行.

如果在顶点着色器中计算光照模型,则为图元的每个角计算反射.在基元之间,反射根据其重心坐标进行插值.查看球面上产生的反射:

另见:


WebGL 示例:球体上的朗伯漫反射

(function loadscene() {var gl, progDraw, vp_size;var bufSphere = {};函数渲染(delteMS){相机创建();Camera.vp = vp_size;gl.viewport(0, 0, vp_size[0], vp_size[1]);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 );//设置绘制着色器ShaderProgram.Use( progDraw.prog );ShaderProgram.SetUniformM44( progDraw.prog, "u_projectionMat44", Camera.Perspective());ShaderProgram.SetUniformM44( progDraw.prog, "u_viewMat44", Camera.LookAt());var modelMat = IdentityMat44()modelMat = RotateAxis(modelMat, CalcAng(delteMS, 13.0), 0);modelMat = RotateAxis(modelMat, CalcAng(delteMS, 17.0), 1);ShaderProgram.SetUniformM44( progDraw.prog, "u_modelMat44", modelMat );ShaderProgram.SetUniformF3( progDraw.prog, "u_color", [1.0, 0.5, 0.0] );ShaderProgram.SetUniformF3( progDraw.prog, "u_lightDir", [-4.0, 0.0, -1.0] )//绘制场景VertexBuffer.Draw( bufSphere );请求动画帧(渲染);}函数调整大小(){//vp_size = [gl.drawingBufferWidth, gl.drawingBufferHeight];vp_size = [window.innerWidth, window.innerHeight]canvas.width = vp_size[0];canvas.height = vp_size[1];}函数 initScene() {canvas = document.getElementById("canvas");gl = canvas.getContext( "experimental-webgl" );如果(!gl)返回空;程序绘制 = {}progDraw.prog = ShaderProgram.Create([ { 来源:绘制着色器-vs",阶段:gl.VERTEX_SHADER },{ 来源:draw-shader-fs",阶段:gl.FRAGMENT_SHADER }]);如果(!progDraw.prog)返回空;progDraw.inPos = gl.getAttribLocation( progDraw.prog, "inPos" );//创建球体var layer_size = 16,circum_size = 32;var rad_circum = 1.0;var rad_tube = 0.5;var sphere_pts = [];sphere_pts.push( 0.0, 0.0, -1.0 );for ( var i_l = 1; i_l = 0) ?0 : Math.sqrt( -a_b );返回 [ a * Math.sin( angRag ) - ea, b * Math.cos( angRag ) - eb, 0 ];}glArrayType = typeof Float32Array !="undefined" ?Float32Array : ( typeof WebGLFloatArray != "undefined" ? WebGLFloatArray : Array );功能 IdentityMat44() {var m = new glArrayType(16);米[0] = 1;m[1] = 0;m[2] = 0;m[3] = 0;m[4] = 0;米[5] = 1;米[6] = 0;米[7] = 0;米[8] = 0;米[9] = 0;米[10] = 1;米[11] = 0;米[12] = 0;m[13] = 0;m[14] = 0;米[15] = 1;返回 m;};函数旋转轴(matA,angRad,轴){var aMap = [ [1, 2], [2, 0], [0, 1] ];var a0 = aMap[axis][0], a1 = aMap[axis][1];var sinAng = Math.sin(angRad), cosAng = Math.cos(angRad);var matB = new glArrayType(16);for ( var i = 0; i <16; ++ i ) matB[i] = matA[i];for ( var i = 0; i <3; ++ i ) {matB[a0*4+i] = matA[a0*4+i] * cosAng + matA[a1*4+i] * sinAng;matB[a1*4+i] = matA[a0*4+i] * -sinAng + matA[a1*4+i] * cosAng;}返回 matB;}function Cross( a, b ) { return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2],a[0] * b[1] - a[1] * b[0], 0.0 ];}function Dot( a, b ) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];}函数归一化( v ) {var len = Math.sqrt( v[0] * v[0] + v[1] * v[1] + v[2] * v[2] );返回 [ v[0]/len, v[1]/len, v[2]/len ];}var 相机 = {};Camera.create = function() {this.pos = [0, 1.5, 0.0];this.target = [0, 0, 0];this.up = [0, 0, 1];this.fov_y = 90;this.vp = [800, 600];this.near = 0.5;this.far = 100.0;}Camera.Perspective = function() {var fn = this.far + this.near;var f_n = this.far - this.near;var r = this.vp[0]/this.vp[1];var t = 1/Math.tan( Math.PI * this.fov_y/360 );var m = IdentityMat44();m[0] = t/r;m[1] = 0;m[2] = 0;m[3] = 0;m[4] = 0;m[5] = t;米[6] = 0;米[7] = 0;米[8] = 0;米[9] = 0;m[10] = -fn/f_n;m[11] = -1;米[12] = 0;m[13] = 0;m[14] = -2 * this.far * this.near/f_n;米[15] = 0;返回 m;}Camera.LookAt = 函数(){var mz = Normalize( [ this.pos[0]-this.target[0], this.pos[1]-this.target[1], this.pos[2]-this.target[2] ] );var mx = Normalize( Cross( this.up, mz ) );var my = Normalize( Cross( mz, mx ) );var tx = Dot( mx, this.pos );var ty = Dot( my, this.pos );var tz = Dot( [-mz[0], -mz[1], -mz[2]], this.pos );var m = IdentityMat44();m[0] = mx[0];米[1] = 我的[0];m[2] = mz[0];m[3] = 0;m[4] = mx[1];米[5] = 我的[1];m[6] = mz[1];米[7] = 0;m[8] = mx[2];米[9] = 我的[2];m[10] = mz[2];米[11] = 0;m[12] = tx;m[13] = ty;m[14] = tz;米[15] = 1;返回 m;}var ShaderProgram = {};ShaderProgram.Create = 函数(着色器列表){var shaderObjs = [];for ( var i_sh = 0; i_sh < shaderList.length; ++ i_sh ) {var shderObj = this.CompileShader( shaderList[i_sh].source, shaderList[i_sh].stage);如果(shderObj == 0)返回0;shaderObjs.push( shderObj );}var progObj = this.LinkProgram( shaderObjs )如果(progObj != 0){progObj.attribIndex = {};var noOfAttributes = gl.getProgramParameter( progObj, gl.ACTIVE_ATTRIBUTES );for ( var i_n = 0; i_n 

html,body {高度:100%;宽度:100%;边距:0;溢出:隐藏;}#gui {位置:绝对;顶部:0;左:0;}

<script id="draw-shader-fs" type="x-shader/x-fragment">精密中等浮点数;不同的 vec3 v_normal;统一 vec3 u_lightDir;统一 vec3 u_color;无效主(){vec3 normalV = normalize( v_normal );vec3 lightV = 标准化(-u_lightDir);float NdotL = max( 0.0, dot( normalV, lightV ) );vec3 lightCol = (0.2 + 0.8 * NdotL) * u_color;gl_FragColor = vec4(lightCol.rgb, 1.0);}<canvas id="canvas" style="border: none;"width="100%" height="100%"></canvas>

I am trying to read up this tutorial:

https://aerotwist.com/tutorials/an-introduction-to-shaders-part-2/

but I am not able to follow up. Basically the code creates a directional light by using shaders that run directly on the GPU. This is the code:

// same name and type as VS
varying vec3 vNormal;

void main() {

    // calc the dot product and clamp
    // 0 -> 1 rather than -1 -> 1
    vec3 light = vec3(0.5,0.2,1.0);

    // ensure it's normalized
    light = normalize(light);

    // calculate the dot product of
    // the light to the vertex normal
    float dProd = max(0.0, dot(vNormal, light));

    // feed into our frag colour
    gl_FragColor = vec4(dProd, dProd, dProd, 1.0);

} 

Specifically, the line that I don't understand is this one:

float dProd = max(0.0, dot(vNormal, light));

How does dot product of vNormal of a vertex and light create a directional light. Can anybody explain me diagrammatically. I am not able to get it . This looks bit of magic to me. I know in this vertex shader each vertex is being passed as an input which is called normal because it is represent in terms of "1" and that shared variable is then used in the above fragment shader code. But apart from this I didn't understand how it works.

P.S: I could have asked to the blog writer but he is on 2 weeks holiday as I know. So I thought someone with some physics or three.js experience might be able to tell me.

解决方案

Lambertian reflectance model

To model the reflection of light in computer graphics is used a Bidirectional reflectance distribution function (BRDF). BRDF is a function that gives the relation between the light reflected along an outgoing direction and the light incident from an incoming direction.

A perfect diffuse surface has a BRDF that has the same value for all incident and outgoing directions. This substantially reduces the computations and thus it is commonly used to model diffuse surfaces as it is physically plausible, even though there are no pure diffuse materials in the real world. This BRDF is called Lambertian reflection because it obeys Lambert's cosine law.

Lambertian reflection is often used as a model for diffuse reflection. This technique causes all closed polygons (such as a triangle within a 3D mesh) to reflect light equally in all directions when rendered The diffusion coefficient is calculated from the angle between the normal vector and the light vector.

f_Lambertian = max( 0.0, dot( N, L )

where N is the normal vector of the surface, and L is the vector towards to the light source.

How it works

In general The dot product of 2 vectors is equal the cosine of the angle between the 2 vectors multiplied by the magnitude (lenght) of both vectors.

dot( A, B ) == length( A ) * length( B ) * cos( angle_A_B ) 

This follows, that the dot product of 2 unit vectors is equal the cosine of the angle between the 2 vectors, because the length of a unit vector is 1.

uA = normalize( A )
uB = normalize( B )
cos( angle_A_B ) == dot( uA, uB )

If we take a look at the cos(x) function between the angles -90° and 90° then we can see that it has a maximum of 1 at an angle of 0° and It goes down to 0 at the angles of 90° and -90°.

This behavior is exactly that what we want for the reflection model. When the nromal vetor of the surface and the diretion to the light source are in the same direction (the angle between is 0°) then we want a maximium of reflection. In contrast, if the vectors a orthonormalized (the angle in between is 90°) then we want a minimum of reflection and we want a smooth and continuous functional running between the two borders of 0° and 90°.

If the light model is calculated in the vertex shader, the reflection is calculated for each corner of the primitive. In between the primitives the reflections are interpolate according to its barycentric coordinates. See the resulting reflections on a spherical surface:

See also:


WebGL example: Lambertian diffuse reflection on a sphere

(function loadscene() {
  
  var gl, progDraw, vp_size;
  var bufSphere = {};
  
  function render(delteMS){

      Camera.create();
      Camera.vp = vp_size;
          
      gl.viewport( 0, 0, vp_size[0], vp_size[1] );
      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 );

      // set up draw shader
      ShaderProgram.Use( progDraw.prog );
      ShaderProgram.SetUniformM44( progDraw.prog, "u_projectionMat44", Camera.Perspective() );
      ShaderProgram.SetUniformM44( progDraw.prog, "u_viewMat44", Camera.LookAt() );
      var modelMat = IdentityMat44()
      modelMat = RotateAxis( modelMat, CalcAng( delteMS, 13.0 ), 0 );
      modelMat = RotateAxis( modelMat, CalcAng( delteMS, 17.0 ), 1 );
      ShaderProgram.SetUniformM44( progDraw.prog, "u_modelMat44", modelMat );
      ShaderProgram.SetUniformF3( progDraw.prog, "u_color", [1.0, 0.5, 0.0] );
      ShaderProgram.SetUniformF3( progDraw.prog, "u_lightDir", [-4.0, 0.0, -1.0] )
      
      // draw scene
      VertexBuffer.Draw( bufSphere );

      requestAnimationFrame(render);
  }
  
  function resize() {
      //vp_size = [gl.drawingBufferWidth, gl.drawingBufferHeight];
      vp_size = [window.innerWidth, window.innerHeight]
      canvas.width = vp_size[0];
      canvas.height = vp_size[1];
  }
  
  function initScene() {
  
      canvas = document.getElementById( "canvas");
      gl = canvas.getContext( "experimental-webgl" );
      if ( !gl )
        return null;
  
      progDraw = {}
      progDraw.prog = ShaderProgram.Create( 
        [ { source : "draw-shader-vs", stage : gl.VERTEX_SHADER },
          { source : "draw-shader-fs", stage : gl.FRAGMENT_SHADER }
        ] );
      if ( !progDraw.prog )
          return null;
      progDraw.inPos = gl.getAttribLocation( progDraw.prog, "inPos" );
      
      // create sphere
      var layer_size = 16, circum_size = 32;
      var rad_circum = 1.0;
      var rad_tube = 0.5;
      var sphere_pts = [];
      sphere_pts.push( 0.0, 0.0, -1.0 );
      for ( var i_l = 1; i_l < layer_size; ++ i_l ) {
          var angH = (1.0 - i_l / layer_size) * Math.PI;
          var h = Math.cos( angH );
          var r = Math.sin( angH );
          for ( var i_c = 0; i_c < circum_size; ++ i_c ) {
              var circumX = Math.cos(2 * Math.PI * i_c / circum_size);
              var circumY = Math.sin(2 * Math.PI * i_c / circum_size);
              sphere_pts.push( r * circumX, r * circumY, h );
          }
      }
      sphere_pts.push( 0.0, 0.0, 1.0 );
      var sphere_inx = [];
      for ( var i_c = 0; i_c < circum_size; ++ i_c ) {
          sphere_inx.push( i_c+1, 0, (i_c+1) % circum_size + 1 )
      } 
      for ( var i_l = 0; i_l < layer_size-2; ++ i_l ) {
          var l1 = i_l * circum_size + 1;
          var l2 = (i_l+1) * circum_size + 1
          for ( var i_c = 0; i_c < circum_size; ++ i_c ) {
              var i_n = (i_c+1) % circum_size;
              sphere_inx.push( l1+i_c, l1+i_n, l2+i_c, l1+i_n, l2+i_n, l2+i_c );
          }
      }
      for ( var i_c = 0; i_c < circum_size; ++ i_c ) {
          var i_start = 1 + (layer_size-2) * circum_size;
          var i_n = (i_c+1) % circum_size;
          sphere_inx.push( i_start + i_c, i_start + i_n, sphere_pts.length/3-1 );
      }
      bufSphere = VertexBuffer.Create(
          [ { data : sphere_pts, attrSize : 3, attrLoc : progDraw.inPos } ],
          sphere_inx );
        
      window.onresize = resize;
      resize();
      requestAnimationFrame(render);
  }
  
  function Fract( val ) { 
      return val - Math.trunc( val );
  }
  function CalcAng( deltaTime, intervall ) {
      return Fract( deltaTime / (1000*intervall) ) * 2.0 * Math.PI;
  }
  function CalcMove( deltaTime, intervall, range ) {
      var pos = self.Fract( deltaTime / (1000*intervall) ) * 2.0
      var pos = pos < 1.0 ? pos : (2.0-pos)
      return range[0] + (range[1] - range[0]) * pos;
  }    
  function EllipticalPosition( a, b, angRag ) {
      var a_b = a * a - b * b
      var ea = (a_b <= 0) ? 0 : Math.sqrt( a_b );
      var eb = (a_b >= 0) ? 0 : Math.sqrt( -a_b );
      return [ a * Math.sin( angRag ) - ea, b * Math.cos( angRag ) - eb, 0 ];
  }
  
  glArrayType = typeof Float32Array !="undefined" ? Float32Array : ( typeof WebGLFloatArray != "undefined" ? WebGLFloatArray : Array );
  
  function IdentityMat44() {
    var m = new glArrayType(16);
    m[0]  = 1; m[1]  = 0; m[2]  = 0; m[3]  = 0;
    m[4]  = 0; m[5]  = 1; m[6]  = 0; m[7]  = 0;
    m[8]  = 0; m[9]  = 0; m[10] = 1; m[11] = 0;
    m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1;
    return m;
  };
  
  function RotateAxis(matA, angRad, axis) {
      var aMap = [ [1, 2], [2, 0], [0, 1] ];
      var a0 = aMap[axis][0], a1 = aMap[axis][1]; 
      var sinAng = Math.sin(angRad), cosAng = Math.cos(angRad);
      var matB = new glArrayType(16);
      for ( var i = 0; i < 16; ++ i ) matB[i] = matA[i];
      for ( var i = 0; i < 3; ++ i ) {
          matB[a0*4+i] = matA[a0*4+i] * cosAng + matA[a1*4+i] * sinAng;
          matB[a1*4+i] = matA[a0*4+i] * -sinAng + matA[a1*4+i] * cosAng;
      }
      return matB;
  }
  
  function Cross( a, b ) { return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0], 0.0 ]; }
  function Dot( a, b ) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; }
  function Normalize( v ) {
      var len = Math.sqrt( v[0] * v[0] + v[1] * v[1] + v[2] * v[2] );
      return [ v[0] / len, v[1] / len, v[2] / len ];
  }
  
  var Camera = {};
  Camera.create = function() {
      this.pos    = [0, 1.5, 0.0];
      this.target = [0, 0, 0];
      this.up     = [0, 0, 1];
      this.fov_y  = 90;
      this.vp     = [800, 600];
      this.near   = 0.5;
      this.far    = 100.0;
  }
  Camera.Perspective = function() {
      var fn = this.far + this.near;
      var f_n = this.far - this.near;
      var r = this.vp[0] / this.vp[1];
      var t = 1 / Math.tan( Math.PI * this.fov_y / 360 );
      var m = IdentityMat44();
      m[0]  = t/r; m[1]  = 0; m[2]  =  0;                              m[3]  = 0;
      m[4]  = 0;   m[5]  = t; m[6]  =  0;                              m[7]  = 0;
      m[8]  = 0;   m[9]  = 0; m[10] = -fn / f_n;                       m[11] = -1;
      m[12] = 0;   m[13] = 0; m[14] = -2 * this.far * this.near / f_n; m[15] =  0;
      return m;
  }
  Camera.LookAt = function() {
      var mz = Normalize( [ this.pos[0]-this.target[0], this.pos[1]-this.target[1], this.pos[2]-this.target[2] ] );
      var mx = Normalize( Cross( this.up, mz ) );
      var my = Normalize( Cross( mz, mx ) );
      var tx = Dot( mx, this.pos );
      var ty = Dot( my, this.pos );
      var tz = Dot( [-mz[0], -mz[1], -mz[2]], this.pos ); 
      var m = IdentityMat44();
      m[0]  = mx[0]; m[1]  = my[0]; m[2]  = mz[0]; m[3]  = 0;
      m[4]  = mx[1]; m[5]  = my[1]; m[6]  = mz[1]; m[7]  = 0;
      m[8]  = mx[2]; m[9]  = my[2]; m[10] = mz[2]; m[11] = 0;
      m[12] = tx;    m[13] = ty;    m[14] = tz;    m[15] = 1; 
      return m;
  } 
  
  var ShaderProgram = {};
  ShaderProgram.Create = function( shaderList ) {
      var shaderObjs = [];
      for ( var i_sh = 0; i_sh < shaderList.length; ++ i_sh ) {
          var shderObj = this.CompileShader( shaderList[i_sh].source, shaderList[i_sh].stage );
          if ( shderObj == 0 )
              return 0;
          shaderObjs.push( shderObj );
      }
      var progObj = this.LinkProgram( shaderObjs )
      if ( progObj != 0 ) {
          progObj.attribIndex = {};
          var noOfAttributes = gl.getProgramParameter( progObj, gl.ACTIVE_ATTRIBUTES );
          for ( var i_n = 0; i_n < noOfAttributes; ++ i_n ) {
              var name = gl.getActiveAttrib( progObj, i_n ).name;
              progObj.attribIndex[name] = gl.getAttribLocation( progObj, name );
          }
          progObj.unifomLocation = {};
          var noOfUniforms = gl.getProgramParameter( progObj, gl.ACTIVE_UNIFORMS );
          for ( var i_n = 0; i_n < noOfUniforms; ++ i_n ) {
              var name = gl.getActiveUniform( progObj, i_n ).name;
              progObj.unifomLocation[name] = gl.getUniformLocation( progObj, name );
          }
      }
      return progObj;
  }
  ShaderProgram.AttributeIndex = function( progObj, name ) { return progObj.attribIndex[name]; } 
  ShaderProgram.UniformLocation = function( progObj, name ) { return progObj.unifomLocation[name]; } 
  ShaderProgram.Use = function( progObj ) { gl.useProgram( progObj ); } 
  ShaderProgram.SetUniformI1  = function( progObj, name, val ) { if(progObj.unifomLocation[name]) gl.uniform1i( progObj.unifomLocation[name], val ); }
  ShaderProgram.SetUniformF1  = function( progObj, name, val ) { if(progObj.unifomLocation[name]) gl.uniform1f( progObj.unifomLocation[name], val ); }
  ShaderProgram.SetUniformF2  = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform2fv( progObj.unifomLocation[name], arr ); }
  ShaderProgram.SetUniformF3  = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform3fv( progObj.unifomLocation[name], arr ); }
  ShaderProgram.SetUniformF4  = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform4fv( progObj.unifomLocation[name], arr ); }
  ShaderProgram.SetUniformM33 = function( progObj, name, mat ) { if(progObj.unifomLocation[name]) gl.uniformMatrix3fv( progObj.unifomLocation[name], false, mat ); }
  ShaderProgram.SetUniformM44 = function( progObj, name, mat ) { if(progObj.unifomLocation[name]) gl.uniformMatrix4fv( progObj.unifomLocation[name], false, mat ); }
  ShaderProgram.CompileShader = function( source, shaderStage ) {
      var shaderScript = document.getElementById(source);
      if (shaderScript)
        source = shaderScript.text;
      var shaderObj = gl.createShader( shaderStage );
      gl.shaderSource( shaderObj, source );
      gl.compileShader( shaderObj );
      var status = gl.getShaderParameter( shaderObj, gl.COMPILE_STATUS );
      if ( !status ) alert(gl.getShaderInfoLog(shaderObj));
      return status ? shaderObj : null;
  } 
  ShaderProgram.LinkProgram = function( shaderObjs ) {
      var prog = gl.createProgram();
      for ( var i_sh = 0; i_sh < shaderObjs.length; ++ i_sh )
          gl.attachShader( prog, shaderObjs[i_sh] );
      gl.linkProgram( prog );
      status = gl.getProgramParameter( prog, gl.LINK_STATUS );
      if ( !status ) alert("Could not initialise shaders");
      gl.useProgram( null );
      return status ? prog : null;
  }
  
  var VertexBuffer = {};
  VertexBuffer.Create = function( attributes, indices ) {
      var buffer = {};
      buffer.buf = [];
      buffer.attr = []
      for ( var i = 0; i < attributes.length; ++ i ) {
          buffer.buf.push( gl.createBuffer() );
          buffer.attr.push( { size : attributes[i].attrSize, loc : attributes[i].attrLoc } );
          gl.bindBuffer( gl.ARRAY_BUFFER, buffer.buf[i] );
          gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( attributes[i].data ), gl.STATIC_DRAW );
      }
      buffer.inx = gl.createBuffer();
      gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, buffer.inx );
      gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( indices ), gl.STATIC_DRAW );
      buffer.inxLen = indices.length;
      gl.bindBuffer( gl.ARRAY_BUFFER, null );
      gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null );
      return buffer;
  }
  VertexBuffer.Draw = function( bufObj ) {
    for ( var i = 0; i < bufObj.buf.length; ++ i ) {
          gl.bindBuffer( gl.ARRAY_BUFFER, bufObj.buf[i] );
          gl.vertexAttribPointer( bufObj.attr[i].loc, bufObj.attr[i].size, gl.FLOAT, false, 0, 0 );
          gl.enableVertexAttribArray( bufObj.attr[i].loc );
      }
      gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufObj.inx );
      gl.drawElements( gl.TRIANGLES, bufObj.inxLen, gl.UNSIGNED_SHORT, 0 );
      for ( var i = 0; i < bufObj.buf.length; ++ i )
         gl.disableVertexAttribArray( bufObj.attr[i].loc );
      gl.bindBuffer( gl.ARRAY_BUFFER, null );
      gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null );
  }
  
  initScene();
  
  })();

html,body {
    height: 100%;
    width: 100%;
    margin: 0;
    overflow: hidden;
}

#gui {
    position : absolute;
    top : 0;
    left : 0;
}

<script id="draw-shader-vs" type="x-shader/x-vertex">
    precision mediump float;
    
    attribute vec3 inPos;
    
    varying vec3 v_normal;

    uniform mat4 u_projectionMat44;
    uniform mat4 u_viewMat44;
    uniform mat4 u_modelMat44;
    
    void main()
    {
        vec3  modelNV = mat3( u_modelMat44 ) * normalize( inPos );
        vec3  normalV = mat3( u_viewMat44 ) * modelNV;
        v_normal      = normalV;

        vec4 modelPos = u_modelMat44 * vec4( inPos, 1.0 );
        vec4 viewPos  = u_viewMat44 * modelPos;
        gl_Position   = u_projectionMat44 * viewPos;
}
</script>
  
<script id="draw-shader-fs" type="x-shader/x-fragment">
    precision mediump float;
    
    varying vec3 v_normal;
    
    uniform vec3 u_lightDir;
    uniform vec3 u_color;

    void main()
    {
        vec3  normalV  = normalize( v_normal );
        vec3  lightV   = normalize( -u_lightDir );
        float NdotL    = max( 0.0, dot( normalV, lightV ) );

        vec3 lightCol  = (0.2 + 0.8 * NdotL) * u_color;
        gl_FragColor   = vec4( lightCol.rgb, 1.0 );
    }
</script>

<canvas id="canvas" style="border: none;" width="100%" height="100%"></canvas>

这篇关于光照模型的计算在着色器程序中是如何工作的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆