3

我尝试使用颜色索引技术进行挑选,但我想使用光线投射技术并在挑选的 3d 点上添加 3d 标签。

我是 webgl 的新手,我想要一个关于如何使用光线投射在 webgl 中选择对象的示例代码。

如何在 webgl 中进行项目和取消项目。

我正在使用纯 WebGl 来执行此操作(没有 three.js 或其他框架),所以请帮助我使用 webgl 代码示例。

4

1 回答 1

0

如果您对基于 CPU 的解决方案感兴趣,方法如下:

首先要将世界空间转换为屏幕空间坐标,您需要做的就是通过视图投影矩阵转换世界位置。然后您需要通过将 x,y,z 除以 w 来进行透视除法。就是这样。这种形式对我来说最有意义:(假设您有适当的矩阵函数):

vec3.toScreenSpace = function(out, v3, viewProjectionMatrix, width, height){
    vec3.transformByMat(out, v3, viewProjectionMatrix);
    var m = viewProjectionMatrix;
    var w = m[3] * v3[0] + m[7] * v3[1] + m[11] * v3[2] + m[15]; // required for perspective divide
    if (w !== 0){
        var invW = 1.0/w;
        out[0] = (out[0]*invW+1)/2 * width;
        out[1] = (1-out[1]*invW)/2 * height; // note: Y axis oriented top -> down in screen space
    }
    return out;
};

将屏幕空间转换为世界空间基本上是使用逆视图投影矩阵的反向操作:

vec3.toWorldSpace = function(out, v3, viewProjectionMatrix, width, height){
    // expects v3[2] (z value) to be -1 if want position at zNear and +1 at zFar
    var invViewProj = mat4.inverse(vec3.SHARED_MAT4, viewProjectionMatrix);
    var x = 2*v3[0]/width - 1.0;
    var y = 1.0 - (2*v3[1]/height); // note: Y axis oriented top -> down in screen space
    var z = v3[2];
    out[0] = x;
    out[1] = y;
    out[2] = z;
    var m = invViewProj;
    vec3.transformByMat(out, out, m);
    var w = m[3] * x + m[7] * y + m[11] * z + m[15]; // required for perspective divide
    if (w !== 0){
        var invW = 1.0/w;
        out[0] *= invW;
        out[1] *= invW;
        out[2] *= invW;
    }

    return out;
};

然后,当您在屏幕上选择 ax,y 坐标时,您可以计算世界空间中的射线,如下所示:

function screenPickTest(x, y){
    var pos = SHARED_V;
    var posFar = SHARED_V2;
    pos[0] = x;
    pos[1] = y;
    pos[2] = -1;

    posFar[0] = x;
    posFar[1] = y;
    posFar[2] = +1;

    pos = vec3.toWorldSpace(pos, pos, viewProjection, canvas.width, canvas.height);
    posFar = vec3.toWorldSpace(posFar, posFar, viewProjection, canvas.width, canvas.height);

    var dir = vec3.minus(SHARED_V2, posFar, pos);

    return raySweepTestAgainst____(pos, dir, COLLISION_GEOMETRYS);
}

您必须实现碰撞检测功能,以检测光线击中的第一个对象并返回碰撞点(如果需要,还可以提供其他数据)。

有了它,您可以在碰撞点创建标签等。

于 2015-07-31T15:32:48.520 回答