Я создал пользовательский компонент в a-frame, который создает заказную геометрию. Я использую функцию tick, чтобы оживить обновление вершин геометрии. Все работает отлично, однако тень на геометрии не обновляется.
В моем примере ниже я переключаю плоскую форму между двумя состояниями, свернутыми и развернутыми. Когда, например, он оживляет от сложенного до развернутого, лица сохраняют тень, как будто она все еще сложена.
Вот HTML, см. <a-fold>
в этом примере, начиная со сложенного состояния (это можно изменить на "развернутый", изменив этот атрибут).
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://aframe.io/releases/0.7.0/aframe.min.js"></script>
</head>
<body>
<a-scene test>
<a-fold
state="folded"
color="blue"
position="-7.5 1 -20">
</a-fold>
<a-plane
position="0 0 -4"
rotation="-90 0 0"
width="20"
height="20"
color="#7BC8A4">
</a-plane>
<a-sky
color="#ECECEC">
</a-sky>
</a-scene>
</body>
</html>
и javascript
//a trigger to test state change
AFRAME.registerComponent('test', {
init: function () {
setTimeout(function(){
var target = document.querySelector('a-fold');
target.setAttribute('changestate', true);
}, 2000);
}
});
//component
AFRAME.registerComponent('folder', {
schema: {
state: {type: 'string', default: 'unfolded'},
color: {type: 'color', default: '#000'},
changestate: {type: 'boolean', default: false},
changedur: {type: 'number', default: 400},
},
store: {
unfolded: [{"x":15,"y":0,"z":0},{"x":15,"y":15,"z":0},{"x":0,"y":15,"z":0},{"x":0,"y":0,"z":0},{"x":0,"y":15,"z":0},{"x":15,"y":0,"z":0},],
folded: [{"x":15,"y":0,"z":0},{"x":12,"y":12,"z":5},{"x":0,"y":15,"z":0},{"x":3,"y":3,"z":5},{"x":0,"y":15,"z":0},{"x":15,"y":0,"z":0},],
},
update: function () {
this.geometry = new THREE.Geometry();
var geometry = this.geometry
var verts = this.store[this.data.state]
$.each( verts, function( i, v3 ) {
geometry.vertices.push ( new THREE.Vector3(v3.x, v3.y, v3.z) );
});
geometry.faces.push(new THREE.Face3(0, 1, 2))
geometry.faces.push(new THREE.Face3(3, 4, 5))
geometry.computeBoundingBox();
geometry.computeFaceNormals();
geometry.computeVertexNormals();
this.material = new THREE.MeshStandardMaterial({color: this.data.color});
this.material.side = THREE.DoubleSide;
this.material.needsUpdate = true
this.mesh = new THREE.Mesh(this.geometry, this.material);
this.mesh.castShadow = true;
this.mesh.receiveShadow = true;
this.el.setObject3D('mesh', this.mesh);
},
tick: function (t, td) {
if (this.data.changestate === true){
var dur = this.data.changedur
var geom = this.el.getObject3D('mesh').geometry
var currVerts = geom.vertices
var toVerts = this.store[this.gotoState()]
var somethingChanged = false;
var allAxis = ["x", "y", "z"];
var thisParent = this
$.each( currVerts, function( i, vert) {
var curr = currVerts[i]
var to = toVerts[i]
$.each( allAxis, function( i, axis ) {
if (thisParent.approxEqual(curr[axis], to[axis])) {
somethingChanged = somethingChanged || false;
} else if (curr[axis] < to[axis]) {
var step = thisParent.stepCalc(curr[axis], to[axis], dur, td)
curr[axis] += step;
somethingChanged = true;
} else {
var step = thisParent.stepCalc(curr[axis], to[axis], dur, td)
curr[axis] -= step;
somethingChanged = true;
}
});
});
geom.verticesNeedUpdate = somethingChanged;
}
},
gotoState: function (){
var to = ""
var current = this.data.state
var states = Object.keys(this.store)
$.each( states, function( i, state) {
if ( state != current ){
to = state
}
});
return to;
},
approxEqual: function (x, y) {
return Math.abs(x - y) < 0.00001;
},
stepCalc: function (curr, to, dur, delta){
var distance = Math.abs(curr - to)
var speed = distance/dur
var step = speed*delta
return step;
},
remove: function () {
this.el.removeObject3D('mesh');
}
});
//primitive
AFRAME.registerPrimitive('a-fold', {
defaultComponents: {
folder: {}
},
mappings: {
state: 'folder.state',
color: 'folder.color',
changestate: 'folder.changestate',
changedur: 'folder.changedur'
}
});
Извините, я знаю его много, но я не хочу его упрощать, если я потеряю проблему. Как вы можете видеть в компоненте, я попытался добавить this.material.needsUpdate = true
а также добавить this.mesh.castShadow = true
и this.mesh.receiveShadow = true
но это не имеет никакого значения.
На стороне примечания, если я делаю анимацию всей сущности (т.е. Вращение), я могу видеть материал, отражающий свет, поэтому материал реагирует на освещение динамически, а не когда я меняю форму, обновляя вершины.
Вот два изображения, которые демонстрируют, что я имею в виду.
Вы можете видеть, что на втором изображении, хотя плоскость плоская, ее тени предполагают, что она имеет складку. И он делает то же самое наоборот (т.е. Если он начинает разворачиваться, тень правильная и сохраняется, когда она складывается).
Если вам нужна дополнительная информация, пожалуйста, спрашивайте. Любая помощь очень ценится как всегда.
Освещение рассчитывается с использованием обычных векторов, в вашем случае вы перемещаете вершины сетки, но оставляете нормальные векторы, поэтому освещение не меняется. Вам нужно добавить geometry.computeVertexNormals();
в вашей функции тика после того, как вы изменили вершины.
В трехмерных тенях различаются оттенки или освещение, проблема, с которой вы сталкиваетесь, связана с освещением, но не с тенями. Вот почему настройка свойств mesh.castShadow
не mesh.castShadow
себя так, как вы ожидали.
material.needsUpdate
, но он не помог (хотя вы можете увидеть его в скрипке)