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

来源:互联网 发布:钢结构节点分析软件 编辑:程序博客网 时间:2024/06/05 06:05
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 };
原创粉丝点击