Webgl - 动态鼠标位置

时间:2017-10-07 03:20:22

标签: javascript webgl glsles

我正在玩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中的updateMousePosition(e)发送静态值时:

gl.uniform2f(mouseLocation, 679, 590);//number taken from console.log

它有效。

我不确定什么不起作用,但我怀疑是数字的格式或类型,js不是严格类型,而是glsl

我该如何解决这个问题?

1 个答案:

答案 0 :(得分:0)

Finaly决定把这个答案(编辑)。

正如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 Number变量传递给WebGL函数,此Javascript变量也会转换为之前的类型化数据。但事实是Javascript永远不会抛出关于错误变量类型的错误:它将它(转换)转换为类型化数据,即使你试图做的是荒谬的,它也永远不会警告你,它会转换不可转换的数据进入' NaN`。

幸运的是,为了避免任何歧义,WebGL附带了一堆新的Javascript对象:Typed Arrays:https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/TypedArray

使用类型化数组,您可以在javascript代码中知道存储的数据,以及在发送数据之前将哪些数据发送到GPU。 也就是说,您可以使用类型化数组将Javascript变量转换(转换)为已知类型数据,然后再将其发送到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);

在上面的示例中,变量e.pageXe.pageY直接转换为WebGL兼容的类型数据。这样,如果您现在使用mousePos打印console.log变量,您将看到将真正发送到WebGL的内容。出于调试目的,您可以在调用console.log之前放置gl.uniform2fv以确保没有发生任何错误"在视图之外"。

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