Three.js 相机旋转顺序

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

我正在尝试使用游戏手柄在 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);
    }
}
javascript rotation three.js euler-angles gamepad-api
3个回答
2
投票

PointerLockControls
使用的方法是创建对象的层次结构:
yawObject
包含
pitchObject
包含
camera
。然后,水平鼠标(或操纵杆)移动将改变偏航对象的 Y 旋转,垂直鼠标(或操纵杆)移动将改变俯仰对象的 X 旋转,而相机的旋转将保持默认值
(0, 0, -1)
。这只是手动模拟 Euler
YXZ
排序,但它可能更适合您。如果您需要整体旋转,它确实会造成一些尴尬。

在我最近编写的自定义控制器中,我通过将相机

add()
设置为单个父对象并将父对象的欧拉阶设置为
YXZ
来实现相同的结果。我不记得为什么这比直接将其设置在相机上效果更好,但确实如此。


0
投票

我自己也遇到过这个问题,我想出了一个简单的解决方案。在执行 y 旋转之前,始终将相机的 x 旋转重置为零。然后,恢复 x 旋转。所以:

// 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;
}

-1
投票

我按下了每个按钮,直到它起作用,这是弹出的代码

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;      
let controllerIndex = null;

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

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

function handleButtons(buttons) {
  for (let i = 0; i < buttons.length; i++) {
    const button = buttons[i];
    const buttonElement = document.getElementById(`controller-b${i}`);
    const 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 updateStick(elementId, leftRightAxis, upDownAxis) {
  const multiplier = 25; 
  const stickLeftRight = leftRightAxis;
  const stickUpDown = upDownAxis;

 



camera.object = camera;
    camera.target = new THREE.Vector3( 0, 0, 0  );

    

    camera.mouseX = 0;
    camera.mouseY = 0;

    camera.lat =  0;
    camera.lon =  360;
    camera.phi = 0;
    camera.theta = 0;

    

        
    




            controlers[4] =  (stickLeftRight   )  ;
            controlers[5] = (stickUpDown ) ;



camera.lon += stickLeftRight * 10 ;
              camera.lat -= stickUpDown * 10  ; // * this.invertVertical?-1:1;

            camera.lat = Math.max( -15, Math.min( 15, camera.lat ) );
            camera.phi = ( 90 - camera.lat ) * Math.PI / 180;
            camera.theta = camera.lon * Math.PI / 360;

            var targetPosition = camera.target,
            position = camera.object.position;


        targetPosition.x = position.x + 100 * Math.cos( camera.theta );
        targetPosition.y = position.y + 200 * Math.cos( camera.phi );
        targetPosition.z = position.z + 100 * Math.sin( camera.phi ) * Math.sin( camera.theta );

var stickLeftRight_a = ( (stickLeftRight) * 100);

var stickUpDown_a = ( (stickUpDown) * 100);


if( stickLeftRight_a < -87 || stickLeftRight_a > 87 || stickUpDown_a < -87 || stickUpDown_a > 87  ){ 
    

if( stickLeftRight_a > -87 && stickLeftRight_a < 87 ){
camera.lon += stickLeftRight  ;
              camera.lat -= stickUpDown ; // * tstickLeftRight_as.invertVertical?-1:1;

            camera.lat = Math.max( -15, Math.min( 15, camera.lat ) );
            camera.phi = ( 90 - camera.lat ) * Math.PI / 180;
            camera.theta = camera.lon * Math.PI / 360;

            var targetPosition = camera.target,
            position = camera.object.position;


        targetPosition.x = position.x + 100 * Math.cos( camera.theta );
        targetPosition.y = position.y + 200 * Math.cos( camera.phi );
        targetPosition.z = position.z + 100 * Math.sin( camera.phi ) * Math.sin( camera.theta );
camera.lookAt(targetPosition);

}




if(  stickLeftRight_a > 87 ){
controlers[6] = controlers[6] + 0.01;

if( controlers[6] > 360 ){
 controlers[6] = 0;

}
camera.rotation.y -= controlers[6];


camera.rotation.z = 0 ;

camera.rotation.x = 0 ;
}
if( stickLeftRight_a < -87 ){

controlers[6] = controlers[6] - 0.01;
if( controlers[6] < 0 ){
 controlers[6] = 360;

}
camera.rotation.y += controlers[6];
camera.rotation.z = 0 ;

camera.rotation.x = 0 ;

}
}
}                       
}
}

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

function gameLoop() {
  if (controllerIndex !== null) {
    const gamepad = navigator.getGamepads()[controllerIndex];
    handleButtons(gamepad.buttons);
    handleSticks(gamepad.axes);
  }
  requestAnimationFrame(gameLoop);
}

gameLoop();
    
© www.soinside.com 2019 - 2024. All rights reserved.