2

使用 three.js 将相机位置锁定到 WebVR/WebXR 中的单个点的最佳方法是什么?

用户仍然需要能够旋转他们的头部,但他们的头部运动不应改变相机的位置 (x,y,z)。

4

2 回答 2

1

请参阅更新以获得简单的解决方案

这种能力被误导了,并从 WebXR 规范中明确删除

他们的“微不足道”的位置数据剥离示例在他们的360-photos.html示例中,并且它是skyboxMaterial类的顶点着色器,被他们复杂的渲染器吃掉了。

具体来说:

get vertexSource() {
    return `
    uniform int EYE_INDEX;
    uniform vec4 texCoordScaleOffset[2];
    attribute vec3 POSITION;
    attribute vec2 TEXCOORD_0;
    varying vec2 vTexCoord;

    vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {
      vec4 scaleOffset = texCoordScaleOffset[EYE_INDEX];
      vTexCoord = (TEXCOORD_0 * scaleOffset.xy) + scaleOffset.zw;
      // Drop the translation portion of the view matrix
      view[3].xyz = vec3(0.0, 0.0, 0.0);
      vec4 out_vec = proj * view * model * vec4(POSITION, 1.0);

      // Returning the W component for both Z and W forces the geometry depth to
      // the far plane. When combined with a depth func of LEQUAL this makes the
      // sky write to any depth fragment that has not been written to yet.
      return out_vec.xyww;
    }`;
  }

美好而琐碎... /s

希望这会有所帮助,我目前正在解决同样的问题,如果/当我克服它时,我会更新这个答案。

更新 2: 正如所承诺的,而不是修改每个着色器以支持此功能。在处理每个 xrPose 的视图时执行以下操作:

    //NOTE: Uses the gl-matrix.js library, albeit slightly modified
    //to add vec3.multiplyBy. Which is used to multiply a vector
    //by a single value.
    
    let dist;
    let poseMaxDist = 0.4; //0.4M or 1.2ft
    
    let calculatedViewPos;
    let viewRotAsQuat;
    let vector;

    let origin = vec3.create();
    let framePose = vec3.create();
    let poseToBounds = vec3.create();
    let elasticTransformMatrix = mat4.create();

    let view = pose.views[viewIdx];
    //If positionDisabled, negate headset position changes, while maintaining
    //eye offset which allows for limited translation as users head does
    //move laterally when looking around.
    if(_positionDisabled){
        //DOMPoint to vec3 easier calculations.
        framePose = vec3.fromValues(
            pose.transform.position.x,
            pose.transform.position.y,
            pose.transform.position.z);

        //Distance from the origin
        dist = vec3.distance(origin, framePose);

        if(dist >= poseMaxDist){
            //calculation 'origin' == A
            //framePose == B
            let AB = vec3.create();
            let AC = vec3.create();
            let C = vec3.create();
            let CB = vec3.create();

            //Vector from origin to pose
            vec3.subtract(AB, framePose, origin);

            //Unit vector from origin to pose
            vec3.normalize(AB, AB);

            //Max allowed vector from origin to pose
            vec3.multiplyBy(AC, AB, poseMaxDist);

            //Limit point from origin to pose using max allowed vector  
            vec3.add(C, origin, AC);
      
            //vector from pose to limit point, use to shift view
            vec3.subtract(poseToBounds, C, framePose);

            //vector from limit point to pose, use to shift origin
            vec3.subtract(CB, framePose, C);

            //Shift calculation 'origin'
            vec3.add(origin, origin, CB);

            //adjust view matrix using the caluclated origin,
            //and the vector from the pose to the limit point.
            calculatedViewPos = vec4.fromValues(
                view.transform.position.x - origin[0] + poseToBounds[0],
                view.transform.position.y - origin[1] + poseToBounds[1],
                view.transform.position.z - origin[2] + poseToBounds[2],
                view.transform.position.w);

        }else{
            //adjust view matrix using the caluclated origin
            calculatedViewPos = vec4.fromValues(
                view.transform.position.x - origin[0],
                view.transform.position.y - origin[1],
                view.transform.position.z - origin[2],
                view.transform.position.w);
        }

        //Changing the DOMPoint to a quat for easier matrix calculation.
        viewRotAsQuat = quat.fromValues(
            view.transform.orientation.x,
            view.transform.orientation.y,
            view.transform.orientation.z,
            view.transform.orientation.w
        );

        mat4.fromRotationTranslation(elasticTransformMatrix, viewRotAsQuat, calculatedViewPos)

        mat4.invert(elasticTransformMatrix, elasticTransformMatrix);
            
        mat4.multiply(modelViewMatrix, elasticTransformMatrix, entity.transformMatrix);

    }else{
        mat4.multiply(modelViewMatrix, view.transform.inverse.matrix, entity.transformMatrix);
    }

仅供参考:您将需要优化变量使用以避免无关的分配。我把它们留在里面是为了更好地可视化每个计算的用途。

于 2021-04-29T19:51:31.963 回答
0

您可以在每一帧上将相机的位置 xyz 值设置为零以将其锁定到位。但是,请注意,许多用户在观看实际 3D 场景时会感到不舒服。它基本上只对源素材不支持空间移动的 180/360 度视频查看器有用,但即使在这种情况下,如果有任何浮动 UI 元素进行交互,您也应该使用头部位置。

于 2020-01-02T18:20:42.280 回答