它有什么问题 - 或者如何找到正确的 THREE.PerspectiveCamera 设置
what's wrong with it - or how to find correct THREE.PerspectiveCamera settings
我有一个简单的 THREE.Scene,其中主要内容是一个 THREE.Line 网格,可视化基于关键帧的路径,相机将遵循该路径进行一些脚本动画。然后有一个基于 THREE.SphereGeometry 的网格,它总是重新定位到当前相机位置。
当前错误的结果如下所示(分形背景独立渲染但使用相同的关键帧输入 - 最终的想法是 "camera path" 可视化结果与 scale/projection 相同各自的分形背景...):
base是一个关键帧数组,每个关键帧代表一个特定相机的modelViewMatrixposition/orientation,直接用于驱动背景的vertexshader,例如:
varying vec3 eye, dir;
void main() {
gl_Position = vec4(position, 1.0);
eye = vec3(modelViewMatrix[3]);
dir = vec3(modelViewMatrix * vec4(position.x , position.y , 1, 0));
}
(据我了解,"eye" 基本上是相机位置,而 "dir" 反映了相机的方向,顺便说一句,它在光线行进期间使用,隐含地导致透视投影)
各个网格对象是这样创建的:
visualizeCameraPath: function(scene) {
// debug: visualize the camera path
var n= this.getNumberOfKeyFrames();
var material = new THREE.LineBasicMaterial({
color: 0xffffff
});
var geometry = new THREE.Geometry();
for (var i= 0; i<n; i++) {
var m= this.getKeyFrameMatrix(true, i);
var pos= new THREE.Vector3();
var q= new THREE.Quaternion();
var scale= new THREE.Vector3();
m.decompose(pos,q,scale);
geometry.vertices.push( new THREE.Vector3( pos.x, pos.y, pos.z ));
}
this.camPath = new THREE.Line( geometry, material );
this.camPath.frustumCulled = false; // Avoid getting clipped - does not seem to help one little bit
scene.add( this.camPath );
var radius= 0.04;
var g = new THREE.SphereGeometry(radius, 10, 10, 0, Math.PI * 2, 0, Math.PI * 2);
this.marker = new THREE.Mesh(g, new THREE.MeshNormalMaterial());
scene.add(this.marker);
}
为了播放动画,我像这样更新相机和标记位置(我想我直接在 "shadowCamera" 上使用输入矩阵 "m" 的方式已经是错误的 - 尽管我认为它包含正确的位置):
syncShadowCamera(m) {
var pos= new THREE.Vector3();
var q= new THREE.Quaternion();
var scale= new THREE.Vector3();
m.decompose(pos,q,scale);
this.applyMatrix(m, this.shadowCamera); // also sets camera position to "pos"
// highlight current camera-position on the camera-path-line
if (this.marker != null) this.marker.position.set(pos.x, pos.y, pos.z);
},
applyMatrix: function(m, targetObj3d) {
var pos= new THREE.Vector3();
var q= new THREE.Quaternion();
var scale= new THREE.Vector3();
m.decompose(pos,q,scale);
targetObj3d.position.set(pos.x, pos.y, pos.z);
targetObj3d.quaternion.set(q.x, q.y, q.z, q.w);
targetObj3d.scale= scale;
targetObj3d.updateMatrix(); // this.matrix.compose( this.position, this.quaternion, this.scale );
targetObj3d.updateMatrixWorld(true);
},
我已经尝试了很多关于相机的事情,屏幕截图反映了禁用 "this.projectionMatrix" 的输出(见下面的代码)。
createShadowCamera: function() {
var speed = 0.00039507;
var z_near = Math.abs(speed);
var z_far = speed * 65535.0;
var fH = Math.tan( this.FOV_Y * Math.PI / 360.0 ) * z_near;
var fW = Math.tan( this.FOV_X * Math.PI / 360.0 ) * z_near;
// orig opengl used: glFrustum(-fW, fW, -fH, fH, z_near, z_far);
var camera= new THREE.PerspectiveCamera();
camera.updateProjectionMatrix = function() {
// this.projectionMatrix.makePerspective( -fW, fW, fH, -fH, z_near, z_far );
this.projectionMatrix= new THREE.Matrix4(); // hack: fallback to no projection
};
camera.updateProjectionMatrix();
return camera;
},
我最初的尝试是使用与分形背景的 opengl 着色器使用的相同类型的设置(参见上面的 glFrustum)。不幸的是,我似乎还没有成功地将输入"modelViewMatrix"(以及由着色器中的光线行进隐式执行的投影)正确映射到等效的THREE.PerspectiveCamera设置(orientation/projectionMatrix)。
这里有没有矩阵计算专家,知道如何获得正确的变换?
我终于找到了一种行之有效的技巧。
实际上问题由两部分组成:
1) modelViewMatrix 的行优先顺序与列优先顺序:顶点着色器预期的顺序与其余 THREE.js 预期的顺序相反..
2) Object3D 层次结构:即场景、网格、几何、线顶点 + 相机:放置 modelViewMatrix 数据的位置,以便它创建所需的结果(即与旧的该死的 opengl 应用程序产生的相同结果):我对我在这里发现的 hack 不满意 - 但到目前为止它是唯一一个似乎有效的:
- 我没有碰相机..它停留在 0/0/0
- 我直接移动我的 "line"-Geometry 相对于真实相机位置的所有顶点(参见 modelViewMatrix 中的 "position")
- 然后我在包含我的 "line" 几何体的网格上禁用 "matrixAutoUpdate" 并将 modelViewMatrix(我首先将 "position" 置零)复制到 "matrix"场.
BINGO.. 然后就可以了。 (我通过 rotating/displacing 相机或 displacing/rotating 涉及的任何 Object3D 实现相同结果的所有尝试都惨遭失败..)
编辑:我找到了一种比更新顶点更好的方法,并且至少将所有操作都保持在网格级别(我仍在移动世界 - 就像旧的 OpenGL 应用程序所做的那样......)。要获得 translation/rotation 的正确顺序,还可以使用("m" 仍然是原始的 OpenGL modelViewMatrix - 具有 0/0/0 位置信息):
var t= new THREE.Matrix4().makeTranslation(-cameraPos.x, -cameraPos.y, -cameraPos.z);
t.premultiply ( m );
obj3d.matrixAutoUpdate=false;
obj3d.matrix.copy(t);
如果有人知道更好的方法(无需直接操作对象矩阵即可更新相机),我当然有兴趣听听。
我有一个简单的 THREE.Scene,其中主要内容是一个 THREE.Line 网格,可视化基于关键帧的路径,相机将遵循该路径进行一些脚本动画。然后有一个基于 THREE.SphereGeometry 的网格,它总是重新定位到当前相机位置。
当前错误的结果如下所示(分形背景独立渲染但使用相同的关键帧输入 - 最终的想法是 "camera path" 可视化结果与 scale/projection 相同各自的分形背景...):
base是一个关键帧数组,每个关键帧代表一个特定相机的modelViewMatrixposition/orientation,直接用于驱动背景的vertexshader,例如:
varying vec3 eye, dir;
void main() {
gl_Position = vec4(position, 1.0);
eye = vec3(modelViewMatrix[3]);
dir = vec3(modelViewMatrix * vec4(position.x , position.y , 1, 0));
}
(据我了解,"eye" 基本上是相机位置,而 "dir" 反映了相机的方向,顺便说一句,它在光线行进期间使用,隐含地导致透视投影)
各个网格对象是这样创建的:
visualizeCameraPath: function(scene) {
// debug: visualize the camera path
var n= this.getNumberOfKeyFrames();
var material = new THREE.LineBasicMaterial({
color: 0xffffff
});
var geometry = new THREE.Geometry();
for (var i= 0; i<n; i++) {
var m= this.getKeyFrameMatrix(true, i);
var pos= new THREE.Vector3();
var q= new THREE.Quaternion();
var scale= new THREE.Vector3();
m.decompose(pos,q,scale);
geometry.vertices.push( new THREE.Vector3( pos.x, pos.y, pos.z ));
}
this.camPath = new THREE.Line( geometry, material );
this.camPath.frustumCulled = false; // Avoid getting clipped - does not seem to help one little bit
scene.add( this.camPath );
var radius= 0.04;
var g = new THREE.SphereGeometry(radius, 10, 10, 0, Math.PI * 2, 0, Math.PI * 2);
this.marker = new THREE.Mesh(g, new THREE.MeshNormalMaterial());
scene.add(this.marker);
}
为了播放动画,我像这样更新相机和标记位置(我想我直接在 "shadowCamera" 上使用输入矩阵 "m" 的方式已经是错误的 - 尽管我认为它包含正确的位置):
syncShadowCamera(m) {
var pos= new THREE.Vector3();
var q= new THREE.Quaternion();
var scale= new THREE.Vector3();
m.decompose(pos,q,scale);
this.applyMatrix(m, this.shadowCamera); // also sets camera position to "pos"
// highlight current camera-position on the camera-path-line
if (this.marker != null) this.marker.position.set(pos.x, pos.y, pos.z);
},
applyMatrix: function(m, targetObj3d) {
var pos= new THREE.Vector3();
var q= new THREE.Quaternion();
var scale= new THREE.Vector3();
m.decompose(pos,q,scale);
targetObj3d.position.set(pos.x, pos.y, pos.z);
targetObj3d.quaternion.set(q.x, q.y, q.z, q.w);
targetObj3d.scale= scale;
targetObj3d.updateMatrix(); // this.matrix.compose( this.position, this.quaternion, this.scale );
targetObj3d.updateMatrixWorld(true);
},
我已经尝试了很多关于相机的事情,屏幕截图反映了禁用 "this.projectionMatrix" 的输出(见下面的代码)。
createShadowCamera: function() {
var speed = 0.00039507;
var z_near = Math.abs(speed);
var z_far = speed * 65535.0;
var fH = Math.tan( this.FOV_Y * Math.PI / 360.0 ) * z_near;
var fW = Math.tan( this.FOV_X * Math.PI / 360.0 ) * z_near;
// orig opengl used: glFrustum(-fW, fW, -fH, fH, z_near, z_far);
var camera= new THREE.PerspectiveCamera();
camera.updateProjectionMatrix = function() {
// this.projectionMatrix.makePerspective( -fW, fW, fH, -fH, z_near, z_far );
this.projectionMatrix= new THREE.Matrix4(); // hack: fallback to no projection
};
camera.updateProjectionMatrix();
return camera;
},
我最初的尝试是使用与分形背景的 opengl 着色器使用的相同类型的设置(参见上面的 glFrustum)。不幸的是,我似乎还没有成功地将输入"modelViewMatrix"(以及由着色器中的光线行进隐式执行的投影)正确映射到等效的THREE.PerspectiveCamera设置(orientation/projectionMatrix)。
这里有没有矩阵计算专家,知道如何获得正确的变换?
我终于找到了一种行之有效的技巧。
1) modelViewMatrix 的行优先顺序与列优先顺序:顶点着色器预期的顺序与其余 THREE.js 预期的顺序相反..
2) Object3D 层次结构:即场景、网格、几何、线顶点 + 相机:放置 modelViewMatrix 数据的位置,以便它创建所需的结果(即与旧的该死的 opengl 应用程序产生的相同结果):我对我在这里发现的 hack 不满意 - 但到目前为止它是唯一一个似乎有效的:
- 我没有碰相机..它停留在 0/0/0
- 我直接移动我的 "line"-Geometry 相对于真实相机位置的所有顶点(参见 modelViewMatrix 中的 "position")
- 然后我在包含我的 "line" 几何体的网格上禁用 "matrixAutoUpdate" 并将 modelViewMatrix(我首先将 "position" 置零)复制到 "matrix"场.
BINGO.. 然后就可以了。 (我通过 rotating/displacing 相机或 displacing/rotating 涉及的任何 Object3D 实现相同结果的所有尝试都惨遭失败..)
编辑:我找到了一种比更新顶点更好的方法,并且至少将所有操作都保持在网格级别(我仍在移动世界 - 就像旧的 OpenGL 应用程序所做的那样......)。要获得 translation/rotation 的正确顺序,还可以使用("m" 仍然是原始的 OpenGL modelViewMatrix - 具有 0/0/0 位置信息):
var t= new THREE.Matrix4().makeTranslation(-cameraPos.x, -cameraPos.y, -cameraPos.z);
t.premultiply ( m );
obj3d.matrixAutoUpdate=false;
obj3d.matrix.copy(t);
如果有人知道更好的方法(无需直接操作对象矩阵即可更新相机),我当然有兴趣听听。