Webgl - 动态鼠标位置
Webgl - dynamic mouse position
我正在玩从 this page 复制的 webgl
。我想用鼠标来控制灯的位置。
如果我只是将静态值从 js
发送到 fragment shader
它将起作用:
mouseLocation = gl.getUniformLocation(program, "mouse");
gl.uniform2f(mouseLocation, 0,0);
我有更新鼠标位置的功能:
function updateMousePosition(e){
console.log(e.pageX);
mousex = e.pageX;
mousey = e.pageY;
}
鼠标移动时调用:
canvas.addEventListener( 'mousemove', updateMousePosition, false );
然后每帧发送鼠标位置到fragment shader
:
gl.uniform2f(mouseLocation, mousex,mousey);
之后我将从 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 ...
}
没用。
但是当我从 console.log
in updateMousePosition(e)
:
发送静态值时
gl.uniform2f(mouseLocation, 679, 590);//number taken from console.log
有效。
我不确定是什么不起作用,但我怀疑是数字的格式或类型,js
不是严格类型,但 glsl
是。
我该如何解决这个问题?
最后决定放这个答案(已编辑)。
正如 Gman 评论的那样,您的代码显然没有任何问题。从技术上讲,这应该可行。但是,与 OpenGL 相比,您指出了 WebGL/Javascript 这对夫妇的一个真正棘手的方面:字体。由于 Javascript 变量的工作方式,您很容易产生奇怪的错误。
想象一下这种荒谬的情况:
var x = 55;
var y = 128;
// some code here...
x = "blah"; // oups !
// some code here...
gl.uniform2f(mouseLocation, x, y);
用C、C++或其他强类型语言,这种荒谬的事情几乎不可能发生(通过指针是可能的,但这是另一个主题),因为编译器严格禁止并抛出错误。但是在javascript中就没有问题了,而且在这种情况下,x
数字变量变成了字符串变量,传给WebGL后就变成了NaN
。如果您没有正确跟踪 x
变量,您将搜索很长时间为什么这不起作用。
所有WebGL函数只接受最后阶段的类型数据,因为最后阶段是GPU,而GPU是低级的。也就是说,即使您将纯 Javascript 数字变量传递给 WebGL 函数,此 Javascript 变量也会先转换为类型化数据。但事实是 Javascript 永远不会抛出关于错误变量类型的错误:它将它转换(转换)为类型化数据,即使你试图做的事情是荒谬的,它也永远不会警告你,它会转换不可将数据转换为“NaN”。
幸运的是,为了避免歧义,WebGL 附带了一堆新的 Javascript 对象:类型化数组:https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/TypedArray
使用类型化数组,您可以在 javascript 代码中知道存储了哪些数据,以及在发送之前将哪些数据发送到 GPU。
也就是说,您可以在将变量发送到 GPU 之前使用类型化数组将 Javascript 变量转换(转换)为已知的类型化数据。
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);
在上面的例子中,变量e.pageX
和e.pageY
被直接转换成WebGL兼容的类型化数据。这样,如果您现在使用 console.log
打印 mousePos
变量,您将看到真正发送给 WebGL 的内容。出于调试目的,您可以将 console.log
放在调用 gl.uniform2fv
之前,以确保没有发生任何错误 "out of view".
在此示例中,如果任何数据被错误转换,您将在输出日志中看到类似 NaN
、NaN
的内容,因此您知道必须在某个地方搜索错误代码。
我正在玩从 this page 复制的 webgl
。我想用鼠标来控制灯的位置。
如果我只是将静态值从 js
发送到 fragment shader
它将起作用:
mouseLocation = gl.getUniformLocation(program, "mouse");
gl.uniform2f(mouseLocation, 0,0);
我有更新鼠标位置的功能:
function updateMousePosition(e){
console.log(e.pageX);
mousex = e.pageX;
mousey = e.pageY;
}
鼠标移动时调用:
canvas.addEventListener( 'mousemove', updateMousePosition, false );
然后每帧发送鼠标位置到fragment shader
:
gl.uniform2f(mouseLocation, mousex,mousey);
之后我将从 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 ...
}
没用。
但是当我从 console.log
in updateMousePosition(e)
:
gl.uniform2f(mouseLocation, 679, 590);//number taken from console.log
有效。
我不确定是什么不起作用,但我怀疑是数字的格式或类型,js
不是严格类型,但 glsl
是。
我该如何解决这个问题?
最后决定放这个答案(已编辑)。
正如 Gman 评论的那样,您的代码显然没有任何问题。从技术上讲,这应该可行。但是,与 OpenGL 相比,您指出了 WebGL/Javascript 这对夫妇的一个真正棘手的方面:字体。由于 Javascript 变量的工作方式,您很容易产生奇怪的错误。
想象一下这种荒谬的情况:
var x = 55;
var y = 128;
// some code here...
x = "blah"; // oups !
// some code here...
gl.uniform2f(mouseLocation, x, y);
用C、C++或其他强类型语言,这种荒谬的事情几乎不可能发生(通过指针是可能的,但这是另一个主题),因为编译器严格禁止并抛出错误。但是在javascript中就没有问题了,而且在这种情况下,x
数字变量变成了字符串变量,传给WebGL后就变成了NaN
。如果您没有正确跟踪 x
变量,您将搜索很长时间为什么这不起作用。
所有WebGL函数只接受最后阶段的类型数据,因为最后阶段是GPU,而GPU是低级的。也就是说,即使您将纯 Javascript 数字变量传递给 WebGL 函数,此 Javascript 变量也会先转换为类型化数据。但事实是 Javascript 永远不会抛出关于错误变量类型的错误:它将它转换(转换)为类型化数据,即使你试图做的事情是荒谬的,它也永远不会警告你,它会转换不可将数据转换为“NaN”。
幸运的是,为了避免歧义,WebGL 附带了一堆新的 Javascript 对象:类型化数组:https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/TypedArray
使用类型化数组,您可以在 javascript 代码中知道存储了哪些数据,以及在发送之前将哪些数据发送到 GPU。 也就是说,您可以在将变量发送到 GPU 之前使用类型化数组将 Javascript 变量转换(转换)为已知的类型化数据。
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);
在上面的例子中,变量e.pageX
和e.pageY
被直接转换成WebGL兼容的类型化数据。这样,如果您现在使用 console.log
打印 mousePos
变量,您将看到真正发送给 WebGL 的内容。出于调试目的,您可以将 console.log
放在调用 gl.uniform2fv
之前,以确保没有发生任何错误 "out of view".
在此示例中,如果任何数据被错误转换,您将在输出日志中看到类似 NaN
、NaN
的内容,因此您知道必须在某个地方搜索错误代码。