如何将 glTF 模型沿其在 A 框架中面向的方向移动?
How to move a glTF model in the direction it is facing in A-frame?
我在 A 帧场景版本 1.0.4 中加载了我的机器人的 gltf 模型。到目前为止,我可以围绕其 x、y、z 轴转动机器人,但是当我尝试将其向前移动时,它仍然沿其初始方向而不是它所面对的方向移动。我希望能够在不使用任何外部库的情况下使用键盘控制它的移动。我相信我必须使用四元数,但我还没有想出如何使用它们。到目前为止,这是我的 A 帧代码。
<a-scene id="myScene">
<a-entity environment="preset:forest;"></a-entity>
<a-entity gltf-model="#humanoid" id="robot" position="0 20 0" rotation="0 0 0"
scale="0.0001 0.0001 0.0001" static-body>
</a-entity>
</a-scene>
这是我的脚本
const robot = document.getElementById('robot');
const update = () => {
if (keys.forward) {
let {x,y,z} = robot.object3D.position;
let ry = robot.object3D.rotation.y;
z += Math.cos(ry * Math.PI/180)/12;
x += Math.sin(ry * Math.PI/180)/12;
robot.object3D.position.set(x, y, z);
}
else if (keys.backwards) {
let {x, y, z} = robot.object3D.position;
let ry = robot.object3D.rotation.y;
z -= Math.cos(ry * Math.PI/180)/10;
x -= Math.sin(ry * Math.PI/180)/10;
robot.object3D.position.set(x, y, z);
}
if (keys.turnLeft) {
let {x, y, z} = robot.getAttribute('rotation');
y += 0.25;
robot.setAttribute('rotation',{x,y,z});
}
else if (keys.turnRight) {
let {x, y, z} = robot.getAttribute('rotation');
y -= 0.25;
robot.setAttribute('rotation',{x,y,z});
}
}
是的,使用四元数是解决这个问题的好方法。
您可以简单地将机器人的当前四元数应用到代表您想要在机器人的原始旋转中进行的运动的 vector3,并将其应用到机器人的位置。
像这样:
fowardVector = new Vector3(0, 0, -0.1)
rotatedForwardVector = new Vector3();
rotatedForwardVector.copy(forwardVector);
rotatedForwardVector.applyQuaternion(robot.object3D.quaternion);
robot.object3D.position.add(rotatedForwardVector);
请注意,您只想创建 Vector3 一次,然后 re-use 它们以避免不必要的垃圾收集,而不是为每个移动都创建它们。
例如使用闭包解释 here
let ry = robot.object3D.rotation.y;
z += Math.cos(ry * Math.PI/180)/12;
虽然a-frame
旋转是用度数,threejs
是用弧度,所以不用再换算:
const robot = document.querySelector("a-box")
document.body.addEventListener("keydown", (evt) => {
if (evt.key === 's') {
let {x,y,z} = robot.object3D.position;
let ry = robot.object3D.rotation.y;
z += Math.cos(ry)/12;
x += Math.sin(ry)/12;
robot.object3D.position.set(x, y, z);
} else if (evt.key === 'w') {
let {x, y, z} = robot.object3D.position;
let ry = robot.object3D.rotation.y;
console.log(ry)
z -= Math.cos(ry)/10;
x -= Math.sin(ry)/10;
robot.object3D.position.set(x, y, z);
}
if (evt.key === 'a') {
let {x, y, z} = robot.getAttribute('rotation');
y += 1;
robot.setAttribute('rotation',{x,y,z});
} else if (evt.key === 'd') {
let {x, y, z} = robot.getAttribute('rotation');
y -= 1;
robot.setAttribute('rotation',{x: x,y: y,z: z});
}
})
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
<a-scene>
<a-box position="-1 0.5 -3" rotation="0 0 0" color="#4CC3D9">
<a-sphere radius="0.5" position="0 0 -1"></a-sphere>
</a-box>
<a-entity camera position="0 1.6 0"></a-entity>
</a-scene>
与getWorldDirection
相同:
const robot = document.querySelector("a-box")
const direction = new THREE.Vector3();
document.body.addEventListener("keydown", (evt) => {
if (evt.key === 's') {
// get robot direction
robot.object3D.getWorldDirection(direction);
// add a "speed" value
direction.multiplyScalar(0.1)
// add the new vector to the actual position
robot.object3D.position.add(direction)
} else if (evt.key === 'w') {
robot.object3D.getWorldDirection(direction);
direction.multiplyScalar(-0.1)
robot.object3D.position.add(direction)
}
if (evt.key === 'a') {
let {x, y, z} = robot.getAttribute('rotation');
y=y+1
robot.setAttribute('rotation',{x,y,z});
} else if (evt.key === 'd') {
let {x, y, z} = robot.getAttribute('rotation');
y=y-1
robot.setAttribute('rotation',{x: x,y: y,z: z});
}
})
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
<a-scene>
<a-box position="-1 0.5 -3" rotation="0 0 0" color="#4CC3D9">
<a-sphere radius="0.5" position="0 0 -1"></a-sphere>
</a-box>
<a-entity camera position="0 1.6 0"></a-entity>
</a-scene>
您可以使用四元数和许多其他方法,但 Object3D 有一些有用且更简单的替代方法来在局部坐标中移动对象:
我觉得最简单的就是用https://threejs.org/docs/#api/en/core/Object3D.translateZ
robot.object3D.translateZ(amountToMoveForward);
也https://threejs.org/docs/#api/en/core/Object3D.localToWorld可以用来转换向量。
我在 A 帧场景版本 1.0.4 中加载了我的机器人的 gltf 模型。到目前为止,我可以围绕其 x、y、z 轴转动机器人,但是当我尝试将其向前移动时,它仍然沿其初始方向而不是它所面对的方向移动。我希望能够在不使用任何外部库的情况下使用键盘控制它的移动。我相信我必须使用四元数,但我还没有想出如何使用它们。到目前为止,这是我的 A 帧代码。
<a-scene id="myScene">
<a-entity environment="preset:forest;"></a-entity>
<a-entity gltf-model="#humanoid" id="robot" position="0 20 0" rotation="0 0 0"
scale="0.0001 0.0001 0.0001" static-body>
</a-entity>
</a-scene>
这是我的脚本
const robot = document.getElementById('robot');
const update = () => {
if (keys.forward) {
let {x,y,z} = robot.object3D.position;
let ry = robot.object3D.rotation.y;
z += Math.cos(ry * Math.PI/180)/12;
x += Math.sin(ry * Math.PI/180)/12;
robot.object3D.position.set(x, y, z);
}
else if (keys.backwards) {
let {x, y, z} = robot.object3D.position;
let ry = robot.object3D.rotation.y;
z -= Math.cos(ry * Math.PI/180)/10;
x -= Math.sin(ry * Math.PI/180)/10;
robot.object3D.position.set(x, y, z);
}
if (keys.turnLeft) {
let {x, y, z} = robot.getAttribute('rotation');
y += 0.25;
robot.setAttribute('rotation',{x,y,z});
}
else if (keys.turnRight) {
let {x, y, z} = robot.getAttribute('rotation');
y -= 0.25;
robot.setAttribute('rotation',{x,y,z});
}
}
是的,使用四元数是解决这个问题的好方法。
您可以简单地将机器人的当前四元数应用到代表您想要在机器人的原始旋转中进行的运动的 vector3,并将其应用到机器人的位置。
像这样:
fowardVector = new Vector3(0, 0, -0.1)
rotatedForwardVector = new Vector3();
rotatedForwardVector.copy(forwardVector);
rotatedForwardVector.applyQuaternion(robot.object3D.quaternion);
robot.object3D.position.add(rotatedForwardVector);
请注意,您只想创建 Vector3 一次,然后 re-use 它们以避免不必要的垃圾收集,而不是为每个移动都创建它们。
例如使用闭包解释 here
let ry = robot.object3D.rotation.y; z += Math.cos(ry * Math.PI/180)/12;
虽然a-frame
旋转是用度数,threejs
是用弧度,所以不用再换算:
const robot = document.querySelector("a-box")
document.body.addEventListener("keydown", (evt) => {
if (evt.key === 's') {
let {x,y,z} = robot.object3D.position;
let ry = robot.object3D.rotation.y;
z += Math.cos(ry)/12;
x += Math.sin(ry)/12;
robot.object3D.position.set(x, y, z);
} else if (evt.key === 'w') {
let {x, y, z} = robot.object3D.position;
let ry = robot.object3D.rotation.y;
console.log(ry)
z -= Math.cos(ry)/10;
x -= Math.sin(ry)/10;
robot.object3D.position.set(x, y, z);
}
if (evt.key === 'a') {
let {x, y, z} = robot.getAttribute('rotation');
y += 1;
robot.setAttribute('rotation',{x,y,z});
} else if (evt.key === 'd') {
let {x, y, z} = robot.getAttribute('rotation');
y -= 1;
robot.setAttribute('rotation',{x: x,y: y,z: z});
}
})
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
<a-scene>
<a-box position="-1 0.5 -3" rotation="0 0 0" color="#4CC3D9">
<a-sphere radius="0.5" position="0 0 -1"></a-sphere>
</a-box>
<a-entity camera position="0 1.6 0"></a-entity>
</a-scene>
与getWorldDirection
相同:
const robot = document.querySelector("a-box")
const direction = new THREE.Vector3();
document.body.addEventListener("keydown", (evt) => {
if (evt.key === 's') {
// get robot direction
robot.object3D.getWorldDirection(direction);
// add a "speed" value
direction.multiplyScalar(0.1)
// add the new vector to the actual position
robot.object3D.position.add(direction)
} else if (evt.key === 'w') {
robot.object3D.getWorldDirection(direction);
direction.multiplyScalar(-0.1)
robot.object3D.position.add(direction)
}
if (evt.key === 'a') {
let {x, y, z} = robot.getAttribute('rotation');
y=y+1
robot.setAttribute('rotation',{x,y,z});
} else if (evt.key === 'd') {
let {x, y, z} = robot.getAttribute('rotation');
y=y-1
robot.setAttribute('rotation',{x: x,y: y,z: z});
}
})
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
<a-scene>
<a-box position="-1 0.5 -3" rotation="0 0 0" color="#4CC3D9">
<a-sphere radius="0.5" position="0 0 -1"></a-sphere>
</a-box>
<a-entity camera position="0 1.6 0"></a-entity>
</a-scene>
您可以使用四元数和许多其他方法,但 Object3D 有一些有用且更简单的替代方法来在局部坐标中移动对象:
我觉得最简单的就是用https://threejs.org/docs/#api/en/core/Object3D.translateZ
robot.object3D.translateZ(amountToMoveForward);
也https://threejs.org/docs/#api/en/core/Object3D.localToWorld可以用来转换向量。