Порядок вращения камеры Three.js
Я пытаюсь использовать геймпад для поворота камеры в Three.js, используя элементы управления в стиле шутера от первого лица.
Браузер обнаруживает геймпад и распознает его ввод, но порядок вращения камеры неправильный. Когда я поворачиваюсь на локальной оси Y камеры, она также учитывает локальное вращение X, что нежелательно.
- Что я хочу: http://jsfiddle.net/fYtwf/3/
- Что происходит: http://jsfiddle.net/fYtwf/2/
Кажется, у меня та же проблема, что и у этого парня, но его проблема была решена с помощью 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();