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 UpdateFogUsage()
        {
            if (MainDXViewportView.DXScene == null) // probably WPF 3D rendering is used
            {
                return;
            }


            // First make sure that we have the StandardEffect that is used by default
            if (_defaultStandardEffect == null)
            {
                _defaultStandardEffect = MainDXViewportView.DXScene.DXDevice.EffectsManager.GetStandardEffect();
            }


            // First reset the changes of previously changed SceneNodes
            if (_changedDXMaterial != null)
            {
                _changedDXMaterial.Effect = null;
                _changedDXMaterial        = null;
            }

            if (_yellowFogWpfMaterial != null)
            {
                // Replace _yellowFogWpfMaterial with default YellowMaterial
                var yellowMaterial = this.FindResource("YellowMaterial") as DiffuseMaterial;

                foreach (var baseModelVisual3D in MainViewport.Children.OfType <BaseModelVisual3D>())
                {
                    if (ReferenceEquals(baseModelVisual3D.Material, _yellowFogWpfMaterial))
                    {
                        baseModelVisual3D.Material = yellowMaterial;
                    }
                }

                _yellowFogWpfMaterial = null;
            }


            // NOTES:
            // We can use two ways to use custom FogEffect:
            //
            // 1) Set FogEffect as StandardEffect on EffectsManager.
            //    StandardEffect is used when DXEngine is rendering standard WPF materials (diffuse, specular, emissive).
            //    This means that if we change the StandardEffect, then all standard objects will be rendered with FogEffect.
            //    Other objects like 3D lines will still be rendered with their special effects.
            //
            // 2) Set FogEffect to the Effect property on the WpfMaterial object that is a DXEngine's material object created from WPF's material.
            //    When setting Effect property on DXEngine's material, the material will be rendered with the specified effect (instead of StandardEffect).


            // Additional notes:
            // 1) EffectsManager is created when the DXDevice is created.
            //    This means that you cannot access it in the constructor of this class.
            //    If you need to change the StandardEffect (or some other setting on DXDevice) before the first frame is rendered,
            //    you need to use DXSceneDeviceCreated or DXSceneInitialized event handler to do that (as in this case).


            Effect newStandardEffect;

            if (StandardEffectRadioButton.IsChecked ?? false)
            {
                newStandardEffect = _fogEffect;
            }
            else if (RootBoxRadioButton.IsChecked ?? false)
            {
                newStandardEffect = _defaultStandardEffect;

                // Get the DXEngine's material that is created from the WPF's Material used for BaseBoxVisual3D
                var dxMaterial = Ab3d.DirectX.Materials.WpfMaterial.GetUsedDXMaterial(BaseBoxVisual3D.Material, MainDXViewportView.DXScene.DXDevice);

                if (dxMaterial != null)
                {
                    // Now we can specify the exact effect that will be used to render dxMaterial (if this is not specified, then StandardEffect is used)
                    dxMaterial.Effect  = _fogEffect;
                    _changedDXMaterial = dxMaterial;
                }
            }
            else if (ReplaceRadioButton.IsChecked ?? false)
            {
                newStandardEffect = _defaultStandardEffect;

                // Create a clone of YellowMaterial
                var yellowMaterial = this.FindResource("YellowMaterial") as DiffuseMaterial;

                if (yellowMaterial != null)
                {
                    _yellowFogWpfMaterial = yellowMaterial.Clone();

                    // Now create a DXEngine's material that is created from WPF's material:
                    var yellowFogDXEngineMaterial = new Ab3d.DirectX.Materials.WpfMaterial(_yellowFogWpfMaterial);

                    // Specify the exact effect that will be used to render this material (if not specified, then the StandardEffect is used)
                    yellowFogDXEngineMaterial.Effect = _fogEffect;

                    // Now that we have both WPF material and DXEngine's material,
                    // we can specify that whenever the _yellowFogWpfMaterial will be used (and when our DXDevice is used),
                    // we should use the specified yellowFogDXEngineMaterial.
                    // This is done with the static SetUsedDXMaterial method.
                    //
                    // TIP: The same approach can be used to use some other rendering technique to render on material - for example to use ModelColorLineEffect, ThickLineEffect or SolidColorEffect.
                    Ab3d.DirectX.Materials.WpfMaterial.SetUsedDXMaterial(_yellowFogWpfMaterial, yellowFogDXEngineMaterial);

                    // NOTE:
                    // Instead of calling SetUsedDXMaterial, we could also specify the DXDevice in the WpfMaterial constructor.
                    // This would call the SetUsedDXMaterial behind the scenes. But we did it here in the long way to better demonstrate what is going on.
                    // The following code would call SetUsedDXMaterial in the constructor:
                    // var yellowFogDXEngineMaterial = new Ab3d.DirectX.Materials.WpfMaterial(_yellowFogWpfMaterial, MainDXViewportView.DXScene.DXDevice);

                    // After the _yellowFogWpfMaterial is "connected" to the yellowFogDXEngineMaterial, we can assign it insetad of yellow material:
                    foreach (var baseModelVisual3D in MainViewport.Children.OfType <BaseModelVisual3D>())
                    {
                        if (ReferenceEquals(baseModelVisual3D.Material, yellowMaterial))
                        {
                            baseModelVisual3D.Material = _yellowFogWpfMaterial;
                        }
                    }
                }
            }
            else
            {
                newStandardEffect = _defaultStandardEffect;
            }

            MainDXViewportView.DXScene.DXDevice.EffectsManager.SetStandardEffect(newStandardEffect);
        }
Esempio n. 3
0
        private void CreateScene()
        {
            int xCount = 40;
            int yCount = 1;
            int zCount = 40;

            float sphereRadius = 10;
            float sphereMargin = 10;

            var sphereMeshGeometry3D = new Ab3d.Meshes.SphereMesh3D(new Point3D(0, 0, 0), sphereRadius, 10).Geometry;

            _oneMeshTriangleIndicesCount = sphereMeshGeometry3D.TriangleIndices.Count;


            PositionNormalTexture[] vertexBuffer;
            int[] indexBuffer;

            var size = new Vector3(xCount * (sphereRadius + sphereMargin), yCount * (sphereRadius + sphereMargin), zCount * (sphereRadius + sphereMargin));

            SubMeshesSample.CreateMultiMeshBuffer(center: new Vector3(0, 0, 0),
                                                  size: size,
                                                  xCount: xCount, yCount: yCount, zCount: zCount,
                                                  meshGeometry3D: sphereMeshGeometry3D,
                                                  vertexBuffer: out vertexBuffer,
                                                  indexBuffer: out indexBuffer);

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


            // Create all 3 SubMeshes at the beginning.
            // Though at first only the first SubMesh will be rendered (the other two have IndexCount set to 0),
            // this will allow us to simply change the StartIndexLocation and IndexCount of the SubMeshes
            // to show selected part without adding or removing any SubMesh (this would regenerate the RenderingQueues).
            // This way the selection is almost a no-op (only changing a few integer values and rendering the scene again).
            _multiMaterialMesh.SubMeshes = new SubMesh[]
            {
                // First sub-mesh will render triangles from the first to the start of selection (or all triangles if there is no selection)
                new SubMesh("MainSubMesh1")
                {
                    MaterialIndex = 0, StartIndexLocation = 0, IndexCount = indexBuffer.Length
                },

                // Second sub-mesh will render triangles after the selection (this one follows the first on to preserve the same material)
                new SubMesh("MainSubMesh2")
                {
                    MaterialIndex = 0, StartIndexLocation = 0, IndexCount = 0
                },

                // The third sub-mesh will render selected triangles and will use the second material for that.
                new SubMesh("SelectionSubMesh")
                {
                    MaterialIndex = 1, StartIndexLocation = 0, IndexCount = 0
                },
            };

            _disposables.Add(_multiMaterialMesh);

            // Create OctTree from vertexBuffer.
            // This will significantly improve hit testing performance (check this with uncommenting the dxScene.GetClosestHitObject call in OnMouseMouse method).
            _octTree = new OctTree(vertexBuffer, indexBuffer);


            var materials = new Ab3d.DirectX.Material[]
            {
                new Ab3d.DirectX.Materials.StandardMaterial()
                {
                    DiffuseColor = Colors.Green.ToColor3()
                },
                new Ab3d.DirectX.Materials.StandardMaterial()
                {
                    DiffuseColor = Colors.Red.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);
        }
Esempio n. 4
0
        //private int _xCount = 10000;
        //private int _yCount = 2000;
        // Performance values for the 10000 x 2000 height map on NVIDIA 1080:
        // DirectXOverlay: render time 0.25 ms (4000 FPS)
        // DirectXImage - with back face rendering (bottom of the height map): render time around 14 ms (70 FPS)
        //              - without back face rendering:                         render time around 7 ms (140 FPS)

        public OptimizedHeightMapGeneration()
        {
            InitializeComponent();


            TitleTextBlock.Text += string.Format(" ({0}x{1} height values)", XCount, YCount);

            // First create very simple height map that can be created immediately.
            // After that we will wait until DXScene is initialized and then start a background worker
            // that will generate the mesh in the background. When this is done, we will update the 3D scene.


            _disposables = new DisposeList();

            int xCount = XCount / 100;
            int yCount = YCount / 100;

            float[,] simpleHeightData;
            Color4[] simplePositionColorsArray;

            //GenerateSimpleHeightData(XCount, YCount, out heightData, out positionColorsArray);
            //GenerateRandomHeightData(XCount, YCount, out heightData, out positionColorsArray);
            GenerateSinusHeightData(xCount, yCount, null, out simpleHeightData, out simplePositionColorsArray);

            var simpleHeightMapMesh = GenerateHeightMapMesh(simpleHeightData, dxDevice: null);

            _simplePositionColorMaterial = GeneratePositionColorMaterial(simplePositionColorsArray, dxDevice: null);

            _disposables.Add(simpleHeightMapMesh);
            _disposables.Add(_simplePositionColorMaterial);

            GenerateHeightMapSceneNodes(simpleHeightMapMesh, _simplePositionColorMaterial);

            //GenerateHeightMapObject(heightData, positionColorsArray);


            MainDXViewportView.DXSceneInitialized += delegate(object sender, EventArgs args)
            {
                if (MainDXViewportView.DXScene == null)
                {
                    return; // WPF 3D rendering
                }
                MeshBase heightMapMesh = null;
                _dxMaterial = null;

                var dxDevice = MainDXViewportView.DXScene.DXDevice;

                _backgroundWorker = new BackgroundWorker()
                {
                    WorkerSupportsCancellation = true,
                    WorkerReportsProgress      = true
                };

                _backgroundWorker.DoWork += delegate(object o, DoWorkEventArgs eventArgs)
                {
                    // 1)
                    // Generate height map data in the background.

                    float[,] heightData;
                    Color4[] positionColorsArray;

                    //GenerateSimpleHeightData(XCount, YCount, out heightData, out positionColorsArray);
                    //GenerateRandomHeightData(XCount, YCount, out heightData, out positionColorsArray);
                    GenerateSinusHeightData(XCount, YCount, _backgroundWorker, out heightData, out positionColorsArray);

                    if (_backgroundWorker.CancellationPending)
                    {
                        return;
                    }

                    // 2)
                    // Generate the mesh object and initialize it with dxDevice
                    // This will generate DirectX resources and send them to GPU
                    heightMapMesh = GenerateHeightMapMesh(heightData, dxDevice);

                    if (_backgroundWorker.CancellationPending)
                    {
                        return;
                    }

                    _backgroundWorker.ReportProgress(95);

                    if (_dxMaterial != null)
                    {
                        _dxMaterial.Dispose();
                    }

                    // 3)
                    // Generate material with position color data and sent that to GPU
                    _dxMaterial = GeneratePositionColorMaterial(positionColorsArray, dxDevice);

                    _backgroundWorker.ReportProgress(100);
                };

                _backgroundWorker.ProgressChanged += delegate(object o, ProgressChangedEventArgs eventArgs)
                {
                    GenerationProgressBar.Value = eventArgs.ProgressPercentage;
                };

                _backgroundWorker.RunWorkerCompleted += delegate(object o, RunWorkerCompletedEventArgs eventArgs)
                {
                    // Clean and dispose existing models
                    RootContentVisual3D.Children.Clear();
                    _disposables.Dispose();

                    // Create new DisposeList
                    _disposables = new DisposeList();
                    _disposables.Add(simpleHeightMapMesh);
                    _disposables.Add(_simplePositionColorMaterial);

                    // Generate SceneNode with new heightMapMesh and dxMaterial.
                    // Note that this is a very fast operation
                    if (heightMapMesh != null && _dxMaterial != null)
                    {
                        GenerateHeightMapSceneNodes(heightMapMesh, _dxMaterial);
                    }

                    _backgroundWorker = null;
                    GenerationProgressBar.Visibility = Visibility.Collapsed;

                    MainDXViewportView.Refresh();
                };

                GenerationProgressBar.Value      = 0;
                GenerationProgressBar.Visibility = Visibility.Visible;

                _backgroundWorker.RunWorkerAsync();
            };

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

                if (_dxMaterial != null)
                {
                    _dxMaterial.Dispose();
                    _dxMaterial = null;
                }

                if (_simplePositionColorMaterial != null)
                {
                    _simplePositionColorMaterial.Dispose();
                    _simplePositionColorMaterial = null;
                }

                _disposables.Dispose();
                MainDXViewportView.Dispose();
            };
        }