// Create a yellow sphere that will represent the light private void CreateLightSphere() { _lightTransform = new TranslateTransform3D(300, 80, 0); var lightSphere = new Ab3d.Visuals.SphereVisual3D(); lightSphere.CenterPosition = new Point3D(0, 0, 0); lightSphere.Radius = 8; lightSphere.Transform = _lightTransform; var materialGroup = new MaterialGroup(); materialGroup.Children.Add(new DiffuseMaterial(Brushes.Black)); materialGroup.Children.Add(new EmissiveMaterial(Brushes.Yellow)); lightSphere.Material = materialGroup; MainDXViewportView.Viewport3D.Children.Add(lightSphere); UpdateLightSpherePosition(); }
private void UpdateClosestLine() { if (_lineSelectorData == null || _lineSelectorData.Count == 0) { return; } if (_isCameraChanged) { // Each time camera is changed, we need to call CalculateScreenSpacePositions method. // This will update the 2D screen positions of the 3D lines. // IMPORTANT: // Before calling CalculateScreenSpacePositions it is highly recommended to call Refresh method on the camera. Camera1.Refresh(); if (MultiThreadedCheckBox.IsChecked ?? false) { // This code demonstrates how to use call CalculateScreenSpacePositions from multiple threads. // This significantly improves performance when many 3D lines are used (thousands) // but is not needed when using only a few lines (as in this demo). // // When calling CalculateScreenSpacePositions we need to prepare all the data // from WPF properties before calling the method because those properties // are not accessible from the other thread. // We need worldToViewportMatrix and // the _lineSelectorData[i].Camera and _lineSelectorData[i].UsedLineThickness need to be set // (in this sample they are set in the LineSelectorData constructor). var worldToViewportMatrix = new Matrix3D(); bool isWorldToViewportMatrixValid = Camera1.GetWorldToViewportMatrix(ref worldToViewportMatrix, forceMatrixRefresh: false); if (isWorldToViewportMatrixValid) { Parallel.For(0, _lineSelectorData.Count, i => _lineSelectorData[i].CalculateScreenSpacePositions(ref worldToViewportMatrix, transform: null)); } } else { for (var i = 0; i < _lineSelectorData.Count; i++) { _lineSelectorData[i].CalculateScreenSpacePositions(Camera1); } } _isCameraChanged = false; } // Now we can call the GetClosestDistance method. // This method calculates the closest distance from the _lastMousePosition to the line that was used to create the LineSelectorData. // GetClosestDistance also sets the LastDistance, LastLinePositionIndex properties on the LineSelectorData. if (MultiThreadedCheckBox.IsChecked ?? false) { Parallel.For(0, _lineSelectorData.Count, i => _lineSelectorData[i].GetClosestDistance(_lastMousePosition)); } else { for (var i = 0; i < _lineSelectorData.Count; i++) { _lineSelectorData[i].GetClosestDistance(_lastMousePosition); } } // Get the closest line IEnumerable <LineSelectorData> usedLineSelectors; // If we limit the distance of the specified position to the line, then we can filter all the line with Where if (_maxSelectionDistance >= 0) { usedLineSelectors = _lineSelectorData.Where(l => l.LastDistance <= _maxSelectionDistance).ToList(); } else { usedLineSelectors = _lineSelectorData; } List <LineSelectorData> orderedLineSelectors; if (OrderByDistanceCheckBox.IsChecked ?? false) { // Order by camera distance orderedLineSelectors = usedLineSelectors.OrderBy(l => l.LastDistanceFromCamera).ToList(); } else { // Order by distance to the specified position orderedLineSelectors = usedLineSelectors.OrderBy(l => l.LastDistance).ToList(); } // Get the closest LineSelectorData LineSelectorData closestLineSelector; if (orderedLineSelectors.Count > 0) { closestLineSelector = orderedLineSelectors[0]; } else { closestLineSelector = null; } // It is possible to get the positions of the line segment that is closest to the mouse position //var closestPolyLine = (PolyLineVisual3D)closestLineSelector.LineVisual; //Point3D firstSegmentPosition = closestPolyLine.Positions[closestLineSelector.LastLinePositionIndex]; //Point3D secondSegmentPosition = closestPolyLine.Positions[closestLineSelector.LastLinePositionIndex + 1]; // To get the actual position on the line that is closest to the mouse position, use the LastClosestPositionOnLine //closestLineSelector.LastClosestPositionOnLine; // The closest position on the line is shown with a SphereVisual3D if (_closestPositionSphereVisual3D == null) { _closestPositionSphereVisual3D = new SphereVisual3D() { Radius = 2, Material = new DiffuseMaterial(Brushes.Red) }; MainViewport.Children.Add(_closestPositionSphereVisual3D); } if (closestLineSelector == null) { ClosestDistanceValue.Text = ""; LineSegmentIndexValue.Text = ""; _closestPositionSphereVisual3D.IsVisible = false; } else { ClosestDistanceValue.Text = string.Format("{0:0.0}", closestLineSelector.LastDistance); LineSegmentIndexValue.Text = closestLineSelector.LastLinePositionIndex.ToString(); _closestPositionSphereVisual3D.CenterPosition = closestLineSelector.LastClosestPositionOnLine; _closestPositionSphereVisual3D.IsVisible = true; } // Show the closest line as red if (!ReferenceEquals(_lastSelectedLineSelector, closestLineSelector)) { if (_lastSelectedLineSelector != null) { _lastSelectedLineSelector.LineVisual3D.LineColor = _savedLineColor; } if (closestLineSelector != null) { _savedLineColor = closestLineSelector.LineVisual3D.LineColor; closestLineSelector.LineVisual3D.LineColor = Colors.Red; } _lastSelectedLineSelector = closestLineSelector; } }
private void CreateScene(Viewport3D parentViewport3D, double sphereRadius, double depthBias, TargetPositionCamera targetPositionCamera, bool showSphere) { parentViewport3D.Children.Clear(); if (showSphere) { var sphereVisual3D = new Ab3d.Visuals.SphereVisual3D() { CenterPosition = new Point3D(0, 0, 0), Radius = sphereRadius, Segments = 10, Material = new DiffuseMaterial(Brushes.SkyBlue), UseCachedMeshGeometry3D = false // This will create a new MeshGeometry3D and will not use the shared MeshGeometry3D with radius = 1 }; parentViewport3D.Children.Add(sphereVisual3D); var sphereMesh = ((GeometryModel3D)sphereVisual3D.Content).Geometry as MeshGeometry3D; var sphereLinePositions = CollectWireframeLinePositions(sphereMesh); var multiLineVisual3D = new Ab3d.Visuals.MultiLineVisual3D() { Positions = sphereLinePositions, LineThickness = 0.5, LineColor = Colors.Black }; // To specify line depth bias to the Ab3d.PowerToys line Visual3D objects, // we use SetDXAttribute extension method and use LineDepthBias as DXAttributeType // NOTE: This can be used only before the Visual3D is created by DXEngine. // If you want to change the line bias after the object has been rendered, use the SetDepthBias method (defined below) multiLineVisual3D.SetDXAttribute(DXAttributeType.LineDepthBias, depthBias); // It would be also possible to set the depth with changing the DepthBias on the WpfWireframeVisual3DNode. // This is done with using the SetDepthBias method //SetDepthBias(dxViewportView, wireframeVisual3D, depthBias); parentViewport3D.Children.Add(multiLineVisual3D); _shownLineVisual3D = multiLineVisual3D; } else { if (_sampleModel == null) { var readerObj = new Ab3d.ReaderObj(); _sampleModel = readerObj.ReadModel3D(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Resources\Models\Teapot.obj"), null, new DiffuseMaterial(Brushes.SkyBlue)); _sampleModel.Freeze(); } double readObjectRadius = Math.Sqrt(_sampleModel.Bounds.SizeX * _sampleModel.Bounds.SizeX + _sampleModel.Bounds.SizeZ + _sampleModel.Bounds.SizeZ) / 2; double scaleFactor = sphereRadius / readObjectRadius; var finalModel = new Model3DGroup(); finalModel.Children.Add(_sampleModel); finalModel.Transform = new ScaleTransform3D(scaleFactor, scaleFactor, scaleFactor); finalModel.Freeze(); var wireframeVisual3D = new WireframeVisual3D() { OriginalModel = finalModel, WireframeType = WireframeVisual3D.WireframeTypes.WireframeWithOriginalSolidModel, UseModelColor = false, LineColor = Colors.Black, LineThickness = 0.5 }; // To specify line depth bias to the WireframeVisual3D, // we use SetDXAttribute extension method and use LineDepthBias as DXAttributeType wireframeVisual3D.SetDXAttribute(DXAttributeType.LineDepthBias, depthBias); // It would be also possible to set the depth with changing the DepthBias on the WpfWireframeVisual3DNode. // This is done with using the SetDepthBias method //SetDepthBias(dxViewportView, wireframeVisual3D, depthBias); parentViewport3D.Children.Add(wireframeVisual3D); _shownLineVisual3D = wireframeVisual3D; } _previousCameraDistance = sphereRadius * 4; targetPositionCamera.Distance = _previousCameraDistance; targetPositionCamera.Offset = new Vector3D(0, sphereRadius * 0.4, 0); }
private void CreateTestModels() { _rootModelVisual3D = new ModelVisual3D(); MainViewport3D.Children.Add(_rootModelVisual3D); // SphereVisual3D var 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); var modelVisual3D = new ModelVisual3D() { Content = teapotModel }; teapotModel.SetName("teapot Model3D"); modelVisual3D.SetName("teapot ModelVisual3D"); _rootModelVisual3D.Children.Add(modelVisual3D); // 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); var 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() }; var meshObjectNode = new Ab3d.DirectX.MeshObjectNode(dxMeshGeometry3D, standardMaterial); _disposables.Add(dxMeshGeometry3D); _disposables.Add(meshObjectNode); var sceneNodeVisual3D = new SceneNodeVisual3D(meshObjectNode); sceneNodeVisual3D.SetName("SceneNodeVisual3D"); _rootModelVisual3D.Children.Add(sceneNodeVisual3D); }