了解 WebGL 状态

Understanding WebGL State

是否有任何我可以在某处找到的文档记录了 WebGL 调用所需的先决条件?

我已经相当深入地掌握了 WebGL 的基础知识,但现在我正在创建自己的 'framework' 并且需要更深入的理解。

例如,enableVertexAttribArray 调用。此调用是否要求当前着色器位于 'use' 中?它在哪里存储这个 'enabled' 标志?如果我切换着色器程序,以后再次使用它时是否必须重新启用它?

我想要某种图表来解释所有 'stateful' 信息的存储位置,以及何时会脱离上下文。

另一个例子是使用 gl.bindBuffer,ARRAY_BUFFER 和 ELEMENT_ARRAY_BUFFER 的缓冲区是否存储在不同的位置?

考虑到所有这些,是否建议在 JavaScript 中使用并行状态以避免 运行 WebGL 调用?即存储一个 'currentBuffer' 对象以避免在已经绑定的情况下一遍又一遍地绑定相同的缓冲区。我可以想象在一般情况下,这会变成相当多的状态重复,但对于性能来说可能会非常好。

有点基本问题,但很难找到相关信息。

我最近给出了类似的答案,但我只是说有很多并且给了规范 link,没有复制粘贴任何东西。吸取教训,我可以解决这个问题。但只是一个公平的警告,如果人们称 WebGL "stateful" 他们 是认真的 。但是包含 WebGL 在哪些条件下可以生成的所有错误的文档称为规范。我不会复制所有可能的错误,因为这很容易使错误加倍,甚至更多。

首先,因为您明确询问了绑定目标,下面是您查询所有这些目标的方式,不包括扩展名:

gl.getParameter( gl.ARRAY_BUFFER_BINDING);
gl.getParameter( gl.ELEMENT_ARRAY_BUFFER_BINDING);
gl.getParameter( gl.FRAMEBUFFER_BINDING);
gl.getParameter( gl.RENDERBUFFER_BINDING);
gl.getParameter( gl.TEXTURE_BINDING_2D);
gl.getParameter( gl.TEXTURE_BINDING_CUBE_MAP);

现在您不必通过这个巨大的列表来找到它们。但是如果你写了一个框架,并且想了解状态,你可能也想使用所有其他的。

getParameter(GLenum pname)

pname                               returned type
ACTIVE_TEXTURE                      GLenum
ALIASED_LINE_WIDTH_RANGE            Float32Array (with 2 elements)
ALIASED_POINT_SIZE_RANGE            Float32Array (with 2 elements)
ALPHA_BITS                          GLint
ARRAY_BUFFER_BINDING                WebGLBuffer
BLEND                               GLboolean
BLEND_COLOR                         Float32Array (with 4 values)
BLEND_DST_ALPHA                     GLenum
BLEND_DST_RGB                       GLenum
BLEND_EQUATION_ALPHA                GLenum
BLEND_EQUATION_RGB                  GLenum
BLEND_SRC_ALPHA                     GLenum
BLEND_SRC_RGB                       GLenum
BLUE_BITS                           GLint
COLOR_CLEAR_VALUE                   Float32Array (with 4 values)
COLOR_WRITEMASK                     sequence<GLboolean> (with 4 values)
COMPRESSED_TEXTURE_FORMATS          Uint32Array
CULL_FACE                           GLboolean
CULL_FACE_MODE                      GLenum
CURRENT_PROGRAM                     WebGLProgram
DEPTH_BITS                          GLint
DEPTH_CLEAR_VALUE                   GLfloat
DEPTH_FUNC                          GLenum
DEPTH_RANGE                         Float32Array (with 2 elements)
DEPTH_TEST                          GLboolean
DEPTH_WRITEMASK                     GLboolean
DITHER                              GLboolean
ELEMENT_ARRAY_BUFFER_BINDING        WebGLBuffer
FRAMEBUFFER_BINDING                 WebGLFramebuffer
FRONT_FACE                          GLenum
GENERATE_MIPMAP_HINT                GLenum
GREEN_BITS                          GLint
IMPLEMENTATION_COLOR_READ_FORMAT    GLenum
IMPLEMENTATION_COLOR_READ_TYPE      GLenum
LINE_WIDTH                          GLfloat
MAX_COMBINED_TEXTURE_IMAGE_UNITS    GLint
MAX_CUBE_MAP_TEXTURE_SIZE           GLint
MAX_FRAGMENT_UNIFORM_VECTORS        GLint
MAX_RENDERBUFFER_SIZE               GLint
MAX_TEXTURE_IMAGE_UNITS             GLint
MAX_TEXTURE_SIZE                    GLint
MAX_VARYING_VECTORS                 GLint
MAX_VERTEX_ATTRIBS                  GLint
MAX_VERTEX_TEXTURE_IMAGE_UNITS      GLint
MAX_VERTEX_UNIFORM_VECTORS          GLint
MAX_VIEWPORT_DIMS                   Int32Array (with 2 elements)
PACK_ALIGNMENT                      GLint
POLYGON_OFFSET_FACTOR               GLfloat
POLYGON_OFFSET_FILL                 GLboolean
POLYGON_OFFSET_UNITS                GLfloat
RED_BITS                            GLint
RENDERBUFFER_BINDING                WebGLRenderbuffer
RENDERER                            DOMString
SAMPLE_BUFFERS                      GLint
SAMPLE_COVERAGE_INVERT              GLboolean
SAMPLE_COVERAGE_VALUE               GLfloat
SAMPLES                             GLint
SCISSOR_BOX                         Int32Array (with 4 elements)
SCISSOR_TEST                        GLboolean
SHADING_LANGUAGE_VERSION            DOMString
STENCIL_BACK_FAIL                   GLenum
STENCIL_BACK_FUNC                   GLenum
STENCIL_BACK_PASS_DEPTH_FAIL        GLenum
STENCIL_BACK_PASS_DEPTH_PASS        GLenum
STENCIL_BACK_REF                    GLint
STENCIL_BACK_VALUE_MASK             GLuint
STENCIL_BACK_WRITEMASK              GLuint
STENCIL_BITS                        GLint
STENCIL_CLEAR_VALUE                 GLint
STENCIL_FAIL                        GLenum
STENCIL_FUNC                        GLenum
STENCIL_PASS_DEPTH_FAIL             GLenum
STENCIL_PASS_DEPTH_PASS             GLenum
STENCIL_REF                         GLint
STENCIL_TEST                        GLboolean
STENCIL_VALUE_MASK                  GLuint
STENCIL_WRITEMASK                   GLuint
SUBPIXEL_BITS                       GLint
TEXTURE_BINDING_2D                  WebGLTexture
TEXTURE_BINDING_CUBE_MAP            WebGLTexture
UNPACK_ALIGNMENT                    GLint
UNPACK_COLORSPACE_CONVERSION_WEBGL  GLenum
UNPACK_FLIP_Y_WEBGL                 GLboolean
UNPACK_PREMULTIPLY_ALPHA_WEBGL      GLboolean
VENDOR                              DOMString
VERSION                             DOMString
VIEWPORT                            Int32Array (with 4 elements)

enableVertexAttribArrayvertexAttribPointer是在特定索引处设置顶点属性数组的状态,与程序无关。您还可以通过上述索引查询所有这些状态。

getVertexAttrib (GLuint index, GLenum pname )

pname                               returned type
VERTEX_ATTRIB_ARRAY_BUFFER_BINDING  WebGLBuffer
VERTEX_ATTRIB_ARRAY_ENABLED         GLboolean
VERTEX_ATTRIB_ARRAY_SIZE            GLint
VERTEX_ATTRIB_ARRAY_STRIDE          GLint
VERTEX_ATTRIB_ARRAY_TYPE            GLenum
VERTEX_ATTRIB_ARRAY_NORMALIZED      GLboolean
CURRENT_VERTEX_ATTRIB               Float32Array (with 4 elements)

如果您现在查看程序的状态,就会发现没有太多重叠。甚至可以做实验,亲眼看看状态是如何变化的。

getProgramParameter(WebGLProgram? program, GLenum pname)

pname               returned type
DELETE_STATUS       GLboolean
LINK_STATUS         GLboolean
VALIDATE_STATUS     GLboolean
ATTACHED_SHADERS    GLint
ACTIVE_ATTRIBUTES   GLint
ACTIVE_UNIFORMS     GLint

或者您可能想检查着色器的运行情况。仍然看不到真正的重叠。

getShaderParameter(WebGLShader? shader, GLenum pname)

pname                   returned type
SHADER_TYPE             GLenum
DELETE_STATUS           GLboolean
COMPILE_STATUS          GLboolean

您看到了 getVertexAttrib returns 一个缓冲区,所以这似乎是相关的。缓冲区本身并不比普通的 ArrayBuffer 更令人兴奋。内容只是不是javacript,而是远在gpu的土地上,辛辛苦苦养家糊口

getBufferParameter(GLenum target, GLenum pname)

pname                       returned type
BUFFER_SIZE                 GLint
BUFFER_USAGE                GLenum

所以程序和顶点数组可能没有那么多共同点。很难通过猜测来推断,但如果您知道(或抽象掉)所有这些吸气剂,则非常简单。

为了完整性,也为了帮助您理解状态,我也复制了所有其他内容。

getFramebufferAttachmentParameter(GLenum target, GLenum attachment, GLenum pname)

pname                                           returned type
FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE              GLenum
FRAMEBUFFER_ATTACHMENT_OBJECT_NAME              WebGLRenderbuffer or WebGLTexture
FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL            GLint
FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE    GLint

getRenderbufferParameter(GLenum target, GLenum pname)

pname                           returned type
RENDERBUFFER_WIDTH              GLint
RENDERBUFFER_HEIGHT             GLint
RENDERBUFFER_INTERNAL_FORMAT    GLenum
RENDERBUFFER_RED_SIZE           GLint
RENDERBUFFER_GREEN_SIZE         GLint
RENDERBUFFER_BLUE_SIZE          GLint
RENDERBUFFER_ALPHA_SIZE         GLint
RENDERBUFFER_DEPTH_SIZE         GLint
RENDERBUFFER_STENCIL_SIZE       GLint

getTexParameter(GLenum target, GLenum pname)

pname               returned type
TEXTURE_MAG_FILTER  GLenum
TEXTURE_MIN_FILTER  GLenum
TEXTURE_WRAP_S      GLenum
TEXTURE_WRAP_T      GLenum

我还没有放弃主持它。所以也许您想检查制服的价值。这有时真的很有用。

getUniform(WebGLProgram? program, WebGLUniformLocation? location)

这里有一些更有用的吸气剂:

getActiveAttrib(WebGLProgram? program, GLuint index)

getActiveUniform(WebGLProgram? program, GLuint index)

当然还有那些人人都爱的人:

getUniformLocation(WebGLProgram? program, DOMString name)

getAttribLocation(WebGLProgram? program, DOMString name)

getProgramInfoLog(WebGLProgram? program)

getShaderInfoLog(WebGLShader? shader)

getShaderSource(WebGLShader? shader)

getShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype)

getSupportedExtensions()

哦这里居然还有一个属于顶点属性的,差点忘了。由于重要的遗留原因,它是分开的。

getVertexAttribOffset(GLuint index, GLenum pname)

(那个 pname 必须是 VERTEX_ATTRIB_ARRAY_POINTER。)

除非我忘记了什么,否则这基本上就是 WebGL 状态的全部。看起来可能很多,但我个人发现所有这些都对理解事物的运作方式非常有帮助。如果没有这些,你基本上会被蒙住双眼,只能一直猜测,并按照教程告诉你调用函数的确切顺序,这在 WebGL 中效果不佳——因为有太多东西,但也有错误你可以的。

Screenius 的回答非常完整。

这是一个webgl state diagram

精简版本为:

在 WebGL 1.0 中,制服是按程序进行的,纹理过滤和包装是按纹理进行的。其他一切都是全球性的。这包括所有属性和所有纹理单元。

从以前的一些回答中粘贴过来

你可以这样想属性和纹理单元

gl = { 
   arrayBuffer: someBuffer, 
   vertexArray: {
     elementArrayBuffer: someOtherBuffer,
     attributes: [], 
   },
};

当您调用 gl.bindBuffer 时,您只是在 gl 状态中设置了 2 个全局变量之一。

gl.bindBuffer = function(bindPoint, buffer) {
   switch (bindPoint) {
      case: this.ARRAY_BUFFER:
         this.arrayBuffer = buffer;
         break;
      case: this.ELEMENT_ARRAY_BUFFER:
         this.vertexArray.elementArrayBuffer = buffer;
         break;
   }
};

当您调用 gl.vertexAttribPointer 时,它会将 arrayBuffer 的当前值复制到指定的属性。

gl.vertexAttribPointer = function(index, size, type, normalized, stride, offset) {
    var attribute = this.vertexArray.attributes[index];
    attribute.size = size;
    attribute.type = type;
    attribute.normalized = normalized;
    attribute.stride = stride;
    attribute.offset = offset;
    attribute.buffer = this.arrayBuffer;  // copies the current buffer reference.
};

纹理的工作方式类似

gl = { 
    activeTextureUnit: 0,
    textureUnits: [], 
};

gl.activeTexture 设置您正在处理的纹理单元。

gl.activeTexture = function(unit) {
   this.activeTextureUnit = unit - this.TEXTURE_0;  // make it zero based.
};

每个纹理单元都有一个 TEXTURE_2D 和一个 TEXTURE_CUBEMAP 所以 gl.bindTexture(b, t) 实际上是

gl.bindTexture = function(bindPoint, texture) {
   var textureUnit = this.textureUnits[this.activeTextureUnit];
   switch (bindPoint) {
       case this.TEXTURE_2D:
           textureUnit.texture2D = texture;
           break;
       case this.TEXTURE_CUBEMAP:
           textureUnit.textureCubeMap = texture;
           break;
   }
};

其余的是全局状态,如透明颜色、视口、混合设置、模板设置、enable/disable 东西,如 DEPTH_TESTSCISSOR_TEST


附带说明:如果您启用 the extension OES_vertex_array_object,则上例中的 vertexArray 将成为您可以与 bindVertexArrayOES 绑定的对象。