使用 three.js 更改一帧场景中 gltf-model 的位置
change position of gltf-model in a-frame scene using three.js
我已将 gltf-model 加载到 a-frame,我想将其沿 y 轴移动 20。我使用此代码:
问题出现在一帧场景中,实际上对象被向上移动(检查 "after" 图像中的阴影和场景检查器),但它仍然显示在它之前的位置。看来场景需要某种刷新。
问题是,如何用three.js代码正确移动它?
前:
BEFORE1
BEFORE2
后:
AFTER1
AFTER2
代码:
<html>
<a-scene>
<a-sky color="#f9f2cf"></a-sky>
<!-- LIGHT a-frame no need to export from blender -->
<a-light color="#fff" position="-8 5 0" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="0 5 -14.163" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="0 5 14.192" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="0 -9.574 -2.443" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="8.5 5 0" intensity="3.5" light="intensity:2"></a-light>
<!-- CAMERA with wasd controls and circle cursor -->
<a-camera fly look-controls wasd-controls position="17.020 16.700 7.958" rotation="-34.149 89.382 0.000">
<a-entity
cursor="fuse: true; fuseTimeout: 500"
position="0 0 -1"
geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03"
material="color: black; shader: flat">
</a-entity>
</a-camera>
<a-assets>
<!-- GLTF animation samples -->
<a-asset-item id="afb_animation" src="models/afb_animation.gltf"></a-asset-item>
</a-assets>
<a-entity id="_afb_animation" position="0 0 0" gltf-model="#afb_animation" ></a-entity>
</a-scene>
<!-- script change model position -->
<script>
$( document ).ready(function() {
var xAxis = new THREE.Vector3(1,0,0);
setTimeout(function(){
console.log("rotation: done");
document.querySelector('#_afb_animation').sceneEl.object3D.translateY(20);
}, 3000);
});
</script>
解决您的问题的一种方法是使用 setAttribute
方法(官方 wiki here) on the position component.
例如:
entity.setAttribute('position', { x: 1, y: 2, z: 3 });
其中实体是任何 A-Frame 实体。
示例 1
所以,在下面的代码中,我注册了一个名为 move-my-model
的 A-Frame component,它允许我移动我的实体(在我的例子中是一个 <a-box>
实体,但它也适用于你的模型)在 3000 毫秒后用 setTimeout
添加 10 到它的 y-position (比如你的代码示例):
<script src="https://aframe.io/releases/0.7.0/aframe.min.js"></script>
<script>
AFRAME.registerComponent('move-my-model', {
init: function () {
setTimeout( () => {
let position = this.el.getAttribute("position")
position.y += 10
this.el.setAttribute("position", position)
}, 3000)
}
})
</script>
<a-scene>
<a-sky color="#f9f2cf"></a-sky>
<!-- LIGHT a-frame no need to export from blender -->
<a-light color="#fff" position="-8 5 0" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="0 5 -14.163" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="0 5 14.192" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="0 -9.574 -2.443" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="8.5 5 0" intensity="3.5" light="intensity:2"></a-light>
<!-- CAMERA with wasd controls and circle cursor -->
<a-camera fly look-controls wasd-controls position="17.020 16.700 7.958" rotation="-34.149 89.382 0.000">
<a-entity
cursor="fuse: true; fuseTimeout: 500"
position="0 0 -1"
geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03"
material="color: black; shader: flat">
</a-entity>
</a-camera>
<a-box move-my-model position="5.020 8.500 7.958" rotation="0 0 0" color="#4CC3D9"></a-box>
</a-scene>
示例 2
相反,如果您需要更复杂的动画,我在第一次使用 A-Frame 框架时自己编写了一个名为 animation-move
的 A-Frame 组件,即:
<script src="https://aframe.io/releases/0.7.0/aframe.min.js"></script>
<script>
AFRAME.registerComponent('animation-move', {
schema: {
path: {
default: [],
parse: function (value) {
return JSON.parse(value);
}
},
animationStepTime: {
type: 'int',
default: 0
}
},
init: function(){
this.next = 0;
let object = this.el;
for (let prop in this.data.path[this.next]) {
object.setAttribute( prop, this.data.path[this.next][prop] );
}
},
tick: function (time, timeDelta) {
let updated = false
if ( this.next >= this.data.path.length ) {
this.next = 0;
}
let delta = this.data.animationStepTime / (16.7 * ((this.data.animationStepTime+timeDelta)/this.data.animationStepTime));
let object = this.el;
for (let prop in this.data.path[this.next]) {
let attr = object.getAttribute(prop);
let nextStep = this.data.path[this.next][prop];
let xDelta = Math.abs( (this.next-1 >= 0) ? nextStep.x - this.data.path[this.next-1][prop].x : nextStep.x - this.data.path[this.data.path.length-1][prop].x)/delta;
let yDelta = Math.abs( (this.next-1 >= 0) ? nextStep.y - this.data.path[this.next-1][prop].y : nextStep.y - this.data.path[this.data.path.length-1][prop].y)/delta;
let zDelta = Math.abs( (this.next-1 >= 0) ? nextStep.z - this.data.path[this.next-1][prop].z : nextStep.z - this.data.path[this.data.path.length-1][prop].z)/delta;
if (attr.x != nextStep.x) {
if ((this.next-1 >= 0 && nextStep.x < this.data.path[this.next-1][prop].x) || (this.next == 0 && nextStep.x < this.data.path[this.data.path.length-1][prop].x)) {
if (attr.x-xDelta < nextStep.x) {
attr.x = nextStep.x;
}
else {
attr.x -= xDelta;
updated = true;
}
}
else if (this.next-1 >= 0 && nextStep.x > this.data.path[this.next-1][prop].x || (this.next == 0 && nextStep.x > this.data.path[this.data.path.length-1][prop].x)) {
if (attr.x+xDelta > nextStep.x) {
attr.x = nextStep.x;
}
else {
attr.x += xDelta;
updated = true;
}
}
else {
attr.x = nextStep.x;
}
}
if (attr.y != nextStep.y) {
if (this.next-1 >= 0 && nextStep.y < this.data.path[this.next-1][prop].y || (this.next == 0 && nextStep.y < this.data.path[this.data.path.length-1][prop].y)) {
if (attr.y-yDelta < nextStep.y) {
attr.y = nextStep.y;
}
else {
attr.y -= yDelta;
updated = true;
}
}
else if (this.next-1 >= 0 && nextStep.y > this.data.path[this.next-1][prop].y || (this.next == 0 && nextStep.y > this.data.path[this.data.path.length-1][prop].y)) {
if (attr.y+yDelta > nextStep.y) {
attr.y = nextStep.y;
}
else {
attr.y += yDelta;
updated = true;
}
}
else {
attr.y = nextStep.y;
}
}
if (attr.z != nextStep.z) {
if (this.next-1 >= 0 && nextStep.z < this.data.path[this.next-1][prop].z || (this.next == 0 && nextStep.z < this.data.path[this.data.path.length-1][prop].z)) {
if (attr.z-zDelta < nextStep.z) {
attr.z = nextStep.z;
}
else {
attr.z -= zDelta;
updated = true;
}
}
else if (this.next-1 >= 0 && nextStep.z > this.data.path[this.next-1][prop].z || (this.next == 0 && nextStep.z > this.data.path[this.data.path.length-1][prop].z)) {
if (attr.z+zDelta > nextStep.z) {
attr.z = nextStep.z;
}
else {
attr.z += zDelta;
updated = true;
}
}
else {
attr.z = nextStep.z;
}
}
object.setAttribute( prop, attr.x+' '+attr.y+' '+attr.z );
}
if (!updated) {
this.next++;
}
}
});
</script>
<a-scene>
<a-sky color="#f9f2cf"></a-sky>
<!-- LIGHT a-frame no need to export from blender -->
<a-light color="#fff" position="-8 5 0" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="0 5 -14.163" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="0 5 14.192" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="0 -9.574 -2.443" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="8.5 5 0" intensity="3.5" light="intensity:2"></a-light>
<!-- CAMERA with wasd controls and circle cursor -->
<a-camera fly look-controls wasd-controls position="17.020 16.700 7.958" rotation="-34.149 89.382 0.000">
<a-entity
cursor="fuse: true; fuseTimeout: 500"
position="0 0 -1"
geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03"
material="color: black; shader: flat">
</a-entity>
</a-camera>
<a-box animation-move='path: [ {"position": {"x": 15.020, "y": 15.500, "z": 7.958}}, {"position": {"x": 10, "y": 17.000, "z": 5}} ]; animationStepTime: 1500' rotation="0 0 0" color="#4CC3D9"></a-box>
</a-scene>
更复杂的例子
Here 您可以找到我的 A-Frame 示例以及其他一些 A-Frame 组件,例如最后一个!此示例展示了拉奎拉(意大利)圣玛格丽塔教堂的重建立面,其中包含一些灯光动画和交互式面板。
我已将 gltf-model 加载到 a-frame,我想将其沿 y 轴移动 20。我使用此代码:
问题出现在一帧场景中,实际上对象被向上移动(检查 "after" 图像中的阴影和场景检查器),但它仍然显示在它之前的位置。看来场景需要某种刷新。
问题是,如何用three.js代码正确移动它?
前:
BEFORE1
BEFORE2
后:
AFTER1
AFTER2
代码:
<html>
<a-scene>
<a-sky color="#f9f2cf"></a-sky>
<!-- LIGHT a-frame no need to export from blender -->
<a-light color="#fff" position="-8 5 0" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="0 5 -14.163" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="0 5 14.192" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="0 -9.574 -2.443" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="8.5 5 0" intensity="3.5" light="intensity:2"></a-light>
<!-- CAMERA with wasd controls and circle cursor -->
<a-camera fly look-controls wasd-controls position="17.020 16.700 7.958" rotation="-34.149 89.382 0.000">
<a-entity
cursor="fuse: true; fuseTimeout: 500"
position="0 0 -1"
geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03"
material="color: black; shader: flat">
</a-entity>
</a-camera>
<a-assets>
<!-- GLTF animation samples -->
<a-asset-item id="afb_animation" src="models/afb_animation.gltf"></a-asset-item>
</a-assets>
<a-entity id="_afb_animation" position="0 0 0" gltf-model="#afb_animation" ></a-entity>
</a-scene>
<!-- script change model position -->
<script>
$( document ).ready(function() {
var xAxis = new THREE.Vector3(1,0,0);
setTimeout(function(){
console.log("rotation: done");
document.querySelector('#_afb_animation').sceneEl.object3D.translateY(20);
}, 3000);
});
</script>
解决您的问题的一种方法是使用 setAttribute
方法(官方 wiki here) on the position component.
例如:
entity.setAttribute('position', { x: 1, y: 2, z: 3 });
其中实体是任何 A-Frame 实体。
示例 1
所以,在下面的代码中,我注册了一个名为 move-my-model
的 A-Frame component,它允许我移动我的实体(在我的例子中是一个 <a-box>
实体,但它也适用于你的模型)在 3000 毫秒后用 setTimeout
添加 10 到它的 y-position (比如你的代码示例):
<script src="https://aframe.io/releases/0.7.0/aframe.min.js"></script>
<script>
AFRAME.registerComponent('move-my-model', {
init: function () {
setTimeout( () => {
let position = this.el.getAttribute("position")
position.y += 10
this.el.setAttribute("position", position)
}, 3000)
}
})
</script>
<a-scene>
<a-sky color="#f9f2cf"></a-sky>
<!-- LIGHT a-frame no need to export from blender -->
<a-light color="#fff" position="-8 5 0" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="0 5 -14.163" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="0 5 14.192" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="0 -9.574 -2.443" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="8.5 5 0" intensity="3.5" light="intensity:2"></a-light>
<!-- CAMERA with wasd controls and circle cursor -->
<a-camera fly look-controls wasd-controls position="17.020 16.700 7.958" rotation="-34.149 89.382 0.000">
<a-entity
cursor="fuse: true; fuseTimeout: 500"
position="0 0 -1"
geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03"
material="color: black; shader: flat">
</a-entity>
</a-camera>
<a-box move-my-model position="5.020 8.500 7.958" rotation="0 0 0" color="#4CC3D9"></a-box>
</a-scene>
示例 2
相反,如果您需要更复杂的动画,我在第一次使用 A-Frame 框架时自己编写了一个名为 animation-move
的 A-Frame 组件,即:
<script src="https://aframe.io/releases/0.7.0/aframe.min.js"></script>
<script>
AFRAME.registerComponent('animation-move', {
schema: {
path: {
default: [],
parse: function (value) {
return JSON.parse(value);
}
},
animationStepTime: {
type: 'int',
default: 0
}
},
init: function(){
this.next = 0;
let object = this.el;
for (let prop in this.data.path[this.next]) {
object.setAttribute( prop, this.data.path[this.next][prop] );
}
},
tick: function (time, timeDelta) {
let updated = false
if ( this.next >= this.data.path.length ) {
this.next = 0;
}
let delta = this.data.animationStepTime / (16.7 * ((this.data.animationStepTime+timeDelta)/this.data.animationStepTime));
let object = this.el;
for (let prop in this.data.path[this.next]) {
let attr = object.getAttribute(prop);
let nextStep = this.data.path[this.next][prop];
let xDelta = Math.abs( (this.next-1 >= 0) ? nextStep.x - this.data.path[this.next-1][prop].x : nextStep.x - this.data.path[this.data.path.length-1][prop].x)/delta;
let yDelta = Math.abs( (this.next-1 >= 0) ? nextStep.y - this.data.path[this.next-1][prop].y : nextStep.y - this.data.path[this.data.path.length-1][prop].y)/delta;
let zDelta = Math.abs( (this.next-1 >= 0) ? nextStep.z - this.data.path[this.next-1][prop].z : nextStep.z - this.data.path[this.data.path.length-1][prop].z)/delta;
if (attr.x != nextStep.x) {
if ((this.next-1 >= 0 && nextStep.x < this.data.path[this.next-1][prop].x) || (this.next == 0 && nextStep.x < this.data.path[this.data.path.length-1][prop].x)) {
if (attr.x-xDelta < nextStep.x) {
attr.x = nextStep.x;
}
else {
attr.x -= xDelta;
updated = true;
}
}
else if (this.next-1 >= 0 && nextStep.x > this.data.path[this.next-1][prop].x || (this.next == 0 && nextStep.x > this.data.path[this.data.path.length-1][prop].x)) {
if (attr.x+xDelta > nextStep.x) {
attr.x = nextStep.x;
}
else {
attr.x += xDelta;
updated = true;
}
}
else {
attr.x = nextStep.x;
}
}
if (attr.y != nextStep.y) {
if (this.next-1 >= 0 && nextStep.y < this.data.path[this.next-1][prop].y || (this.next == 0 && nextStep.y < this.data.path[this.data.path.length-1][prop].y)) {
if (attr.y-yDelta < nextStep.y) {
attr.y = nextStep.y;
}
else {
attr.y -= yDelta;
updated = true;
}
}
else if (this.next-1 >= 0 && nextStep.y > this.data.path[this.next-1][prop].y || (this.next == 0 && nextStep.y > this.data.path[this.data.path.length-1][prop].y)) {
if (attr.y+yDelta > nextStep.y) {
attr.y = nextStep.y;
}
else {
attr.y += yDelta;
updated = true;
}
}
else {
attr.y = nextStep.y;
}
}
if (attr.z != nextStep.z) {
if (this.next-1 >= 0 && nextStep.z < this.data.path[this.next-1][prop].z || (this.next == 0 && nextStep.z < this.data.path[this.data.path.length-1][prop].z)) {
if (attr.z-zDelta < nextStep.z) {
attr.z = nextStep.z;
}
else {
attr.z -= zDelta;
updated = true;
}
}
else if (this.next-1 >= 0 && nextStep.z > this.data.path[this.next-1][prop].z || (this.next == 0 && nextStep.z > this.data.path[this.data.path.length-1][prop].z)) {
if (attr.z+zDelta > nextStep.z) {
attr.z = nextStep.z;
}
else {
attr.z += zDelta;
updated = true;
}
}
else {
attr.z = nextStep.z;
}
}
object.setAttribute( prop, attr.x+' '+attr.y+' '+attr.z );
}
if (!updated) {
this.next++;
}
}
});
</script>
<a-scene>
<a-sky color="#f9f2cf"></a-sky>
<!-- LIGHT a-frame no need to export from blender -->
<a-light color="#fff" position="-8 5 0" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="0 5 -14.163" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="0 5 14.192" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="0 -9.574 -2.443" intensity="3.5" light="intensity:2"></a-light>
<a-light color="#fff" position="8.5 5 0" intensity="3.5" light="intensity:2"></a-light>
<!-- CAMERA with wasd controls and circle cursor -->
<a-camera fly look-controls wasd-controls position="17.020 16.700 7.958" rotation="-34.149 89.382 0.000">
<a-entity
cursor="fuse: true; fuseTimeout: 500"
position="0 0 -1"
geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03"
material="color: black; shader: flat">
</a-entity>
</a-camera>
<a-box animation-move='path: [ {"position": {"x": 15.020, "y": 15.500, "z": 7.958}}, {"position": {"x": 10, "y": 17.000, "z": 5}} ]; animationStepTime: 1500' rotation="0 0 0" color="#4CC3D9"></a-box>
</a-scene>
更复杂的例子
Here 您可以找到我的 A-Frame 示例以及其他一些 A-Frame 组件,例如最后一个!此示例展示了拉奎拉(意大利)圣玛格丽塔教堂的重建立面,其中包含一些灯光动画和交互式面板。