Main | API | Shaders (SBO) |


Shaders are very important for a 3D rendering library as they allow for customisation and flexibility by the user application. In traditional libraries, shaders are created in a special language and then compiled and sent to the graphics hardware. WebRender is purely a software renderer so we don't need to have to build a complex language and instead can simply pass a function reference to act as a shader. Since a 'shader' is actually made up of a vertex and pixel shader, along with attributes and helper functions, we package them all into a 'shader program' that can be easily loaded and unloaded from the rendering pipeline.

Creating a shader program involves multiple complex function calls. First space must be allocated for it using getSBOId, which returns a reference id for that shader program. Following this, a vertex and pixel shader function must be assigned to this program, using assignSBOVertexShader and assignSBOPixelShader. Next the program must be told how many vertex attributes each shader is working with, addSBOVertexAttribute is used for this. Adding the attributes is one of the more complex parts of setting up the shaders, therefore for more information look at the function page and Tutorial 2. Lastly loadSBO is called, which takes all the information we provided and compiles the shader program. Once compiled, the sahder can then be set to be used using bindSBO.

Now it is unusual for a JavaScript application to be 'compiled' during runtime. Much of the critical rendering pipeline code within WebRender (scanline, edge generation, vertex sampling) is all run on code loaded in using eval. While this is normally a bad function to use, in our case it allows for all the variables used the in pipeline to be local and therefore have the fastest lookup. Since we don't know how many vertex attributes there are until after the program has started, the code for these functions HAS to be generated. In order to maintain security, the inputs for this generated code is VERY specific and should be hardcoded into your application and never provided by the user.

The vertex shader for WebRender has 3 inputs, the WebRender instance that is calling the function, an array reference representing the incoming vertex, and an array reference representing the outgoing vertex. The reason we use two different arrays is to allow for there to be more or less vertex attributes after the vertex shader. In a 3D application your object, world, camera and perspective transformations will be in the vertex shader. The only requirement to take note of is that your outgoing vertex must have XYZW coordinates, these would have be defined using addSBOVertexAttribute when you created the shader program.

The pixel shader, also known as fragment shader is other libraries, is where the colour of pixels is determined. The inputs for your pixel shader will are determined by your vertex attributes. First we again have the WebRender instance, but it is then followed by each vertex attribute that you defined when creating the shader and in the order you defined them. Due to the requirement of your vertex attributes having XYZW coordinates, these will be somewhere in the inputs. The pixel shader then outputs a 32-bit colour value, that will be used to colour a pixel on the screen. If the value 0 is returned, then the pixel will not be coloured and the Z-Buffer (if being used) will not be updated either. This is similar to calling 'discard' in the OpenGL fragment shader.

In to allow texture sampling, the function getTexturePixelColour can be called on the provided WebRender instance. This then returns the 32-bit colour sampled from the bound texture at the coordinates given. Along with that, two vertex/matrix multiplcation functions, vecByMatrixCol and vecByMatrixRow are provided for use in the vertex shader. Though these aren't required, it can save you having to create them at first. The reason these functions are different from all the others that your application uses when communicating with WebRender, is that these are provided from within WR_Core, which is the main internal class where the rendering pipeline is.

In other graphics libraries, you can pass uniform values to your shaders that stay consistent. In WebRender these 'shader variables' are simply variables defined in the global scope that both your application and the shaders can have access to. In order to support these in multi-threaded mode, these variables must be defined in the same file/s as the shader functions. In order to update these variables, in a non-threaded enviroment you could just change them directly, but in order to support multi-threading, it is advised you use the special setShaderVariable function.

The shader architecture is by far the most complex part of WebRender, mainly due to the amount of customisability it provides. To gain a full understand of how everything works, read the tutorials and look at the API pages for each function. There should be very few restrictions on the types of shaders you can build within WebRender.


Related Functions