这种伪造的灯光如何作用于气动扭力? [英] How does this faking the light work on aerotwist?

查看:70
本文介绍了这种伪造的灯光如何作用于气动扭力?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试阅读本教程:

I am trying to read up this tutorial:

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

但是我无法跟进.基本上,代码通过使用直接在GPU上运行的着色器来创建定向光.这是代码:

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));

顶点vNormal与光的点积如何创建定向光.有人可以用图解的方式解释我吗?我无法得到它.在我看来,这有点不可思议.我知道在此顶点着色器中,每个顶点都作为输入传递,这称为法线,因为它以"1"表示,然后在上面的片段着色器代码中使用了共享变量.但是除此之外,我不知道它是如何工作的.

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.

附言::我本可以问博客作者,但据我所知,他正休假2周.因此,我认为具有某些物理或Three.js经验的人也许可以告诉我.

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.

推荐答案

朗伯反射模型

要建模计算机图形中的光反射,请使用双向反射率分布函数(BRDF). BRDF是一种功能,它可以给出沿出射方向反射的光与从出射方向入射的光之间的关系.

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.

一个完美的漫反射表面具有一个BRDF,该BRDF对于所有入射和出射方向都具有相同的值.这大大减少了计算量,因此,即使在现实世界中没有纯粹的漫反射材料,它在物理上也很合理,因此通常用于对漫反射表面进行建模.这种BRDF被称为Lambertian反射,因为它遵循Lambert的余弦定律.

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.

朗伯反射通常用作漫反射的模型.这项技术可使所有闭合的多边形(例如3D网格中的三角形)在渲染时在所有方向均等地反射光.扩散系数是从法向矢量和光矢量之间的角度计算的.

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 )

其中N是表面的法线向量,L是朝向光源的向量.

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

通常,两个向量的 dot 乘积等于两个向量之间的角度的 cosine 乘以两个向量的大小(长度).

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 ) 

因此,由于一个单位矢量的长度为1,所以两个单位矢量的 dot 乘积等于两个矢量之间的角度的 cosine .

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 )

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

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°.

此行为正是反射模型所需要的.当表面的矢量与光源的方向相同(方向之间的夹角为0°)时,我们需要最大的反射率. 相反,如果向量是正交的(两者之间的夹角为90°),则我们需要最小的反射,并且我们希望在0°和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:

另请参阅:

  • GLSL fixed function fragment program replacement
  • Phong lighting: add specular lighting separately or with ambient and diffuse?

(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天全站免登陆