Artikel

6.6: Die Matrix einer linearen Abbildung


Nun werden wir sehen, dass jede lineare Abbildung (Tinmathcal{L}(V,W)), mit (V) und (W) endlichdimensionalen Vektorräumen, durch eine Matrix kodiert werden kann , und umgekehrt definiert jede Matrix eine solche lineare Abbildung.

Seien (V) und (W) endlichdimensionale Vektorräume und (T:V o W) eine lineare Abbildung. Angenommen ((v_1,ldots,v_n)) ist eine Basis von (V) und ((w_1,ldots,w_m)) ist eine Basis für (W). Wir haben in Satz 6.1.3 gesehen, dass (T) durch die Angabe der Vektoren (Tv_1,ldots, Tv_nin W) eindeutig bestimmt ist. Da ((w_1,ldots,w_m)) eine Basis von (W) ist, gibt es eindeutige Skalare (a_{ij}inmathbb{F}) mit
egin{equation}label{eq:Tv}
Tv_j = a_{1j} w_1 + cdots + a_{mj} w_m quad ext{für (1le jle n).} ag{6.6.1}
end{gleichung}
Wir können diese Skalare in einer (m imes n)-Matrix wie folgt anordnen:
egin{Gleichung*}
M(T) = egin{bmatrix}
a_{11} & ldots & a_{1n}
vdots && vdots
a_{m1} & ldots & a_{mn}
end{bmatrix}.
end{gleichung*}
Oft wird dies auch als (A=(a_{ij})_{1le ile m,1le jle n}) geschrieben. Wie in Abschnitt A.1.1 wird die Menge aller (m imes n)-Matrizen mit Einträgen in (mathbb{F}) mit (mathbb{F}^{m imes n} ).

Anmerkung 6.6.1. Es ist wichtig, sich daran zu erinnern, dass (M(T) ) nicht nur von der linearen Abbildung (T ) abhängt, sondern auch von der Wahl der Basis ((v_1,ldots,v_n) ) für (V ) und die Wahl der Basis ((w_1,ldots,w_m)) für (W). Die Spalte (j^{ ext{th}}) von (M(T)) enthält die Koeffizienten des (j^{ ext{th}})-Basisvektors (v_j ) wenn erweitert um die Basis ((w_1,ldots,w_m)), wie in Gleichung 6.6.1.

Beispiel 6.6.2. Sei (T:mathbb{R}^2 o mathbb{R}^2) die lineare Abbildung gegeben durch (T(x,y)=(ax+by,cx+dy)) für einige (a,b,c,dinmathbb{R}). Dann ist bezüglich der kanonischen Basis von (mathbb{R}^2) gegeben durch (((1,0),(0,1))) die entsprechende Matrix matrix
egin{Gleichung*}
M(T) = egin{bmatrix} a&b c&d end{bmatrix}
end{gleichung*}
da (T(1,0) = (a,c) ) die erste Spalte und (T(0,1)=(b,d) ) die zweite Spalte ergibt.

Nehmen wir allgemeiner an, dass (V=mathbb{F}^n) und (W=mathbb{F}^m) und die Standardbasis für (V) mit ((e_1, ldots,e_n) ) und die Standardbasis für (W ) nach ((f_1,ldots,f_m) ). Hier ist (e_i ) (bzw. (f_i)) das (n)-Tupel (bzw. (m)-Tupel) mit einer Eins an Position (i ) und Nullen überall sonst . Dann ist die Matrix (M(T)=(a_{ij})) gegeben durch

egin{Gleichung*}
a_{ij} = (Te_j)_i,
end{gleichung*}
wobei ((Te_j)_i ) die (i^{ ext{th}} )-Komponente des Vektors (Te_j ) bezeichnet.

Beispiel 6.6.3. Sei (T:mathbb{R}^2 omathbb{R}^3) die lineare Abbildung definiert durch (T(x,y)=(y,x+2y,x+y) ). Dann gilt bezüglich der Standardbasis (T(1,0)=(0,1,1)) und (T(0,1)=(1,2,1) ) so dass so
egin{Gleichung*}
M(T) = egin{bmatrix} 0&1 1& 2 1&1 end{bmatrix}.
end{gleichung*}
Nehmen wir jedoch alternativ die Basen (((1,2),(0,1))) für (mathbb{R}^2) und
(((1,0,0),(0,1,0),(0,0,1))) für (mathbb{R}^3), dann (T(1,2 )=(2,5,3) ) und (T(0,1)=(1,2,1) ) so dass
egin{Gleichung*}
M(T) = egin{bmatrix} 2&1 5&2 3&1 end{bmatrix}.
end{gleichung*}

Beispiel 6.6.4. Sei (S:mathbb{R}^2 o mathbb{R}^2) die lineare Abbildung (S(x,y)=(y,x)). Bezüglich der Basis (((1,2),(0,1))) für (mathbb{R}^2) gilt
egin{Gleichung*}
S(1,2) = (2,1) = 2(1,2) -3(0,1) quad ext{und} quad
S(0,1) = (1,0) = 1(1,2)-2(0,1),
end{gleichung*}
und so
[ M(S) = egin{bmatrix} 2&1- 3& -2 end{bmatrix}. ]

Bei gegebenen Vektorräumen (V ) und (W ) der Dimensionen (n ) bzw. (m ) und einer festen Wahl der Basen sei angemerkt, dass zwischen lineare Abbildungen in (mathcal{L}(V,W)) und Matrizen in (mathbb{F}^{m imes n}). Beginnen wir mit der linearen Abbildung (T), dann ist die Matrix (M(T)=A=(a_{ij})) über Gleichung 6.6.1 definiert. Umgekehrt können wir bei gegebener Matrix (A=(a_{ij})in mathbb{F}^{m imes n}) eine lineare Abbildung (T:V o W) definieren, indem wir

[ Tv_j = sum_{i=1}^m a_{ij} w_i. ]

Denken Sie daran, dass die Menge der linearen Abbildungen (mathcal{L}(V,W)) ein Vektorraum ist. Da wir eine Eins-zu-Eins-Entsprechung zwischen linearen Abbildungen und Matrizen haben, können wir auch die Menge der Matrizen (mathbb{F}^{m imes n}) zu einem Vektorraum machen. Gegeben zwei Matrizen (A=(a_{ij})) und (B=(b_{ij})) in (mathbb{F}^{m imes n}) und gegebenem Skalar (alphainmathbb{F}), definieren wir die Matrixaddition und Skalarmultiplikation Komponentenweise:

egin{Gleichung*}
egin{split}
A+B &= (a_{ij}+b_{ij}),
alpha A &= (alpha a_{ij}).
end{split}
end{gleichung*}

Als nächstes zeigen wir, dass die Komposition von linearen Abbildungen erlegt Matrizen ein Produkt auf, auch genannt Matrix-Multiplikation. Angenommen (U,V,W) sind Vektorräume über (mathbb{F}) mit Basen ((u_1,ldots,u_p)), ((v_1,ldots,v_n)) bzw. ((w_1,ldots,w_m)). Seien (S:U o V) und (T:V o W) lineare Abbildungen. Dann ist das Produkt eine lineare Abbildung (Tcirc S:U o W).

Jede lineare Abbildung hat ihre entsprechende Matrix (M(T)=A, M(S)=B) und (M(TS)=C). Die Frage ist, ob (C) durch (A) und (B) bestimmt ist. Wir haben für jedes (jin{1,2,ldots p}), dass

egin{Gleichung*}
egin{split}
(Tcirc S) u_j &= T(b_{1j}v_1 + cdots + b_{nj} v_n) = b_{1j} Tv_1 + cdots + b_{nj} Tv_n
&= sum_{k=1}^n b_{kj} Tv_k
= sum_{k=1}^n b_{kj} igl( sum_{i=1}^m a_{ik} w_i igr)
&= sum_{i=1}^m igl(sum_{k=1}^n a_{ik} b_{kj} igr) w_i.
end{split}
end{gleichung*}

Somit ist die Matrix (C=(c_{ij})) gegeben durch
egin{equation} label{eq:c}
c_{ij} = sum_{k=1}^n a_{ik} b_{kj}. ag{6.6.2}
end{gleichung}

Gleichung 6.6.2 kann verwendet werden, um die (m imes p)-Matrix (C) als das Produkt einer (m imes n)-Matrix (A) und einer (n imes p ) Matrix (B ), dh
egin{Gleichung}
C = AB. ag{6.6.3}
end{gleichung}

Unsere Herleitung impliziert, dass die Korrespondenz zwischen linearen Abbildungen und Matrizen die Produktstruktur respektiert.

Vorschlag 6.6.5. Lassen (S:U ach V) und (T:V ach W) lineare Karten sein. Dann

[ M(TS) = M(T)M(S).]

Beispiel 6.6.6. Mit der Notation wie in den Beispielen 6.6.3 und 6.6.4 sollten Sie überprüfen können, dass
egin{Gleichung*}
M(TS) = M(T)M(S) = egin{bmatrix} 2&1 5&2 3&1 end{bmatrix}
egin{bmatrix} 2&1- 3& -2 end{bmatrix}
= egin{bmatrix} 1&0 4&1 3&1 end{bmatrix}.
end{gleichung*}

Bei einem gegebenen Vektor (vin V) können wir auch eine Matrix (M(v)) mit (v) wie folgt assoziieren. Sei ((v_1,ldots,v_n)) eine Basis von (V). Dann gibt es eindeutige Skalare (b_1,ldots,b_n) mit

[ v= b_1 v_1 + cdots b_n v_n. ]

Die Matrix von (v) ist dann die (n imes 1)-Matrix

[ M(v) = egin{bmatrix} b_1 vdots b_n end{bmatrix}. ]

Beispiel 6.6.7 Die Matrix eines Vektors (x=(x_1,ldots,x_n)inmathbb{F}^n) in der Standardbasis ((e_1,ldots,e_n)) ist der Spaltenvektor oder (n imes 1 ) Matrix
egin{Gleichung*}
M(x) = egin{bmatrix} x_1 vdots x_n end{bmatrix}
end{gleichung*}
da (x=(x_1,ldots,x_n) = x_1 e_1 + cdots + x_n e_n ).

Das nächste Ergebnis zeigt, wie der Begriff einer Matrix einer linearen Abbildung (T:V o W) und die Matrix eines Vektors (vin V) zusammenpassen.

Vorschlag 6.6.8. Lassen (T:V ach W) eine lineare Abbildung sein. Dann für alle (vin V),
egin{Gleichung*}
M(Tv) = M(T)M(v).
end{gleichung*}

Nachweisen.

Sei ((v_1,ldots,v_n)) eine Basis von (V) und ((w_1,ldots,w_m)) eine Basis von (W). Angenommen, bezüglich dieser Basen ist die Matrix von (T) (M(T)=(a_{ij})_{1le ile m, 1le jle n} ). Dies bedeutet, dass für alle (jin{1,2,ldots,n})

[ egin{gleichung*}
Tv_j = sum_{k=1}^m a_{kj} w_k.
end{gleichung*} ]

Der Vektor (vin V) lässt sich eindeutig als Linearkombination der Basisvektoren schreiben als

[ v = b_1 v_1 + cdots + b_n v_n. ]

Somit,

egin{Gleichung*}
egin{split}
TV &= b_1 T v_1 + cdots + b_n T v_n
&= b_1 sum_{k=1}^m a_{k1} w_k + cdots + b_n sum_{k=1}^m a_{kn} w_k
&= sum_{k=1}^m (a_{k1} b_1 + cdots + a_{kn} b_n) w_k.
end{split}
end{gleichung*}

Dies zeigt, dass (M(Tv)) die (m imes 1)-Matrix . ist

egin{Gleichung*}
M(Tv) = egin{bmatrix} a_{11}b_1 + cdots + a_{1n} b_n vdots
a_{m1}b_1 + cdots + a_{mn} b_n end{bmatrix}.
end{gleichung*}

Es ist nicht schwer, mit der Formel für die Matrixmultiplikation zu überprüfen, dass (M(T)M(v)) das gleiche Ergebnis liefert.

Beispiel 6.6.9. Nehmen Sie die lineare Abbildung (S) aus Beispiel 6.6.4 mit der Basis (((1,2),(0,1))) von (mathbb{R}^2). Um die Wirkung auf den Vektor (v=(1,4)inmathbb{R}^2 zu bestimmen, beachte, dass (v=(1,4)=1(1,2)+2(0 ,1)). Somit,
egin{Gleichung*}
M(Sv) = M(S)M(v) = egin{bmatrix} 2&1-3&-2 end{bmatrix}
egin{bmatrix} 12 end{bmatrix}
= egin{bmatrix} 4 -7 end{bmatrix}.
end{gleichung*}

Dies bedeutet, dass

[ Sv= 4(1,2)-7(0,1)=(4,1), ]

was in der Tat wahr ist.


Dr. Mark V. Sapir

wobei A eine m mal n Matrix von Koeffizienten ist und b die Spalte der rechten Seiten ist. Für jeden n-Vektor v erhalten wir einen m-Vektor Av. Unser Ziel ist es, alle n -Vektoren v zu finden, so dass dieser m -Vektor b ist. Somit haben wir eine Funktion, die einen beliebigen Vektor v von R n in den Vektor Av von R m nimmt, und unser Ziel ist es, alle Werte des Arguments dieser Funktion zu finden, für die die Funktion einen bestimmten Wert hat.

Eine Funktion von R n nach R m, die jeden n -Vektor v zum m -Vektor Av bringt, wobei A eine m mal n Matrix ist, heißt a lineare Transformation. Die Matrix A heißt die Standardmatrix dieser Verwandlung. Für n = m heißt die Transformation a linearer Operator des Vektorraums R n .

Beachten Sie, dass die lineare Transformation mit einer Standardmatrix A definitionsgemäß jeden Vektor ( x1. xn )

aus R m wobei A(i,j) die Einträge von A sind. Umgekehrt ist jede durch eine solche Formel gegebene Transformation von R n nach R m eine lineare Transformation und die Koeffizienten A(i,j) bilden die Standardmatrix dieser Transformation.

Beispiele. 1. Betrachten Sie die Transformation von R 2 , die jeden Vektor ( a,b ) in den entgegengesetzten Vektor ( -a,-b ) umwandelt. Dies ist ein linearer Operator mit Standardmatrix

2. Allgemeiner ausgedrückt ist der Dilatationsoperator der lineare Operator von R n nach R n, der jeden Vektor nimmt

3. Wenn wir einen Vektor ( x,y ) in R 2 nehmen und ihn um die x-Achse spiegeln, erhalten wir den Vektor ( x,-y ). Diese Spiegelung ist offensichtlich ein linearer Operator. Seine Standardmatrix ist

4. Wenn wir einen Vektor ( x,y ) auf die x-Achse projizieren, erhalten wir den Vektor ( x ,0). Diese Projektion ist ebenfalls ein linearer Operator. Seine Standardmatrix ist

5. Wenn wir einen Vektor ( x,y ) um 90 Grad gegen den Uhrzeigersinn drehen, erhalten wir den Vektor ( -y, x ). Diese Drehung ist ein linearer Operator mit Standardmatrix

Wir werden beweisen, dass Spiegelungen an beliebigen Geraden, Projektionen auf beliebige Achsen und Drehungen um beliebige Winkel im R 2 lineare Operatoren sind. Dazu benötigen wir die folgende einfache Charakterisierung linearer Transformationen von R n nach R n .

Satz. Eine Funktion T von R n nach R m ist genau dann eine lineare Transformation, wenn sie die folgenden zwei Eigenschaften erfüllt:

    Für je zwei Vektoren A und B in R n

Dieser Beweis zeigt, dass wenn T ist eine lineare Transformation, Vich (ich=1. n ) ist der Vektor mit ich-te Koordinate 1 und andere Koordinaten 0, dann T(Vich) ist der ich-te Spalte in der Standardmatrix von T. Dies bietet uns eine Möglichkeit, die Standardmatrix einer linearen Transformation zu finden.
Beachten Sie, dass in R 3 Vektoren V1, V2, V3 sind die Basisvektoren i, j, k . Also nennen wir Vich das Basic Vektoren in R n . Wir geben eine allgemeine Definition von Basen in R n und anderen Vektorräumen später.

Als Folge der Charakterisierung linearer Transformationen von R m nach R n können wir die folgende Aussage ableiten.

Logische Folge. Jede lineare Transformation T von R m bis R n nimmt 0 von R m bis 0 von R n an.

In der Tat sei k = 0 und ein beliebiger Vektor A dann

Hier haben wir die zweite Bedingung der Charakterisierung verwendet.

Beispiel 1. Projektion auf eine beliebige Linie in R 2 . Sei L eine beliebige Gerade in R 2 . Lass TL sei die Transformation von R 2 , die jeden 2-Vektor zu seiner Projektion auf L führt. Es ist klar, dass die Projektion der Summe zweier Vektoren die Summe der Projektionen dieser Vektoren ist. Wenn wir einen Vektor mit einem Skalar multiplizieren, wird seine Projektion auch mit diesem Skalar multipliziert. Somit ist durch die Charakterisierung linearer Transformationen TL ist ein linearer Operator auf R 2 .

Finden wir die Standardmatrix der Projektion auf der Geraden y=kx . Diese Linie hat die Richtung des Vektors A = (1, k ). Sei V ein beliebiger Vektor ( x,y ) in R 2 . Dann ist die Projektion P ein solcher Vektor, dass

  1. P ist parallel zu A , also P=tA=(t, kt)
  2. V-P steht senkrecht zu A . Dies bedeutet, dass <(V-P),A> =0 oder

Daraus können wir ableiten

Daher ist die Standardmatrix der Projektion

1/(k2+1) [ 1 k ]
[ k k 2 ]

Beachten Sie, dass die Formel für den Vektor P einen weiteren Beweis dafür liefert, dass die Projektion ein linearer Operator ist (vergleiche mit der allgemeinen Form der linearen Operatoren).

Beispiel 2. Reflexion über eine beliebige Linie.

Wenn P die Projektion des Vektors v auf die Linie L ist, dann ist V-P senkrecht zu L und Q=V-2(V-P) ist gleich der Reflexion von V an der Linie L. Somit ist Q=2P-V. Mit der Formel für P, die wir haben, können wir eine Formel für Q herleiten:

Damit erhalten wir die Standardmatrix der Reflexion:

1/(k2+1) [ 1-k 2 2k ]
[ 2 k k 2 -1 ]

Beispiel 3. RDrehung durch den Winkel ein

Mit Hilfe der Charakterisierung linearer Transformationen lässt sich leicht zeigen, dass die Drehung von Vektoren im R 2 um jeden Winkel ein (gegen den Uhrzeigersinn) ist ein linearer Operator. Um seine Standardmatrix zu finden, verwenden wir die Beobachtung, die unmittelbar nach dem Beweis der Charakterisierung linearer Transformationen gemacht wurde. Diese Beobachtung besagt, dass die Spalten der Standardmatrix Bilder der Basisvektoren (1,0) und (0,1) sind. Es ist klar, dass diese Bilder (cos(ein), Sünde (ein)) und (-sünde(ein), weil (ein)). Daher lautet die Standardmatrix der Rotation:


[ weil (ein) -Sünde(ein) ]
[ Sünde (ein) weil (ein) ]

Beachten Sie, dass die Drehung im Uhrzeigersinn um den Winkel ein hat die folgende Matrix:


[ weil (ein) Sünde (ein) ]
[ -sünde(ein) weil (ein) ]

weil es gleich der Drehung gegen den Uhrzeigersinn um den Winkel ist -ein.

Nehme an, dass T ist eine lineare Transformation von R m nach R n mit Standardmatrix A und S ist eine lineare Transformation von R n nach R k mit Standardmatrix B . Dann können wir komponieren oder multiplizieren diese beiden Transformationen und erzeugen eine neue Transformation ST, die Vektoren von R m nach R k nimmt. Diese Transformation gilt zuerst T und dann S. Keine zwei Transformationen können multipliziert werden: die Transformation S muss wo anfangen T endet. Aber zwei beliebige lineare Operatoren in R n (dh lineare Transformationen von R n nach R n ) können multipliziert werden.

Beachten Sie, dass, wenn v ein Vektor in R n ist,

durch die Definition der Standardmatrix einer linearen Transformation. Dann
ST(V)=S(T(V))=B(AV)=(BA)V

Somit ist das Produkt ST eine lineare Transformation und die Standardmatrix ST ist das Produkt der Standardmatrizen BA .

Beispiel 1. Nehme an, dass T und S sind Drehungen in R 2 , T dreht sich um den Winkel ein und S dreht sich um den Winkel b (alle Drehungen sind gegen den Uhrzeigersinn). Dann ist ST natürlich die Drehung um den Winkel a+b. Die Standardmatrix von T ist

[ cos ( a ) -sünde(a)]
[ Sünde ( a ) cos(a)]

Die Standardmatrix von S ist

[ cos ( b ) -sünde(b)]
[ Sünde ( b ) cos(b)]

Somit muss die Standardmatrix von ST das Produkt dieser Matrizen sein:

[ cos(a)cos(b)-sin(a)sin(b) -cos(a)sin(b)-sin(a)cos(b)]
[ cos(a)sin(b)+sin(a)cos(b) cos(a)cos(b)-sin(a)sin(b)]

Andererseits ist dies die Standardmatrix der Drehung um den Winkel a+b , also muss ihre Standardmatrix gleich sein

[ cos( a+b ) -sünde(a+b)]
[ Sünde ( a+b ) cos(a+b)]

Damit erhalten wir die bekannten trigonometrischen Formeln:

cos(a+b)=cos(a)cos(b)-sin(a)sin(b)
sin(a+b)=sin(a)cos(b)+cos(a)sin(b)

  1. Die Drehung durch ein im Uhrzeigersinn.
  2. Die Spiegelung um die x-Achse.
  3. Die Drehung durch ein gegen den Uhrzeigersinn.

Somit könnten wir die Standardmatrix der Spiegelung um die Linie L durch Multiplikation der Standardmatrizen dieser drei Transformationen finden.

  1. Die Drehung durch ein im Uhrzeigersinn.
  2. Die Projektion auf der x-Achse.
  3. Die Drehung durch ein gegen den Uhrzeigersinn.

Wenn A und B die Standardmatrizen von sind T und S bzw. dann

Somit ist die Summe der linearen Transformationen von R m nach R n wieder eine lineare Transformation und die Standardmatrix der Summe der linearen Transformationen ist die Summe der Standardmatrizen dieser Transformationen.

Wir können auch eine lineare Transformation mit einem Skalar multiplizieren. Wenn k eine Zahl ist und T eine lineare Transformation von R m nach R n ist, dann ist kT eine Funktion von R m nach R n, die jeden Vektor V von R m nach kT(V) nimmt. Es ist leicht zu erkennen, dass die Standardmatrix von kT kA ist.

Fassen wir die bisher erhaltenen Eigenschaften der linearen Transformationen von R m nach R n zusammen, können wir den folgenden Satz formulieren.

Satz. 1. Das Produkt NS einer linearen Transformation T von R m nach R n und eine lineare Transformation S von R n nach R k ist eine lineare Transformation von R m nach R k und die Standardmatrix von ST ist gleich dem Produkt der Standardmatrizen von S und T.

2. Wenn T und S sind lineare Transformationen von R m nach R n dann T+S ist wieder eine lineare Transformation von R m nach R n und die Standardmatrix dieser Transformation ist gleich der Summe der Standardmatrizen von T und S.

3. Wenn T ist eine lineare Transformation von R m nach R n und k ist ein Skalar dann kT ist wieder eine lineare Transformation von R m nach R n und die Standardmatrix dieser Transformation ist gleich k mal der Standardmatrix von T.

Per Definition ist die Identität Funktion von R n bis R n ist die Funktion, die jeden Vektor zu sich nimmt. Es ist klar, dass die Identitätsfunktion ein linearer Operator ist, dessen Standardmatrix die Identitätsmatrix ist. Bezeichnen wir den Identitätsoperator mit Id .

Ein linearer Operator T in R n heißt invertierbar falls es einen anderen linearen Operator gibt S in R n mit TS = ST = Id . In diesem Fall S heißt der invers von T. Per Definition S macht was rückgängig T tut, das ist wenn T nimmt V nach W dann S muss W nach V bringen (sonst wäre ST nicht der Identitätsoperator). Wenn A die Standardmatrix von ist T und B ist die Standardmatrix von S dann NS hat die Standardmatrix BA . Also wenn S ist die Umkehrung von T dann BA =ich. Umgekehrt gilt, wenn BA =ich dann der lineare Operator S mit Standardmatrix B ist die Umkehrung von T weil ST der lineare Operator ist, dessen Standardmatrix ist ich. Daraus können wir schließen, dass die folgende Aussage wahr ist.

Satz. Ein linearer Operator T in R n ist genau dann invertierbar, wenn seine Standardmatrix invertierbar ist. Wenn A die Standardmatrix von ist T dann ist A -1 die Standardmatrix von T -1 .


Beispiel 1. Die Spiegelung an einer Linie in R 2 ist invertierbar und die Umkehrung einer Spiegelung ist die Spiegelung selbst (in der Tat, wenn wir die Spiegelung zweimal auf einen Vektor anwenden, ändern wir den Vektor nicht).


Beispiel 2. Die Drehung um den Winkel ein ist invertierbar und das Inverse ist die Drehung um den Winkel -ein.

Beispiel 3. Die Projektion auf eine Linie in R 2 ist nicht invertierbar, da viele Vektoren von der Projektion auf denselben Vektor genommen werden, sodass wir einen Vektor nicht eindeutig durch sein Bild unter der Projektion rekonstruieren können.

Unser nächstes Ziel ist es, Eigenschaften von invertierbaren linearen Operatoren zu betrachten.

Erinnern wir uns zunächst an einige Eigenschaften von invertierbaren Abbildungen (Funktionen). Lassen T sei eine Abbildung von der Menge X in die Menge Y . Wir sagen das T ist injektiv oder eins zu eins Wenn T bildet verschiedene Elemente auf verschiedene Elemente ab, dh wenn T(u)=T(v) dann notwendigerweise u=v . Wir nennen T surjektiv oder auf zu wenn jedes Element in Y ein Bild eines Elements in X ist, das heißt für jedes y in Y existiert ein x in X mit T(x)=y .

Eine Funktion T von X nach X heißt invertierbar wenn es eine andere Funktion gibt S von X nach X mit TS=ST= Id , die Identitätsfunktion (dh wenn T nimmt x zu y dann S muss y zu x nehmen). Das sieht man leicht T ist genau dann invertierbar, wenn sie injektiv und surjektiv ist.

Es gibt Funktionen, die nicht injektiv und nicht surjektiv sind (die Funktion T(x)=x 2 von R nach R ), nicht injektiv und surjektiv (sagen wir T(x)=x 3 -x von R nach R ) , injektiv und nicht surjektiv (sagen wir T(x)=arctan(x) von R nach R ), injektiv und surjektiv (jede invertierbare Funktion, sagen wir T(x)=x 3 von R zu R).

Daher ist der folgende Satz über lineare Operatoren sehr überraschend.

Satz. Für jeden linearen Operator T in R n mit Standardmatrix A sind folgende Bedingungen äquivalent:

Seien V und W beliebige Vektorräume. Eine Landkarte T von V nach W heißt a lineare Transformation Wenn

    Für je zwei Vektoren A und B in V

Im speziellen Fall, wenn V = W , T heißt a linearer Operator im V.

Wir haben gesehen (siehe die Charakterisierung linearer Transformationen von R m nach R n ), dass lineare Transformationen von R m nach R n genau die Abbildungen sind, die diese Bedingungen erfüllen. Bei Vektorräumen von n -Vektoren ist diese Definition daher äquivalent zur ursprünglichen Definition. Andere Vektorräume geben uns weitere Beispiele für natürliche lineare Transformationen.

Positive Beispiele.1. Sei V die Menge aller Polynome in einer Variablen. Wir werden später sehen, dass V ein Vektorraum mit natürlicher Addition und Skalarmultiplikation ist (es ist nicht schwer, es direkt zu zeigen). Die Abbildung, die jedes Polynom in seine Ableitung führt, ist ein linearer Operator in V, wie leicht aus den Eigenschaften der Ableitung folgt:

2. Sei C [0,1] der Vektorraum aller stetigen Funktionen auf dem Intervall [0,1]. Dann ist die Abbildung, die jede Funktion S(x) von C [0,1] auf die Funktion h(x) bringt, die gleich dem Integral von 0 bis x von S(t) ist, ein linearer Operator in C [0,1 ] wie aus den Eigenschaften von Integralen folgt.

int(T(t)+S(t)) dt = int T(t)dt + int S(t)dt
int kS(t) dt = k int S(t) dt.

3. Die Abbildung von C [0,1] nach R, die jede Funktion S(x) auf die Zahl S(1/3) bringt, ist eine lineare Transformation (1/3 kann durch eine beliebige Zahl zwischen 0 und 1 ersetzt werden):

4. Die Abbildung aus dem Vektorraum aller komplexen Zahlen C auf sich selbst, die jede komplexe Zahl a+b . nimmt ich zu seinem Imaginärteil b ich ist ein linearer Operator (check!).

5. Die Abbildung aus dem Vektorraum aller n mal n Matrizen ( n ist fest) auf R, die jede Matrix A zu ihrem (1,1)-Eintrag A (1,1) führt, ist eine lineare Transformation (check!).

6. Die Karte aus dem Vektorraum aller n von n Matrizen zu R, die jede Matrix A auf ihre Spur führt trace( A ) ist eine lineare Transformation (check!).

7. Die Abbildung von einem beliebigen Vektorraum V in einen beliebigen Vektorraum W, die jeden Vektor v von V nach 0 nimmt, ist eine lineare Transformation (check!). Diese Transformation wird als . bezeichnet Nulltransformation

8. Die Abbildung aus einem beliebigen Vektorraum V nach V, die jeden Vektor zu sich nimmt (die Identitätsabbildung) ist ein linearer Operator (check!). Es heißt die Identitätsoperator, bezeichnet ich.

Negativbeispiele. 1. Die Karte T woraus jede Funktion S(x) von C [0,1] auf die Funktion S(x) +1 ist keine lineare Transformation, denn wenn wir k = 0, S(x)=x nehmen, dann ist das Bild von kT(x) (=0) die konstante Funktion 1 und k mal das Bild von T(x) ist die konstante Funktion 0. Die zweite Eigenschaft linearer Transformationen gilt also nicht.

2. Die Karte T aus dem Vektorraum der komplexen Zahlen C nach R, das jede komplexe Zahl a+bi zu ihrer Norm sqrt( a 2 +b 2 ) nimmt, ist keine lineare Transformation, denn wenn wir A =3 und B =4i nehmen, dann gilt T(A+B) =||3+4i ||=5 und T(A)+T(B) =3+4=7, also ist T(A+B) ungleich T(A)+T(B) , also gilt die erste Eigenschaft linearer Transformationen nicht halten.

Der folgende Satz enthält einige wichtige Eigenschaften linearer Transformationen (vergleiche mit dem Korollar aus der Charakterisierung T lineare Transformationen von R m nach R n und der Satz über Produkte, Summen und skalare Vielfache linearer Transformationen).

Satz. 1. Wenn T eine lineare Transformation von V nach W ist, dann T(0)=0.

2. Wenn T ist eine lineare Transformation von V nach W und S ist eine lineare Transformation von W nach Y ( V, W, Y sind Vektorräume) dann das Produkt (Zusammensetzung) NS ist eine lineare Transformation von V nach Y .

3. Wenn T und S sind lineare Transformationen von V nach W ( V und W sind Vektorräume) dann die Summe T+S die jeden Vektor A in V zur Summe T(A)+S(A) in W bringt, ist wieder eine lineare Transformation von V nach W .

4. Wenn T eine lineare Transformation von V nach W und k ein Skalar ist, dann ist die Abbildung kT, die jeden Vektor A in V zu k mal T(A) nimmt, wieder eine lineare Transformation von V nach W .

Der Beweis bleibt als Übung.

Einige Eigenschaften linearer Transformationen, die für lineare Transformationen von R m nach R n gelten, gelten nicht für beliebige Vektorräume.

Sei beispielsweise P der Vektorraum aller Polynome. Lassen T sei der lineare Operator, der jedes Polynom zu seiner Ableitung führt. Dann T ist surjektiv, weil jedes Polynom eine Ableitung eines anderen Polynoms ist (Anti-Ableitungen eines Polynoms sind Polynome). Aber T ist nicht injektiv, weil die Bilder von x 2 und x 2 +1 gleich sind (2 x ). Denken Sie daran, dass für lineare Transformationen von R m nach R n Injektivität und Surjektivität äquivalent sind.

Beachten Sie, dass der Operator T ist nicht injektiv, es kann kein Inverses haben. Aber lass S sei der Operator auf dem gleichen Raum, der jedes Polynom zu seiner Stammfunktion int(p(t), t=0..x) führt. Dann gilt für jedes Polynom p: TS(p)=p (die Ableitung der Stammfunktion einer Funktion ist die Funktion selbst). Also TS=I . Andererseits ist ST nicht gleich ich, denn, sagen wir, wenn p=x +1 dann ist T(p) = 1, ST(p)=x , also ist ST(p) nicht gleich p .

Bei linearen Operatoren in R m kann dies nicht passieren. In der Tat, wenn TS=I, dann ist das Produkt der Standardmatrizen von T und S ist ich. Die Standardmatrix A von T ist invertierbar, und die Standardmatrix B von S ist die Umkehrung von A. Somit S ist die Umkehrung von T und ST =ich.

Der Beweis im letzten Absatz enthält keine Verweise auf die von uns verwendeten Ergebnisse. Finden Sie diese Referenzen!


Projektionen auf Unterräume, Abstand von einem Vektor zu einem Unterraum

Der Satz über orthogonale Komplemente sagt uns, dass wenn V ist ein Unterraum eines euklidischen Vektorraums W und w ist ein Vektor von W dann w=v+v' für einige v In V und v' im orthogonalen Komplement V c von V . Wir wissen auch, dass diese Darstellung von w ist einzigartig. Der Vektor v heißt dann die Projektion von w auf V heißt der Vektor v ' der normale Komponente von w.

Das Gram-Schmidt-Verfahren gibt uns die Formel für die Projektion und die Normalkomponente. Wenn v1. vk eine orthogonale Basis des Unterraums V ist, dann

In der Tat, v gehört V weil jedes v ich ist in V und V ist unter Linearkombinationen abgeschlossen. Und es ist leicht zu überprüfen (Übung), dass v'=w-v orthogonal zu jedem von vich . Dies impliziert, dass v' ist orthogonal zu jedem Vektor in V weil Vektoren in V sind Linearkombinationen von v1. vk (überprüfe, ob ein Vektor P ist orthogonal zu den Vektoren q1. Qn , dann P ist orthogonal zu jeder Linearkombination von q1. Qn ).

Der Satz über orthogonale Komplemente ermöglicht es uns, Abstände von Vektoren zu Unterräumen in jedem euklidischen Vektorraum zu finden.


Ein eher visuelles Beispiel. Matrixtransformation

Im folgenden Beispiel verwenden wir eine größere Matrix, dargestellt als Bild zur visuellen Unterstützung. Sobald wir die neue Indexmatrix berechnet haben, werden wir die ursprüngliche Matrix auf die neuen Indizes abbilden und die Out-of-Bounds-Indizes umhüllen, um eine kontinuierliche Ebene zu erhalten, indem wir numpy.take mit mode='wrap' verwenden.

Erstellen Sie für dieses Beispiel eine 200x200-Matrix:

Die lineare Transformationsfunktion, die die Operationen der vorherigen Beispiele enthält, aber die neuen Indexpaare rundet und die Quellmatrix auf die neuen Indizes abbildet, könnte wie folgt geschrieben werden:

Sehen wir uns einige lineare Transformationen an, die wir durchführen können.

Skalierung der Ebene in der (x)-Achse um den Faktor 1,5:

Dilatation der Ebene um den Faktor 1,8:

Ausdehnung der Ebene um den Faktor 0,5:

Skalierung der Ebene in der (y)-Achse um den Faktor 0,5:

Scherung um die (y)-Achse mit einer vertikalen Verschiebung von (+x/2) :

Drehung um (45^) um den Ursprung:

Reflexion in einer Linie mit Neigung von (45^) durch den Ursprung:


Kanonische Form von Jordanien

Jordanische kanonische Form ist eine Darstellung einer linearen Transformation über einen endlichdimensionalen komplexen Vektorraum durch eine besondere Art einer oberen Dreiecksmatrix. Jede solche lineare Transformation hat eine einzigartige kanonische Form nach Jordan, die nützliche Eigenschaften hat: Sie ist leicht zu beschreiben und für Berechnungen gut geeignet.

Weniger abstrakt kann man von der Jordan-kanonischen Form einer quadratischen Matrix sprechen jede quadratische Matrix ähnelt einer eindeutigen Matrix in der Jordan-kanonischen Form, da ähnliche Matrizen Darstellungen derselben linearen Transformation bezüglich verschiedener Basen entsprechen, durch die Änderung von change Basissatz bzw.

Die kanonische Form von Jordan kann als eine Verallgemeinerung der Diagonalisierungsfähigkeit auf beliebige lineare Transformationen (oder Matrizen) betrachtet werden. Tatsächlich ist die kanonische Form von Jordan einer diagonalisierbaren linearen Transformation (oder einer diagonalisierbaren Matrix) eine diagonale Matrix.

Inhalt


Das obige Beispiel zeigt eine Punktzahl von 4 im Menschen Abschnitt und eine Punktzahl von 6 in der Aufgabe Sektion. Das Viereck, an dem sich die beiden Linien schneiden, ist der Führungsstil, in diesem Fall — Autoritär.

Diese Tabelle gibt Ihnen eine Vorstellung von Ihrem Führungsstil:

Verarmt (1,1 bis 4,4): schwach in Bezug auf Aufgaben und soziale Fähigkeiten

Autoritär (Personen - 1 bis 4 und Aufgabe - 5 bis 9): stark bei Aufgaben, schwach bei Menschenkenntnissen

Socialite (Personen - 5 bis 9 und Aufgabe 1-4): stark in Bezug auf soziale Fähigkeiten, schwach in Aufgaben

Teamführung (6,6 bis 9,9): stark in Aufgaben und Menschenkenntnis

Middle-of-the-Road (5,5): in der Mitte des Charts, aber mit mehr Erfahrung und Fähigkeiten kann eine gute Teamführung gezeigt werden

Wie bei jedem anderen Instrument, das versucht, eine Person zu profilieren, müssen Sie jedoch andere Faktoren berücksichtigen, wie z. B. wie Ihr Vorgesetzter und Ihre Mitarbeiter Sie als Führungskraft bewerten, ob Sie Ihre Arbeit erledigen, sich um Ihre Mitarbeiter kümmern, Oder tragen Sie zum “Wachstum” Ihrer Organisation bei?

Sie sollten die Aussagen in der Umfrage überprüfen und über die niedrigen Werte nachdenken, indem Sie sich fragen, “Wenn ich in diesem Bereich bessere Ergebnisse erzielen würde, wäre ich dann ein effektiverer Anführer?” Und wenn die Antwort ja ist, dann sollte es a . werden persönlicher Aktionsgegenstand.


Matrizen¶

Eine Matrix ist ein rechteckiges Raster aus Zahlen oder Begriffen (wie eine Excel-Tabelle) mit speziellen Regeln für Addition, Subtraktion und Multiplikation.

Maße¶

Wir beschreiben die Dimensionen einer Matrix in Form von Zeilen für Spalten.

Die erste hat Dimensionen (3,2). Die zweite (2,3).

Skalare Operationen¶

Skalare Operationen mit Matrizen funktionieren genauso wie für Vektoren. Wenden Sie einfach den Skalar auf jedes Element in der Matrix an – addieren, subtrahieren, dividieren, multiplizieren usw.

Elementweise Operationen¶

Um zwei Matrizen addieren, subtrahieren oder dividieren zu können, müssen sie gleiche Dimensionen haben. Wir kombinieren entsprechende Werte elementweise zu einer neuen Matrix.

Hadamard-Produkt¶

Das Hadamard-Produkt von Matrizen ist eine elementweise Operation. Werte, die positionsmäßig übereinstimmen, werden multipliziert, um eine neue Matrix zu erzeugen.

In numpy können Sie das Hadamard-Produkt einer Matrix und eines Vektors verwenden, solange ihre Abmessungen den Anforderungen des Rundfunks entsprechen.

Matrix transponieren¶

Neuronale Netze verarbeiten häufig Gewichte und Eingaben unterschiedlicher Größe, deren Abmessungen nicht den Anforderungen der Matrixmultiplikation genügen. Die Matrixtransposition (oft gekennzeichnet durch ein hochgestelltes „T“, z. B. M^T) bietet eine Möglichkeit, eine der Matrizen zu „drehen“, damit die Operation den Multiplikationsanforderungen entspricht und fortgesetzt werden kann. Es gibt zwei Schritte, um eine Matrix zu transponieren:

  1. Drehen Sie die Matrix um 90° nach rechts
  2. Kehren Sie die Reihenfolge der Elemente in jeder Zeile um (z. B. [a b c] wird zu [c b a])

Transponieren Sie als Beispiel die Matrix M in T:

Matrix-Multiplikation¶

Die Matrixmultiplikation gibt einen Satz von Regeln zum Multiplizieren von Matrizen an, um eine neue Matrix zu erzeugen.

Nicht alle Matrizen können multipliziert werden. Darüber hinaus besteht eine Anforderung an die Dimensionen der resultierenden Matrixausgabe. Quelle.

  1. Die Anzahl der Spalten der 1. Matrix muss der Anzahl der Zeilen der 2.
  2. Das Produkt einer M x N-Matrix und einer N x K-Matrix ist eine M x K-Matrix. Die neue Matrix nimmt die Zeilen der 1. und die Spalten der 2.

Die Matrixmultiplikation beruht auf dem Punktprodukt, um verschiedene Kombinationen von Zeilen und Spalten zu multiplizieren. In der Abbildung unten, die aus dem exzellenten Linear-Algebra-Kurs der Khan Academy stammt, ist jeder Eintrag in Matrix C das Punktprodukt einer Zeile in Matrix A und einer Spalte in Matrix B [3].

Die Operation a1 · b1 bedeutet, dass wir das Skalarprodukt der 1. Zeile in Matrix A (1, 7) und der 1. Spalte in Matrix B (3, 5) nehmen.

Hier ist eine andere Möglichkeit, es zu betrachten:

Teste dich selbst¶


6.6: Die Matrix einer linearen Abbildung

Nachdem Sie dieses Kapitel gelesen haben, können Sie Folgendes tun:

  • Verstehen Sie, was Textur-Mapping zu Ihrer Szene hinzufügen kann
  • Geben Sie ein Texturbild an
  • Steuern Sie, wie ein Texturbild gefiltert wird, wenn es auf ein Fragment angewendet wird
  • Erstellen und verwalten Sie Texturbilder in Texturobjekten und steuern Sie, falls verfügbar, einen leistungsstarken Arbeitssatz dieser Texturobjekte
  • Geben Sie an, wie die Farbwerte im Bild mit denen des Fragments kombiniert werden, auf das es angewendet wird
  • Geben Sie Texturkoordinaten an, um anzugeben, wie das Texturbild an den Objekten in Ihrer Szene ausgerichtet werden soll
  • Verwenden Sie die automatische Generierung von Texturkoordinaten, um Effekte wie Konturkarten und Umgebungskarten zu erzeugen

Bisher wurde jedes geometrische Grundelement entweder als Volltonfarbe oder an seinen Scheitelpunkten zwischen den Farben schattiert gezeichnet – das heißt, sie wurden ohne Textur-Mapping gezeichnet. Wenn Sie beispielsweise eine große Ziegelwand ohne Textur-Mapping zeichnen möchten, muss jeder Ziegel als separates Polygon gezeichnet werden. Ohne Texturierung kann eine große flache Wand – die in Wirklichkeit ein einzelnes Rechteck ist – Tausende von einzelnen Ziegeln erfordern, und selbst dann können die Ziegel zu glatt und regelmäßig erscheinen, um realistisch zu sein.

Textur-Mapping ermöglicht es Ihnen, ein Bild einer Ziegelmauer (vielleicht durch Einscannen eines Fotos einer echten Wand erhalten) auf ein Polygon zu kleben und die gesamte Wand als einzelnes Polygon zu zeichnen. Textur-Mapping stellt sicher, dass beim Transformieren und Rendern des Polygons die richtigen Dinge passieren. Wenn die Wand beispielsweise perspektivisch betrachtet wird, können die Ziegel kleiner erscheinen, je weiter die Wand vom Blickpunkt entfernt ist. Andere Verwendungen für das Textur-Mapping umfassen die Darstellung von Vegetation auf großen Polygonen, die den Boden in der Flugsimulation darstellen, Tapetenmuster und Texturen, die Polygone wie natürliche Substanzen wie Marmor, Holz oder Stoff aussehen lassen.Die Möglichkeiten sind endlos. Obwohl es am natürlichsten ist, Texturen auf Polygone anzuwenden, können Texturen auf alle Grundelemente angewendet werden - Punkte, Linien, Polygone, Bitmaps und Bilder. Die Tafeln 6, 8, 18, 21, 24, 27 und 29, 31 zeigen alle die Verwendung von Texturen.

Da es so viele Möglichkeiten gibt, ist Textur-Mapping ein ziemlich großes und komplexes Thema, und Sie müssen mehrere Programmierentscheidungen treffen, wenn Sie es verwenden. Sie können beispielsweise Oberflächen, die aus einem Satz von Polygonen bestehen, oder gekrümmten Oberflächen Texturen zuordnen, und Sie können eine Textur in eine oder beide Richtungen wiederholen, um die Oberfläche zu bedecken. Eine Textur kann sogar eindimensional sein. Darüber hinaus können Sie einem Objekt automatisch eine Textur so zuordnen, dass die Textur Konturen oder andere Eigenschaften des betrachteten Objekts anzeigt. Glänzende Objekte können so strukturiert werden, dass sie sich in der Mitte eines Raums oder einer anderen Umgebung befinden und die Umgebung von ihren Oberflächen reflektieren. Schließlich kann eine Textur auf unterschiedliche Weise auf eine Oberfläche aufgebracht werden. Es kann direkt aufgemalt werden (wie ein Aufkleber auf einer Oberfläche), verwendet werden, um die Farbe zu modulieren, die sonst gemalt worden wäre, oder verwendet werden, um eine Texturfarbe mit der Oberflächenfarbe zu mischen. Wenn Sie zum ersten Mal mit Texture Mapping in Berührung kommen, werden Sie feststellen, dass die Diskussion in diesem Kapitel ziemlich schnell voranschreitet. Als zusätzliche Referenz können Sie sich das Kapitel über Textur-Mapping in Fundamentals of Three-Dimensional Computer Graphics von Alan Watt (Reading, MA: Addison-Wesley Publishing Company, 1990) ansehen.

Texturen sind einfach rechteckige Datenfelder – zum Beispiel Farbdaten, Luminanzdaten oder Farb- und Alphadaten. Die einzelnen Werte in einem Texturarray werden oft als Texel bezeichnet. Was das Textur-Mapping schwierig macht, ist, dass eine rechteckige Textur auf nicht rechteckige Bereiche abgebildet werden kann, und dies muss auf vernünftige Weise erfolgen.

Abbildung 9-1 veranschaulicht den Textur-Mapping-Prozess. Die linke Seite der Figur stellt die gesamte Textur dar, und der schwarze Umriss stellt eine vierseitige Form dar, deren Ecken diesen Punkten auf der Textur zugeordnet sind. Wenn das Viereck auf dem Bildschirm angezeigt wird, kann es durch verschiedene Transformationen - Drehungen, Translationen, Skalierungen und Projektionen - verzerrt werden. Die rechte Seite der Abbildung zeigt, wie das texturierte Viereck nach diesen Transformationen auf Ihrem Bildschirm erscheinen könnte. (Beachten Sie, dass dieses Viereck konkav ist und von OpenGL ohne vorherige Tesselierung möglicherweise nicht korrekt gerendert wird. Siehe Kapitel 11 für weitere Informationen zum Tesselieren von Polygonen.)

Abbildung 9-1: Textur-Mapping-Prozess

Beachten Sie, wie die Textur verzerrt ist, um der Verzerrung des Vierecks zu entsprechen. In diesem Fall wird es in x-Richtung gestreckt und in y-Richtung gestaucht, es findet auch eine kleine Drehung und Scherung statt. Abhängig von der Texturgröße, der Verzerrung des Vierecks und der Größe des Bildschirmbilds können einige der Texel auf mehr als ein Fragment abgebildet werden und einige Fragmente können von mehreren Texeln bedeckt sein. Da die Textur aus diskreten Texeln besteht (in diesem Fall 256 ´ 256 davon), müssen Filteroperationen durchgeführt werden, um Texel auf Fragmente abzubilden. Wenn zum Beispiel viele Texel einem Fragment entsprechen, werden sie gemittelt, damit sie passen, wenn Texelgrenzen über Fragmentgrenzen fallen, wird ein gewichteter Durchschnitt der anwendbaren Texel durchgeführt. Aufgrund dieser Berechnungen ist die Texturierung rechenintensiv, weshalb viele spezialisierte Grafiksysteme Hardwareunterstützung für das Textur-Mapping beinhalten.

Eine Anwendung kann Texturobjekte erstellen, wobei jedes Texturobjekt eine einzelne Textur (und mögliche zugehörige Mipmaps) darstellt. Einige Implementierungen von OpenGL können einen speziellen Arbeitssatz von Texturobjekten unterstützen, der eine bessere Leistung als Texturobjekte außerhalb des Arbeitssatzes hat. Diese Hochleistungstexturobjekte werden als resident bezeichnet und können über spezielle Hardware- und/oder Softwarebeschleunigung verfügen. Sie können OpenGL verwenden, um Texturobjekte zu erstellen und zu löschen und um zu bestimmen, welche Texturen Ihr Arbeitsset bilden.

Dieses Kapitel behandelt die Textur-Mapping-Funktion von OpenGL in den folgenden Hauptabschnitten.

  • "Ein Überblick und ein Beispiel" gibt einen kurzen, umfassenden Überblick über die Schritte, die erforderlich sind, um ein Textur-Mapping durchzuführen. Es präsentiert auch ein relativ einfaches Beispiel für Textur-Mapping.
  • "Specifying the Texture" erklärt, wie Sie ein- oder zweidimensionale Texturen festlegen. Außerdem wird erläutert, wie die Ränder einer Textur verwendet werden, wie eine Reihe verwandter Texturen unterschiedlicher Größe bereitgestellt und die Filtermethoden gesteuert werden, die verwendet werden, um zu bestimmen, wie eine angewendete Textur auf Bildschirmkoordinaten abgebildet wird.
  • "Filtern" beschreibt, wie Texturen entweder vergrößert oder verkleinert werden, wenn sie auf die Pixel von Polygonen angewendet werden. Die Verkleinerung mit speziellen Mipmap-Texturen wird ebenfalls erklärt.
  • "Texturobjekte" beschreibt, wie Sie Texturbilder in Objekte einfügen, damit Sie mehrere Texturen gleichzeitig steuern können. Mit Texturobjekten können Sie möglicherweise einen Arbeitssatz von Hochleistungstexturen erstellen, die als resident bezeichnet werden. Sie können auch Texturobjekte priorisieren, um die Wahrscheinlichkeit zu erhöhen oder zu verringern, dass ein Texturobjekt resident ist.
  • "Texture Functions" diskutiert die Methoden, die zum Malen einer Textur auf eine Oberfläche verwendet werden. Sie können wählen, ob die Texturfarbwerte diejenigen ersetzen, die verwendet würden, wenn die Texturierung nicht wirksam wäre, oder die endgültige Farbe eine Kombination aus beiden sein soll.
  • "Texturkoordinaten zuweisen" beschreibt, wie man den Scheitelpunkten eines Objekts geeignete Texturkoordinaten berechnet und zuweist. Außerdem wird erläutert, wie Sie das Verhalten von Koordinaten steuern, die außerhalb des Standardbereichs liegen, d. h. wie Texturen über eine Oberfläche wiederholt oder geklemmt werden.
  • "Automatic Texture-Coordinate Generation" zeigt, wie OpenGL automatisch Texturkoordinaten generieren lässt, damit Sie Effekte wie Kontur- und Umgebungskarten erzielen können.
  • "Erweiterte Funktionen" erklärt, wie Sie den Texturmatrixstapel manipulieren und die q-Texturkoordinate verwenden.

Version 1.1 von OpenGL führt mehrere neue Textur-Mapping-Operationen ein:

    • 38 zusätzliche interne Texturbildformate
    • Textur-Proxy, um abzufragen, ob genügend Ressourcen vorhanden sind, um ein bestimmtes Texturbild aufzunehmen
    • Texturunterbild, um ein vorhandenes Texturbild ganz oder teilweise zu ersetzen, anstatt eine Textur vollständig zu löschen und zu erstellen, um den gleichen Effekt zu erzielen
    • Angabe von Texturdaten aus dem Framebuffer-Speicher (sowie aus dem Prozessorspeicher)
    • Texturobjekte, einschließlich residenter Texturen und Priorisierung

    Wenn Sie versuchen, eine dieser Textur-Mapping-Operationen zu verwenden und sie nicht finden können, überprüfen Sie die Versionsnummer Ihrer OpenGL-Implementierung, um zu sehen, ob sie diese tatsächlich unterstützt. (Siehe „Welche Version verwende ich?“ in Kapitel 14.)

    Ein Überblick und ein Beispiel

    Dieser Abschnitt gibt einen Überblick über die Schritte, die zum Ausführen des Textur-Mappings erforderlich sind. Es präsentiert auch ein relativ einfaches Textur-Mapping-Programm. Natürlich wissen Sie, dass Textur-Mapping ein sehr aufwendiger Prozess sein kann.

    Schritte beim Textur-Mapping

    Um Textur-Mapping zu verwenden, führen Sie diese Schritte aus.

    Erstellen Sie ein Texturobjekt und geben Sie eine Textur für dieses Objekt an.

    Geben Sie an, wie die Textur auf jedes Pixel angewendet werden soll.

    Zeichnen Sie die Szene und geben Sie sowohl Textur als auch geometrische Koordinaten an.

    Beachten Sie, dass das Textur-Mapping nur im RGBA-Modus funktioniert. Textur-Mapping-Ergebnisse im Farbindex-Modus sind undefiniert.

    Erstellen Sie ein Texturobjekt und geben Sie eine Textur für dieses Objekt an

    Eine Textur wird normalerweise wie die meisten Bilder als zweidimensional angesehen, sie kann jedoch auch eindimensional sein. Die eine Textur beschreibenden Daten können aus einem, zwei, drei oder vier Elementen pro Texel bestehen, die alles von einer Modulationskonstante bis zu einem (R, G, B, A)-Vierfach darstellen.

    In Beispiel 9-1, das sehr einfach ist, wird ein einzelnes Texturobjekt erstellt, um eine einzelne zweidimensionale Textur zu erhalten. In diesem Beispiel wird nicht ermittelt, wie viel Speicher verfügbar ist. Da nur eine Textur erstellt wird, gibt es keinen Versuch, einen Arbeitssatz von Texturobjekten zu priorisieren oder anderweitig zu verwalten. Andere fortgeschrittene Techniken wie Texturgrenzen oder Mipmaps werden in diesem einfachen Beispiel nicht verwendet.

    Geben Sie an, wie die Textur auf jedes Pixel angewendet werden soll

    Sie können eine von vier möglichen Funktionen zum Berechnen des endgültigen RGBA-Werts aus der Fragmentfarbe und den Texturbilddaten auswählen. Eine Möglichkeit besteht darin, einfach die Texturfarbe als endgültige Farbe zu verwenden. Dies ist der Abziehbildmodus, bei dem die Textur auf das Fragment gemalt wird, so wie ein Abziehbild aufgetragen würde. (Beispiel 9-1 verwendet den Abziehmodus.) Der Ersetzungsmodus, eine Variante des Abziehbildmodus, ist eine zweite Methode. Eine andere Methode besteht darin, die Textur zu verwenden, um die Farbe des Fragments zu modulieren oder zu skalieren. Diese Technik ist nützlich, um die Effekte von Beleuchtung mit Texturen zu kombinieren. Schließlich kann basierend auf dem Texturwert eine konstante Farbe mit der des Fragments gemischt werden.

    Texturzuordnung aktivieren

    Sie müssen die Texturierung aktivieren, bevor Sie Ihre Szene zeichnen. Die Texturierung wird mit glEnable() bzw. glDisable() mit der symbolischen Konstante GL_TEXTURE_1D bzw. GL_TEXTURE_2D für ein- bzw. zweidimensionale Texturierung aktiviert bzw. deaktiviert. (Wenn beide aktiviert sind, wird GL_TEXTURE_2D verwendet.)

    Zeichnen Sie die Szene und geben Sie sowohl Textur als auch geometrische Koordinaten an

    Sie müssen angeben, wie die Textur relativ zu den Fragmenten ausgerichtet werden soll, auf die sie angewendet werden soll, bevor sie "aufgeklebt" wird. Das heißt, Sie müssen sowohl Texturkoordinaten als auch geometrische Koordinaten angeben, wenn Sie die Objekte in Ihrer Szene angeben. Bei einer zweidimensionalen Texturabbildung reichen die Texturkoordinaten beispielsweise von 0,0 bis 1,0 in beide Richtungen, aber die Koordinaten der zu texturierenden Elemente können beliebig sein. Wenn die Wand im Beispiel einer Ziegelwand quadratisch ist und eine Kopie der Textur darstellen soll, weist der Code wahrscheinlich Texturkoordinaten (0, 0) (1, 0), (1, 1) und (0 .) zu , 1) an den vier Ecken der Wand. Wenn die Wand groß ist, möchten Sie möglicherweise mehrere Kopien der Textur-Map darauf malen. Wenn Sie dies tun, muss die Textur-Map so gestaltet werden, dass die Steine ​​am linken Rand gut zu den Steinen am rechten Rand passen, und ähnlich für die Steine ​​oben und unten.

    Sie müssen auch angeben, wie Texturkoordinaten außerhalb des Bereichs [0.0,1.0] behandelt werden sollen. Wiederholen sich die Texturen, um das Objekt abzudecken, oder sind sie auf einen Grenzwert geklemmt?

    Ein Beispielprogramm

    Eines der Probleme beim Zeigen von Beispielprogrammen zur Veranschaulichung des Textur-Mappings besteht darin, dass interessante Texturen groß sind. Normalerweise werden Texturen aus einer Bilddatei gelesen, da die programmgesteuerte Angabe einer Textur Hunderte von Codezeilen erfordern kann. In Beispiel 9-1 wird die Textur - die wie ein Schachbrett aus abwechselnd weißen und schwarzen Quadraten besteht - vom Programm generiert. Das Programm wendet diese Textur auf zwei Quadrate an, die dann perspektivisch gerendert werden, von denen eines dem Betrachter im Quadrat zugewandt ist und das andere um 45 Grad nach hinten geneigt ist, wie in Abbildung 9-2 gezeigt. In Objektkoordinaten sind beide Quadrate gleich groß.

    Abbildung 9-2: Textur-zugeordnete Quadrate

    Beispiel 9-1: Textur-Mapped Checkerboard: checker.c

    Die Checkerboard-Textur wird in der Routine makeCheckImage() generiert, und die gesamte Textur-Mapping-Initialisierung erfolgt in der Routine init() . glGenTextures() und glBindTexture() benennen und erzeugen ein Texturobjekt für ein Texturbild. (Siehe "Texturobjekte".) Die einzelne Textur-Map mit voller Auflösung wird von glTexImage2D() spezifiziert, dessen Parameter die Größe des Bildes, den Typ des Bildes, die Position des Bildes und andere Eigenschaften davon angeben. (Weitere Informationen zu glTexImage2D() finden Sie unter "Angeben der Textur".)

    Die vier Aufrufe von glTexParameter*() geben an, wie die Textur umbrochen und die Farben gefiltert werden sollen, wenn keine exakte Übereinstimmung zwischen Pixeln in der Textur und Pixeln auf dem Bildschirm besteht. (Siehe „Wiederholen und Einspannen von Texturen“ und „Filtern“.)

    In display() aktiviert glEnable() die Texturierung. glTexEnv*() setzt den Zeichenmodus auf GL_DECAL, sodass die texturierten Polygone mit den Farben aus der Textur-Map gezeichnet werden (anstatt zu berücksichtigen, welche Farbe die Polygone ohne die Textur gezeichnet worden wären).

    Dann werden zwei Polygone gezeichnet. Beachten Sie, dass Texturkoordinaten zusammen mit Scheitelpunktkoordinaten angegeben werden. Der Befehl glTexCoord*() verhält sich ähnlich wie der Befehl glNormal(). glTexCoord*() setzt die aktuellen Texturkoordinaten jedem nachfolgenden Vertex-Befehl sind diese Texturkoordinaten zugeordnet, bis glTexCoord*() erneut aufgerufen wird.

    Hinweis: Das Schachbrettbild auf dem geneigten Polygon sieht möglicherweise falsch aus, wenn Sie es kompilieren und auf Ihrem Computer ausführen - zum Beispiel kann es wie zwei Dreiecke mit unterschiedlichen Projektionen des Schachbrettbildes darauf aussehen. Versuchen Sie in diesem Fall, den Parameter GL_PERSPECTIVE_CORRECTION_HINT auf GL_NICEST zu setzen und das Beispiel erneut auszuführen. Verwenden Sie dazu glHint() .

    Spezifizieren der Textur

    Der Befehl glTexImage2D() definiert eine zweidimensionale Textur. Es braucht mehrere Argumente, die hier kurz und in den folgenden Unterabschnitten ausführlicher beschrieben werden. Der zugehörige Befehl für eindimensionale Texturen, glTexImage1D() , wird in "Eindimensionale Texturen" beschrieben.

    void glTexImage2D (GLenum target , GLint level , GLint internalFormat ,
    GLsizei Breite , GLsizei Höhe , GLint Rahmen ,
    GLenum-Format , GLenum-Typ ,
    const GLvoid *pixels ) Definiert eine zweidimensionale Textur. Der Zielparameter wird entweder auf die Konstante GL_TEXTURE_2D oder GL_PROXY_TEXTURE_2D gesetzt. Sie verwenden den level-Parameter, wenn Sie mehrere Auflösungen der Textur-Map mit nur einer Auflösung bereitstellen, level sollte 0 sein. (Weitere Informationen zur Verwendung mehrerer Auflösungen finden Sie unter "Mehrere Detailebenen".) Der nächste Parameter, internalFormat, gibt an welche der R-, G-, B- und A-Komponenten oder Luminanz- oder Intensitätswerte zur Verwendung beim Beschreiben der Texel eines Bildes ausgewählt werden. Der Wert von internalFormat ist eine ganze Zahl von 1 bis 4 oder eine von 38 symbolischen Konstanten. Die achtunddreißig symbolischen Konstanten, die auch rechtliche Werte für internalFormat sind GL_ALPHA, GL_ALPHA4, GL_ALPHA8, GL_ALPHA12, GL_ALPHA16, GL_LUMINANCE, GL_LUMINANCE4, GL_LUMINANCE8, GL_LUMINANCE12, GL_LUMINANCE16, GL_LUMINANCE_ALPHA, GL_LUMINANCE4_ALPHA4, GL_LUMINANCE6_ALPHA2, GL_LUMINANCE8_ALPHA8, GL_LUMINANCE12_ALPHA4, GL_LUMINANCE12_ALPHA12, GL_LUMINANCE16_ALPHA16, GL_INTENSITY, GL_INTENSITY4, GL_INTENSITY8, GL_INTENSITY12, GL_INTENSITY16, GL_RGB, GL_R3_G3_B2, GL_RGB4, GL_RGB5, GL_RGB8, GL_RGB10, GL_RGB12, GL_RGB16, GL_RGBA, GL_RGBA2, GL_RGBA4, GL_RGB5_A1, GL_RGBA8, GL_RGB10_A2, GL_RGBA12 und GL_RGBA16. (Siehe "Texturfunktionen" für eine Diskussion darüber, wie diese ausgewählten Komponenten angewendet werden.) Wenn internalFormat eine der 38 symbolischen Konstanten ist, dann fragen Sie nach bestimmten Komponenten und vielleicht nach der Auflösung dieser Komponenten. Wenn internalFormat beispielsweise GL_R3_G3_B2 ist, verlangen Sie, dass Texel 3 Bits Rot, 3 Bits Grün und 2 Bits Blau haben, aber OpenGL kann dies nicht garantieren. OpenGL ist nur verpflichtet, eine interne Darstellung zu wählen, die der Anforderung sehr nahe kommt, aber eine genaue Übereinstimmung ist normalerweise nicht erforderlich. Per Definition sind GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB und GL_RGBA nachsichtig, da sie keine bestimmte Auflösung verlangen. (Aus Gründen der Kompatibilität mit der OpenGL-Version 1.0 entsprechen die numerischen Werte 1, 2, 3 und 4 für internalFormat den symbolischen Konstanten GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB bzw. GL_RGBA.) Die Parameter width und height geben die Abmessungen an des Texturbildrahmens gibt die Breite des Rahmens an, die entweder null (kein Rahmen) oder eins ist. (Siehe "Verwenden der Grenzen einer Textur" .) Sowohl Breite als auch Höhe müssen die Form 2m+2b haben, wobei m eine nicht negative ganze Zahl ist (die einen anderen Wert für Breite als für Höhe haben kann) und b der Wert von border ist. Die maximale Größe einer Texturmap hängt von der Implementierung von OpenGL ab, muss jedoch mindestens 64 ´ 64 (oder 66 ´ 66 mit Rahmen) betragen. Die Parameter format und type beschreiben das Format und den Datentyp der Texturbilddaten. Sie haben die gleiche Bedeutung wie bei glDrawPixels() . (Siehe "Imaging Pipeline" in Kapitel 8.) Tatsächlich haben Texturdaten das gleiche Format wie die Daten, die von glDrawPixels() verwendet werden, daher werden die Einstellungen von glPixelStore*() und glPixelTransfer*() angewendet. (In Beispiel 9-1 ist der Aufruf
    wird erstellt, weil die Daten im Beispiel nicht am Ende jeder Texelzeile aufgefüllt werden.) Der Formatparameter kann GL_COLOR_INDEX, GL_RGB, GL_RGBA, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA, GL_LUMINANCE oder GL_LUMINANCE_ALPHA sein für glDrawPixels() verfügbare Formate mit Ausnahme von GL_STENCIL_INDEX und GL_DEPTH_COMPONENT. Ebenso kann der Typparameter GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT, GL_FLOAT oder GL_BITMAP sein. Schließlich enthält Pixel die Texturbilddaten. Diese Daten beschreiben das Texturbild selbst sowie seinen Rand.

    Das interne Format eines Texturbildes kann die Leistung von Texturoperationen beeinflussen. Beispielsweise führen einige Implementierungen die Texturierung mit GL_RGBA schneller als mit GL_RGB durch, da die Farbkomponenten den Prozessorspeicher besser ausrichten. Da dies unterschiedlich ist, sollten Sie spezifische Informationen zu Ihrer OpenGL-Implementierung überprüfen.

    Das interne Format eines Texturbildes kann auch steuern, wie viel Speicher ein Texturbild verbraucht. Beispielsweise verwendet eine Textur des internen Formats GL_RGBA8 32 Bits pro Texel, während eine Textur des internen Formats GL_R3_G3_B2 nur 8 Bits pro Texel verwendet. Natürlich gibt es einen entsprechenden Kompromiss zwischen Speicherverbrauch und Farbauflösung.

    Hinweis: Obwohl Textur-Mapping-Ergebnisse im Farbindexmodus undefiniert sind, können Sie dennoch eine Textur mit einem GL_COLOR_INDEX-Bild angeben. In diesem Fall werden Pixelübertragungsoperationen angewendet, um die Indizes durch Tabellensuche in RGBA-Werte umzuwandeln, bevor sie zum Bilden des Texturbilds verwendet werden.

    Die Anzahl der Texel sowohl für die Breite als auch für die Höhe eines Texturbildes, ohne den optionalen Rahmen, muss eine Potenz von 2 sein. Wenn Ihr Originalbild keine Abmessungen hat, die dieser Beschränkung entsprechen, können Sie die OpenGL Utility Library-Routine gluScaleImage . verwenden (), um die Größe Ihrer Texturen zu ändern.

    int gluScaleImage (GLenum format , GLint widthin , GLint heightin ,
    GLenum typein , const void * datain , GLint widthout ,
    GLint heightout , GLenum typeout , void * dataout ) Skaliert ein Bild mit den entsprechenden Pixelspeichermodi, um die Daten aus datain zu entpacken. Die Parameter format , typein und typeout können sich auf alle Formate oder Datentypen beziehen, die von glDrawPixels() unterstützt werden. Das Bild wird unter Verwendung von linearer Interpolation und Boxfilterung skaliert (von der durch widthin und heightin angegebenen Größe zu widthout und heightout ), und das resultierende Bild wird unter Verwendung der Pixel-GL_PACK*-Speichermodi in dataout geschrieben. Der Aufrufer von gluScaleImage() muss ausreichend Platz für den Ausgabepuffer zuweisen.Bei Erfolg wird der Wert 0 zurückgegeben, und bei einem Fehler wird ein GLU-Fehlercode zurückgegeben.

    Der Framebuffer selbst kann auch als Quelle für Texturdaten verwendet werden. glCopyTexImage2D() liest ein Pixel-Rechteck aus dem Framebuffer und verwendet es für eine neue Textur.

    void glCopyTexImage2D (GLenum target , GLint level ,
    GLint internesFormat ,
    GLint x , GLint y , GLsizei Breite , GLsizei Höhe ,
    GLint border ) Erstellt eine zweidimensionale Textur, die Framebuffer-Daten verwendet, um die Texel zu definieren. Die Pixel werden aus dem aktuellen GL_READ_BUFFER gelesen und genau so verarbeitet, als ob glCopyPixels() aufgerufen, aber vor der endgültigen Konvertierung gestoppt wurde. Die Einstellungen von glPixelTransfer*() werden übernommen. Der Zielparameter muss auf die Konstante GL_TEXTURE_2D gesetzt werden. Die Parameter level, internalFormat und border haben dieselben Auswirkungen wie für glTexImage2D() . Das Texturarray wird aus einem am Bildschirm ausgerichteten Pixelrechteck mit der unteren linken Ecke an den durch die (x, y)-Parameter angegebenen Koordinaten entnommen. Die Parameter width und height geben die Größe dieses Pixelrechtecks ​​an. Sowohl Breite als auch Höhe müssen die Form 2m+2b haben, wobei m eine nichtnegative ganze Zahl ist (die einen anderen Wert für Breite als für Höhe haben kann) und b der Wert von border ist.

    Die nächsten Abschnitte enthalten weitere Details zur Texturierung, einschließlich der Verwendung der Parameter target , border und level. Der Parameter target kann verwendet werden, um die Größe einer Textur genau abzufragen (durch Erstellen eines Textur-Proxys mit glTexImage*D() ) und ob eine Textur möglicherweise innerhalb der Texturressourcen einer OpenGL-Implementierung verwendet werden kann. Das Neudefinieren eines Teils einer Textur wird unter "Ersetzen eines gesamten oder eines Teils eines Texturbildes" beschrieben. Eindimensionale Texturen werden in "Eindimensionale Texturen" besprochen. Der Texturrahmen, dessen Größe durch den border-Parameter gesteuert wird, wird in "Verwenden der Grenzen einer Textur" beschrieben. Der Parameter level dient zur Angabe von Texturen unterschiedlicher Auflösung und ist in die spezielle Technik des Mipmappings integriert, die in "Multiple Levels of Detail" erklärt wird. Mipmapping erfordert das Verständnis, wie Texturen gefiltert werden, wenn sie angewendet werden. Filtern ist das Thema von "Filtern".

    Textur-Proxy

    Für einen OpenGL-Programmierer, der Texturen verwendet, ist die Größe wichtig. Texturressourcen sind in der Regel begrenzt und variieren je nach OpenGL-Implementierung. Es gibt ein spezielles Textur-Proxy-Target, um zu bewerten, ob genügend Ressourcen verfügbar sind.

    glGetIntegerv (GL_MAX_TEXTURE_SIZE. ) sagt Ihnen die größte Dimension (Breite oder Höhe, ohne Rahmen) eines Texturbildes, normalerweise die Größe der größten unterstützten quadratischen Textur. GL_MAX_TEXTURE_SIZE berücksichtigt jedoch nicht die Auswirkungen des internen Formats einer Textur. Ein Texturbild, das Texel im internen Format GL_RGBA16 speichert, verwendet möglicherweise 64 Bit pro Texel, sodass sein Bild möglicherweise 16-mal kleiner sein muss als ein Bild mit dem internen Format GL_LUMINANCE4. (Außerdem können Bilder, die Rahmen oder Mipmaps erfordern, den verfügbaren Speicher weiter reduzieren.)

    Ein spezieller Platzhalter oder Proxy für ein Texturbild ermöglicht es dem Programm, genauer abzufragen, ob OpenGL eine Textur eines gewünschten internen Formats aufnehmen kann. Um den Proxy zum Abfragen von OpenGL zu verwenden, rufen Sie glTexImage2D() mit einem Zielparameter von GL_PROXY_TEXTURE_2D und dem angegebenen Level, internalFormat, width, height, border, format und type auf. (Verwenden Sie für eindimensionale Texturen entsprechende 1D-Routinen und symbolische Konstanten.) Für einen Proxy sollten Sie NULL als Zeiger für das Pixel-Array übergeben.

    Um herauszufinden, ob für Ihre Textur genügend Ressourcen zur Verfügung stehen, fragen Sie nach dem Erstellen des Textur-Proxys die Textur-Zustandsvariablen mit glGetTexLevelParameter*() ab. Wenn nicht genügend Ressourcen für den Textur-Proxy vorhanden sind, werden die Texturzustandsvariablen für Breite, Höhe, Rahmenbreite und Komponentenauflösung auf 0 gesetzt.

    void glGetTexLevelParameter v (GLenum-Ziel , GLint-Ebene ,
    GLenum pname , TYPE * params ) Gibt in params Texturparameterwerte für eine bestimmte Detailebene zurück, angegeben als level . target definiert die Zieltextur und ist eine von GL_TEXTURE_1D, GL_TEXTURE_2D, GL_PROXY_TEXTURE_1D oder GL_PROXY_TEXTURE_2D. Zulässige Werte für pname sind GL_TEXTURE_WIDTH, GL_TEXTURE_HEIGHT, GL_TEXTURE_BORDER, GL_TEXTURE_INTERNAL_FORMAT, GL_TEXTURE_RED_SIZE, GL_TEXTURE_GREEN_SIZE, GL_TEXTURE_BLUE_SIZE, GL_TEXTURE_ALPHA_SIZE, GL_TEXTURE_ALPHA_SIZE, GL_TEXTURE_ALPHA_SIZE, GL_TEXTURE_ALPHA_SIZE, GL_TEXTURE_ALPHA_SIZE, GL_TEXTURE_COMPONENTS wird auch für pname akzeptiert, aber nur aus Gründen der Abwärtskompatibilität mit OpenGL Release 1.0 - GL_TEXTURE_INTERNAL_FORMAT ist die empfohlene symbolische Konstante für Release 1.1.

    Beispiel 9-2 zeigt, wie Sie den Textur-Proxy verwenden, um herauszufinden, ob genügend Ressourcen vorhanden sind, um eine 64 ´ 64 Texel-Textur mit RGBA-Komponenten mit 8 Bit Auflösung zu erstellen. Gelingt dies, dann speichert glGetTexLevelParameteriv() das interne Format (in diesem Fall GL_RGBA8) in die Variable format .

    Beispiel 9-2: Abfragen von Texturressourcen mit einem Texture-Proxy

    Hinweis: Es gibt eine große Einschränkung bei Textur-Proxys: Der Textur-Proxy sagt Ihnen, ob Platz für Ihre Textur vorhanden ist, aber nur, wenn alle Textur-Ressourcen verfügbar sind (mit anderen Worten, wenn es die einzige Textur in der Stadt ist). Wenn andere Texturen Ressourcen verwenden, reagiert die Textur-Proxy-Abfrage möglicherweise positiv, aber möglicherweise ist nicht genügend Platz vorhanden, um Ihre Textur resident zu machen (dh Teil eines möglicherweise leistungsstarken Arbeitssatzes von Texturen). (Weitere Informationen zum Verwalten residenter Texturen finden Sie unter "Texturobjekte".)

    Ersetzen des gesamten oder eines Teils eines Texturbilds

    Das Erstellen einer Textur kann rechenintensiver sein als das Modifizieren einer bestehenden. In OpenGL Release 1.1 gibt es neue Routinen, um ein Texturbild ganz oder teilweise durch neue Informationen zu ersetzen. Dies kann für bestimmte Anwendungen hilfreich sein, z. B. die Verwendung von in Echtzeit aufgenommenen Videobildern als Texturbilder. Für diese Anwendung ist es sinnvoll, eine einzelne Textur zu erstellen und mit glTexSubImage2D() die Texturdaten wiederholt durch neue Videobilder zu ersetzen. Außerdem gibt es für glTexSubImage2D() keine Größenbeschränkungen, die die Höhe oder Breite zu einer Zweierpotenz zwingen. Dies ist hilfreich bei der Verarbeitung von Videobildern, die im Allgemeinen keine Zweierpotenzen haben.

    void glTexSubImage2D (GLenum target , GLint level , GLint xoffset ,
    GLint yoffset , GLsizei Breite , GLsizei Höhe ,
    GLenum format , GLenum type , const GLvoid *pixels ) Definiert ein zweidimensionales Texturbild, das einen zusammenhängenden Unterbereich (in 2D einfach ein Rechteck) des aktuellen, existierenden zweidimensionalen Texturbildes ganz oder teilweise ersetzt. Der Zielparameter muss auf GL_TEXTURE_2D gesetzt werden. Die Parameter level, format und type ähneln denen, die für glTexImage2D() verwendet werden. level ist die Mipmap-Detailgenauigkeitsnummer. Es ist kein Fehler, eine Breite oder Höhe von Null anzugeben, aber das Unterbild hat keine Auswirkung. format und type beschreiben das Format und den Datentyp der Texturbilddaten. Das Unterbild wird auch von den Modi beeinflusst, die von glPixelStore*() und glPixelTransfer*() gesetzt werden. Pixel enthält die Texturdaten für das Unterbild. Breite und Höhe sind die Abmessungen des Unterbereichs, der das gesamte oder einen Teil des aktuellen Texturbilds ersetzt. xoffset und yoffset geben den Texel-Offset in x- und y-Richtung an (mit (0, 0) in der unteren linken Ecke der Textur) und geben an, wo das Unterbild innerhalb des vorhandenen Textur-Arrays platziert werden soll. Dieser Bereich darf keine Texel außerhalb des Bereichs des ursprünglich definierten Texturarrays enthalten.

    In Beispiel 9-3 wurde ein Teil des Codes aus Beispiel 9-1 modifiziert, sodass durch Drücken der Taste `s' ein kleineres kariertes Unterbild in das vorhandene Bild eingefügt wird. (Die resultierende Textur ist in Abbildung 9-3 dargestellt.) Durch Drücken der Taste `r' wird das Originalbild wiederhergestellt. Beispiel 9-3 zeigt die beiden Routinen makeCheckImages() und keyboard() , die grundlegend geändert wurden. (Weitere Informationen zu glBindTexture() finden Sie unter "Texturobjekte".)

    Abbildung 9-3: Textur mit hinzugefügtem Unterbild

    Beispiel 9-3 : Ersetzen eines Texturunterbilds: texsub.c

    Auch diesmal kann der Framebuffer selbst als Quelle für Texturdaten verwendet werden, ein Texturunterbild. glCopyTexSubImage2D() liest ein Rechteck von Pixeln aus dem Framebuffer und ersetzt einen Teil eines vorhandenen Texturarrays. ( glCopyTexSubImage2D() ist eine Art Kreuzung zwischen glCopyTexImage2D() und glTexSubImage2D() .)

    void glCopyTexSubImage2D (GLenum target , GLint level ,
    GLint xoffset , GLint yoffset , GLint x , GLint y ,
    GLsizei width , GLsizei height ) Verwendet Bilddaten aus dem Framebuffer, um einen zusammenhängenden Unterbereich des aktuellen, existierenden zweidimensionalen Texturbildes ganz oder teilweise zu ersetzen. Die Pixel werden aus dem aktuellen GL_READ_BUFFER gelesen und genau so verarbeitet, als ob glCopyPixels() aufgerufen worden wäre, und stoppt vor der endgültigen Konvertierung. Die Einstellungen von glPixelStore*() und glPixelTransfer*() werden übernommen. Der Zielparameter muss auf GL_TEXTURE_2D gesetzt werden. level ist die Mipmap-Detailgenauigkeitsnummer. xoffset und yoffset geben den Texel-Offset in x- und y-Richtung an (mit (0, 0) in der unteren linken Ecke der Textur) und geben an, wo das Unterbild innerhalb des vorhandenen Textur-Arrays platziert werden soll. Das Unterbild-Texturarray wird aus einem am Bildschirm ausgerichteten Pixelrechteck mit der unteren linken Ecke an den durch die (x, y)-Parameter angegebenen Koordinaten entnommen. Die Parameter width und height geben die Größe dieses Unterbildrechtecks ​​an.

    Eindimensionale Texturen

    Manchmal reicht eine eindimensionale Textur aus – zum Beispiel, wenn Sie texturierte Bänder zeichnen, bei denen alle Variationen in eine Richtung gehen. Eine eindimensionale Textur verhält sich wie eine zweidimensionale mit Höhe = 1 und ohne Rand oben und unten. Alle zweidimensionalen Textur- und Subtextur-Definitionsroutinen haben entsprechende eindimensionale Routinen. Um eine einfache eindimensionale Textur zu erstellen, verwenden Sie glTexImage1D() .

    void glTexImage1D (GLenum target , GLint level , GLint internalFormat ,
    GLsizei Breite , GLint Rahmen , GLenum Format ,
    GLenum type , const GLvoid *pixels ) Definiert eine eindimensionale Textur. Alle Parameter haben die gleiche Bedeutung wie für glTexImage2D() , außer dass das Bild jetzt ein eindimensionales Array von Texeln ist. Wie zuvor beträgt der Wert der Breite 2 m (oder 2 m + 2, wenn ein Rahmen vorhanden ist), wobei m eine nicht negative ganze Zahl ist. Sie können Mipmaps und Proxys bereitstellen (Ziel auf GL_PROXY_TEXTURE_1D setzen) und dieselben Filteroptionen sind ebenfalls verfügbar.

    Ein Beispielprogramm, das eine eindimensionale Textur-Map verwendet, finden Sie in Beispiel 9-6.

    Um alle oder einige Texel einer eindimensionalen Textur zu ersetzen, verwenden Sie glTexSubImage1D() .

    void glTexSubImage1D (GLenum target , GLint level , GLint xoffset ,
    GLsizei Breite , GLenum Format ,
    GLenum type , const GLvoid *pixels ) Definiert ein eindimensionales Texturarray, das einen zusammenhängenden Unterbereich (in 1D eine Zeile) des aktuellen, existierenden eindimensionalen Texturbildes ganz oder teilweise ersetzt. Der Zielparameter muss auf GL_TEXTURE_1D gesetzt werden. Die Parameter level, format und type ähneln denen, die für glTexImage1D() verwendet werden. level ist die Mipmap-Detailgenauigkeitsnummer. format und type beschreiben das Format und den Datentyp der Texturbilddaten. Das Unterbild wird auch von Modi beeinflusst, die von glPixelStore*() oder glPixelTransfer*() gesetzt wurden.

    Pixel enthält die Texturdaten für das Unterbild. width ist die Anzahl der Texel, die einen Teil oder das gesamte aktuelle Texturbild ersetzen. xoffset gibt den Texel-Offset an, an dem das Unterbild innerhalb des vorhandenen Texturarrays platziert werden soll.

    Um den Framebuffer als Quelle einer neuen oder als Ersatz für eine alte eindimensionale Textur zu verwenden, verwenden Sie entweder glCopyTexImage1D() oder glCopyTexSubImage1D() .

    void glCopyTexImage1D (GLenum target , GLint level ,
    GLint internesFormat , GLint x , GLint y ,
    GLsizei width , GLint border ) Erzeugt eine eindimensionale Textur, die Framebuffer-Daten verwendet, um die Texel zu definieren. Die Pixel werden aus dem aktuellen GL_READ_BUFFER gelesen und genau so verarbeitet, als ob glCopyPixels() aufgerufen, aber vor der endgültigen Konvertierung gestoppt wurde. Die Einstellungen von glPixelStore*() und glPixelTransfer*() werden übernommen. Der Zielparameter muss auf die Konstante GL_TEXTURE_1D gesetzt werden. Die Parameter level, internalFormat und border haben dieselben Auswirkungen wie für glCopyTexImage2D() . Das Texturarray wird aus einer Pixelreihe entnommen, wobei die untere linke Ecke an den durch die (x, y)-Parameter angegebenen Koordinaten liegt. Der Parameter width gibt die Anzahl der Pixel in dieser Zeile an. Der Wert der Breite beträgt 2 m (oder 2 m + 2, wenn ein Rahmen vorhanden ist), wobei m eine nicht negative ganze Zahl ist. void glCopyTexSubImage1D (GLenum target , GLint level , GLint xoffset ,
    GLint x , GLint y , GLsizei width ) Verwendet Bilddaten aus dem Framebuffer, um den gesamten oder einen Teil eines zusammenhängenden Unterbereichs des aktuellen, existierenden eindimensionalen Texturbildes zu ersetzen. Die Pixel werden aus dem aktuellen GL_READ_BUFFER gelesen und genau so verarbeitet, als ob glCopyPixels() aufgerufen, aber vor der endgültigen Konvertierung gestoppt wurde. Die Einstellungen von glPixelStore*() und glPixelTransfer*() werden übernommen. Der Zielparameter muss auf GL_TEXTURE_1D gesetzt werden. level ist die Mipmap-Detailgenauigkeitsnummer. xoffset gibt den Texel-Offset an und gibt an, wo das Unterbild innerhalb des vorhandenen Texturarrays platziert werden soll. Das Unterbild-Texturarray wird aus einer Pixelreihe entnommen, wobei die untere linke Ecke an Koordinaten liegt, die durch die (x, y)-Parameter angegeben sind. Der Parameter width gibt die Anzahl der Pixel in dieser Zeile an.

    Verwenden der Ränder einer Textur

    Wenn Sie eine größere Textur-Map anwenden müssen, als Ihre OpenGL-Implementierung zulässt, können Sie mit ein wenig Sorgfalt effektiv größere Texturen erstellen, indem Sie mehrere verschiedene Texturen kacheln. Wenn Sie beispielsweise eine Textur benötigen, die doppelt so groß ist wie die maximal zulässige Größe, die einem Quadrat zugeordnet ist, zeichnen Sie das Quadrat als vier Unterquadrate und laden Sie eine andere Textur, bevor Sie jedes Teil zeichnen.

    Da immer nur eine einzige Textur-Map verfügbar ist, kann dieser Ansatz zu Problemen an den Rändern der Texturen führen, insbesondere wenn irgendeine Form der linearen Filterung aktiviert ist. Der für Pixel an den Rändern zu verwendende Texturwert muss mit etwas außerhalb der Kante gemittelt werden, was idealerweise aus der benachbarten Textur-Map stammen sollte. Wenn Sie für jede Textur, deren Texel-Werte gleich den Werten der Texel am Rand der angrenzenden Textur-Map sind, einen Rahmen definieren, dann ergibt sich bei linearer Filterung das richtige Verhalten.

    Um dies richtig zu machen, beachten Sie, dass jede Karte acht Nachbarn haben kann – einen angrenzend an jede Kante und einen, der jede Ecke berührt. Die Werte der Texel in der Ecke der Grenze müssen mit den Texeln in den Textur-Maps übereinstimmen, die die Ecken berühren. Wenn Ihre Textur eine Kante oder Ecke der gesamten Kachelung ist, müssen Sie entscheiden, welche Werte für die Umrandung sinnvoll sind. Am einfachsten ist es, den Wert des angrenzenden Texels in die Textur-Map zu kopieren. Denken Sie daran, dass die Randwerte gleichzeitig mit den Texturbilddaten bereitgestellt werden müssen, also müssen Sie dies im Voraus herausfinden.

    Die Rahmenfarbe einer Textur wird auch verwendet, wenn die Textur so angewendet wird, dass sie ein Primitiv nur teilweise bedeckt. (Weitere Informationen zu dieser Situation finden Sie unter "Texturen wiederholen und klemmen".)

    Mehrere Detailebenen

    Texturierte Objekte können wie alle anderen Objekte in einer Szene in unterschiedlichen Abständen vom Blickpunkt betrachtet werden. In einer dynamischen Szene muss die Textur-Map zusammen mit der Größe des projizierten Bildes kleiner werden, wenn sich ein texturiertes Objekt weiter vom Blickpunkt entfernt. Um dies zu erreichen, muss OpenGL die Textur-Map auf eine geeignete Größe für das Mapping auf das Objekt herunterfiltern, ohne visuell störende Artefakte einzubringen. Um beispielsweise eine Ziegelwand zu rendern, können Sie ein großes Texturbild (z. B. 128 ´ 128 Texel) verwenden, wenn es sich in der Nähe des Betrachters befindet. Wenn die Wand jedoch weiter vom Betrachter entfernt wird, bis sie als einzelnes Pixel auf dem Bildschirm erscheint, können sich die gefilterten Texturen an bestimmten Übergangspunkten abrupt ändern.

    Um solche Artefakte zu vermeiden, können Sie eine Reihe vorgefilterter Textur-Maps mit abnehmender Auflösung, sogenannte Mipmaps, angeben, wie in Abbildung 9-4 gezeigt. Der Begriff Mipmap wurde von Lance Williams geprägt, als er die Idee in seiner Arbeit „Pyramidal Parametrics“ (SIGGRAPH 1983 Proceedings) vorstellte. Mip steht für das lateinische multim im parvo und bedeutet „viele Dinge auf kleinem Raum“. Mipmapping verwendet einige clevere Methoden, um Bilddaten in den Speicher zu packen.

    Bei der Verwendung von Mipmapping bestimmt OpenGL automatisch, welche Textur-Map basierend auf der Größe (in Pixel) des gemappten Objekts verwendet werden soll. Bei diesem Ansatz ist der Detaillierungsgrad der Textur-Map für das auf dem Bildschirm gezeichnete Bild angemessen - wenn das Bild des Objekts kleiner wird, nimmt die Größe der Textur-Map ab. Mipmapping erfordert jedoch etwas zusätzlichen Rechen- und Texturspeicherbereich. Wenn es jedoch nicht verwendet wird, können Texturen, die auf kleinere Objekte abgebildet werden, schimmern und blinken, wenn sich die Objekte bewegen.

    Um Mipmapping zu verwenden, müssen Sie alle Größen Ihrer Textur in Zweierpotenzen zwischen der größten Größe und einer 1 ´ 1 Map bereitstellen. Wenn Ihre Karte beispielsweise mit der höchsten Auflösung 64 ´ 16 ist, müssen Sie auch Karten der Größe 32 ´ 8, 16 ´ 4, 8 ´ 2, 4 ´ 1, 2 &# 180 1 und 1 ´ 1. Die kleineren Maps sind typischerweise gefilterte und gemittelte Versionen der größten Map, in der jedes Texel in einer kleineren Textur ein Durchschnitt der entsprechenden vier Texel in der größeren Textur ist. (Da OpenGL keine besondere Methode zum Berechnen der kleineren Maps erfordert, könnten die unterschiedlich großen Texturen völlig unabhängig sein. In der Praxis würden nicht verwandte Texturen die Übergänge zwischen Mipmaps extrem auffällig machen.)

    Um diese Texturen anzugeben, rufen Sie glTexImage2D() einmal für jede Auflösung der Textur-Map mit unterschiedlichen Werten für die Parameter level , width , height und image auf. Beginnend mit Null identifiziert level, welche Textur in der Reihe mit dem vorherigen Beispiel angegeben ist, die größte Textur der Größe 64 ´ 16 würde mit level = 0 deklariert, die 32 ´ 8 Textur mit level = 1 und so an. Damit die Mipmap-Texturen wirksam werden, müssen Sie außerdem eine der geeigneten Filtermethoden auswählen, die im nächsten Abschnitt beschrieben werden.

    Beispiel 9-4 veranschaulicht die Verwendung einer Reihe von sechs Textur-Maps, die von 32 ´ 32 auf 1 ´ 1 abnehmen. Dieses Programm zeichnet ein Rechteck, das sich vom Vordergrund weit in die Ferne erstreckt und schließlich bei a . verschwindet Punkt, wie in "Platte 20" in Anhang I gezeigt. Beachten Sie, dass die Texturkoordinaten von 0,0 bis 8,0 reichen, sodass 64 Kopien der Texturabbildung erforderlich sind, um das Rechteck zu kacheln, acht in jede Richtung. Um zu veranschaulichen, wie eine Textur-Map auf eine andere ab folgt, hat jede Map eine andere Farbe.

    Beispiel 9-4: Mipmap-Texturen: mipmap.c

    Beispiel 9-4 veranschaulicht Mipmapping, indem es jeder Mipmap eine andere Farbe gibt, damit es offensichtlich ist, wenn eine Map durch eine andere ersetzt wird. In einer realen Situation definieren Sie Mipmaps, damit der Übergang so reibungslos wie möglich verläuft.Daher sind die Karten mit niedrigerer Auflösung normalerweise gefilterte Versionen einer ursprünglichen, hochauflösenden Karte. Die Erstellung einer Reihe solcher Mipmaps ist ein Softwareprozess und daher nicht Teil von OpenGL, das einfach eine Rendering-Bibliothek ist. Da die Mipmap-Konstruktion jedoch eine so wichtige Operation ist, enthält die OpenGL Utility Library zwei Routinen, die bei der Manipulation von Bildern helfen, die als Mipmap-Texturen verwendet werden sollen.

    Angenommen, Sie haben die Ebene 0 oder die Karte mit der höchsten Auflösung konstruiert, die Routinen gluBuild1DMipmaps() und gluBuild2DMipmaps() konstruieren und definieren die Pyramide von Mipmaps bis zu einer Auflösung von 1 ´ 1 (oder 1, für eindimensionale Texturkarten .). ). Wenn Ihr Originalbild Abmessungen hat, die keine exakten Zweierpotenzen sind, skaliert gluBuild*DMipmaps() das Bild hilfreicherweise auf die nächste Zweierpotenz.

    int gluBuild1DMipmaps (GLenum-Ziel , GLint-Komponenten , GLint-Breite ,
    GLenum-Format, GLenum-Typ, void * data)
    int gluBuild2DMipmaps (GLenum-Ziel , GLint-Komponenten , GLint-Breite ,
    GLint Höhe , GLenum Format , GLenum Typ ,
    void * data ) Konstruiert eine Reihe von Mipmaps und ruft glTexImage*D() auf, um die Bilder zu laden. Die Parameter für Ziel , Komponenten , Breite , Höhe , Format , Typ und Daten sind genau die gleichen wie für glTexImage1D() und glTexImage2D() . Ein Wert von 0 wird zurückgegeben, wenn alle Mipmaps erfolgreich erstellt wurden, andernfalls wird ein GLU-Fehlercode zurückgegeben.

    Filtern

    Texturabbildungen sind quadratisch oder rechteckig, aber nachdem sie auf ein Polygon oder eine Oberfläche abgebildet und in Bildschirmkoordinaten umgewandelt wurden, entsprechen die einzelnen Texel einer Textur selten einzelnen Pixeln des endgültigen Bildschirmbildes. Abhängig von den verwendeten Transformationen und dem angewendeten Textur-Mapping kann ein einzelnes Pixel auf dem Bildschirm einem winzigen Teil eines Texels (Vergrößerung) bis hin zu einer großen Sammlung von Texeln (Verkleinerung) entsprechen, wie in Abbildung 9-5 gezeigt. In beiden Fällen ist unklar, welche Texelwerte genau verwendet und wie sie gemittelt oder interpoliert werden sollen. Folglich können Sie mit OpenGL eine von mehreren Filteroptionen angeben, um diese Berechnungen zu bestimmen. Die Optionen bieten verschiedene Kompromisse zwischen Geschwindigkeit und Bildqualität. Außerdem können Sie die Filtermethoden für Vergrößerung und Verkleinerung unabhängig festlegen.

    Abbildung 9-5: Texturvergrößerung und -verkleinerung

    In manchen Fällen ist nicht ersichtlich, ob eine Vergrößerung oder eine Verkleinerung erforderlich ist. Wenn die Mipmap sowohl in x- als auch in y-Richtung gedehnt (oder verkleinert) werden muss, ist eine Vergrößerung (oder Verkleinerung) erforderlich. Wenn die Mipmap in eine Richtung gestreckt und in die andere verkleinert werden muss, wählt OpenGL zwischen Vergrößerung und Verkleinerung, die in den meisten Fällen das bestmögliche Ergebnis liefert. Versuchen Sie am besten, diese Situationen zu vermeiden, indem Sie Texturkoordinaten verwenden, die ohne solche Verzerrungen abgebildet werden. (Siehe "Berechnen geeigneter Texturkoordinaten".)

    Die folgenden Zeilen sind Beispiele für die Verwendung von glTexParameter*(), um die Filtermethoden für Vergrößerung und Verkleinerung anzugeben:

    Das erste Argument von glTexParameter*() ist entweder GL_TEXTURE_2D oder GL_TEXTURE_1D, je nachdem, ob Sie mit zwei- oder eindimensionalen Texturen arbeiten. Für diese Diskussion ist das zweite Argument entweder GL_TEXTURE_MAG_FILTER oder GL_TEXTURE_MIN_FILTER, um anzugeben, ob Sie die Filtermethode für Vergrößerung oder Verkleinerung angeben. Das dritte Argument gibt die Filtermethode an. Tabelle 9-1 listet die möglichen Werte auf.

    Tabelle 9-1: Filtermethoden für Vergrößerung und Verkleinerung

    GL_NEAREST, GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_NEAREST oder GL_LINEAR_MIPMAP_LINEAR

    Wenn Sie GL_NEAREST wählen, wird das Texel mit den Koordinaten am nächsten zum Mittelpunkt des Pixels sowohl für die Vergrößerung als auch für die Verkleinerung verwendet. Dies kann zu Aliasing-Artefakten führen (manchmal schwerwiegend). Wenn Sie GL_LINEAR wählen, wird ein gewichteter linearer Durchschnitt des 2 ´ 2 Arrays von Texeln verwendet, die der Mitte des Pixels am nächsten liegen, wiederum sowohl für die Vergrößerung als auch für die Verkleinerung. Wenn sich die Texturkoordinaten in der Nähe des Randes der Texturmap befinden, kann das nächste 2 ´ 2 Array von Texeln einige enthalten, die außerhalb der Texturmap liegen. In diesen Fällen hängen die verwendeten Texelwerte davon ab, ob GL_REPEAT oder GL_CLAMP aktiv ist und ob Sie der Textur einen Rahmen zugewiesen haben. (Siehe "Verwenden der Grenzen einer Textur".) GL_NEAREST erfordert weniger Berechnungen als GL_LINEAR und kann daher schneller ausgeführt werden, aber GL_LINEAR liefert glattere Ergebnisse.

    Bei der Vergrößerung wird, auch wenn Sie Mipmaps bereitgestellt haben, immer die größte Texturmap ( level = 0) verwendet. Bei der Verkleinerung können Sie eine Filtermethode auswählen, die die am besten geeignete ein oder zwei Mipmaps verwendet, wie im nächsten Absatz beschrieben. (Wenn GL_NEAREST oder GL_LINEAR mit Verkleinerung angegeben wird, wird die größte Textur-Map verwendet.)

    Wie in Tabelle 9-1 gezeigt, stehen beim Minimieren mit Mipmaps vier zusätzliche Filteroptionen zur Verfügung. Innerhalb einer einzelnen Mipmap können Sie mit GL_NEAREST_MIPMAP_NEAREST den nächstgelegenen Texelwert wählen oder durch Angabe von GL_LINEAR_MIPMAP_NEAREST linear interpolieren. Die Verwendung der nächsten Texel ist schneller, führt jedoch zu weniger wünschenswerten Ergebnissen. Die bestimmte ausgewählte Mipmap ist eine Funktion des erforderlichen Minifizierungsumfangs, und es gibt einen Grenzpunkt von der Verwendung einer bestimmten Mipmap zur nächsten. Um einen plötzlichen Übergang zu vermeiden, verwenden Sie GL_NEAREST_MIPMAP_LINEAR oder GL_LINEAR_MIPMAP_LINEAR, um Texelwerte aus den beiden nächstbesten Mipmap-Auswahlmöglichkeiten linear zu interpolieren. GL_NEAREST_MIPMAP_LINEAR wählt das nächste Texel in jeder der beiden Abbildungen aus und interpoliert dann linear zwischen diesen beiden Werten. GL_LINEAR_MIPMAP_LINEAR verwendet die lineare Interpolation, um den Wert in jeder von zwei Karten zu berechnen, und interpoliert dann linear zwischen diesen beiden Werten. Wie zu erwarten, liefert GL_LINEAR_MIPMAP_LINEAR im Allgemeinen die glattesten Ergebnisse, erfordert jedoch die meisten Berechnungen und ist daher möglicherweise am langsamsten.

    Texturobjekte

    Texturobjekte sind ein wichtiges neues Feature in Release 1.1 von OpenGL. Ein Texturobjekt speichert Texturdaten und macht sie leicht verfügbar. Sie können jetzt viele Texturen steuern und zu Texturen zurückkehren, die zuvor in Ihre Texturressourcen geladen wurden. Die Verwendung von Texturobjekten ist normalerweise der schnellste Weg, um Texturen anzuwenden, was zu großen Leistungssteigerungen führt, da es fast immer viel schneller ist, ein vorhandenes Texturobjekt zu binden (wiederzuverwenden), als ein Texturbild mit glTexImage*D() neu zu laden.

    Außerdem unterstützen einige Implementierungen einen begrenzten Arbeitssatz von Hochleistungstexturen. Sie können Texturobjekte verwenden, um Ihre am häufigsten verwendeten Texturen in diesen begrenzten Bereich zu laden.

    Gehen Sie wie folgt vor, um Texturobjekte für Ihre Texturdaten zu verwenden.

    Binden (erstellen) Sie zunächst Texturobjekte an Texturdaten, einschließlich der Bildarrays und Textureigenschaften.

    Wenn Ihre Implementierung einen Arbeitssatz von Hochleistungstexturen unterstützt, prüfen Sie, ob Sie genügend Platz für alle Ihre Texturobjekte haben. Wenn nicht genügend Platz vorhanden ist, können Sie für jedes Texturobjekt Prioritäten festlegen, damit häufiger verwendete Texturen im Arbeitssatz bleiben.

    Binden Sie Texturobjekte und binden Sie sie erneut, um deren Daten aktuell für das Rendern texturierter Modelle verfügbar zu machen.

    Benennen eines Texturobjekts

    Als Texturname kann jede beliebige ganze Zahl ohne Vorzeichen verwendet werden. Um eine versehentliche Wiederverwendung von Namen zu vermeiden, verwenden Sie konsequent glGenTextures(), um nicht verwendete Texturnamen bereitzustellen.

    void glGenTextures (GLsizei n , GLuint *textureNames ) Gibt n derzeit nicht verwendete Namen für Texturobjekte im Array textureNames zurück. Die in textureNames zurückgegebenen Namen müssen keine zusammenhängenden Ganzzahlen sein. Die Namen in textureNames werden als verwendet markiert, aber sie erhalten Texturzustand und Dimensionalität (1D oder 2D) nur, wenn sie zum ersten Mal gebunden werden. Zero ist ein reservierter Texturname und wird von glGenTextures() nie als Texturname zurückgegeben.

    glIsTexture() bestimmt, ob ein Texturname tatsächlich verwendet wird. Wenn ein Texturname von glGenTextures() zurückgegeben wurde, aber noch nicht gebunden wurde (indem glBindTexture() mindestens einmal mit dem Namen aufgerufen wird), dann gibt glIsTexture() GL_FALSE zurück.

    GLboolean glIsTexture (GLuint textureName ) Gibt GL_TRUE zurück, wenn textureName der Name einer gebundenen und anschließend nicht gelöschten Textur ist. Gibt GL_FALSE zurück, wenn textureName null ist oder textureName ein Wert ungleich null ist, der nicht der Name einer vorhandenen Textur ist.

    Erstellen und Verwenden von Texturobjekten

    Dieselbe Routine, glBindTexture() , erstellt und verwendet Texturobjekte. Wenn ein Texturname anfänglich gebunden wird (verwendet mit glBindTexture() ), wird ein neues Texturobjekt mit Standardwerten für das Texturbild und die Textureigenschaften erstellt. Nachfolgende Aufrufe von glTexImage*() , glTexSubImage*() , glCopyTexImage*() , glCopyTexSubImage*() , glTexParameter*() und glPrioritizeTextures() speichern Daten im Texturobjekt. Das Texturobjekt kann ein Texturbild und zugehörige Mipmap-Bilder (falls vorhanden) enthalten, einschließlich zugehöriger Daten wie Breite, Höhe, Rahmenbreite, internes Format, Auflösung von Komponenten und Textureigenschaften. Zu den gespeicherten Textureigenschaften gehören Verkleinerungs- und Vergrößerungsfilter, Umbruchmodi, Rahmenfarbe und Texturpriorität.

    Wenn ein Texturobjekt anschließend erneut gebunden wird, werden seine Daten zum aktuellen Texturzustand. (Der Zustand der zuvor gebundenen Textur wird ersetzt.)

    void glBindTexture (GLenum target , GLuint textureName ) glBindTexture() macht drei Dinge. Wenn Sie textureName zum ersten Mal mit einer vorzeichenlosen Ganzzahl ungleich Null verwenden, wird ein neues Texturobjekt erstellt und diesem Namen zugewiesen. Beim Binden an ein zuvor erstelltes Texturobjekt wird dieses Texturobjekt aktiv. Beim Binden an einen textureName-Wert von Null beendet OpenGL die Verwendung von Texturobjekten und kehrt zur unbenannten Standardtextur zurück. Wenn ein Texturobjekt anfänglich gebunden (dh erzeugt) wird, nimmt es die Dimensionalität des Ziels an, die entweder GL_TEXTURE_1D oder GL_TEXTURE_2D ist. Unmittelbar nach seiner anfänglichen Bindung entspricht der Zustand des Texturobjekts dem Zustand der Vorgabe GL_TEXTURE_1D oder GL_TEXTURE_2D (je nach Dimensionalität) bei der Initialisierung von OpenGL. In diesem Ausgangszustand werden Textureigenschaften wie Verkleinerungs- und Vergrößerungsfilter, Umbruchmodi, Rahmenfarbe und Texturpriorität auf ihre Standardwerte gesetzt.

    In Beispiel 9-5 werden in init() zwei Texturobjekte erstellt. In display() wird jedes Texturobjekt verwendet, um ein anderes vierseitiges Polygon zu rendern.

    Beispiel 9-5: Binden von Texturobjekten: texbind.c

    Immer wenn ein Texturobjekt erneut gebunden wird, können Sie den Inhalt des gebundenen Texturobjekts bearbeiten. Alle Befehle, die Sie aufrufen, die das Texturbild oder andere Eigenschaften ändern, ändern den Inhalt des aktuell gebundenen Texturobjekts sowie den aktuellen Texturzustand.

    In Beispiel 9-5 sind Sie nach Beendigung von display() immer noch an die Textur gebunden, die durch den Inhalt von texName[1] benannt wird. Achten Sie darauf, dass Sie keine falsche Texturroutine aufrufen, die die Daten in diesem Texturobjekt ändert.

    Bei der Verwendung von Mipmaps müssen alle zugehörigen Mipmaps eines einzelnen Texturbildes in ein einzelnes Texturobjekt eingefügt werden. In Beispiel 9-4 werden die Ebenen 0,5 eines Mipmapped-Texturbilds in ein einzelnes Texturobjekt namens texName eingefügt.

    Bereinigen von Texturobjekten

    Wenn Sie Texturobjekte binden und aufheben, befinden sich ihre Daten immer noch irgendwo zwischen Ihren Texturressourcen. Wenn die Texturressourcen begrenzt sind, kann das Löschen von Texturen eine Möglichkeit sein, Ressourcen freizugeben.

    void glDeleteTextures (GLsizei n , const GLuint *textureNames ) Löscht n Texturobjekte, benannt nach Elementen im Array textureNames. Die freigegebenen Texturnamen können nun wiederverwendet werden (zB von glGenTextures() ). Wenn eine aktuell gebundene Textur gelöscht wird, wird die Bindung auf die Standardtextur zurückgesetzt, als ob glBindTexture() mit Null für den Wert von textureName aufgerufen würde. Versuche, nicht vorhandene Texturnamen oder den Texturnamen Null zu löschen, werden ignoriert, ohne einen Fehler zu generieren.

    Ein funktionierender Satz residenter Texturen

    Einige OpenGL-Implementierungen unterstützen einen funktionierenden Satz von Hochleistungstexturen, die als resident bezeichnet werden. Typischerweise haben diese Implementierungen spezialisierte Hardware zum Durchführen von Texturoperationen und einen begrenzten Hardware-Cache zum Speichern von Texturbildern. In diesem Fall empfiehlt sich die Verwendung von Texturobjekten, da Sie viele Texturen in das Arbeitsset laden und dann steuern können.

    Wenn alle von der Anwendung benötigten Texturen die Größe des Caches überschreiten, können einige Texturen nicht resident sein. Wenn Sie herausfinden möchten, ob eine einzelne Textur derzeit resident ist, binden Sie ihr Objekt und verwenden Sie dann glGetTexParameter*v(), um den mit dem Zustand GL_TEXTURE_RESIDENT verknüpften Wert herauszufinden. Wenn Sie den Textur-Residence-Status vieler Texturen wissen möchten, verwenden Sie glAreTexturesResident() .

    GLboolean glAreTexturesResident (GLsizei n , const
    GLuint *textureNames , GLboolean *residences ) Fragt den Textur-Residence-Status der n Textur-Objekte ab, die im Array textureNames benannt sind. Residences ist ein Array, in dem der Textur-Residence-Status für die entsprechenden Texturobjekte im Array textureNames zurückgegeben wird. Wenn alle benannten Texturen in textureNames resident sind, gibt die Funktion glAreTexturesResident() GL_TRUE zurück und der Inhalt der Array-Residenzen bleibt ungestört. Wenn eine Textur in textureNames nicht resident ist, dann gibt glAreTexturesResident() GL_FALSE zurück und die Elemente in Residenzen, die nicht-residenten Texturobjekten in textureNames entsprechen, werden ebenfalls auf GL_FALSE gesetzt.

    Beachten Sie, dass glAreTexturesResident() den aktuellen Aufenthaltsstatus zurückgibt. Texturressourcen sind sehr dynamisch und der Status des Texturwohnsitzes kann sich jederzeit ändern. Einige Implementierungen cachen Texturen, wenn sie zum ersten Mal verwendet werden. Es kann erforderlich sein, mit der Textur zu zeichnen, bevor Sie die Residenz überprüfen.

    Wenn Ihre OpenGL-Implementierung keinen funktionierenden Satz von Hochleistungstexturen erstellt, werden die Texturobjekte immer als resident betrachtet. In diesem Fall gibt glAreTexturesResident() immer GL_TRUE zurück und liefert grundsätzlich keine Informationen.

    Texture-Residence-Strategien

    Wenn Sie einen funktionierenden Satz von Texturen erstellen können und die bestmögliche Texturleistung erzielen möchten, müssen Sie die Besonderheiten Ihrer Implementierung und Anwendung wirklich kennen. Bei einer visuellen Simulation oder einem Videospiel müssen Sie beispielsweise die Leistung in allen Situationen aufrechterhalten. In diesem Fall sollten Sie niemals auf eine nicht residente Textur zugreifen. Für diese Anwendungen möchten Sie alle Ihre Texturen bei der Initialisierung laden und sie alle resident machen. Wenn Sie nicht genügend Texturspeicher zur Verfügung haben, müssen Sie möglicherweise die Größe, Auflösung und Ebenen der Mipmaps für Ihre Texturbilder reduzieren, oder Sie können glTexSubImage*() verwenden, um denselben Texturspeicher wiederholt wiederzuverwenden.

    Für Anwendungen, die Texturen "on the fly" erstellen, sind nicht-residente Texturen möglicherweise unvermeidlich. Wenn einige Texturen häufiger verwendet werden als andere, können Sie diesen Texturobjekten eine höhere Priorität zuweisen, um ihre Wahrscheinlichkeit zu erhöhen, dass sie resident sind. Durch das Löschen von Texturobjekten wird auch Speicherplatz frei. Abgesehen davon kann die Zuweisung einer niedrigeren Priorität zu einem Texturobjekt dazu führen, dass es an erster Stelle steht, wenn es aus dem Arbeitssatz verschoben wird, da die Ressourcen schwinden. glPrioritizeTextures() wird verwendet, um Texturobjekten Prioritäten zuzuweisen.

    void glPrioritizeTextures (GLsizei n , const GLuint *textureNames ,
    const GLclamp *priorities ) Weist den n Texturobjekten, benannt im Array textureNames, die Textur-Residence-Prioritäten in den entsprechenden Elementen des Array-Prioritäten zu. Die Prioritätswerte in den Array-Prioritäten werden auf den Bereich [0.0, 1.0] begrenzt, bevor sie zugewiesen werden. Null zeigt die niedrigste Priorität an, die diese Texturen mit der geringsten Wahrscheinlichkeit resident sind. Einer zeigt die höchste Priorität an. glPrioritizeTextures() erfordert nicht, dass irgendeine der Texturen in textureNames gebunden ist. Die Priorität hat jedoch möglicherweise keine Auswirkung auf ein Texturobjekt, bis es anfänglich gebunden wird.

    glTexParameter*() kann auch verwendet werden, um die Priorität einer einzelnen Textur festzulegen, jedoch nur, wenn die Textur aktuell gebunden ist. Tatsächlich ist die Verwendung von glTexParameter*() die einzige Möglichkeit, die Priorität einer Standardtextur festzulegen.

    Wenn Texturobjekte die gleiche Priorität haben, wenden typische Implementierungen von OpenGL eine LRU-Strategie an, um zu entscheiden, welche Texturobjekte aus dem Arbeitssatz entfernt werden sollen. Wenn Sie wissen, dass Ihre OpenGL-Implementierung dieses Verhalten aufweist, dann schaffen gleiche Prioritäten für alle Texturobjekte ein vernünftiges LRU-System für die Neuzuweisung von Texturressourcen.

    Wenn Ihre OpenGL-Implementierung keine LRU-Strategie für Texturobjekte gleicher Priorität verwendet (oder Sie nicht wissen, wie sie sich entscheidet), können Sie Ihre eigene LRU-Strategie implementieren, indem Sie die Texturobjektprioritäten sorgfältig beibehalten. Wenn eine Textur verwendet (gebunden) wird, können Sie ihre Priorität maximieren, die ihre kürzliche Verwendung widerspiegelt. Dann können Sie in regelmäßigen (Zeit-)Intervallen die Prioritäten aller Texturobjekte herabsetzen.

    Hinweis: Die Fragmentierung des Texturspeichers kann ein Problem sein, insbesondere wenn Sie viele neue Texturen löschen und erstellen. Obwohl es sogar möglich ist, alle Texturobjekte in ein Arbeitsset zu laden, indem Sie sie in einer Sequenz binden, kann das Binden in eine andere Sequenz dazu führen, dass einige Texturen nicht resident bleiben.

    Texturfunktionen

    In allen bisherigen Beispielen in diesem Kapitel wurden die Werte in der Textur-Map direkt als Farben verwendet, die auf die zu rendernde Oberfläche gemalt werden. Sie können die Werte in der Textur-Map auch verwenden, um die Farbe zu modulieren, die die Oberfläche ohne Texturierung gerendert würde, oder um die Farbe in der Textur-Map mit der Originalfarbe der Oberfläche zu mischen. Sie wählen eine von vier Texturierungsfunktionen aus, indem Sie glTexEnv*() die entsprechenden Argumente übergeben.

    void glTexEnv (GLenum target , GLenum pname , TYPEparam )
    void glTexEnv v (GLenum target , GLenum pname , TYPE * param ) Legt die aktuelle Texturierungsfunktion fest. Ziel muss GL_TEXTURE_ENV sein. Wenn pname GL_TEXTURE_ENV_MODE ist, kann param GL_DECAL, GL_REPLACE, GL_MODULATE oder GL_BLEND sein, um anzugeben, wie Texturwerte mit den Farbwerten des verarbeiteten Fragments kombiniert werden sollen. Wenn pname GL_TEXTURE_ENV_COLOR ist, ist param ein Array von vier Gleitkommawerten, die R-, G-, B- und A-Komponenten darstellen. Diese Werte werden nur verwendet, wenn auch die Texturfunktion GL_BLEND angegeben wurde.

    Die Kombination der Texturierungsfunktion und des internen Basisformats bestimmt, wie die Texturen für jede Komponente der Textur angewendet werden. Die Texturierungsfunktion arbeitet mit ausgewählten Komponenten der Textur und den Farbwerten, die ohne Texturierung verwendet würden. (Beachten Sie, dass die Auswahl durchgeführt wird, nachdem die Pixel-Transfer-Funktion angewendet wurde.) Denken Sie daran, dass bei der Angabe Ihrer Textur-Map mit glTexImage*D() das dritte Argument das interne Format ist, das für jedes Texel ausgewählt werden soll.

    Tabelle 9-2 und Tabelle 9-3 zeigen, wie die Texturierungsfunktion und das interne Basisformat die Texturierungsanwendungsformel bestimmen, die für jede Komponente der Textur verwendet wird. Es gibt sechs interne Basisformate (die Buchstaben in Klammern stellen ihre Werte in den Tabellen dar): GL_ALPHA (A), GL_LUMINANCE (L), GL_LUMINANCE_ALPHA (L und A), GL_INTENSITY (I), GL_RGB (C) und GL_RGBA (C und ein). Andere interne Formate spezifizieren gewünschte Auflösungen der Texturkomponenten und können an eines dieser sechs internen Basisformate angepasst werden.


    Verfassen linearer Transformationen

    Seien und positive ganze Zahlen. Angenommen und seien Sie lineare Transformationen. Ist die Komposition auch eine lineare Transformation?

    Um das herauszufinden, nehmen Sie an und . Wir können die Definition der Linearität in Abschnitt 1.7, “Hochdimensionale Lineare Algebra” verwenden, um die folgende Berechnung durchzuführen. Beachten Sie die Bedeutung der Annahme, dass und beide in dieser Berechnung linear sind.

    Aber wie hängt diese Linearität mit den Matrixrepräsentanten dieser linearen Transformationen zusammen? Wir könnten beginnen, die Antwort auf diese Frage zu untersuchen, indem wir Beispiele in niedrigen Dimensionen betrachten.

    Bevor Sie dies tun, ist es wichtig, sich daran zu erinnern, dass wir haben bereits eine Matrix mal einen Vektor definiert in Abschnitt 1.7, “Hochdimensionale Lineare Algebra”. Genauer gesagt, wenn ist eine Matrix (Zeilen und Spalten) und ein -dimensionaler Vektor (eine Matrix), dann ist die Matrix-/Vektorprodukt wird ein -dimensionaler Vektor (eine Matrix) sein. Noch genauer gesagt, wird der -dimensionale Vektor sein, der als Linearkombination der Spalten von mit den Einträgen von als den entsprechenden Gewichten gebildet wird.

    In einer Formel, if , wobei die Spalten von sind, und if , dann:

    Matrixmultiplikation für eine Komposition

    Angenommen und sind lineare Transformationen. Dann gibt es Konstanten (Matrizen) und so und für alle.

    Die Zusammensetzung dieser Funktionen ist . Mit anderen Worten, die der Zusammensetzung entsprechende Matrix (Zahl) ist die Produkt der Matrizen (Zahlen), die jedem der “Faktoren” und von entsprechen.

    Dies führt uns dazu, das Produkt von Matrizen als eine andere Matrix zu definieren: . Die Matrixmultiplikation ist einfach, wenn die Matrizen . Einfach die Zahlen multiplizieren!

    Matrixmultiplikation für eine Komposition

    Angenommen und sind lineare Transformationen. Dann gibt es eine Matrix und eine Matrix mit für alle und für alle .

    Wir versuchen, das Matrixprodukt so zu definieren, dass für alle . Dies impliziert in dieser Situation notwendigerweise, dass das Produkt eine Matrix (eine Zahl) sein muss.

    Wenn und , können wir die folgenden Gleichungen schreiben.

    Die zusammengesetzte Funktion lautet daher:

    Beachten Sie, dass die endgültige Antwort dasselbe ist wie das folgende Matrixprodukt von Matrizen (Zahlen)

    Daher sollte das Matrixprodukt die folgende Matrix sein. Dies veranschaulicht, dass eine Matrix mal eine Matrix definiert werden kann und die Antwort eine Matrix ist.

    Da es sich tatsächlich um einen zweidimensionalen (Spalten-)Vektor handelt, haben wir diese Berechnung bereits zuvor durchgeführt! Die Antwort ist eine Linearkombination der Spalten von mit den Einträgen von als Gewichte.

    Matrixmultiplikation für eine Komposition

    Angenommen und sind lineare Transformationen. Dann gibt es eine Matrix und eine Matrix mit für alle und für alle .

    Wir versuchen, das Matrixprodukt so zu definieren, dass für alle . Dies impliziert in dieser Situation notwendigerweise, dass das Produkt eine Matrix sein muss.

    Wenn und , können wir die folgenden Gleichungen schreiben.

    Die zusammengesetzte Funktion lautet daher:

    Nach unserer vorherigen Definition der Matrix/Vektor-Multiplikation ist dies dasselbe, als würde man sagen, dass

    Um die Matrixmultiplikation einer Matrix mal einer Matrix zu definieren, sollten wir es daher wie unten gezeigt tun:

    Dies ist ein grundsätzlich Neu Art von Produkt von dem, was wir zuvor gemacht haben. Beachten Sie jedoch, dass es wie folgt geschrieben werden kann, wobei jede Spalte der Antwort ein zweidimensionaler Vektor ist, der durch die Matrix mal eine Spalte von gebildet wird.

    Dieses Muster funktioniert im allgemeinen Fall, den wir in Kürze spezifizieren werden.

    Matrixmultiplikation für eine Komposition

    Ein weiteres Beispiel in niedrigen Dimensionen wird betrachtet, bevor wir den allgemeinen Fall diskutieren.

    Angenommen und sind lineare Transformationen. Dann gibt es eine Matrix und eine Matrix mit für alle und für alle .

    Auch hier versuchen wir das Matrixprodukt so zu definieren, dass für alle . Dies impliziert in dieser Situation notwendigerweise, dass das Produkt eine Matrix sein muss.

    Wenn und , können wir die folgenden Gleichungen schreiben.

    Die zusammengesetzte Funktion lautet daher:

    Nach unserer Definition der Matrix-/Vektormultiplikation ist dies dasselbe wie

    Daher definieren wir die Matrixmultiplikation zweier Matrizen als dieselbe Matrix wie in der vorherigen Zeile. Speziell,

    Beachten Sie, dass wenn und die Spalten von sind, dann

    Dies ist wiederum das Muster, das wir im allgemeinen Fall sehen werden.

    Matrixmultiplikation für den allgemeinen Fall

    Die Argumentation im allgemeinen Fall ist wahrscheinlich interessanter und aufschlussreicher, obwohl es intensive Konzentration erfordert, um sie vollständig zu verstehen.

    Angenommen und sind lineare Transformationen. Dann gibt es eine Matrix und eine Matrix mit für alle und für alle .

    Auch hier versuchen wir das Matrixprodukt so zu definieren, dass für alle . Dies impliziert in dieser Situation notwendigerweise, dass das Produkt eine Matrix sein muss.

    Angenommen, wo jeder, und angenommen.

    Da linear und ist, können wir auch sagen:

    Dies ist aber eine Linearkombination der -dimensionalen Vektoren mit den Einträgen von als Gewichte!

    Wenn dies gleich ist, sollten wir das Matrixprodukt als die folgende Matrix definieren:

    Dies ist tatsächlich das, was wir tun.

    Alternativer Ansatz mit Dot-Produkten

    Dies bedeutet natürlich, dass jede Spalte von eine Linearkombination der Spalten von mit Einträgen aus der entsprechenden Spalte von als die entsprechenden Gewichtungen ist.

    Um genauer zu sein, lassen Sie , wobei jede Spalte ein Vektor in ist. Außerdem sei die Spalte von , für . Dann ist die Spalte von is

    Sei der Eintrag in der Zeile und Spalte des Produkts (mit und ). Außerdem sei für die Spalte von .

    Was wir getan haben, zeigt auch, dass für und ,

    Das ist sehr erwähnenswert ist ein Punktprodukt. Es ist ein Punktprodukt der Spalte von mit die Zeile von (was wir uns sicherlich als Vektor vorstellen können).

    Diese Beschreibung der Einträge von as-dot-Produkten ist eigentlich ein schnellerer Weg, um . Als Definition ist sie jedoch weniger aussagekräftig.

    Unser Ansatz mit linearen Transformationen bringt die wahre Bedeutung der Matrixmultiplikation auf den Punkt: sie sollte in direktem Zusammenhang mit zusammengesetzten linearen Transformationen stehen.

    Die Dimensionen der Matrixfaktoren des Produkts

    Es ist wichtig zu beachten, dass das Produkt einer Matrix (links) mal einer Matrix (rechts) erstellt werden kann und dass die Antwort eine Matrix ist.

    Das ist, die Anzahl der Spalten von muss mit der Anzahl der Zeilen von übereinstimmen. Weiter, die endgültige Antwort hat die gleiche Anzahl von Zeilen wie und die gleiche Anzahl von Spalten wie.

    Aus diesem Grund sollten Sie sich auch bewusst sein, dass dies, nur weil das Produkt berechnet werden kann, dies tut nicht bedeutet, dass das Umkehrprodukt berechnet werden kann.

    Wenn ist und ist, kann das Umkehrprodukt genau dann berechnet werden, wenn. Aber auch in dieser Situation ist es in der Regel so, dass . Dies spiegelt die Tatsache wider, dass auch die Funktionszusammensetzung im Allgemeinen nicht kommutativ ist.

    Die assoziative Eigenschaft der Matrixmultiplikation

    Bevor wir Beispiele betrachten, ist es wert zu betonen, dass die Matrixmultiplikation die assoziative Eigenschaft erfüllt. Dies spiegelt die Tatsache wider, dass die Funktionszusammensetzung assoziativ ist.

    Angenommen , , und sind alle lineare Transformationen. Dann ist die Gleichung leicht zu überprüfen.

    Gegeben ein beliebiges , haben wir

    Wenn , , und für geeignet bemessene Matrizen und variable Vektoren gilt die Gleichung ebenfalls.

    Die assoziative Eigenschaft verallgemeinert sich auf jedes Matrixprodukt mit einer endlichen Anzahl von Faktoren. Es impliziert auch, dass solche Produkte ohne Klammern geschrieben werden können.

    Beispiel 1

    Wir betrachten zunächst ein rein rechnerisches hochdimensionales Beispiel. Nach diesem Punkt betrachten wir niedrigdimensionale Beispiele, die visualisiert werden können.

    Definieren Sie und durch die folgenden Formeln.

    Dann ist definiert durch , wobei .

    Berechnen Sie nun jede Spalte einzeln. Wir machen die erste Spalte.

    Sie sollten sich auf jeden Fall die Zeit nehmen, um zu überprüfen, ob das endgültige Matrixprodukt

    Wir können dies auch überprüfen, indem wir das Punktprodukt wie oben beschrieben verwenden.

    Betrachten Sie beispielsweise den Eintrag in der dritten Zeile und zweiten Spalte des Produkts . Die dritte Zeile ist , die zweite Spalte ist . Das Skalarprodukt dieser beiden Vektoren ist .

    Daher lautet die endgültige Formel für die zusammengesetzte lineare Transformation

    Da wir nun die Matrix für die Komposition kennen, können wir natürlich elementare Zeilenoperationen verwenden, um beispielsweise ihren Kernel (Nullraum) zu bestimmen.

    Als Übung sollten Sie sich die Zeit nehmen zu zeigen, dass die Augmented Matrix für das System auf die gezeigte Reduced Row Echelon Form (RREF) reduziert werden kann.

    Daher sind und freie Variablen und der Kernel (Nullraum) ist eine zweidimensionale Ebene durch den Ursprung im fünfdimensionalen Raum.

    Beispiel 2

    Die nächsten beiden Beispiele sind zweidimensional, damit wir sie leicht visualisieren können. Zur Überprüfung von Abschnitt 1.4, “Lineare Transformationen in zwei Dimensionen”, betonen wir die Visualisierung einer linearen Transformation sowohl als Abbildung als auch als Vektorfeld.

    Was passiert, wenn wir zum Beispiel eine Rotation und eine Scherung zusammensetzen?

    Das erforschen wir jetzt. Wir werden für die Transformationsnamen einen anderen Buchstabensatz verwenden, um Verwechslungen mit ihren geometrischen Effekten zu vermeiden.

    Angenommen und definiert durch

    Dann folgt die Schertransformation, die in Abschnitt 1.4, “Lineare Transformationen in zwei Dimensionen” diskutiert wird, und ist eine Rotationstransformation gegen den Uhrzeigersinn um den Ursprung um .

    Das Matrixprodukt definiert die Formel für die zusammengesetzte Transformation. Andererseits definiert das Matrixprodukt die Formel für die zusammengesetzte Transformation.

    Lassen Sie uns Formeln für beide Funktionen berechnen. Wir werden die äquivalente Punktproduktformulierung der Matrixmultiplikation verwenden.

    Damit die umgekehrte Komposition mit dem übereinstimmt, was wir bisher gemacht haben, verwenden wir ja‘s für die Variablennamen. Lassen Sie sich davon nicht stören. Wir hätten es gebrauchen können x‘s.

    Diese beiden Transformationen sind in der Tat unterschiedlich. Das ist, . Dies sollte erwartet werden. Die Funktionszusammensetzung ist nicht kommutativ.

    Die Matrixmultiplikation ist auch nicht kommutativ, selbst wenn beide und berechnet werden können.

    Visualisieren der Kompositionen als Mappings

    Lassen sich die geometrischen Effekte dieser Kompositionen leicht visualisieren? Ja, aber es sind keine “einfachen” Visualisierungen. Grundsätzlich ist es am besten, ihre geometrischen Effekte in der Reihenfolge ihres Auftretens zu betrachten.

    Hier ist ein Bild, das zeigt, wie sich diese beiden unterschiedlichen Kompositionen jeweils auf die Schmetterlingskurve aus Abschnitt 1.4, “Lineare Transformationen in zwei Dimensionen” auswirken. In jedem Fall stellt der Anfangsschmetterling (rot) eine Menge von Punkten dar, die unter der zusammengesetzten Abbildung in den Endschmetterling (blau) umgewandelt werden. Der Endschmetterling ist das Bild der zusammengesetzten Karte (links) bzw. (rechts).

    Visualisierung der Kompositionen als Vektorfelder

    Denken Sie daran, dass eine Vektorfelddarstellung einer linearen Transformation jeden Punkt als Eingabe verwendet und den Ausgabevektor als Pfeil an diesen Punkt anhängt.

    Als statische Bilder sind diese Vektorfelder unten dargestellt.

    Wir können dies auch animieren, um den Zusammenhang mit der Mapping-Ansicht der linearen Transformation zu sehen. Wir können das “scheren” und das“rotieren” in jedem Fall sehen, wenn wir uns vorstellen, jeden Vektor im Vektorfeld aus dem “identity” Vektorfeld zu transformieren.

    In jedem Fall ist das Start-(Identitäts-)Vektorfeld rot, das Zwischenvektorfeld ist lila und das letzte Vektorfeld ist blau.

    Beispiel 3

    Für unser letztes Beispiel betrachten wir die Zusammensetzung zweier Reflexionen. Eine Transformation ist eine Spiegelung entlang der horizontalen Achse. Die andere Transformation ist eine Spiegelung über die diagonale Linie durch den Ursprung.

    Wir nennen diese Reflexionen und (“h” für horizontal und “D” für Diagonale). Wir schreiben auch und für einige Matrizen und und .

    Die Formel für basierend auf dem Matrixprodukt lautet:

    Und die Formel für basierend auf dem Matrixprodukt lautet:

    Visualisierungen

    Seien Sie willkürlich. Beachten Sie, dass . Andererseits können wir das sagen. Dies ist eine ganz besondere Eigenschaft.

    Wir sollten das sehen reflektiert in unseren Animationen (Wortspiel beabsichtigt).

    Hier sind die statischen Vektorfelder.

    Und hier sind die Animationen des Identitätsvektorfeldes, das in jedes dieser Vektorfelder umgewandelt wird. Beachten Sie, wie die Startvektoren (rot) in den Zwischenzustand (lila) gespiegelt werden, bevor sie zum Endzustand (blau) übergehen.


    Verweise

    Zeileis A (2006), Objektorientierte Berechnung von Sandwichschätzern. Zeitschrift für Statistiksoftware, 16(9), 1-16. URL https://www.jstatsoft.org/v16/i09/.

    Pierre Chausse (2010), Computing Generalized Method of Moments and Generalized Empirical Likelihood with R. Zeitschrift für Statistiksoftware, 34(11), 1--35. URL https://www.jstatsoft.org/v34/i11/.

    Andrews DWK (1991), Heteroskedastizität und Autokorrelationskonsistente Kovarianzmatrixschätzung. Ökonometrie, 59, 817--858.

    Newey WK & West KD (1987), A Simple, Positive Semi-Definite, Heteroskedasticity and Autocorrelation Consistent Covariance Matrix. Ökonometrie, 55, 703--708.

    Newey WK & West KD (1994), Automatic Lag Selection in Covariance Matrix Estimation. Rückblick Wirtschaftswissenschaften, 61, 631-653.


    Schau das Video: 27 - Matice zobrazení MAT - Lineární algebra (Oktober 2021).