浅谈Three.js源码-render之WebGLState.js(重要)

来源:互联网 发布:遗传算法视频讲解 编辑:程序博客网 时间:2024/06/04 20:05

    不好意思,这段时间买了本书多瞅了几眼,更新速度有点慢了,大家多多谅解 嘿嘿嘿。

咱们闲话少说,下面将给出WebGLState.js的源码注释。WebGL可以说是一个状态机,程序中多个API控制着多种功能的开启和显示,而WebGLState.js算是render中最最重要的脚本了,总体控制着程序的渲染工作,代码如下。

/** * @author mrdoob / http://mrdoob.com/ */import { NotEqualDepth, GreaterDepth, GreaterEqualDepth, EqualDepth, LessEqualDepth, LessDepth, AlwaysDepth, NeverDepth, CullFaceFront, CullFaceBack, CullFaceNone, CustomBlending, MultiplyBlending, SubtractiveBlending, AdditiveBlending, NoBlending, NormalBlending, DoubleSide, BackSide } from '../../constants';import { Vector4 } from '../../math/Vector4';function WebGLState( gl, extensions, paramThreeToGL ) {   function ColorBuffer() {//颜色缓冲      var locked = false;//是否加锁      var color = new Vector4();//创建颜色值      var currentColorMask = null;//当前能否写入颜色帧缓冲区      var currentColorClear = new Vector4();//当前背景的渲染颜色      return {         setMask: function ( colorMask ) {//设置能否写入颜色帧缓冲区            if ( currentColorMask !== colorMask && ! locked ) {//如果用户改变了颜色帧缓冲区的写入状态并且没有加锁               gl.colorMask( colorMask, colorMask, colorMask, colorMask );//重新设置颜色帧缓冲区的写入状态               currentColorMask = colorMask;//记录当前颜色帧缓冲区的状态               /*colorMask为GL_TRUE时,程序允许对颜色帧缓冲区进行修改和写入*/            }         },         setLocked: function ( lock ) {//设置是否加锁,如果lock为true,则表示一直已经加锁,颜色帧缓冲区的写入状态不能改变            locked = lock;         },         setClear: function ( r, g, b, a, premultipliedAlpha ) {//premultipliedAlpha表示是否需要增加透明效果            if ( premultipliedAlpha === true ) {               r *= a; g *= a; b *= a;            }            color.set( r, g, b, a );            if ( currentColorClear.equals( color ) === false ) {               gl.clearColor( r, g, b, a );               currentColorClear.copy( color );            }         },         reset: function () {//重置相关设置            locked = false;            currentColorMask = null;            currentColorClear.set( 0, 0, 0, 1 );         }      };   }   function DepthBuffer() {//关于深度缓冲的设置      var locked = false;//是否加锁      var currentDepthMask = null;//表示是否可以对深度缓冲区进行修改      var currentDepthFunc = null;      var currentDepthClear = null;      return {         setTest: function ( depthTest ) {//设置是否开启深度检测            if ( depthTest ) {               enable( gl.DEPTH_TEST );            } else {               disable( gl.DEPTH_TEST );            }         },         setMask: function ( depthMask ) {//设置是否可以对深度缓冲区进行修改            if ( currentDepthMask !== depthMask && ! locked ) {               gl.depthMask( depthMask );               currentDepthMask = depthMask;            }         },         setFunc: function ( depthFunc ) {            /*            *            *            *            * 关于gl.depthFunc()官方是这样解释的:            * Specifies the depth comparison function.             Symbolic constants             GL_NEVER,             GL_LESS,             GL_EQUAL,             GL_LEQUAL,             GL_GREATER,             GL_NOTEQUAL,             GL_GEQUAL, and             GL_ALWAYS are accepted.             The initial value is GL_LESS.             那么来翻译一下吧。             此函数的作用是确定深度值的比较方式。             每画一个物体,设备中将存储每个像素点的深度值,如果需要新绘制一个物体A,则对应像素处的深度值需要             和深度缓冲区的值进行比较,默认情况下,gl.depthFunc( GL_LESS),也就是在对于某个像素处,A的深度值小于             帧缓冲区中对应的深度值才会取A的颜色,否则不会发生改变。             */            if ( currentDepthFunc !== depthFunc ) {               if ( depthFunc ) {                  switch ( depthFunc ) {                     case NeverDepth:                        gl.depthFunc( gl.NEVER );                        break;                     case AlwaysDepth:                        gl.depthFunc( gl.ALWAYS );                        break;                     case LessDepth:                        gl.depthFunc( gl.LESS );                        break;                     case LessEqualDepth:                        gl.depthFunc( gl.LEQUAL );                        break;                     case EqualDepth:                        gl.depthFunc( gl.EQUAL );                        break;                     case GreaterEqualDepth:                        gl.depthFunc( gl.GEQUAL );                        break;                     case GreaterDepth:                        gl.depthFunc( gl.GREATER );                        break;                     case NotEqualDepth:                        gl.depthFunc( gl.NOTEQUAL );                        break;                     default:                        gl.depthFunc( gl.LEQUAL );                  }               } else {                  gl.depthFunc( gl.LEQUAL );               }               currentDepthFunc = depthFunc;            }         },         setLocked: function ( lock ) {/*                                 表示深度缓冲区设置是否可以进行更改                                 */            locked = lock;         },         setClear: function ( depth ) {//清除深度缓冲区,depth值为要设置的深度缓冲区的值,取值范围为【0-1】            if ( currentDepthClear !== depth ) {               gl.clearDepth( depth );               currentDepthClear = depth;            }         },         reset: function () {//重置关于深度缓冲的相关设置            locked = false;            currentDepthMask = null;            currentDepthFunc = null;            currentDepthClear = null;         }      };   }   /*关于模板测试,有一篇文章写的挺好的,分享给大家,http://blog.csdn.net/wangdingqiaoit/article/details/52143197*/   function StencilBuffer() {//模板缓冲的相关设置,模板缓冲的值取值范围为[0-2的n次方-1],其中n代表模板缓冲值在2进制下      // 的位数,(一般为8位)      //      var locked = false;      var currentStencilMask = null;//设置模板缓冲是否可以写入      var currentStencilFunc = null;//设置模板测试的比较方式      var currentStencilRef = null;      var currentStencilFuncMask = null;      var currentStencilFail = null;      var currentStencilZFail = null;      var currentStencilZPass = null;      var currentStencilClear = null;      return {         setTest: function ( stencilTest ) {//是否开启模板测试            if ( stencilTest ) {               enable( gl.STENCIL_TEST );            } else {               disable( gl.STENCIL_TEST );            }         },         setMask: function ( stencilMask ) {//设置是否可以对模板缓冲区进行写入和修改            if ( currentStencilMask !== stencilMask && ! locked ) {               gl.stencilMask( stencilMask );               currentStencilMask = stencilMask;            }         },         setFunc: function ( stencilFunc, stencilRef, stencilMask ) {//设置模板缓冲的比较方式            if ( currentStencilFunc !== stencilFunc ||                 currentStencilRef     !== stencilRef     ||                 currentStencilFuncMask !== stencilMask ) {               gl.stencilFunc( stencilFunc, stencilRef, stencilMask );               currentStencilFunc = stencilFunc;               currentStencilRef = stencilRef;               currentStencilFuncMask = stencilMask;            }         },         /*stencilFail代表的是模板测试失败,对应模板缓冲区的值应该进行的操作,可选的值有          GL_KEEP,GL_ZERO,GL_REPLACE,GL_INCR,GL_INCR_WRAP,GL_DECR,GL_DECR_WRAP,GL_INVERT          stencilZFail代表的是模板测试成功,但是深度检测没有通过后的操作,可选的值和上面的相同          stencilZPass代表的是模板测试和深度检测都通过时,可选择的值和上面相同*/         setOp: function ( stencilFail, stencilZFail, stencilZPass ) {            if ( currentStencilFail     !== stencilFail   ||                 currentStencilZFail !== stencilZFail ||                 currentStencilZPass !== stencilZPass ) {               gl.stencilOp( stencilFail, stencilZFail, stencilZPass );               currentStencilFail = stencilFail;               currentStencilZFail = stencilZFail;               currentStencilZPass = stencilZPass;            }         },         setLocked: function ( lock ) {            locked = lock;         },         setClear: function ( stencil ) {            if ( currentStencilClear !== stencil ) {               gl.clearStencil( stencil );               currentStencilClear = stencil;            }         },         reset: function () {            locked = false;            currentStencilMask = null;            currentStencilFunc = null;            currentStencilRef = null;            currentStencilFuncMask = null;            currentStencilFail = null;            currentStencilZFail = null;            currentStencilZPass = null;            currentStencilClear = null;         }      };   }   //   var colorBuffer = new ColorBuffer();/*新建颜色缓冲区*/   var depthBuffer = new DepthBuffer();/*新建深度缓冲区*/   var stencilBuffer = new StencilBuffer();/*新建模板缓冲区*/   var maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );//从系统最多支持的顶点属性个数   var newAttributes = new Uint8Array( maxVertexAttributes );   var enabledAttributes = new Uint8Array( maxVertexAttributes );   var attributeDivisors = new Uint8Array( maxVertexAttributes );   var capabilities = {};   var compressedTextureFormats = null;   var currentBlending = null;   var currentBlendEquation = null;   var currentBlendSrc = null;   var currentBlendDst = null;   var currentBlendEquationAlpha = null;   var currentBlendSrcAlpha = null;   var currentBlendDstAlpha = null;   var currentPremultipledAlpha = false;   var currentFlipSided = null;   var currentCullFace = null;   var currentLineWidth = null;   var currentPolygonOffsetFactor = null;   var currentPolygonOffsetUnits = null;   var currentScissorTest = null;   var maxTextures = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS );//单个片段着色器能访问的纹理单元数,最低16,一般16或32   var version = parseFloat( /^WebGL\ ([0-9])/.exec( gl.getParameter( gl.VERSION ) )[ 1 ] );//获取当前WebGL的版本   var lineWidthAvailable = parseFloat( version ) >= 1.0;   var currentTextureSlot = null;   var currentBoundTextures = {};   var currentScissor = new Vector4();   var currentViewport = new Vector4();   function createTexture( type, target, count ) {//type:GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP      var data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4.      var texture = gl.createTexture();//创建纹理单元      gl.bindTexture( type, texture );//将图片和纹理单元绑定      gl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST );//设置纹理缩小取样的方式为最近点采样      gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST );//设置纹理扩大取样的方式为最近点采样      /*      此处就设计到了纹理映射的高级话题,以后再进行专题解析,下面是gl.texParameteri()的官方文档。关于纹理映射的基本知识,可以看一下这里:https://www.web-tinker.com/article/20163.html;       Parameters       target       Specifies the target texture of the active texture unit, which must be either GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP.       pname       Specifies the symbolic name of a texture parameter. pname can be one of the following: GL_TEXTURE_MIN_FILTER, GL_TEXTURE_MAG_FILTER, GL_TEXTURE_WRAP_S, or GL_TEXTURE_WRAP_T.       params       Specifies a pointer to an array where the value of pname is stored.       Description       Texture mapping is a technique that applies an image onto an object's surface as if the image were a decal or cellophane shrink-wrap. The image is created in texture space, with an (s, t) coordinate system. A texture is a two-dimensional or cube-mapped image and a set of parameters that determine how samples are derived from the image.       glTexParameter assigns the value or values in params to the texture parameter specified as pname. target defines the target texture of the active texture unit, either GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP. The following symbols are accepted in pname:       GL_TEXTURE_MIN_FILTER       The texture minifying function is used whenever the pixel being textured maps to an area greater than one texture element. There are six defined minifying functions. Two of them use the nearest one or nearest four texture elements to compute the texture value. The other four use mipmaps.       A mipmap is an ordered set of arrays representing the same image at progressively lower resolutions. If the texture has dimensions w × h , there are floor  log 2  max  w h + 1 mipmap levels. The first mipmap level is the original texture, with dimensions w × h . Each subsequent mipmap level has dimensions max  1 floor  w 2 i × max  1 floor  h 2 i , where i is the mipmap level, until the final mipmap is reached, which has dimension 1 × 1 .       To define the mipmap levels, call glTexImage2D, glCompressedTexImage2D, or glCopyTexImage2D with the level argument indicating the order of the mipmaps. Level 0 is the original texture; level floor  log 2  max  w h is the final 1 × 1 mipmap.       params supplies a function for minifying the texture as one of the following:       GL_NEAREST       Returns the value of the texture element that is nearest (in Manhattan distance) to the center of the pixel being textured.       GL_LINEAR       Returns the weighted average of the four texture elements that are closest to the center of the pixel being textured.       GL_NEAREST_MIPMAP_NEAREST       Chooses the mipmap that most closely matches the size of the pixel being textured and uses the GL_NEAREST criterion (the texture element nearest to the center of the pixel) to produce a texture value.       GL_LINEAR_MIPMAP_NEAREST       Chooses the mipmap that most closely matches the size of the pixel being textured and uses the GL_LINEAR criterion (a weighted average of the four texture elements that are closest to the center of the pixel) to produce a texture value.       GL_NEAREST_MIPMAP_LINEAR       Chooses the two mipmaps that most closely match the size of the pixel being textured and uses the GL_NEAREST criterion (the texture element nearest to the center of the pixel) to produce a texture value from each mipmap. The final texture value is a weighted average of those two values.       GL_LINEAR_MIPMAP_LINEAR       Chooses the two mipmaps that most closely match the size of the pixel being textured and uses the GL_LINEAR criterion (a weighted average of the four texture elements that are closest to the center of the pixel) to produce a texture value from each mipmap. The final texture value is a weighted average of those two values.       As more texture elements are sampled in the minification process, fewer aliasing artifacts will be apparent. While the GL_NEAREST and GL_LINEAR minification functions can be faster than the other four, they sample only one or four texture elements to determine the texture value of the pixel being rendered and can produce moire patterns or ragged transitions. The initial value of GL_TEXTURE_MIN_FILTER is GL_NEAREST_MIPMAP_LINEAR.       GL_TEXTURE_MAG_FILTER       The texture magnification function is used when the pixel being textured maps to an area less than or equal to one texture element. It sets the texture magnification function to either GL_NEAREST or GL_LINEAR (see below). GL_NEAREST is generally faster than GL_LINEAR, but it can produce textured images with sharper edges because the transition between texture elements is not as smooth. The initial value of GL_TEXTURE_MAG_FILTER is GL_LINEAR.       GL_NEAREST       Returns the value of the texture element that is nearest (in Manhattan distance) to the center of the pixel being textured.       GL_LINEAR       Returns the weighted average of the four texture elements that are closest to the center of the pixel being textured.       GL_TEXTURE_WRAP_S       Sets the wrap parameter for texture coordinate s to either GL_CLAMP_TO_EDGE, GL_MIRRORED_REPEAT, or GL_REPEAT. GL_CLAMP_TO_EDGE causes s coordinates to be clamped to the range 1 2N 1 - 1 2N , where N is the size of the texture in the direction of clamping. GL_REPEAT causes the integer part of the s coordinate to be ignored; the GL uses only the fractional part, thereby creating a repeating pattern. GL_MIRRORED_REPEAT causes the s coordinate to be set to the fractional part of the texture coordinate if the integer part of s is even; if the integer part of s is odd, then the s texture coordinate is set to 1 - frac  s , where frac  s represents the fractional part of s. Initially, GL_TEXTURE_WRAP_S is set to GL_REPEAT.       GL_TEXTURE_WRAP_T       Sets the wrap parameter for texture coordinate t to either GL_CLAMP_TO_EDGE, GL_MIRRORED_REPEAT, or GL_REPEAT. See the discussion under GL_TEXTURE_WRAP_S. Initially, GL_TEXTURE_WRAP_T is set to GL_REPEAT.      * */      for ( var i = 0; i < count; i ++ ) {         gl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data );//指定目标纹理的数据和格式      }      return texture;   }   var emptyTextures = {};   emptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 );//初始化2D纹理   emptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 );//初始化立方体纹理   //   function init() {      colorBuffer.setClear( 0, 0, 0, 1 );//设置刷新颜色      depthBuffer.setClear( 1 );//设置深度值      stencilBuffer.setClear( 0 );//设置模板值      enable( gl.DEPTH_TEST );//开启深度检测      depthBuffer.setFunc( LessEqualDepth );//深度值的比较方式是小于等于      setFlipSided( false );//是否开启正反面转换,通常情况下,当观察者从正面看三角形时ti,三角形的构造方式是逆时针的。      // 这样程序会将所有顺时针构造的三角形面当作被遮挡的面进行剔除。从而很大程度上避免了无用的系统开销      setCullFace( CullFaceBack );//设置背面剪裁的方式,一共有三种(1.只显示正面,2.只显示背面,3同时显示正面和背面)      enable( gl.CULL_FACE );//开启背面剪裁      enable( gl.BLEND );//开启混合      setBlending( NormalBlending );//设置混合方式   }   function initAttributes() {//初始化属性数组(WebGL中可支持的属性最多有8种包括 顶点坐标、颜色、纹理坐标、多重纹理坐标、顶点坐标索引等)      for ( var i = 0, l = newAttributes.length; i < l; i ++ ) {         newAttributes[ i ] = 0;      }   }   function enableAttribute( attribute ) {//开启对应的属性数组      newAttributes[ attribute ] = 1;//newAttributes[“属性名” ] = 1;表示应启用对应属性      if ( enabledAttributes[ attribute ] === 0 ) {//如果当前未开启此属性         gl.enableVertexAttribArray( attribute );//开启对应的属性         enabledAttributes[ attribute ] = 1;//表示对应属性已经开启      }      if ( attributeDivisors[ attribute ] !== 0 ) {//?????????????????????????不太明白这里,,望大牛指教         var extension = extensions.get( 'ANGLE_instanced_arrays' );         extension.vertexAttribDivisorANGLE( attribute, 0 );         attributeDivisors[ attribute ] = 0;      }   }   function enableAttributeAndDivisor( attribute, meshPerAttribute ) {//???????????????????????      newAttributes[ attribute ] = 1;      if ( enabledAttributes[ attribute ] === 0 ) {         gl.enableVertexAttribArray( attribute );         enabledAttributes[ attribute ] = 1;      }      if ( attributeDivisors[ attribute ] !== meshPerAttribute ) {         var extension = extensions.get( 'ANGLE_instanced_arrays' );         extension.vertexAttribDivisorANGLE( attribute, meshPerAttribute );         attributeDivisors[ attribute ] = meshPerAttribute;      }   }   function disableUnusedAttributes() {//禁用相关属性数组      for ( var i = 0, l = enabledAttributes.length; i !== l; ++ i ) {         if ( enabledAttributes[ i ] !== newAttributes[ i ] ) {            gl.disableVertexAttribArray( i );            enabledAttributes[ i ] = 0;         }      }   }   function enable( id ) {      if ( capabilities[ id ] !== true ) {         gl.enable( id );         capabilities[ id ] = true;      }   }   function disable( id ) {      if ( capabilities[ id ] !== false ) {         gl.disable( id );         capabilities[ id ] = false;      }   }   function getCompressedTextureFormats() {//得到压缩纹理格式      if ( compressedTextureFormats === null ) {         compressedTextureFormats = [];         if ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) ||              extensions.get( 'WEBGL_compressed_texture_s3tc' ) ||              extensions.get( 'WEBGL_compressed_texture_etc1' ) ) {            var formats = gl.getParameter( gl.COMPRESSED_TEXTURE_FORMATS );            for ( var i = 0; i < formats.length; i ++ ) {               compressedTextureFormats.push( formats[ i ] );            }         }      }      return compressedTextureFormats;   }   function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) {//设置颜色混合的多种方式和比例      if ( blending !== NoBlending ) {         enable( gl.BLEND );      } else {         disable( gl.BLEND );      }      if ( ( blending !== CustomBlending ) && ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) ) {         if ( blending === AdditiveBlending ) {            if ( premultipliedAlpha ) {               gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );               gl.blendFuncSeparate( gl.ONE, gl.ONE, gl.ONE, gl.ONE );            } else {               gl.blendEquation( gl.FUNC_ADD );               gl.blendFunc( gl.SRC_ALPHA, gl.ONE );            }         } else if ( blending === SubtractiveBlending ) {            if ( premultipliedAlpha ) {               gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );               gl.blendFuncSeparate( gl.ZERO, gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ONE_MINUS_SRC_ALPHA );            } else {               gl.blendEquation( gl.FUNC_ADD );               gl.blendFunc( gl.ZERO, gl.ONE_MINUS_SRC_COLOR );            }         } else if ( blending === MultiplyBlending ) {            if ( premultipliedAlpha ) {               gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );               gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA );            } else {               gl.blendEquation( gl.FUNC_ADD );               gl.blendFunc( gl.ZERO, gl.SRC_COLOR );            }         } else {            if ( premultipliedAlpha ) {               gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );               gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );            } else {               gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );               gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );            }         }         currentBlending = blending;         currentPremultipledAlpha = premultipliedAlpha;      }      if ( blending === CustomBlending ) {         blendEquationAlpha = blendEquationAlpha || blendEquation;         blendSrcAlpha = blendSrcAlpha || blendSrc;         blendDstAlpha = blendDstAlpha || blendDst;         if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) {            gl.blendEquationSeparate( paramThreeToGL( blendEquation ), paramThreeToGL( blendEquationAlpha ) );            currentBlendEquation = blendEquation;            currentBlendEquationAlpha = blendEquationAlpha;         }         if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) {            gl.blendFuncSeparate( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ), paramThreeToGL( blendSrcAlpha ), paramThreeToGL( blendDstAlpha ) );            currentBlendSrc = blendSrc;            currentBlendDst = blendDst;            currentBlendSrcAlpha = blendSrcAlpha;            currentBlendDstAlpha = blendDstAlpha;         }      } else {         currentBlendEquation = null;         currentBlendSrc = null;         currentBlendDst = null;         currentBlendEquationAlpha = null;         currentBlendSrcAlpha = null;         currentBlendDstAlpha = null;      }   }   function setMaterial( material ) {      material.side === DoubleSide         ? disable( gl.CULL_FACE )         : enable( gl.CULL_FACE );      setFlipSided( material.side === BackSide );      material.transparent === true         ? setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha )         : setBlending( NoBlending );      depthBuffer.setFunc( material.depthFunc );      depthBuffer.setTest( material.depthTest );      depthBuffer.setMask( material.depthWrite );      colorBuffer.setMask( material.colorWrite );      setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );   }   //   function setFlipSided( flipSided ) {      if ( currentFlipSided !== flipSided ) {         if ( flipSided ) {            gl.frontFace( gl.CW );         } else {            gl.frontFace( gl.CCW );         }         currentFlipSided = flipSided;      }   }   function setCullFace( cullFace ) {      if ( cullFace !== CullFaceNone ) {         enable( gl.CULL_FACE );         if ( cullFace !== currentCullFace ) {            if ( cullFace === CullFaceBack ) {               gl.cullFace( gl.BACK );            } else if ( cullFace === CullFaceFront ) {               gl.cullFace( gl.FRONT );            } else {               gl.cullFace( gl.FRONT_AND_BACK );            }         }      } else {         disable( gl.CULL_FACE );      }      currentCullFace = cullFace;   }   function setLineWidth( width ) {      if ( width !== currentLineWidth ) {         if ( lineWidthAvailable ) gl.lineWidth( width );         currentLineWidth = width;      }   }   function setPolygonOffset( polygonOffset, factor, units ) {//设置多边形偏移量,此方法可以有效解决Z-fight问题。      // 详情请看这里:http://www.cnblogs.com/bitzhuwei/archive/2015/06/12/4571539.html      if ( polygonOffset ) {         enable( gl.POLYGON_OFFSET_FILL );         if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) {            gl.polygonOffset( factor, units );            currentPolygonOffsetFactor = factor;            currentPolygonOffsetUnits = units;         }      } else {         disable( gl.POLYGON_OFFSET_FILL );      }   }   function getScissorTest() {      return currentScissorTest;   }   function setScissorTest( scissorTest ) {//是否进行模板测试      currentScissorTest = scissorTest;      if ( scissorTest ) {         enable( gl.SCISSOR_TEST );      } else {         disable( gl.SCISSOR_TEST );      }   }   // texture   function activeTexture( webglSlot ) {      if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1;      if ( currentTextureSlot !== webglSlot ) {         gl.activeTexture( webglSlot );         currentTextureSlot = webglSlot;      }   }   function bindTexture( webglType, webglTexture ) {      if ( currentTextureSlot === null ) {         activeTexture();      }      var boundTexture = currentBoundTextures[ currentTextureSlot ];      if ( boundTexture === undefined ) {         boundTexture = { type: undefined, texture: undefined };         currentBoundTextures[ currentTextureSlot ] = boundTexture;      }      if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) {         gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] );         boundTexture.type = webglType;         boundTexture.texture = webglTexture;      }   }   function compressedTexImage2D() {      try {         gl.compressedTexImage2D.apply( gl, arguments );      } catch ( error ) {         console.error( 'THREE.WebGLState:', error );      }   }   function texImage2D() {      try {         gl.texImage2D.apply( gl, arguments );      } catch ( error ) {         console.error( 'THREE.WebGLState:', error );      }   }   //   function scissor( scissor ) {      if ( currentScissor.equals( scissor ) === false ) {         gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w );         currentScissor.copy( scissor );      }   }   function viewport( viewport ) {      if ( currentViewport.equals( viewport ) === false ) {         gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );         currentViewport.copy( viewport );      }   }   //   function reset() {      for ( var i = 0; i < enabledAttributes.length; i ++ ) {         if ( enabledAttributes[ i ] === 1 ) {            gl.disableVertexAttribArray( i );            enabledAttributes[ i ] = 0;         }      }      capabilities = {};      compressedTextureFormats = null;      currentTextureSlot = null;      currentBoundTextures = {};      currentBlending = null;      currentFlipSided = null;      currentCullFace = null;      colorBuffer.reset();      depthBuffer.reset();      stencilBuffer.reset();   }   return {      buffers: {         color: colorBuffer,         depth: depthBuffer,         stencil: stencilBuffer      },      init: init,      initAttributes: initAttributes,      enableAttribute: enableAttribute,      enableAttributeAndDivisor: enableAttributeAndDivisor,      disableUnusedAttributes: disableUnusedAttributes,      enable: enable,      disable: disable,      getCompressedTextureFormats: getCompressedTextureFormats,      setBlending: setBlending,      setMaterial: setMaterial,      setFlipSided: setFlipSided,      setCullFace: setCullFace,      setLineWidth: setLineWidth,      setPolygonOffset: setPolygonOffset,      getScissorTest: getScissorTest,      setScissorTest: setScissorTest,      activeTexture: activeTexture,      bindTexture: bindTexture,      compressedTexImage2D: compressedTexImage2D,      texImage2D: texImage2D,      scissor: scissor,      viewport: viewport,      reset: reset   };}export { WebGLState };