【问题标题】:WebGL: how to prevent camera bounce when changing center of rotationWebGL:更改旋转中心时如何防止相机反弹
【发布时间】:2013-03-30 02:05:14
【问题描述】:

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

我有一个 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 轴定义的,依此类推。不过,感谢您的建议。

【问题讨论】:

  • 我无法理解您发布的新代码。您计算了eyePitcheyeYaw,但在示例中没有使用eyePitcheyeYaw。如果不了解它们是如何使用的,就很难理解你想要做什么
  • 您好,感谢您的回复。在第二个代码示例中,这只是将轨道从一个点更改为另一个点的代码。实际计算模型视图矩阵以进行渲染的代码是我发布的第一个代码块。这就是使用“eyePitch”和“eyeYaw”的地方。基本上,模型视图矩阵是通过平移到轨道位置来计算的,基于轨道偏航/俯仰定向,然后通过眼睛矢量从轨道平移(在我之前的代码中,它向后平移 -z)。然后它通过眼睛俯仰和眼睛偏航来定位视图。这有帮助吗?
  • 要使用我提供的代码,您需要 2 个矩阵。 (1)相机矩阵。 (2) B的矩阵(matB)。相机矩阵是 matA * eyestuff (请参阅您的第一段代码)。在您上面的示例中,您不计算相机,您只计算 matA。希望这是有道理的。基本加mat4.translate(matA, matA, this.eye); mat.rotateY(matA, matA, this.eyeYaw); mat4.rotateX(matA, matA, this.eyePitch);

标签: javascript math graphics 3d webgl


【解决方案1】:

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

当从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);

【讨论】:

  • w3.org/TR/css3-transforms/#matrix-decomposing 中给出的方法可能会有所帮助。
  • 感谢您的回复。今天我会试试你的建议。
  • 我的建议有问题。主要是因为我不确定在哪个步骤提取轨道角度和眼睛角度(每个偏航和俯仰 - 总共 4 个)。我尝试了很多东西,但都没有奏效。 Pitch 似乎特别糟糕,当我在AB 之间切换时,眼睛越来越远。我将发布一些我所做的代码(目前,我已经对其进行了一些更改以使其正常工作)。
  • 您只需要计算 1 个偏航角和俯仰角。您从A 的平移、偏航和俯仰开始。从A 到相机的平移、偏航和俯仰。而且你还有B 的翻译、偏航和俯仰。您正在尝试将“从 A 到相机的平移、偏航和俯仰”切换为“从 B 到相机的平移、偏航和俯仰”。换句话说,您从 realCamera = A * camera 开始。您希望以 realCamera = B * newCamera 结束,并让 realCamera 与以前相同。
  • 我添加了一个 jsfiddle 示例
猜你喜欢
  • 1970-01-01
  • 2019-10-30
  • 1970-01-01
  • 2014-12-29
  • 1970-01-01
  • 2016-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多