Colmea Posted January 22, 2016 Share Posted January 22, 2016 Hello, It's my first post, so thank you for your awesome work on Babylon.js. I come from Three.js, and I hope my journey here will be good ! Let me explain the situation: I need to create a custom 6 faces polygon. I decided to start from a Babylon Box, and then update vertices position. It was easy on Three.js, but seems harder on Babylon. I have some questions: 1) What's the order of the vertices position ? It looks like the first vertice is on the back face, in the bottom right side, and the second one bottom left. Is it normal or am I doing something wrong ? 2) Why are there two vertices for a same 3D position ? In other words, why can't we share a vertex for several faces ? It's really complicated to have 24 vertices for a single box. 8 vertices are not enough ? (I'm not an expert at all, I guess there's a reason. Again, in Three.js there are only 8 vertices). 3) I'm surprised that getVerticesData(POSITION) returns an array of numbers. Why don't we have an array of Vector3 ? All these questions can be summarized in a single one: how do you easily manage vertices update in a box. I find it really complicated to deal with a "big-array-with-96-number-and-deal-with-it" for a single cube (knowing I will have to deal with more complicated polygons in the future). Hope you can give me advices or tools for that ! Have a nice day, Colmea Quote Link to comment Share on other sites More sharing options...
jerome Posted January 22, 2016 Share Posted January 22, 2016 Hi welcome on this forum and welcome in the wonderful BJS world 1) well, the concepts of front, back, up, down are quite complex in 3D as they depend upon the camera position To exactly know what face of your box you want to address, you could first give each a different color. This doc may help you : http://doc.babylonjs.com/tutorials/CreateBox_Per_Face_Textures_And_Colors http://doc.babylonjs.com/tutorials/CreateBox_Per_Face_Textures_And_Colors#colors 2) In BJS, contrary to ThreeJS, all the vertices are indexed. This means, there is an array called "indices" to reference all the used vertices. As a normal is set per vertex only, it is required to have as many vertices as the normal vectors wanted. This method is really fast as soon as the number of vertices increase, in particular for vertex re-use. So for a box, there are 2 triangular facets per box side, so 4 vertices per box side (2 are shared between the two facets). So in total, 6 sides * 4 = 24 vertices. Please have a look at the first part of this tutorial to understand what the indexed vertices mean : https://blogs.msdn.microsoft.com/eternalcoding/2014/04/17/what-do-you-mean-by-shaders-learn-how-to-create-shaders-with-babylon-js/ 3 ) getVerticesData(Positions) returns the array "positions" of the mesh... each successive triplet of floats is each vertex coordinates : [v1.x, v1.y, v1.z, v2.x, v2.y, v2.z ....] If you set your mesh as updatable at creation time, you can easily change its vertex position with updateMeshPositions() http://doc.babylonjs.com/tutorials/How_to_dynamically_morph_a_mesh#other-shapes-updatemeshpositions Hope it helps Quote Link to comment Share on other sites More sharing options...
Colmea Posted January 22, 2016 Author Share Posted January 22, 2016 Thanks for your fast answer. Well, that's not good news actually (but I expected this kind of answer). I guess I will have to extend the Box class and create methods to help me update vertices easily (give only 8 Vector3). I will share my code here I hope someone already works on this ! Thanks you (and the per face texture is a good idea ! ) Quote Link to comment Share on other sites More sharing options...
jerome Posted January 22, 2016 Share Posted January 22, 2016 Actually, all the BJS parametric shapes can be morphed from their geometry declaration (in short, from their vertices or from the way the vertices are built) : http://doc.babylonjs.com/tutorials/How_to_dynamically_morph_a_mesh Unfortunately, there's no such high level provided method to do this with the fixed shapes... as noone asked for this until now We will enjoy to share your code. Please feel free to use the playground (aka PG, the place we all share here our ideas, bugs, attempts, etc) for this : http://www.babylonjs-playground.com/# BTW, I guess you're from Belgium (Twitter told me that) so you might attend the very next FOSDEM conference in Brussels and discover the session from Raanan and Temechon, two of the framework core team and nice forum animators, here : https://fosdem.org/2016/schedule/event/babylon/ Confs or speaking directly to the core devs are one of the best experience to get very fast into the framework. It's really worth it imho. Quote Link to comment Share on other sites More sharing options...
GameMonetize Posted January 22, 2016 Share Posted January 22, 2016 Hello and Welcome Colmea! Regarding array of number or array of vector3: the main reason is performance. Internally we are using a foat32Array to provide the fastest support possible. And if, for instance you want to do fancy things like updating your mesh on every frame, this is the best option. I completely understand your point though but if you want to achieve what you mention you will have to do a copy of data. Which could be ok if you don't plan to do it too much (regarding performance AND memory consumption ;)) Other question: why 24 instead of 8? Because of uv and normal. With only 8 vertices you cannot provide decent shading (normal) or per-face textures coordinates. The core foundation of BJS is simplicity and I must agree with you. This is not the case here. But sometimes simplicity has to disappear to gain performance. ANd in this case, you will always be able to count on this community to help you Quote Link to comment Share on other sites More sharing options...
Colmea Posted January 25, 2016 Author Share Posted January 25, 2016 Thanks for your clarification Deltakosh ! I agree, simplicity is not always the right choice. However, in my case, vertices are not updated on each frame: it's an event triggered by the user (which fill a form to build a new polygon). So performance is not really the main issue in my case. One last thing: I understand the reason behind the 24 vertices, but is there a single reason why someone would like to move two "same" vertices on different positions ? In other words, why BABYLON doesn't hide this complexity for developers ? I'm working on a custom Box class to help me move vertices easily. Here is a (WIP) demo: http://babylonjs-playground.com/#1QHDMR#0 This way I can move vertices from a specific face and don't care about linked vertices anymore: // Create custom box (extend createBox helper) var box = new CustomBox('customBox', scene); // Move vertice 0 and 2 on top face (according to world axis) // This automatically move linked vertices var topFace = []; topFace[0] = new BABYLON.Vector3(-3, 2, 0); topFace[2] = new BABYLON.Vector3(0.5, 0.5, 0); box.updateFacesVertices({ top: topFace }); Some important points: The vertice index on each face is related to the order of creation in the CreateBox method (which is not logical between faces, or I'm missing something). Code is not DRY at all, and the 'top', 'back', 'left', ... references are arbitrary. Need some clean up. Next step is to be able to do something like this: box.getFace('top').vertices[0].position.x += 10; I know this is a really specific use case. But maybe it can helps someone Quote Link to comment Share on other sites More sharing options...
GameMonetize Posted January 25, 2016 Share Posted January 25, 2016 Thank you for sharing This is not done by BJs because thisis (as you mentioned) a really specific use case. Quote Link to comment Share on other sites More sharing options...
Stvsynrj Posted January 26, 2016 Share Posted January 26, 2016 In case of, this was my first considaration on babylonjs ! you can play with that : http://www.babylonjs-playground.com/#20GQPQ#0 Quote Link to comment Share on other sites More sharing options...
GameMonetize Posted January 26, 2016 Share Posted January 26, 2016 Remind me of some great demos on my Amiga Quote Link to comment Share on other sites More sharing options...
DeadTaco Posted February 17, 2016 Share Posted February 17, 2016 My explanation of this code just got evaporated when I did a minor edit to this post so here it is again. I had the exact same issue after coming from Three.JS so I had to come up with an easy solution. Here is a function that will allow you to move any vertex in a mesh. If the vertex is shared among faces, all shared vertices will move with it. Some of the code originally came from a tutorial I found online. Sorry if it's a little messy. use: shiftVertex(yourMesh, vertexNumber, [x, y, z]) where x y z is the amount to move the vertex. /* Shift a vertex by an amount on the xyz axis */ function shiftVertex(mesh, vertexNumber, xyz) { var vertexData = BABYLON.VertexData.ExtractFromMesh(mesh); var positions = vertexData.positions; var numberOfPoints = positions.length / 3; // Build a map containing all vertices at the same position var map = []; for (var i = 0; i < numberOfPoints; i++) { var p = new BABYLON.Vector3(positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2]); var found = false; for (var index = 0; index < map.length && !found; index++) { var array = map[index]; var p0 = array[0]; if (p0.equals(p) || (p0.subtract(p)).lengthSquared() < 0.01) { array.push(i * 3); found = true; } } if (!found) { var array = []; array.push(p, i * 3); map.push(array); } } var thisVertex = map[vertexNumber]; /* Change the "+=" to just "=" for direct coordinate placement */ for (index = 1; index < thisVertex.length; index++) { var i = thisVertex[index]; positions += xyz[0]; positions[i + 1] += xyz[1]; positions[i + 2] += xyz[2]; } vertexData.applyToMesh(mesh); } Quote Link to comment Share on other sites More sharing options...
DeadTaco Posted February 17, 2016 Share Posted February 17, 2016 (edited) Here is a useful vertex labeller to use with the shiftVertex function above. This will label every vertex of a mesh with a number that corresponds to the vertex number. Used in tandem with scene.debugLayer.show() and "clickable labels" turned on, it's very useful as each vertex will be clearly labeled for use on my previous shiftVertex function. Use labelVertices(mesh) to add labels, and clearLabels() to remove labels. /* Mark each vertex with a number. WARNING! Large meshes will raise havoc here if the maxLabelsForSafety is too high! Make sure you define 'camera' and 'scene' if their names are different */ function labelVertices(mesh) { var maxLabelsForSafety = 100; /* Set a maximum number of labels to prevent complete lockup on large meshes */ /* If labels already exist, clear them first */ if( typeof _global_vertex_labelgroup != "undefined" ) { clearLabels(); } else { _global_vertex_labelgroup = []; } var positions = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind); var numberOfPoints = positions.length / 3; // Build a map containing all vertices at the same position var map = []; for (var i = 0; i < numberOfPoints; i++) { var p = new BABYLON.Vector3(positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2]); var found = false; for (var index = 0; index < map.length && !found; index++) { var array = map[index]; var p0 = array[0]; if (p0.equals(p) || (p0.subtract(p)).lengthSquared() < 0.01) { array.push(i * 3); found = true; } } if (!found) { var array = []; array.push(p, i * 3); map.push(array); } } var vertCount = 0; map.forEach(function(array) { var index; if(_global_vertex_labelgroup.length >= maxLabelsForSafety) { console.log("Too many labels! Aborting."); return; } index = 1; var i = array[index]; var textPlane = BABYLON.MeshBuilder.CreatePlane("Vertex " + vertCount, {width:1,height:1}, scene); textPlane.position = new BABYLON.Vector3(positions, positions[i+1],positions[i+2]); textPlane.billboardMode = 7; var text = vertCount.toString(); var dynamicText = new BABYLON.DynamicTexture("dt"+vertCount, 1024, scene, true); dynamicText.drawText(text, 100, 700, "bold 452px Arial", "white", "black", true); var textMaterial = new BABYLON.StandardMaterial("Text"+vertCount, scene); textMaterial.diffuseTexture = dynamicText; textPlane.material = textMaterial; var cleanupGroup = [ textPlane, dynamicText, textMaterial]; _global_vertex_labelgroup.push(cleanupGroup); vertCount++; }); } /* Clear any existing vertex labels in the scene. Make sure Babylon disposes of them cleanly. */ function clearLabels() { if( !_global_vertex_labelgroup ) { console.log("No labels were found to be cleared!"); return; } for(var i = 0; i < _global_vertex_labelgroup.length; i++) { _global_vertex_labelgroup[0].dispose(); _global_vertex_labelgroup[1].dispose(); _global_vertex_labelgroup[2].dispose(); } _global_vertex_labelgroup = []; } Admittedly, I only tested this in an app I'm working on but it works well. Edited February 18, 2016 by DeadTaco Numbers were being shown one value off Quote Link to comment Share on other sites More sharing options...
Pryme8 Posted February 17, 2016 Share Posted February 17, 2016 why not just push the array of three numbers into an object array that holds a Quat, so like with the 4th value being a unique identifier or the vertex number. then just parse then arrange those any way you would want then parse them back to a standard array minus the unique ID when you need to propagate them back. Quote Link to comment Share on other sites More sharing options...
Colmea Posted February 18, 2016 Author Share Posted February 18, 2016 Thanks DeadTaco, it's really interesting ! 14 hours ago, DeadTaco said: If the vertex is shared among faces, all shared vertices will move with it. If I understand the code, you define "shared" vertices by their position. This could be a problem for me (vertices sometimes are on the same position). But I will use your code, thanks. What is missing now is an easy way to create polygons, and remove the "3 vertices complexity". Would be awesome to do something like this: // Create a custom pyramid vertices = [ new BABYLON.Vector3(0, 0, 0), // 0 new BABYLON.Vector3(4, 0, 0), // 1 new BABYLON.Vector3(2, 0, 4), // 2 new BABYLON.Vector3(2, 4, 2), // 3 ]; var pyramid = new BABYLON.CreatePolygon('myPyramid', scene, vertices, ...); // Move vertices with DeadTaco's function adaption // Move vertex 0 (and all shared vertices) to a new position pyramid.moveVertex(0, new BABYLON.Vector3(1, 0, 0)); Do you think it's feasible with Babylon ? (I mean, the vertices algo is not a problem, but I don't know a lot about faces, normals, ... Is it possible to compute them based on vertices ?) Rehkitz 1 Quote Link to comment Share on other sites More sharing options...
jerome Posted February 18, 2016 Share Posted February 18, 2016 http://doc.babylonjs.com/tutorials/Mesh_CreateXXX_Methods_With_Options_Parameter#polyhedron by default, all the faces of a polyhedron are independant, so you can move/morph them without changing the others [EDIT] http://www.babylonjs-playground.com/#21QRSK#1 Minimize the editor (button EDITOR-) to see their names with the mouse pointer Quote Link to comment Share on other sites More sharing options...
Suphi Posted February 18, 2016 Share Posted February 18, 2016 i never did the uv mapping but is this what you want? mesh that does not share verticeshttp://www.babylonjs-playground.com/#I6FWR#1 mesh that share vertices (gives a smooth effect)http://www.babylonjs-playground.com/#1EWY8M#1 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.