IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Tracé de contour d'objet 3D : GeometryGroup


Sujet :

C#

  1. #1
    Membre à l'essai
    Profil pro
    Étudiant
    Inscrit en
    Août 2012
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2012
    Messages : 25
    Points : 11
    Points
    11
    Par défaut Tracé de contour d'objet 3D : GeometryGroup
    Bonjour,

    Je souhaiterais améliorer les performances de tracé d'un contour d'un objet 3D.

    Cela consistait au début à relier les points composant un objet 3 par 3 puis à les ranger dans une Geometry à l'aide de la méthode Geometry.Combine(..,..,GeometryCombineMode.Union). Il est cependant précisé sur MSDN que cette fonction est fortement déconseillée pour les unions car "peut nécessiter beaucoup d'UC". J'ai donc essayé de procéder comme ils le suggèrent, à l'aide de GeometryGroup. La performance est vraiment excellente (division du temps de calculs par 10 !), seulement voilà.. je n'obtient pas un contour : Nom : Contour mal tracé 1.jpg
Affichages : 685
Taille : 3,5 Ko
    Au lieu de ca : Nom : Contour bien tracé 1.jpg
Affichages : 677
Taille : 3,2 Ko

    En fait j'ai cru comprendre que l'avantage du Combine(Union) était que ca supprimait les intersections ! Pour rappel, les opérations élémentaires : Nom : geometry.jpg
Affichages : 686
Taille : 67,6 Ko

    J'ai bien essayé le Geometry.GetOulinedPathGeometry() sur chaque objet mais ca me donne un contour sur une face seulement, peu importe la rotation de l'objet. Ce n'est donc pas un vrai contour comme je souhaite : Nom : Contour GetOulinedPathGeometry.jpg
Affichages : 647
Taille : 3,4 Ko

    Auriez-vous une idée pour effectuer une opération similaire sans passer par un "combine"? En agissant sur le GeometryGroup ou en passant par autre chose..

    Merci beaucoup !

  2. #2
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    bonjour mikeycast
    Chose promise ,chose due....Je n'ai pas bien compris mais un contour d'un objet 3D peut sous entendre 2 choses...
    1/ Un "vrai" contour 3D
    -c'est le convexhull
    2/un contour 2D
    -c'est la projection de l'objet 3D sur une surface plane ("son ombre" ) sur le ViewPort3D qui une est surface 2D....malgre le "3D" accole à son nom.
    Note au passage que nos yeux font un grand travail insoupconne d'interpretation de la profondeur de vue....
    Si c'est bien un contour 2D relatif au viewport3D que tu recherches voici les etapes:
    - Obtenir une instance GeneralTransform3DTo2D relatif au ViewPort3D du ModelVisual3D courant
    -Obtient instance du Transform3DGroup applique au GeomeryModel3D
    et qui sera applique au MeshGemotry3D
    Car une instance de Mesh est toujour definie en coord. locales du Mesh (n'est pas donc affectee par le Transform3DGroup du GeomeryModel3D).....

    3/Boucler sur les Positions du MeshGeomtry
    - Appliquer le TransformGroup à chaque Position locale du Mesh
    - Appliquer GeneralTransform3DTo2D qui renvoie un Point2D relatif au ViewPort pour chaque point ainsi transforme.....
    - Recuperer les nouvelles positions modifies dans un List <Point> pts (2D)
    et creer avec un Polygon qu'on dessine sur un canvas....
    bref voici un exemple code emballe dans un user control avec:
    -un "box cube"
    -un viewport3D
    -un canvas "layer" aligne sur le Viewport3D qui servira à tracer le contour 2D...à l'aide du class Polygon..
    -un slider qui fait tourner le "box" cube et un bouton GetContour pour mettre à jour le contour 2D trace sur le canvas.....lors d'une rotation....
    code behind .cs du usercontrol:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Windows.Media.Media3D;
    namespace WpTransform3Dto2D
    {
        /// <summary>
        /// Logique d'interaction pour UserControl3.xaml
        /// </summary>
        public partial class UserControlContour2D : UserControl
        {
            private List<Point> pts;
            Rect bounds2D;
            public UserControlContour2D()
            {
                InitializeComponent();
            }
     
            private void btnContour_Click(object sender, RoutedEventArgs e)
            {
                //refresh canvas overlay
                MyCanvasOverlay.Children.Clear();
                pts = new List<Point>();
     
     
                // Recupere GeneralTransform3DTo2D relatif au viewport du ModelVisual3D
                GeneralTransform3DTo2D tt = this.MyModel.TransformToAncestor(this.MyViewport);
     
                // Recupere instance Transform3DGroup  applique au GeometryModel3D
                // qui sera applique aux positions locales  mesh
                Transform3DGroup trans3D = (Transform3DGroup)this.MyGeomModel.Transform;
     
                // Bounding Box(cadre englobant) du ModelVisual3D
                bounds2D = this.MyModel.TransformToAncestor(this.MyViewport).TransformBounds(VisualTreeHelper.GetContentBounds(this.MyModel));
     
                // Dessine  Bounding Box 2D sur canvas overlay
                Rectangle MyRectangle = new Rectangle();
                MyRectangle.Stroke = Brushes.Blue;
                MyRectangle.Width = bounds2D.Width;
                MyRectangle.Height = bounds2D.Height;
                MyCanvasOverlay.Children.Add(MyRectangle);
                Canvas.SetLeft(MyRectangle, bounds2D.X);
                Canvas.SetTop(MyRectangle, bounds2D.Y);
     
     
     
     
                /* "contour" projete  du MeshGeometry3D
                 sur la vue 2D du ViewPort   */
     
                MeshGeometry3D mesh = (MeshGeometry3D)this.MyGeomModel.Geometry;
                Point3D ptOut3D;
                for (int j = 0; j <  mesh.Positions.Count; j++)
    			{
                   /* Applique le transformGroup au positions locales du Mesh */
                   if( trans3D.TryTransform(mesh.Positions[j],out ptOut3D)) 
                   {
     
                    /* Applique GeneralTransform3DTo2D et  renvoie un Point2D relatif 
                        au ViewPort pour chaque point positions*/  
     
                       pts.Add(tt.Transform(ptOut3D));
                   }
    			}
     
                // et  dessine pts grace à un polygone  
                Polygon myPolygon = GetPolygon(pts);
                myPolygon.Stroke = Brushes.Magenta;
                myPolygon.StrokeThickness = 4.0;
                MyCanvasOverlay.Children.Add(myPolygon);
     
            }
            private Polygon GetPolygon(List<Point> pts)
            {
                Polygon myPolygon = new Polygon();
     
                myPolygon.Points.Add(pts[0]); 
                for (int i = 1; i < pts.Count; i++)
                {
     
                        myPolygon.Points.Add(pts[i]);
     
     
     
                }
                return myPolygon;
            }
        }
    }
    code xaml du usercontrol:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
     
    <UserControl x:Class="WpTransform3Dto2D.UserControlContour2D"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:local="clr-namespace:WpTransform3Dto2D"
                >
        <UserControl.Resources>
            <local:GeometryGenerator x:Key="GeomGenerator"></local:GeometryGenerator>
        </UserControl.Resources>
     
        <StackPanel  >
            <DockPanel>
                <!-- Label Title. -->
                <Label 
                    DockPanel.Dock="Left"
                    FontSize="14" 
                    Foreground="Red" 
                    Content="Model: Cube"/>
                <!-- Button  Contour . -->
                <Button 
                    Name="btnContour"
                    FontSize="14" 
                    Foreground="Red" 
                    Content="Get Contour 2D Cube"
                    Click="btnContour_Click">
                </Button>
                <Slider 
                    DockPanel.Dock="Right" 
                    Name="rotationSlider"
                    Maximum="90"
                    Value="0">
                </Slider>
            </DockPanel>
            <!-- Viewport3D is the rendering surface. -->
            <Grid>
                <Viewport3D 
                    MinHeight="400"
                    MinWidth="540"
                    Name="MyViewport"
                    ClipToBounds="True">
                    <!-- Add a camera. -->
                    <Viewport3D.Camera>
                        <PerspectiveCamera 
                              x:Name="MyCamera"
    	                      FarPlaneDistance="100"
    	                      LookDirection="-11,-10,-9"
    	                      UpDirection="0,1,0"
    	                      NearPlaneDistance="10" 
    	                      Position="11,10,9" 
    	                      FieldOfView="25" />
                    </Viewport3D.Camera>
     
                    <!-- Add models. -->
                    <Viewport3D.Children>
                        <ModelVisual3D x:Name="MyModel" >
                            <ModelVisual3D.Content>
                                <Model3DGroup>
                                    <Model3DGroup.Children>
                                        <!-- Lights, MeshGeometry3D and DiffuseMaterial objects are added to the ModelVisual3D. -->
                                        <DirectionalLight Color="#FFFFFFFF" Direction="3,-4,5" />
     
                                        <!-- Define a red cube. -->
                                        <GeometryModel3D 
                                            x:Name="MyGeomModel"
                                            Geometry="{Binding
                                            Source={StaticResource 
                                            GeomGenerator},
                                            Path= GeomMesh}">
                                            <GeometryModel3D.Material>
                                                <DiffuseMaterial>
                                                    <DiffuseMaterial.Brush>
                                                        <SolidColorBrush 
                                                            Color="Red" 
                                                            Opacity="1.0"/>
                                                    </DiffuseMaterial.Brush>
                                                </DiffuseMaterial>
                                            </GeometryModel3D.Material>
                                            <GeometryModel3D.Transform>
                                                <Transform3DGroup>
                                                    <RotateTransform3D>
                                                        <RotateTransform3D.Rotation>
                                                            <AxisAngleRotation3D
                                                                 x:Name="MyRotation"
                                                                 Axis="0,1,0"
    												             Angle="{Binding ElementName=rotationSlider,Path=Value}" />
                                                        </RotateTransform3D.Rotation>
                                                    </RotateTransform3D>
                                                    <TranslateTransform3D />
                                                </Transform3DGroup>
                                            </GeometryModel3D.Transform>
                                        </GeometryModel3D>
     
                                        <DirectionalLight 
    	                                    Color="White" 
    	                                    Direction="-2,-3,-1" />
                                    </Model3DGroup.Children>
                                </Model3DGroup>
                            </ModelVisual3D.Content>
                        </ModelVisual3D>
                    </Viewport3D.Children>
                </Viewport3D>
                <Canvas
                    Name="MyCanvasOverlay"   >
                </Canvas>
            </Grid>
        </StackPanel>
     
    </UserControl>
    code behind .cs du generateur du "box cube":
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
     
     
    using System.Windows.Media.Media3D;
    using System.Windows.Media;
    namespace WpTransform3Dto2D
    { 
        public class GeometryGenerator
        {
            public  GeometryGenerator()
            {
                GeomMesh = CreateCubeModel();
     
            }
            public MeshGeometry3D GeomMesh { get; set; }
            public static MeshGeometry3D CreateCubeModel()
            {
                MeshGeometry3D mesh = new MeshGeometry3D();
     
                mesh.Positions.Add(new Point3D(-1, -1, 1));
                mesh.Positions.Add(new Point3D(1, -1, 1));
                mesh.Positions.Add(new Point3D(1, 1, 1));
                mesh.Positions.Add(new Point3D(-1, 1, 1));
                mesh.TriangleIndices.Add(0);
                mesh.TriangleIndices.Add(1);
                mesh.TriangleIndices.Add(2);
                mesh.TriangleIndices.Add(0);
                mesh.TriangleIndices.Add(2);
                mesh.TriangleIndices.Add(3);
                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.Positions.Add(new Point3D(1, -1, 1));
                mesh.Positions.Add(new Point3D(1, -1, -1));
                mesh.Positions.Add(new Point3D(1, 1, -1));
                mesh.Positions.Add(new Point3D(1, 1, 1));
                mesh.TriangleIndices.Add(4);
                mesh.TriangleIndices.Add(5);
                mesh.TriangleIndices.Add(6);
                mesh.TriangleIndices.Add(4);
                mesh.TriangleIndices.Add(6);
                mesh.TriangleIndices.Add(7);
                mesh.Normals.Add(new Vector3D(1, 0, 0));
                mesh.Normals.Add(new Vector3D(1, 0, 0));
                mesh.Normals.Add(new Vector3D(1, 0, 0));
                mesh.Normals.Add(new Vector3D(1, 0, 0));
     
                mesh.Positions.Add(new Point3D(1, -1, -1));
                mesh.Positions.Add(new Point3D(-1, -1, -1));
                mesh.Positions.Add(new Point3D(-1, 1, -1));
                mesh.Positions.Add(new Point3D(1, 1, -1));
                mesh.TriangleIndices.Add(8);
                mesh.TriangleIndices.Add(9);
                mesh.TriangleIndices.Add(10);
                mesh.TriangleIndices.Add(8);
                mesh.TriangleIndices.Add(10);
                mesh.TriangleIndices.Add(11);
                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.Positions.Add(new Point3D(-1, -1, -1));
                mesh.Positions.Add(new Point3D(-1, -1, 1));
                mesh.Positions.Add(new Point3D(-1, 1, 1));
                mesh.Positions.Add(new Point3D(-1, 1, -1));
                mesh.TriangleIndices.Add(12);
                mesh.TriangleIndices.Add(13);
                mesh.TriangleIndices.Add(14);
                mesh.TriangleIndices.Add(12);
                mesh.TriangleIndices.Add(14);
                mesh.TriangleIndices.Add(15);
                mesh.Normals.Add(new Vector3D(-1, 0, 0));
                mesh.Normals.Add(new Vector3D(-1, 0, 0));
                mesh.Normals.Add(new Vector3D(-1, 0, 0));
                mesh.Normals.Add(new Vector3D(-1, 0, 0));
     
                mesh.Positions.Add(new Point3D(-1, -1, 1));
                mesh.Positions.Add(new Point3D(-1, -1, -1));
                mesh.Positions.Add(new Point3D(1, -1, -1));
                mesh.Positions.Add(new Point3D(1, -1, 1));
                mesh.TriangleIndices.Add(16);
                mesh.TriangleIndices.Add(17);
                mesh.TriangleIndices.Add(18);
                mesh.TriangleIndices.Add(16);
                mesh.TriangleIndices.Add(18);
                mesh.TriangleIndices.Add(19);
                mesh.Normals.Add(new Vector3D(0, -1, 0));
                mesh.Normals.Add(new Vector3D(0, -1, 0));
                mesh.Normals.Add(new Vector3D(0, -1, 0));
                mesh.Normals.Add(new Vector3D(0, -1, 0));
     
                mesh.Positions.Add(new Point3D(-1, 1, 1));
                mesh.Positions.Add(new Point3D(1, 1, 1));
                mesh.Positions.Add(new Point3D(1, 1, -1));
                mesh.Positions.Add(new Point3D(-1, 1, -1));
                mesh.TriangleIndices.Add(20);
                mesh.TriangleIndices.Add(21);
                mesh.TriangleIndices.Add(22);
                mesh.TriangleIndices.Add(20);
                mesh.TriangleIndices.Add(22);
                mesh.TriangleIndices.Add(23);
                mesh.Normals.Add(new Vector3D(0, 1, 0));
                mesh.Normals.Add(new Vector3D(0, 1, 0));
                mesh.Normals.Add(new Vector3D(0, 1, 0));
                mesh.Normals.Add(new Vector3D(0, 1, 0));
     
     
                return mesh;
     
            }
     
        }
    }
    code xamL du simplistic winform:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    <Window x:Class="WpTransform3Dto2D.WindowContour2D"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpTransform3Dto2D"
            Title="Contour2D" Height="300" Width="300">
        <Grid>
            <local:UserControlContour2D></local:UserControlContour2D>
        </Grid>
    </Window>
    En esperant qu'il reponde au souci........

    A propos des Tasks bonne nouvelle pour toi:
    - le .Net FrameWork 4.5 donc VS2011 ou VS2012
    dispose du class static BindingOperations.EnableCollectionSynchronization qui permet un acces multi-thread aux ....ObservableCollection du ViewModel.(plus besoin du Dispatcher UI).
    Il sufit d'une ligne de code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    private static object _itemsLock = new object();  
    private ObservableCollection<string> _items = new ObservableCollection<string>();  
    public ObservableCollection<string> Items { get { return _items; } }  
    public MainWindow()  
    {  
     
         InitializeComponent();  
         BindingOperations.EnableCollectionSynchronization(_items, _itemsLock);  
     
    }
    Si tu n'as pas VS2011 alors comme moi j'ai le .Net Framework 4.0 donc VS2010 on a quand meme les BlockingCollection(spacename using System.Collections.Concurrent) qui gerent l'acces multi-thread...
    Mais il faut :
    -recopier l'ObservableCollection avec une boucle dans un BlockingCollection(T) (et ceci s'applique à toute collection sous-reference à laquelle tu accedes dans un Task thread y compris les natives comme Pisitions,Vertices et tutti quanti....)................

    bon code................

  3. #3
    Membre à l'essai
    Profil pro
    Étudiant
    Inscrit en
    Août 2012
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2012
    Messages : 25
    Points : 11
    Points
    11
    Par défaut
    Bonjour Mabrouki,

    merci beaucoup pour ta réponse très complète ! Pour répondre à ta première question, je veux bien entendu tracer un contour sur le Viewport3D, c'est-à-dire sur le plan 2D !
    J'ai essayé ton code et malheureusement ça ne correspond pas bien à ce que je veux. Ton code trace le contour de toutes les arrêtes du cube, mais je souhaite uniquement avoir le contour extérieur ! En d'autres mots, "La plus grande figure qui englobe tout le cube", c'est la deuxième image que j'ai mis dans mon post, alors que ton code me donne : Nom : ContourCube.jpg
Affichages : 863
Taille : 54,2 Ko

    A mon avis ton code est performant comme il le faut, mais il faut trouver le moyen de "vider l'intérieur du cube", c'est-à-dire enlever les arrêtes qui sont à l'intérieur.

    As-tu une idée pour arriver à cela?

  4. #4
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    bonjour mickeycast....
    D'abord on ne peut pas dessiner des objets 2D sur le ViewPort3D avec l'api WPF actuelle.... c'est un "lack" de wpf..
    Il n' y a aucune commande en WPF pour dire au ViewPort3D trace un mesh entre 2 points 3D (x,y,z)

    Pourtant on peut dessiner en 3D les aretes qu'on veut sur le ViewPort3D mais avec un "wireframe" (en francais une cage 3D).
    C'est ce que nombre de logiciels DAO font couramment.
    Pour combler ce "lack" il y a 2 ToolKit WPF:
    -3D Tools sur le site Microsoft CodePlex.Com qui permet grace à son class ScreenSpaceLines3D de generer le "wireframe" 3D dans le ViewPort3D et de dessiner par exemple les axes ou les normales (1er exemple de code).....

    -Petzold.Media3D librairie avec code source sur le site de l'auteur Charles Petzold (un mentor de Microsoft) que je prefere car plus riche(class WireFrame,WirePolyline, WireLine ,et meme...... WirePath et WireText si on ecrit du texte au point3d(x,y,z) du VP).....bref un arsenal de guerre.....
    (2er exemple de code ).....

    Le class ScreenSpaceLines3D aussi bien que les class "wire" de Petzold.Media disposent de la collection Points.....pour les points du trace...

    Autre point important :
    -le wireframe cree (cage) est ajoute simplement à ViewPort3d.Children quoique n'etant pas un Model3D....simplistic....
    Maintenant pour dessiner uniquement ce qui est autour c'est subtil car tu oublies que si le model est en mouvement(rotation) c'est difficile :
    - de defnir les points à l'interieur car ils changes constamment .....
    - c'est pour cela que je dessine tout ....
    Exemple du cube:quelque soit la position au cours du temps(rotation) on voit constamment 4 sommets +1 sommet central(cube a 6 sommets)
    Mais..... qui ne sont pas les memes d'ou la difficulte de definir les sommets du contour.....C'est pour cela que j'ai parle d' "ombre" (c'est presque l'adage prendre l'ombre pour la proie)......

    bref voici :
    1er code exemple pour 3DTools:
    code behind.cs du winform :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Windows.Media.Media3D;
    //ScreenSpaceLines3D Class
    using _3DTools;
    namespace WpfWireFrame3D
    {
        /// <summary>
        /// Logique d'interaction pour MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
     
            private void cubeButtonClick(object sender, RoutedEventArgs e)
            {
                Model3DGroup cube = new Model3DGroup();
                Point3D p0 = new Point3D(0, 0, 0);
                Point3D p1 = new Point3D(5, 0, 0);
                Point3D p2 = new Point3D(5, 0, 5);
     
                Point3D p3 = new Point3D(0, 0, 5);
                Point3D p4 = new Point3D(0, 5, 0);
                Point3D p5 = new Point3D(5, 5, 0);
     
                Point3D p6 = new Point3D(5, 5, 5);
                Point3D p7 = new Point3D(0, 5, 5);
                //front side triangles
                cube.Children.Add(CreateTriangleModel(p3, p2, p6));
                cube.Children.Add(CreateTriangleModel(p3, p6, p7));
                //right side triangles
                cube.Children.Add(CreateTriangleModel(p2, p1, p5));
                cube.Children.Add(CreateTriangleModel(p2, p5, p6));
                //back side triangles
                cube.Children.Add(CreateTriangleModel(p1, p0, p4));
                cube.Children.Add(CreateTriangleModel(p1, p4, p5));
                //left side triangles
                cube.Children.Add(CreateTriangleModel(p0, p3, p7));
                cube.Children.Add(CreateTriangleModel(p0, p7, p4));
                //top side triangles
                cube.Children.Add(CreateTriangleModel(p7, p6, p5));
                cube.Children.Add(CreateTriangleModel(p7, p5, p4));
                //bottom side triangles
                cube.Children.Add(CreateTriangleModel(p2, p3, p0));
                cube.Children.Add(CreateTriangleModel(p2, p0, p1));
     
                ModelVisual3D model = new ModelVisual3D();
                model.Content = cube;
     
                //ATTENTION APPLIQUER LE TRANSFORM AU MODEL CUBE  
                model.Transform = this.myRotation;
     
                this.mainViewport.Children.Add(model);
     
            }
     
     
            //abstract your model model mesh
            private Model3DGroup CreateTriangleModel(Point3D p0, Point3D p1, Point3D p2)
            {
                MeshGeometry3D mesh = new MeshGeometry3D();
                mesh.Positions.Add(p0);
                mesh.Positions.Add(p1);
                mesh.Positions.Add(p2);
                mesh.TriangleIndices.Add(0);
                mesh.TriangleIndices.Add(1);
                mesh.TriangleIndices.Add(2);
                Vector3D normal = CalculateNormal(p0, p1, p2);
                mesh.Normals.Add(normal);
                mesh.Normals.Add(normal);
                mesh.Normals.Add(normal);
                Material material = new DiffuseMaterial(
                    new SolidColorBrush(Colors.DarkKhaki));
                GeometryModel3D model = new GeometryModel3D(
                    mesh, material);
                Model3DGroup group = new Model3DGroup();
                group.Children.Add(model);
     
                // creer les droites normales en "2D" oui?
                if (normalsCheckBox.IsChecked == true)
                    group.Children.Add(BuildNormals(p0, p1, p2, normal));
     
                // creer le "wirefram" qui fera ton bonheur peut etre
                if (wireframeCheckBox.IsChecked == true)
                {
                    ScreenSpaceLines3D wireframe = new ScreenSpaceLines3D();
                    wireframe.Points.Add(p0);
                    wireframe.Points.Add(p1);
                    wireframe.Points.Add(p2);
                    wireframe.Points.Add(p0);
                    wireframe.Color = Colors.LightBlue;
                    wireframe.Thickness = 3;
                    //ATTENTION  APPLIQUER LE MEME TRANSFORM AU "WIREFRAME"  
                    wireframe.Transform = this.myRotation;
                    this.mainViewport.Children.Add(wireframe);
                }
     
                return group;
            }
            private Vector3D CalculateNormal(Point3D p0, Point3D p1, Point3D p2)
            {
                Vector3D v0 = new Vector3D(
                    p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
                Vector3D v1 = new Vector3D(
                    p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
                return Vector3D.CrossProduct(v0, v1);
            }
     
            // builds normals
            private Model3DGroup BuildNormals(
                Point3D p0,
                Point3D p1,
                Point3D p2,
                Vector3D normal)
            {
                Model3DGroup normalGroup = new Model3DGroup();
                Point3D p;
                ScreenSpaceLines3D normal0Wire = new ScreenSpaceLines3D();
                ScreenSpaceLines3D normal1Wire = new ScreenSpaceLines3D();
                ScreenSpaceLines3D normal2Wire = new ScreenSpaceLines3D();
                Color c = Colors.Blue;
                int width = 1;
                normal0Wire.Thickness = width;
                normal0Wire.Color = c;
                normal1Wire.Thickness = width;
                normal1Wire.Color = c;
                normal2Wire.Thickness = width;
                normal2Wire.Color = c;
                double num = 1;
                double mult = .01;
                double denom = mult * Convert.ToDouble(normalSizeTextBox.Text);
                double factor = num / denom;
                p = Vector3D.Add(Vector3D.Divide(normal, factor), p0);
                normal0Wire.Points.Add(p0);
                normal0Wire.Points.Add(p);
                p = Vector3D.Add(Vector3D.Divide(normal, factor), p1);
                normal1Wire.Points.Add(p1);
                normal1Wire.Points.Add(p);
                p = Vector3D.Add(Vector3D.Divide(normal, factor), p2);
                normal2Wire.Points.Add(p2);
                normal2Wire.Points.Add(p);
     
                //Normal wires are not models, so we can't
                //add them to the normal group.  Just add them
                //to the viewport for now...
     
                this.mainViewport.Children.Add(normal0Wire);
                this.mainViewport.Children.Add(normal1Wire);
                this.mainViewport.Children.Add(normal2Wire);
     
                return normalGroup;
            }
     
        }
    }
    code xaml du winform:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
     
     
    <Window x:Class="WpfWireFrame3D.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <DockPanel 
                  Width="Auto" 
                  VerticalAlignment="Stretch" 
                  Height="Auto" 
                  HorizontalAlignment="Stretch" 
                  Grid.ColumnSpan="1" 
                  Grid.Column="0" 
                  Grid.Row="0" 
                  Margin="0,0,0,0" 
                  Grid.RowSpan="1">
                <StackPanel>
                    <StackPanel.Background>
                        <LinearGradientBrush>
                            <GradientStop Color="White" Offset="0"/>
                            <GradientStop Color="DarkKhaki" Offset=".3"/>
                            <GradientStop Color="DarkKhaki" Offset=".7"/>
                            <GradientStop Color="White" Offset="1"/>
                        </LinearGradientBrush>
                    </StackPanel.Background>
                    <StackPanel Margin="10">
                        <Button 
                            Name="cubeButton" 
                            Click="cubeButtonClick"
                            Content="Cube">
                        </Button>
                        <Separator/>
                        <CheckBox Name="wireframeCheckBox"
                                  Content="Show Wireframe">
                        </CheckBox>
                        <Separator/>
                        <CheckBox Name="normalsCheckBox"
                                  Content="Show Normals">
                        </CheckBox>
                        <TextBlock Text="Normal Size:"/>
                        <TextBox Name="normalSizeTextBox" Text="1"/>
                        <Slider 
                            Name="sliderRotation"
                            Minimum="0"
                            Maximum="360"
                            Value="0">
                        </Slider>
                    </StackPanel>
                </StackPanel>
                <Viewport3D 
                    Name="mainViewport" 
                    ClipToBounds="True">
                    <Viewport3D.Camera>
                        <PerspectiveCamera 
    	                  FarPlaneDistance="100"
    	                  LookDirection="-11,-10,-9"
    	                  UpDirection="0,1,0"
    	                  NearPlaneDistance="1" 
    	                  Position="11,10,9" 
    	                  FieldOfView="70" />
                    </Viewport3D.Camera>
                    <ModelVisual3D>
                        <ModelVisual3D.Transform>
                            <RotateTransform3D   x:Name="myRotation">
                                <RotateTransform3D.Rotation>
                                    <AxisAngleRotation3D
                                        Angle="{Binding ElementName=sliderRotation,Path=Value}"
                                        Axis="0,1,0"/>                 
                                </RotateTransform3D.Rotation>
                            </RotateTransform3D>
                        </ModelVisual3D.Transform>
                        <ModelVisual3D.Content>
                            <DirectionalLight 
    	                        Color="White" 
    	                        Direction="-2,-3,-1" />
                        </ModelVisual3D.Content>
                    </ModelVisual3D>
                </Viewport3D>
            </DockPanel>
        </Grid>
    </Window>
    2er code exemple pour Petzold.Media3D
    bien plus simple.....
    code behind.cs du winform :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
     
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;
    using System.Windows.Media.Media3D;
    //WireFrame Class de la lib  Petzold.Media3D
    using Petzold.Media3D;
    namespace WpfWireFrame3D
    {
        /// <summary>
        /// Logique d'interaction pour Window1.xaml
        /// </summary>
        public partial class Window1 : Window
        {
            Petzold.Media3D.WireFrame wire;
     
            public Window1()
            {
                InitializeComponent();
     
            }
     
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                MeshGeometry3D mesh3D = this.meshMain;
                wire = new WireFrame();
                wire.Rounding = 10;
                wire.Thickness = 2;
                wire.Color = Colors.LightBlue;
                wire.Positions = mesh3D.Positions;
                wire.TriangleIndices = mesh3D.TriangleIndices;
                wire.TextureCoordinates = mesh3D.TextureCoordinates;
                wire.Normals = mesh3D.Normals;
                //ATTENTION  APPLIQUER LE MEME TRANSFORM AU "WIREFRAME"  
                wire.Transform = this.mainModel.Transform;
                this.mainViewport3D.Children.Add(wire);
            }
        }
    }
    code xaml du winform
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
     
    <Window x:Class="WpfWireFrame3D.Window1"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Window1" Height="300" Width="300"
            Loaded="Window_Loaded">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="30"></RowDefinition>
                <RowDefinition Height="*"></RowDefinition>
            </Grid.RowDefinitions>
            <Slider 
                Name="sliderRotation"
                Minimum="0"
                Maximum="360"
                Value="0">
            </Slider>
            <Viewport3D 
                Grid.Row="1"
                Name="mainViewport3D"
                ClipToBounds="True"
                HorizontalAlignment="Stretch"
                VerticalAlignment="Stretch">
                <Viewport3D.Camera>
                    <PerspectiveCamera x:Name="camMain" Position="6 5 4" LookDirection="-6 -5 -4">
                        </PerspectiveCamera>
                </Viewport3D.Camera>
                <ModelVisual3D>
                    <ModelVisual3D.Content>
                        <DirectionalLight x:Name="dirLightMain" Direction="-1,-1,-1">
                           </DirectionalLight>
                    </ModelVisual3D.Content>
                </ModelVisual3D>
                <ModelVisual3D  x:Name="mainModel">
                    <ModelVisual3D.Transform>
                        <RotateTransform3D   x:Name="myRotation">
                            <RotateTransform3D.Rotation>
                                <AxisAngleRotation3D
                                        Angle="{Binding ElementName=sliderRotation,Path=Value}"
                                        Axis="0,1,0"/>
                            </RotateTransform3D.Rotation>
                        </RotateTransform3D>
                    </ModelVisual3D.Transform>
                    <ModelVisual3D.Content>
                        <GeometryModel3D  >
                            <GeometryModel3D.Geometry>
                                <MeshGeometry3D
                                    x:Name="meshMain" 
                                     Positions="0 0 0  1 0 0  0 1 0  1 1 0  0 0 1  1 0 1  0 1 1  1 1 1" 
                                     TriangleIndices="2 3 1  2 1 0  7 1 3  7 5 1  6 5 7  6 4 5  6 2 0  2 0 4  2 7 3  2 6 7  0 1 5  0 5 4">
                                </MeshGeometry3D>
                            </GeometryModel3D.Geometry>
                            <GeometryModel3D.Material>
                                <DiffuseMaterial x:Name="matDiffuseMain">
                                    <DiffuseMaterial.Brush>
                                        <SolidColorBrush Color="Red"/>
                                    </DiffuseMaterial.Brush>
                                </DiffuseMaterial>
                            </GeometryModel3D.Material>
                        </GeometryModel3D>
                    </ModelVisual3D.Content>
                </ModelVisual3D>
            </Viewport3D>
        </Grid> 
    </Window>
    lien 3DTools codeplex:

    http://www.codeplex.com/3DTools

    -----------------------------------------------------------------
    lien Petzold.Media site (auteur Microsoft):
    http://www.charlespetzold.com/blog/2007/08/310158.html

    bon code.....................

  5. #5
    Membre à l'essai
    Profil pro
    Étudiant
    Inscrit en
    Août 2012
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2012
    Messages : 25
    Points : 11
    Points
    11
    Par défaut
    Bonjour Mabrouki,

    J'ai cru comprendre que les deux exemples de bibliothèques que tu me donnais permettent de mieux manipuler le "wireframe", la cage 3d, mais qu'au final je ne pourrais quand même pas tracer les contours car c'est compliqué.

    On m'a donné une idée qui me semble pas mal, et qui est de tracé deux "wireframes" et de réduire un petit peu la taille de la deuxième. Ensuite, on fait une opération de soustraction (la première moins la deuxième) qui revient à supprimer tout ce qu'il y a à l'intérieur de la première !

    Comme je ne connais vraiment pas la manipulation du viewport et des bibliothèques que tu m'as donné, aurais tu une idée des manières de mettre en place ce que j'avance?

    Et aussi ton avis sur son fonctionnement?

    Vraiment merci à toi

  6. #6
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    bonjour mickeycast
    C'est une bonne idee mais qui n'as aucun sens dans WPF car il ne supporte pas les operations booleenes ni sur les solides Model3D ni à fortiori sur les "wires" frames des biblio citees
    Car elles sont basees sur les Model3D de wpf.....
    Bon code...........

  7. #7
    Membre à l'essai
    Profil pro
    Étudiant
    Inscrit en
    Août 2012
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2012
    Messages : 25
    Points : 11
    Points
    11
    Par défaut
    Bonjour MABROUKI,

    Une autre idée que l'on m'a donné est d'utiliser l'ombre de l'objet, ce qui revient à tracer un contour. Si l'on ne donne aucune direction à l'ombre mais qu'elle est juste "derrière" l'objet sera visuellement équivalent.

    Dans MSDN j'ai trouvé l'effet mais qui apparemment ne s'applique qu'aux "Visual".

    Est-ce qu'il est possible d'appliquer cette ombre à mon objet Geometry3D sur mon Viewport?


    Merci beaucoup par avance, je ne m'en sors pas trop avec les différentes classes Media3D, j'ai un peu du mal à faire les casts..

  8. #8
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    bonjour mickeycast

    L'ombre est une idee mais je ne t'apprendrais rien car tu sais que l'ombre est une couleur sombre....il faut :
    => un autre solide derriere ton objet dont une face sera chargee de recueuillir la lumiere de l'ombre.Cette face doit etre perpendiculaire à la direction de la camera(vecteur camera)...
    => une source de lumiere directionnele (vecteur) parallele au vecteur camera(et qui sera donc perpendiculaire à la face du 2eme solide charge de recueullir la lumiere d'ombre)......bref un peu complique car comment gerer l'eclairage l'Api WPF n'offrant aucun support pour l'eclairage d'ombrage....

    Moi je te propose un algo classique des "visibles faces" ou "removal hidden faces"....le plus couramment utilise pour visualiser des objets 3D....

    Pour visualiser un objet 3D en 2D on projette toutes les aretes des faces(cotes des triangles) comme dans l'exemple sur le canvas(deja vu par ailleurs) et on n'affiche en fait que celles qui "sont visibles par le vecteur camera" (observateur) ..
    - la definition des "faces visibles" par le vecteur camera est la suivante :
    produit scalaire =vecteur camera X vecteur normale face[i] doit etre negatif.....
    En voici un exemple qui stroke les aretes visibles et fille les surfaces correspondantes (dont tu peux enlever le stroke des polylines):
    code xaml du winform:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
     
    <Window x:Class="WpfWireFrame3DBis.WinCustomCubeVisFaces"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfWireFrame3DBis"
            xmlns:gm="clr-namespace:WpfCustomGeometries;assembly=WpfCustomGeometries"
            Title="CustomCube Visibles Faces" Height="300" Width="300"
            Loaded="Window_Loaded">
        <Window.Resources>
            <gm:CustomCube
                x:Key ="custCubeGeom"
                Center="0,0,0"
                Length="0.5"
                Width="0.5"
                Height="0.5">
            </gm:CustomCube>
        </Window.Resources>
        <Grid Margin="5">
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"></RowDefinition>
                <RowDefinition Height="*"></RowDefinition>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"></ColumnDefinition>
                <ColumnDefinition Width="*"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <StackPanel
                    Width="Auto"
                    Height="Auto">
                <Button 
                        Name="btnDrawNormal" 
                        Click="btnDrawNormal_Click"
                        Content="Draw Normals">
                </Button>
                <Button 
                        Name="btnDrawFaces" 
                        Click="btnDrawFaces_Click"
                        Content="Draw Faces ">
                </Button>
                <Button 
                        Name="btnDrawVisibles" 
                        Click="btnDrawVisibleFaces_Click"
                        Content="Draw Visible Faces ">
                </Button>
            </StackPanel>
            <StackPanel
                Width="auto"
                Height="auto"
                Grid.Column="1">
                <Slider 
                    x:Name="rotSliderY"
                    Maximum="360"
                    Minimum="0"
                    Value="0">
                </Slider>
                <Slider 
                    x:Name="rotSliderX"
                    Maximum="360"
                    Minimum="0"
                    Value="0">
                    <Slider.ToolTip>
                        <TextBlock 
                            Text="{Binding 
                            ElementName=rotSliderX,
                            Path=Value}"/>
                    </Slider.ToolTip>
                </Slider>
            </StackPanel>
            <Grid
                Grid.Row="1"
                Grid.Column="0"
                Grid.ColumnSpan="2">
                <Border 
                    BorderBrush="Gray" 
                    BorderThickness="1"
                    Background="White">
                    <Viewport3D 
                        Name="MyViewport"
                        >
                        <Viewport3D.Camera>
                            <!--4,5,6-->
                            <PerspectiveCamera 
                                x:Name="mainCam"
                                Position="4,4,4"
                                LookDirection="-4,-4,-4"
                                UpDirection="0,1,0"
                                FieldOfView="15"/>
                        </Viewport3D.Camera>
                        <!-- Set light source: -->
                        <ModelVisual3D >
                            <ModelVisual3D.Content>
                                <DirectionalLight 
                                x:Name="mainLight"
                                Color="White"
                                Direction="10,-25, 0"
                                />
                            </ModelVisual3D.Content>
     
                        </ModelVisual3D>
                        <ModelVisual3D
                            x:Name="MyModel">
                            <ModelVisual3D.Content>
                                <GeometryModel3D
                                    x:Name="MyGeomModel"
                                    Geometry="{Binding 
                                    Source={StaticResource  
                                    custCubeGeom},
                                    Path=Mesh3D}">
                                    <GeometryModel3D.Material>
                                        <MaterialGroup>
                                            <DiffuseMaterial 
                                                Brush="Red"  />
                                            </MaterialGroup>
                                    </GeometryModel3D.Material>
                                    <GeometryModel3D.Transform>
                                        <Transform3DGroup >
                                            <RotateTransform3D>
                                                <RotateTransform3D.Rotation>
                                                    <AxisAngleRotation3D
                                                    Angle="{Binding ElementName=rotSliderY,Path=Value}"
                                                    Axis="0,1,0"/>
                                                </RotateTransform3D.Rotation>
                                            </RotateTransform3D>
                                            <RotateTransform3D>
                                                <RotateTransform3D.Rotation>
                                                    <AxisAngleRotation3D
                                                    Angle="{Binding ElementName=rotSliderX,Path=Value}"
                                                    Axis="1,0,0"/>
                                                </RotateTransform3D.Rotation>
                                            </RotateTransform3D>
                                        </Transform3DGroup>
                                    </GeometryModel3D.Transform>
                                </GeometryModel3D>
                            </ModelVisual3D.Content>
                        </ModelVisual3D>
                    </Viewport3D>
                </Border>
                <Canvas
                    Name="MyCanvasOverlay">
                </Canvas>
            </Grid>
        </Grid>
    </Window>
    code behind .cs du winform:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;
    using System.Collections;
    using System.Windows.Media.Media3D;
    //ref à petzold media
    using Petzold.Media3D;
    namespace WpfWireFrame3DBis
    {
        /// <summary>
        /// Logique d'interaction pour WinCustomCubeVisFaces.xaml
        /// </summary>
        public partial class WinCustomCubeVisFaces : Window
        {
            Axes OX;
            Axes OY;
            public WinCustomCubeVisFaces()
            {
                InitializeComponent();
            }
            //dessine les axes 3D
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                //x'Ox
                OX = new Petzold.Media3D.Axes();
                OX.Color = Colors.Red;
                OX.LineCollection.Add(new Point3D(4, 0, 0));
                OX.LineCollection.Add(new Point3D(3, 0, 0));
                OX.Thickness = 0.5;
                //y'Oy
                OY = new Petzold.Media3D.Axes();
                OY.Color = Colors.DarkBlue;
                OY.LineCollection.Add(new Point3D(0, -5, 0));
                OY.LineCollection.Add(new Point3D(0, 3, 0));
                OY.Thickness = 0.5;
                this.MyViewport.Children.Add(OX);
                this.MyViewport.Children.Add(OY);
            }
     
            // Dessin des normales 3D pour mieux illustrer l'algo
            // des "visibles faces" ou "removal hidden lines"
            List<WireLine> wireNormals = new List<WireLine>();
            private void btnDrawNormal_Click(object sender, RoutedEventArgs e)
            {
                GeometryModel3D geom3D = (GeometryModel3D)this.MyGeomModel;
                MeshGeometry3D mesh = (MeshGeometry3D)geom3D.Geometry;
                Transform3D trans3D = (Transform3D)this.MyGeomModel.Transform;
     
                // dessin Normales
                if (wireNormals.Count != 0)
                {
                    for (int i = 0; i < wireNormals.Count; i++)
                    {
                        this.MyViewport.Children.Remove(wireNormals[i]);
                    }
                }
     
                wireNormals.Clear();
                Point3D position;
                Vector3D normal;
                WireLine wln;
                int numVertex;
                for (int i = 0; i < mesh.TriangleIndices.Count; i++)
                {
                    numVertex = mesh.TriangleIndices[i];
                    position = mesh.Positions[numVertex];
                    //il faut appliquer le transform courant
                    position = trans3D.Transform(position);
                    normal = trans3D.Transform(mesh.Normals[numVertex]);
                    wln = new WireLine();
                    wln.Rounding = 10;
                    wln.Color = Colors.Brown;
                    wln.Thickness = 3;
                    //dessine segment du "position courant"  suivant direction du vecteur "normale courante"
                    // de longueur =module normale courante/ 0.3
                    wln.Point1 = position;
                    wln.Point2 = Vector3D.Add(Vector3D.Divide(normal, 3.0), position);
                    //segment est ajoute en 3d comme un objet wire 
                    this.MyViewport.Children.Add(wln);
                    wireNormals.Add(wln);
     
                }
            }
            // Dessin de toutes les  faces avec un fill et leurs aretes 
            private List<Polyline> plines = new List<Polyline>();
            private Polyline pline;
            Rect bounds2D;
            private void btnDrawFaces_Click(object sender, RoutedEventArgs e)
            {
                //refresh canvas overlay
                this.MyCanvasOverlay.Children.Clear();
                plines.Clear();
     
     
                // Bounding Box ModelVisual3D
                //bounds2D = this.MyModel.TransformToAncestor(this.MyViewport).TransformBounds(VisualTreeHelper.GetContentBounds(this.MyModel));
                bounds2D = this.MyModel.TransformToAncestor(this.MyViewport).TransformBounds(this.MyModel.Content.Bounds);
     
                // Dessin Bounding Box
                Rectangle MyRectangle = new Rectangle();
                MyRectangle.Stroke = Brushes.Blue;
                MyRectangle.Width = bounds2D.Width;
                MyRectangle.Height = bounds2D.Height;
                Canvas.SetLeft(MyRectangle, bounds2D.X);
                Canvas.SetTop(MyRectangle, bounds2D.Y);
                MyCanvasOverlay.Children.Add(MyRectangle);
     
     
                // GeneralTransform3DTo2D du ModelUIElement3D
                GeneralTransform3DTo2D tt = this.MyModel.TransformToAncestor(this.MyViewport);
                // GeneralTransform3DTo2D 
                Transform3D trans3D = (Transform3D)this.MyGeomModel.Transform;
     
     
     
     
                /* "contour" projete  des points 3D  */
                GeometryModel3D geom3D = (GeometryModel3D)this.MyGeomModel;
                MeshGeometry3D mesh = (MeshGeometry3D)geom3D.Geometry;
     
                Point3D ptOut3D;
                int numVertex;
                for (int i = 0; i < mesh.TriangleIndices.Count; i += 3)
                {
                    pline = new Polyline();
                    for (int j = i; j < i + 3; j++)
                    {
                        numVertex = mesh.TriangleIndices[j];
                        ptOut3D = mesh.Positions[numVertex];
                        /* Transform3D  positions locales du Mesh */
                        ptOut3D = trans3D.Transform(ptOut3D);
     
                        /* GeneralTransform3DTo2D( Point2D relatif au ViewPort */
                        pline.Points.Add(tt.Transform(ptOut3D));
     
                    }
                    plines.Add(pline);
     
                }
     
                //Dessin  Polylines  
     
                foreach (Polyline pl in plines)
                {
                    pl.Stroke = Brushes.Chartreuse;
                    pl.StrokeThickness = 2.0;
                    pl.StrokeDashOffset = 4.0;
                    pl.Opacity = 0.2;
                    pl.Fill = Brushes.LightBlue;
                    MyCanvasOverlay.Children.Add(pl);
                }
     
            }
            // Dessin des faces "visibles" avec un fill y compris leurs aretes 
            //suivant l'algo "visibles faces" ou "removal hidden lines"
            Point3D[,] visiblesFaces = null;
            private void btnDrawVisibleFaces_Click(object sender, RoutedEventArgs e)
            {
                //refresh canvas 
                this.MyCanvasOverlay.Children.Clear();
                plines.Clear();
                visiblesFaces = null;
                // Bounding Box ModelVisual3D
                //bounds2D = this.MyModel.TransformToAncestor(this.MyViewport).TransformBounds(VisualTreeHelper.GetContentBounds(this.MyModel));
                bounds2D = this.MyModel.TransformToAncestor(this.MyViewport).TransformBounds(this.MyModel.Content.Bounds);
     
                // dessin Bounding Box 2D 
                Rectangle MyRectangle = new Rectangle();
                MyRectangle.Stroke = Brushes.Blue;
                MyRectangle.Width = bounds2D.Width;
                MyRectangle.Height = bounds2D.Height;
                Canvas.SetLeft(MyRectangle, bounds2D.X);
                Canvas.SetTop(MyRectangle, bounds2D.Y);
                MyCanvasOverlay.Children.Add(MyRectangle);
     
                // GeneralTransform3DTo2D 
                GeneralTransform3DTo2D tt = this.MyModel.TransformToAncestor(this.MyViewport);
     
                // Transform3D  du GeometryModel3D
                Transform3D trans3D = (Transform3D)this.MyGeomModel.Transform;
     
                /* GeometryModel3D & MeshGeometry3D */
                GeometryModel3D geom3D = (GeometryModel3D)this.MyGeomModel;
                MeshGeometry3D mesh = (MeshGeometry3D)geom3D.Geometry;
     
     
                /* Faces Visibles en 3D  */
                /* paremetres:camera et mesh => 
                - cloner le mesh car il est "freeze"  
                - lui appliquer le transform3D: positions et normales */
                Point3D outPt3D = new Point3D(0, 0, 0);
                Vector3D outNormal = new Vector3D();
                MeshGeometry3D meshClone = mesh.Clone();
                for (int i = 0; i < meshClone.Positions.Count; i++)
                {
                    outPt3D = trans3D.Transform(meshClone.Positions[i]);
                    meshClone.Positions[i] = outPt3D;
                    outNormal = trans3D.Transform(meshClone.Normals[i]);
                    meshClone.Normals[i] = outNormal;
                }
     
                visiblesFaces = GetVisiblesFaces(meshClone, this.mainCam);
     
                /* "contour" projete 2D des points 3D  */
                Point pt2D;
                for (int i = 0; i < visiblesFaces.GetUpperBound(0)+1; i ++)
                {
                    pline = new Polyline();
                    for (int j = 0; j < visiblesFaces.GetUpperBound(1) + 1; j++)
                    {
                        pt2D = tt.Transform(visiblesFaces[i,j]);
                        pline.Points.Add(pt2D);
                    }
                    plines.Add(pline);
                }
     
                //Dessin  Polylines
     
                foreach (Polyline p in plines)
                {
     
                    p.Stroke = Brushes.Purple;;
                    p.StrokeThickness = 4.0;
                    p.Opacity = 0.4;
                    p.Fill = Brushes.Yellow;
                    MyCanvasOverlay.Children.Add(p);
                }
     
            }
            //algo "visibles faces" ou "removal hidden lines"
            private Point3D[,] GetVisiblesFaces(MeshGeometry3D mesh, PerspectiveCamera cam)
            {
                //c'est le camera
                Vector3D viewer ;
                //indice i => numero de face
                //indice j => numero position(sommet) de la face 
                Point3D[,] dispFaces = new Point3D[mesh.TriangleIndices.Count / 3, 3];
                int numFace = 0;
                int numVertex = 0;
                double dot = 0.0;
                //parcours par face =>step=3
                for (int i = 0; i < mesh.TriangleIndices.Count; i += 3)
                {
     
                    for (int j = i; j < i + 3; j++)
                    {
                        //numero de position
                        numVertex = mesh.TriangleIndices[j];
     
                        //vecteur direction camera
                        viewer = cam.LookDirection;
     
                        //produit scalaire vecteur camera * normale sommet
                        dot = Vector3D.DotProduct(viewer, mesh.Normals[numVertex]);
                        // si dot produit scalaire negatif => face est visible 
                        if (dot < 0)  
                        {
                            /* add visible face */
                            dispFaces[numFace, j - i] = mesh.Positions[numVertex];
     
                        }
                    }
                    numFace++;
     
                }
                return dispFaces;
            }
        }
    }
    Cet algo fonctionne correctement sur la plupart des "mesh" petzold.media....
    sauf la sphere et le cylindre car ces 2 meshes ont l'inconvenient que 2 aretes opposes par rapport à l'axe de symetrie presentent le meme angle de la normale relatif au vecteur camera...ce qui rend les 2 aretes visibles alors qu'une seule devrait l'etre....
    Ceci fait que l'algo doit etre reamenage pour tenir compte de cette situation....
    bon code.....

  9. #9
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    rebonjour mickeycast ...
    Ooops ! un petit loupe ....j'ai oublie le meshcube utilise avec la definition des normales qui est exigible en wpf quand on travaille les normales....

    C'est un petit projet lib.dll qui decrit le mesh du custom cube utilise et qu'il faut referencer dans l'exemple communique (post precedent):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
     
    using System;
    using System.Windows;
    using System.Windows.Media;
    using System.Windows.Media.Media3D;
    namespace WpfCustomGeometries
    {
        public class CustomCube 
        {
            // Define private fields:
            private double length = 1.0;
            private double width = 1.0;
            private double height = 1.0;
            private Point3D center = new Point3D();
            // Define public properties:
            public double Length
            {
            get { return length; }
            set { length = value; }
            }
            public double Width
            {
            get { return width; }
            set { width = value; }
            }
            public double Height
            {
            get { return height; }
            set { height = value; }
            }
            public Point3D Center
            {
            get { return center; }
            set { center = value; }
            }
            // Get-only property generates MeshGeometry3D object:
            public MeshGeometry3D Mesh3D
            {
            get { return GetMesh3D(); }
            }
            private MeshGeometry3D GetMesh3D()
            {
                MeshGeometry3D mesh = new MeshGeometry3D();
                Point3D[] verts = new Point3D[36];
     
     
                double hx = 0.5 * Length;//X
                double hy = 0.5 * Height;//Y
                double hz = 0.5 * Width; //Z
                // center
                for (int i = 0; i < 36; i++)
                {
                    verts[i] += (Vector3D)Center;
                }
     
                // Front face
                verts[0] += (Vector3D)new Point3D(+hx, +hy, +hz);
                verts[1] += (Vector3D)new Point3D(-hx, +hy, +hz);
                verts[2] += (Vector3D)new Point3D(-hx, -hy, +hz);
                verts[3] += (Vector3D)new Point3D(-hx, -hy, +hz);
                verts[4] += (Vector3D)new Point3D(+hx, -hy, +hz);
                verts[5] += (Vector3D)new Point3D(+hx, +hy, +hz);
     
                for (int i = 0; i < 6; i++)
                {
                    mesh.Positions.Add(verts[i]);
                    mesh.TriangleIndices.Add(i);
                }
                //normals
                for (int i = 0; i < 6; i += 3)
                {
                    CalculateNormalFaces(i, i + 1, i + 2, mesh);
                }
     
     
                // Back face (remember this is facing *away* from the camera, so vertices should be
                //clockwise order)
                verts[6] += (Vector3D)new Point3D(-hx, +hy, -hz);
                verts[7] += (Vector3D)new Point3D(+hx, +hy, -hz);
                verts[8] += (Vector3D)new Point3D(+hx, -hy, -hz);
     
                verts[9] += (Vector3D)new Point3D(+hx, -hy, -hz);
                verts[10] += (Vector3D)new Point3D(-hx, -hy, -hz);
                verts[11] += (Vector3D)new Point3D(-hx, +hy, -hz);
                for (int i = 6; i < 12; i++)
                {
                    mesh.Positions.Add(verts[i]);
                    mesh.TriangleIndices.Add(i);
                }
                //normals
                for (int i = 6; i < 12; i += 3)
                {
                    CalculateNormalFaces(i, i + 1, i + 2, mesh);
                }
     
     
               // Top face
                verts[12] += (Vector3D)new Point3D(-hx, +hy, +hz);
                verts[13] += (Vector3D)new Point3D(+hx, +hy, +hz);
                verts[14] += (Vector3D)new Point3D(+hx, +hy, -hz);
                verts[15] += (Vector3D)new Point3D(+hx, +hy, -hz);
                verts[16] += (Vector3D)new Point3D(-hx, +hy, -hz);
                verts[17] += (Vector3D)new Point3D(-hx, +hy, +hz);
     
     
                for (int i = 12; i < 18; i++)
                {
                    mesh.Positions.Add(verts[i]);
                    mesh.TriangleIndices.Add(i);
                }
                //normals
                for (int i = 12; i < 18; i += 3)
                {
                    CalculateNormalFaces(i, i + 1, i + 2, mesh);
                }
     
     
                // Bottom face (remember this is facing *away* from the camera, so vertices should be
                //clockwise order)
                verts[18] += (Vector3D)new Point3D(-hx, -hy, +hz);
                verts[19] += (Vector3D)new Point3D(-hx, -hy, -hz);
                verts[20] += (Vector3D)new Point3D(+hx, -hy, -hz);
                verts[21] += (Vector3D)new Point3D(+hx, -hy, -hz);
                verts[22] += (Vector3D)new Point3D(+hx, -hy, +hz);
                verts[23] += (Vector3D)new Point3D(-hx, -hy, +hz);
                for (int i = 18; i < 24; i++)
                {
                    mesh.Positions.Add(verts[i]); 
                    mesh.TriangleIndices.Add(i);
                }
                //normals
                for (int i = 18; i < 24; i += 3)
                {
                    CalculateNormalFaces(i, i + 1, i + 2, mesh);
                }
     
                // Left face
                verts[24] += (Vector3D)new Point3D(-hx, +hy, +hz);
                verts[25] += (Vector3D)new Point3D(-hx, +hy, -hz);
                verts[26] += (Vector3D)new Point3D(-hx, -hy, -hz);
                verts[27] += (Vector3D)new Point3D(-hx, -hy, -hz);
                verts[28] += (Vector3D)new Point3D(-hx, -hy, +hz);
                verts[29] += (Vector3D)new Point3D(-hx, +hy, +hz);
     
     
                for (int i = 24; i < 30; i++)
                {
                    mesh.Positions.Add(verts[i]);
                    mesh.TriangleIndices.Add(i);
                }
                //normals
                for (int i = 24; i < 30; i += 3)
                {
                    CalculateNormalFaces(i, i + 1, i + 2, mesh);
                }
     
                // Right face (remember this is facing *away* from the camera, so vertices should be
                //clockwise order)
                verts[30] += (Vector3D)new Point3D(+hx, +hy, +hz);
                verts[31] += (Vector3D)new Point3D(+hx, -hy, +hz);
                verts[32] += (Vector3D)new Point3D(+hx, -hy, -hz);
                verts[33] += (Vector3D)new Point3D(+hx, -hy, -hz);
                verts[34] += (Vector3D)new Point3D(+hx, +hy, -hz);
                verts[35] += (Vector3D)new Point3D(+hx, +hy, +hz);
     
     
                for (int i = 30; i < 36; i++)
                {
                    mesh.Positions.Add(verts[i]); 
                    mesh.TriangleIndices.Add(i);
                }
                //normals
                for (int i = 30; i < 36; i+=3)
                {
                    CalculateNormalFaces(i, i+1, i+2, mesh);
                }
     
     
                // textures coord. default wpf
     
                mesh.Freeze();
                return mesh;
            }
            private void CalculateNormalFaces(int i, int j, int k, MeshGeometry3D mesh)
            {
     
                Vector3D v0 = new Vector3D(
                    mesh.Positions[j].X - mesh.Positions[i].X,
                    mesh.Positions[j].Y - mesh.Positions[i].Y,
                    mesh.Positions[j].Z - mesh.Positions[i].Z);
                Vector3D v1 = new Vector3D(
                     mesh.Positions[k].X - mesh.Positions[j].X,
                     mesh.Positions[k].Y - mesh.Positions[j].Y,
                     mesh.Positions[k].Z - mesh.Positions[j].Z);
     
                /* 3 normales par faces(1 normale/vertex) */
     
                mesh.Normals.Add(Vector3D.CrossProduct(v0, v1));
                mesh.Normals.Add(Vector3D.CrossProduct(v0, v1));
                mesh.Normals.Add(Vector3D.CrossProduct(v0, v1));
            }
            private Vector3D CalculateNormal(Point3D p0, Point3D p1, Point3D p2)
            {
                Vector3D v0 = new Vector3D(
                    p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
                Vector3D v1 = new Vector3D(
                    p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
                return Vector3D.CrossProduct(v0, v1);
            }
        }
    }
    bon code et bonne soiree...........

  10. #10
    Membre à l'essai
    Profil pro
    Étudiant
    Inscrit en
    Août 2012
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2012
    Messages : 25
    Points : 11
    Points
    11
    Par défaut
    Bonjour MABROUKI,

    merci beaucoup pour ta réponse complète. Cependant ton dernier post qui dit qu'il précise les mesh d'un cube signifie-t-il qu'on ne peut utiliser l'algorithme qu'avec des cubes?

    Par ailleurs tu as précisé
    Cet algo fonctionne correctement sur la plupart des "mesh" petzold.media....
    . Est-ce que ca signifie que ca fonctionne normalement moins bien sur d'autres géométries? Cela est gênant dans mon cas car je dois pour l'appliquer sur des géométries issues de logiciels de 3D tels que 3DSmax, qui donnent il me semble lorsque les géométries ne sont pas simples des maillages à l'aide de petits triangles.

    Est-ce que ton code est susceptible de fonctionner dans ce cas?

  11. #11
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    bonjour mickeycast
    Ma remarque visait en fait le cas ou tu ferais ta propre bibliotheque car tu dois faire attention à l'orientation des vertex par triangle (sens-anti horaire) lorsque tu genere tes vertex et leurs normales ..........(des vertex mal orientes generent des normales aberrantes)......
    J'ai teste l'algo sur la lib petzold.media car je n'ai pas 3dmaxet pour voir le sysndrome de la sphere et du cylindre.....
    C.Petzold par ailleurs est une reference chez microsoft pour la qualite du code..........
    Normalement il fonctionne sur des mesh generes par des logiciels pro car ils utilisent des vertex soigneusement ordonnes (sens anti-horaire)pour chaque triangle et leurs normales consequentes....ainsi que les coord. de textures.

    bon code...............

  12. #12
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    bonjour mickeycast....

    Je crois bien que ton countour d'objet 3D n'est autre que le "fameux Silhouette" d'un objet 3D...
    Evidement il est intiment lie a l'utilisation de l'algo deja vu precedement des "hidden removal lines" ou encore plus connu sous le nom "backculling faces" en 3D...
    L' algo "Silhouette Edges" consiste simplement a faire l'intersection booleenne des "segments" (cotes triangles elementaires) :
    - des faces visibles et faces hidden adjacentes(mitoyennes)...

    Qu'est ce à dire ?..
    - parcourir les segments -Si- dans chaque face Fi visible du mesh definit par ses 2 positions(coords 3D)..
    -retenir ce segment dans la "silhouette" s'il existe un segment adjacent -Sj- dans une face adjacente hiddenFj qui possedent les memes positions que Si...

    Pour remplir cette condition d'intersection des positions l'algo "Silhouette" necessite evidemment de ne pas utiliser les fameux :
    - "shared edges" => numeros de triangles indices identiques sur 2 faces adjacentes(mitoyennes)...
    A noter que l'api WPF recommende egalement cela mais pour d'autre raisons :le shading ou eclairage.....et que un mesh peut parfaitement etre decrit par des shared edges.....

    En effet avec des "shared edges" l'intersection booleenne n'a aucun sens(un segment commun ou partage sur 2 faces adjacentes aura en plus les memes numeros triangles indices )....
    Dans le "cube" donne en exemple les numeros triangles indices :
    - sont differents sur 2 faces mitoyennes meme s'ils referencent les memes positions(coord 3d des sommets).....
    En fait les triangles indices forment pour chaque segment(de chaque face triangulaire) une suite:
    - numeros vertexFrom- vertexTo...
    Compte-tenu du fait que l'algo "Silhouette " necessite de garder en memoire
    les listes :
    - faces triangles visibles
    - faces triangles hidden
    - "segments" de la "sil-houette" recherchee ...(contour 2D ou 3D whatever you want !),
    Il faut eviter de manipuler des listes de "flottant" (positions du mesh) vu la surcharge memoire....
    Pour cela 2 class auxiliares à base d' "integer" sont utilisees:
    - MeshSegment
    - MeshFace
    et initialise au debut de l'algo qui tient à jour la liste des faces (chacune possedant sa liste de segments reperes par les numero From et To).....

    bref voici sans attendre le :
    1er projet avec representation en 2D sur notre canvas d'un icosahedre de c.petzold (groupe fondamental en physique)....
    -segments visibles
    -segments hidden
    -segments "silhouete"(contour)...
    code behind .cs des simples class MeshSegment & MeshFace:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows.Media.Media3D;
     
    namespace WpfWireFrame3DBis
    {
        // class segment
        public class MeshSegment
        {
            public MeshSegment()
            {
                Face = Facing.None;
            }
            public int From { get; set; }
            public int To { get; set; }
            public Facing Face { get; set; }
        }
        // class MeshFace
        public class MeshFace
        {
            public MeshFace()
            {
                Segments = new List<MeshSegment>();
            }
            public List<MeshSegment> Segments { get; set; }
        }
        // class list des MeshFace
        public class MFaces : List<MeshFace>
        {
            private MeshFace mf;
            private MeshSegment seg;
            public MFaces()
            { }
            public MFaces(MeshGeometry3D m)
            {
                for (int i = 0; i < m.TriangleIndices.Count; i += 3)
                {
                    mf = new MeshFace();
                    seg = new MeshSegment();
                    seg.From = m.TriangleIndices[i];
                    seg.To = m.TriangleIndices[i + 1];
                    mf.Segments.Add(seg);
                    seg = new MeshSegment();
                    seg.From = m.TriangleIndices[i + 1];
                    seg.To = m.TriangleIndices[i + 2];
                    mf.Segments.Add(seg);
                    seg = new MeshSegment();
                    seg.From = m.TriangleIndices[i + 2];
                    seg.To = m.TriangleIndices[i];
                    mf.Segments.Add(seg);
                    this.Add(mf);
                }
            }
        }
        public enum Facing
        {
            Front,
            Back,
            None
        }
    }
    code xaml du form:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
     
    <Window x:Class="WpfWireFrame3DBis.WinSilhouette2D"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfWireFrame3DBis"
            xmlns:gm="clr-namespace:WpfCustomGeometries;assembly=WpfCustomGeometries"
            xmlns:lib="clr-namespace:Petzold.Media3D;assembly=Petzold.Media3D"
            Title="WinSilhouette2D" Height="300" Width="300">
        <Window.Resources>
            <gm:CustomCube
                x:Key ="custCubeGeom"
                Center="0,0,0"
                Length="0.5"
                Width="0.5"
                Height="0.5">
            </gm:CustomCube>
            <lib:BoxMesh 
                x:Key="box"
                 Depth="0.5"
                 Width="0.5"
                 Height="0.5"
                  >
            </lib:BoxMesh>
            <lib:CubeMesh 
                x:Key="cube"
                 >
            </lib:CubeMesh>
            <lib:TetrahedronMesh
                x:Key="tetrahedron"
                 >
            </lib:TetrahedronMesh>
            <lib:OctahedronMesh
                x:Key="octahedron"
                  >
            </lib:OctahedronMesh>
            <!--12 pentagonal faces,
             20 vertices and 30 edges.-->
            <lib:DodecahedronMesh
                x:Key="dodecahedron"
                 >
            </lib:DodecahedronMesh>
            <!--20 equilateral triangular faces,
              30 edges and 12 vertices. -->
            <lib:IcosahedronMesh
                x:Key="icosahedron"
                 >
            </lib:IcosahedronMesh>
            <lib:CylinderMesh
                x:Key="cylinder"
                 Length="1.0"
                 Radius="1.0"
                  >
            </lib:CylinderMesh>
            <lib:SphereMesh
                x:Key="sphere"
                 Center="0,0,0"
                 Radius="1.0"
                 Slices="10"
                 Stacks="10">
     
            </lib:SphereMesh>
            <lib:TorusMesh 
                x:Key="torus"
                Radius="1.0"
                TubeRadius="0.5"
                Slices="10"
                Stacks="10">
     
            </lib:TorusMesh>
              </Window.Resources>
        <Grid Margin="5">
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"></RowDefinition>
                <RowDefinition Height="*"></RowDefinition>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"></ColumnDefinition>
                <ColumnDefinition Width="*"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <StackPanel
                    Width="Auto"
                    Height="Auto">
                <Button 
                        Name="btnDrawNormal" 
                        Click="btnDrawNormal_Click"
                        Content="Draw Normals">
                </Button>
                <Button 
                        Name="btnDrawVisibleHiddenFaces" 
                        Click="btnDrawVisibleHiddenFaces_Click"
                        Content="Draw Visible And Hidden Faces">
                </Button>
                <CheckBox
                        Name="showVisibleFaces" 
                        IsChecked="True" 
                        Content="Show Visible Faces ">
                </CheckBox>
                <CheckBox
                        Name="showHiddenFaces" 
                        IsChecked="True" 
                        Content="Show Hidden Faces ">
                </CheckBox>
                <CheckBox 
                        Name="showSilhouette" 
                        IsChecked="True" 
                        Content="Show Silhouette Edges ">
                </CheckBox>
            </StackPanel>
            <StackPanel
                Width="auto"
                Height="auto"
                Grid.Column="1">
                <Slider 
                    x:Name="rotSliderY"
                    Maximum="360"
                    Minimum="0"
                    Value="0">
                </Slider>
                <Slider 
                    x:Name="rotSliderX"
                    Maximum="360"
                    Minimum="0"
                    Value="0">
                </Slider>
            </StackPanel>
            <!--Geometry="{Binding 
                        Source={StaticResource  
                        custCubeGeom},
                        Path=Mesh3D}">-->
            <Grid
                Grid.Row="1"
                Grid.Column="0"
                Grid.ColumnSpan="2">
                <Border 
                    BorderBrush="Gray" 
                    BorderThickness="1"
                    Background="White">
                    <Viewport3D 
                        Name="MyViewport"
                        >
                        <Viewport3D.Camera>
                            <!--4,5,6-->
                            <PerspectiveCamera 
                                x:Name="mainCam"
                                Position="4,4,6"
                                LookDirection="-4,-4,-6"
                                UpDirection="0,1,0"
                                FieldOfView="40"/>
                        </Viewport3D.Camera>
                        <!-- Set light source: -->
                        <ModelVisual3D >
                            <ModelVisual3D.Content>
                                <DirectionalLight 
                                    Color="White"
                                    Direction="10,-25, 0"
                                />
                            </ModelVisual3D.Content>
                        </ModelVisual3D>
                        <ModelVisual3D
                            x:Name="MyModel">
                            <ModelVisual3D.Content>
                                <GeometryModel3D
                                    x:Name="MyGeomModel"
                                    Geometry="{Binding 
                                    Source={StaticResource 
                                    icosahedron},
                                    Path=Geometry}">
                                    <GeometryModel3D.Material>
                                        <MaterialGroup>
                                            <DiffuseMaterial
                                                Brush="Red"   />
                                            <SpecularMaterial 
                                                SpecularPower="20"
                                                Brush="Yellow"/>
                                        </MaterialGroup>
     
                                    </GeometryModel3D.Material>
                                    <GeometryModel3D.Transform>
                                        <Transform3DGroup >
                                            <RotateTransform3D>
                                                <RotateTransform3D.Rotation>
                                                    <AxisAngleRotation3D
                                                    Angle="{Binding ElementName=rotSliderY,Path=Value}"
                                                    Axis="0,1,0"/>
                                                </RotateTransform3D.Rotation>
                                            </RotateTransform3D>
                                            <RotateTransform3D>
                                                <RotateTransform3D.Rotation>
                                                    <AxisAngleRotation3D
                                                    Angle="{Binding ElementName=rotSliderX,Path=Value}"
                                                    Axis="1,0,0"/>
                                                </RotateTransform3D.Rotation>
                                            </RotateTransform3D>
                                        </Transform3DGroup>
                                    </GeometryModel3D.Transform>
                                </GeometryModel3D>
                            </ModelVisual3D.Content>
                        </ModelVisual3D>
                    </Viewport3D>
                </Border>
                <Canvas
                    Name="MyCanvasOverlay">
                </Canvas>
            </Grid>
        </Grid>
    </Window>
    code behind .cs du form:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;
    using System.Windows.Media.Media3D;
    //ref à petzold media
    using Petzold.Media3D;
    namespace WpfWireFrame3DBis
    {
        /// <summary>
        /// Logique d'interaction pour WinSilhouette2D.xaml
        /// </summary>
        public partial class WinSilhouette2D : Window
        {
            Axes OX;
            Axes OY;
            public WinSilhouette2D()
            {
                InitializeComponent();
            }
     
            //dessine les axes 3D+axe camera
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                //x'Ox
                OX = new Petzold.Media3D.Axes();
                OX.Color = Colors.Red;
                OX.LineCollection.Add(new Point3D(4, 0, 0));
                OX.LineCollection.Add(new Point3D(3, 0, 0));
                OX.Thickness = 0.5;
                //y'Oy
                OY = new Petzold.Media3D.Axes();
                OY.Color = Colors.DarkBlue;
                OY.LineCollection.Add(new Point3D(0, -5, 0));
                OY.LineCollection.Add(new Point3D(0, 3, 0));
                OY.Thickness = 0.5;
                this.MyViewport.Children.Add(OX);
                this.MyViewport.Children.Add(OY);
     
     
            }
            // Dessin des normales 3D 
            List<WireLine> wireNormals = new List<WireLine>();
            private void btnDrawNormal_Click(object sender, RoutedEventArgs e)
            {
                GeometryModel3D geom3D = (GeometryModel3D)this.MyGeomModel;
                MeshGeometry3D mesh = (MeshGeometry3D)geom3D.Geometry;
                Transform3D trans3D = (Transform3D)this.MyGeomModel.Transform;
     
                // dessin Normales
                if (wireNormals.Count != 0)
                {
                    for (int i = 0; i < wireNormals.Count; i++)
                    {
                        this.MyViewport.Children.Remove(wireNormals[i]);
                    }
                }
     
                wireNormals.Clear();
                Point3D position;
                Vector3D normal;
                WireLine wln;
                int numVertex;
                for (int i = 0; i < mesh.TriangleIndices.Count; i++)
                {
                    numVertex = mesh.TriangleIndices[i];
                    position = mesh.Positions[numVertex];
                    //il faut appliquer le transform courant
                    position = trans3D.Transform(position);
                    normal = trans3D.Transform(mesh.Normals[numVertex]);
                    wln = new WireLine();
                    wln.Rounding = 10;
                    wln.Color = Colors.Brown;
                    wln.Thickness = 3;
                    //dessine segment du "position courant"  suivant direction du vecteur "normale courante"
                    // de longueur =module normale courante/ 0.3
                    wln.Point1 = position;
                    wln.Point2 = Vector3D.Add(Vector3D.Divide(normal, 3.0), position);
                    //segment est ajoute en 3d comme un objet wire 
                    this.MyViewport.Children.Add(wln);
                    wireNormals.Add(wln);
     
                }
     
     
     
            }
     
            private  Rect bounds2D;
     
            /* Dessin segments :
             - faces triangles  "visible" & "hidden"(algo "visible faces" ou "removal hidden lines") 
            -  ensuite algo "Silhouette": aretes Silhouette = "visible" intersection "hidden".... 
            */
     
            /*  store faces triangles  "visible" & "hidden"  */
            private MFaces FaceTriangles = new MFaces();
            //+ polylines correspondant 
            private List<Polyline> visPolylines = new List<Polyline>();
            private List<Polyline> hidPolylines = new List<Polyline>();
     
            /* store segments triangles  "Silhouette" */
            private List<MeshSegment>  silhoSegs = new List<MeshSegment>();
            //+ polylines correspondant 
            private List<Polyline> silhoPolylines = new List<Polyline>();
     
            private void btnDrawVisibleHiddenFaces_Click(object sender, RoutedEventArgs e)
            {
                //refresh canvas 
                this.MyCanvasOverlay.Children.Clear();
     
                //clear list faces & segments
                FaceTriangles.Clear();
                silhoSegs.Clear();
     
                visPolylines.Clear();
                hidPolylines.Clear();
                silhoPolylines.Clear();
                // Bounding Box ModelVisual3D
                bounds2D = this.MyModel.TransformToAncestor(this.MyViewport).TransformBounds(this.MyModel.Content.Bounds);
     
                // dessin Bounding Box 2D 
                Rectangle MyRectangle = new Rectangle();
                MyRectangle.Stroke = Brushes.Blue;
                MyRectangle.Width = bounds2D.Width;
                MyRectangle.Height = bounds2D.Height;
                Canvas.SetLeft(MyRectangle, bounds2D.X);
                Canvas.SetTop(MyRectangle, bounds2D.Y);
                MyCanvasOverlay.Children.Add(MyRectangle);
     
                // GeneralTransform3DTo2D 
                GeneralTransform3DTo2D tt = this.MyModel.TransformToAncestor(this.MyViewport);
     
                // Transform3D  du GeometryModel3D
                Transform3D trans3D = (Transform3D)this.MyGeomModel.Transform;
     
                /* GeometryModel3D & MeshGeometry3D */
                GeometryModel3D geom3D = (GeometryModel3D)this.MyGeomModel;
                MeshGeometry3D mesh = (MeshGeometry3D)geom3D.Geometry;
     
     
                /* Visible & Hidden Faces triangles  en 3D    */
                /* param: camera et mesh => 
                - cloner  mesh car  "freeze"  
                - appliquer transform3D: positions et normales */
                Point3D outPt3D = new Point3D(0, 0, 0);
                Vector3D outNormal = new Vector3D();
                MeshGeometry3D meshClone = mesh.Clone();
                for (int i = 0; i < meshClone.Positions.Count; i++)
                {
                    outPt3D = trans3D.Transform(meshClone.Positions[i]);
                    meshClone.Positions[i] = outPt3D;
                    outNormal = trans3D.Transform(meshClone.Normals[i]);
                    meshClone.Normals[i] = outNormal;
                }
     
     
                /* "contour" projete 2D des points 3D  */
     
                 GetSegmentsSilhouette(meshClone, this.mainCam, ref FaceTriangles, ref silhoSegs);
     
                Point3D pt3D;
                Point pt2D;
                MeshFace mf;
                MeshSegment seg;
                Polyline myPoly;
                // segments "visible" & "hidden"
                for (int i = 0; i < FaceTriangles.Count; i++)
                {
                    mf=FaceTriangles[i];
                    for (int j = 0; j < mf.Segments.Count; j++)
                    { 
                        seg=mf.Segments[j];
                        if (seg.Face==Facing.Front )
                        {
                            myPoly = new Polyline();
                            pt3D = meshClone.Positions[seg.From];
                            pt2D = tt.Transform(pt3D);
                            myPoly.Points.Add(pt2D);
     
                            pt3D = meshClone.Positions[seg.To];
                            pt2D = tt.Transform(pt3D);
                            myPoly.Points.Add(pt2D);
     
                            visPolylines.Add(myPoly);
                        }
                        else if(seg.Face == Facing.Back)
                        {
                            myPoly = new Polyline();
                            pt3D = meshClone.Positions[seg.From];
                            pt2D = tt.Transform(pt3D);
                            myPoly.Points.Add(pt2D);
     
                            pt3D = meshClone.Positions[seg.To];
                            pt2D = tt.Transform(pt3D);
                            myPoly.Points.Add(pt2D);
     
                            hidPolylines.Add(myPoly);
                        }
     
                    }
     
                }
     
                // segments "Silhouette"
                for (int i = 0; i < silhoSegs.Count; i++)
                {
                    seg = silhoSegs[i];
                    myPoly = new Polyline();
     
                    pt3D = meshClone.Positions[seg.From];
                    pt2D = tt.Transform(pt3D );
                    myPoly.Points.Add(pt2D);
     
                    pt3D = meshClone.Positions[seg.To];
                    pt2D = tt.Transform(pt3D);
                    myPoly.Points.Add(pt2D);
     
                    silhoPolylines.Add(myPoly);
                }
                // dessin  polylines "visible"
                foreach (Polyline pln in visPolylines)
                {
     
                    if (this.showVisibleFaces.IsChecked == true)
                    {
                        pln.Visibility = Visibility.Visible;
                    }
                    else
                    {
                        pln.Visibility = Visibility.Hidden;
                    }
                    pln.Stroke = Brushes.LightPink; ;
                    pln.StrokeThickness = 4.0;
                    MyCanvasOverlay.Children.Add(pln);
                }
                // dessin  polylines "hidden"
                foreach (Polyline pln in hidPolylines)
                {
                    if (this.showHiddenFaces.IsChecked == true)
                    {
                        pln.Visibility = Visibility.Visible;
                    }
                    else
                    {
                        pln.Visibility = Visibility.Hidden;
                    }
                    pln.Stroke = Brushes.Yellow;
                    pln.StrokeThickness = 1.5;
                    MyCanvasOverlay.Children.Add(pln);
                }
                // dessin  polylines "Silhouette"
                foreach (Polyline pln in silhoPolylines)
                {
                    if (this.showSilhouette.IsChecked == true)
                    {
                        pln.Visibility = Visibility.Visible;
                    }
                    else
                    {
                        pln.Visibility = Visibility.Hidden;
                    }
                    pln.Stroke = Brushes.LimeGreen ;
                    pln.StrokeThickness = 2.0;
                    MyCanvasOverlay.Children.Add(pln);
                }
            }
     
            // faces triangles  "visible" & "hidden": algo "visible faces" ou "removal hidden lines" 
            // segments silhouettes = "visible" intersection "hidden"....:algo "silhouette": 
            private void GetSegmentsSilhouette(MeshGeometry3D mesh, PerspectiveCamera cam,
                                              ref MFaces FacesTriangles, ref List<MeshSegment> silhoSegs)
            {
                //vector camera
                Vector3D viewer;
     
                //construit faces triangles et leurs segments  
                FacesTriangles = new MFaces(mesh );
                int  numFromVert = 0;
                int  numToVert=0;
                double dotFrom = 0.0;
                double dotTo = 0.0;
     
                for (int i = 0; i < FacesTriangles.Count; i ++)
                {
                    MeshFace mf = FacesTriangles[i];
                    for (int j =0; j < mf.Segments.Count; j++)
                    {
                        viewer = cam.LookDirection;
                        numFromVert = mf.Segments[j].From;
                        dotFrom = Vector3D.DotProduct(viewer, mesh.Normals[numFromVert]);
     
                        numToVert = mf.Segments[j].To;
                        dotTo = Vector3D.DotProduct(viewer, mesh.Normals[numToVert]);
     
                        // si dot produit scalaire negatif => vertex visible 
                        if (dotFrom < 0 && dotTo < 0 )
                        {
                            /* mark "visible" segment */
                            mf.Segments[j].Face = Facing.Front;
     
                        }
                        else 
                        {
                            /* mark "hidden" segment */
                            mf.Segments[j].Face = Facing.Back;
     
                        }
     
                    }
     
                }
                // init...egdes silhouette new version
                silhoSegs = new List<MeshSegment>();
                for (int i = 0; i < FacesTriangles.Count; i++)
                {
                    MeshFace   mf1 = FacesTriangles[i];
                    for (int j = 0; j < mf1.Segments.Count; j++)
                    {
                        MeshSegment seg1 = mf1.Segments[j];
     
                        for (int k = 0; k < FacesTriangles.Count; k++)
                        {
                            MeshFace mf2 = FacesTriangles[k];
                            if (mf2 == mf1) continue;
                            for (int n = 0; n < mf2.Segments.Count; n++)
                            { 
                                MeshSegment seg2 = mf2.Segments[n];
                                if (seg2.Face != seg1.Face)
                                {
                                    if (mesh.Positions[seg2.From] ==mesh.Positions[seg1.From] && mesh.Positions[seg2.To] ==mesh.Positions[seg1.To])
                                    {
                                        silhoSegs.Add(seg1);
                                    }
                                    else if (mesh.Positions[seg2.From] ==mesh.Positions[seg1.To] && mesh.Positions[seg2.To] ==mesh.Positions[seg1.From] )
                                    {
                                        silhoSegs.Add(seg1);
                                    }
                                }
     
                            }
                        }
                    }
     
                }
     
            }
        }
     
     
    }
    2eme projet avec representation en 3D dans le viewport3D(wirepolyline) du meme icosahedre :
    code xaml du winform:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
     
    <Window x:Class="WpfWireFrame3DBis.WinSilhouetteWire"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WpfWireFrame3DBis"
            xmlns:gm="clr-namespace:WpfCustomGeometries;assembly=WpfCustomGeometries"
            xmlns:lib="clr-namespace:Petzold.Media3D;assembly=Petzold.Media3D"
            Title="WinSilhouetteWire" Height="300" Width="300">
        <Window.Resources>
            <gm:CustomCube
                x:Key ="custCubeGeom"
                Center="0,0,0"
                Length="0.5"
                Width="0.5"
                Height="0.5">
            </gm:CustomCube>
            <lib:BoxMesh 
                x:Key="box"
                 Depth="0.5"
                 Width="0.5"
                 Height="0.5"
                  >
            </lib:BoxMesh>
            <lib:CubeMesh 
                x:Key="cube"
                 >
            </lib:CubeMesh>
            <lib:TetrahedronMesh
                x:Key="tetrahedron"
                 >
            </lib:TetrahedronMesh>
            <lib:OctahedronMesh
                x:Key="octahedron"
                  >
            </lib:OctahedronMesh>
            <!--12 pentagonal faces,
             20 vertices and 30 edges.-->
            <lib:DodecahedronMesh
                x:Key="dodecahedron"
                 >
            </lib:DodecahedronMesh>
            <!--20 equilateral triangular faces,
              30 edges and 12 vertices. -->
            <lib:IcosahedronMesh
                x:Key="icosahedron"
                 >
            </lib:IcosahedronMesh>
            <lib:CylinderMesh
                x:Key="cylinder"
                 Length="1.0"
                 Radius="1.0"
                  >
            </lib:CylinderMesh>
            <lib:SphereMesh
                x:Key="sphere"
                 Center="0,0,0"
                 Radius="1.0"
                 Slices="10"
                 Stacks="10">
     
            </lib:SphereMesh>
            <lib:TorusMesh 
                x:Key="torus"
                Radius="1.0"
                TubeRadius="0.5"
                Slices="10"
                Stacks="10">
     
            </lib:TorusMesh>
                   <lib:Axes 
                x:Key="YOY"
                Color="DarkBlue" 
                Thickness="0.5"
                >
        </Window.Resources>
        <Grid Margin="5">
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"></RowDefinition>
                <RowDefinition Height="*"></RowDefinition>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"></ColumnDefinition>
                <ColumnDefinition Width="*"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <StackPanel
                    Width="Auto"
                    Height="Auto">
                <Button 
                        Name="btnDrawNormal" 
                        Click="btnDrawNormal_Click"
                        Content="Draw Normals">
                </Button>
                <Button 
                        Name="btnDrawVisibleHiddenFaces" 
                        Click="btnDrawVisibleHiddenFaces_Click"
                        Content="Draw Visible And Hidden Faces">
                </Button>
                <CheckBox
                        Name="showVisibleFaces" 
                        IsChecked="True" 
                        Content="Show Visible Faces ">
                </CheckBox>
                <CheckBox
                        Name="showHiddenFaces" 
                        IsChecked="True" 
                        Content="Show Hidden Faces ">
                </CheckBox>
                <CheckBox 
                        Name="showSilhouette" 
                        IsChecked="True" 
                        Content="Show Silhouette Edges ">
                </CheckBox>
            </StackPanel>
            <StackPanel
                Width="auto"
                Height="auto"
                Grid.Column="1">
                <Slider 
                    x:Name="rotSliderY"
                    Maximum="360"
                    Minimum="0"
                    Value="0">
                </Slider>
                <Slider 
                    x:Name="rotSliderX"
                    Maximum="360"
                    Minimum="0"
                    Value="0">
                </Slider>
            </StackPanel>
            <!--Geometry="{Binding 
                        Source={StaticResource  
                        custCubeGeom},
                        Path=Mesh3D}">-->
            <Grid
                Grid.Row="1"
                Grid.Column="0"
                Grid.ColumnSpan="2">
                <Border 
                    BorderBrush="Gray" 
                    BorderThickness="1"
                    Background="White">
                    <Viewport3D 
                        Name="MyViewport"
                        >
                        <Viewport3D.Camera>
                            <!--4,5,6-->
                            <PerspectiveCamera 
                                x:Name="mainCam"
                                Position="4,4,6"
                                LookDirection="-4,-4,-6"
                                UpDirection="0,1,0"
                                FieldOfView="40"/>
                        </Viewport3D.Camera>
                        <!-- Set light source: -->
                        <ModelVisual3D >
                            <ModelVisual3D.Content>
                                <DirectionalLight 
                                    Color="White"
                                    Direction="10,-25, 0"
                                />
                            </ModelVisual3D.Content>
                        </ModelVisual3D>
                        <ModelVisual3D
                            x:Name="MyModel">
                            <ModelVisual3D.Content>
                                <GeometryModel3D
                                    x:Name="MyGeomModel"
                                    Geometry="{Binding 
                                    Source={StaticResource 
                                    icosahedron},
                                    Path=Geometry}">
                                    <GeometryModel3D.Material>
                                        <MaterialGroup>
                                            <DiffuseMaterial
                                                Brush="Red"   />
                                            <SpecularMaterial 
                                                SpecularPower="20"
                                                Brush="Yellow"/>
                                        </MaterialGroup>
                                    </GeometryModel3D.Material>
                                    <GeometryModel3D.Transform>
                                        <Transform3DGroup >
                                            <RotateTransform3D>
                                                <RotateTransform3D.Rotation>
                                                    <AxisAngleRotation3D
                                                    Angle="{Binding ElementName=rotSliderY,Path=Value}"
                                                    Axis="0,1,0"/>
                                                </RotateTransform3D.Rotation>
                                            </RotateTransform3D>
                                            <RotateTransform3D>
                                                <RotateTransform3D.Rotation>
                                                    <AxisAngleRotation3D
                                                    Angle="{Binding ElementName=rotSliderX,Path=Value}"
                                                    Axis="1,0,0"/>
                                                </RotateTransform3D.Rotation>
                                            </RotateTransform3D>
                                        </Transform3DGroup>
                                    </GeometryModel3D.Transform>
                                </GeometryModel3D>
                            </ModelVisual3D.Content>
                        </ModelVisual3D>
                    </Viewport3D>
                </Border>
            </Grid>
        </Grid>
    </Window>
    code behind .cs du winform:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;
    using System.Windows.Media.Media3D;
    //ref à petzold media
    using Petzold.Media3D;
     
    namespace WpfWireFrame3DBis
    {
        /// <summary>
        /// Logique d'interaction pour WinSilhouetteWire.xaml
        /// </summary>
        public partial class WinSilhouetteWire : Window
        {
            Axes OX;
            Axes OY;
            public WinSilhouetteWire()
            {
                InitializeComponent();
            }
            //dessine les axes 3D+axe camera
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                //x'Ox
                OX = new Petzold.Media3D.Axes();
                OX.Color = Colors.Red;
                OX.LineCollection.Add(new Point3D(4, 0, 0));
                OX.LineCollection.Add(new Point3D(3, 0, 0));
                OX.Thickness = 0.5;
                //y'Oy
                OY = new Petzold.Media3D.Axes();
                OY.Color = Colors.DarkBlue;
                OY.LineCollection.Add(new Point3D(0, -5, 0));
                OY.LineCollection.Add(new Point3D(0, 3, 0));
                OY.Thickness = 0.5;
                this.MyViewport.Children.Add(OX);
                this.MyViewport.Children.Add(OY);
     
     
            }
            // Dessin des normales 3D 
            List<WireLine> wireNormals = new List<WireLine>();
            private void btnDrawNormal_Click(object sender, RoutedEventArgs e)
            {
                GeometryModel3D geom3D = (GeometryModel3D)this.MyGeomModel;
                MeshGeometry3D mesh = (MeshGeometry3D)geom3D.Geometry;
                Transform3D trans3D = (Transform3D)this.MyGeomModel.Transform;
     
                // dessin Normales
                if (wireNormals.Count != 0)
                {
                    for (int i = 0; i < wireNormals.Count; i++)
                    {
                        this.MyViewport.Children.Remove(wireNormals[i]);
                    }
                }
     
                wireNormals.Clear();
                Point3D position;
                Vector3D normal;
                WireLine wln;
                int numVertex;
                for (int i = 0; i < mesh.TriangleIndices.Count; i++)
                {
                    numVertex = mesh.TriangleIndices[i];
                    position = mesh.Positions[numVertex];
                    //il faut appliquer le transform courant
                    position = trans3D.Transform(position);
                    normal = trans3D.Transform(mesh.Normals[numVertex]);
                    wln = new WireLine();
                    wln.Rounding = 10;
                    wln.Color = Colors.Brown;
                    wln.Thickness = 3;
                    //dessine segment du "position courant"  suivant direction du vecteur "normale courante"
                    // de longueur =module normale courante/ 0.3
                    wln.Point1 = position;
                    wln.Point2 = Vector3D.Add(Vector3D.Divide(normal, 3.0), position);
                    //segment est ajoute en 3d comme un objet wire 
                    this.MyViewport.Children.Add(wln);
                    wireNormals.Add(wln);
     
                }
     
     
     
            }
     
     
            /* Dessin segments :
             - faces triangles  "visible" & "hidden"(algo "visible faces" ou "removal hidden lines") 
            -  ensuite algo "Silhouette": aretes Silhouette = "visible" intersection "hidden".... 
            */
     
            /*  store faces triangles  "visible" & "hidden"  */
            private MFaces FaceTriangles = new MFaces();
            //+ WirePolylines correspondant 
            private List<WirePolyline> visWPolylines = new List<WirePolyline>();
            private List<WirePolyline> hidWPolylines = new List<WirePolyline>();
     
            /* store segments triangles  "Silhouette" */
            private List<MeshSegment> silhoSegs = new List<MeshSegment>();
            //+ polylines correspondant 
            private List<WirePolyline> silhoWPolylines = new List<WirePolyline>();
     
            private void btnDrawVisibleHiddenFaces_Click(object sender, RoutedEventArgs e)
            {
     
                //clear list faces & segments
                FaceTriangles.Clear();
                silhoSegs.Clear();
     
                //refresh lists WirePolylines & viewport
                if (visWPolylines.Count != 0)
                {
                    foreach(WirePolyline pln in visWPolylines )
                    {
                        MyViewport.Children.Remove(pln);
                    }
                }
                visWPolylines.Clear();
                if (hidWPolylines.Count != 0)
                {
                    foreach (WirePolyline pln in hidWPolylines)
                    {
                        MyViewport.Children.Remove(pln);
                    }
                } 
                 hidWPolylines.Clear();
                 if (silhoWPolylines.Count != 0)
                 {
                     foreach (WirePolyline pln in silhoWPolylines)
                     {
                         MyViewport.Children.Remove(pln);
                     }
                 } 
                silhoWPolylines.Clear();
     
     
                // GeneralTransform3DTo2D 
                GeneralTransform3DTo2D tt = this.MyModel.TransformToAncestor(this.MyViewport);
     
                // Transform3D  du GeometryModel3D
                Transform3D trans3D = (Transform3D)this.MyGeomModel.Transform;
     
                /* GeometryModel3D & MeshGeometry3D */
                GeometryModel3D geom3D = (GeometryModel3D)this.MyGeomModel;
                MeshGeometry3D mesh = (MeshGeometry3D)geom3D.Geometry;
     
     
                /* Visible & Hidden Faces triangles  en 3D    */
                /* param: camera et mesh => 
                - cloner  mesh car  "freeze"  
                - appliquer transform3D: positions et normales */
                Point3D outPt3D = new Point3D(0, 0, 0);
                Vector3D outNormal = new Vector3D();
                MeshGeometry3D meshClone = mesh.Clone();
                for (int i = 0; i < meshClone.Positions.Count; i++)
                {
                    outPt3D = trans3D.Transform(meshClone.Positions[i]);
                    meshClone.Positions[i] = outPt3D;
                    outNormal = trans3D.Transform(meshClone.Normals[i]);
                    meshClone.Normals[i] = outNormal;
                }
     
     
                /* "contour" des points 3D  */
     
                GetSegmentsSilhouette(meshClone, this.mainCam, ref FaceTriangles, ref silhoSegs);
     
                Point3D pt3D;
                //Point pt2D;pas besoin de transform tt
                MeshFace mf;
                MeshSegment seg;
                WirePolyline myWirePoly;
                // segments "visible" & "hidden"
                for (int i = 0; i < FaceTriangles.Count; i++)
                {
                    mf = FaceTriangles[i];
                    for (int j = 0; j < mf.Segments.Count; j++)
                    {
                        seg = mf.Segments[j];
                        if (seg.Face == Facing.Front)
                        {
                            myWirePoly = new WirePolyline();
                            myWirePoly.Points = new Point3DCollection();
                            pt3D = meshClone.Positions[seg.From];
                            myWirePoly.Points.Add(pt3D);
     
                            pt3D = meshClone.Positions[seg.To];
                            myWirePoly.Points.Add(pt3D);
     
                            visWPolylines.Add(myWirePoly);
                        }
                        else if (seg.Face == Facing.Back)
                        {
                            myWirePoly = new WirePolyline();
                            myWirePoly.Points = new Point3DCollection(); 
                            pt3D = meshClone.Positions[seg.From];
                            myWirePoly.Points.Add(pt3D);
     
                            pt3D = meshClone.Positions[seg.To];
                            myWirePoly.Points.Add(pt3D);
     
                            hidWPolylines.Add(myWirePoly);
                        }
     
                    }
     
                }
     
                // segments "Silhouette"
                for (int i = 0; i < silhoSegs.Count; i++)
                {
                    seg = silhoSegs[i];
                    myWirePoly = new WirePolyline() ;
                    myWirePoly.Points = new Point3DCollection();
     
                    pt3D = meshClone.Positions[seg.From];
                    myWirePoly.Points.Add(pt3D);
     
                    pt3D = meshClone.Positions[seg.To];
                    myWirePoly.Points.Add(pt3D);
     
                    silhoWPolylines.Add(myWirePoly);
                }
                // dessin  WirePolylines "visible" dans Viewport3D 
                if (this.showVisibleFaces.IsChecked == true)
                {
                    foreach (WirePolyline pln in visWPolylines)
                    {
                        pln.Color  =Colors.LightPink ;
                        pln.Thickness = 4.0;
                        MyViewport.Children.Add(pln);
                    }
                }
                // dessin  polylines "hidden"
                if (this.showHiddenFaces.IsChecked == true)
                {
                    foreach (WirePolyline pln in hidWPolylines)
                    {
                        pln.Color = Colors.Yellow;
                        pln.Thickness = 1.5;
                        MyViewport.Children.Add(pln);
                    }
                }
                // dessin  polylines "Silhouette"
                if (this.showSilhouette.IsChecked == true)
                {
                    foreach (WirePolyline pln in silhoWPolylines)
                    {
                        pln.Color = Colors.Turquoise ;
                        pln.Thickness = 2.0;
                        MyViewport.Children.Add(pln);
                    }
                }
            }
     
            // faces triangles  "visible" & "hidden": algo "visible faces" ou "removal hidden lines" 
            // segments silhouettes = "visible" intersection "hidden"....:algo "silhouette": 
            private void GetSegmentsSilhouette(MeshGeometry3D mesh, PerspectiveCamera cam,
                                              ref MFaces FacesTriangles, ref List<MeshSegment> silhoSegs)
            {
                //vector camera
                Vector3D viewer;
     
                //construit faces triangles et leurs segments  
                FacesTriangles = new MFaces(mesh);
                int numFromVert = 0;
                int numToVert = 0;
                double dotFrom = 0.0;
                double dotTo = 0.0;
     
                for (int i = 0; i < FacesTriangles.Count; i++)
                {
                    MeshFace mf = FacesTriangles[i];
                    for (int j = 0; j < mf.Segments.Count; j++)
                    {
                        viewer = cam.LookDirection;
                        numFromVert = mf.Segments[j].From;
                        dotFrom = Vector3D.DotProduct(viewer, mesh.Normals[numFromVert]);
     
                        numToVert = mf.Segments[j].To;
                        dotTo = Vector3D.DotProduct(viewer, mesh.Normals[numToVert]);
     
                        // si dot produit scalaire negatif => vertex visible 
                        if (dotFrom < 0 && dotTo < 0)
                        {
                            /* mark "visible" segment */
                            mf.Segments[j].Face = Facing.Front;
     
                        }
                        else
                        {
                            /* mark "hidden" segment */
                            mf.Segments[j].Face = Facing.Back;
     
                        }
     
                    }
     
                }
                // init...egdes silhouette 
                silhoSegs = new List<MeshSegment>();
                for (int i = 0; i < FacesTriangles.Count; i++)
                {
                    MeshFace mf1 = FacesTriangles[i];
                    for (int j = 0; j < mf1.Segments.Count; j++)
                    {
                        MeshSegment seg1 = mf1.Segments[j];
     
                        for (int k = 0; k < FacesTriangles.Count; k++)
                        {
                            MeshFace mf2 = FacesTriangles[k];
                            if (mf2 == mf1) continue;
                            for (int n = 0; n < mf2.Segments.Count; n++)
                            {
                                MeshSegment seg2 = mf2.Segments[n];
                                if (seg2.Face != seg1.Face)
                                {
                                    if (mesh.Positions[seg2.From] == mesh.Positions[seg1.From] && mesh.Positions[seg2.To] == mesh.Positions[seg1.To])
                                    {
                                        silhoSegs.Add(seg1);
                                    }
                                    else if (mesh.Positions[seg2.From] == mesh.Positions[seg1.To] && mesh.Positions[seg2.To] == mesh.Positions[seg1.From])
                                    {
                                        silhoSegs.Add(seg1);
                                    }
                                }
     
                            }
                        }
                    }
     
                }
     
            }
        }
     
    }
    Drawbacks de l'algo deja signale:
    -teste le cylindre de c.petzold pour voir pourquoi les 2 aretes visibles verticales du cylindre qui fement le contour n'apparaissent pas(elles n'ont pas d'aretes adjacentes adjacentes hidden vu la symetrie de cet objet)..
    Il en est de meme de la sphere pour les "meridiens extremes " qui forment le contour(pas d'aretes adjacentes invisibles)....
    Au fait l'algo "silhouette" tire son nom du fait que les "artistes" voulaient recuperer la silhouette (contour y compris les aretes visibles)...
    Une autre utilisation de cette algo est le calcul de la fameuse ombre en prenant un vecteur light (light directionnel oriente dans le sens voulu) au lieu vecteur camera ...les aretes projetes en 2D ou 3D forment l'ombre de l'objet
    3D cible.....
    bon code.......

Discussions similaires

  1. Contours d'objet après triangulation
    Par enita dans le forum MATLAB
    Réponses: 3
    Dernier message: 28/06/2011, 17h37
  2. Tracé de contours (outlining)
    Par pottiez dans le forum Contribuez
    Réponses: 0
    Dernier message: 03/01/2011, 14h47
  3. Trier des vertices pour tracé de contour
    Par Djakisback dans le forum Algorithmes et structures de données
    Réponses: 22
    Dernier message: 12/06/2010, 13h46
  4. Tracé de contour dans des tableaux
    Par airballman dans le forum Calcul scientifique
    Réponses: 4
    Dernier message: 17/07/2009, 09h03
  5. tracé d'un contour
    Par Omfraax dans le forum OpenGL
    Réponses: 13
    Dernier message: 06/03/2006, 21h42

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo