I am playing around with webgl
copied from this page. I want to use mouse to control the light position.
If I just send the static value from js
to fragment shader
it will work:
mouseLocation = gl.getUniformLocation(program, "mouse");
gl.uniform2f(mouseLocation, 0,0);
I have a function to update the mouse position:
function updateMousePosition(e){
console.log(e.pageX);
mousex = e.pageX;
mousey = e.pageY;
}
which is called when mouse move:
canvas.addEventListener( 'mousemove', updateMousePosition, false );
then send the mouse position to fragment shader
every frame:
gl.uniform2f(mouseLocation, mousex,mousey);
After that I will get the mouse position from fragment shader
:
uniform vec2 mouse;
void main(void) {
//mp - mouse position
vec2 mp = vec2(mouse.x / resolution.x, 1.0 - mouse.y / resolution.y);
//lp depend on mp
vec3 lp = vec3(mp.x, mp.y, -1.0);
//other calculation ...
}
it did not work.
But when I send down static value from console.log
in updateMousePosition(e)
:
gl.uniform2f(mouseLocation, 679, 590);//number taken from console.log
it work.
I am not sure what is not working but I suspect is the format or type of the number, js
is not strictly type but glsl
is.
How can I resolve this?
Finaly decided to put this answer (edited).
As Gman commented, there is apprently nothing wrong with your code. Technically, this should work. However you pointed out a real tricky aspect of the WebGL/Javascript couple compared to OpenGL: The typage. And due to how Javascript variables works, you easily generate strange bugs.
Imagine this absurde situation:
var x = 55;
var y = 128;
// some code here...
x = "blah"; // oups !
// some code here...
gl.uniform2f(mouseLocation, x, y);
With C, C++ or other strong typed language, such absurdity is almost impossible to do (this is possible through pointers, but this is another subject), because the compiler forbid it stricly and throw an error. But in javascript, there is no problem, and in this case, the x
number variable becomes an string variable, and when passed to WebGL, it become NaN
. If you don't have correctly tracked the x
variable, you will search long time why this does not work.
All WebGL functions only accepts typed data in the last stage, because last stage is the GPU, and GPU is low-level. That is, even if you pass a pure Javascript Number variable to a WebGL function, this Javascript variable WILL BE converted to typed data before. But the fact is that Javascript will never throw an error about wrong variable types: It converts it (cast) to typed data, and even if what you attempt to do is absurd, it will never warn you, it will transform non-convertible data into 'NaN`.
Fortunately, to avoid any ambiguity, WebGL comes with a bunch of new Javascript objects: the Typed Arrays: https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/TypedArray
With typed Arrays, you can know within your javascript code what data is stored, and so what data will be sent to the GPU before you send it. That is, you can use typed array to convert (cast) Javascript variables into known typed data before it is sent to GPU.
var mousePos = new Float32Array(2);
function updateMousePosition(e){
mousePos[0] = e.pageX;
mousePos[1] = e.pageY;
}
// do something
console.log(mousePos);
gl.uniform2fv(mouseLocation, mousePos);
In the above example, the variables e.pageX
and e.pageY
are directly converted into WebGL compatible typed data. That way, if you now print the mousePos
variable using console.log
you will see what will be really sent, as it, to WebGL. For debug purpose, you can put the console.log
just before the call to gl.uniform2fv
to ensure nothing wrong happened "out of view".
In this example, if any data was wrongly converted, you will see something like NaN
, NaN
in your output log, so you know that you have to search somewhere a mistake in your code.