Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I merge geometries in A-Frame without losing material information?

Tags:

aframe

I have a large set of block objects using a custom geometry, that I am hoping to merge into a smaller number of larger geometries, as I believe this will reduce rendering costs.

I have been following guidance here: https://aframe.io/docs/1.2.0/introduction/best-practices.html#performance which has led me to the geometry-merger component here: https://github.com/supermedium/superframe/tree/master/components/geometry-merger/

The A-Frame docs say: "You can use geometry-merger and then make use a three.js material with vertex colors enabled. three.js geometries keep data such as color, uvs per vertex."

The geometry-merger component also says: "Useful if using vertex or face coloring as individual geometries' colors can still be manipulated individually since this component keeps a faceIndex and vertexIndex."

However I have a couple of problems.

  1. If I set vertexColors on my material (as suggested by the A-Frame docs), then this ruins the appearance of my blocks.
  2. Whether or not I set vertexColors on my material, all material information seems to be lost when the geometries are merged, and everything just ends up white.

See this glitch for a demonstration of both problems. https://tundra-mercurial-garden.glitch.me/

My suspicion is that the A-Frame geometry-merger component just won't do what I need here, and I need to implement something myself using the underlying three.js functions.

Is that right, or is there a way that I could make this work using geometry-merger?

like image 230
Diarmid Mackenzie Avatar asked Jan 21 '26 10:01

Diarmid Mackenzie


1 Answers

For the vertexColors to work, you need to have your vertices coloured :)
More specifically - the BufferGeometry expects an array of rgb values for each vertex - which will be used as color for the material.


In this bit of code:
var geometry = new THREE.BoxGeometry();
var mat = new THREE.MeshStandardMaterial({color: 0xffffff, vertexColors: THREE.FaceColors});
var mesh = new THREE.Mesh(geometry, mat);

The mesh will be be black unless the geometry contains information about the vertex colors:

// create a color attribute in the geometry
geometry.setAttribute('color', new THREE.BufferAttribute(new Float32Array(vertices_count), 3));
// grab the array
const colors = this.geometry.attributes.color.array;

// fill the array with rgb values
const faceColor = new THREE.Color(color_hex);
for (var i = 0; i < vertices_count / 3; i += 3) {
   colors[i + 0] = faceColor.r; // lol +0
   colors[i + 1] = faceColor.g;
   colors[i + 2] = faceColor.b;
}
// tell the geometry to update the color attribute
geometry.attributes.color.needsUpdate = true;

I can't make the buffer-geometry-merger component work for some reason, but It's core seems to be valid:

AFRAME.registerComponent("merger", {
  init: function() {
    // replace with an event where all child entities are ready
    setTimeout(this.mergeChildren.bind(this), 500);
  },
  mergeChildren: function() {
   const geometries = [];
   // traverse the child and store all geometries.
   this.el.object3D.traverse(node => {
     if (node.type === "Mesh") {
       const geometry = node.geometry.clone();
       geometry.applyMatrix4(node.parent.matrix);
       geometries.push(geometry)

       // dispose the merged meshes 
       node.parent.remove(node);
       node.geometry.dispose();
       node.material.dispose();
     }
   }); 
   // create a mesh from the "merged" geometry         
   const mergedGeo = THREE.BufferGeometryUtils.mergeBufferGeometries(geometries);
   const mergedMaterial = new THREE.MeshStandardMaterial({color: 0xffffff, roughness: 0.3, vertexColors: THREE.FaceColors});
    
   const mergedMesh = new THREE.Mesh(mergedGeo, mergedMaterial);
   this.el.object3D.add(mergedMesh)
 }
})

You can check it out in this glitch. There is also an example on using the vertex colors here (source).

like image 114
Piotr Adam Milewski Avatar answered Jan 23 '26 20:01

Piotr Adam Milewski



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!