Search Unity

Runtime edge editing (just like runtime editing example for faces)

Discussion in 'World Building' started by Thimo_, Apr 29, 2020.

  1. Thimo_

    Thimo_

    Joined:
    Aug 26, 2019
    Posts:
    59
    Hi,

    Question one:
    I'm building a probuilder runtime building editor and I need to be able to select/highlight individual edges from a probuilder object. The "Handles.cs" class has a method to select every face of an object. How can I get an Edge just like a face?

    Question two:
    How can I translate a selected edge at runtime? Just like its done in the sceneview. Is there something like translate(edge)?

    Question three:
    How can I use the insert edge loop functionality at runtime. I don't see something like that in the probuilder examples (or am I missing something?)
     
  2. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
    You'll probably want to read through https://github.com/Unity-Technologi...r/blob/master/Runtime/Core/SelectionPicker.cs

    You can see exactly how this is done here https://github.com/Unity-Technologi.../master/Editor/EditorCore/PositionMoveTool.cs

    Your best bet for these kind of questions is to just look at the source code for whatever action you want to mimic. In this case, see "InsertEdgeLoop.cs" in the MenuAction directory https://github.com/Unity-Technologies/com.unity.probuilder/tree/master/Editor/MenuActions/Geometry
     
    Thimo_ likes this.
  3. Thimo_

    Thimo_

    Joined:
    Aug 26, 2019
    Posts:
    59
    Dear @kaarrrllll ,

    Thank you for your help so far! I got it working to select a single edge and to insert a edge loop at runtime. I only have a question about the PositionMoveTool script. For my understanding: The Applytranslation method gets the vertices of the selected mesh and executes a translation matrix on these vertices.

    Code (CSharp):
    1. void ApplyTranslation(Vector3 translation)
    2.         {
    3.             foreach (var key in elementSelection)
    4.             {
    5.                 if (!(key is MeshAndPositions))
    6.                     continue;
    7.  
    8.                 var kvp = (MeshAndPositions)key;
    9.                 var mesh = kvp.mesh;
    10.                 var worldToLocal = mesh.transform.worldToLocalMatrix;
    11.                 var origins = kvp.positions;
    12.                 var positions = mesh.positionsInternal;
    13.  
    14.                 foreach (var group in kvp.elementGroups)
    15.                 {
    16.                     var postApplyMatrix = GetPostApplyMatrix(group);
    17.                     var preApplyMatrix = postApplyMatrix.inverse;
    18.  
    19.                     foreach (var index in group.indices)
    20.                     {
    21.                             positions[index] = worldToLocal.MultiplyPoint3x4(
    22.                                 postApplyMatrix.MultiplyPoint3x4(
    23.                                     translation + preApplyMatrix.MultiplyPoint3x4(origins[index])));
    24.                         }
    25.                 }
    26.  
    27.                 mesh.mesh.vertices = positions;
    28.                 mesh.RefreshUV(MeshSelection.selectedFacesInEditZone[mesh]);
    29.                 mesh.Refresh(RefreshMask.Normals);
    30.             }
    31.  
    32.             ProBuilderEditor.Refresh(false);
    33.         }
    This code above gets executed when translating the edge loop in the editor.

    Code (CSharp):
    1. private void SetEdgeLoopPosition(Vector3 position, Edge[] edges)
    2.     {
    3.         var mesh = objectSelection.mesh;
    4.         var origins = mesh.positions;
    5.         var worldToLocal = mesh.transform.worldToLocalMatrix;
    6.         var positions = mesh.positions;
    7.     }
    I do have the edges of the edge loop but I do not have acces to the elementselection as far as I know.

    Do I have to implement this elementSelection @ runtime or is there a smarter way of doing this?
    Thank you in advance!
     
    Last edited: May 27, 2020
  4. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
    Yes, I think that's about the gist of it. Looking at the source for MeshAndElementSelection, I don't see any technical reason that this couldn't be made into a runtime class. It's likely that I just wasn't happy with the API at the time, so it stayed internal and editor-only.
     
  5. Thimo_

    Thimo_

    Joined:
    Aug 26, 2019
    Posts:
    59
    Dear @kaarrrllll ,

    I have searched through the code and found the way to get my edge loop position. I can add my desired translation to this.The editor code is working with the x,y,z gizmos but I dont need any of that. I only have a static translation value that I want to apply.

    I have the idea that the matrix translation calculation isnt nessesary @ runtime to translate the edge loop. Is that correct?

    Code (CSharp):
    1.  private void SetEdgeLoopPosition(Vector3 translation, Edge[] edges)
    2.     {
    3.         var mesh = objectSelection.mesh;
    4.  
    5.         for (int i = 0; i < edges.Length; i++)
    6.         {
    7.             var edgePosition = HandleUtility.GetActiveElementPosition(mesh, edges);
    8.             edgePosition += translation;
    9.  
    10.             //apply translation
    11.             mesh.positions[i] = edgePosition;
    12.             //HandleUtility.SetActiveElementPosition(mesh, edges, translation);
    13.         }
    14.     }
    Is a SetActiveElementPosition() (edge) method an option (how would I make that)?.
     
  6. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
    What you have there will work, yes. Just make sure to call mesh.ToMesh and mesh.Refresh after making modifications to the vertex arrays.
     
  7. Thimo_

    Thimo_

    Joined:
    Aug 26, 2019
    Posts:
    59
    @kaarrrllll ,

    Thank you, I can manipulate the vertices now. But my edge loop stays at the same position. Do you know what I need to change so I can translate the edge loop instead? This code currently does only reposition the vertices not the edge loop:

    Code (CSharp):
    1. private void SetEdgeLoopPosition(Vector3 translation, Edge[] edges)
    2.     {
    3.         var mesh = objectSelection.mesh;
    4.         var verticesArray = mesh.GetVertices();
    5.  
    6.         foreach (var edge in edges)
    7.         {
    8.             var edgePosition = HandleUtility.GetActiveElementPosition(mesh, edges);
    9.             edgePosition += translation;
    10.  
    11.             //apply translation
    12.             verticesArray[edge.a].position += translation;
    13.             verticesArray[edge.b].position += translation;
    14.         }
    15.         mesh.SetVertices(verticesArray);
    16.  
    17.         mesh.ToMesh();
    18.         mesh.Refresh();
    19.     }
     

    Attached Files:

  8. Thimo_

    Thimo_

    Joined:
    Aug 26, 2019
    Posts:
    59
    Dear @kaarrrllll ,

    Could it be that my cube is misformed at runtime because I dont use the matrix translation like the code for moving the edge loop in the scene view?

    Thanks in advance!
     
  9. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
    What you have looks generally correct to me. I'm not sure I understand what your problem is, but I added some comments that you may find helpful.

    Code (CSharp):
    1. private void SetEdgeLoopPosition(Vector3 translation, Edge[] edges)
    2. {
    3.     var mesh = objectSelection.mesh;
    4.     var verticesArray = mesh.GetVertices();
    5.  
    6.     foreach (var edge in edges)
    7.     {
    8.         // apply translation in model space
    9.         // if translation is in world space, convert it with mesh.transform.InverseTransformDirection(translation)
    10.         verticesArray[edge.a].position += translation;
    11.         verticesArray[edge.b].position += translation;
    12.     }
    13.  
    14.     mesh.SetVertices(verticesArray);
    15.     mesh.ToMesh();
    16.     mesh.Refresh();
    17.  
    18.     // in the editor, let ProBuilder know that the mesh has been modified so that it can rebuild gizmos
    19. #if UNITY_EDITOR
    20.     ProBuilderEditor.Update();
    21. #endif
    22. }
    23.  
     
  10. Thimo_

    Thimo_

    Joined:
    Aug 26, 2019
    Posts:
    59
    Dear @kaarrrllll ,

    I found out that I had to use a list of coincedent vertices instead of the list of vertices from the edge loop. That fixed my problem and it now works perfect.

    Thank you for your help!
     
    kaarrrllll likes this.