Understanding WebGL State

前端 未结 2 1900
走了就别回头了
走了就别回头了 2020-12-14 05:09

Is there any documentation I can find somewhere which documents the preconditions required for WebGL calls?

I have gotten a fairly strong grasp of the WebGL basics,

相关标签:
2条回答
  • 2020-12-14 05:17

    I recently gave a similar answer, but I just said that there's quite a lot and gave a link to the spec, without copy pasting anything. Lesson learned, I can fix that. But just a fair warning, if people call WebGL "stateful" they mean it. But the document, that contains all the errors WebGL can generate under which conditions is called the spec. I'm not copying over all the possible errors, because that would easily double it, if not more.

    First, because are you explicitly asked about binding targets, here is how you query all of those, not counting extensions:

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

    Now you don't have to go through this huge list to find those. But if you write a framework, and want to understand the state, you may want to use all the others, too.

    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)
    

    enableVertexAttribArray and vertexAttribPointer are setting the state of a vertex attribute array at a specific index, and don't have anything to do with the program. You can also query all this state, by aforementioned index.

    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)
    

    If you now look at the state of the program, there isn't much overlap. One could even go as far as make experiments and see yourself how the states change.

    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
    

    Or maybe you want to check how your shader is doing. Still no real overlap in sight.

    getShaderParameter(WebGLShader? shader, GLenum pname)

    pname                   returned type
    SHADER_TYPE             GLenum
    DELETE_STATUS           GLboolean
    COMPILE_STATUS          GLboolean
    

    You saw getVertexAttrib returns a buffer, so that seems relevant. The buffer itself isn't that much more exciting than say a plain ArrayBuffer. The contents are just not in javacript, but far away in gpu land, doing hard work to support the family at home.

    getBufferParameter(GLenum target, GLenum pname)

    pname                       returned type
    BUFFER_SIZE                 GLint
    BUFFER_USAGE                GLenum
    

    So probably programs and vertex arrays don't have that much in common. Difficult to deduce by guessing, but really simple to find out if you know ( or abstract away ) all those getters.

    For completeness, and to help you understand state, I also copy over all the other things.

    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
    

    I didn't give up moderating it just yet. So maybe you want to check the value of your uniforms. That's really useful sometimes.

    getUniform(WebGLProgram? program, WebGLUniformLocation? location)

    Here a few more really useful getters:

    getActiveAttrib(WebGLProgram? program, GLuint index)

    getActiveUniform(WebGLProgram? program, GLuint index)

    And of course the ones everbody loves:

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

    Oh here that one actually belongs to the vertex attributes, almost forgot. It's separate for important legacy reasons.

    getVertexAttribOffset(GLuint index, GLenum pname)

    ( pname has to be VERTEX_ATTRIB_ARRAY_POINTER on that one. )

    Unless I forgot something, that's basically all of WebGL state. It may seem like a lot, but I personally found all of it to be really helpful to understand how things work. Without those you are basically blindfolded and have to just guess all the time, and follow tutorials telling you the exact order you have to call functions in, which doesn't work well with WebGL - just because there are so many things, but also mistakes you can do.

    0 讨论(0)
  • 2020-12-14 05:36

    Screenius answer is pretty complete.

    Here is a webgl state diagram

    The terser version is:

    In WebGL 1.0, uniforms are per program, texture filtering and wrapping is per texture. Everything else is global. That includes all attributes and all texture units.

    Pasted from some previous answers that cover this

    You can think of attributes and texture units like this

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

    When you call gl.bindBuffer you're just setting one of 2 global variables in the gl state.

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

    When you call gl.vertexAttribPointer it copies current value of arrayBuffer to the specified attribute.

    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.
    };
    

    Textures work similarly

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

    gl.activeTexture sets which texture unit you're working on.

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

    Every texture unit has both a TEXTURE_2D and a TEXTURE_CUBEMAP so gl.bindTexture(b, t) is effectively

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

    The rest is global state like the clear color, viewport, the blend settings, the stencil settings, the enable/disable stuff like DEPTH_TEST, SCISSOR_TEST


    Just a side note: If you enable the extension OES_vertex_array_object the vertexArray in the example above becomes its own object that you can bind with bindVertexArrayOES.

    0 讨论(0)
提交回复
热议问题