使用 three.js 将相机位置锁定到 WebVR/WebXR 中的单个点的最佳方法是什么?
用户仍然需要能够旋转他们的头部,但他们的头部运动不应改变相机的位置 (x,y,z)。
请参阅更新以获得简单的解决方案
这种能力被误导了,并从 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);
}
仅供参考:您将需要优化变量使用以避免无关的分配。我把它们留在里面是为了更好地可视化每个计算的用途。
您可以在每一帧上将相机的位置 xyz 值设置为零以将其锁定到位。但是,请注意,许多用户在观看实际 3D 场景时会感到不舒服。它基本上只对源素材不支持空间移动的 180/360 度视频查看器有用,但即使在这种情况下,如果有任何浮动 UI 元素进行交互,您也应该使用头部位置。