我有一个GLTF模型,其中的网格代表低聚水。在A框架中加载GLTF模型后,我试图通过在tick()函数中修改每个顶点的y坐标来对水进行动画处理。
问题在于,修改后的顶点未绘制在屏幕上,仅绘制了初始修改。我想念什么?
为重现该问题,我制作了一个简单的GLTF模型,该模型具有单个网格,该网格由4x4网格中的32个三角形组成:
{
"accessors": [
{
"bufferView": 0,
"byteOffset": 0,
"componentType": 5123,
"count": 96,
"max": [
24
],
"min": [
0
],
"type": "SCALAR"
},
{
"bufferView": 1,
"byteOffset": 0,
"componentType": 5126,
"count": 25,
"max": [
1.0,
0.0,
1.0
],
"min": [
-1.0,
0.0,
-1.0
],
"type": "VEC3"
},
{
"bufferView": 2,
"byteOffset": 0,
"componentType": 5126,
"count": 25,
"max": [
0.0,
1.0,
0.0
],
"min": [
0.0,
1.0,
0.0
],
"type": "VEC3"
}
],
"asset": {
"version": "2.0"
},
"bufferViews": [
{
"buffer": 0,
"byteLength": 192,
"byteOffset": 0,
"target": 34963
},
{
"buffer": 0,
"byteLength": 300,
"byteOffset": 192,
"target": 34962
},
{
"buffer": 0,
"byteLength": 300,
"byteOffset": 492,
"target": 34962
}
],
"buffers": [
{
"byteLength": 792,
"uri": "data:application/octet-stream;base64,AAABAAIAAAADAAEAAwAEAAEAAwAFAAQABQAGAAQABQAHAAYABwAIAAYABwAJAAgABgAIAAoABgAKAAsABAAGAAsABAALAAwAAQAEAAwAAQAMAA0AAgABAA0AAgANAA4ADgANAA8ADgAPABAAEAAPABEAEAARABIADwATABEADwAUABMADQAUAA8ADQAMABQADAAVABQADAALABUACwAWABUACwAKABYAFQAWABcAFQAXABgAFAAVABgAFAAYABMAAACAvwAAAAAAAIC/AAAAvwAAAAAAAAC/AAAAvwAAAAAAAIC/AACAvwAAAAAAAAC/AAAAvwAAAAAAAACAAACAvwAAAAAAAAAAAAAAvwAAAAAAAAA/AACAvwAAAAAAAAA/AAAAvwAAAAAAAIA/AACAvwAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAAA/AAAAAAAAAAAAAACAAAAAAAAAAAAAAAC/AAAAAAAAAAAAAIC/AAAAPwAAAAAAAAC/AAAAPwAAAAAAAIC/AACAPwAAAAAAAAC/AACAPwAAAAAAAIC/AACAPwAAAAAAAAAAAAAAPwAAAAAAAACAAAAAPwAAAAAAAAA/AAAAPwAAAAAAAIA/AACAPwAAAAAAAIA/AACAPwAAAAAAAAA/AAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAA"
}
],
"materials": [
{
"name": "Water",
"pbrMetallicRoughness": {
"baseColorFactor": [
0.0,
0.46700000762939453,
0.7450000047683716,
1.0
],
"metallicFactor": 0.0,
"roughnessFactor": 1.0
}
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"NORMAL": 2,
"POSITION": 1
},
"indices": 0,
"material": 0,
"mode": 4
}
]
}
],
"nodes": [
{
"mesh": 0,
"name": "water"
}
],
"scene": 0,
"scenes": [
{
"nodes": [
0
]
}
]
}
要在A-Frame中加载GLTF模式并为其设置动画,我正在使用以下HTML + JavaScript:
<html>
<head>
<script src="https://aframe.io/releases/0.9.2/aframe.min.js"></script>
</head>
<body>
<script>
AFRAME.registerComponent('aniwater', {
init: function() {
const data = this.data;
this.setupWater();
this.el.addEventListener('object3dset', this.setupWater.bind(this));
},
tick: function() {
const mesh = this.el.getObject3D('mesh');
if (!mesh) {
return;
}
mesh.traverse(function (node) {
// water is child node
if (node.name === "water") {
var vertexCount = node.geometry.attributes.position.count;
var vertices = node.geometry.attributes.position.array;
// update y of vertex
for (var i = 0; i < vertexCount; i++) {
var vy = vertices[i * 3 + 1];
// get the data associated to it
var vprops = this.waves[i];
// update the position of the vertex
vy = vprops.y + Math.sin(vprops.ang) * vprops.amp;
// increment the angle for the next frame
vprops.ang += vprops.speed;
vertices[i * 3 + 1] = vy;
}
// compute normals
node.geometry.computeFaceNormals();
node.geometry.computeVertexNormals();
// this does not work?
node.geometry.verticesNeedUpdate=true;
}
});
},
setupWater: function() {
const mesh = this.el.getObject3D('mesh');
if (!mesh) {
return;
}
mesh.traverse(function (node) {
// water is child node
if (node.name === "water") {
// array with wave information
this.waves = [];
var vertexCount = node.geometry.attributes.position.count;
var vertices = node.geometry.attributes.position.array;
// create an array to store new data associated to each vertex
for (var i = 0; i < vertexCount; i++) {
// get y position of each vertex
var vy = vertices[i * 3 + 1];
// store some data associated to it
this.waves.push({
y: vy,
// random start angle
ang: Math.random() * Math.PI * 2,
// random amplitude
amp: 0.5 + Math.random() * 0.15,
// random speed
speed:0.016 + Math.random() * 0.032
});
}
}
});
}
});
</script>
<a-scene>
<a-assets>
<a-asset-item id="water_asset" src="water.gltf">
</a-assets>
<a-gltf-model id="water" src="#water_asset" position="0 0 -4" aniwater></a-gltf-model>
<a-sky color="#ECECEC"></a-sky>
</a-scene>
</body>
</html>
使用资产将GLTF模型加载到 a-gltf模型中,并附加了名为 aniwater 的自定义组件。
自定义组件基于aframes-extra存储库(https://github.com/donmccurdy/aframe-extras/blob/master/src/misc/cube-env-map.js)中的cube-env-map.js并定义了3个功能。
setupWater()函数创建一个数组,其中包含有关每个顶点的信息,以便可以对水进行动画处理。目前,这是基于此处的代码:https://tympanus.net/codrops/2016/04/26/the-aviator-animating-basic-3d-scene-threejs/
init()函数在加载模型时将setupWater()函数附加到模型。这似乎工作正常。
对顶点的实际修改是在函数tick()中完成的。对于每个顶点,将更新y坐标,并计算y的新值。此后,将重新计算法线并将 verticesNeedUpdate 标志设置为true以指示更改。 这似乎不起作用。
我认为问题出在以下事实:GLTF模型的顶点不是存储在 geometry.vertices 中,而是存储在 geometry.attributes.position.array 中,因为三角形是顶点的索引。这使我怀疑 verticesNeedUpdate 标志仅适用于 geometry.vertices ,但我不确定。
位置数组中的顶点似乎确实已更新,因为我可以看到网格上的阴影变化是由更新的法线引起的。
在绘制水网格时,如何使A-Frame使用更新的顶点?
答案 0 :(得分:1)
根据docs和this anwser:
使用缓冲区几何图形(并且这样加载模型)时,需要在更改的属性对象上设置needsUpdate
标志:
// Vertices change
var vertices = node.geometry.attributes.position.array;
// .... updates ...
// nofitication
node.geometry.attributes.position.needsUpdate = true
小故障here。