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.pageXe.pageY被直接转换成WebGL兼容的类型化数据。这样,如果您现在使用 console.log 打印 mousePos 变量,您将看到真正发送给 WebGL 的内容。出于调试目的,您可以将 console.log 放在调用 gl.uniform2fv 之前,以确保没有发生任何错误 "out of view".

在此示例中,如果任何数据被错误转换,您将在输出日志中看到类似 NaNNaN 的内容,因此您知道必须在某个地方搜索错误代码。