three.js - 使用 webvr-boilerplate 将 Three.js 对象放置在相机前面,但不绑定(bind)到相机

标签 three.js webvr

我有一个不可见的 object3D。我可以使用 webvr-boilerplate 自由地环顾四周。单击时,我想将此对象放置在相机前面的 3D 位置,使其可见,但位于“地面”上方的某个 y 位置。

我尝试了以下操作,但如果我看向那里,它会将 object3D 放置在半空中,而不是在“地面”上方的某个位置:

var updateMatrix =camera.matrixWorld.clone(); object3D.applyMatrix(updateMatrix);

我认为我需要从中提取某些相机旋转和位置组件并将其应用到我的 object3D 中以获得我想要的。

非常欢迎任何提示!

最佳答案

实现此目的的一种方法是将对象放在枢轴上您希望其出现的位置,然后旋转并定位枢轴,而不是尝试同时计算对象的旋转和位置。

var pivot = new THREE.Object3D();
scene.add(pivot);
pivot.add(object3D);
// position the object on the pivot, so that it appears 5 meters 
// in front of the user.
object3D.position.z = -5;

接下来,一般来说,您希望将相机的四元数分解为其相对于平面的组件。在你的例子中,平面是地面(X-Z,我假设)。

源自 another Stack Overflow answer ,您可以在 Three.js 中通过一些操作来完成此操作:

var yaxis = new THREE.Vector3(0, 1, 0);
var zaxis = new THREE.Vector3(0, 0, 1);
var direction = zaxis.clone();
// Apply the camera's quaternion onto the unit vector of one of the axes
// of our desired rotation plane (the z axis of the xz plane, in this case).
direction.applyQuaternion(camera.quaternion);
// Project the direction vector onto the y axis to get the y component
// of the direction.
var ycomponent = yaxis.clone().multiplyScalar(direction.dot(yaxis));
// Subtract the y component from the direction vector so that we are
// left with the x and z components.
direction.sub(ycomponent);
// Normalize the direction into a unit vector again.
direction.normalize();
// Set the pivot's quaternion to the rotation required to get from the z axis
// to the xz component of the camera's direction.
pivot.quaternion.setFromUnitVectors(zaxis, direction);
// Finally, set the pivot's position as well, so that it follows the camera.
pivot.position.copy(camera.position);

完整示例代码:

var renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.domElement);
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 10000);
var controls = new THREE.VRControls(camera);
var effect = new THREE.VREffect(renderer);
effect.setSize(window.innerWidth, window.innerHeight);
var manager = new WebVRManager(renderer, effect, {hideButton: false});

// Add a repeating grid as a skybox.
var boxWidth = 5;
THREE.ImageUtils.crossOrigin = '';
var texture = THREE.ImageUtils.loadTexture(
  'http://cdn.rawgit.com/borismus/webvr-boilerplate/0.3.3/img/box.png'
);
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(boxWidth, boxWidth);
var skybox = new THREE.Mesh(
  new THREE.BoxGeometry(boxWidth, boxWidth, boxWidth),
  new THREE.MeshBasicMaterial({
    map: texture,
    color: 0x01BE00,
    side: THREE.BackSide
  })
);
scene.add(skybox);

var floorPos = -1.5;
var floor = new THREE.Mesh(
  new THREE.PlaneGeometry(100, 100, 2, 2),
  new THREE.MeshBasicMaterial({color: 'white'})
);
floor.position.set(0, floorPos, 0);
floor.rotation.x = -Math.PI / 2;
scene.add(floor);

var thingDistance = -1;

var box = new THREE.Mesh(
  new THREE.BoxGeometry(0.5, 0.5, 0.5),
  new THREE.MeshNormalMaterial()
  );
box.position.set(-0.5, floorPos, thingDistance);
var boxPos = box.position.clone();
scene.add(box);

var ball = new THREE.Mesh(
  new THREE.SphereGeometry(0.3),
  new THREE.MeshNormalMaterial()
  );
ball.position.set(0.5, floorPos, thingDistance);
var ballPos = ball.position.clone();
scene.add(ball);

var pivot = new THREE.Object3D();
scene.add(pivot);

var ballInFront = false;
document.addEventListener('click', function () {
  if (ballInFront) {
    scene.add(ball);
    ball.position.copy(ballPos);
    
    pivot.add(box);
    box.position.set(0, 0, thingDistance);
    ballInFront = false;
  }
  else {
    scene.add(box);
    box.position.copy(boxPos);
    
    pivot.add(ball);
    ball.position.set(0, 0, thingDistance);
    ballInFront = true;
  }
});


var yaxis = new THREE.Vector3(0, 1, 0);
var zaxis = new THREE.Vector3(0, 0, 1);
function animate(timestamp) {
  controls.update();
  
  var direction = zaxis.clone();
  // Apply the camera's quaternion onto the unit vector of one of the axes
  // of our desired rotation plane (the z axis of the xz plane, in this case).
  direction.applyQuaternion(camera.quaternion);
  // Project the direction vector onto the y axis to get the y component
  // of the direction.
  var ycomponent = yaxis.clone().multiplyScalar(direction.dot(yaxis));
  // Subtract the y component from the direction vector so that we are
  // left with the x and z components.
  direction.sub(ycomponent);
  // Normalize the direction into a unit vector again.
  direction.normalize();
  // Set the pivot's quaternion to the rotation required to get from the z axis
  // to the xz component of the camera's direction.
  pivot.quaternion.setFromUnitVectors(zaxis, direction);
  
  pivot.position.copy(camera.position);
  
  manager.render(scene, camera, timestamp);
  requestAnimationFrame(animate);
}
animate();

function onKey(event) {
  if (event.keyCode == 90) { // z
    controls.resetSensor();
  }
}
window.addEventListener('keydown', onKey, true);
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="SO 34447119">
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
  <meta name="mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-capable" content="yes" />
  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
  <title>JS Bin</title>
  <script src="https://cdn.rawgit.com/borismus/webvr-boilerplate/0.2.2/bower_components/threejs/build/three.js"></script>
  <script src="https://cdn.rawgit.com/borismus/webvr-boilerplate/0.2.2/bower_components/threejs/examples/js/controls/VRControls.js"></script>
  <script src="https://cdn.rawgit.com/borismus/webvr-boilerplate/0.2.2/bower_components/threejs/examples/js/effects/VREffect.js"></script>
  <script src="https://cdn.rawgit.com/borismus/webvr-boilerplate/0.2.2/bower_components/webvr-polyfill/build/webvr-polyfill.js"></script>
  <script src="https://cdn.rawgit.com/borismus/webvr-boilerplate/0.2.2/build/webvr-manager.js"></script>
</head>
<body>
</body> 
</html>

关于three.js - 使用 webvr-boilerplate 将 Three.js 对象放置在相机前面,但不绑定(bind)到相机,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34447119/

相关文章:

animation - 如何克隆蒙皮网格?

javascript - 三.TransformControls属性和方法

javascript - a 框架实体定位和旋转

3d - 如何在 A 型框架中启用加法混合?

Three.js - VRControls 集成 - 如何在场景中移动?

javascript - Three.js:找不到变量 THREE 和意外的字符串文字 l'./polyfills.js'

javascript - 高效地捕捉到threejs中的顶点

javascript - Three.js - Shadow.bias 修复阴影静态,但移动阴影。怎么修?

javascript - teleport-controls 在 VR 模式下的 Aframe 0.8.2 下不起作用

javascript - 如何使用 THREE.js VREffect 渲染多个场景