protected Section3DChartBase() { border.Color = DefaultColor; Material material = new DiffuseMaterial { Brush = new SolidColorBrush(Color.FromArgb(0x7F, 0x4C, 0x88, 0xFF)) }; material.Freeze(); billboard.Material = material; billboard.BackMaterial = material; Children.Add(billboard); Children.Add(border); UpdateUI(); }
protected Viewport2DBillboardBase() { Material material = new DiffuseMaterial(Brushes.White); Viewport2DVisual3D.SetIsVisualHostMaterial(material, true); material.Freeze(); viewport2DVisual.Material = material; Children.Add(viewport2DVisual); meshGeometry.TextureCoordinates.Add(new Point(0, 1)); meshGeometry.TextureCoordinates.Add(new Point(1, 1)); meshGeometry.TextureCoordinates.Add(new Point(0, 0)); meshGeometry.TextureCoordinates.Add(new Point(1, 0)); meshGeometry.TriangleIndices.Add(0); meshGeometry.TriangleIndices.Add(1); meshGeometry.TriangleIndices.Add(3); meshGeometry.TriangleIndices.Add(0); meshGeometry.TriangleIndices.Add(3); meshGeometry.TriangleIndices.Add(2); viewport2DVisual.Geometry = meshGeometry; }
private void UpdateUI() { Children.Clear(); var grid = GridSource; if (grid == null) return; double sphereRadius = SphereRadius; Material sphereMaterial = new DiffuseMaterial(Brushes.Cyan); sphereMaterial.Freeze(); for (int k = 0; k < grid.Depth; k++) { int kLocal = k; Dispatcher.BeginInvoke(() => { for (int i = 0; i < grid.Width; i++) { for (int j = 0; j < grid.Height; j++) { Point3D position = grid.Grid[i, j, kLocal]; Sphere sphere = new Sphere { Radius = sphereRadius, Center = position, Material = sphereMaterial, Slices = 4, Stacks = 2 }; Children.Add(sphere); } } }, DispatcherPriority.Background); } }
void UpdateShadow() { if (substance == null) return; if (style == null) return; Thread.Sleep(300); // Black material DiffuseMaterial material = new DiffuseMaterial(Brushes.Black); material.Freeze(); // Create molecules ModelVisual3D container = new ModelVisual3D(); foreach (Data.Molecule molecule in substance.Molecules) { foreach (Data.Atom atom in molecule.Atoms) { if (style.ColorStyle.ColorScheme[atom.Element].Diffuse.A < 5) continue; Sphere sphere = new Sphere(); sphere.Material = material; sphere.Radius = Atom.GetAtomRadius(atom, style.GeometryStyle); sphere.Center = atom.Position; container.Children.Add(sphere); } double bondRadius = Bond.GetBondRadius(style.GeometryStyle); foreach (Data.Bond bond in molecule.Bonds) { if (style.ColorStyle.UseSingleBondMaterial) { if (style.ColorStyle.BondMaterial.Diffuse.A < 5) continue; } else if (style.ColorStyle.ColorScheme[bond.Begin.Element].Diffuse.A < 5 || style.ColorStyle.ColorScheme[bond.End.Element].Diffuse.A < 5) continue; Cylinder cylinder = new Cylinder(bond.Begin.Position, bond.End.Position, bondRadius); cylinder.Material = material; container.Children.Add(cylinder); } #region Build approximation of ribbon double radius = 0.45; foreach (Data.Chain chain in molecule.Chains) { for (int i = 0; i < chain.Residues.Count; i++) { if (chain.Residues[i].GetStructureType() == SecondaryStructureType.Helix) if (style.GeometryStyle.HelixHeight < 0.05 || style.GeometryStyle.HelixWidth < 0.05) continue; else radius = Residue.HelixWidth * ((style.GeometryStyle.HelixHeight + style.GeometryStyle.HelixWidth) / 2.0); if (chain.Residues[i].GetStructureType() == SecondaryStructureType.Sheet) if (style.GeometryStyle.SheetHeight < 0.05 || style.GeometryStyle.SheetWidth < 0.05) continue; else radius = Residue.SheetWidth * ((style.GeometryStyle.SheetHeight + style.GeometryStyle.SheetWidth) / 2.0); if (chain.Residues[i].GetStructureType() == SecondaryStructureType.NotDefined) if (style.GeometryStyle.TurnHeight < 0.05 || style.GeometryStyle.TurnWidth < 0.05) continue; else radius = Residue.TurnWidth * ((style.GeometryStyle.TurnHeight + style.GeometryStyle.TurnWidth) / 2.0); if (chain.Residues[i].GetStructureType() == SecondaryStructureType.Helix && style.ColorStyle.HelixMaterial.Diffuse.A < 5) continue; if (chain.Residues[i].GetStructureType() == SecondaryStructureType.Sheet && style.ColorStyle.SheetMaterial.Diffuse.A < 5) continue; if (chain.Residues[i].GetStructureType() == SecondaryStructureType.NotDefined && style.ColorStyle.TurnMaterial.Diffuse.A < 5) continue; Data.Atom alfaCarbon = chain.Residues[i].AlfaCarbon; if (alfaCarbon != null) { Point3D begin = alfaCarbon.Position; alfaCarbon = null; for (int j = i + 1; j < chain.Residues.Count; j++) { alfaCarbon = chain.Residues[j].AlfaCarbon; if (alfaCarbon != null) break; } if (alfaCarbon != null) { Point3D end = alfaCarbon.Position; Cylinder cylinder = new Cylinder(begin, end, radius); container.Children.Add(cylinder); } } } } #endregion } // Get bounding box Rect3D boundingBox = VisualTreeHelper.GetDescendantBounds(container); if (boundingBox.IsEmpty) { shadowRefreshStarted = false; return; } #region Render Shadow const double blurSize = 25; const int renderTargetWidth = 200; int renderTargetHeight = (int)(200.0 * (boundingBox.SizeX / boundingBox.SizeY)); RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap(renderTargetWidth, renderTargetHeight, 96, 96, PixelFormats.Pbgra32); Viewport3D shadowViewport3D = new Viewport3D(); Border border = new Border(); border.Padding = new Thickness(blurSize); border.Child = shadowViewport3D; // Change size of the visualizer border.Width = renderTargetBitmap.PixelWidth; border.Height = renderTargetBitmap.PixelHeight; border.Measure(new Size(renderTargetBitmap.PixelWidth, renderTargetBitmap.PixelHeight)); border.Arrange(new Rect(0, 0, renderTargetBitmap.PixelWidth, renderTargetBitmap.PixelHeight)); shadowViewport3D.Children.Add(container); // Create camera OrthographicCamera orthographicCamera = new OrthographicCamera(); #region Accomodate camera to fit content orthographicCamera.Position = new Point3D(boundingBox.Location.X + boundingBox.SizeX / 2.0, boundingBox.Location.Y, boundingBox.Location.Z + boundingBox.SizeZ / 2.0); orthographicCamera.LookDirection = new Vector3D(0, 1, 0); orthographicCamera.UpDirection = new Vector3D(-1, 0, 0); orthographicCamera.Width = boundingBox.SizeZ; #endregion orthographicCamera.NearPlaneDistance = 0; // Set the camera & correct lights shadowViewport3D.Camera = orthographicCamera; BlurEffect blurEffect = new BlurEffect(); blurEffect.Radius = blurSize; border.Effect = blurEffect; renderTargetBitmap.Render(border); renderTargetBitmap.Freeze(); #endregion // Invoke in main thread Dispatcher.BeginInvoke((Action) delegate { #region Create Plane Vector3D margin = new Vector3D(boundingBox.SizeX * 0.4, 0, boundingBox.SizeZ * 0.4); Point3D[] points = new Point3D[] { boundingBox.Location + new Vector3D(-margin.X, -margin.Y, -margin.Z), boundingBox.Location + new Vector3D(margin.X + boundingBox.SizeX, -margin.Y, -margin.Z), boundingBox.Location + new Vector3D(margin.X + boundingBox.SizeX, -margin.Y, margin.Z + boundingBox.SizeZ), boundingBox.Location + new Vector3D(-margin.X, -margin.Y, margin.Z + boundingBox.SizeZ) }; Polygon shadowPlane = new Polygon(); shadowPlane.Positions = points; shadowPlane.TextureCoordinates = new Point[] { new Point(0, 0), new Point(0, 1), new Point(1, 1), new Point(1, 0) }; #endregion shadowBrush.ImageSource = renderTargetBitmap; shadowBrush.Stretch = Stretch.Fill; shadowTargetOpacity = 0.8; shadowPlane.Material = new DiffuseMaterial(shadowBrush); shadowContainer.Children.Clear(); shadowContainer.Children.Add(shadowPlane); // Update shadow hash shadowRefreshStarted = false; }, DispatcherPriority.SystemIdle); }
static InteractiveVisual3D() { _defaultMaterialPropertyValue = new DiffuseMaterial(); _defaultMaterialPropertyValue.SetValue(InteractiveVisual3D.IsInteractiveMaterialProperty, true); _defaultMaterialPropertyValue.Freeze(); MaterialProperty = DependencyProperty.Register("Material", typeof(Material), typeof(InteractiveVisual3D), new PropertyMetadata(_defaultMaterialPropertyValue, new PropertyChangedCallback(OnMaterialPropertyChanged))); }
private void UpdateCurrentTile(PointCloudTile tile) { if (tile == null) return; List<PointCloudTile> tilesToLoad = new List<PointCloudTile>(); int pointsToLoad = 0; Model3DGroup emptyModelGroup = new Model3DGroup(); emptyModelGroup.Freeze(); bool isDirty = false; int radius = 2; int xMin = Math.Max(0, tile.Col - radius); int xMax = Math.Min(tile.Col + radius + 1, CurrentTileSource.TileSet.Cols); int yMin = Math.Max(0, tile.Row - radius); int yMax = Math.Min(tile.Row + radius + 1, CurrentTileSource.TileSet.Rows); for (int x = xMin; x < xMax; x++) { for (int y = yMin; y < yMax; y++) { PointCloudTile currentTile = CurrentTileSource.TileSet.GetTile(y, x); if (currentTile != null) { if (!m_loadedTiles.ContainsKey(currentTile)) { tilesToLoad.Add(currentTile); pointsToLoad += currentTile.PointCount; isDirty = true; } } } } PointCloudTile[] loadedTiles = m_loadedTiles.Keys.ToArray(); SortByDistanceFromTile(loadedTiles, tile); Array.Reverse(loadedTiles); // drop loaded tiles that are the farthest from the center int totalAllowedPoints = MAX_BUFFER_SIZE_BYTES / CurrentTileSource.PointSizeBytes; int loadedPoints = loadedTiles.Sum(t => t.PointCount); int potentialTotalPoints = loadedPoints + pointsToLoad; Dictionary<PointCloudTile, TileInfo3D> alteredTiles = new Dictionary<PointCloudTile, TileInfo3D>(); if (potentialTotalPoints > totalAllowedPoints) { int pointsToDrop = potentialTotalPoints - totalAllowedPoints; int i = 0; while (pointsToDrop > 0) { PointCloudTile currentTile = loadedTiles[i]; TileInfo3D tileInfo = m_tileInfo[currentTile]; GeometryModel3D model = m_loadedTiles[currentTile]; m_meshTileMap.Remove(model); m_loadedTiles.Remove(currentTile); //m_loadedTileBuffers.Remove(currentTile); // replace high-res tile with low-res geometry int modelIndex = tileInfo.Tile.ValidIndex; m_tileModelCollection[modelIndex] = tileInfo.LowResGeometry; // clear stitching m_stitchingModelCollection[modelIndex] = emptyModelGroup; tileInfo.ClearGeometry(); alteredTiles.Add(currentTile, tileInfo); pointsToDrop -= currentTile.PointCount; ++i; } } Jacere.Core.Geometry.Point3D centerOfMass = CurrentTileSource.CenterOfMass; PointCloudTile[] tilesToLoadArray = tilesToLoad.ToArray(); #warning sort so that disk reads are in order? or make a tile cache SortByDistanceFromTile(tilesToLoadArray, tile); foreach (PointCloudTile currentTile in tilesToLoadArray) { TileInfo3D tileInfo = m_tileInfo[currentTile]; CurrentTileSource.LoadTileGrid(currentTile, m_buffer, m_gridHighRes, m_quantizedGridHighRes); if (ENABLE_HEIGHT_EXAGGERATION) m_gridHighRes.Multiply(m_heightExaggerationFactor, (float)centerOfMass.Z); Jacere.Core.Geometry.Extent3D tileExtent = currentTile.Extent; MeshGeometry3D mesh = CurrentTileSource.GenerateMesh(m_gridHighRes, tileExtent); DiffuseMaterial material = new DiffuseMaterial(); if (USE_HIGH_RES_TEXTURE) { material.Brush = m_overviewTextureBrush; mesh.TextureCoordinates = MeshUtils.GeneratePlanarTextureCoordinates(mesh, m_overallCenteredExtent, MathUtils.ZAxis); } else { material.Brush = m_solidBrush; } material.Freeze(); GeometryModel3D geometryModel = new GeometryModel3D(mesh, material); geometryModel.Freeze(); // replace low-res tile with high-res geometry int modelIndex = tileInfo.Tile.ValidIndex; m_tileModelCollection[modelIndex] = geometryModel; // clear stitching m_stitchingModelCollection[modelIndex] = emptyModelGroup; tileInfo.UpdateGeometry(geometryModel, m_gridHighRes); alteredTiles.Add(currentTile, tileInfo); m_meshTileMap.Add(geometryModel, currentTile); m_loadedTiles.Add(currentTile, geometryModel); //m_loadedTileBuffers.Add(currentTile, inputBuffer); } // in the future, I could have a list of which tiles need to be checked for stitching updates // go through the stitching groups and replace any empty ones with the appropriate stitching if (ENABLE_STITCHING && isDirty) { PointCloudTile[] alteredTileArray = alteredTiles.Keys.ToArray(); foreach (PointCloudTile currentTile in alteredTileArray) { // this amount of clearing is excessive. I only want to clear one of the edges if (currentTile.Col < CurrentTileSource.TileSet.Cols - 1) { PointCloudTile adjacentTile = CurrentTileSource.TileSet.GetTile(currentTile.Row, currentTile.Col + 1); if (adjacentTile != null && m_tileInfo.ContainsKey(adjacentTile)) { TileInfo3D adjacentTileInfo = m_tileInfo[adjacentTile]; if (!alteredTiles.ContainsKey(adjacentTile)) alteredTiles.Add(adjacentTile, adjacentTileInfo); m_stitchingModelCollection[adjacentTileInfo.Tile.ValidIndex] = emptyModelGroup; adjacentTileInfo.UpdateStitching(null, null, TileStitchingEdge.Left); } } if (currentTile.Row < CurrentTileSource.TileSet.Rows - 1) { PointCloudTile adjacentTile = CurrentTileSource.TileSet.GetTile(currentTile.Row + 1, currentTile.Col); if (adjacentTile != null && m_tileInfo.ContainsKey(adjacentTile)) { TileInfo3D adjacentTileInfo = m_tileInfo[adjacentTile]; if (!alteredTiles.ContainsKey(adjacentTile)) alteredTiles.Add(adjacentTile, adjacentTileInfo); m_stitchingModelCollection[adjacentTileInfo.Tile.ValidIndex] = emptyModelGroup; adjacentTileInfo.UpdateStitching(null, null, TileStitchingEdge.Top); } } if (currentTile.Col < CurrentTileSource.TileSet.Cols - 1 && currentTile.Row < CurrentTileSource.TileSet.Rows - 1) { PointCloudTile adjacentTile = CurrentTileSource.TileSet.GetTile(currentTile.Row + 1, currentTile.Col + 1); if (adjacentTile != null && m_tileInfo.ContainsKey(adjacentTile)) { TileInfo3D adjacentTileInfo = m_tileInfo[adjacentTile]; if (!alteredTiles.ContainsKey(adjacentTile)) alteredTiles.Add(adjacentTile, adjacentTileInfo); m_stitchingModelCollection[adjacentTileInfo.Tile.ValidIndex] = emptyModelGroup; adjacentTileInfo.UpdateStitching(null, null, TileStitchingEdge.TopLeft); } } } foreach (KeyValuePair<PointCloudTile, TileInfo3D> kvp in alteredTiles) { int i = kvp.Value.Tile.ValidIndex; Model3DGroup stitchingGroup = m_stitchingModelCollection[i] as Model3DGroup; if (stitchingGroup.Children.Count == 0) { GeometryModel3D geometryModel = m_tileModelCollection[i] as GeometryModel3D; Model3DGroup newStitchingGroup = GenerateTileStitching(CurrentTileSource, kvp.Value); if (newStitchingGroup.Children.Count > 0) m_stitchingModelCollection[i] = newStitchingGroup; } } //for (int i = 0; i < m_stitchingModelCollection.Count; i++) //{ // Model3DGroup stitchingGroup = m_stitchingModelCollection[i] as Model3DGroup; // // this is an incorrect condition, but it won't be apparent until I get multi-res stitching // if (stitchingGroup.Children.Count < 3) // { // GeometryModel3D geometryModel = m_tileModelCollection[i] as GeometryModel3D; // PointCloudTile currentTile = m_meshTileMap[geometryModel]; // TileInfo3D currentTileInfo = m_tileInfo[currentTile]; // Model3DGroup newStitchingGroup = GenerateTileStitching(CurrentTileSource, currentTileInfo); // if (newStitchingGroup.Children.Count > 0) // m_stitchingModelCollection[i] = newStitchingGroup; // } //} } }
private void OnBackgroundDoWork(object sender, DoWorkEventArgs e) { PointCloudTileSource tileSource = e.Argument as PointCloudTileSource; Jacere.Core.Geometry.Extent3D extent = tileSource.Extent; m_overviewTextureBrush = new ImageBrush(tileSource.Preview.Image); m_overviewTextureBrush.ViewportUnits = BrushMappingMode.Absolute; m_overviewTextureBrush.Freeze(); m_overviewMaterial = new DiffuseMaterial(m_overviewTextureBrush); m_overviewMaterial.Freeze(); if (tileSource != null) { previewImageGrid.MouseMove -= OnViewportGridMouseMove; Action<string> logAction = value => Context.WriteLine(value); m_progressManager = new BackgroundWorkerProgressManager(m_backgroundWorker, e, logAction, null); m_gridDimensionLowRes = (ushort)Math.Sqrt(VERTEX_COUNT_FAST / tileSource.TileSet.ValidTileCount); //m_gridDimensionHighRes = (ushort)Math.Sqrt(VERTEX_COUNT_LARGE / tileSource.TileSet.ValidTileCount); m_gridDimensionHighRes = (ushort)(Math.Sqrt(tileSource.TileSet.Density.MedianTileCount) / 3); //m_gridDimensionLowRes = (ushort)20; //m_gridDimensionHighRes = (ushort)40; Jacere.Core.Geometry.Point3D centerOfMass = tileSource.CenterOfMass; m_overallCenteredExtent = new Rect3D(extent.MinX - extent.MidpointX, extent.MinY - extent.MidpointY, extent.MinZ - centerOfMass.Z, extent.RangeX, extent.RangeY, extent.RangeZ); // load tiles KeyValuePair<Grid<int>, Grid<float>> gridsLowRes = tileSource.GenerateGrid(m_gridDimensionLowRes); m_gridLowRes = gridsLowRes.Value; m_quantizedGridLowRes = gridsLowRes.Key; KeyValuePair<Grid<int>, Grid<float>> gridsHighRes = tileSource.GenerateGrid(m_gridDimensionHighRes); m_gridHighRes = gridsHighRes.Value; m_quantizedGridHighRes = gridsHighRes.Key; foreach (PointCloudTile tile in tileSource.TileSet) { tileSource.LoadTileGrid(tile, m_buffer, m_gridLowRes, m_quantizedGridLowRes); if (ENABLE_HEIGHT_EXAGGERATION) m_gridLowRes.Multiply(m_heightExaggerationFactor, (float)centerOfMass.Z); Jacere.Core.Geometry.Extent3D tileExtent = tile.Extent; MeshGeometry3D mesh = tileSource.GenerateMesh(m_gridLowRes, tileExtent); DiffuseMaterial material = new DiffuseMaterial(); if (USE_LOW_RES_TEXTURE) { material.Brush = m_overviewTextureBrush; mesh.TextureCoordinates = MeshUtils.GeneratePlanarTextureCoordinates(mesh, m_overallCenteredExtent, MathUtils.ZAxis); } else { material.Brush = m_solidBrush; } material.Freeze(); GeometryModel3D geometryModel = new GeometryModel3D(mesh, material); geometryModel.Freeze(); TileInfo3D tileInfo = new TileInfo3D(tile, geometryModel, m_gridLowRes); m_tileInfo.Add(tile, tileInfo); // add mappings m_meshTileMap.Add(geometryModel, tile); //m_lowResMap.Add(tile, geometryModel); if (!m_progressManager.Update(tile, geometryModel)) break; } //// test //foreach (double level in new double[] { centerOfMass.Z }) //{ // Grid<float> grid0 = new Grid<float>(20, 20, extent, false); // grid0.FillVal = (float)level; // grid0.Reset(); // grid0.FillVal = float.MinValue; // MeshGeometry3D mesh0 = tileSource.GenerateMesh(grid0, extent); // DiffuseMaterial material0 = new DiffuseMaterial(m_solidBrush); // material0.Freeze(); // GeometryModel3D geometryModel0 = new GeometryModel3D(mesh0, material0); // geometryModel0.Freeze(); // m_progressManager.Update(1.0f, geometryModel0); //} if (ENABLE_STITCHING) { int validStitchingIndex = 0; foreach (PointCloudTile tile in tileSource.TileSet) { TileInfo3D tileInfo = m_tileInfo[tile]; Model3DGroup stitchingGroup = GenerateTileStitching(tileSource, tileInfo); if (stitchingGroup != null) ++validStitchingIndex; if (!m_progressManager.Update(1.0f, stitchingGroup)) break; } } } }
private void BuildTextures(OptFile opt) { this.nullTexture = null; this.textures = null; if (opt == null) { return; } this.nullTexture = new DiffuseMaterial(Brushes.White); this.textures = new Dictionary<string, Material>(); foreach (var texture in opt.Textures.Values) { var image = CreateTexture(opt, texture.Name); image.Freeze(); var brush = new ImageBrush(image) { ViewportUnits = BrushMappingMode.Absolute, Stretch = Stretch.Fill, TileMode = TileMode.Tile, Opacity = texture.HasAlpha ? 0.999 : 1.0 }; brush.Freeze(); var material = new DiffuseMaterial(brush); material.Freeze(); this.textures.Add(texture.Name, material); } }
internal static Material GetMaterial(bool isReflective, Color color) { if (isReflective) { DiffuseMaterial litMaterial = new DiffuseMaterial(new SolidColorBrush(color)); litMaterial.Freeze(); return litMaterial; } else { return UtilityWPF.GetUnlitMaterial(color); } }
private Model3D ConvertVisualToModel3D(Visual visual, ref double z) { Model3D model = null; Rect bounds = VisualTreeHelper.GetContentBounds(visual); Viewport3D viewport = visual as Viewport3D; if (viewport != null) { bounds = new Rect(viewport.RenderSize); } if (this.includeEmptyVisuals) { bounds.Union(VisualTreeHelper.GetDescendantBounds(visual)); } if (!bounds.IsEmpty && bounds.Width > 0 && bounds.Height > 0) { MeshGeometry3D mesh = new MeshGeometry3D(); mesh.Positions.Add(new Point3D(bounds.Left, bounds.Top, z)); mesh.Positions.Add(new Point3D(bounds.Right, bounds.Top, z)); mesh.Positions.Add(new Point3D(bounds.Right, bounds.Bottom, z)); mesh.Positions.Add(new Point3D(bounds.Left, bounds.Bottom, z)); mesh.TextureCoordinates.Add(new Point(0, 0)); mesh.TextureCoordinates.Add(new Point(1, 0)); mesh.TextureCoordinates.Add(new Point(1, 1)); mesh.TextureCoordinates.Add(new Point(0, 1)); mesh.Normals.Add(new Vector3D(0, 0, 1)); mesh.Normals.Add(new Vector3D(0, 0, 1)); mesh.Normals.Add(new Vector3D(0, 0, 1)); mesh.Normals.Add(new Vector3D(0, 0, 1)); mesh.TriangleIndices = new Int32Collection(new int[] { 0, 1, 2, 2, 3, 0 }); mesh.Freeze(); Brush brush = this.MakeBrushFromVisual(visual, bounds); DiffuseMaterial material = new DiffuseMaterial(brush); material.Freeze(); model = new GeometryModel3D(mesh, material); ((GeometryModel3D)model).BackMaterial = material; z -= 1; } int childrenCount = VisualTreeHelper.GetChildrenCount(visual); if (childrenCount > 0) { Model3DGroup group = new Model3DGroup(); if (model != null) { group.Children.Add(model); } for (int i = 0; i < childrenCount; i++) { Visual childVisual = VisualTreeHelper.GetChild(visual, i) as Visual; if (childVisual != null) { Model3D childModel = this.ConvertVisualToModel3D(childVisual, ref z); if (childModel != null) { group.Children.Add(childModel); } } } model = group; } if (model != null) { Transform transform = VisualTreeHelper.GetTransform(visual); Matrix matrix = (transform == null ? Matrix.Identity : transform.Value); Vector offset = VisualTreeHelper.GetOffset(visual); matrix.Translate(offset.X, offset.Y); if (!matrix.IsIdentity) { Matrix3D matrix3D = new Matrix3D(matrix.M11, matrix.M12, 0, 0, matrix.M21, matrix.M22, 0, 0, 0, 0, 1, 0, matrix.OffsetX, matrix.OffsetY, 0, 1); Transform3D transform3D = new MatrixTransform3D(matrix3D); transform3D.Freeze(); model.Transform = transform3D; } model.Freeze(); } return model; }