dotNed

Welkom bij dotNed Inloggen | Aanmelden | Help
in Zoeken

Dennis' avonturen in .net

3D Graphics in WPF, deel 8 (het tekenen van de box in code)

We hebben bijna alle elementen op hun plaats staan voor onze Box class. Het enige wat we nu nog moeten doen is het daadwerkelijke tekenen. Hier is de code

private void DrawIt()

{

    // Maak een kopie

    var positions = _mesh.Positions;

    var indices = _mesh.TriangleIndices;

    var normals = _mesh.Normals;

    var textures = _mesh.TextureCoordinates;

 

    _mesh.Positions = null;

    _mesh.TriangleIndices = null;

    _mesh.Normals = null;

    _mesh.TextureCoordinates = null;

 

    positions.Clear();

    indices.Clear();

    normals.Clear();

    textures.Clear();

 

    // Definieer de punten

    Point3D pointA = LeftBottomCorner;

    Point3D pointB = new Point3D(LeftBottomCorner.X + Width, LeftBottomCorner.Y, LeftBottomCorner.Z);

    Point3D pointC = new Point3D(LeftBottomCorner.X + Width, LeftBottomCorner.Y, LeftBottomCorner.Z - Depth);

    Point3D pointD = new Point3D(LeftBottomCorner.X, LeftBottomCorner.Y, LeftBottomCorner.Z - Depth);

    Point3D pointE = new Point3D(LeftBottomCorner.X, LeftBottomCorner.Y + Height, LeftBottomCorner.Z);

    Point3D pointF = new Point3D(LeftBottomCorner.X + Width, LeftBottomCorner.Y + Height, LeftBottomCorner.Z);

    Point3D pointG = new Point3D(LeftBottomCorner.X + Width, LeftBottomCorner.Y + Height, LeftBottomCorner.Z - Depth);

    Point3D pointH = new Point3D(LeftBottomCorner.X, LeftBottomCorner.Y + Height, LeftBottomCorner.Z - Depth);

 

    // Voeg de punten toe

    // Grond vlak

    positions.Add(pointD);

    positions.Add(pointC);

    positions.Add(pointB);

    positions.Add(pointA);

    // Voor vlak

    positions.Add(pointA);

    positions.Add(pointB);

    positions.Add(pointF);

    positions.Add(pointE);

    // Rechtervlak

    positions.Add(pointB);

    positions.Add(pointC);

    positions.Add(pointG);

    positions.Add(pointF);

    // Achter vlak

    positions.Add(pointC);

    positions.Add(pointD);

    positions.Add(pointH);

    positions.Add(pointG);

    // Linker vlak

    positions.Add(pointD);

    positions.Add(pointA);

    positions.Add(pointE);

    positions.Add(pointH);

    // Boven vlak

    positions.Add(pointE);

    positions.Add(pointF);

    positions.Add(pointG);

    positions.Add(pointH);

 

    // Voeg de TriangleIndices toe.

    for (int i = 0; i

    {

        indices.Add((i * 4) + 0);

        indices.Add((i * 4) + 1);

        indices.Add((i * 4) + 2);

        indices.Add((i * 4) + 0);

        indices.Add((i * 4) + 2);

        indices.Add((i * 4) + 3);

    }

 

    // Zet de collections terug in de mesh

    _mesh.TextureCoordinates = textures;

    _mesh.Normals = normals;

    _mesh.TriangleIndices = indices;

    _mesh.Positions = positions;

}

Het lijkt veel maar echt ingewikkeld is het niet. Er is echter een klein dingetje dat wel erg belangrijk is: de properties Positions, TriangleIndices, Normals en TextureCoordinates (die laaste is nieuw, daar kom ik op terug als we het over materialen gaan hebben) zijn DependencyProperties. Als we iets wijzigigen in deze collections, zal er een PropertyChanged even afgevuurd worden in onze _mesh member (van het type MeshGeometry3D) en wordt de boel opnieuw getekend. Voor ieder punt dat we toevoegen zal hij opnieuw berekend worden. Ook voor iedere TriangleIndex die we toevoegen gaan WPF opnieuw rekenen. Hetzelfde geldt voor de Normals en TextureCoordinates collections. Aangezien we een hoop punten en zo toevoegen zal er een hoop nodeloze berekeningen plaats gaan vinden!

Om dat te voorkomen maken we eerst een kopie van de collections. Vervolgens zetten we de properties van de _mesh op null. Als we nu iets doen met de kopie van de collections heeft dat geen enkele invloed op de _mesh. Aan het einde van de method plaatsen we de gewijzigde collecties weer terug in de _mesh waarna WPF alles opnieuw gaat berekenen. Dit scheelt enorm veel tijd!

Nu we een kopie hebben van de collecties, wissen we de inhoud. Immers: we gaan alles opnieuw maken!

Ik definieer eerst de 8 hoekpunten. Dat hoef ik maar een maal te doen, we hergebruiken de gemaakte punten later bij het toevoegen aan de positions collectie. Je ziet dat de punten gelijk op de goede plaats staan: ik tel de linkeronder hoek er bij op en zorg ervoor dat de Width, Height en Depth gelijk meegenomen worden.

Nu definieren we de zes vlakken. Let er op dat je het wel in de goede volgorde doet, alle punten worden tegen de klok in gedefinieerd.

Als we alle punten toegevoegd hebben, wordt het tijd om de TriangleIndices berekent. Dit is hetzelfde als wat je gezien hebt in mijn vorige post, nu alleen voor alle vlakken. Als dat gebeurdt is, plaatsen we de collecties terug en we zijn klaar!

Nou ja.. we moeten nog een aanroep naar DrawIt() plaatsen in de constructor (aan het einde) en belangrijker: in de PropertyChanged:

///

/// Initializes a new instance of the class.

///

public Box()

{

    _model = new GeometryModel3D();

    _mesh = new MeshGeometry3D();

    _model.Geometry = _mesh;

    this.Content = _model;

 

    DrawIt();

}

en...

///

/// Handles the Property Changed event (static)

///

/// The

/// instance containing the event data.

private void PropertyChanged(DependencyPropertyChangedEventArgs args)

{

    // opnieuw tekenen!

    DrawIt();

}

Om dit nu zichtbaar te maken in onze XAML file, moeten we een referentie naar deze code in de header van de file maken.

De XAML ziet er nu als volgt uit:

<Window x:Class="WpfApplication11.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:detrio="clr-namespace:WpfApplication11"
    Title="Window1" Height="300" Width="300">
    <Viewport3D>
        <detrio:Box LeftBottomCorner="0 0 0" Width="1" Height="1" Depth="1">
            <detrio:Box.Material>
                <DiffuseMaterial Brush="Blue"/>
            </detrio:Box.Material>
        </detrio:Box>

        <!-- Lampjes! -->
        <ModelVisual3D>
            <ModelVisual3D.Content>
                <Model3DGroup>
                    <AmbientLight Color="#404040"/>
                    <DirectionalLight Color="#BFBFBF" Direction="1 -1 -1"/>
                </Model3DGroup>
            </ModelVisual3D.Content>
        </ModelVisual3D>

        <!-- Camera -->
        <Viewport3D.Camera>
            <PerspectiveCamera Position="2.1 2 2" 
                           LookDirection="-0.5 -0.7 -1" 
                           UpDirection="0 1 0" 
                           FieldOfView="60.0" 
                           />
        </Viewport3D.Camera>
    </Viewport3D>
</Window>

En meer hebben we niet nodig!

Ik weet niet hoe het met jou zit, maar ik ben dat blauwe blokje een beetje zat. Laten we de volgende keer eens kijken of we die niet mooier kunnen maken, laten we het eens over Materials gaan hebben!

Published Thursday, August 28, 2008 10:24 AM door dvroegop
Filed Under: ,

Comments

No Comments
Anonymous comments are disabled

About dvroegop

Programmeert al sinds 1982. Microsoft Surface MVP.
Powered by Community Server, by Telligent Systems