Javascript 如何使用Matrix4.setLookAt在场景中移动摄影机
正在尝试在webGL中制作第一人称摄影机控制器。我试图使用Matrix4.setLookAt()函数来实现这一点,但我不确定如何计算(坦率地说,有点不确定需要修改哪些参数以及何时修改)如何移动。我目前实现的“向左看”和“向右看”的方式最初似乎可以正常工作,但一旦g_eyeX值接近1.0或-1.0,它就会开始将摄影机从场景中的立方体移开(在负x方向移开)。我找不到太多关于如何利用此函数在场景中移动“摄影机”的文档,因为其中大部分引用了three.js(我正在尝试了解它的工作原理,不想使用库)。谁能给我一些帮助或者给我指出正确的方向?我们将不胜感激 下面列出了我的代码,下面是setLookAt函数的参数 矩阵4.setLookAt(eyeX,eyeY,eyeZ,atX,atY,atZ,upX,upY,upZ) “眼X,Y,Z”-指定眼点的位置 “atX、atY、atZ”-指定注视点的位置 “upX,upY,upZ”-指定场景中的向上方向 JS:Javascript 如何使用Matrix4.setLookAt在场景中移动摄影机,javascript,webgl,Javascript,Webgl,正在尝试在webGL中制作第一人称摄影机控制器。我试图使用Matrix4.setLookAt()函数来实现这一点,但我不确定如何计算(坦率地说,有点不确定需要修改哪些参数以及何时修改)如何移动。我目前实现的“向左看”和“向右看”的方式最初似乎可以正常工作,但一旦g_eyeX值接近1.0或-1.0,它就会开始将摄影机从场景中的立方体移开(在负x方向移开)。我找不到太多关于如何利用此函数在场景中移动“摄影机”的文档,因为其中大部分引用了three.js(我正在尝试了解它的工作原理,不想使用库)。谁能
//sceneWalker.js
//修改自RotatingTriangle.js(c)2012 matsuda
//使用非索引立方体-每边2个三角形-36个顶点
//顶点着色器程序
var-VSHADER_源=
'属性向量4 a_位置\不+
'统一mat4 u_视图矩阵\不+
'统一mat4 u_模型矩阵\不+
“一致mat4 u_ProjMatrix\不+
'void main(){\n'+
'gl_Position=u_ProjMatrix*u_ViewMatrix*u_ModelMatrix*a_Position;\n'+
'}\n';
//片段着色器程序
var FSHADER_源=
'void main(){\n'+
'gl_FragColor=vec4(1.0,0.0,0.0,1.0);\n'+
'}\n';
//旋转角度(度/秒)
var角_阶跃=0.0;
var移动金额=0.0;
var g_eyeX=0.0,g_eyeY=0.0,g_eyeZ=0.25;//眼睛位置
var g_curX=0.0,g_curZ=-3.0;
函数main(){
//检索元素
var canvas=document.getElementById('webgl');
//获取WebGL的渲染上下文
var gl=getWebGLContext(画布);
如果(!gl){
log('未能获取WebGL的呈现上下文');
返回;
}
//初始化着色器
if(!initShaders(gl、VSHADER_源、FSHADER_源)){
log('初始化着色器失败');
返回;
}
//将顶点的位置写入顶点着色器
var n=initVertexBuffers(gl);
if(n<0){
console.log('未能设置顶点的位置');
返回;
}
//指定要清除的颜色
gl.clearColor(0.0,0.0,0.0,1.0);
//获取u_ViewMatrix的存储位置
var u_ViewMatrix=gl.getUniformLocation(gl.program,“u_ViewMatrix”);
如果(!u_ViewMatrix){
console.log('无法获取u_ViewMatrix的存储位置');
返回;
}
var u_ModelMatrix=gl.getUniformLocation(gl.program,“u_ModelMatrix”);
如果(!u_ModelMatrix){
console.log('未能获取u_ModelMatrix的存储位置');
返回;
}
var u_ProjMatrix=gl.getUniformLocation(gl.program,“u_ProjMatrix”);
如果(!u_ModelMatrix){
console.log('未能获取u_ProjMatrix的存储位置');
返回;
}
//当前旋转角度
var currentAngle=0.0;
//模型矩阵
var modelMatrix=new Matrix4();
var viewMatrix=新矩阵4();
var projMatrix=新矩阵4();
modelMatrix.setTranslate(0,0100);
setLookAt(g_-eyeX,g_-eyeY,g_-eyeZ,0,0,0,1,0);
projMatrix.setPerspective(45,(canvas.width)/(canvas.height),0.1100000);
gl.uniformMatrix4fv(u_ModelMatrix,false,ModelMatrix.elements);
gl.uniformMatrix4fv(u_ViewMatrix,false,ViewMatrix.elements);
gl.uniformMatrix4fv(u_ProjMatrix,false,ProjMatrix.elements);
document.onkeydown=函数(ev){keydown(ev,gl,n,u_ViewMatrix,ViewMatrix);};
//开始绘图
var tick=函数(){
//currentAngle=动画(currentAngle);//更新旋转角度
绘制(gl,n,currentAngle,modelMatrix,viewMatrix,u_modelMatrix,u_viewMatrix);//绘制三角形
requestAnimationFrame(勾号,画布);//请求浏览器调用勾号
};
勾选();
}
功能键控(ev、gl、n、u_ViewMatrix、ViewMatrix){
控制台日志(ev.keyCode);
如果(ev.keyCode==39){//按下右箭头键
g_eyeX-=0.01;
控制台日志(g_eyeX);
}否则
如果(ev.keyCode==37){//按下左箭头键
g_eyeX+=0.01;
控制台日志(g_eyeX);
}
如果(ev.keyCode==38){
g_eyeY+=0.01;
}
如果(ev.keyCode==40){
g_eyeY-=0.01;
}
如果(ev.keyCode==68){
g_curX-=0.01;
}
如果(ev.keyCode==65){
g_curX+=0.01;
}
如果(ev.keyCode==87){
g_curZ+=0.01;
}
如果(ev.keyCode==83){
g_curZ-=0.01;
}
else{return;}
}
函数initVertexBuffers(gl){
var顶点=新数组([
-0.5, 0.5, 0.5,
-0.5, -0.5, 0.5,
0.5, -0.5, 0.5,
-0.5, 0.5, 0.5,
0.5, -0.5, 0.5,
0.5, 0.5, 0.5,
0.5, 0.5, 0.5,
0.5, -0.5, 0.5,
0.5, -0.5, -0.5,
0.5, 0.5, 0.5,
0.5, -0.5, -0.5,
0.5, 0.5, -0.5,
0.5, -0.5, 0.5,
-0.5, -0.5, 0.5,
-0.5, -0.5, -0.5,
0.5, -0.5, 0.5,
-0.5, -0.5, -0.5,
0.5, -0.5, -0.5,
0.5, 0.5, -0.5,
-0.5, 0.5, -0.5,
-0.5, 0.5, 0.5,
0.5, 0.5, -0.5,
-0.5, 0.5, 0.5,
0.5, 0.
// sceneWalker.js
// modified from RotatingTriangle.js (c) 2012 matsuda
// uses a non-indexed cube - 2 triangles per side - 36 vertices
// Vertex shader program
var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'uniform mat4 u_ViewMatrix;\n' +
'uniform mat4 u_ModelMatrix;\n' +
'uniform mat4 u_ProjMatrix;\n' +
'void main() {\n' +
' gl_Position = u_ProjMatrix * u_ViewMatrix * u_ModelMatrix * a_Position;\n' +
'}\n';
// Fragment shader program
var FSHADER_SOURCE =
'void main() {\n' +
' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' +
'}\n';
// Rotation angle (degrees/second)
var ANGLE_STEP = 0.0;
var MOVE_AMOUNT = 0.0;
var g_eyeX = 0.0, g_eyeY = 0.0, g_eyeZ = 0.25; // Eye position
var g_curX = 0.0, g_curZ = -3.0;
function main() {
// Retrieve <canvas> element
var canvas = document.getElementById('webgl');
// Get the rendering context for WebGL
var gl = getWebGLContext(canvas);
if (!gl) {
console.log('Failed to get the rendering context for WebGL');
return;
}
// Initialize shaders
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
console.log('Failed to intialize shaders.');
return;
}
// Write the positions of vertices to a vertex shader
var n = initVertexBuffers(gl);
if (n < 0) {
console.log('Failed to set the positions of the vertices');
return;
}
// Specify the color for clearing <canvas>
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// Get storage location of u_ViewMatrix
var u_ViewMatrix = gl.getUniformLocation(gl.program, 'u_ViewMatrix');
if (!u_ViewMatrix) {
console.log('Failed to get the storage location of u_ViewMatrix');
return;
}
var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');
if (!u_ModelMatrix) {
console.log('Failed to get the storage location of u_ModelMatrix');
return;
}
var u_ProjMatrix = gl.getUniformLocation(gl.program, 'u_ProjMatrix');
if (!u_ModelMatrix) {
console.log('Failed to get the storage location of u_ProjMatrix');
return;
}
// Current rotation angle
var currentAngle = 0.0;
// Model matrix
var modelMatrix = new Matrix4();
var viewMatrix = new Matrix4();
var projMatrix = new Matrix4();
modelMatrix.setTranslate(0, 0, 100);
viewMatrix.setLookAt(g_eyeX, g_eyeY, g_eyeZ, 0, 0, 0, 0, 1, 0);
projMatrix.setPerspective(45, (canvas.width)/(canvas.height), 0.1, 10000000);
gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);
gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix.elements);
gl.uniformMatrix4fv(u_ProjMatrix, false, projMatrix.elements);
document.onkeydown = function(ev){ keydown(ev, gl, n, u_ViewMatrix, viewMatrix); };
// Start drawing
var tick = function() {
//currentAngle = animate(currentAngle); // Update the rotation angle
draw(gl, n, currentAngle, modelMatrix, viewMatrix, u_ModelMatrix, u_ViewMatrix); // Draw the triangle
requestAnimationFrame(tick, canvas); // Request that the browser calls tick
};
tick();
}
function keydown(ev, gl, n, u_ViewMatrix, viewMatrix) {
console.log(ev.keyCode);
if(ev.keyCode == 39) { // The right arrow key was pressed
g_eyeX -= 0.01;
console.log(g_eyeX);
} else
if (ev.keyCode == 37) { // The left arrow key was pressed
g_eyeX += 0.01;
console.log(g_eyeX);
}
if(ev.keyCode == 38){
g_eyeY += 0.01;
}
if(ev.keyCode == 40){
g_eyeY -= 0.01;
}
if(ev.keyCode == 68){
g_curX -= 0.01;
}
if(ev.keyCode == 65){
g_curX += 0.01;
}
if(ev.keyCode == 87){
g_curZ += 0.01;
}
if(ev.keyCode == 83){
g_curZ -= 0.01;
}
else { return; }
}
function initVertexBuffers(gl) {
var vertices = new Float32Array ([
-0.5, 0.5, 0.5,
-0.5, -0.5, 0.5,
0.5, -0.5, 0.5,
-0.5, 0.5, 0.5,
0.5, -0.5, 0.5,
0.5, 0.5, 0.5,
0.5, 0.5, 0.5,
0.5, -0.5, 0.5,
0.5, -0.5, -0.5,
0.5, 0.5, 0.5,
0.5, -0.5, -0.5,
0.5, 0.5, -0.5,
0.5, -0.5, 0.5,
-0.5, -0.5, 0.5,
-0.5, -0.5, -0.5,
0.5, -0.5, 0.5,
-0.5, -0.5, -0.5,
0.5, -0.5, -0.5,
0.5, 0.5, -0.5,
-0.5, 0.5, -0.5,
-0.5, 0.5, 0.5,
0.5, 0.5, -0.5,
-0.5, 0.5, 0.5,
0.5, 0.5, 0.5,
-0.5, -0.5, -0.5,
-0.5, 0.5, -0.5,
0.5, 0.5, -0.5,
-0.5, -0.5, -0.5,
0.5, 0.5, -0.5,
0.5, -0.5, -0.5,
-0.5, 0.5, -0.5,
-0.5, -0.5, -0.5,
-0.5, -0.5, 0.5,
-0.5, 0.5, -0.5,
-0.5, -0.5, 0.5,
-0.5, 0.5, 0.5
]);
var n = 36; // The number of vertices
// Create a buffer object
var vertexBuffer = gl.createBuffer();
if (!vertexBuffer) {
console.log('Failed to create the buffer object');
return -1;
}
// Bind the buffer object to target
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
// Write date into the buffer object
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
// Assign the buffer object to a_Position variable
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if(a_Position < 0) {
console.log('Failed to get the storage location of a_Position');
return -1;
}
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, 0, 0);
// Enable the assignment to a_Position variable
gl.enableVertexAttribArray(a_Position);
return n;
}
function draw(gl, n, currentAngle, modelMatrix, viewMatrix, u_ModelMatrix, u_ViewMatrix) {
// Set the rotation matrix
modelMatrix.setRotate(currentAngle, 1, 1, 1);
modelMatrix.setTranslate(g_curX, 0, g_curZ);
viewMatrix.setLookAt(g_eyeX, g_eyeY, g_eyeZ, 0, 0, 0, 0, 1, 0);
// Pass the rotation matrix to the vertex shader
gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix.elements);
gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);
// Clear <canvas>
gl.clear(gl.COLOR_BUFFER_BIT);
// Draw the rectangle
gl.drawArrays(gl.TRIANGLES, 0, n);
}
// Last time that this function was called
var g_last = Date.now();
function animate(angle) {
// Calculate the elapsed time
var now = Date.now();
var elapsed = now - g_last;
g_last = now;
// Update the current rotation angle (adjusted by the elapsed time)
var newAngle = angle + (ANGLE_STEP * elapsed) / 1000.0;
return newAngle %= 360;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Cube</title>
</head>
<body onload="main()">
<canvas id="webgl" width="400" height="400">
Please use a browser that supports "canvas"
</canvas>
<script src="../lib/webgl-utils.js"></script>
<script src="../lib/webgl-debug.js"></script>
<script src="../lib/cuon-utils.js"></script>
<script src="../lib/cuon-matrix.js"></script>
<script src="sceneWalker.js"></script>
</body>
</html>
/** @constructor */
function FPSCamera(){
this.pos = [0.0, 0.0, 0.0];
this.dir = [0.0, 0.0, -1.0]; // or forward
this.up = [0.0, 1.0, 0.0];
this.side = [1.0, 0.0, 0.0]; // or right
}
FPSCamera.prototype.forward = function(dist){
this.pos[0] += this.dir[0] * dist;
this.pos[1] += this.dir[1] * dist;
this.pos[2] += this.dir[2] * dist;
};
// do the same for other 2 directions, strife and fly
// looks to left/right
FPSCamera.prototype.yaw = function(radians){
var orientationChange = ORIENTATION.fromAxisAngle(this.up, radians);
this.dir = VEC3.rotatedByOrientation(this.dir, orientationChange);
this.side = VEC3.cross(this.dir, this.up);
this.side = VEC3.normalize(this.side);
};
// same for pitch... except the rotation axis is this.side and you need to ensure the pitch is within +/- 90 degrees
FPSCamera.prototype.getViewMatrix = function(){
// matrix can be extracted from the 3 direction vectors, but lets use lookAt here;
return MAT4.lookAt(this.pos, VEC3.plus(this.pos, this.dir), this.up);
};