Beispiel #1
0
        public void ShowModel(Model3D model3D, bool updateCamera)
        {
            try
            {
                ContentVisual.SetCurrentValue(ModelVisual3D.ContentProperty, model3D);

                // NOTE:
                // We could show both solid model and wireframe in WireframeVisual3D (ContentWireframeVisual) with using WireframeWithOriginalSolidModel for WireframeType.
                // But in this sample we show solid frame is separate ModelVisual3D and therefore we show only wireframe in WireframeVisual3D.
                ContentWireframeVisual.BeginInit();
                ContentWireframeVisual.SetCurrentValue(Ab3d.Visuals.WireframeVisual3D.ShowPolygonLinesProperty, ReadPolygonIndicesCheckBox.IsChecked ?? false);
                ContentWireframeVisual.SetCurrentValue(Ab3d.Visuals.WireframeVisual3D.OriginalModelProperty, model3D);
                ContentWireframeVisual.EndInit();

                if (AddLineDepthBiasCheckBox.IsChecked ?? false)
                {
                    // To specify line depth bias to the Ab3d.PowerToys line Visual3D objects,
                    // we use SetDXAttribute extension method and use LineDepthBias as DXAttributeType
                    // NOTE: This can be used only before the Visual3D is created by DXEngine.
                    // If you want to change the line bias after the object has been rendered, use the SetDepthBias method (see OnAddLineDepthBiasCheckBoxCheckedChanged)
                    //
                    // See DXEngineVisuals/LineDepthBiasSample for more info.
                    ContentWireframeVisual.SetDXAttribute(DXAttributeType.LineDepthBias, model3D.Bounds.GetDiagonalLength() * 0.001);
                }

                // Calculate the center of the model and its size
                // This will be used to position the camera

                if (updateCamera)
                {
                    var bounds = model3D.Bounds;

                    var modelCenter = new Point3D(bounds.X + bounds.SizeX / 2,
                                                  bounds.Y + bounds.SizeY / 2,
                                                  bounds.Z + bounds.SizeZ / 2);

                    var modelSize = Math.Sqrt(bounds.SizeX * bounds.SizeX +
                                              bounds.SizeY * bounds.SizeY +
                                              bounds.SizeZ * bounds.SizeZ);

                    Camera1.TargetPosition = modelCenter;
                    Camera1.SetCurrentValue(Ab3d.Cameras.BaseTargetPositionCamera.DistanceProperty, modelSize * 2);
                }

                // If the read model already define some lights, then do not show the Camera's light
                if (ModelUtils.HasAnyLight(model3D))
                {
                    Camera1.SetCurrentValue(Ab3d.Cameras.BaseCamera.ShowCameraLightProperty, ShowCameraLightType.Never);
                }
                else
                {
                    Camera1.SetCurrentValue(Ab3d.Cameras.BaseCamera.ShowCameraLightProperty, ShowCameraLightType.Always);
                }

                ShowInfoButton.SetCurrentValue(IsEnabledProperty, true);
            }
            catch
            {
            }
        }
        private void ShowModel(Model3D model3D, bool updateCamera)
        {
            ContentVisual.Content = model3D;

            if (model3D == null)
            {
                return;
            }

            // NOTE:
            // We could show both solid model and wireframe in WireframeVisual3D (ContentWireframeVisual) with using WireframeWithOriginalSolidModel for WireframeType.
            // But in this sample we show solid frame is separate ModelVisual3D and therefore we show only wireframe in WireframeVisual3D.
            ContentWireframeVisual.BeginInit();
            ContentWireframeVisual.ShowPolygonLines = ReadPolygonIndicesCheckBox.IsChecked ?? false;
            ContentWireframeVisual.OriginalModel    = model3D;
            ContentWireframeVisual.EndInit();


            // Calculate the center of the model and its size
            // This will be used to position the camera

            if (updateCamera)
            {
                var bounds = model3D.Bounds;

                var modelCenter = new Point3D(bounds.X + bounds.SizeX / 2,
                                              bounds.Y + bounds.SizeY / 2,
                                              bounds.Z + bounds.SizeZ / 2);

                var modelSize = Math.Sqrt(bounds.SizeX * bounds.SizeX +
                                          bounds.SizeY * bounds.SizeY +
                                          bounds.SizeZ * bounds.SizeZ);


                Camera1.TargetPosition = modelCenter;
                Camera1.Distance       = modelSize * 2;
            }

            // If the read model already define some lights, then do not show the Camera's light
            if (ModelUtils.HasAnyLight(model3D))
            {
                Camera1.ShowCameraLight = ShowCameraLightType.Never;
            }
            else
            {
                Camera1.ShowCameraLight = ShowCameraLightType.Always;
            }

            ShowInfoButton.IsEnabled = true;
        }
Beispiel #3
0
        private void LoadObj(string fileName)
        {
            if (_isLoading)
            {
                return;
            }

            bool isNewFile = (_fileName != fileName);

            _fileName   = fileName;
            _wpf3DModel = null;


            // Set ReadPolygonIndices in UI thread
            // When true ReaderObj will read PolygonIndices collection that can be used to show polygons instead of triangles
            _readerObj.ReadPolygonIndices = ReadPolygonIndicesCheckBox.IsChecked ?? false;

            // To read polygon indices from the read models,
            // iterating through GeometryModel3D objects (children of Model3DGroup) and
            // then converting its Geometry object into MeshGeometry3D.
            // The MeshGeometry3D defines the Positions, TriangleIndices, Normals and TextureCoordinates collections.
            //
            // On top of that the Ab3d.PowerToys and ReaderObj can also add the polygon indices collection.
            // It is set to MeshGeometry3D as a PolygonIndices dependency property (defined in Ab3d.Utilities.MeshUtils).
            // You can read the PolygonIndices directly with the following:
            //
            // var polygonIndices = meshGeometry3D.GetValue(Ab3d.Utilities.MeshUtils.PolygonIndicesProperty) as Int32Collection;
            //
            // You can also use the GetPolygonIndices, SetPolygonIndices and GetPolygonPositions extension methods on MeshGeometry3D,
            // or use GetPolygonPositions from MeshUtils.
            //
            // See also the following to get know how the polygon positions are organized:
            // https://www.ab4d.com/help/PowerToys/html/F_Ab3d_Utilities_MeshUtils_PolygonIndicesProperty.htm



            // UH: The following code is much much easier with async and await from .net 4.5
            // But here we want to use only .net 4.0

            // Read obj file and convert to wpf 3d objects in background thread
            var readObjFileTask = new Task(() =>
            {
                _lastException = null;

                try
                {
                    string texturesPath = Path.GetDirectoryName(_fileName);

                    // Read obj file from _fileName
                    // We read the object names into objectNames dictionary (Dictionary<string, Model3D>)
                    // This allows us to quickly get objects from their name.
                    // ReaderObj also set name to all objects and materials with using SetName extension method
                    // This way you can get object name or material name with GetName method.
                    // For example:
                    // _wpf3DModel.GetName();

                    var defaultMaterial = new DiffuseMaterial(Brushes.Silver);

                    _wpf3DModel = _readerObj.ReadModel3D(_fileName, texturesPath, defaultMaterial);

                    if (_wpf3DModel != null)
                    {
                        // We need to freeze the model because it was created on another thread.
                        // After the model is forzen, it cannot be changed any more.
                        // if you want to change the model, than Convert method must be called on UI thread
                        // or you must clone the read object in the UI thread
                        _wpf3DModel.Freeze();
                    }

                    // NOTE:
                    // If we wanted more control over reading obj files, we could read them in two steps
                    // 1) Read obj file into ObjFileData object
                    // 2) Convert read ObjFileData object into WPF Model3D
                    // The following code does that (uncomment it to see it in action):

                    //var objFileData = _readerObj.ReadFile(_fileName);
                    ////var objFileData = _readerObj.ReadStream(fileStream);

                    //var objMeshToWpfModel3DConverter = new ObjFileToWpfModel3DConverter();
                    //objMeshToWpfModel3DConverter.InvertYTextureCoordinate = false;
                    //objMeshToWpfModel3DConverter.TexturesDirectory = Path.GetDirectoryName(_fileName);

                    //// DefaultMaterial is a Material that is used when no other material is specified.
                    //// Actually with leaving DefaultMaterial as null, the same Silver material would be used (setting it here only to show the user what properties exist)
                    //objMeshToWpfModel3DConverter.DefaultMaterial = new DiffuseMaterial(Brushes.Silver);

                    //// ReuseMaterials specified if one material instance defined in obj file can be reused for all Model3D objects that use that material.
                    //// If false than a new material instance will be created for each usage
                    //// This is useful when user wants to change material on individual objects without applying the change to all other objects that use that material.
                    //// Default value is true.
                    //objMeshToWpfModel3DConverter.ReuseMaterials = true;

                    //_wpf3DModel = _objMeshToWpfModel3DConverter.Convert(objFileData);
                }
                catch (Exception ex)
                {
                    _lastException = ex;
                }
            });

            // After reading the obj file and converting it to WPF 3D objects we need to show the objects or errors - this needs to be done on UI thread
            var showObjectTask = readObjFileTask.ContinueWith(_ =>
            {
                try
                {
                    if (_lastException != null)
                    {
                        ResultTextBlock.Text = "ERROR reading obj file:\r\n" + _lastException.Message;
                    }
                    else if (_wpf3DModel != null)
                    {
                        string objectsDescriptions = Ab3d.Utilities.Dumper.GetObjectHierarchyString(_wpf3DModel);

                        if (_readerObj.Errors != null && _readerObj.Errors.Count > 0)
                        {
                            var sb = new StringBuilder();

                            sb.AppendLine("Obj file errors:");
                            foreach (var error in _readerObj.Errors)
                            {
                                sb.AppendLine(error);
                            }

                            ResultTextBlock.Text = objectsDescriptions + Environment.NewLine + Environment.NewLine + sb.ToString();
                        }
                        else
                        {
                            ResultTextBlock.Text = objectsDescriptions;
                        }

                        //ResultTextBlock.Text = Ab3d.Utilities.Dumper.GetMeshInitializationCode(model);
                        //ResultTextBlock.Text += "\r\n\n" + Ab3d.Utilities.Dumper.Dump(model);

                        ContentVisual.Content = _wpf3DModel;

                        // NOTE:
                        // We could show both solid model and wireframe in WireframeVisual3D (ContentWireframeVisual) with using WireframeWithOriginalSolidModel for WireframeType.
                        // But in this sample we show solid frame is separate ModelVisual3D and therefore we show only wireframe in WireframeVisual3D.
                        ContentWireframeVisual.BeginInit();
                        ContentWireframeVisual.ShowPolygonLines = ReadPolygonIndicesCheckBox.IsChecked ?? false;
                        ContentWireframeVisual.OriginalModel    = _wpf3DModel;
                        ContentWireframeVisual.EndInit();



                        // Calculate the center of the model and its size
                        // This will be used to position the camera

                        if (isNewFile) // If we just reloaded the previous file, we preserve the current camera TargetPosition and Distance
                        {
                            var bounds = _wpf3DModel.Bounds;

                            var modelCenter = new Point3D(bounds.X + bounds.SizeX / 2,
                                                          bounds.Y + bounds.SizeY / 2,
                                                          bounds.Z + bounds.SizeZ / 2);

                            var modelSize = Math.Sqrt(bounds.SizeX * bounds.SizeX +
                                                      bounds.SizeY * bounds.SizeY +
                                                      bounds.SizeZ * bounds.SizeZ);


                            Camera1.TargetPosition = modelCenter;
                            Camera1.Distance       = modelSize * 1.5;
                        }

                        // If the read model already define some lights, then do not show the Camera's light
                        if (ModelUtils.HasAnyLight(_wpf3DModel))
                        {
                            Camera1.ShowCameraLight = ShowCameraLightType.Never;
                        }
                        else
                        {
                            Camera1.ShowCameraLight = ShowCameraLightType.Always;
                        }
                    }

                    _isLoading = false;
                }
                finally
                {
                    Mouse.OverrideCursor = null;
                }
            },
                                                              TaskScheduler.FromCurrentSynchronizationContext()); // Run on UI thread


            _isLoading           = true;
            Mouse.OverrideCursor = Cursors.Wait;

            // Start tasks
            readObjFileTask.Start();
        }