public ObjectIdRendering()
        {
            InitializeComponent();

            var boxMesh      = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, 0, 0), new Size3D(1, 1, 1), 1, 1, 1).Geometry;
            int modelsXCount = 20;
            int modelsYCount = 1;
            int modelsZCount = 20;

            var model3DGroup = CreateModel3DGroup(boxMesh, new Point3D(0, 5, 0), new Size3D(500, modelsYCount * 10, 500), 10, modelsXCount, modelsYCount, modelsZCount);

            MainViewport.Children.Add(model3DGroup.CreateModelVisual3D());


            _disposables = new DisposeList();

            MainDXViewportView.DXSceneDeviceCreated += MainDxViewportViewOnDxSceneDeviceCreated;

            this.Unloaded += delegate(object sender, RoutedEventArgs args)
            {
                if (_disposables != null)
                {
                    _disposables.Dispose();
                    _disposables = null;
                }

                MainDXViewportView.Dispose();
            };
        }
Exemplo n.º 2
0
        private void CreateTestScene()
        {
            var boxMesh    = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, 0, 0), new Size3D(1, 1, 1), 1, 1, 1).Geometry;
            var sphereMesh = new Ab3d.Meshes.SphereMesh3D(new Point3D(0, 0, 0), 0.7, 30).Geometry;

            int modelsXCount = 10;
            int modelsYCount = 1;
            int modelsZCount = 10;

            _objectsModel3DGroup = new Model3DGroup();

            AddModels(_objectsModel3DGroup, boxMesh, new Point3D(0, 5, 0), new Size3D(500, modelsYCount * 10, 500), 10, modelsXCount, modelsYCount, modelsZCount);
            AddModels(_objectsModel3DGroup, sphereMesh, new Point3D(25, 5, 25), new Size3D(500, modelsYCount * 10, 500), 10, modelsXCount, modelsYCount, modelsZCount);

            MainViewport.Children.Add(_objectsModel3DGroup.CreateContentVisual3D());

            // It would be optimal to use WireGridVisual3D to create a wire grid.
            // But because WireGridVisual3D creates a MultiLineVisual3D behind the scene, all the lines can have only a single color.
            // Therefore we create multiple lines for this sample so we can easily change color of individual lines.
            // And what is more, this way the object id map can get us the hit 3D lines (otherwise the whole MultiLineVisual3D would be hit)
            // <visuals:WireGridVisual3D CenterPosition="0 0 0" Size="500 500" WidthCellsCount="20" HeightCellsCount="20" LineColor="#555555" LineThickness="5"/>

            var contentVisual3D = CreateWireGridLines(new Point3D(0, 0, 0), new Size(500, 500), 20, 20, new Vector3D(1, 0, 0), new Vector3D(0, 0, 1), Colors.Gray, 5);

            MainViewport.Children.Add(contentVisual3D);
        }
            private Model3DGroup Create3DScene(Point3D center, int xCount, int yCount, int zCount, float modelSize)
            {
                var semiTransparentBrush = new SolidColorBrush(Color.FromArgb(64, 200, 200, 200)); // alpha = 1/4
                var diffuseMaterial      = new DiffuseMaterial(semiTransparentBrush);

                diffuseMaterial.Freeze(); // This will significantly speed up the creation of objects

                var modelSizeWithMargin = modelSize * 1.2;
                var size          = new Size3D(xCount * modelSizeWithMargin, yCount * modelSizeWithMargin, zCount * modelSizeWithMargin);
                var instancedData = InstancedMeshGeometry3DTest.CreateInstancesData(center, size, modelSize, xCount, yCount, zCount, false);

                var model3DGroup = new Model3DGroup();
                var boxMesh3D    = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, 0, 0), new Size3D(1, 1, 1), 1, 1, 1).Geometry;

                for (int i = 0; i < instancedData.Length; i++)
                {
                    var geometryModel3D = new GeometryModel3D(boxMesh3D, diffuseMaterial);
                    geometryModel3D.BackMaterial = diffuseMaterial;
                    geometryModel3D.Transform    = new MatrixTransform3D(instancedData[i].World.ToWpfMatrix3D());

                    model3DGroup.Children.Add(geometryModel3D);
                }

                var modelVisual3D = new ModelVisual3D();

                modelVisual3D.Content = model3DGroup;

                MainViewport3D.Children.Add(modelVisual3D);

                return(model3DGroup);
            }
        private void AddTestModel()
        {
            var boxMesh3D = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, 0, 0), new Size3D(1, 1, 1), 1, 1, 1).Geometry;

            int positionsCount = boxMesh3D.Positions.Count;
            var bounds         = boxMesh3D.Bounds;

            // Create positionColorsArray that will define colors for each position
            var positionColorsArray = new Color4[positionsCount];

            for (int i = 0; i < positionsCount; i++)
            {
                var position = boxMesh3D.Positions[i];

                // Get colors based on the relative position inside the Bounds - in range from (0, 0, 0) to (1, 1, 1)
                float red   = (float)((position.X - bounds.X) / bounds.SizeX);
                float green = (float)((position.Y - bounds.Y) / bounds.SizeY);
                float blue  = (float)((position.Z - bounds.Z) / bounds.SizeZ);

                // Set Color this position
                positionColorsArray[i] = new Color4(red, green, blue, alpha: 1.0f);
            }


            // Now create the VertexColorMaterial that will be used instead of standard material
            // and will make the model render with special effect where each vertex can have its own color.
            _vertexColorMaterial = new VertexColorMaterial()
            {
                PositionColors = positionColorsArray, // The PositionColors property is used to specify colors for each vertex

                // To show specular effect set the specular data here:
                //SpecularPower = 16,
                //SpecularColor = Color3.White,
                //HasSpecularColor = true

                // If we would update the positionColorsArray very often, then set CreateDynamicBuffer to true
                //CreateDynamicBuffer = true,
            };


            // Create standard WPF material and set the _vertexColorMaterial to be used when the model is rendered in DXEngine.
            var vertexColorDiffuseMaterial = new DiffuseMaterial();

            vertexColorDiffuseMaterial.SetUsedDXMaterial(_vertexColorMaterial);


            // Create a GeometryModel3D that will be rendered with _vertexColorMaterial
            var vertexColorGeometryModel3D = new GeometryModel3D(boxMesh3D, vertexColorDiffuseMaterial);

            vertexColorGeometryModel3D.Transform = new ScaleTransform3D(100, 50, 80); // Scale the box

            var vertexColorModelVisual3D = new ModelVisual3D()
            {
                Content = vertexColorGeometryModel3D
            };

            MainViewport.Children.Add(vertexColorModelVisual3D);
        }
Exemplo n.º 5
0
        private void CreateInstancedObjects()
        {
            MainViewport.Children.Clear();


            _currentMeshType = (MeshTypes)Enum.Parse(typeof(MeshTypes), (string)ObjectsTypeComboBox.SelectedItem);
            _screenSize      = (float)ScreenSizeComboBox.SelectedItem;

            MeshGeometry3D mesh;

            switch (_currentMeshType)
            {
            case MeshTypes.Box:
                mesh = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, 0, 0), new Size3D(1, 1, 1), 1, 1, 1).Geometry;
                break;

            case MeshTypes.Sphere:
                mesh = new Ab3d.Meshes.SphereMesh3D(new Point3D(0, 0, 0), 0.5, 30).Geometry;
                break;

            case MeshTypes.Arrow:
                mesh = new Ab3d.Meshes.ArrowMesh3D(new Point3D(-0.5, 0, 0), new Point3D(0.5, 0, 0), 0.1, 0.2, 45, 30, false).Geometry;
                break;

            default:
                mesh = null;
                break;
            }

            var instancedData = GetInstancedData(_currentMeshType, _screenSize);


            _instancedMeshGeometryVisual3D = new InstancedMeshGeometryVisual3D(mesh);
            _instancedMeshGeometryVisual3D.InstancesData = instancedData;

            // To enable screen-space scaling, set the UseScreenSpaceScaling to true.
            //
            // IMPORTANT:
            // For this to work correctly, the size of the instance mesh must be 1 and the center of the mesh must be at (0, 0, 0).
            // In this case the mesh will be scaled correctly to the screen size that is defined in the instance matrix's scale component.
            _instancedMeshGeometryVisual3D.UseScreenSpaceScaling = UseScreenSpaceScaleCheckBox.IsChecked ?? false;

            MainViewport.Children.Add(_instancedMeshGeometryVisual3D);

            _instanceWorldPositions = null; // Reset array of instance positions that is used for finding the closest instance in screen coordinates
            _selectedInstanceIndex  = -1;

            // Because we have cleared all MainViewport.Children, this also removed the camera's light.
            // Call Refresh to recreate the light
            Camera1.Refresh();
        }
Exemplo n.º 6
0
        private void CreateTestScene()
        {
            var rootModel3DGroup = new Model3DGroup();

            var greenMaterial = new DiffuseMaterial(Brushes.Green);
            var redMaterial   = new DiffuseMaterial(Brushes.Red);

            var boxMesh3D = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, 0, 0), new Size3D(1, 1, 1), 1, 1, 1).Geometry;

            // Create 7 x 7 boxes with different height
            for (int y = -3; y <= 3; y++)
            {
                for (int x = -3; x <= 3; x++)
                {
                    // Height is based on the distance from the center
                    double height = (5 - Math.Sqrt(x * x + y * y)) * 60;

                    // Instead of creating MeshGeometry3D for each box, we reuse the standard box mesh
                    //var boxGeometryModel3D = Ab3d.Models.Model3DFactory.CreateBox(centerPosition: new Point3D(x * 100, height / 2, y * 100),
                    //                                                              size: new Size3D(80, height, 80),
                    //                                                              material: height > 200 ? redMaterial : greenMaterial);

                    // Create the 3D Box
                    var boxGeometryModel3D = new GeometryModel3D(boxMesh3D, material: height > 200 ? redMaterial : greenMaterial);

                    // Scale: 80, height, 80
                    // Translate: x * 100, height / 2, y * 100
                    boxGeometryModel3D.Transform = new MatrixTransform3D(new Matrix3D(80, 0, 0, 0,
                                                                                      0, height, 0, 0,
                                                                                      0, 0, 80, 0,
                                                                                      x * 100, height / 2, y * 100, 1));

                    // To preserve the object names we can fill the names into the _namedObjects dictionary
                    boxGeometryModel3D.SetName(string.Format("Box_{0}_{1}", x + 4, y + 4));

                    rootModel3DGroup.Children.Add(boxGeometryModel3D);
                }
            }

            ContentModelVisual3D.Content = rootModel3DGroup;
            _rootModel3D = rootModel3DGroup;
        }
Exemplo n.º 7
0
        private void CreateRootModel()
        {
            switch (ObjectComboBox.SelectedIndex)
            {
            case 0:
                Ab3d.Meshes.BoxMesh3D box = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, 0, 0), new Size3D(130, 60, 100), 1, 1, 1);
                _rootMesh = box.Geometry;
                break;

            case 1:
                Ab3d.Meshes.BoxMesh3D box2 = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, 0, 0), new Size3D(130, 60, 100), 4, 4, 4);
                _rootMesh = box2.Geometry;
                break;

            case 2:
                Ab3d.Meshes.SphereMesh3D sphere = new Ab3d.Meshes.SphereMesh3D(new Point3D(0, 0, 0), 80, 10);
                _rootMesh = sphere.Geometry;
                break;

            case 3:
                Ab3d.Meshes.SphereMesh3D sphere2 = new Ab3d.Meshes.SphereMesh3D(new Point3D(0, 0, 0), 80, 5);
                _rootMesh = sphere2.Geometry;
                break;

            case 4:
                Ab3d.Meshes.CylinderMesh3D cylinder = new Ab3d.Meshes.CylinderMesh3D(new Point3D(0, -50, 0), 60, 100, 12, true);
                _rootMesh = cylinder.Geometry;
                break;

            case 5:
                Ab3d.Meshes.ConeMesh3D cone = new Ab3d.Meshes.ConeMesh3D(new Point3D(0, -50, 0), 30, 60, 100, 12, true);
                _rootMesh = cone.Geometry;
                break;

            case 6:
                Ab3d.Meshes.ConeMesh3D cone2 = new Ab3d.Meshes.ConeMesh3D(new Point3D(0, -50, 0), 30, 60, 100, 6, false);
                _rootMesh = cone2.Geometry;
                break;

            case 7:
                var readerObj   = new Ab3d.ReaderObj();
                var teapotModel = readerObj.ReadModel3D(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Resources\ObjFiles\Teapot.obj")) as GeometryModel3D;

                if (teapotModel == null)
                {
                    return;
                }

                // Get the teapot MeshGeometry3D
                _rootMesh = (MeshGeometry3D)teapotModel.Geometry;

                break;

            default:
                _rootMesh = null;
                break;
            }


            var geometryModel3D = new GeometryModel3D(_rootMesh, new DiffuseMaterial(Brushes.Silver));

            MainViewport.Children.Clear();
            MainViewport.Children.Add(geometryModel3D.CreateModelVisual3D());

            MeshInspector.MeshGeometry3D = _rootMesh;
        }
        private void CreateScene()
        {
            var boxMeshGeometry3D = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, 0, 0), new Size3D(BoxSize, BoxSize, BoxSize), 1, 1, 1).Geometry;

            _oneMeshTriangleIndicesCount = boxMeshGeometry3D.TriangleIndices.Count;


            PositionNormalTexture[] vertexBuffer;
            int[] indexBuffer;

            CreateMultiMeshBuffer(center: new Vector3(0, 0, 0),
                                  size: new Vector3(XCount * (BoxSize + BoxesMargin), YCount * (BoxSize + BoxesMargin), ZCount * (BoxSize + BoxesMargin)),
                                  xCount: XCount, yCount: YCount, zCount: ZCount,
                                  meshGeometry3D: boxMeshGeometry3D,
                                  vertexBuffer: out vertexBuffer,
                                  indexBuffer: out indexBuffer);

            _multiMaterialMesh = new SimpleMesh <PositionNormalTexture>(vertexBuffer, indexBuffer,
                                                                        inputLayoutType: InputLayoutType.Position | InputLayoutType.Normal | InputLayoutType.TextureCoordinate);


            _indexBufferLength = indexBuffer.Length;

            // i1 is at 1/4 of the height of the box
            _firstColorIndex = (int)(_indexBufferLength / 4);

            // i2 is at 3/4 of the height
            _secondColorIndex = _firstColorIndex * 3;

            _multiMaterialMesh.SubMeshes = new SubMesh[]
            {
                new SubMesh("SubMesh1")
                {
                    MaterialIndex = 0, StartIndexLocation = 0, IndexCount = _firstColorIndex
                },
                new SubMesh("SubMesh2")
                {
                    MaterialIndex = 1, StartIndexLocation = _firstColorIndex, IndexCount = _secondColorIndex - _firstColorIndex
                },
                new SubMesh("SubMesh3")
                {
                    MaterialIndex = 2, StartIndexLocation = _secondColorIndex, IndexCount = _indexBufferLength - _secondColorIndex
                },
            };

            _disposables.Add(_multiMaterialMesh);


            var materials = new Ab3d.DirectX.Material[]
            {
                new Ab3d.DirectX.Materials.StandardMaterial()
                {
                    DiffuseColor = Colors.DimGray.ToColor3()
                },
                new Ab3d.DirectX.Materials.StandardMaterial()
                {
                    DiffuseColor = Colors.Silver.ToColor3()
                },
                new Ab3d.DirectX.Materials.StandardMaterial()
                {
                    DiffuseColor = Colors.Gold.ToColor3()
                },
            };

            _meshObjectNode = new Ab3d.DirectX.MeshObjectNode(_multiMaterialMesh, materials);

            _disposables.Add(_meshObjectNode);

            // Use SceneNodeVisual3D to show SceneNode in DXViewportView
            var sceneNodeVisual3D = new SceneNodeVisual3D(_meshObjectNode);

            MainViewport.Children.Add(sceneNodeVisual3D);
        }
        private void CreateRootModel()
        {
            bool show3DLine = false;

            switch (ObjectComboBox.SelectedIndex)
            {
            case 0:
                Ab3d.Meshes.SphereMesh3D sphere = new Ab3d.Meshes.SphereMesh3D(new Point3D(0, 0, 0), 80, 10);
                _rootMesh = sphere.Geometry;
                break;

            case 1:
                Ab3d.Meshes.SphereMesh3D sphere2 = new Ab3d.Meshes.SphereMesh3D(new Point3D(0, 0, 0), 80, 5);
                _rootMesh = sphere2.Geometry;
                break;

            case 2:
                // NOTE: Here we create an optimized version of sphere but it does not have texture coordinates
                // If we do not need texture coordinates (do not need to show texture), than we can slightly simplify the sphere model.
                // When we also need to create texture coordinates, the top most position that represent the same point in space is defined multiple times
                // - each time with slightly different texture coordinate (so that the whole top line on the texture is shown around the top sphere position).
                // Also there are x + 1 position around the sphere (in one row) - one additional position is added that the first and last position in the "row" are in the same space position,
                // but the first position has x texture coordinate 0, the last position has x texture coordinate 1 - this shows the whole texture nicely around the sphere.
                // If texture coordinates are not needed, than we do not need to define more than one upper and bottom positions,
                // and also do not need to add another position to the row.
                // Optimized sphere can be created only with SphereMesh3D object (not with SphereVisual3D)
                Ab3d.Meshes.SphereMesh3D sphere3 = new Ab3d.Meshes.SphereMesh3D(new Point3D(0, 0, 0), 80, 12, false);     // false: generateTextureCoordinates
                _rootMesh = sphere3.Geometry;
                break;

            case 3:
                Ab3d.Meshes.BoxMesh3D box = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, 0, 0), new Size3D(130, 60, 100), 1, 1, 1);
                _rootMesh = box.Geometry;
                break;

            case 4:
                Ab3d.Meshes.BoxMesh3D box2 = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, 0, 0), new Size3D(130, 60, 100), 4, 4, 4);
                _rootMesh = box2.Geometry;
                break;

            case 5:
                Ab3d.Meshes.CylinderMesh3D cylinder = new Ab3d.Meshes.CylinderMesh3D(new Point3D(0, -50, 0), 60, 100, 12, true);
                _rootMesh = cylinder.Geometry;
                break;

            case 6:
                Ab3d.Meshes.ConeMesh3D cone = new Ab3d.Meshes.ConeMesh3D(new Point3D(0, -50, 0), 30, 60, 100, 12, true);
                _rootMesh = cone.Geometry;
                break;

            case 7:
                Ab3d.Meshes.ConeMesh3D cone2 = new Ab3d.Meshes.ConeMesh3D(new Point3D(0, -50, 0), 30, 60, 100, 6, false);
                _rootMesh = cone2.Geometry;
                break;

            case 8:
                var readerObj   = new Ab3d.ReaderObj();
                var teapotModel = readerObj.ReadModel3D(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Resources\ObjFiles\Teapot.obj")) as GeometryModel3D;

                if (teapotModel == null)
                {
                    return;
                }

                // Get the teapot MeshGeometry3D
                _rootMesh = (MeshGeometry3D)teapotModel.Geometry;

                break;

            case 9:
                var line = new Ab3d.Visuals.LineVisual3D()
                {
                    StartPosition = new Point3D(0, 0, 0),
                    EndPosition   = new Point3D(100, 0, 0),
                    LineColor     = Colors.Silver,
                    LineThickness = 20
                };

                Show3DLines(line);
                show3DLine = true;
                break;

            case 10:
                var polyLineVisual3D = new Ab3d.Visuals.PolyLineVisual3D()
                {
                    Positions     = new Point3DCollection(new Point3D[] { new Point3D(-75, 50, 0), new Point3D(-25, 0, 0), new Point3D(25, 50, 0), new Point3D(75, 0, 0) }),
                    LineThickness = 20
                };

                Show3DLines(polyLineVisual3D);
                show3DLine = true;
                break;

            case 11:
                // This is the same line as in the previous sample (PolyLineVisual3D), but this time
                // it is created as diconnected list of lines - note that this requires that the positions are duplicated.
                var multiLineVisual3D = new Ab3d.Visuals.MultiLineVisual3D()
                {
                    Positions = new Point3DCollection(new Point3D[] { new Point3D(-75, 50, 0), new Point3D(-25, 0, 0),
                                                                      new Point3D(-25, 0, 0), new Point3D(25, 50, 0),
                                                                      new Point3D(25, 50, 0), new Point3D(75, 0, 0) }),
                    LineThickness = 20
                };

                Show3DLines(multiLineVisual3D);
                show3DLine = true;
                break;

            default:
                _rootMesh = null;
                break;
            }

            // If we were looking at 3D lines before and now we are looking an standard 3D models,
            // we adjust the camera back to the side view (from direct front view)
            if (_isShowing3DLines && !show3DLine)
            {
                Camera1.Heading  = 30;
                Camera1.Attitude = -20;
                Camera1.Distance = 300;
            }

            _isShowing3DLines = show3DLine;


            _rootModel          = new GeometryModel3D();
            _rootModel.Geometry = _rootMesh;
            _rootModel.Material = new DiffuseMaterial(Brushes.DarkBlue);

            ObjectModelVisual.Content = _rootModel;

            Ab3d.Utilities.ModelEventSource3D modelEventSource = new Ab3d.Utilities.ModelEventSource3D();
            modelEventSource.TargetModel3D = _rootModel;
            modelEventSource.MouseClick   += new Ab3d.Common.EventManager3D.MouseButton3DEventHandler(modelEventSource_MouseClick);

            _eventsManager.ResetEventSources3D();
            _eventsManager.RegisterEventSource3D(modelEventSource);

            MainViewport.Cursor = Cursors.Hand;
        }
        private void CreateBoxes(Model3DGroup rootGroup, Dictionary <object, string> objectNames)
        {
            GeometryModel3D geometryModel3D;
            DiffuseMaterial material;
            Color           color;

            Ab3d.Meshes.BoxMesh3D boxMesh = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, 0, 0),
                                                                      new Size3D(80, 80, 80),
                                                                      1, 1, 1);

            string objectName;
            string colorName;
            double offsetX, offsetY, offsetZ;

            for (int x = 0; x < 3; x++)
            {
                offsetX = -100 + x * 100;

                if (x == 0)
                {
                    color     = Color.FromArgb(255, 255, 0, 0);
                    colorName = "red";
                }
                else if (x == 1)
                {
                    color     = Color.FromArgb(255, 0, 255, 0);
                    colorName = "green";
                }
                else
                {
                    color     = Color.FromArgb(255, 0, 0, 255);
                    colorName = "blue";
                }

                for (int y = 0; y < 3; y++)
                {
                    offsetY = -100 + y * 100;

                    for (int z = 0; z < 3; z++)
                    {
                        offsetZ = -100 + z * 100;

                        if (z == 0)
                        {
                            color.A = 80;
                        }
                        else if (z == 1)
                        {
                            color.A = 160;
                        }
                        else
                        {
                            color.A = 255;
                        }

                        material = new DiffuseMaterial(new SolidColorBrush(color));

                        geometryModel3D = new GeometryModel3D(boxMesh.Geometry, material);
                        if (z != 2)
                        {
                            geometryModel3D.BackMaterial = material; // Set BackMaterial to transparent models
                        }
                        geometryModel3D.Transform = new TranslateTransform3D(offsetX, offsetY, offsetZ);

                        rootGroup.Children.Add(geometryModel3D);

                        objectName = string.Format("Box_{0}_{1}_{2}", colorName, color.A, y + 1);
                        objectNames.Add(geometryModel3D, objectName);
                    }
                }
            }
        }
        // See also:
        // - Objects3D/BooleanOperationsSample to see other boolean operations
        // - Utilities/TextureCoordinatesGeneratorSample to see other options to define TextureCoordinates that are needed to show texture images

        public ModelingWithBooleanOperations()
        {
            InitializeComponent();

            _orangeMaterial = new MaterialGroup();
            _orangeMaterial.Children.Add(new DiffuseMaterial(Brushes.Orange));
            _orangeMaterial.Children.Add(new SpecularMaterial(Brushes.White, 16));

            // We will start with a simple box
            // Create it manually with MeshGeometry3D
            MeshGeometry3D initialBoxMesh3D = new Ab3d.Meshes.BoxMesh3D(new Point3D(-100, 25, 0), new Size3D(200, 50, 100), 1, 1, 1).Geometry;

            // Without boolean operations, we could simply create the box with:
            //var boxVisual3D = new BoxVisual3D()
            //{
            //    CenterPosition = new Point3D(-100, 25, 0),
            //    Size = new Size3D(200, 50, 100),
            //    UseCachedMeshGeometry3D = false, // we should not use the cached
            //    Material = _orangeMaterial
            //};


            // Define MeshGeometry3D objects that will be used for subtractions
            var centerSphereMesh = new Ab3d.Meshes.SphereMesh3D(new Point3D(-100, 50, 0), 40, 16).Geometry;

            var box1Mesh = new Ab3d.Meshes.BoxMesh3D(new Point3D(-180, 0, -30), new Size3D(10, 200, 10), 1, 1, 1).Geometry;
            var box2Mesh = new Ab3d.Meshes.BoxMesh3D(new Point3D(-180, 0, 0), new Size3D(10, 200, 10), 1, 1, 1).Geometry;
            var box3Mesh = new Ab3d.Meshes.BoxMesh3D(new Point3D(-180, 0, 30), new Size3D(10, 200, 10), 1, 1, 1).Geometry;

            var cylinder1Mesh3D = new Ab3d.Meshes.CylinderMesh3D(new Point3D(-20, 0, -30), 8, 200, segments: 16, isSmooth: false).Geometry;
            var cylinder2Mesh3D = new Ab3d.Meshes.CylinderMesh3D(new Point3D(-20, 0, 0), 8, 200, segments: 16, isSmooth: false).Geometry;
            var cylinder3Mesh3D = new Ab3d.Meshes.CylinderMesh3D(new Point3D(-20, 0, 30), 8, 200, segments: 16, isSmooth: false).Geometry;


            // When doing multiple boolean operations one after another,
            // it is recommended (and mush faster) to use BooleanMesh3D object.

            var booleanMesh3D = new Ab3d.Meshes.BooleanMesh3D(initialBoxMesh3D);

            booleanMesh3D.Subtract(centerSphereMesh);

            booleanMesh3D.Subtract(box1Mesh);
            booleanMesh3D.Subtract(box2Mesh);
            booleanMesh3D.Subtract(box3Mesh);

            booleanMesh3D.Subtract(cylinder1Mesh3D);
            booleanMesh3D.Subtract(cylinder2Mesh3D);
            booleanMesh3D.Subtract(cylinder3Mesh3D);


            // It is also possible to use Subtract method on BoxVisual3D object:
            //boxVisual3D.Subtract(centerSphereMesh);
            //boxVisual3D.Subtract(box1Mesh);
            //boxVisual3D.Subtract(box2Mesh);
            //boxVisual3D.Subtract(box3Mesh);
            //boxVisual3D.Subtract(cylinder1Mesh3D);
            //boxVisual3D.Subtract(cylinder2Mesh3D);
            //boxVisual3D.Subtract(cylinder3Mesh3D);


            // We could also use the static methods on Ab3d.Utilities.MeshBooleanOperations class:
            //Ab3d.Utilities.MeshBooleanOperations.Subtract(boxVisual3D, sphereMesh);
            //Ab3d.Utilities.MeshBooleanOperations.Subtract(boxVisual3D, boxMesh);


            // When calling the Geometry getter, the BooleanMesh3D converts the internal object into MeshGeometry3D.
            var meshGeometry3D = booleanMesh3D.Geometry;

            var initialGeometryModel3D = new GeometryModel3D(meshGeometry3D, _orangeMaterial);
            var boxVisual3D            = initialGeometryModel3D.CreateModelVisual3D();

            // Now add the changed box to the scene
            MainViewport.Children.Add(boxVisual3D);



            // When working with more complex meshes, the boolean operations can take some time.
            // To prevent blocking UI thread, we can do the boolean operations in the background thread.
            // To do this we need to freeze the MeshGeometry3D that are send to the background thread and back to UI thread.
            //
            // The following code is using spheres with 30 segments to demonstrate a longer boolean operations.
            //

            // First define the original MeshGeometry3D
            initialBoxMesh3D = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, 25, 0), new Size3D(100, 50, 100), 1, 1, 1).Geometry;

            ShowNewOriginalMesh(initialBoxMesh3D);


            var initialBooleanMesh3D = new Ab3d.Meshes.BooleanMesh3D(initialBoxMesh3D);

            var sphereCenters = new Point3D[]
            {
                new Point3D(-50, 50, 50),
                new Point3D(50, 50, 50),
                new Point3D(50, 50, -50),
                new Point3D(-50, 50, -50),
                new Point3D(-50, 0, 50),
                new Point3D(50, 0, 50),
                new Point3D(50, 0, -50),
                new Point3D(-50, 0, -50)
            };

            // We can create the MeshGeometry3D and prepare the BooleanMesh3D in parallel - each can be created in its own thread
            var sphereBooleanMeshes = sphereCenters.AsParallel().Select(sphereCenter =>
            {
                //System.Diagnostics.Debug.WriteLine($"Start creating SphereMesh3D with {sphereCenter} on {System.Threading.Thread.CurrentThread.ManagedThreadId}");

                var sphereMeshGeometry3D = new Ab3d.Meshes.SphereMesh3D(sphereCenter, radius: 15, segments: 30).Geometry;
                var sphereBooleanMesh3D  = new Ab3d.Meshes.BooleanMesh3D(sphereMeshGeometry3D);

                return(sphereBooleanMesh3D);
            });

            // After that we can subtract each of the sphere meshes from the initialBooleanMesh3D.
            // This can be done in background thread (we use Dispatcher.Invoke to "send" the mesh to the UI thread)
            Task.Factory.StartNew(() =>
            {
                // Note the order in which the sphereBooleanMesh are created is not determined (as the BooleanMesh3D are created, they get available to the foreach)
                foreach (var sphereBooleanMesh in sphereBooleanMeshes)
                {
                    // Subtract the sphereBooleanMesh from the initialBooleanMesh3D
                    initialBooleanMesh3D.Subtract(sphereBooleanMesh);

                    // Get the MeshGeometry3D
                    var mesh = initialBooleanMesh3D.Geometry;

                    // Freeze the MeshGeometry3D
                    // This will allow using the mesh in UI thread (different thread as the mesh was created)
                    mesh.Freeze();

                    // Send it to UI thread
                    this.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        ShowNewOriginalMesh(mesh);
                    }));
                }
            })
            // After all the boolean operations are completed, we generate texture coordinates
            // so we will be able to use texture image as material (meshes that are created with boolean operations do not have texture coordinates defined)
            .ContinueWith(_ => GenerateTextureCoordinates(), TaskScheduler.FromCurrentSynchronizationContext()); // The last one is run on UI thread
        }
        private void CreateTestModels()
        {
            _rootModelVisual3D = new ModelVisual3D();
            MainViewport3D.Children.Add(_rootModelVisual3D);



            // SphereVisual3D
            _sphereVisual3D = new Ab3d.Visuals.SphereVisual3D()
            {
                CenterPosition = new Point3D(-50, 0, -50),
                Radius         = 30,
                Material       = new DiffuseMaterial(Brushes.Silver)
            };

            _sphereVisual3D.SetName("SphereVisual3D");

            _rootModelVisual3D.Children.Add(_sphereVisual3D);


            var readerObj   = new ReaderObj();
            var teapotModel = readerObj.ReadModel3D(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Resources\Models\teapot-hires.obj"));

            Ab3d.Utilities.ModelUtils.CenterAndScaleModel3D(teapotModel, centerPosition: new Point3D(50, 0, -50), finalSize: new Size3D(80, 80, 80), preserveAspectRatio: true);

            _teapotModelVisual3D = new ModelVisual3D()
            {
                Content = teapotModel
            };

            teapotModel.SetName("teapot Model3D");
            _teapotModelVisual3D.SetName("teapot ModelVisual3D");

            _rootModelVisual3D.Children.Add(_teapotModelVisual3D);


            // InstancedMeshGeometryVisual3D
            var boxMesh3D = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, 0, 0), new Size3D(6, 6, 6), 1, 1, 1);

            InstanceData[] instancedData = DXEnginePerformance.InstancedMeshGeometry3DTest.CreateInstancesData(center: new Point3D(-50, 0, 50),
                                                                                                               size: new Size3D(80, 50, 80),
                                                                                                               modelScaleFactor: 1,
                                                                                                               xCount: 5,
                                                                                                               yCount: 1,
                                                                                                               zCount: 5,
                                                                                                               useTransparency: false);

            _instancedMeshGeometryVisual3D = new InstancedMeshGeometryVisual3D(boxMesh3D.Geometry);
            _instancedMeshGeometryVisual3D.InstancesData = instancedData;

            _instancedMeshGeometryVisual3D.SetName("InstancedMeshGeometryVisual3D");
            _rootModelVisual3D.Children.Add(_instancedMeshGeometryVisual3D);



            // MeshObjectNode and SceneNodeVisual3D
            var meshGeometry3D   = new Ab3d.Meshes.PyramidMesh3D(new Point3D(50, -20, 50), new Size3D(80, 40, 80)).Geometry;
            var dxMeshGeometry3D = new Ab3d.DirectX.Models.DXMeshGeometry3D(meshGeometry3D);

            var standardMaterial = new StandardMaterial()
            {
                DiffuseColor = Colors.Gold.ToColor3()
            };

            _pyramidMeshObjectNode = new Ab3d.DirectX.MeshObjectNode(dxMeshGeometry3D, standardMaterial);

            _disposables.Add(dxMeshGeometry3D);
            _disposables.Add(_pyramidMeshObjectNode);

            var sceneNodeVisual3D = new SceneNodeVisual3D(_pyramidMeshObjectNode);

            sceneNodeVisual3D.SetName("SceneNodeVisual3D");
            _rootModelVisual3D.Children.Add(sceneNodeVisual3D);
        }
        private void GenerateSampleObjects()
        {
            // We will show multiple instances of box MeshGeometry3D that is created here.
            //
            // IMPORTANT:
            //
            // It is very important to specify the correct position and size of the mesh.
            // The size should be one unit so that when you scale this mesh in instance data,
            // the scale factor will tell you the final size (for example xScale = 3 would render box with xSize set to 3).
            //
            // The position is even more important because when you will scale and rotate the mesh,
            // the mesh will be scaled and rotated around (0, 0, 0).
            // So if center of mesh is at (0, 0, 0), then the mesh will be also scale in all directions.
            // But if left edge is at (0, 0, 0), then the object will scale to the right (all coordinates are multiplied by the scale).
            //
            // What is more, the position that is at (0, 0, 0) in the original mesh will be positioned at the position
            // defined in the World transform by the M41, M42, M43 fields.
            // So if center of the mesh is at (0, 0, 0) - as in our case - then M41, M42, M43 will define the position of the center.
            // But if left-bottom-front edge would be at (0, 0, 0) - if we would use "centerPosition: new Point3D(0.5, 0.5, 0.5)" -
            // then  M41, M42, M43 will define the position of the left-bottom-front edge when the box is shown.
            //
            // See also comments in CalculateMatrixFromPositionsAndSize method.

            Point3D boxCenterPosition = CenterBoxMeshToCoordinateCenter ? new Point3D(0, 0, 0) : new Point3D(0.5, 0, 0);

            var boxMeshGeometry3D = new Ab3d.Meshes.BoxMesh3D(centerPosition: boxCenterPosition,
                                                              size: new Size3D(1, 1, 1),
                                                              xSegments: 1, ySegments: 1, zSegments: 1).Geometry;

            // Uncomment the following line to see how an ArrowMesh3D would look like (note that arrow part is also scaled so ArrowMesh3D is not a very good candidate for mesh used for instancing when scale is not uniform)
            //boxMeshGeometry3D = new Ab3d.Meshes.ArrowMesh3D(startPosition: new Point3D(0, 0, 0), endPosition: new Point3D(1, 0, 0), radius: 0.1f, arrowRadius: 0.2f, arrowAngle: 45, segments: 10, generateTextureCoordinates: false).Geometry;

            // Create an instance of InstancedMeshGeometryVisual3D
            var instancedMeshGeometryVisual3D = new InstancedMeshGeometryVisual3D(boxMeshGeometry3D);


            // Create an array of InstanceData with the matrices define in the _matrices list and Green color.

            var instanceData = new InstanceData[_samplesData.Count];

            for (int i = 0; i < _samplesData.Count; i++)
            {
                instanceData[i]            = new InstanceData(_samplesData[i].Matrix, Colors.Green.ToColor4());
                instanceData[i].World.M43 -= SamplesDistance * i;

                var wireGridVisual3D = new WireGridVisual3D()
                {
                    CenterPosition   = new Point3D(0, 0, -SamplesDistance * i),
                    Size             = new Size(4, 4),
                    WidthCellsCount  = 4,
                    HeightCellsCount = 4,
                    LineColor        = Colors.Gray,
                    LineThickness    = 1
                };

                MainViewport.Children.Add(wireGridVisual3D);


                var yAxisLineVisual3D = new LineVisual3D()
                {
                    StartPosition = wireGridVisual3D.CenterPosition,
                    EndPosition   = wireGridVisual3D.CenterPosition + new Vector3D(0, 1.2, 0),
                    LineColor     = wireGridVisual3D.LineColor,
                    LineThickness = wireGridVisual3D.LineThickness,
                    EndLineCap    = LineCap.ArrowAnchor
                };

                MainViewport.Children.Add(yAxisLineVisual3D);
            }

            instancedMeshGeometryVisual3D.InstancesData = instanceData;

            MainViewport.Children.Add(instancedMeshGeometryVisual3D);
        }
        private void MainDXViewportViewOnDXSceneDeviceCreated(object sender, EventArgs e)
        {
            var instancedData = CreateInstancesData(center: new Point3D(0, 0, 0),
                                                    size: new Size3D(4 * XInstancesCount, 4 * YInstancesCount, 4 * ZInstancesCount),
                                                    modelScaleFactor: 1,
                                                    xCount: XInstancesCount, yCount: YInstancesCount, zCount: ZInstancesCount,
                                                    useTransparency: false);

            // Update colors
            int dataCount = instancedData.Length;

            for (int i = 0; i < dataCount; i++)
            {
                float percentage = 1.0f - (float)i / (float)dataCount;
                instancedData[i].DiffuseColor = new Color4(red: percentage, green: 1, blue: percentage, alpha: 1);
            }


            var boxMeshGeometry = new Ab3d.Meshes.BoxMesh3D(centerPosition: new Point3D(0, 0, 0), size: new Size3D(3, 3, 3), xSegments: 1, ySegments: 1, zSegments: 1).Geometry;


            // The first InstancedMeshGeometry3DNode will get the instancedData and
            // will also create the DirectX instance buffer.
            _instancedMeshGeometry3DNode1 = new InstancedMeshGeometry3DNode(boxMeshGeometry);
            _instancedMeshGeometry3DNode1.SetInstanceData(instancedData);

            // Manually call InitializeResources.
            // For this to work, the dxViewportView.DXScene must be set.
            // This is the reason why this method is called inside a DXViewportView.DXSceneDeviceCreated event handler.
            _instancedMeshGeometry3DNode1.InitializeResources(MainDXViewportView.DXScene);

            _disposables.Add(_instancedMeshGeometry3DNode1);


            var instanceBuffer = _instancedMeshGeometry3DNode1.GetInstanceBuffer();

            if (instanceBuffer == null)
            {
                throw new Exception("GetInstanceBuffer returned null"); // Probably DXScene is not initialized
            }
            // Now create another 2 InstancedMeshGeometry3DNode objects
            // and initialize it with already created instanceBuffer

            // The next InstancedMeshGeometry3DNode will be also initialized so
            // that all instances will be rendered with red color instead of the color defined in the instances data.
            _instancedMeshGeometry3DNode2 = new InstancedMeshGeometry3DNode(boxMeshGeometry);
            _instancedMeshGeometry3DNode2.SetInstanceBuffer(instanceBuffer, InstanceData.SizeInBytes, instancedData.Length, instancedData);
            _instancedMeshGeometry3DNode2.UseSingleObjectColor(Colors.Red.ToColor4());
            _disposables.Add(_instancedMeshGeometry3DNode2);

            // The last InstancedMeshGeometry3DNode will render last part of the instances with the color defined in the instance data.
            _instancedMeshGeometry3DNode3 = new InstancedMeshGeometry3DNode(boxMeshGeometry);
            _instancedMeshGeometry3DNode3.SetInstanceBuffer(instanceBuffer, InstanceData.SizeInBytes, instancedData.Length, instancedData);
            _disposables.Add(_instancedMeshGeometry3DNode3);


            // Set StartInstanceIndex and InstancesCount
            _startTime         = DateTime.Now;
            _lastStartRowIndex = int.MinValue;
            UpdateHiddenInstancesPositions();


            var rootSceneNode = new SceneNode();

            rootSceneNode.AddChild(_instancedMeshGeometry3DNode1);
            rootSceneNode.AddChild(_instancedMeshGeometry3DNode2);
            rootSceneNode.AddChild(_instancedMeshGeometry3DNode3);

            var sceneNodeVisual3D = new SceneNodeVisual3D(rootSceneNode);

            MainViewport.Children.Add(sceneNodeVisual3D);
        }
        private void CreateTestScene(Viewport3D wpfViewport3D)
        {
            var boxMaterial = new DiffuseMaterial(Brushes.Orange);

            var sphereMaterial = new MaterialGroup();

            sphereMaterial.Children.Add(new DiffuseMaterial(Brushes.SkyBlue));
            sphereMaterial.Children.Add(new SpecularMaterial(Brushes.White, 20));

            var lightMaterialGroup = new MaterialGroup();

            lightMaterialGroup.Children.Add(new DiffuseMaterial(Brushes.Black));
            lightMaterialGroup.Children.Add(new EmissiveMaterial(Brushes.Yellow));


            var objectsGroup = new Model3DGroup();

            //var boxMesh = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, 0, 0), new Size3D(30, 30, 30), 1, 1, 1).Geometry;
            //var sphereMesh = new Ab3d.Meshes.SphereMesh3D(new Point3D(0, 0, 0), 15, 20, false).Geometry;


            //for (int y = 0; y < 5; y++)
            //{
            //    for (int x = -200; x <= 200; x += 100)
            //    {
            //        for (int z = -200; z <= 200; z += 100)
            //        {
            //            var geometryModel3D = new GeometryModel3D();

            //            if ((y % 2) == 0)
            //            {
            //                geometryModel3D.Geometry = boxMesh;
            //                geometryModel3D.Material = boxMaterial;
            //            }
            //            else
            //            {
            //                geometryModel3D.Geometry = sphereMesh;
            //                geometryModel3D.Material = sphereMaterial;
            //            }

            //            geometryModel3D.Transform = new TranslateTransform3D(x, y * 50, z);

            //            objectsGroup.Children.Add(geometryModel3D);
            //        }
            //    }
            //}

            var boxMesh    = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, 0, 0), new Size3D(1, 1, 1), 1, 1, 1).Geometry;
            var sphereMesh = new Ab3d.Meshes.SphereMesh3D(new Point3D(0, 0, 0), 10, 20, false).Geometry;

            double yPos      = 0;
            double firstSize = 50;

            for (int y = 0; y < 5; y++)
            {
                int    samples     = (y * 2) + 2;
                int    halfSamples = samples / 2;
                double size        = 400 / (samples * 1.5);

                if (y == 0)
                {
                    firstSize = size;
                }

                double xPos = -200;

                for (int x = -halfSamples; x <= halfSamples; x++)
                {
                    double zPos = -200;

                    for (int z = -halfSamples; z <= halfSamples; z++)
                    {
                        var geometryModel3D = new GeometryModel3D();

                        geometryModel3D.Geometry = boxMesh;
                        geometryModel3D.Material = boxMaterial;

                        var transform3DGroup = new Transform3DGroup();
                        transform3DGroup.Children.Add(new ScaleTransform3D(size, size, size));
                        transform3DGroup.Children.Add(new TranslateTransform3D(xPos, yPos, zPos));

                        geometryModel3D.Transform = transform3DGroup;

                        objectsGroup.Children.Add(geometryModel3D);


                        zPos += size * 1.5;
                    }

                    xPos += size * 1.5;
                }

                yPos += size + y * 7 + 10;
            }


            for (int a = 0; a < 360; a += 20)
            {
                double rad = MathUtil.DegreesToRadians(a);
                double x   = Math.Sin(rad) * 600;
                double z   = Math.Cos(rad) * 600;


                var geometryModel3D = new GeometryModel3D();

                geometryModel3D.Geometry = sphereMesh;
                geometryModel3D.Material = sphereMaterial;

                var transform3DGroup = new Transform3DGroup();
                transform3DGroup.Children.Add(new ScaleTransform3D(8, 8, 8));
                transform3DGroup.Children.Add(new TranslateTransform3D(x, 20, z));

                geometryModel3D.Transform = transform3DGroup;

                objectsGroup.Children.Add(geometryModel3D);
            }

            var bottomBoxModel3D = new GeometryModel3D();

            bottomBoxModel3D.Geometry = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, -(firstSize / 2), 0), new Size3D(2000, 10, 2000), 1, 1, 1).Geometry;
            //bottomBoxModel3D.Geometry = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, -(firstSize / 2), 0), new Size3D(2000, 10, 2000), 50, 1, 50).Geometry; // To see at least some spot light on bottom box in WPF, create the box from 50 x 50 mesh (or more)
            bottomBoxModel3D.Material = new DiffuseMaterial(Brushes.Silver);

            objectsGroup.Children.Add(bottomBoxModel3D);

            var wireGrid = new Ab3d.Visuals.WireGridVisual3D();

            wireGrid.CenterPosition   = new Point3D(0, -(firstSize / 2) + 11, 0);
            wireGrid.Size             = new Size(1800, 1800);
            wireGrid.WidthCellsCount  = 9;
            wireGrid.HeightCellsCount = 9;
            wireGrid.LineColor        = Colors.SkyBlue;
            wireGrid.LineThickness    = 3;

            wpfViewport3D.Children.Add(wireGrid);



            var lightsGroup = new Model3DGroup();

            _spotLightModel          = new GeometryModel3D();
            _spotLightModel.Geometry = sphereMesh;
            _spotLightModel.Material = lightMaterialGroup;

            _spotLightTranslate       = new TranslateTransform3D(_wpfSpotLight.Position.X, _wpfSpotLight.Position.Y, _wpfSpotLight.Position.Z);
            _spotLightModel.Transform = _spotLightTranslate;

            lightsGroup.Children.Add(_spotLightModel);


            _pointLightModel          = new GeometryModel3D();
            _pointLightModel.Geometry = sphereMesh;
            _pointLightModel.Material = lightMaterialGroup;

            _pointLightTranslate       = new TranslateTransform3D(_wpfPointLight1.Position.X, _wpfPointLight1.Position.Y, _wpfPointLight1.Position.Z);
            _pointLightModel.Transform = _pointLightTranslate;

            lightsGroup.Children.Add(_pointLightModel);



            var modelVisual3D = new ModelVisual3D();

            modelVisual3D.Content = objectsGroup;

            wpfViewport3D.Children.Add(modelVisual3D);

            var lightsVisual3D = new ModelVisual3D();

            lightsVisual3D.Content = lightsGroup;

            wpfViewport3D.Children.Add(lightsVisual3D);
        }