WebGL FPS摄像头沿着局部轴而不是glMatrix.js沿着世界轴移动

问题描述 投票:0回答:1

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

我有变量:

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 )
camera rotation webgl translation
1个回答
0
投票

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

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

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>

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.