WebGL- 添加标签和拾取对象

WebGL- add label and pick object

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

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

如何在 webgl 中进行投影和取消投影。

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

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

首先将worldspace转换成screenspace坐标,你需要做的就是通过view-projection矩阵变换world pos。然后,您需要通过将 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;
};

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

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;
};

然后当你 select 屏幕上的 x,y 坐标时,你可以像这样计算世界 space 中的光线:

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);
}

您必须实施碰撞检测功能,检测光线击中的第一个物体和returns碰撞点(如果需要,还有其他数据)。

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