Fedor Posted June 9, 2017 Share Posted June 9, 2017 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? Quote Link to comment Share on other sites More sharing options...
jerome Posted June 9, 2017 Share Posted June 9, 2017 this one is fast (used in the SPS and can change colors, positions, uvs, normals, etc of thousands of vertices per frame) : https://github.com/BabylonJS/Babylon.js/blob/master/src/Particles/babylon.solidParticleSystem.ts#L826 Quote Link to comment Share on other sites More sharing options...
Fedor Posted June 9, 2017 Author Share Posted June 9, 2017 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. Quote Link to comment Share on other sites More sharing options...
jerome Posted June 9, 2017 Share Posted June 9, 2017 Well... interesting approach. Nevertheless be careful because BJS provides a cache mechanism, so skipping it can lead to weird results sometimes. Quote Link to comment Share on other sites More sharing options...
Fedor Posted June 9, 2017 Author Share Posted June 9, 2017 I am aware that hacking can lead to unforseen or even unwanted results. I am hoping someone will stop by who can help me a) get it to work and b) prevent some problems... @Deltakosh? Quote Link to comment Share on other sites More sharing options...
GameMonetize Posted June 9, 2017 Share Posted June 9, 2017 I can help only if you provide a repro (in the PG) NasimiAsl 1 Quote Link to comment Share on other sites More sharing options...
Fedor Posted June 9, 2017 Author Share Posted June 9, 2017 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? Wingnut 1 Quote Link to comment Share on other sites More sharing options...
GameMonetize Posted June 10, 2017 Share Posted June 10, 2017 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); Wingnut 1 Quote Link to comment Share on other sites More sharing options...
Fedor Posted June 11, 2017 Author Share Posted June 11, 2017 Great, I will create a speed benchmark demo in PG to see how much time we have won. Quote Link to comment Share on other sites More sharing options...
Fedor Posted June 12, 2017 Author Share Posted June 12, 2017 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... Quote Link to comment Share on other sites More sharing options...
GameMonetize Posted June 12, 2017 Share Posted June 12, 2017 It works for me if I do not multiply by 4: http://www.babylonjs-playground.com/#DMYNYQ#11 Quote Link to comment Share on other sites More sharing options...
Fedor Posted June 12, 2017 Author Share Posted June 12, 2017 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) Quote Link to comment Share on other sites More sharing options...
sable Posted June 12, 2017 Share Posted June 12, 2017 I think this is because the offset is in bytes. With four bytes per float32 number the multiply by 4 is needed to convert the index offset to the byte offset. Quote Link to comment Share on other sites More sharing options...
Fedor Posted June 13, 2017 Author Share Posted June 13, 2017 That sounds like a plausible explaination... @Deltakosh can I ask for an extra feature? It would be great if there would be a function that would (re)calculate a single normal... Quote Link to comment Share on other sites More sharing options...
GameMonetize Posted June 13, 2017 Share Posted June 13, 2017 What for? How do you think about using it? Quote Link to comment Share on other sites More sharing options...
Fedor Posted June 14, 2017 Author Share Posted June 14, 2017 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. Quote Link to comment Share on other sites More sharing options...
GameMonetize Posted June 14, 2017 Share Posted June 14, 2017 I understand. In this case you will have to save the faces somewhere and when you update the vertices, you will have to find the affected faces, recompute the normals and update only affected normals (the same way you update the positions with updateVerticesDataDirectly) Quote Link to comment Share on other sites More sharing options...
jerome Posted June 14, 2017 Share Posted June 14, 2017 to get facets, facet normals, and other info about each face, simply use FacetData : http://doc.babylonjs.com/tutorials/how_to_use_facetdata Quote Link to comment Share on other sites More sharing options...
Fedor Posted June 17, 2017 Author Share Posted June 17, 2017 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. Quote Link to comment Share on other sites More sharing options...
NasimiAsl Posted June 17, 2017 Share Posted June 17, 2017 why you don't change it in GPU side? you can calculate normal in gpu side too Quote Link to comment Share on other sites More sharing options...
Fedor Posted June 18, 2017 Author Share Posted June 18, 2017 I think that is what Babylon does. But that seems to be slower then this routine. It involves copying buffers and it does all normals on my 50K model... Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.