1

我遇到了某种心理障碍,正在寻找一些建议或建议。我的问题是这样的:

我有一个 WebGL 场景(我没有使用第三方库,除了 gl-matrix),用户可以在其中向上/向下和向左/向右旋转相机(围绕 X/Y 轴旋转)。他们也可以旋转模型(偏航/俯仰)。

要查看问题,假设模型有两个块,A 和 B 在场景中,A 在中心,B 在右侧(在视口中),旋转中心在 A 的中心。如果用户旋转模型,它围绕块 A 的中心旋转。但是如果用户单击对象 B,我需要能够将旋转中心更改为 B 的中心,但仍保持当前的相机方向。目前,当旋转中心切换到 B 时,块 B 移动到屏幕中心,块 A 移动到左侧。基本上,代码始终以当前中心或旋转为中心。

我使用以下代码进行模型视图矩阵更新:

var mvMatrix = this.mvMatrix;

mat4.identity(mvMatrix);

mat4.translate(mvMatrix, mvMatrix, this.orbit);
mat4.rotateY(mvMatrix, mvMatrix, this.orbitYaw);
mat4.rotateX(mvMatrix, mvMatrix, this.orbitPitch);

mat4.translate(mvMatrix, mvMatrix, this.eye);
mat4.rotateY(mvMatrix, mvMatrix, this.eyeYaw);
mat4.rotateX(mvMatrix, mvMatrix, this.eyePitch);

我试图弄清楚我应该使用什么正确的轨道和眼睛的偏航和俯仰值来移回当前位置并实现当前的相机/眼睛方向以避免从一个物体“反弹”到另一个物体旋转中心移动。

我搜索了很多,似乎找不到最好的方法(我目前的尝试有问题​​)。任何示例代码,或者只是好的描述将不胜感激。

编辑

我按照 gman 的建议尝试了以下代码,但切换轨道只是跳来跳去。我的模型是由多个物体组成的,轨道中心可以改变,但是改变轨道后,相机的方向需要保持稳定,这就是为什么我要计算对轨道偏航/俯仰和眼睛偏航/俯仰的校正改变轨道后将眼睛放回同一位置并指向同一方向。顺便说一句,根据当前轨道的位置,我只有一个轨道偏航和俯仰,所以这与 gman 的样本有点不同:

Camera.prototype.changeOrbit = function (newOrbit) {
var matA = mat4.create();
var matB = mat4.create();

mat4.translate(matA, matA, this.orbit);
mat4.rotateY(matA, matA, this.orbitYaw);
mat4.rotateX(matA, matA, this.orbitPitch);

mat4.translate(matB, matB, newOrbit);
mat4.rotateY(matB, matB, this.orbitYaw);
mat4.rotateX(matB, matB, this.orbitPitch);

var matInverseNewOrbit  = mat4.create();
var matNewOrbitToCamera = mat4.create();

mat4.invert(matInverseNewOrbit, matB);
mat4.multiply(matNewOrbitToCamera, matInverseNewOrbit, matA);

var m = matNewOrbitToCamera;

this.eye[0] = m[12];
this.eye[1] = m[13];
this.eye[2] = m[14];

this.eyePitch = ExtractPitch(m);
this.eyeYaw   = ExtractYaw(m);

this.update();
};

ExtractPitch 和 ExtractYaw 按照 gman 的规定工作,但我确实围绕不同的轴旋转,因为俯仰通常是围绕 Y 轴定义的,依此类推。不过,感谢您的建议。

4

1 回答 1

0

我不确定我能否解释这一点,但基本上:

当从 切换A到 时B,在切换时,

  1. 计算相机的矩阵A(上面的代码)。( camera)
  2. 计算B( matB)的矩阵
  3. 计算矩阵的逆B。( inverseMatB)
  4. 乘以。camera_ inverseMatB( matBtoCamera)

    您现在有一个从B相机到相机的矩阵。

  5. 将此矩阵 ( matBToCamera) 分解回平移和旋转。

不幸的是,我不知道有一个好的分解矩阵函数来指向你。我已经很久不需要了。翻译基本上是矩阵的第 12、13、14 个元素。(假设您使用的是 16 个元素矩阵,我认为这是 glMatrix 使用的)。

var translation = [m[12], m[13], m[14]];

对于旋转,矩阵的上/左 3x3 部分表示旋转。只要不涉及缩放或倾斜,根据此页面 ( http://nghiaho.com/?page_id=846 ) 它是

var rotXInRadians = Math.atan2(m[9], m[10]);
var rotYInRadians = Math.atan2(-m[8], Math.sqrt(m[9] * m[9] + m[10] * m[10]));
var rotZInRadians = Math.atan2(m[4], m[0]);

这是一个例子

http://jsfiddle.net/greggman/q7Bsy/

我将在此处粘贴特定于 glMatrix 的代码

// first let's make 3 nodes, 'a', 'b', and 'camera

var degToRad = function(v) {
  return v * Math.PI / 180;
}

var a = {
  name: "a",
  translation: [0, -50, -75],
  pitch: 0,
  yaw: degToRad(30),
};

var b = {
  name: "b",
  translation: [0, 100, 50],
  pitch: 0,
  yaw: degToRad(-75),
}

var camera = {
  name: "cam",
  translation: [0, 15, 10],
  pitch: 0,
  yaw: degToRad(16),
  parent: a,
};

这是计算每个矩阵的代码

var matA = mat4.create();
mat4.identity(matA);
mat4.translate(matA, matA, a.translation);
mat4.rotateY(matA, matA, a.pitch);
mat4.rotateX(matA, matA, a.yaw);
a.mat = matA;

var matB = mat4.create();
mat4.identity(matB);
mat4.translate(matB, matB, b.translation);
mat4.rotateY(matB, matB, b.pitch);
mat4.rotateX(matB, matB, b.yaw);
b.mat = matB;

var matCamera = mat4.create();
mat4.identity(matCamera);

var parent = camera.parent;

mat4.translate(matCamera, matCamera, parent.translation);
mat4.rotateY(matCamera, matCamera, parent.pitch);
mat4.rotateX(matCamera, matCamera, parent.yaw);

mat4.translate(matCamera, matCamera, camera.translation);
mat4.rotateY(matCamera, matCamera, camera.pitch);
mat4.rotateX(matCamera, matCamera, camera.yaw);

camera.mat = matCamera;

这是交换相机的代码

// Note: Assumes matrices on objects are updated.
var reparentObject = function(obj, newParent) {
  var matInverseNewParent = mat4.create();
  var matNewParentToObject = mat4.create();
  mat4.invert(matInverseNewParent, newParent.mat);
  mat4.multiply(matNewParentToObject, matInverseNewParent, obj.mat);

  var m = matNewParentToObject;
  obj.translation[0] = m[12];
  obj.translation[1] = m[13];
  obj.translation[2] = m[14];

  var rotXInRadians = Math.atan2(m[9], m[10]);
  var rotYInRadians = Math.atan2(-m[8], Math.sqrt(m[9] * m[9] + m[10] * m[10]));
  var rotZInRadians = Math.atan2(m[4], m[0]);

  obj.pitch = rotYInRadians;
  obj.yaw = rotXInRadians;
  obj.parent = newParent;
};

var newParent = camera.parent == a ? b : a;
reparentObject(camera, newParent);
于 2013-04-09T03:49:54.160 回答