Порядок вращения камеры Three.js

Я пытаюсь использовать геймпад для поворота камеры в Three.js, используя элементы управления в стиле шутера от первого лица.

Браузер обнаруживает геймпад и распознает его ввод, но порядок вращения камеры неправильный. Когда я поворачиваюсь на локальной оси Y камеры, она также учитывает локальное вращение X, что нежелательно.

Кажется, у меня та же проблема, что и у этого парня, но его проблема была решена с помощью Three.js r54, а я использую r60. Он сел camera.eulerOrder = "YXZ"; чтобы это заработало, но текущий эквивалент camera.rotation.order = "YXZ"; кажется, не работает для меня.

Мне известен встроенный класс Three.js "FirstPersonControls", но он мне не подходит, так как он не принимает входные данные контроллера, и было бы грязно включать другие элементы управления без перемещения позже. Я также знаю о gamepad.js и не заинтересован в его использовании.

Кто-нибудь может помочь?

Мой код ротации:

function pollGamepad()
{
    gamepad = navigator.webkitGetGamepads()[0];

    //Rotation
    if(gamepad.axes[3] > 0.20)
    {
        camera.rotateX(-gamepad.axes[3] * 0.02);
    }
    if(gamepad.axes[3] < -0.20)
    {
        camera.rotateX(-gamepad.axes[3] * 0.02);
    }

    if(gamepad.axes[2] < -0.20)
    {
        camera.rotateY(-gamepad.axes[2] * 0.02);
    }
    if(gamepad.axes[2] > 0.20)
    {
        camera.rotateY(-gamepad.axes[2] * 0.02);
    }
}

3 ответа

Решение

Подход, который PointerLockControls использует для создания иерархии объектов: yawObject содержит pitchObject содержит camera, Затем горизонтальное движение мыши (или джойстика) изменит Y-вращение объекта рыскания, вертикальное движение мыши (или джойстика) изменит X-вращение основного объекта, и вращение камеры останется фиксированным по умолчанию. (0, 0, -1), Это просто вручную имитирует Эйлера YXZ заказ, но это может работать лучше для вас. Это создает некоторую неловкость, если вам нужно получить общее вращение.

В пользовательском контроллере, который я недавно написал, я достиг того же результата, add() привязка камеры к одному родительскому объекту и установка порядка Эйлера родительского объекта в YXZ, Я не помню, почему это сработало лучше, чем установить его непосредственно на камеру, но это сработало.

Я сам столкнулся с этой проблемой и нашел простое решение. Всегда сбрасывайте вращение камеры на ноль перед выполнением вращения. Затем восстановите вращение х. Так:

// Rotate camera Fps style
function rotateCamera(dx,dy){
    //store previous x rotation
    var x = camera.rotation.x;

    //reset camera's x rotation.
    camera.rotateX(-x);

    //rotate camera on y axis
    camera.rotateY(dy);

    //check if we are trying to look to high or too low
    if ( Math.abs( dx + x ) > Math.Pi/2 - 0.05) {
        camera.rotateX(x);
    else
        camera.rotateX(x+dx);

    //reset z rotation. Floating point operations might change z rotation during the above operations.
    camera.rotation.z = 0;
}
      I pressed every button until it worked this is the code it pops out

    var controlers = [];
controlers[0] = 0;
controlers[1] = 0;
controlers[2] = 0;
controlers[3] = 0;
controlers[4] = 0;
controlers[5] = 0;
controlers[6] = 0;
controlers[7] = 0;
controlers[8] = 0;
controlers[20] = 0;
var shooting = [];
shooting[0] = 0;        
let controllerIndex = [];

window.addEventListener("gamepadconnected", (event) => {
  const gamepad = event.gamepad;
  controllerIndex[event.gamepad.index] = event.gamepad.index;
  console.log("connected");
});

window.addEventListener("gamepaddisconnected", (event) => {
  controllerIndex = [];
  console.log("disconnected");
});

function handleButtons(buttons, indexid) {
  for (let i = 0; i < buttons.length; i++) {
    var button = buttons[i];
    var buttonElement = document.getElementById(`controller-b${i}`);
    var selectedButtonClass = "selected-button";

    if (buttonElement) {
      if (button.value > 0) {
        buttonElement.classList.add(selectedButtonClass);
        buttonElement.style.filter = `contrast(${button.value * 150}%)`;
     

 } else {
        buttonElement.classList.remove(selectedButtonClass);
        buttonElement.style.filter = `contrast(100%)`;
      }
    }
  }
}

function updateStickk(elementId, leftRightAxis, upDownAxis, indexid) 
{
    const stickLeftRighta = leftRightAxis;
    const stickUpDowna = upDownAxis;

    var stickUpDown_b = ( (stickLeftRighta) * 100);

    var stickLeftRight_b = ( (stickUpDowna) * 100);



    if( stickLeftRight_b > 30  ){

    camera.translateZ(15);


    }
    if( stickLeftRight_b < -30  ){
    camera.translateZ(-15);
    }


    if( stickUpDown_b > 30  ){
    camera.translateX(15);
    }
    if( stickUpDown_b < -30  ){
    camera.translateX(-15);
    }
}

function updateStick(elementId, leftRightAxis, upDownAxis, indexid) 
{
   if( indexid != null)  
   {
           const multiplier = 25; 
           const stickLeftRight = leftRightAxis;
           const stickUpDown = upDownAxis;



     if( controlers[0] + 100 < Date.now())
     {

    camera.cameras[indexid] = camera.cameras[indexid];
    camera.target = new THREE.Vector3( 0, 0, 0  );

    var stickLeftRight_b = ( (stickLeftRight) * 100);
    var stickUpDown_b = ( (stickUpDown) * 100);

    if( stickLeftRight_b <= -100 || stickLeftRight_b >= 100 || stickUpDown_b < -10 || stickUpDown_b > 10 ){ 
    


        if(  stickUpDown_b < -10 )
        {

            if(camera.rotation.x > -25)
                    {
                        camera.rotateX(0.1) ; 
                    } 
                else 
                    {
                        camera.rotation.x = 0;
                    }

        
        }

    if( stickUpDown_b > 10  )
        {
            if(camera.rotation.x < 25)
            {
                camera.rotateX(-0.1) ; 
            } 
            else 
            {
                camera.rotation.x =  0;
            }
            
        }

        if(  stickLeftRight_b >= 100 )
        {
            if( camera.rotation.y >= -359)
            {
                camera.rotation.y -=  0.1 ;
                camera.rotation.z = 0;
                camera.rotation.x = 0 ;
            }
        }

        if( stickLeftRight_b <= -100 )
        {
            if( camera.rotation.y <= 359)
            {
                camera.rotation.y += 0.1 ;
                camera.rotation.z = 0 ;
                camera.rotation.x = 0 ;
            }
        }
           }
controlers[0] = 0; 

    }
      }
   }
    
function handleSticks(axes, indexid) 
    {
        updateStickk("controller-b10", axes[0], axes[1], indexid );
        updateStick("controller-b11", axes[2], axes[3], indexid );
    }

function gameLoop()
   {
      if (controllerIndex.length > 0)  
      { 
        for( var loop_id = 0; loop_id < controllerIndex.length; loop_id++)
        {
                const gamepad = navigator.getGamepads()[loop_id];
                gamepad.indexid = controllerIndex[loop_id];
            handleButtons(gamepad.buttons, gamepad.indexid);
                handleSticks(gamepad.axes , gamepad.indexid );
        }
       }
    requestAnimationFrame(gameLoop);
   }

gameLoop();
Другие вопросы по тегам