浅谈Three.js源码-render之SpritePlugin.js

import { Texture } from '../../../textures/Texture';
import { Vector3 } from '../../../math/Vector3';
import { Quaternion } from '../../../math/Quaternion';

/**当场景中需要添加不被遮挡的热点信息时,就需要使用到精灵类了。
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/

 */

function SpritePlugin( renderer, sprites ) {//threejs中精灵的管理类

   var gl = renderer.context;//WebGL上下文
   var state = renderer.state;//当前WebGL的状态管理对象

   var vertexBuffer, elementBuffer;//精灵对象需要的顶点缓冲对象和索引缓冲区
   var program, attributes, uniforms;//shader的程序编号、attribute和uniform值

   var texture;//精灵所需要的纹理

   // decompose matrixWorld

   var spritePosition = new Vector3();//精灵的位置
   var spriteRotation = new Quaternion();//精灵旋转的四元数
   var spriteScale = new Vector3();//精灵的缩放倍数

   function init() {//初始化精灵的方法

      var vertices = new Float32Array( [//构建精灵所需要的顶点坐标信息
         - 0.5, - 0.5,  0, 0,
           0.5, - 0.5,  1, 0,
           0.5,   0.5,  1, 1,
         - 0.5,   0.5,  0, 1
      ] );

      var faces = new Uint16Array( [//索引信息
         0, 1, 2,
         0, 2, 3
      ] );

      vertexBuffer  = gl.createBuffer();//创建顶点缓冲区
      elementBuffer = gl.createBuffer();//创建索引缓冲区

      gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );//绑定顶点缓冲区
      gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW );//初始化顶点缓冲区

      gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );//绑定索引缓冲区
      gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW );//初始化索引缓冲区

      program = createProgram();//创建着色器程序

      attributes = {
         position:        gl.getAttribLocation ( program, 'position' ),     //顶点坐标
         uv:                gl.getAttribLocation ( program, 'uv' )          //纹理坐标
      };

      uniforms = {
         uvOffset:        gl.getUniformLocation( program, 'uvOffset' ),     //纹理的偏移量
         uvScale:         gl.getUniformLocation( program, 'uvScale' ),      //纹理的缩放值

         rotation:        gl.getUniformLocation( program, 'rotation' ),     //旋转四元数
         scale:          gl.getUniformLocation( program, 'scale' ),

         color:          gl.getUniformLocation( program, 'color' ),
         map:            gl.getUniformLocation( program, 'map' ),         //精灵上的贴图
         opacity:         gl.getUniformLocation( program, 'opacity' ),      //精灵的透明度

         modelViewMatrix:   gl.getUniformLocation( program, 'modelViewMatrix' ),   //模-视矩阵
         projectionMatrix:  gl.getUniformLocation( program, 'projectionMatrix' ),  //投影矩阵

         fogType:         gl.getUniformLocation( program, 'fogType' ),         //雾的类型
         fogDensity:          gl.getUniformLocation( program, 'fogDensity' ),    //雾的密度
         fogNear:         gl.getUniformLocation( program, 'fogNear' ),         //雾的近平面
         fogFar:             gl.getUniformLocation( program, 'fogFar' ),             //雾的远平面
         fogColor:        gl.getUniformLocation( program, 'fogColor' ),        //雾的颜色

         alphaTest:       gl.getUniformLocation( program, 'alphaTest' )        //透明度检测
      };

      var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );//创建canvas对象
      canvas.width = 8;                                               //设置canvas的长和宽
      canvas.height = 8;

      var context = canvas.getContext( '2d' );                              //获取canvas的上下文
      context.fillStyle = 'white';                                       //设置白色背景
      context.fillRect( 0, 0, 8, 8 );                                        //使用白色进行填充

      texture = new Texture( canvas );                                    //将canvas作为纹理
      texture.needsUpdate = true;                                        //更新纹理对象

   }

   this.render = function ( scene, camera ) {                               //精灵的绘制方法

      if ( sprites.length === 0 ) return;

      // setup gl

      if ( program === undefined ) {                                     //如果没有指定着色器程序编号

         init();                                                       //对着色器程序进行初始化

      }

      gl.useProgram( program );                                         //指定使用的着色器程序

      state.initAttributes();                                              //重置webGL的状态
      state.enableAttribute( attributes.position );                          //开启顶点坐标数组
      state.enableAttribute( attributes.uv );                                  //开启纹理坐标数组
      state.disableUnusedAttributes();                                    //禁用所有没使用到的属性

      state.disable( gl.CULL_FACE );                                     //关闭背面剪裁
      state.enable( gl.BLEND );                                         //开启混合

      gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );                            //绑定顶点坐标缓冲
      gl.vertexAttribPointer( attributes.position, 2, gl.FLOAT, false, 2 * 8, 0 );   //指定定点坐标缓冲区数据的位置和格式
      gl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 );       //指定纹理坐标缓冲区数据的位置和格式

      gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );                  //绑定索引缓冲区

      gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements );//将投影矩阵传入渲染管线

      state.activeTexture( gl.TEXTURE0 );                                     //激活对应纹理?????????
      gl.uniform1i( uniforms.map, 0 );                                    //将纹理图传入渲染管线中

      var oldFogType = 0;
      var sceneFogType = 0;
      var fog = scene.fog;

      if ( fog ) {//两种雾的实现方法

         gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b );

         if ( fog.isFog ) {

            gl.uniform1f( uniforms.fogNear, fog.near );
            gl.uniform1f( uniforms.fogFar, fog.far );

            gl.uniform1i( uniforms.fogType, 1 );
            oldFogType = 1;
            sceneFogType = 1;

         } else if ( fog.isFogExp2 ) {

            gl.uniform1f( uniforms.fogDensity, fog.density );

            gl.uniform1i( uniforms.fogType, 2 );
            oldFogType = 2;
            sceneFogType = 2;

         }

      } else {

         gl.uniform1i( uniforms.fogType, 0 );
         oldFogType = 0;
         sceneFogType = 0;

      }


      // update positions and sort

      for ( var i = 0, l = sprites.length; i < l; i ++ ) {

         var sprite = sprites[ i ];

         sprite.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld );//更新精灵图的模-视矩阵
         sprite.z = - sprite.modelViewMatrix.elements[ 14 ];//获取精灵在摄像机视图下的Z值 (其实也就是深度值)

      }

      sprites.sort( painterSortStable );//根据精灵的深度值进行排序,确定渲染顺序(肯定是需要先绘制远处的精灵,再绘制近处的,否则遮挡顺序就不对咯)

      // render all sprites

      var scale = [];

      for ( var i = 0, l = sprites.length; i < l; i ++ ) {

         var sprite = sprites[ i ];//获取精灵对象
         var material = sprite.material;//获取精灵的材质

         if ( material.visible === false ) continue;//如果该精灵不可见  直接跳出

         sprite.onBeforeRender( renderer, scene, camera, undefined, material, undefined );//??????????????????????搜索一下再写

         gl.uniform1f( uniforms.alphaTest, material.alphaTest );
         gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite.modelViewMatrix.elements );

         sprite.matrixWorld.decompose( spritePosition, spriteRotation, spriteScale );//根据各种属性 生成精灵的世界坐标矩阵

         /*
         传入各种着色器中用到的变量
         * */
         scale[ 0 ] = spriteScale.x;
         scale[ 1 ] = spriteScale.y;

         var fogType = 0;

         if ( scene.fog && material.fog ) {

            fogType = sceneFogType;

         }

         if ( oldFogType !== fogType ) {

            gl.uniform1i( uniforms.fogType, fogType );
            oldFogType = fogType;

         }

         if ( material.map !== null ) {

            gl.uniform2f( uniforms.uvOffset, material.map.offset.x, material.map.offset.y );
            gl.uniform2f( uniforms.uvScale, material.map.repeat.x, material.map.repeat.y );

         } else {

            gl.uniform2f( uniforms.uvOffset, 0, 0 );
            gl.uniform2f( uniforms.uvScale, 1, 1 );

         }

         gl.uniform1f( uniforms.opacity, material.opacity );
         gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b );

         gl.uniform1f( uniforms.rotation, material.rotation );
         gl.uniform2fv( uniforms.scale, scale );

         state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha );
         state.buffers.depth.setTest( material.depthTest );//开启深度测试
         state.buffers.depth.setMask( material.depthWrite );//开启深度写入

         if ( material.map ) {

            renderer.setTexture2D( material.map, 0 );

         } else {

            renderer.setTexture2D( texture, 0 );

         }

         gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );//进行绘制

         sprite.onAfterRender( renderer, scene, camera, undefined, material, undefined );

      }

      // restore gl

      state.enable( gl.CULL_FACE );

      renderer.resetGLState();

   };

   function createProgram() {//创建绘制精灵所用的着色器

      var program = gl.createProgram();

      var vertexShader = gl.createShader( gl.VERTEX_SHADER );
      var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );

      //*顶点着色器内容*/
      gl.shaderSource( vertexShader, [

         'precision ' + renderer.getPrecision() + ' float;',

         '#define SHADER_NAME ' + 'SpriteMaterial',

         'uniform mat4 modelViewMatrix;',
         'uniform mat4 projectionMatrix;',
         'uniform float rotation;',
         'uniform vec2 scale;',
         'uniform vec2 uvOffset;',
         'uniform vec2 uvScale;',

         'attribute vec2 position;',
         'attribute vec2 uv;',

         'varying vec2 vUV;',

         'void main() {',

            'vUV = uvOffset + uv * uvScale;',

            'vec2 alignedPosition = position * scale;',

            'vec2 rotatedPosition;',
            'rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;',
            'rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;',

            'vec4 finalPosition;',

            'finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );',
            'finalPosition.xy += rotatedPosition;',
            'finalPosition = projectionMatrix * finalPosition;',

            'gl_Position = finalPosition;',

         '}'

      ].join( '\n' ) );
      /*片元着色器内容*/
      gl.shaderSource( fragmentShader, [

         'precision ' + renderer.getPrecision() + ' float;',

         '#define SHADER_NAME ' + 'SpriteMaterial',

         'uniform vec3 color;',
         'uniform sampler2D map;',
         'uniform float opacity;',

         'uniform int fogType;',
         'uniform vec3 fogColor;',
         'uniform float fogDensity;',
         'uniform float fogNear;',
         'uniform float fogFar;',
         'uniform float alphaTest;',

         'varying vec2 vUV;',

         'void main() {',

            'vec4 texture = texture2D( map, vUV );',

            'if ( texture.a < alphaTest ) discard;',//如果当前片元中的透明度小于alphaTest直接舍弃,

            'gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );',

            'if ( fogType > 0 ) {',/*下面是两种雾的着色器实现*/

               'float depth = gl_FragCoord.z / gl_FragCoord.w;',
               'float fogFactor = 0.0;',

               'if ( fogType == 1 ) {',

                  'fogFactor = smoothstep( fogNear, fogFar, depth );',

               '} else {',

                  'const float LOG2 = 1.442695;',
                  'fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );',
                  'fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );',

               '}',

               'gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );',

            '}',

         '}'

      ].join( '\n' ) );

      gl.compileShader( vertexShader );
      gl.compileShader( fragmentShader );

      gl.attachShader( program, vertexShader );
      gl.attachShader( program, fragmentShader );

      gl.linkProgram( program );

      return program;

   }

   function painterSortStable( a, b ) {

      if ( a.renderOrder !== b.renderOrder ) {

         return a.renderOrder - b.renderOrder;

      } else if ( a.z !== b.z ) {

         return b.z - a.z;

      } else {

         return b.id - a.id;

      }

   }

}


export { SpritePlugin };
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值