Entwickler-Ecke

WPF / Silverlight - TextureCoordinates


_Joe_ - Mo 09.02.09 17:26
Titel: TextureCoordinates
Hallo,

ich arbeite mit Silverlight + Kit3D. Ich würde gern Bilder(Layer) um ein Objekt legen, leider weis ich nicht so genau wie. Bilder um einfache Objekte wie Vierecke,Dreiecke oder Kegel zu legen ist nicht sonderlich schwer. Aber bei Freiform Objekten bin ich überfragt, denn ich weis nicht wie ich Texturkoordinaten für ein beliebiges Objekt ausrechnen soll.

Eine Möglichkeit wäre es für jedes Dreieck was zu berechen. Nur hab auch hier keine Idee wie das gehen soll.


Kha - Mo 09.02.09 17:40

Wenn du deinen Text nicht mindestens auf das Vierfache aufblähst, sehe ich keine Hoffnung, da irgendetwas zu verstehen - schon der Zusammenhang von Text und Überschrift bleibt mir verschlossen :nixweiss: . Geht es um Media3D/Kit3D?


_Joe_ - Mo 09.02.09 18:25

update, hoffe das ist verständlicher :)


Kha - Mo 09.02.09 19:07
Titel: Re: TextureCoordinates
Viel besser, danke :D .
user profile icon_Joe_ hat folgendes geschrieben Zum zitierten Posting springen:
Eine Möglichkeit wäre es für jedes Dreieck was zu berechen.
Ja, UV-Koordinaten für jedes Tri muss ja das Resultat sein. Wie du zu denen kommst, hängt ganz vom Mesh (vorgegeben oder dynamisch generiert?) ab. Entweder benutzt du eine generische Map-Methode, eine schöne Übersicht gibt es hier [http://wiki.blender.org/index.php/Manual/Map_Input#Options_2] oder du musst eben wirklich die UV-Koordinaten von Hand angeben (was bei einem generierten Mesh natürlich etwas schwieriger werden könnte).


_Joe_ - Mo 09.02.09 21:07

Der Mesh wird zur Laufzeit generiert. Ich glaube Flat passt mal schauen ich melde mich wenn es Probleme gibt.

thx


_Joe_ - Fr 13.02.09 14:41

ich finde nichts zu Berechnung der uvw Koordinaten, hat jemand einen tipp?


Kha - Fr 13.02.09 17:23

Worum geht es nun, Flat :nixweiss: ? Wenn du dir das Bild anschaust, sollte klar sein, dass im einfachsten Falle u=x und v=y gilt, z wird ignoriert (jede andere Kombination ist genauso möglich).
Je nachdem musst du die Skalierung noch anpassen; liegt der Objektmittelpunkt beispielsweise im Ursprung und die Bounding Box ist w Einheiten breit, würdest du mit u=x/w+0.5 u auf das Intervall [0..1] bringen, die Textur würde also auf die gesamte Breite gestreckt werden.


_Joe_ - Sa 14.02.09 15:43

gehen wir vom einfachsten Fall aus

Ich habe als anschauliches beispiel einen Würfel wobei der minimale Punkt (0,0,0) und der maximale Punkt (1,1,1) ist


C#-Quelltext
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:
    public MeshGeometry3D Cube(Point3D min, Point3D max)
        {
            MeshGeometry3D mesh = new MeshGeometry3D();
            mesh.Positions = new Point3DCollection
            {
                new Point3D(min.X,min.Y,min.Z), 
                new Point3D(max.X,min.Y,min.Z), 
                new Point3D(min.X,max.Y,min.Z), 
                new Point3D(max.X,max.Y,min.Z),
                new Point3D(min.X,min.Y,max.Z),
                new Point3D(max.X,min.Y,max.Z),
                new Point3D(min.X,max.Y,max.Z),
                new Point3D(max.X,max.Y,max.Z)
            };

            mesh.TextureCoordinates = new Kit3D.Windows.Media.PointCollection
               {
                new Point(min.X,min.Y), 
                new Point(max.X,min.Y), 
                new Point(min.X,max.Y), 
                new Point(max.X,max.Y),
                new Point(min.X,min.Y),
                new Point(max.X,min.Y),
                new Point(min.X,max.Y),
                new Point(max.X,max.Y)
               };
            mesh.TriangleIndices = new Int32Collection
            {
                231,  210,  713,  751,  657,  645,  620,  604,
                273,  267,  01 ,5054
            };
            return mesh;
        }


wenn ich die uv Koordinaten einfach nach u=x und v=y anordne sieht mein Cube so aus:

Moderiert von user profile iconNarses: Bild als Anhang hochgeladen

das macht für mich auch sinn, den ich habe nur 8 Punkte.

Wie bekomme ich nun die Restlichen punkte?


Kha - Sa 14.02.09 17:57

user profile icon_Joe_ hat folgendes geschrieben Zum zitierten Posting springen:
das macht für mich auch sinn, den ich habe nur 8 Punkte.

Wie bekomme ich nun die Restlichen punkte?
Ich verstehe nicht, was du meinst. Warum sollte man für einen Cube mehr als 8 Vertices benötigen?
Und aus deinem Bild werde ich auch nicht ganz schlau. Es wird ja anscheinend nur eine Seite (zwei Tris) angezeigt, aber kann das an falschen Textur-Koordinaten liegen?


_Joe_ - Sa 14.02.09 19:29

ich denke schon, wenn ich denn Cube mit einer Farbe belege dann wird dieser komplett dargestellt.

Moderiert von user profile iconNarses: Bild als Anhang hochgeladen

Wegen den 8 Punkten: Ist es nicht so das ich die Koordinaten für jedes Dreieck benötige? Das wären dann bei einem Viereck 2 Dreiecke = 6 Koordinaten und bei einem Cube 36 Koordinaten?


Kann das an der Reihenfolge der Koordinaten liegen?


Kha - Sa 14.02.09 21:21

Hab deinen Code in ein WPF-SDK-Sample eingebaut und als Textur einen Farbverlauf genommen, das Ergebnis ist wie erwartet.
user profile icon_Joe_ hat folgendes geschrieben Zum zitierten Posting springen:
Wegen den 8 Punkten: Ist es nicht so das ich die Koordinaten für jedes Dreieck benötige? Das wären dann bei einem Viereck 2 Dreiecke = 6 Koordinaten und bei einem Cube 36 Koordinaten?
Jeder Vertex ist zwar Teil von 6 Dreiecken, aber gerade dadurch, dass er in allen die gleichen Texture Coords besitzt, erreichst man, dass sich die Textur nahtlos übers gesamte Mesh zieht. Wenn jede Seite eine eigene Textur haben soll, brauchst du jeden Vertex wirklich dreimal, dann allerdings wahrscheinlich sowieso 6 unabhängige Meshes.


_Joe_ - Mi 18.02.09 09:34

Könntest du mir mal die Textur hochladen?


_Joe_ - Mi 11.03.09 12:00

ich beschäftige mich gerade mal wieder damit :)

ich glaub wir haben aneinander vorbei geredet meine Textur ist 256x256 Pixel groß. Die soll nun gekachelt um ein Objeckt gelegt werden. Ich hab gerade mal probiert "Planar mapping" zu verstehen aber komme nicht so ganz dahinter.


C#-Quelltext
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:
 public void MapTextureCoordinates(Face aFace, AxisAlignedBox aBox)
{
            // calc the plane, in which this triangle lies
            Vector3 size = aBox.Max - aBox.Min;

            if (aFace.Childs.Count < 3)
                return;
            
            Vertex[] vertices = new Vertex[3];
            forint i = 0; i < 3; i++)
                vertices[i] = aFace.Childs[i] as Vertex;

            Plane plane = new Plane(vertices[0].Position, vertices[1].Position, vertices[2].Position);

            float cross_X = Vector3.Dot(plane.Normal, new Vector3(100));
            float cross_Y = Vector3.Dot(plane.Normal, new Vector3(010));
            float cross_Z = Vector3.Dot(plane.Normal, new Vector3(001));
            int on_plane = -1// 0 == X, 1 == y, 2 == z

            
            cross_X = Math.Abs(cross_X);
            cross_Y = Math.Abs(cross_Y);
            cross_Z = Math.Abs(cross_Z);

            if (cross_X >= cross_Y && cross_X >= cross_Z)
                on_plane = 0;
            if (cross_Y > cross_X && cross_Y > cross_Z)
                on_plane = 1;
            if (cross_Z > cross_X && cross_Z > cross_Y)
                on_plane = 2;

            // wrap the texture coords in this boundingbox
            Vector2 tmp = new Vector2();
            for(int i = 0; i < 3; i++)
            {
                switch (on_plane)
                {
                    case 0:
                        {
                            tmp.X = ((vertices[i].Position.Z - aBox.Min.Z) / size.Z);
                            tmp.Y = ((vertices[i].Position.Y - aBox.Max.Y) / size.Y);
                            break;
                        }
                    case 1:
                        {
                            tmp.X = ((vertices[i].Position.X - aBox.Min.X) / size.X);
                            tmp.Y = ((vertices[i].Position.Z - aBox.Max.Z) / size.Z);
                            break;
                        }
                    case 2:
                        {
                            tmp.X = ((vertices[i].Position.X - aBox.Min.X) / size.X);
                            tmp.Y = ((vertices[i].Position.Y - aBox.Max.Y) / size.Y);
                            break;
                        }
                }
                // assign
                vertices[i].TextureCoordinate = tmp;
            }
        }
    }


Kha - Mi 11.03.09 14:35

user profile icon_Joe_ hat folgendes geschrieben Zum zitierten Posting springen:
Könntest du mir mal die Textur hochladen?
Sorry, habe ich irgendwie übersehen :gruebel: :( .

C#-Quelltext
1:
model.Material = new DiffuseMaterial(new LinearGradientBrush(Colors.Blue, Colors.Red, 45));                    


Dein Code sagt mir leider nicht allzu viel ;) .


_Joe_ - Mi 11.03.09 17:02

Aha macht sinn das es bei dir Funktioniert. Wenn du einen LinearGradientBrush verwendest kann du dir Texturkoordinaten schenken.


Kha - Mi 11.03.09 19:29

Aha - dann frage ich mich nur, warum das Ergebnis genau so aussieht, wie man es mit diesen UV Coords erwarten würde :| ?

Nun gut, von mir aus kann's auch ein ImageBrush sein:

C#-Quelltext
1:
new DiffuseMaterial(new ImageBrush(new BitmapImage(new Uri("pack://application:,,,/Green.jpg"))));                    



/add:
user profile icon_Joe_ hat folgendes geschrieben Zum zitierten Posting springen:
Ich habe beliebige Mesh und würde eben gern die best möglichen Koordinaten ausrechnen.
Ein Allheilmittel gibt es afaik einfach nicht. Jedenfalls nicht solange du uns nicht mehr über deine Meshes und Texturen verrätst.


_Joe_ - Do 12.03.09 09:49

Die Layer sind 256x256 Pixel die Mesh sind eben freiform von eckig bis rund. Unter anderem Tische, Stühle, Schränke und so weiter. Der Layer ist doch aber bei dir ein Überzug und nicht gekachelt? Ich müsste die bei denn kleinen Layer eigentlich Kacheln. Ich glaube WPF ist bei der Textur Geschichte eine ganze ecke mächtiger als das Kit3D. Kann man irgendwo in den WPF code schauen?


Das sollte eigentlich Planare Mapping sein.


C#-Quelltext
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:
       public Point MapTextureCoordinates(Point3D[] vertices, Vector3D min, Vector3D max) //max und min der Geometrie
        {
            Vector3D size = max - min;
            /*for( int i = 0; i < 3; i++)
                vertices[i] = aFace.Childs[i] as Vertex; */


            Plane plane = new Plane(vertices[0], vertices[1], vertices[2]);

            double cross_X = Vector3D.DotProduct(plane.Normal, new Vector3D(100));
            double cross_Y = Vector3D.DotProduct(plane.Normal, new Vector3D(010));
            double cross_Z = Vector3D.DotProduct(plane.Normal, new Vector3D(001));
            int on_plane = -1// 0 == X, 1 == y, 2 == z

            cross_X = Math.Abs(cross_X);
            cross_Y = Math.Abs(cross_Y);
            cross_Z = Math.Abs(cross_Z);

            if (cross_X >= cross_Y && cross_X >= cross_Z)
                on_plane = 0;
            if (cross_Y > cross_X && cross_Y > cross_Z)
                on_plane = 1;
            if (cross_Z > cross_X && cross_Z > cross_Y)
                on_plane = 2;


            Point tmp = new Point();
            for(int i = 0; i < 3; i++)
            {
                switch (on_plane)
                {
                    case 0:
                        {
                            tmp.X = ((vertices[i].Z - min.Z) / size.Z);
                            tmp.Y = ((vertices[i].Y - max.Y) / size.Y);
                            break;
                        }
                    case 1:
                        {
                            tmp.X = ((vertices[i].X - min.X) / size.X);
                            tmp.Y = ((vertices[i].Z - max.Z) / size.Z);
                            break;
                        }
                    case 2:
                        {
                            tmp.X = ((vertices[i].X - min.X) / size.X);
                            tmp.Y = ((vertices[i].Y - max.Y) / size.Y);
                            break;
                        }
                }
            }
            return tmp;
        }


Kha - Do 12.03.09 13:52

user profile icon_Joe_ hat folgendes geschrieben Zum zitierten Posting springen:
Unter anderem Tische, Stühle, Schränke und so weiter.
Also vor allem rechte Winkel, dann wäre ein Cube-Mapping ideal.

user profile icon_Joe_ hat folgendes geschrieben Zum zitierten Posting springen:
Der Layer ist doch aber bei dir ein Überzug und nicht gekachelt?
Hmpf, denk dir halt noch ein

C#-Quelltext
1:
2:
3:
4:
... {
  Viewport = new Rect(000.50.5),
  TileMode = TileMode.Tile
};
dazu ;) . Funktionieren tut es dann jedenfalls immer noch.
user profile icon_Joe_ hat folgendes geschrieben Zum zitierten Posting springen:
Ich glaube WPF ist bei der Textur Geschichte eine ganze ecke mächtiger als das Kit3D. Kann man irgendwo in den WPF code schauen?
Ja, aber da der interessante Teil in DirectX abläuft, wird dir das nicht viel nützen.
user profile icon_Joe_ hat folgendes geschrieben Zum zitierten Posting springen:
Das sollte eigentlich Planare Mapping sein.
Hast du die UV-Koordinaten schonmal im Debugger überprüft, ob sie z.B. wirklich ins Intervall [0;1] fallen?
Bzw. da ich diesem Kit3D nicht ganz traue: Hast du schon versucht, einen Cube von Hand zu "planar mappen"?


_Joe_ - Do 12.03.09 14:23

0;0
1;-1
1;-1
0;0
0;0
1;0
1;-1
0;-1
1;-1
0;-1
0;0
1;0
1;0
0;0
0;-1
1;-1
1;-1
1;0
0;0
0;-1
1;-1
0;0
0;0
1;-1

wohl eher zwischen 0 und -1. Das liegt aber an meinem Planar Mapping ich denke mal das ist falsch. Ich google mal nach cube mapping. Hast du zufällig code dazu :)

"Beim Cubemapping gibt man nicht wie bisher nur eine einzige Textur als Ziel an, sondern wie der Name vermuten lässt sechs Texturen" http://wiki.delphigl.com/index.php/Tutorial_Cubemap
ist aber eigentlich nich ziel der Übung. Ich will nur 1 Textur verwenden.


Kha - Do 12.03.09 18:24

user profile icon_Joe_ hat folgendes geschrieben Zum zitierten Posting springen:
Ich google mal nach cube mapping. Hast du zufällig code dazu :)
Wenn ich mir die Sphere so anschaue, ist das wahrscheinlich nicht ganz trivial. Aber wahrscheinlich bist du mit deinem veränderten Plane-Mapping schon ziemlich nah dran, ich würde also erstmal versuchen, die UV-Coords zu reparieren.
user profile icon_Joe_ hat folgendes geschrieben Zum zitierten Posting springen:
"Beim Cubemapping gibt man nicht wie bisher nur eine einzige Textur als Ziel an, sondern wie der Name vermuten lässt sechs Texturen" http://wiki.delphigl.com/index.php/Tutorial_Cubemap
ist aber eigentlich nich ziel der Übung. Ich will nur 1 Textur verwenden.
Jo, eine Cubic Environment Map [http://msdn.microsoft.com/en-us/library/bb204881(VS.85).aspx] ist wieder was anderes :mrgreen: . Ich glaube ehrlich gesagt nicht, dass die Map-Begriffe außerhalb von Blender weit verbreitet sind, denn dynamisches Texturieren ist imo immer noch eher eine Ausnahme.


_Joe_ - Do 12.03.09 20:51

Ich hab mir mal den Code von GLScene angeschaut aber schlau wird man dabei auch nicht. Vielleicht fällt mir noch was ein *hoff*


_Joe_ - Do 19.03.09 17:39

ich hab das ganze nochmal überarbeitet aber funktionieren tuts trotzdem nicht :-/


C#-Quelltext
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:
        public Plane(Point3D p0, Point3D p1, Point3D p2)
        {
            //Ebene 
            Vector3D e1 = p1 - p0;
            Vector3D e2 = p2 - p1;
            this.normal = Vector3D.CrossProduct(e1, e2);
            Vector3D n = normal/normal.Length;
            this.d = Vector3D.DotProduct(e1, n); 

        }

        public Point[] MapTextureCoordinates(Point3D[] vertices, Vector3D max, Vector3D min)
        {
            Vector3D size = max - min;
            Plane plane = new Plane(vertices[0], vertices[2], vertices[1]);

            double cross_X = Vector3D.DotProduct(plane.Normal, new Vector3D(100));
            double cross_Y = Vector3D.DotProduct(plane.Normal, new Vector3D(010));
            double cross_Z = Vector3D.DotProduct(plane.Normal, new Vector3D(001));

            Point[] tmp = new Point[3];
            if ((Math.Abs(cross_X) > Math.Abs(cross_Y)) && (Math.Abs(cross_X) > Math.Abs(cross_Z)))
            {
                for (int i = 0; i < 3; i++)
                {
                    tmp[i].X = ((vertices[i].Z - max.Z) / size.Z);
                    tmp[i].Y = ((vertices[i].Y - min.Y) / size.Y);
                }
            }
            if ((Math.Abs(cross_Y) > Math.Abs(cross_X)) && (Math.Abs(cross_Y) > Math.Abs(cross_Z)))
            {
                for (int i = 0; i < 3; i++)
                {
                    tmp[i].X = ((vertices[i].X - max.X) / size.X);
                    tmp[i].Y = ((vertices[i].Z - min.Z) / size.Z);
                }
            }
            if ((Math.Abs(cross_Z) > Math.Abs(cross_X)) && (Math.Abs(cross_Z) > Math.Abs(cross_Y)))
            {
                for (int i = 0; i < 3; i++)
                {
                    tmp[i].X = ((vertices[i].X - max.X) / size.X);
                    tmp[i].Y = ((vertices[i].Y - min.Y) / size.Y);
                }
            }
            return tmp;
        }


findet jemand den Fehler?