Jump to content

Messing with meshes: can I work on the geometry directly


Fedor
 Share

Recommended Posts

Working on my sculpting tool with 50K vertices, I am still researching ways to modify the vertices as fast as possible. 

As I understand it now, the methods meshes offer to modify the geometry do the following:

- setVerticesData - creates a new array and does a copy of the given buffer

- updataVerticesData - only copies the buffer.

- The ApplyToMesh from VertexData copies all the buffers to the mesh 

 

I just found the _geometry-property of the mesh, which seems to hold all buffers. So I started testing modifying them directly.

When I modify the color buffer (base_model.mesh._geometry._vertexBuffers.color._buffer._data) nothing happens. 

My guess is I need something to trigger the buffer to be fed to WebGl. Does anyone know how to pull this trigger?

 

 

 

Link to comment
Share on other sites

Is it in my case?

I red it copies the given buffer. I can imagine that would be very fast in cases where many vertices are changed at once. But when changing only a handful of vertices per rendering pass, copying the entire buffer would be a lot of overhead. 

I am sure it is the fastest of all the 'official' methods that are now available. But could there be a hack that allows me to directly write the buffers WebGL uses. Or even better, could there be a method to do this in the future.

 

Link to comment
Share on other sites

Ok,

Here is a simple exampe:

http://www.babylonjs-playground.com/#YVA9CM#1

I take the custom mesh from the manual 'Creating Custom Meshes'. At creation time the first vertice is blue and the second is green. I then try to change the color of the second vertice as follows:

    colorbuffer=customMesh._geometry._vertexBuffers.color._buffer._data;
    idx=2
        colorbuffer[idx*4]=1;
        colorbuffer[idx*4+1]=0;
        colorbuffer[idx*4+2]=0;
        colorbuffer[idx*4+3]=1;

I would expect the second vertice to be red now. But as you see it isn't

When you hit F12, you'll see in the console that the buffer is filled with the expected values - being the original color array with postions 4 to 7 altered. So I got a hunch this is the color buffer but the changes are not applied.

My expectation is, that if I get this to work, it will be a faster way to modify the meshes - at least in the case where there only are a few vertices changed per frame.

Now, how do I get these change to be rendered?

 

Link to comment
Share on other sites

So good news: this is feasible with no hack :) 

http://www.babylonjs-playground.com/#YVA9CM#2

Note several things:

- Must flag the mesh as updatable to be able to change a part of the buffer: customMesh.markVerticesDataAsUpdatable(BABYLON.VertexBuffer.ColorKind, true);

- You can get the geometry through mesh.geometry

- the geometry knows how to update a part of buffer: geometry.updateVerticesDataDirectly(BABYLON.VertexBuffer.ColorKind, new Float32Array(newData), idx * 4);

Link to comment
Share on other sites

Okay, here it is: http://www.babylonjs-playground.com/#DMYNYQ#10

It shows that setVerticesData and updateVerticesData do not differ in speed all too much. updateVerticesDataDirectly indeed is a lot faster. 

I am updating about 100 vertices per frame in this benchmark.

You may want to try this in all major browsers, there is a huge speed difference between Firefox and Chrome. The latter one being much slower for the first two cases and twice as fast for 'Directly'

One more question for @Deltakosh: as you can see in case '2' I pick a number between 0 and the number of vertices and multiply that by 4 (four numbers in a colour). Strange enough I only got this case to work when I multiplied the idx variable by 4 a second time... 

Link to comment
Share on other sites

if you comment out the test++ line (#124) you will notice that it will only cover the top of the sphere AND that test #2 uses different colors while it should only paint vertices red:

http://www.babylonjs-playground.com/#DMYNYQ#13

Now multiply it again and it does what I've asked it to do, color vertices red all over the sphere:

http://www.babylonjs-playground.com/#DMYNYQ#14

(tested on Chrome and Firefox on Ubuntu 17.04 machine)

 

 

 

 

Link to comment
Share on other sites

Well, I am building a sculpting application in which I will change a small number of vertices per frame on a now 50K vertices model. The updateVerticesDataDirectly-method helps me to change just them and not have to swap the entire vertices buffers all the time. But to recalculate the normals every frame I now use computeNormals and then use updateVerticesData to swap the entire normals-table.

 

Link to comment
Share on other sites

Using facet data would not help here because I need updated normals for just a few facets. 

I have coded a function that recalculates the vertice normals. It depends on an extra buffer for the vertice to triangle relation. I also stored indices, normals and points in my own object to have quicker access.

calcNormals: function(list) {
	var tri_normals = {};
	var newData3 = new Float32Array(3);
	var idx = 0;
	
	var _p2t = base_model.p2t;
	var points = base_model.points;
	var poly = base_model.poly;
	var normals = base_model.normals;
	var geometry = base_model.mesh.geometry;
	
	var tlist = [];

	for (var i in list) {
		// Recalculate for every vertice in the list
		
		var currPoint=list[i];
		tlist = _p2t[currPoint];
		var normal = new BABYLON.Vector3(0, 0, 0);

		var tl = tlist.length;
		for (var t = 0; t < tl; t++) {
			// Calc all triangles connected to the vertice
			var currTri=tlist[t];

			
			if (tri_normals[tlist[t]]) {
				// If we already got this one, use that
				var tnormal = tri_normals[currTri];
			} else {
				// If not, calculate it.  
				faceId = currTri*3;
				var vertex1 = BABYLON.Vector3.FromArray(points, poly[faceId] * 3);
				var vertex2 = BABYLON.Vector3.FromArray(points, poly[faceId + 1] * 3);
				var vertex3 = BABYLON.Vector3.FromArray(points, poly[faceId + 2] * 3);
				var p1p2 = vertex1.subtract(vertex2);
				var p3p2 = vertex3.subtract(vertex2);
				var tnormal = BABYLON.Vector3.Normalize(BABYLON.Vector3.Cross(p1p2, p3p2));
				// Keep it for later use
				tri_normals[currTri] = tnormal;
			}

			normal.x += tnormal.x;
			normal.y += tnormal.y;
			normal.z += tnormal.z;

		}
		// Divide to get the average (no need to normalize it!)
		normal.x/=tl;
		normal.y/=tl;
		normal.z/=tl;
		
		// Store it in my normals array and feed it to the mesh
		idx=currPoint*3;
		newData3[0]=normals[idx]=normal.x;
		newData3[1]=normals[idx+1]=normal.y;
		newData3[2]=normals[idx+2]=normal.z;
		geometry.updateVerticesDataDirectly(BABYLON.VertexBuffer.NormalKind, newData3, idx * 4)
		
	}
},

Works fine, hope it will be of use for others. If anyone has an idea how to increase the speed, let me know.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...