| # Introduction |
| |
| There are many situations in which it's useful for WebGL applications to |
| transform shaders in various ways. ANGLE's shader translator can be used for |
| this purpose: compiling it with [Emscripten](http://emscripten.org/) allows it |
| to be invoked from a web page. This wiki page provides some preliminary details |
| about how to do this. |
| |
| # Details |
| |
| Pull top of tree ANGLE. |
| |
| Install the Emscripten toolchain per the [instructions](http://emscripten.org/). |
| |
| Symlink (preferred) or copy the ANGLE directory into ...emsdk/emscripten/master. |
| |
| Put a shader to compile into a file (named with .vert or .frag suffix) in the |
| same directory. For example, put the following shader from the [WebGL Aquarium] |
| (http://webglsamples.org/aquarium/aquarium.html) into `aq-fish-nm.frag`: |
| |
| ``` |
| precision mediump float; |
| uniform vec4 lightColor; |
| varying vec4 v_position; |
| varying vec2 v_texCoord; |
| varying vec3 v_tangent; // #normalMap |
| varying vec3 v_binormal; // #normalMap |
| varying vec3 v_normal; |
| varying vec3 v_surfaceToLight; |
| varying vec3 v_surfaceToView; |
| |
| uniform vec4 ambient; |
| uniform sampler2D diffuse; |
| uniform vec4 specular; |
| uniform sampler2D normalMap; // #normalMap |
| uniform float shininess; |
| uniform float specularFactor; |
| // #fogUniforms |
| |
| vec4 lit(float l ,float h, float m) { |
| return vec4(1.0, |
| max(l, 0.0), |
| (l > 0.0) ? pow(max(0.0, h), m) : 0.0, |
| 1.0); |
| } |
| void main() { |
| vec4 diffuseColor = texture2D(diffuse, v_texCoord); |
| mat3 tangentToWorld = mat3(v_tangent, // #normalMap |
| v_binormal, // #normalMap |
| v_normal); // #normalMap |
| vec4 normalSpec = texture2D(normalMap, v_texCoord.xy); // #normalMap |
| vec3 tangentNormal = normalSpec.xyz - vec3(0.5, 0.5, 0.5); // #normalMap |
| tangentNormal = normalize(tangentNormal + vec3(0, 0, 2)); // #normalMap |
| vec3 normal = (tangentToWorld * tangentNormal); // #normalMap |
| normal = normalize(normal); // #normalMap |
| vec3 surfaceToLight = normalize(v_surfaceToLight); |
| vec3 surfaceToView = normalize(v_surfaceToView); |
| vec3 halfVector = normalize(surfaceToLight + surfaceToView); |
| vec4 litR = lit(dot(normal, surfaceToLight), |
| dot(normal, halfVector), shininess); |
| vec4 outColor = vec4( |
| (lightColor * (diffuseColor * litR.y + diffuseColor * ambient + |
| specular * litR.z * specularFactor * normalSpec.a)).rgb, |
| diffuseColor.a); |
| // #fogCode |
| gl_FragColor = outColor; |
| } |
| ``` |
| |
| Compile the shader translator, the translator sample, and the shader all |
| together: |
| |
| ``` |
| ./emcc -Iangle/include -Iangle/src angle/samples/translator/translator.cpp angle/src/compiler/preprocessor/*.cpp angle/src/compiler/translator/*.cpp angle/src/compiler/translator/timing/*.cpp angle/src/compiler/translator/depgraph/*.cpp angle/src/third_party/compiler/*.cpp angle/src/common/*.cpp -o translator.html --preload-file aq-fish-nm.frag -s NO_EXIT_RUNTIME=1 |
| ``` |
| |
| Serve up the resulting translator.html via `python -m SimpleHTTPServer`. |
| Navigate the browser to localhost:8000. |
| |
| The translator sample will run, displaying its output into the text area on the |
| page. Since it isn't receiving any input, it simply outputs a help message and |
| exits. |
| |
| To invoke the translator again, processing the shader we included along with the |
| source code, open the JavaScript console and type: |
| |
| ``` |
| Module['callMain'](['-s=w', '-u', 'aq-fish-nm.frag']) |
| ``` |
| |
| The active uniforms and their types will be printed to the text area after the |
| translator sample processes the shader. |
| |
| # Issues and Next Steps |
| |
| It's clearly not useful to have to compile the shader in to the |
| Emscripten-translated executable. It would be helpful to define a simple wrapper |
| function which can easily be called from JavaScript and which defines enough |
| parameters to pass in a shader as a string, transform it somehow or compile it |
| to another language target, and return the compiled result (or other |
| information). A simple JavaScript library that wraps all of the interactions |
| with the Emscripten binary would be useful. |
| |
| It's not feasible to interact with the translator's data structures, nor |
| traverse the AST from JavaScript. The code that operates upon the shader must be |
| written in C++ and compiled in to the shader translator. |
| |
| emcc should be integrated better with ANGLE's build system. |