-
Notifications
You must be signed in to change notification settings - Fork 103
CustomShader
The CustomShader class is used to encapsulate a user-defined shader that can be applied to a Material. CustomShader will automatically parse the given script and extract the uniforms and attributes and self-bind them to the CustomShader object. Self-binding includes support for structures, arrays and arrays of structures as well as utilizing #define statements for dynamically compiled structure sizes.
Construction is simple and takes only a vertex and fragment shader script tag ID containing script or a src='' URL for retrieval plus optional functions for initialization and update.
Example of script inclusion (HTML):
<head>
...
<script id="vs" src="noise.vs" type="x-shader/x-vertex"></script>
<script id="fs" src="noise.fs" type="x-shader/x-fragment"></script>
...
</head>
Javascript usage:
var myShader = new CubicVR.CustomShader({
vertex: "#vs", // Vertex Shader source or ID of <script> tag containing source or src='' url.
fragment: "#fs", // Fragment Shader source or ID of <script> tag containing source or src='' url.
init: function(shader) { // function called upon initialization of the shader
// ... useful for setting one-time values here same way as ready() scope
}
});
// Apply the custom shader to a material
var customMaterial = new CubicVR.Material({
shader: myShader
});
By utilizing the code at the end of the Core shaders (CubicVR_Core.vs, CubicVR_Core.fs) to create your own you can start your material with a fully functional version of the CubicVR GLSL material and lighting pipeline with minimal effort. By using this code to start your shaders will support the material parameters, shadows, morphing and lighting that the internal shaders can do without the need for additional bindings or tedious definitions.
The following is the minimal code from those files required to produce a compatible CustomShader material. No additional code from the Core shader files is required as it will be prefixed automatically at runtime.
Standard Vertex shader: (copied from last lines of CubicVR_Core.vs)
void main(void)
{
vertexTexCoordOut = cubicvr_texCoord();
gl_Position = matrixProjection * matrixModelView * cubicvr_transform();
#if !LIGHT_DEPTH_PASS
vertexNormalOut = matrixNormal * cubicvr_normal();
cubicvr_lighting();
#endif
}
Standard Fragment shader: (copied from last lines of CubicVR_Core.fs)
void main(void)
{
vec2 texCoord = cubicvr_texCoord();
#if !LIGHT_DEPTH_PASS
vec4 color = cubicvr_color(texCoord);
vec3 normal = cubicvr_normal(texCoord);
color = cubicvr_environment(color,normal,texCoord);
color = cubicvr_lighting(color,normal,texCoord);
gl_FragColor = clamp(color,0.0,1.0);
#else
gl_FragColor = cubicvr_depthPack(texCoord);
#endif
}
You may leave out the depth pass conditions but if the check for LIGHT_DEPTH_PASS is omitted CubicVR.js will bypass your custom shader and use it's internal shaders for shadow and depth passes. The available uniforms and attributes will be listed in the CubicVR_Core shader source -- if you wish to use the internal parameters take note of any #ifdef statements used to control logic as they will apply to your usage as well.
If the shader has been successfully compiled and parsed this function will return true. This is used to ensure that a shader is loaded and bound prior to attempting to set any values, otherwise they may fail.
Example:
CubicVR.MainLoop(function(timer, gl) {
if (myShader.ready()) {
// Just assign the value, CustomShader handles the rest.
myShader.myTimer.value = timer.getSeconds();
}
myScene.render();
});
Returns:
true if ready, false if not.
Get the Shader object that the CustomShader is utilizing internally.
Returns:
CubicVR Shader object if ready(), null otherwise.
Assignment of variables is simple, if you added the variable to your shader source and it was successfully compiled and ready() returns true it will be available to set.
Shader source (example snippet of part where uniforms are defined):
#define somePointsSize 3
struct myType
{
vec3 a;
float b;
mat4 c;
};
uniform float myTimer; // standard type
uniform myType myStruct; // structure
uniform myType myStructArray[3]; // array of structure
uniform vec3 somePoints[somePointsSize]; // array of standard type via define
// ...
Would yield the following accessable variables and usage:
CubicVR.MainLoop(function(timer, gl) {
if (myShader.ready()) {
// standard type
myShader.myTimer.value = timer.getSeconds();
// structure
myShader.myStruct.a.value = [0,1,2];
myShader.myStruct.b.value = 10.5;
myShader.myStruct.c.value = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
// array of structure
myShader.myStructArray[0].a.value = [2,3,4];
myShader.myStructArray[1].b.value = 20.6;
myShader.myStructArray[2].c.value = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
// array of standard type
myShader.somePoints[0].value = [0, 1, 2];
myShader.somePoints[1].value = [2, 3, 4];
myShader.somePoints[2].value = [4, 5, 6];
}
myScene.render();
});