private void OnCustomPlaneCheckBoxChanged(object sender, RoutedEventArgs e)
        {
            if (_planarShadowRenderingProvider != null)
            {
                if (CustomPlaneCheckBox.IsChecked ?? false)
                {
                    // When we set ShadowPlaneMaterial and ShadowPlaneMaterial to null, then the 3D plane is not drawn any more.
                    // But shadow can be still clipped to the bounds of the "plane" defined by the ShadowPlaneCenterPosition and ShadowPlaneSize.
                    _planarShadowRenderingProvider.ShadowPlaneMaterial     = null;
                    _planarShadowRenderingProvider.ShadowPlaneBackMaterial = null;

                    _wireGridVisual3D = new WireGridVisual3D()
                    {
                        CenterPosition   = new Point3D(_planarShadowRenderingProvider.ShadowPlaneCenterPosition.X, _planarShadowRenderingProvider.ShadowPlaneCenterPosition.Y - 0.2, _planarShadowRenderingProvider.ShadowPlaneCenterPosition.Z),
                        Size             = new Size(_planarShadowRenderingProvider.ShadowPlaneSize.X, _planarShadowRenderingProvider.ShadowPlaneSize.Y),
                        WidthCellsCount  = 10,
                        HeightCellsCount = 10,
                        LineThickness    = 1,
                    };

                    MainViewport.Children.Add(_wireGridVisual3D);
                }
                else
                {
                    _planarShadowRenderingProvider.ShadowPlaneMaterial     = _shadowPlaneMaterial;
                    _planarShadowRenderingProvider.ShadowPlaneBackMaterial = _shadowPlaneBackMaterial;

                    if (_wireGridVisual3D != null)
                    {
                        MainViewport.Children.Remove(_wireGridVisual3D);
                        _wireGridVisual3D = null;
                    }
                }

                MainDXViewportView.Refresh();
            }
        }
        private void CreateTestScene()
        {
            // Line StartPosition and EndPosition define where the center of the line goes.
            // Half of line thickness is rendered on each side of the center line and the other half on the other side of the center line.
            // So if line thickness is 1 screen pixel and center of the line goes over the border between two pixels,
            // then line is rendered half pixels on each side of the center.
            // The doth (.) in the following image show where only half of the pixel is occupied by the line color.
            // If line color is black and background color is white, then such line will produce gray pixels
            // that will be shown as 2 pixels thick line.

            // Line with LineThickness = 1 pixel
            // StartPosition = (-1, 0)
            // EndPosition = (3, 0)

            //     -2  -1   0   1   2   3
            //  2   --------|------------
            //      |   |   |   |   |   |
            //  1   --------|------------
            //      |   | . | . | . | . |
            //  0 ----------|--------------
            //      |   | . | . | . | . |
            // -1   --------|------------
            //      |   |   |   |   |   |
            // -2   --------|------------


            // To render a 1 pixel thick line in such a way that it will fill the whole pixel,
            // we need to move the center of the line so that it will go through the center of the pixels.
            // This will render the line as black line.
            // In the image below this is done with setting y to 0.5:

            // Line with LineThickness = 1 pixel
            // StartPosition = (-1, 0.5)
            // EndPosition = (3, 0.5)

            //     -2  -1   0   1   2   3
            //  2   --------|------------
            //      |   |   |   |   |   |
            //  1   --------|------------
            //      |   | x | x | x | x |
            //  0 ----------|--------------
            //      |   |   |   |   |   |
            // -1   --------|------------
            //      |   |   |   |   |   |
            // -2   --------|------------


            // For this to work the following conditions need to be meet:
            // - the line need to be correctly positioned (also taking into account DPI settings and ZoomFactor)
            // - the camera need to be correctly set so that the (0, 0) position lies between screen pixels.
            // - DXViewportView need to be correctly snapped to screen pixels by WPF.
            //
            // It is not easy to correctly account all those parameters.
            // The current version of TwoDimensionalCamera does not yet support that.
            //
            // But with Ab3d.DXEngine it is possible to render some (or all) the lines
            // in such a way that they will be rendered exactly to screen pixels.
            //
            // This can be done with setting UseGeometryShaderFor3DLines and RenderAntialiased3DLines attributes to false.
            // This way the lines are rendered by DirectX. Such lines are always 1 screen pixel thick
            // and are always rendered to the screen pixels.
            //
            // The biggest disadvantage of this is that such lines are always 1 screen pixel thick.
            //
            // Such lines look good only when they are horizontal or vertical.
            // But when they are at an angle, the standard lines appear much nicer and smoother.
            //
            // Another disadvantage is that such lines are not rendered correctly when super-sampling is used.
            // The problem is that such line is rendered with 1 pixel thickness to a super-sized texture,
            // so when such texture is down-sampled the line will appear much dimmer because its color will
            // combined with surrounding colors. For example with 4xSSAA they will be half dimmer, with 16xSSAA they will be 4 times dimmer.
            // (standard lines are rendered thicker to super-sampled texture so thickness is correct after down-sampling).


            // We will render two sets of lines:
            // 1) The lines on the left will be rendered normally.
            // 2) The lines on the right will be rendered without using geometry shader and without anti-aliasing.


            double screenPixelLineThickness = _twoDimensionalCamera.ScreenPixelSize;

            var triangleFan1 = AddTriangleFan(new Point3D(-300, 60, 0), linesLength: 200, lineThickness: screenPixelLineThickness);
            var triangleFan2 = AddTriangleFan(new Point3D(100, 60, 0), linesLength: 200, lineThickness: screenPixelLineThickness);

            triangleFan2.SetDXAttribute(DXAttributeType.UseGeometryShaderFor3DLines, false);
            triangleFan2.SetDXAttribute(DXAttributeType.RenderAntialiased3DLines, false);


            var wireGridVisual1 = new WireGridVisual3D()
            {
                CenterPosition   = new Point3D(-200, -60, 0),
                Size             = new Size(200, 200),
                HeightDirection  = new Vector3D(0, 1, 0),
                WidthDirection   = new Vector3D(1, 0, 0),
                WidthCellsCount  = 10,
                HeightCellsCount = 10,
                LineThickness    = screenPixelLineThickness,
            };

            MainViewport.Children.Add(wireGridVisual1);


            var wireGridVisual2 = new WireGridVisual3D()
            {
                CenterPosition   = new Point3D(200, -60, 0),
                Size             = new Size(200, 200),
                HeightDirection  = new Vector3D(0, 1, 0),
                WidthDirection   = new Vector3D(1, 0, 0),
                WidthCellsCount  = 10,
                HeightCellsCount = 10,
                LineThickness    = screenPixelLineThickness

                                   // NOTE:
                                   // When IsClosed is set to true or when using MajorLinesFrequency,
                                   // then WireGridVisual3D creates a Model3DGroup to render multiple line types.
                                   // In this case setting DXAttribute does not work.
                                   // If you want to to use MajorLinesFrequency, then create two WireGridVisual3D.
                                   // For closed WireGridVisual3D, create a separate RectangleVisual3D
                                   // MajorLinesFrequency = 2,
                                   // IsClosed = true
            };

            wireGridVisual2.SetDXAttribute(DXAttributeType.UseGeometryShaderFor3DLines, false);
            wireGridVisual2.SetDXAttribute(DXAttributeType.RenderAntialiased3DLines, false);

            MainViewport.Children.Add(wireGridVisual2);


            // Add list of lines each with slightly different sub-pixel position.
            AddLineList(startPosition: new Point3D(-300, -220, 0), lineVector: new Vector3D(0, 40, 0), offsetVector: new Vector3D(10 + screenPixelLineThickness / 10, 0, 0), startLineThickness: screenPixelLineThickness, endLineThickness: screenPixelLineThickness, count: 20, renderAs1PixelNonAntiAliasedLine: false);
            AddLineList(startPosition: new Point3D(100, -220, 0), lineVector: new Vector3D(0, 40, 0), offsetVector: new Vector3D(10 + screenPixelLineThickness / 10, 0, 0), startLineThickness: screenPixelLineThickness, endLineThickness: screenPixelLineThickness, count: 20, renderAs1PixelNonAntiAliasedLine: true);

            // Add list of lines with different line thickness.
            // This shows that lines without geometry shader are always 1 screen pixel thick and do not support line thickness.
            AddLineList(startPosition: new Point3D(-300, -280, 0), lineVector: new Vector3D(0, 40, 0), offsetVector: new Vector3D(10 + screenPixelLineThickness / 10, 0, 0), startLineThickness: 0.5, endLineThickness: 5, count: 20, renderAs1PixelNonAntiAliasedLine: false);
            AddLineList(startPosition: new Point3D(100, -280, 0), lineVector: new Vector3D(0, 40, 0), offsetVector: new Vector3D(10 + screenPixelLineThickness / 10, 0, 0), startLineThickness: 0.5, endLineThickness: 5, count: 20, renderAs1PixelNonAntiAliasedLine: true);
        }
        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 CreateSceneObjects()
        {
            // NOTE:
            // It is recommended to use meter as basic unit for all 3D objects used by VR.

            var rootVisual3D = new ModelVisual3D();

            var wireGridVisual3D = new WireGridVisual3D()
            {
                CenterPosition   = new Point3D(0, 0, 0),
                Size             = new Size(3, 3), // 3 x 3 meters
                WidthCellsCount  = 10,
                HeightCellsCount = 10,
                LineColor        = Colors.Gray,
                LineThickness    = 2
            };

            rootVisual3D.Children.Add(wireGridVisual3D);


            double centerX      = 0;
            double centerZ      = 0;
            double circleRadius = 1;

            var boxMaterial    = new DiffuseMaterial(Brushes.Gray);
            var sphereMaterial = new MaterialGroup();

            sphereMaterial.Children.Add(new DiffuseMaterial(Brushes.Silver));
            sphereMaterial.Children.Add(new SpecularMaterial(Brushes.White, 16));

            for (int a = 0; a < 360; a += 36)
            {
                double rad = SharpDX.MathUtil.DegreesToRadians(a);
                double x   = Math.Sin(rad) * circleRadius + centerX;
                double z   = Math.Cos(rad) * circleRadius + centerZ;

                var boxVisual3D = new BoxVisual3D()
                {
                    CenterPosition = new Point3D(x, 0.3, z),
                    Size           = new Size3D(0.2, 0.6, 0.2),
                    Material       = boxMaterial
                };

                var sphereVisual3D = new SphereVisual3D()
                {
                    CenterPosition = new Point3D(x, 0.75, z),
                    Radius         = 0.15,
                    Material       = sphereMaterial
                };

                rootVisual3D.Children.Add(boxVisual3D);
                rootVisual3D.Children.Add(sphereVisual3D);
            }

            MainViewport.Children.Clear();
            MainViewport.Children.Add(rootVisual3D);

            Camera1.Heading  = 25;
            Camera1.Attitude = -20;
            Camera1.Distance = 4; // 3 meters

            Camera1.Refresh();
        }
Exemple #5
0
            private ModelVisual3D CreateTestObjects()
            {
                var modelVisual3D = new ModelVisual3D();

                // NOTE:
                // The following box will be crated from 10 x 1 x 10 cells
                // This is needed to see at least some lights rendered on it in WPF rendering that is using per-vertex rendering
                // For DXEngine this is not needed because it is using per-pixel rendering (here we can create standard 1 x 1 x 1 box)
                var greenBaseBox = new BoxVisual3D()
                {
                    CenterPosition = new Point3D(0, -5, 0),
                    Size           = new Size3D(2000, 10, 2000),
                    XCellsCount    = 20,
                    YCellsCount    = 1,
                    ZCellsCount    = 20,
                    Material       = new DiffuseMaterial(Brushes.White)
                };

                modelVisual3D.Children.Add(greenBaseBox);


                var wireGridVisual3D = new WireGridVisual3D()
                {
                    CenterPosition      = new Point3D(0, 0.1, 0),
                    Size                = new Size(2000, 2000),
                    WidthDirection      = new Vector3D(1, 0, 0),
                    HeightDirection     = new Vector3D(0, 0, -1),
                    WidthCellsCount     = 100,
                    HeightCellsCount    = 100,
                    MajorLinesFrequency = 5,
                    IsClosed            = true,
                    MajorLineThickness  = 1.5,
                    MajorLineColor      = Colors.DimGray,

                    LineThickness = 0.8,
                    LineColor     = Colors.Gray,

                    RenderingTechnique = WireGridVisual3D.WireGridRenderingTechniques.FixedMesh3DLines, // Use fixed MeshGeometry3D to render wire grid instead of dynamic 3D lines
                    IsEmissiveMaterial = false                                                          // This also allows us to use standard material instead of emissive material - this means that the lines will be visible only where they are illuminated by the light.
                };

                modelVisual3D.Children.Add(wireGridVisual3D);


                double centerX = 0;
                double centerZ = 0;

                var orangeBox = new BoxVisual3D()
                {
                    CenterPosition = new Point3D(centerX, 100, centerZ),
                    Size           = new Size3D(50, 200, 50),
                    Material       = new DiffuseMaterial(Brushes.Orange)
                };

                modelVisual3D.Children.Add(orangeBox);


                var blueSpecularMaterial = new MaterialGroup();

                blueSpecularMaterial.Children.Add(new DiffuseMaterial(Brushes.LightSkyBlue));
                blueSpecularMaterial.Children.Add(new SpecularMaterial(Brushes.White, 20));

                for (int a = 0; a < 360; a += 40)
                {
                    double rad = SharpDX.MathUtil.DegreesToRadians(a);
                    double x   = Math.Sin(rad) * 100 + centerX;
                    double z   = Math.Cos(rad) * 100 + centerZ;

                    var sphereVisual3D = new SphereVisual3D()
                    {
                        CenterPosition = new Point3D(x, 25, z),
                        Radius         = 25,
                        Segments       = 10, // Intentially lowered from default 30 to make the rendering difference bigger (between per vertex (WPF) and per pixel (DXEngine) rendering)
                        Material       = blueSpecularMaterial
                    };

                    modelVisual3D.Children.Add(sphereVisual3D);
                }

                return(modelVisual3D);
            }