2013-04-08 69 views
1

我已经打了一个脑筋急转弯,正在寻找一些建议或建议。我的问题是这样的:WebGL:如何在更改旋转中心时防止相机反弹

我有一个WebGL场景(我不使用第三方库,除了gl矩阵),其中用户可以旋转相机上/下和左/右(围绕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); 

我试图找出什么轨道和眼右偏航和变桨值,我应该以回迁当前使用位置并实现当前的相机/眼睛方向以避免随着旋转中心移动从一个对象“跳动”到另一个对象。

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

编辑

我也跟着GMAN的建议,尝试下面的代码,但切换轨道只是蹦来跳去。我的模型由多个物体组成,轨道中心可以改变,但是在改变轨道之后,摄像机的方向需要保持稳定,这就是为什么我必须计算对轨道偏航/俯仰和眼睛偏航/俯仰的校正将眼球放回同一点并在改变轨道后指向相同的方向。顺便说一句,我只有一个轨道偏航和变桨的基础上,在当前轨道是,所以这是一个有点不同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工作,但我做左右旋转不同因为音调通常围绕Y轴定义,等等。不过谢谢你的建议。

+0

我无法理解你发布新的代码。你计算'eyePitch'和'eyeYaw',但是在这个例子中你没有使用'eyePitch'和'eyeYaw'。没有看到他们如何使用它很难理解你想要做什么 – gman 2013-04-18 20:53:06

+0

嗨,谢谢你的回应。在第二个代码示例中,这只是从一个点改变到另一个点的代码。实际计算用于渲染的模型视图矩阵的代码是我发布的第一个代码块。这就是'eyePitch'和'eyeYaw'被使用的地方。基本上,模型视图矩阵是通过转化为轨道位置,根据轨道偏航/俯仰定向,然后通过眼矢量(在我之前的代码中,它向后翻转-z)从轨道上转移来计算的。然后它通过眼球俯仰和眼睛偏航定向视图。这有帮助吗? – superqd 2013-04-19 18:38:44

+0

要使用我提供的代码,您需要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);' – gman 2013-04-19 23:15:23

回答

0

我不知道我能解释这一点,但基本上是:

当从A切换到B,在开关机时间,

  1. 计算相机四处A(你的代码的矩阵有以上)。 (camera
  2. 计算矩阵为BmatB
  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; 

和这里的是,CDS相机

// 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); 
+0

在http://www.w3.org/TR/css3-transforms/#matrix-decomposing中给出了一种方法,可能有所帮助。 – JayC 2013-04-09 05:46:46

+0

我很欣赏这个回应。我会在今天尝试你的建议。 – superqd 2013-04-09 20:12:10

+0

我的建议存在问题。主要是因为我不确定在哪个步骤中提取轨道角度和眼角(偏航和俯仰 - 每个 - 总共4个)。我尝试了一些东西,没有什么工作。当我在'A'和'B'之间切换时,音高看起来特别糟糕,眼睛越来越远。我会发布我所做的一些代码(目前,我已经改变了一下它试图让它工作)。 – superqd 2013-04-10 22:08:44