使用glMatrix.js,WebGL FPS摄像机沿局部轴而不是世界轴移动 [英] WebGL FPS camera movement along the local axis instead of the world axis with glMatrix.js

查看:74
本文介绍了使用glMatrix.js,WebGL FPS摄像机沿局部轴而不是世界轴移动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在WebGL中制作FPS相机.当我从初始位置移动相机然后旋转时,相机沿着起始位置移动,而不是沿新位置移动.平移和旋转是通过glMatrix.js库进行的.

I'm trying to make a FPS camera in WebGL. When I move the camera from the initial position and then rotate, the camera moves along the start position instead of the new position. The translation and rotation are made with glMatrix.js library.

我有变量:

var rotateY = 0;  // For rotating along the Y axis
var fronBackMovement = 0;   // Front and back movement
var sideMovement  = 0;  // Movement from side to side

键盘事件:

// Movement
if( key.w == true ){
    fronBackMovement += 5;
}
if( key.a == true ){
    sideMovement += 5;
}
if( key.s == true ){
    fronBackMovement -= 5;
}
if( key.d == true ){
    sideMovement -= 5;
}

鼠标移动:

// Rotation
if( mouse.movementX != 0 ){
    rotateY += mouse.movementX;  // mouse.movementX is screen movement of the cursor
}

平移和旋转:

camera.matrix = mat4.fromTranslation( mat4.create() ,vec3.fromValues(sideMovement,0,fronBackMovement) )
camera.matrix = mat4.rotateY(camera.matrix,camera.matrix,rotateY )

推荐答案

摄像机通常向下看-Z轴,因此,只需将摄像机的Z轴添加到您的位置即可向前移动.如果您不想垂直移动,则将Y分量归零并进行归一化.最后乘以您想要的速度.

The camera generally looks down the -Z axis so to move forward you just add the camera's Z axis to your position. If you don't want to move vertically then zero out the Y component and normalize. Finally multiply by your desired speed.

相机的x轴包含侧向移动方向,因此您可以执行相同的操作.

The camera's x-axis contains the side movement direction so you can do the same for that.

const cameraPosition = vec3.create();
const tempForwardDirection = vec3.create();
const tempSideDirection = vec3.create();
...


tempForwardDirection[0] = camera.matrix[8];
tempForwardDirection[1] = 0;  // camera.matrix[9];
tempForwardDirection[2] = camera.matrix[10];
vec3.normalize(tempForwardDirection, tempForwardDirection)

tempSideDirection[0] = camera.matrix[0];
tempSideDirection[1] = camera.matrix[1];
tempSideDirection[2] = camera.matrix[2];

vec3.scaleAndAdd(
    cameraPosition,
    cameraPosition,
    tempForwardDirection, 
    -fronBackMovement);
vec3.scaleAndAdd(
    cameraPosition,
    cameraPosition,
    tempSideDirection,
    sideMovement)

camera.matrix = mat4.fromTranslation(camera.matrix, cameraPosition);
camera.matrix = mat4.rotateY(camera.matrix,camera.matrix,rotateY);

let rotateY = 0;  // For rotating along the Y axis
let fronBackMovement = 0;   // Front and back movement
let sideMovement  = 0;  // Movement from side to side

const cameraPosition = vec3.create();
const tempForwardDirection = vec3.create();
const tempSideDirection = vec3.create();

const camera = {
  matrix: mat4.create(),
};
const mouse = {
  movementX: 0,
};

const gl = document.querySelector("canvas").getContext("webgl");
const vs = `
uniform mat4 u_worldViewProjection;
uniform mat4 u_worldInverseTranspose;

attribute vec4 position;
attribute vec3 normal;

varying vec3 v_normal;

void main() {
  gl_Position = u_worldViewProjection * position;
  v_normal = (u_worldInverseTranspose * vec4(normal, 0)).xyz;
}
`;
const fs = `
precision mediump float;

varying vec3 v_normal;
uniform vec3 u_lightDir;
uniform vec4 u_color;

void main() {
  vec3 norm = normalize(v_normal);
  float light = dot(u_lightDir, norm) * .5 + .5;
  gl_FragColor = vec4(u_color.rgb * light, u_color.a);
}
`;

const progInfo = twgl.createProgramInfo(gl, [vs, fs]);
const bufferInfo = twgl.primitives.createCubeBufferInfo(gl, 1);

const projection = mat4.create();
const view = mat4.create();
const viewProjection = mat4.create();
const world = mat4.create();
const worldViewProjection = mat4.create();
const worldInverse = mat4.create();
const worldInverseTranspose = mat4.create();

const fov = degToRad(90);
const zNear = 0.1;
const zFar = 100;

const lightDir = vec3.normalize(vec3.create(), [1, 2, 3]);

const key = {};

let px = 0;
let py = 0;
let pz = 0;
let elev = 0;
let ang = 0;
let roll = 0;
const speed = 1;
const turnSpeed = 90;

let then = 0;
function render(now) {
  now *= 0.001;  // seconds;
  const deltaTime = now - then;
  then = now;
  
  twgl.resizeCanvasToDisplaySize(gl.canvas);
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  
  gl.enable(gl.DEPTH_TEST);
  gl.enable(gl.CULL_FACE);
  
  gl.useProgram(progInfo.program);
  
  const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
  mat4.perspective(projection, fov, aspect, zNear, zFar);

  fronBackMovement = 0;
  sideMovement = 0;
  
  if( key.w == true ){
      fronBackMovement = 5 * deltaTime;
  }
  if( key.a == true ){
      sideMovement = -5 * deltaTime;
  }
  if( key.s == true ){
      fronBackMovement = -5 * deltaTime;
  }
  if( key.d == true ){
      sideMovement = 5 * deltaTime;
  }

  // Rotation
  if( mouse.movementX != 0 ){
      rotateY += mouse.movementX / 200;  // mouse.movementX is screen movement of the cursor
      mouse.movementX = 0;
  }

  tempForwardDirection[0] = camera.matrix[8];
  tempForwardDirection[1] = 0;  // camera.matrix[9];
  tempForwardDirection[2] = camera.matrix[10];
  vec3.normalize(tempForwardDirection, tempForwardDirection)

  tempSideDirection[0] = camera.matrix[0];
  tempSideDirection[1] = camera.matrix[1];
  tempSideDirection[2] = camera.matrix[2];

  vec3.scaleAndAdd(
      cameraPosition,
      cameraPosition,
      tempForwardDirection, 
      -fronBackMovement);
  vec3.scaleAndAdd(
      cameraPosition,
      cameraPosition,
      tempSideDirection,
      sideMovement)

  camera.matrix = mat4.fromTranslation(camera.matrix, cameraPosition);
  camera.matrix = mat4.rotateY(camera.matrix,camera.matrix,rotateY);


  mat4.invert(view, camera.matrix);

  mat4.multiply(viewProjection, projection, view);
  
  for (let z = -1; z <= 1; ++z) {
    for (let y = -1; y <= 1; ++y) {
      for (let x = -1; x <= 1; ++x) {
        if (x === 0 && y === 0 && z === 0) {
          continue;
        }
        
        mat4.identity(world);
        mat4.translate(world, world, [x * 3, y * 3, z * 3]);
        
        mat4.multiply(worldViewProjection, viewProjection, world);
        mat4.invert(worldInverse, world);
        mat4.transpose(worldInverseTranspose, worldInverse);
        
        twgl.setBuffersAndAttributes(gl, progInfo, bufferInfo);
        twgl.setUniforms(progInfo, {
          u_worldViewProjection: worldViewProjection,
          u_worldInverseTranspose: worldInverseTranspose,
          u_color: [(x + 2) / 3, (y + 2) / 3, (z + 2) / 3, 1],
          u_lightDir: lightDir,
        });
        twgl.drawBufferInfo(gl, bufferInfo);
      }
    }
  }
  
  requestAnimationFrame(render);
}
requestAnimationFrame(render);

window.addEventListener('keydown', (e) => {
  key[e.key] = true;
  e.preventDefault();
});
window.addEventListener('keyup', (e) => {
  key[e.key] = false;
  e.preventDefault();
});
window.addEventListener('mousemove', (e) => {
  mouse.movementX = e.movementX;
});


function degToRad(d) {
  return d * Math.PI / 180;
}

body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
pre { position: absolute; left: 1em; top: 0; }

<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.8.1/gl-matrix-min.js"></script>
<canvas></canvas>
<pre>
A = left
D = right
W = forward
S = down
</pre>

这篇关于使用glMatrix.js,WebGL FPS摄像机沿局部轴而不是世界轴移动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆