2015-09-22 21:14:18 +03:00
|
|
|
# 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.
|
|
|
|
|
2017-11-27 08:15:54 +03:00
|
|
|
Install the Emscripten toolchain per the [instructions](http://emscripten.org/).
|
2015-09-22 21:14:18 +03:00
|
|
|
|
|
|
|
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.
|