【问题标题】:View matrix needed for eye tracking scenario眼动追踪场景所需的视图矩阵
【发布时间】:2017-09-06 15:45:51
【问题描述】:

我正忙于一个小项目,我不会使用网络摄像头来跟踪用户的“眼睛位置”(从人的眼睛位置相对于屏幕中心的矢量)并使用这个“摄像头角度”来操作一个threeJS场景(或者可能只是直接的WebGL),这样看起来屏幕本身就是一个进入3d环境的“窗口”。完成这一点我相信所需要的(假设您已经拥有“眼睛摄像机角度”)就是操纵视图矩阵。例如,左边的图像将是标准视图矩阵的典型视锥体,给定一个直的摄像机角度。如果“眼睛相机位置”向上移动,右侧的图像将是理想的矩阵和产生的视锥。

这就像换掉使用的标准视图矩阵一样简单吗? 矩阵会是什么样子。

回答时请记住,我对线性代数的了解与一年级学生一样多。 此外,有关详细信息,此项目将基于使用 WebGL 和 JavaScript 的浏览器。

顺便说一句,我刚刚发现,我在这里尝试做的事情被称为:“头部耦合透视”

【问题讨论】:

  • 我所拥有的有限知识告诉我,你所说的正是我的想法,在这两个方面,但我严重缺乏数学知识来弄清楚如何构建这样的矩阵。

标签: javascript math 3d three.js


【解决方案1】:

这不是一个完整的答案,但是......目前我太懒/太忙了,但如果我理解正确,你基本上想要一个像glFrustum 这样的函数。数学在那里,但格式很差。这使您可以生成一个眼睛不在中心的平截头体矩阵(就像透视函数一样)。 Three.js 在Camera.setViewOffset 中也对此提供了支持。

要使用Camera.setViewOffset,基本上你定义了一个更大的视图,以及画布代表那个更大视图的three.js画布的哪个子部分。在这种情况下,我们不关心更大的视图,因此我们可以将更大的视图和子视图设置为相同的大小,但仍然偏移较小的视图。

因此,为了有效地匹配用户的眼睛位置,您需要在较大区域内选择一个中心区域移动相机。

我现在懒得做的是弄清楚每个人要移动多少。除了相机以世界单位移动并且setViewOffset 以像素为单位之外,它们似乎是相同的。 CSS 像素应该是每英寸 96,因此对于眼睛移动的每一英寸,我们需要将视图偏移到相反的方向 96 * 眼睛移动英寸。

我们还需要知道用户的眼睛离屏幕有多远屏幕有多大,以便我们可以计算屏幕的视野。当用户站在 3 英尺外的 60 英寸电视上,用户在 11 英寸笔记本电脑前,脸在 1 英尺外时的视野会有所不同

let mouse = new THREE.Vector2(), INTERSECTED;
let radius = 100, theta = 0;

const camera = new THREE.PerspectiveCamera(70, 1, 1, 10000);

const scene = new THREE.Scene();
scene.background = new THREE.Color(0xf0f0f0);

const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set( 1, 1, 1 ).normalize();
scene.add( light );

const geometry = new THREE.BoxBufferGeometry(1, 1, 1);

for (let z = 0; z < 50; ++z) {
  for (let y = -1; y <= 1; ++y) {
    for (let x = -1; x <= 1; ++x) {
      if (x === 0 && y === 0) {
         continue;
      }
      const object = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({ color: Math.random() * 0xffffff}));
  
      object.position.x =  x * 1.5;
      object.position.y =  y * 1.5;
      object.position.z = -z * 2.5;

      scene.add(object);
    }
  }
}

renderer = new THREE.WebGLRenderer({canvas: document.querySelector("canvas")});
resize(true);
document.addEventListener( 'mousemove', onDocumentMouseMove, false );

requestAnimationFrame(render);

function resize(force) {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  if (force || canvas.width !== width || canvas.height !== height) {
    renderer.setSize(width, height, true);
    camera.aspect = width / height;
    camera.updateProjectionMatrix();
  }
}

function onDocumentMouseMove( event ) {
  event.preventDefault();
  const canvas = renderer.domElement;
  // compute mouse movement in inches
  mouse.x = (event.clientX - canvas.clientWidth  / 2) / 96;
  mouse.y = (event.clientY - canvas.clientHeight / 2) / 96;
}

function render(time) {
  const worldUnits = 1;
  const pixelUnits = worldUnits * 96;  

  const canvas = renderer.domElement;
  const fullWidth  = canvas.clientWidth;
  const fullHeight = canvas.clientHeight;
  const aspect = fullWidth / fullHeight;
  
  const eyeOffsetX = mouse.x;
  const eyeOffsetY = mouse.y;
  
  const eyeDistFromScreenInches = 12;
  const halfHeightOfScreenInches = fullHeight / 96 * .5;
  const halfFov = Math.atan2(halfHeightOfScreenInches, eyeDistFromScreenInches) * 180 / Math.PI;
  const width   = fullWidth;
  const height  = fullHeight;
  const centerX = fullWidth / 2;
  const centerY = fullHeight / 2;
  const left    = centerX - width /  2 - eyeOffsetX * pixelUnits;
  const top     = centerY - height / 2 - eyeOffsetY * pixelUnits;
  
  camera.fov = halfFov * 2;  
  camera.position.x =  eyeOffsetX * worldUnits;
  camera.position.y = -eyeOffsetY * worldUnits;
  
  camera.setViewOffset(fullWidth, fullHeight, left, top, width, height);
  camera.updateProjectionMatrix();
  
  renderer.render(scene, camera);
  
  requestAnimationFrame(render);
}
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/87/three.min.js"></script>
<canvas></canvas>

【讨论】:

  • 有机会我会看看这个,但这听起来像是我正在寻找的解决方案。
  • 所以我初步看了一下,它看起来正是我想要的,谢谢。至于关于实际深度计算的评论,我想无论如何我都必须“猜测”,尽管也许在某个时候,我会将这个项目连接到谷歌探戈硬件以获得实际距离信息:)
  • 顺便说一句:有一个图书馆,headtrackr.js。它links to a sample。在图书馆里我看到similar code
猜你喜欢
  • 2014-10-20
  • 2012-11-30
  • 2018-07-09
  • 2011-05-15
  • 2012-05-19
  • 2015-12-17
  • 1970-01-01
  • 2018-12-08
  • 2015-08-12
相关资源
最近更新 更多