Canvas:3D/Historical
Contents
Canvas 3D Context
VladVukicevic, work in progress
Archived historical content; much of this is still accurate, but more detailed roadmap and plans are available on the main Canvas:3D page.
Rationale
Since <canvas> provides basically a rectangular immediate-mode drawing surface, extending it to programmatic 3D rendering is straightforward. OpenGL is the natural accepted cross-platform 3D API to follow; it has a well-defined and rigorous specification that would be well beyond my ability to recreate. However, OpenGL itself (2.0 in its latest incarnation) is extremely sprawling, including many redundant ways and now-obsolete methods.
Instead, I plan to follow OpenGL ES, which is a version of the OpenGL spec pared down for implementation in embedded systems. It removes much of the dead weight of OpenGL, e.g. rendering via glBegin, glVertex[234][dfis][v], etc.; rendering quads and polygons (since they can be emulated through triangles trivially); and similar.
OpenGL ES 1.1.4 is the current plan, which presents a traditional fixed-function OpenGL API. I would like to, at some point, support OpenGL ES 2.0, which provides maps today's modern programmable hardware; however, implementing 2.0 can be done an incremental step over implementing the fixed-function API.
One of the difficulties of OpenGL is that it is extremely low level, and in many ways looks strange when exposed as a web API. Where appropriate, the addition of helper objects and functions will be done to allow for speed and ease of use -- however, as with OpenGL on the desktop, it should be possible to create a richer API on top of OpenGL in whatever language is being used to interact with the 3D canvas context (e.g. JavaScript, Python, etc.).
Security Considerations
The OpenGL API is complex and stateful; much of the API, out of permance requirements, deals with pointers to arbitrary data types. For example, the function glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr) can take bytes, integers, floats, doubles, etc. as valid ptr types, based on the given type. After a vertex pointer is set, calling glDrawArrays(GLenum mode, GLint first, GLsizei count) to actually draw the given vertex/texture/etc. pointer arrays will require a different size of array depending on whether one is drawing TRIANGLES, TRIANGLE_STRIPS, TRIANGLE_FANS, etc. -- for example, assuming the appropriate types are used, TRIANGLES will need 3*count floats from vertices, 2*count floats from texcoords (assuming they're specified), 4*count floats from a color array, etc.
OpenGL implementations usually handle an error by simply crashing; no size is passed when the various pointer arrays are set (the size parameter refers to the number of coordinates per element, e.g. 3 for a 3D vertex). This is obviously not acceptable for a 3D Canvas Context executing within a web browser; thus the implementation must be extrmely careful to track array sizes and the like and to check them before calling in to any underlying OpenGL implementation.
Performance
Initial testing reveals that performance can be quite good; a pbuffer context is created for the canvas, and copying into the front buffer is performed when SwapBuffers() is executed. Because all drawing is done through arrays, there isn't a lot of method call overhead for drawing operations.
Implementation Notes
- vertex/color/texcoord array data - matrix manipulation (load/push/pop/translate/rotate/scale/ortho/frustum/lookAt/matrixmode) - drawing via drawarrays or drawelements (indexes) - texturing from <img> (2D POT textures only, no TEXTURE_RECTANGLE or 1D/3D supported)