Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/365.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript WebGL:如何在更改旋转中心时防止相机反弹_Javascript_Math_Graphics_3d_Webgl - Fatal编程技术网

Javascript WebGL:如何在更改旋转中心时防止相机反弹

Javascript WebGL:如何在更改旋转中心时防止相机反弹,javascript,math,graphics,3d,webgl,Javascript,Math,Graphics,3d,Webgl,我遇到了各种各样的心理障碍,正在寻求一些建议或建议。我的问题是: 我有一个WebGL场景(除了gl矩阵,我没有使用第三方库),用户可以在其中上/下和左/右旋转相机(绕X/Y轴旋转)。它们还可以旋转模型(偏航/俯仰) 要查看问题,请假设模型在场景中有两个块,A和B,A在中心,B在右侧(在视口中),旋转中心在A的中心。如果用户旋转模型,它将围绕块A的中心旋转。但是如果用户单击对象B,我需要能够将旋转中心更改为B的中心,但仍保持当前相机方向。当前,当旋转中心切换到B时,块B移到屏幕中心,块A移到左侧。

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

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

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

我使用以下代码更新modelview矩阵:

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轴定义的,依此类推。不过,谢谢你的建议。

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

A
切换到
B
时,在切换时间

  • 计算相机绕
    A
    旋转的矩阵(上面的代码)。(
    摄像机
  • 计算
    B
    matB
    )的矩阵
  • 计算
    B
    的矩阵的逆。(
    inverseMatB
  • inverseMatB
    乘以
    camera
    。(
    matBtoCamera

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

  • 将此矩阵(
    matBToCamera
    )分解回平移和旋转

  • 不幸的是,我不知道有什么好的分解矩阵函数可以告诉你。我已经很久不需要了。翻译基本上是矩阵的元素12,13,14。(假设您使用16个元素矩阵,我认为这就是glMatrix使用的)

    对于旋转,矩阵的上/左3x3部分表示旋转。根据本页()的说法,只要不涉及缩放或倾斜,它就是

    这里有一个例子

    我将在这里粘贴特定于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);
    

    有一种方法可能会有所帮助。我很感激你的回答。我今天会试试你的建议。我对这个建议有意见。主要是因为我不确定在哪一步提取轨道角和眼角(每一步的偏航和俯仰总计为-4)。我尝试了很多方法,但都没有奏效。音调似乎特别糟糕,当我在
    A
    B
    之间切换时,眼睛越来越远。我将发布一些我所做的代码(目前,为了让它工作,我对它做了一些修改)。你只需要计算1个偏航和俯仰。从
    A
    的平移、偏航和俯仰开始。从
    A
    到摄像机的平移、偏航和俯仰。还有
    B
    的平移、偏航和俯仰。您正在尝试将“从A到摄影机的平移、偏航和俯仰”切换为“从B到摄影机的平移、偏航和俯仰”。换句话说,从realCamera=A*camera开始。您希望以realCamera=B*newCamera结束,并使realCamera与以前一样。我添加了一个JSFIDLE示例我在理解您发布的新代码时遇到问题。您可以计算
    眼距
    眼偏航
    ,但在示例中没有使用
    眼距
    眼偏航
    。如果看不到它们是如何使用的,很难理解你想做什么。嗨,谢谢你的回复。在第二个代码示例中,这只是将轨道从一点更改到另一点的代码。实际计算模型视图矩阵以进行渲染的代码是我发布的第一段代码。这就是“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)
    
    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);