第二章 创建webGL设备和绘制缓冲区呈现 Context Creation and Drawing Buffer Presentation
在开始使用webGL API之前您先要从现有的HTML Canvas控件中创建一个WebGLRenderingContext对象,有关HTML Canvas的知识将在后边进行介绍
WebGLRenderingContext实例对象管理OpenGL状态并将绘图的数据放到缓冲区里,缓冲区也需要在这时候创建
在创建缓冲区时您也可以提供配置参数,否则将使用默认参数,有关默认配置在该文档的其它部分介绍
绘制缓冲区将在HTML混合操作开始之前立即渲染到HTML混合器中,但只有当自上次HTML混合操作之后缓冲区有修改时才会这样
2.1 画布元素 The canvas
Element
通过调用现有的HTMLCanvasElement实例的getContext("webgl")方法可以得到WebGLRenderingContext对象,参数需明确指定为"webgl",并且区分大小写.(实际试验时,在现阶段chrome需要传递参数experimental-webgl才可以创建,待WEBGL规范正式颁发后应该会改回webgl)
第一次调用这个方法时,一个WebGLRenderingContext对象将被创建并返回,同时一个绘图缓冲区也将同时创建,重复调用getContext方法并使用相关的参数'webgl',则返回上次创建的对象并不会创建新的实例
HTML Canvas规范中定义了试图在同一个Canvas中创建两个或以上不兼容设备时的行为
如果调用时getContext方法时传递了第二个参数,那么这个参数一定是WebGLContextAttributes类型的对象,它包含的配置将在创建缓冲区时使用,有关WebGLContextAttributes细节请点击这里.
混合(alpha),深度(depth),模板(stencil
)和抗矩齿(antialias
)特性都可以接收,但都不是必须的.webGL不保证它们一定遵守它们,但是会尽最大努力去工作.
即使特性的组合不受webGL支持时,或者不受显卡支持的时候,webGL在创建WebGLRenderingContext对象时也不会报错.创建WebGLRenderingContext时使用的特性可以通过调用WebGLRenderingContext对象的getContextAttributes()方法获得.透明像素(premultipliedAlpha
)和缓冲区保护(preserveDrawingBuffer
)功能必须实现.
重复使用参数'webgl'调用getContext方法时,已经存在的WebGLContextAttributes对象,如果有的话,将被忽略.
2.2 绘制缓冲区 The Drawing Buffer
在调用API方法后缓冲区将被立即渲染,所以在创建WebGLRenderingContext对象后,应紧接着定义缓冲区.下表展示了不同类型缓冲区组成的绘制缓冲区,还有它们的大小,以及是否有默认值.整个绘制缓冲区的大小取决于HTMLCanvasElement的宽和高.下表同时展示了这些缓冲区首次创建时,或者当尺寸变化后,或者创建保护缓冲区参数设置为false时,这些缓冲区将使用的默认值.
如果width和height属性没有提供,则不论缓存冲是首次创建,还是HTMLCanvasElement对象的
宽高发生变化,一个小面积的缓冲区都将被创建.这个缓冲区的建立取决于webAPI具体实现.并且不保证它们总能符合预期的长宽比例.实际使用的缓冲区的大小可以通过drawingBufferWidth
和drawingBufferHeight
属性获得.
By default, the buffers shall be the size shown below.可选参数WebGLContextAttributes可以用来修改无论是否已经定义的缓冲.它也可以用来定义颜色缓冲区是否包含透明通道.如果有定义透明通道那么HTML混合器将使用透明通道与页面其余部分合并.WebGLContextAttributes对象只能在首次调用getContext时使用,在绘制缓冲区建立之后将再没有机会修改它.
在HTML混合操作之前webGL将它的绘制缓冲区渲染到HTML中,但是只有自最后混合操作后缓冲区有修改时才这样.在绘制缓冲区渲染之前,需要确保所有的渲染操作都flush到绘制缓冲区.默认情况下,混合操作之后,绘制缓冲区的将被清空成上表中的默认值.
这个默认行为可以通过WebGLContextAttributes对象的preserveDrawingBuffer属性进行修改.如果这个标识为true,缓冲区的内容将被保留,直到用户手动清除或者覆盖.如果该标识为false,那么在渲染方法返回后,以此
context为源图像进行一些操作时将会导致undefined错误,这些操作包括
readPixels
方法或者toDataURL
方法.或者把它作为另外一个context的texImage2D或drawImage时(进行上述操作也将导致undefined错误).
虽然有时候保留缓冲区很方便,但是在某些平台上运行时将可能导致性能损失.只要有可能就应当把它(preserveDrawingBuffer)设置为false,包括使用同步技术获取绘制缓冲区得到绘制缓冲区内容.当需要调用一系列的方法渲染同一个绘制缓冲区时,您可以使用Framebuffer Object对象.
当开发人员无法获取缓冲区内容的一些情况下,webGL都将保证去优化您对缓冲区执行的指定的清除操作(clear operation).例如,当开发人员明确指定了清除操作,但这并非必须时(Implementations may optimize away the required implicit clear operation of the Drawing Buffer as long as a guarantee can be made that the author cannot gain access to buffer contents from another process. For instance, if the author performs an explicit clear then the implicit clear is not needed.)
2.3 WebGL视图 The WebGL Viewport
OpenGL管理一个矩形的视图作为它状态(state)的一部分.OpenGL状态(state)在绘制缓冲区里定义了一块存放渲染结果的区域.webGL Context创建后,视图紧接着进行了初始化,并且以(0,0)为源点,Canvas的宽高作为视图的宽和高(Canvas.width,Canvas.height).
Canvas大小变化时,WebGL不应该影响OpenGL Viewport的状态.
如果webGL程序中没有设置视图的逻辑,那么它将不处理Canvas大小变化事件,下边的EAMCScript代码示例演示了如何通过代码重置视图大小.
基础原理:自动设置viewport将会干扰程序里的手动设置,程序应该处理Canvas大小发生变化时引发的resize事件,并且重新设置视图
2.3 透明像素,画布接口和texImage2D Premultiplied Alpha,Canvas APIs and texImage2D
OpenGL API允许程序修改在渲染时使用的混合模型(blending models),基于这个特性,控制绘制缓冲区的透明值如何被解释将成为可能(and for this reason allows control over how alpha values in the drawing buffer are interpreted;),参见WebGLContextAttributes节点中的介绍
HTML Canvas在实现接口toDataURL
和drawImage
必须考虑创建context时指定的透明像素参数.在对已经渲染完毕的Canvas对象调用toDataURL方法时,如果请求的图像没有透明像素而webGL Context的透明像素参数(
premultipliedAlpha
)指定为true,那么像素的值必须被拨离.颜色通道将被混合操作分离,请注意这个操作会让原图像失真.在绘制过程中,使用CanvasRenderingContext2D对象的drawImage方法可以得到被webGL渲染过的Canvas对象,可以在这里修改(也可以不修改)webGL的内容,这取决于
CanvasRenderingContext2D
的预乘(Premultiplication)操作的需要.
预乘(Premultiplication) 定义:一个图像用它自己的RGB通道乘以它自己的ALPHA通道
把webGL渲染过的Canvas对象传递给texImage2D方法时,像素值可能需要根据透明像素格式进行修改,或者,像素值可能需要修改成透明格式.
http://www.lighthouse3d.com/tutorials/glsl-tutorial/?lights
http://www.khronos.org/webgl/wiki/Tutorial
http://learningwebgl.com/blog/?p=28
http://learningwebgl.com/lessons/lesson01/index.html
http://www.lighthouse3d.com/tutorials/glsl-tutorial/?lights
2 Context Creation and Drawing Buffer Presentation
Before using the WebGL API, the author must obtain a WebGLRenderingContext object for a given HTMLCanvasElement as described below. This object is used to manage OpenGL state and render to the drawing buffer, which must also be created at the time of context creation. The author may supply configuration options for this drawing buffer, otherwise default values shall be used as specified elsewhere in this document. This drawing buffer is presented to the HTML page compositor immediately before an HTML page compositing operation, but only if the drawing buffer has been modified since the last compositing operation.
2.1 The canvas
Element
A WebGLRenderingContext object shall be created by calling the getContext()
method of a given HTMLCanvasElement [CANVAS] object with the exact string ‘webgl
’. This string is case sensitive. When called for the first time, a WebGLRenderingContext object is created and returned. Also at this time a drawing buffer shall be created. Subsequent calls to getContext()
with the same string shall return the same object.
The HTML Canvas specification [CANVAS] defines the behavior when attempting to fetch two or more incompatible contexts against the same canvas element.
A second parameter may be passed to the getContext()
method. If passed, this parameter shall be a WebGLContextAttributes object containing configuration parameters to be used in creating the drawing buffer. See WebGLContextAttributes for more details.
The alpha
, depth
, stencil
and antialias
attributes are requests, not requirements. The WebGL implementation does not guarantee that they will be obeyed, but should make a best effort to honor them. Combinations of attributes not supported by the WebGL implementation or graphics hardware shall not cause a failure to create a WebGLRenderingContext. The attributes actually used to create the context may be queried by the getContextAttributes()
method on the WebGLRenderingContext. The premultipliedAlpha
and preserveDrawingBuffer
attributes must be obeyed by the WebGL implementation.
On subsequent calls to getContext() with the ‘webgl
’ string, the passed WebGLContextAttributes object, if any, shall be ignored.
2.2 The Drawing Buffer
The drawing buffer into which the API calls are rendered shall be defined upon creation of the WebGLRenderingContext object. The table below shows all the buffers which make up the drawing buffer, along with their minimum sizes and whether they are defined or not by default. The size of this drawing buffer shall be determined by the width
and height
attributes of the HTMLCanvasElement. The table below also shows the value to which these buffers shall be cleared when first created, when the size is changed, or after presentation when the preserveDrawingBuffer
context creation attribute is false
.
If the requested width or height cannot be satisfied, either when the drawing buffer is first created or when the width
and height
attributes of theHTMLCanvasElement
are changed, a drawing buffer with smaller dimensions shall be created. The dimensions actually used are implementation dependent and there is no guarantee that a buffer with the same aspect ratio will be created. The actual drawing buffer size can be obtained from the drawingBufferWidth
anddrawingBufferHeight
attributes.
By default, the buffers shall be the size shown below. The optional WebGLContextAttributes object may be used to change whether or not the buffers are defined. It can also be used to define whether the color buffer will include an alpha channel. If defined, the alpha channel is used by the HTML compositor to combine the color buffer with the rest of the page. The WebGLContextAttributes object is only used on the first call to getContext
. No facility is provided to change the attributes of the drawing buffer after its creation.
WebGL presents its drawing buffer to the HTML page compositor immediately before a compositing operation, but only if the drawing buffer has been modified since the last compositing operation. Before the drawing buffer is presented for compositing the implementation shall ensure that all rendering operations have been flushed to the drawing buffer. By default, after compositing the contents of the drawing buffer shall be cleared to their default values, as shown in the table above.
This default behavior can be changed by setting the preserveDrawingBuffer
attribute of the WebGLContextAttributes object. If this flag is true, the contents of the drawing buffer shall be preserved until the author either clears or overwrites them. If this flag is false, attempting to perform operations using this context as a source image after the rendering function has returned can lead to undefined behavior. This includes readPixels
or toDataURL
calls, or using this context as the source image of another context's texImage2D
or drawImage
call.
While it is sometimes desirable to preserve the drawing buffer, it can cause significant performance loss on some platforms. Whenever possible this flag should remain false and other techniques used. Techniques like synchronous drawing buffer access (e.g., calling readPixels
or toDataURL
in the same function that renders to the drawing buffer) can be used to get the contents of the drawing buffer. If the author needs to render to the same drawing buffer over a series of calls, a Framebuffer Object can be used.
Implementations may optimize away the required implicit clear operation of the Drawing Buffer as long as a guarantee can be made that the author cannot gain access to buffer contents from another process. For instance, if the author performs an explicit clear then the implicit clear is not needed.
2.3 The WebGL Viewport
OpenGL manages a rectangular viewport as part of its state which defines the placement of the rendering results in the drawing buffer. Upon creation of the WebGL context, the viewport is initialized to a rectangle with origin at (0, 0) and width and height equal to (canvas.width, canvas.height).
A WebGL implementation shall not affect the state of the OpenGL viewport in response to resizing of the canvas element.
Note that if a WebGL program does not contain logic to set the viewport, it will not properly handle the case where the canvas is resized. The following ECMAScript example illustrates how a WebGL program might resize the canvas programmatically.
Rationale: automatically setting the viewport will interfere with applications that set it manually. Applications are expected to use onresize
handlers to respond to changes in size of the canvas and set the OpenGL viewport in turn.
2.4 Premultiplied Alpha, Canvas APIs and texImage2D
The OpenGL API allows the application to modify the blending modes used during rendering, and for this reason allows control over how alpha values in the drawing buffer are interpreted; see the premultipliedAlpha
parameter in the WebGLContextAttributes section.
The HTML Canvas APIs toDataURL
and drawImage
must respect the premultipliedAlpha
context creation parameter. When toDataURL
is called against a Canvas into which WebGL content is being rendered, then if the requested image format does not specify premultiplied alpha and the WebGL context has thepremultipliedAlpha
parameter set to true, then the pixel values must be de-multiplied; i.e., the color channels are divided by the alpha channel. Note that this operation is lossy.
Passing a WebGL-rendered Canvas to the drawImage
method of CanvasRenderingContext2D
may or may not need to modify the the rendered WebGL content during the drawing operation, depending on the premultiplication needs of the CanvasRenderingContext2D
implementation.
When passing a WebGL-rendered Canvas to the texImage2D
API, then depending on the setting of the premultipliedAlpha
context creation parameter of the passed canvas and the UNPACK_PREMULTIPLY_ALPHA_WEBGL
pixel store parameter of the destination WebGL context, the pixel data may need to be changed to or from premultiplied form.