Search code examples
c#wpfhelix-3d-toolkit

Obj files import and cursor position in HelixToolkit.SharpDX


I am new in HelixToolkit.SharpDX and I have 2 questions, maybe anyone can help me:

First: I want to import obj model (with textures) and display it in Viewport3DX. How to do it correctly? Now I have next:

ObjReader Reader = new HelixToolkit.Wpf.SharpDX.ObjReader();
List<Object3D> objs = Reader.Read(ModelPath);

After reading objs variable contains near 1000 objects. What shall be the next steps to to display model in viewport?

Second: And one more question: How to receive cursor position in Viewport3DX. Is there some property like CursorPosition in HelixViewport3D?

Thank you in advance!


Solution

  • First

    As you have your List<Object3D> objs you could create a Element3DCollection and bind to it within your xaml code.

    XAML Code (put this snippet into your Viewport3DX)

    Create a GroupModel3D and add bindings its properties

    <hx:GroupModel3D 
        x:Name="Viewport3D"
        ItemsSource="{Binding YourElement3DCollection}"   
        Transform="{Binding YourTransformToMousePosition}"/>
    

    Somewhere in your ViewModel

    Fill your Element3DCollection with Object3Ds

    ObjReader Reader = new HelixToolkit.Wpf.SharpDX.ObjReader();
    List<Object3D> objs = Reader.Read(ModelPath);
    
    var ele3DCollection = new Element3DCollection();
    foreach (var ob in objs)
    {
        var meshGeometry = new MeshGeometryModel3D
        {
            Geometry = ob.Geometry,
            Material = ob.Material,
        };
        ele3DCollection.Add(meshGeometry);
    
        // Run this line if you are using a render host
        meshGeometry.Attach(Viewport3D.RenderHost);
    }
    
    // Now assign the ele3DCollection to the property you bound to and raise property changed
    YourElement3DCollection = ele3DCollection;
    

    where YourElement3DCollection is of type Element3DCollection. Don't forget to raise INotifyPropertyChanged.

    Alternatively you could bind to a DependencyProperty of your code behind. Then just call InvalidateProperty(YourElement3DCollectionProperty) after assigning it.


    Second

    You could perform a raycast from your mouse position to a object in the scene (maybe an XY-Plane intersecting the origin). Then use the coordinates of this point and create your Transform3D object.

    Untested code (code behind):

    var yourRay = Viewport3D.UnProjectToRay(Mouse.GetPosition(Viewport3D));
    
    var yourTargetPoint = yourRay.PlaneIntersection(new Point3D(0, 0, 0), new Vector3D(0, 0, 1));
    
    // todo: check for null
    var yourTranslation = new TranslateTransform3D(
        yourTargetPoint.Value.X, yourTargetPoint.Value.Y, yourTargetPoint.Value.Z);
    
    // assign the relation to your viewModel somehow
    ((YourViewModelType)DataContext).YourTransformToMousePosition = yourTranslation;
    

    where YourTransformToMousePosition is of type Transform3D