private void CreateInstances() { MeshGeometry3D meshGeometry3D; double modelScaleFactor; if (MeshTypeComboBox.SelectedIndex == 2) // Bunnies { // Load standard Standfor Bunny model (res3) with 11533 position meshGeometry3D = LoadMeshFromObjFile("bun_zipper_res3.obj"); var bounds = meshGeometry3D.Bounds; double diagonalSize = Math.Sqrt(bounds.SizeX * bounds.SizeX + bounds.SizeY * bounds.SizeY + bounds.SizeZ * bounds.SizeZ); modelScaleFactor = 20 / diagonalSize; // Scale model so that its diagonal is 20 units big } else if (MeshTypeComboBox.SelectedIndex == 1) // Spheres { // Sphere with 382 meshGeometry3D = new Ab3d.Meshes.SphereMesh3D(centerPosition: new Point3D(0, 0, 0), radius: 5, segments: 20, generateTextureCoordinates: false).Geometry; modelScaleFactor = 1; } else { // Box with 24 positions (for each corner we need 3 positions to create sharp edges - we need 3 normal vectors for each edge) meshGeometry3D = new Ab3d.Meshes.BoxMesh3D(centerPosition: new Point3D(0, 0, 0), size: new Size3D(10, 10, 10), xSegments: 1, ySegments: 1, zSegments: 1).Geometry; modelScaleFactor = 1; } int selectedInstancesYCount = GetSelectedInstancesYCount(); bool useTransparency = UseTransparencyCheckBox.IsChecked ?? false; float alphaColor = useTransparency ? 0.3f : 1.0f; // When we use transparency, we set alpha color to 0.3 (we also need to set UseAlphaBlend to true - see below) // The following method prepare InstanceData array with data for each instance (WorldMatrix and Color) InstanceData[] instancedData = CreateInstancesData(new Point3D(0, 200, 0), new Size3D(400, 400, 400), (float)modelScaleFactor, 20, selectedInstancesYCount, 20, useTransparency); // Create InstancedGeometryVisual3D with selected meshGeometry and InstancesData var instancedMeshGeometryVisual3D = new InstancedMeshGeometryVisual3D(meshGeometry3D); instancedMeshGeometryVisual3D.InstancesData = instancedData; // When we use transparency, we also need to set UseAlphaBlend to true instancedMeshGeometryVisual3D.UseAlphaBlend = useTransparency; // If we would only change the InstancedData we would need to call Update method (but here this is not needed because we have set the data for the first time) //_instancedGeometryVisual3D.Update(); ObjectsPlaceholder.Children.Clear(); ObjectsPlaceholder.Children.Add(instancedMeshGeometryVisual3D); // Update statistics: //PositionsPerMeshTextBlock.Text = string.Format("Positions per mesh: {0:#,##0}", meshGeometry3D.Positions.Count); TotalTextBlock.Text = string.Format("Total positions: {0:#,##0} * {1:#,##0} = {2:#,##0}", meshGeometry3D.Positions.Count, 20 * 20 * selectedInstancesYCount, meshGeometry3D.Positions.Count * selectedInstancesYCount * 20 * 20); }
private void CreateArrows() { if (DesignerProperties.GetIsInDesignMode(this)) { return; } try { Mouse.OverrideCursor = Cursors.Hand; MainViewport.Children.Clear(); var selectedArrowsNumber = GetSelectedArrowsNumber(); _xCount = selectedArrowsNumber; _yCount = selectedArrowsNumber; var sphereVisual3D = new SphereVisual3D() { CenterPosition = new Point3D(0, 0, 0), Radius = 10, Material = new DiffuseMaterial(Brushes.Gold) }; _sphereTranslate = new TranslateTransform3D(_sphereStartPosition.ToWpfVector3D()); sphereVisual3D.Transform = _sphereTranslate; MainViewport.Children.Add(sphereVisual3D); _instanceData = new InstanceData[_xCount * _yCount]; UpdateInstanceData(); var arrowMesh3D = new Ab3d.Meshes.ArrowMesh3D(new Point3D(0, 0, 0), new Point3D(1, 0, 0), 1.0 / 15.0, 2.0 / 15.0, 45, 10, false).Geometry; _instancedMeshGeometryVisual3D = new InstancedMeshGeometryVisual3D(arrowMesh3D); _instancedMeshGeometryVisual3D.InstancesData = _instanceData; MainViewport.Children.Add(_instancedMeshGeometryVisual3D); Camera1.Refresh(); // This will regenerate camera light if it was removed with MainViewport.Children.Clear() TotalTextBlock.Text = string.Format(System.Globalization.CultureInfo.InvariantCulture, "Total positions: {0:#,###}; total triangles: {1:#,###}", _xCount * _yCount * _instancedMeshGeometryVisual3D.MeshGeometry3D.Positions.Count, _xCount * _yCount * _instancedMeshGeometryVisual3D.MeshGeometry3D.TriangleIndices.Count / 3); } finally { Mouse.OverrideCursor = null; } }
private InstancedMeshGeometryVisual3D AddInstancedTubePath(Point3DCollection spiralPositionCollection, Color4 tubeColor) { // Setup InstanceData var instanceData = new InstanceData[spiralPositionCollection.Count]; // Convert to list of Vector3 var dxCurvePositions = spiralPositionCollection.Select(p => p.ToVector3()).ToList(); // NOTE: // When a tube path is created from a lot of positions, // then it is worth to transform the following loop into Parallel.For loop. var startPosition = dxCurvePositions[0]; for (int i = 1; i < dxCurvePositions.Count; i++) { var endPosition = dxCurvePositions[i]; var direction = endPosition - startPosition; var length = direction.Length(); // length will be used for x scale var scale = new Vector3(length, 1, 1); //direction.Normalize(); // Because we already have length, we can quickly normalize with simply dividing by length direction /= length; instanceData[i].World = Common.MatrixUtils.GetMatrixFromNormalizedDirection(direction, startPosition, scale); instanceData[i].DiffuseColor = Color4.White; startPosition = endPosition; } // Create tube mesh with normalized radius (=1) and from (0,0,0) to (1,0,0). // This mesh is then transformed to connect positions along the path var tubeLineMesh3D = new Ab3d.Meshes.TubeLineMesh3D(startPosition: new Point3D(0, 0, 0), endPosition: new Point3D(1, 0, 0), radius: 1, segments: 8, generateTextureCoordinates: false).Geometry; // Create InstancedMeshGeometryVisual3D var instancedMeshGeometryVisual3D = new InstancedMeshGeometryVisual3D(tubeLineMesh3D); instancedMeshGeometryVisual3D.InstancesData = instanceData; // Set IsSolidColorMaterial to render tube instances with solid color without any shading based on lighting instancedMeshGeometryVisual3D.IsSolidColorMaterial = true; // Add instancedMeshGeometryVisual3D to the scene MainViewport.Children.Add(instancedMeshGeometryVisual3D); return(instancedMeshGeometryVisual3D); }
private void DXEngineTestingRadioButton_OnClick(object sender, RoutedEventArgs e) { _useDXEngineHitTesting = true; // If _instancedMeshGeometryVisual3D is null after the next frame is rendered, // the CreateScene method with _useDXEngineHitTesting parameter will be called. // This way the scene will be immediately cleared and when this will be show a new scene can be created. _instancedMeshGeometryVisual3D = null; ObjectsPlaceholder.Children.Clear(); }
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(); }
private void CreateInstances() { // Load standard Stanford Bunny model (res3) with 11533 position var meshGeometry3D = LoadMeshFromObjFile("bun_zipper_res3.obj"); var bounds = meshGeometry3D.Bounds; double diagonalSize = Math.Sqrt(bounds.SizeX * bounds.SizeX + bounds.SizeY * bounds.SizeY + bounds.SizeZ * bounds.SizeZ); var modelScaleFactor = 20 / diagonalSize; // Scale model so that its diagonal is 20 units big // The following method prepare InstanceData array with data for each instance (WorldMatrix and Color) InstanceData[] instancedData = CreateInstancesData(new Point3D(0, 25, 0), new Size3D(100, 60, 100), (float)modelScaleFactor, 6, 4, 6, useTransparency: false); // Create InstancedGeometryVisual3D with selected meshGeometry and InstancesData _instancedMeshGeometryVisual3D = new InstancedMeshGeometryVisual3D(meshGeometry3D); _instancedMeshGeometryVisual3D.InstancesData = instancedData; ObjectsPlaceholder.Children.Clear(); ObjectsPlaceholder.Children.Add(_instancedMeshGeometryVisual3D); }
private void CreateInstancedTubePath() { // Create curve through those points var controlPoints = new Point3D[] { new Point3D(-200, 50, 150), new Point3D(0, 50, 20), new Point3D(150, 50, 0), new Point3D(150, 50, 200), new Point3D(250, 50, 200) }; // To create curve through specified points we must first convert the points into a bezierCurve (curve that has tangents defined for each point). // The curve is created with 10 points per segments - 10 points between two control points. var bezierCurve = Ab3d.Utilities.BezierCurve.CreateFromCurvePositions(controlPoints); var curvePositions = bezierCurve.CreateBezierCurve(positionsPerSegment: 10); // Convert Point3D to Vector3 var dxCurvePositions = curvePositions.Select(p => p.ToVector3()).ToList(); // Setup InstanceData var instanceData = new InstanceData[curvePositions.Count]; // NOTE: // When a tube path is created from a lot of positions, // then it is worth to transform the following loop into Parallel.For loop. var startPosition = dxCurvePositions[0]; for (int i = 1; i < dxCurvePositions.Count; i++) { var endPosition = dxCurvePositions[i]; var direction = endPosition - startPosition; var length = direction.Length(); // length will be used for x scale var scale = new Vector3(length, 1, 1); //direction.Normalize(); // Because we already have length, we can quickly normalize with simply dividing by length direction /= length; instanceData[i].World = Common.MatrixUtils.GetMatrixFromNormalizedDirection(direction, startPosition, scale); instanceData[i].DiffuseColor = Color4.White; startPosition = endPosition; } // Create tube mesh with normalized radius (=1) and from (0,0,0) to (1,0,0). // This mesh is then transformed to connect positions along the path var tubeLineMesh3D = new Ab3d.Meshes.TubeLineMesh3D(startPosition: new Point3D(0, 0, 0), endPosition: new Point3D(1, 0, 0), radius: 1, segments: 8, generateTextureCoordinates: false).Geometry; // Create InstancedMeshGeometryVisual3D var instancedMeshGeometryVisual3D = new InstancedMeshGeometryVisual3D(tubeLineMesh3D); instancedMeshGeometryVisual3D.InstancesData = instanceData; // Set IsSolidColorMaterial to render tube instances with solid color without any shading based on lighting instancedMeshGeometryVisual3D.IsSolidColorMaterial = true; // Add instancedMeshGeometryVisual3D to the scene MainViewport.Children.Add(instancedMeshGeometryVisual3D); }
public DXEventManager3DSample() { InitializeComponent(); Box1Visual3D.SetName("Box1Visual3D"); BoxesGroupVisual3D.SetName("BoxesGroupVisual3D"); Box2Visual3D.SetName("Box2Visual3D"); Box3Visual3D.SetName("Box3Visual3D"); Box4Visual3D.SetName("Box4Visual3D"); Line1.SetName("Line1"); Line2.SetName("Line2"); Rectangle1.SetName("Rectangle1"); var meshGeometry3D = new Ab3d.Meshes.SphereMesh3D(centerPosition: new Point3D(0, 0, 0), radius: 5, segments: 20, generateTextureCoordinates: false).Geometry; // The following method prepare InstanceData array with data for each instance (WorldMatrix and Color) InstanceData[] instancedData = DXEnginePerformance.InstancedMeshGeometry3DTest.CreateInstancesData(center: new Point3D(0, 0, 0), size: new Size3D(200, 50, 50), modelScaleFactor: 1, xCount: 10, yCount: 3, zCount: 3, useTransparency: false); // Create InstancedGeometryVisual3D with selected meshGeometry and InstancesData _instancedMeshGeometryVisual3D = new InstancedMeshGeometryVisual3D(meshGeometry3D); _instancedMeshGeometryVisual3D.InstancesData = instancedData; _instancedMeshGeometryVisual3D.SetName("InstancedMeshGeometryVisual3D"); _instancedMeshGeometryVisual3D.Transform = new TranslateTransform3D(0, 50, 0); MainViewport3D.Children.Add(_instancedMeshGeometryVisual3D); _selectedInstanceIndex = -1; var model3DGroup = new Model3DGroup(); model3DGroup.SetName("Model3DGroup"); var frozenModel3DGroup = new Model3DGroup(); frozenModel3DGroup.SetName("FrozenModel3DGroup"); var box1Material = new DiffuseMaterial(Brushes.LightPink); var box2Material = new DiffuseMaterial(Brushes.LightCyan); var boxModel3D = Ab3d.Models.Model3DFactory.CreateBox(new Point3D(-100, 2, 25), new Size3D(60, 4, 50), box2Material); frozenModel3DGroup.Children.Add(boxModel3D); var pyramidModel3D = Ab3d.Models.Model3DFactory.CreatePyramid(new Point3D(-100, 2, 20), new Size3D(20, 20, 20), box2Material); frozenModel3DGroup.Children.Add(pyramidModel3D); for (int i = 0; i < 5; i++) { var geometryModel3D = new GeometryModel3D(meshGeometry3D, box1Material); geometryModel3D.Transform = new TranslateTransform3D(-130 + i * 15, 5, 80); geometryModel3D.SetName("GroupedSphere_" + i.ToString()); model3DGroup.Children.Add(geometryModel3D); geometryModel3D = new GeometryModel3D(meshGeometry3D, box2Material); geometryModel3D.Transform = new TranslateTransform3D(-130 + i * 15, 10, 50); geometryModel3D.SetName("FrozenGroupedSphere_" + i.ToString()); frozenModel3DGroup.Children.Add(geometryModel3D); } frozenModel3DGroup.Freeze(); MainViewport3D.Children.Add(model3DGroup.CreateModelVisual3D()); MainViewport3D.Children.Add(frozenModel3DGroup.CreateModelVisual3D()); _dxEventManager3D = new DXEventManager3D(MainDXViewportView); RegisterEventSource(Box1Visual3D); RegisterEventSource(BoxesGroupVisual3D); RegisterEventSource(Line1); RegisterEventSource(Line2); RegisterEventSource(Rectangle1); RegisterEventSource(_instancedMeshGeometryVisual3D); RegisterEventSource(model3DGroup); RegisterEventSource(frozenModel3DGroup); // Prevent TransparentPlaneVisual3D to be used by hit-testing _dxEventManager3D.RegisterExcludedVisual3D(TransparentPlaneVisual3D); this.PreviewMouseMove += delegate(object sender, MouseEventArgs args) { var position = args.GetPosition(this); MousePositionTextBlock.Text = $"Mouse pos: {position.X:0} {position.Y:0}"; }; this.PreviewMouseDown += delegate(object sender, MouseButtonEventArgs e) { var position = e.GetPosition(this); if (position == _lastMouseDownPosition) { return; } System.Diagnostics.Debug.WriteLine("Mouse position: " + position.ToString()); _lastMouseDownPosition = position; }; // IMPORTANT: // It is very important to call Dispose method on DXSceneView after the control is not used any more (see help file for more info) this.Unloaded += (sender, args) => MainDXViewportView.Dispose(); }
private void CreateScene(bool useDXEngineHitTesting) { ObjectsPlaceholder.Children.Clear(); if (_dxEventManager3D != null) { _dxEventManager3D.ResetEventSources3D(); _dxEventManager3D = null; } if (_wpfEventManager != null) { _wpfEventManager.ResetEventSources3D(); _wpfEventManager = null; } if (_instancedMeshGeometryVisual3D != null) { _instancedMeshGeometryVisual3D.Dispose(); } _stopwatch = new Stopwatch(); _stopwatch.Start(); Mouse.OverrideCursor = Cursors.Wait; // Create InstancedGeometryVisual3D _instancedMeshGeometryVisual3D = new InstancedMeshGeometryVisual3D(_instanceMeshGeometry3D); _instancedMeshGeometryVisual3D.InstancesData = _instancedData; // Setup hit testing if (useDXEngineHitTesting) { // Use DXEventManager3D from Ab3d.DXEngine - it has optimized hit testing for instanced objects _dxEventManager3D = new Ab3d.DirectX.Utilities.DXEventManager3D(MainDXViewportView); var visualEventSource3D = new Ab3d.DirectX.Utilities.VisualEventSource3D(_instancedMeshGeometryVisual3D); visualEventSource3D.MouseEnter += delegate(object sender, DirectX.Common.EventManager3D.Mouse3DEventArgs e) { var dxRayInstancedHitTestResult = e.RayHitResult as DXRayInstancedHitTestResult; if (dxRayInstancedHitTestResult != null) { ProcessMouseEnter(dxRayInstancedHitTestResult.HitInstanceIndex); } }; visualEventSource3D.MouseMove += delegate(object sender, DirectX.Common.EventManager3D.Mouse3DEventArgs e) { var dxRayInstancedHitTestResult = e.RayHitResult as DXRayInstancedHitTestResult; if (dxRayInstancedHitTestResult != null) { ProcessMouseMove(dxRayInstancedHitTestResult.HitInstanceIndex); } }; visualEventSource3D.MouseLeave += delegate(object sender, DirectX.Common.EventManager3D.Mouse3DEventArgs e) { ProcessMouseLeave(); }; _dxEventManager3D.RegisterEventSource3D(visualEventSource3D); } else { // // IMPORTANT: // // To make WPF hit testing work (also used by EventManager3D), you need to set the IsWpfHitTestVisible to true. // This increases initialization time because WPF objects needs to be created for each instance, but this makes the WPF hit testing work. _instancedMeshGeometryVisual3D.IsWpfHitTestVisible = true; _wpfEventManager = new Ab3d.Utilities.EventManager3D(MainViewport); // Because Viewport3D is actually not shown, we need to specify different WPF's object for the source of mouse events - this could be MainDXViewportView or even better a parent Border _wpfEventManager.CustomEventsSourceElement = MainDXViewportView; var visualEventSource3D = new Ab3d.Utilities.VisualEventSource3D(_instancedMeshGeometryVisual3D); visualEventSource3D.MouseEnter += delegate(object sender, Mouse3DEventArgs e) { if (e.RayHitResult == null || e.RayHitResult.ModelHit == null) { return; // This should not happen, but it is safer to have this check anyway } // Get instance index of the hit object int hitInstanceIndex = GetHitInstanceIndex(e.RayHitResult); ProcessMouseEnter(hitInstanceIndex); }; visualEventSource3D.MouseMove += delegate(object sender, Mouse3DEventArgs e) { if (e.RayHitResult == null || e.RayHitResult.ModelHit == null) { return; // This should not happen, but it is safer to have this check anyway } // Get instance index of the hit object int hitInstanceIndex = GetHitInstanceIndex(e.RayHitResult); ProcessMouseMove(hitInstanceIndex); }; visualEventSource3D.MouseLeave += delegate(object sender, Mouse3DEventArgs e) { ProcessMouseLeave(); }; _wpfEventManager.RegisterEventSource3D(visualEventSource3D); } ObjectsPlaceholder.Children.Add(_instancedMeshGeometryVisual3D); Mouse.OverrideCursor = null; // If we would only change the InstancedData we would need to call Update method (but here this is not needed because we have set the data for the first time) //_instancedGeometryVisual3D.Update(); }
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); }