How to edit CustomGeometry vertices using UrhoSharp.Forms?

BenColemanBenColeman USMember ✭✭

I have an application where I create many lines (just two vertices) using CustomGeometry. I need to be able to edit the world position of those vertices. I'm not sure how to go about this. I have done something like:

var component = node.GetComponent<CustomGeometry>();
var vertex = component.GetVertex(0, 0);

In this case, vertex is a pointer. I have seen in the docs that these vertices can be edited, but I don't see how, nor have I seen any examples. Or, is there another approach I should be taking?

Answers

  • utekaiutekai USMember ✭✭✭
    edited November 2016

    I've struggled with that a bit and ended up deleting (disable and dispose) and then redrawing the geometry in order to move an existing geometry. It works fairly well and easy to implement. So for something simple it's a fall back. But likely not performant at large scale.

    In regards to GetVertex, here how to access in c# ...

    My component has 1 geometry and 4 vertices. So this code reads out the first vertex. Remember if you change a vertex, then be sure to commit after.

                unsafe
                {
                    var cgvPointer = someCustGeoCompWith4VerticesAnd1Geometry.GetVertex(0, 0);
                    var cgv = *(CustomGeometryVertex*)cgvPointer;
                    TextToSpeech(cgv.Position.ToString());
                }
    

    In order to be able to edit Vertices, use .GetVertex with .DefineGeometry rather than .BeginGeometry that only allows .DefineVertex call to set a vertext that is then only readable..


    Here's the dll import statement and implementation code from Component.cs:

        [DllImport (Consts.NativeImport, CallingConvention = CallingConvention.Cdecl)]
        internal static extern CustomGeometryVertex* CustomGeometry_GetVertex (IntPtr handle, uint geometryIndex, uint vertexNum);
    
        /// <summary>
        /// Return a vertex in a geometry for editing, or null if out of bounds. After the edits are finished, calling Commit() updates  the vertex buffer.
        /// </summary>
        public CustomGeometryVertex* GetVertex (uint geometryIndex, uint vertexNum)
        {
            Runtime.ValidateRefCounted (this);
            return CustomGeometry_GetVertex (handle, geometryIndex, vertexNum);
        }
    

    That function returns a pointer to this struct:

    [StructLayout (LayoutKind.Sequential)]
    public struct CustomGeometryVertex
    {
        public Vector3 Position;
        public Vector3 Normal;
        public uint Color;
        public Vector2 TexCoord;
        public Vector4 Tangent;
    }
    

    So code like this will bring back that pointer (and need to allow compilation of unsafe code) ... and here's the same answer as above.

    My component has 1 geometry and 4 vertices. So this code reads out the first vertex. Remember if you change a vertex, then be sure to commit after.

                unsafe
                {
                    var cgvPointer = someCustGeoCompWith4VerticesAnd1Geometry.GetVertex(0, 0);
                    var cgv = *(CustomGeometryVertex*)cgvPointer;
                    TextToSpeech(cgv.Position.ToString());
                }
    
  • BenColemanBenColeman USMember ✭✭
    edited November 2016

    @utekai, thanks for your response. I did what I think would work, but I'm getting strange behavior (actually, no behavior) when I implement it. Immediately before the block of code below I move the node tmpNode that one end of the line is connected to. I then go to update the position (with RunActionsAsync()) of one of the line's vertices to coincide with the position of tmpNode.

    unsafe
    {
        CustomGeometry geom = lineNode.GetComponent<CustomGeometry>();
        CustomGeometryVertex* cgvPtr = geom.GetVertex( 0, 0 );
        (*cgvPtr).Position = tmpNode.Position;
        geom.Commit();
    }
    

    When the above block of code is absent, the position of tmpNode changes. However, when it is present, neither the position of tmpNode nor the vertex positions of lineNode. No exceptions are thrown, and I even stepped through it in the debugger . . . it looks like the vertex positions are being changed appropriately. Not sure what's up. . .

  • BenColemanBenColeman USMember ✭✭

    @utekai UPDATE: I was moving tmpNode using the following (without await):

    tmpNode.RunActionsAsync( new MoveTo( 0.0f, newPosition ) );
    

    This was causing the unresponsive behavior described in my previous post. However, when I add await, the lines begin to move (slowly) to their correct positions. But in the middle of it all, a SystemAccessViolation is thrown, with the following relevant portion of the stack trace:

    at Urho.CustomGeometry.CustomGeometry_Commit(IntPtr handle)
    at Urho.CustomGeometry.Commit()
    
  • utekaiutekai USMember ✭✭✭
    edited November 2016

    I experienced issues getting vertices to move using similar coding. Thus I started deleting and creating new customgeometry component any time a move was needed. As far as scale, I've done it with hundreds/maybe thousands of CustomGeometry components, moving ALL of them at the same time, and it works well. I do worry that scaling up to tens/hundreds of thousands may not work well, but maybe it will.

    It's likely some handoff issue between the c# wrapper and the c++ base code. But don't know for sure only guessing at this point.

    Something I've not tried yet is to add new geometries to the existing component and trying to delete the current geometry. Nor have I tried just BeginGeometry on the same component, ended up just drawing a new one altogether.

  • BenColemanBenColeman USMember ✭✭

    Well, I'll try the deleting/creating routine and see if that works. I do have concerns about scale as the number of components to be deleted and created could get into the tens of thousands.

  • BenColemanBenColeman USMember ✭✭

    As a side note, I've been getting frequent SystemAccessViolation exceptions whenver I try to Enable, Disable, or move nodes.

  • utekaiutekai USMember ✭✭✭

    Just wanted to add, easily able to move a node, but not sure putting one component per node would be a good coding model to follow.

  • BenColemanBenColeman USMember ✭✭

    Can you add multiple components to a node and set their world position independently?

  • utekaiutekai USMember ✭✭✭

    I'm working on hololens, so what we experience is likely a bit different due to different bindings, but in theory should be close.

    I don't disable/enable nodes, rather the specific CustomGeometry component inside the node, in fact all the components. I disable(or perhaps .Remove is better, but I used .Enabled = false, then .Dispose()). Then just add a new component to the node.

    To get rid of a node, I use code like this:

               var temp = sgNode;
                foreach (var comp in temp.Components)
                { //might use .Remove() instead of both these, but haven't tried it yet
                    comp.Enabled = false;
                    comp.Dispose();
                }
                temp.Dispose();
    

    Not sure what you mean by the last question.

  • BenColemanBenColeman USMember ✭✭

    RE: the last question on my previous post. In my scene there are nodes with StaticModel components, nodes with Text3D components, and nodes with CustomGeometry components. Because I'm creating the vertices on the CustomGeometry components, I can specify exactly where they go in world space. It seems I can specify the location of the StaticModel components using .SetGeometryCenter(), but I'm at a loss as to how to specify the coordinates of the Text3D components without having one node for each component.

  • utekaiutekai USMember ✭✭✭
    edited November 2016

    Just checked some older code I did and sure enough have the Text3D components inside their own node to be able to move around easily.

    Maybe there's another way ... don't know.

    Would love to see .Translate() and .Rotate() and similar functions on components. But perhaps nodes are a cheap and efficient wrapper to bring it already.

    Will know more fairly soon, will soon be at a point where I can scale easily to millions (if this technology will support) of components. I'll be very interested in performance then.

    There is a sample in core features called 'HugeObjectCount' that looks to produce on the order of 250 X 250 nodes. It isn't very performant on UWP, rather doesnt work well on a rather powerful desktop machine. The WPF and WinForms versions work fairly well but FPS drops quite a bit at times.

  • BenColemanBenColeman USMember ✭✭

    Also, for the StaticModel components, for their model I'm using CoreAssets.Models.Sphere, and when I try to position them using .SetGeometryCenter(), they don't move. And I cannot find a way to scale the components.

  • utekaiutekai USMember ✭✭✭

    I think setgeometrycenter appoints to that geometry the specific point that represents the center of the object. It's not related to moving the object.

    For scale, I scale the node, using node.ScaleNode(1.5f) to go 50% bigger, or node.ScaleNode(.6666667f) to go 33% smaller.

    Or apply a scale to the points used in defining the vertices of a custom geometry (so I scale it then create it).

  • BenColemanBenColeman USMember ✭✭

    Right, I'm not having any problem scaling the nodes. But I didn't see a way to scale the StaticModel components individually if they're all components of the same node.

    I've tried updating the line vertices of the CustomGeometry using the method we discussed earlier, like below:

    CustomGeometryVertex* cgvPtr = tmpLineGeom.GetVertex( 0, 0 );
    (*cgvPtr).Position = tmpSrcNode.Position;
    tmpLineGeom.Commit();
    

    . . .but as I said, it results in the following:

    System.AccessViolationException was unhandled
    Message: An unhandled exception of type 'System.AccessViolationException' occurred in Urho.Forms.dll
    Additional information: Attempted to read or write protected memory. This is often an indication that other memory is     corrupt.
    

    Also, when I try to remove the old component and replace it with a new component with:

    tmpLineGeom.Enabled = false;
    tmpLineGeom.Dispose();
    
    CustomGeometry lineGeom = lineNode.CreateComponent<CustomGeometry>( CreateMode.Local );
    

    . . .then go on to use .DefineVetex(), the same System.AccessViolationException occurs. So I haven't yet successfully been able to edit the geometry or delete and replace the component. Thanks for your help on this @utekai. I wonder if @EgorBo has any insight on this subject.

  • BenColemanBenColeman USMember ✭✭

    FYI there are 2683 of these CustomGeometry components I'm trying to update in a loop.

  • utekaiutekai USMember ✭✭✭

    I don't get access violations as you report. Not sure I can help out with that. But I'm not using the forms dll either.

    When I assign to the pointer's dereferenced field, it modifies it just fine, but doesn't then modify the underlying object's actual values.

    If for instance I run:

    (*cgvPtr).Position = tmpSrcNode.Position;

    It will work, but the component is not changed. And if I call up the pointer anew and read it's position, it's the same as it originally was, so it ignored the change. So for me, no access violation, but it's not saving the value either.

  • utekaiutekai USMember ✭✭✭
    edited November 2016

    For a load test, created 1000 of the pyramid shown, each pyramid is comprised of 20 wireframed tetrahedrons, and each tetrahedron is 4 vertices and 6 edges. The 4 legged contraption is 1000 of those pyramids very close (.01f apart) together but distributed in four directions. Scaled it down a bit then started rotation of the node.

    So it would be 1000 X 20 X 4 vertices, and 1000 X 20 X 6 edges, and rotation too.

    Over all it slowed down performance on a hololens to something less than 30-fps, but didn't measure just observed.

    The 1000 were created on the main thread and it caused about a 30 second hang until they painted. Once painted and toational it picked up performance a bit. Could still continue creating new objects at this point, just slower performance. Next will do it in a background thread.

    http://screencast.com/t/oA7Lj55A

  • utekaiutekai USMember ✭✭✭
    edited November 2016

    I reworked this sample to run on hololens, and now get the Memory Access violation, but this when I attempt to use just a single node.

    https://github.com/xamarin/urho-samples/tree/master/FeatureSamples/Core/34_DynamicGeometry

    See http://screencast.com/t/UGsV8iZYQN

    In that pic I've slightly modified the original sample code and pass in a single node that I use throughout.

    At the .Clone(), the access exception occurs.

    However, if I create new nodes for each pass, then all works.

    So wondering if this gives a clue to your memory AVException. Trying using new nodes.

  • utekaiutekai USMember ✭✭✭

    So have been able to use the Box.mdl from that same sample, and edit the vertices similarly to what is shown in the Animation() routine of that sample code.

    But have not be able to edit vertices of a CustomGeometry object, nor have I been able to create a from scratch model (as shown in that sample) to attempt to edit it's vertices. The from scratch model sample code never draws and throws no errors.

  • utekaiutekai USMember ✭✭✭

    So have been able to use the Box.mdl from that same sample, and edit the vertices similarly to what is shown in the Animation() routine of that sample code.

    But have not be able to edit vertices of a CustomGeometry object, nor have I been able to create a from scratch model (as shown in that sample) to attempt to edit it's vertices. The from scratch model sample code never draws and throws no errors.

  • BenColemanBenColeman USMember ✭✭

    Hmmm. When I try to run the DynamicGeometry.cs example without modification, the System.AccessViolationException occurs at the same Model cloneModel = originalModel.Clone(); line as your reworked example. I suppose I could use Box.mdl or Cylinder.mdl and try to edit their vertices accordingly to make them look like lines, although that seems kind of expensive. I tried creating my own .mdl file to use, but the cache.GetModel(...) was returning null.

  • utekaiutekai USMember ✭✭✭

    Continuing to work with trying to be able to edit vertices on a from scratch model (as shown in the dynamic geometries sample), and find when the .Clone() is called on the from scratch model, the IndexBuffer and VertexBuffer are NOT cloned.

    When .Clone() is called on an imported model, the buffers are cloned.

    VertexBuffer is read only so can't be updated, though IndexBuffer can be set. .

    Thus, that particular sample WILL NOT edit vertices of the from scratch model as the fromScratchModel is only cloned for display.

    HOWEVER, the original UNCLONED fromScratchModel, if it's vertex buffers are passed to the animatingBuffers object, will successfully have it's vertices edit ed.

    So, in summary, the DynamicGeometries sample is a bit flawed in that the .Clone() won't work successfully on a from scratch model. But instead of cloning, new models can be added instead of cloned.

    Or just pass in a single model instead of trying to create 9 of them, as in the sample.

    I deleted the last for loop on y, and just added this statement
    animatingBuffers.Add(fromScratchModel.GetGeometry(0, 0).GetVertexBuffer(0);

    And it works fine. Vertices can be edited as shown in the AnimateObjects routine which edits the vertices.

  • utekaiutekai USMember ✭✭✭
    edited November 2016

    I had trouble with the .Clone throwing memory access violations, but then passed in a unique name for each, and that fixed it.

    But as per my last, .Clone routine is not deep enough on the fromScratchModel, so that sample code will not work right.

    So I dumped that loop in a loop that was doing the cloning entirely, and just passed a single vertex buffer to the animating routine from the uncloned model's geometry.

    This shows the majority of the implementation http://screencast.com/t/JixaE3nqM

    So the animatingBuffers array can hold however many vertex buffers you desire, then each one can be edited to move that geometry.

Sign In or Register to comment.