• Keine Ergebnisse gefunden

Vorlesung„Computergraphik I“S. Müller (7) Scan-Konvertierung

N/A
N/A
Protected

Academic year: 2022

Aktie "Vorlesung„Computergraphik I“S. Müller (7) Scan-Konvertierung"

Copied!
44
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

U N I V E R S I T Ä T KOBLENZ · LANDAU

(7) Scan-Konvertierung

Vorlesung

„Computergraphik I“

S. Müller

(2)

U N I V E R S I T Ä T

Wdh I: Sutherland-Hodgman

A

B A

B

A B

A

B

Beide Punkte drinnen:

Output B

Annahme: der Startpunkt A wurde bereits behandelt

Linie „zeigt“ nach außen:

Output S

Linie „zeigt“ nach innen:

Output S, B

Beide Punkte draußen:

Output (nichts)

S

S

(3)

U N I V E R S I T Ä T KOBLENZ · LANDAU

Wdh. II

Der Polygonzug wird der Reihe nach an den Clip-Kanten geschnitten.

(4)

U N I V E R S I T Ä T

Wiederhol. III: Sutherland-Hodgman

 Diese Routine wird der Reihe nach für jede Clip-Kante

aufgerufen.

 „Innerhalb/Außerhalb“: hier wird wieder die Normale auf die

Kante berechnet und mit Hilfe des Vorzeichens des

Skalarproduktes entschieden.

 „Output“: stellt ein neues

Polygon zusammen, das am Ende zurückgegeben wird.

 „Schnittpunkt“ berechnet den Schnittpunkt mit der Clipkante, wobei nur Punkte zw. A und B berechnet werden dürfen.

Polygon SutherlandHodgman(Polygon poly, Edge clipedge)

{

A ist letzter Punkt des Polygons;

Schleife über alle Ecken B des Polygons

{

Wenn B innerhalb von clipedge Wenn A innerhalb von clipedge Output (B);

else {

S = Schnittpunkt (A,B,edge);

Output(S), Output(B);

} else

Wenn A innerhalb von clipedge {

S = Schnittpunkt (A,B,edge);

Output(S);

} A = B;

}

Ergebnis von Output zurückgeben.

(5)

U N I V E R S I T Ä T KOBLENZ · LANDAU

Wdh. IV

 Clipping eines Polygonzugs gegen ein konvexes Clip- Polygon (z.B. Bildschirm); der Polygonzug darf konkav sein.

 Problem: unnötige Kanten können am Rand

entstehen, was nicht unbedingt zu Fehlern führt; aus Effizienzgründen können diese nachträglich gelöscht werden.

 Lässt sich sehr gut als Pipeline in Hardware umsetzen.

 Erweiterung für konkave Clip-Polygone:

 Weiler-Atherton

(6)

U N I V E R S I T Ä T

Beispielprogramm mit Mauseingabe

#include "Vector2D.h"

#include "Polygon2D.h"

#include <GL/glut.h>

#define BREITE 520

#define HOEHE 520 Polygon2D poly;

void display( void) {

glClear (GL_COLOR_BUFFER_BIT);

glColor3f( 0.0, 0.0, 1.0);

poly.draw();

glFlush ();

}

void init( void) {

glClearColor (1.0, 1.0, 1.0, 0.0);

glOrtho(0, BREITE, 0, HOEHE, -1, 1);

}

void mouse( int button, int state, int x, int y)

{

s. letzte Folie }

int main(int argc, char** argv) {

glutInit(&argc, argv);

glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);

glutInitWindowSize( BREITE, HOEHE);

glutInitWindowPosition (100, 100);

glutCreateWindow („Polygoneingabe");

init ();

glutMouseFunc(mouse);

glutDisplayFunc(display);

glutMainLoop();

return 0;

}

Poly_input.vcproj

(7)

U N I V E R S I T Ä T KOBLENZ · LANDAU

Kleiner Test…

 Cohen-Sutherland Clipping:

Linie an einem Rechteck

Linie an einem konvexen Objekt

Linie an einem konkaven Objekt

 Cyrus-Beck

Rechteck an Rechteck

Linie an einem konvexen Objekt

Linie an einem konkaven Objekt

 Sutherland-Hodgman

Linie an einem konkaven Objekt

Polygonzug an einem konvexen Objekt

Polygonzug an einem

konkaven Objekt

(8)

U N I V E R S I T Ä T

Füllen von Flächen

(9)

U N I V E R S I T Ä T KOBLENZ · LANDAU

Mögliche Methode durch In/Out-Test

 Das Verfahren von Cyrus- Beck stellt im Kern einen Test bereit, ob ein Punkt innerhalb eines (konvexen) Polygonszugs liegt oder nicht.

 Mit Hilfe dieses Tests lässt sich auch ein Algorithmus zum Füllen von Polygonen entwickeln

 Grobes Verfahren:

1. Bestimme das „umgebende Rechteck“ (bounding box) des Polygons

2. Gehe in einer Schleife über alle Pixel der Bounding Box

3. Bestimme für jedes Pixel, ob es außen liegt (dann

ignorieren)

4. Sonst wird die Farbe für das

Pixel gesetzt

(10)

U N I V E R S I T Ä T

(achsen-parallele) Bounding-Box

 Ermittlung der minimalen, bzw. maximalen x- und y-

Koordinaten des Polygonzugs

void Polygon2D::computeBoundingBox( Vector2D &min, Vector2D &max) const {

unsigned int i;

min = mPoints[0];

max = mPoints[0];

for (i = 1; i < mPoints.size(); i++) {

if (mPoints[i].x() < min.x()) min.setX( mPoints[i].x());

else if (mPoints[i].x() > max.x()) max.setX( mPoints[i].x());

if (mPoints[i].y() < min.y()) min.setY( mPoints[i].y());

else if (mPoints[i].y() > max.y()) max.setY( mPoints[i].y());

} }

P0 P1

C

P2

xmin xmax

ymax

ymin

(11)

U N I V E R S I T Ä T KOBLENZ · LANDAU

In/Out Beispiel

P

0

P

1

P

2

P

3

A B

n

0

n

1

n

2

n

3

0 - - - - 3

out in in out out

+ -

- E

- 0

- D

- -

- C

- +

+ B

- -

+ A

2 1

0

C

D E

w

0

: <

w   n

i

(Punkt innerhalb)

0

: >

+ w   n

i

(Punkt außerhalb)

(12)

U N I V E R S I T Ä T

In/Out Beispiel II

P

0

P

1

A B

n

0

n

1

n

2

C

D E

P

2

out in in out out

+ -

- E

- 0

- D

- -

- C

- +

+ B

- -

+ A

2 1

0

(13)

U N I V E R S I T Ä T KOBLENZ · LANDAU

Implementierung

void Polygon2D::fill_polygon() const {

Vector2D min, max;

computeBoundingBox( min, max);

glBegin(GL_POINTS);

for (int x = (int) min.x(); x <= (int) max.x(); x++)

for (int y = (int) min.y(); y <= (int) max.y(); y++) {

if (in_out(Vector2D(x,y))) { glVertex2i(x,y);

} }

glEnd();

}

P0 P1

C

P2

xmin xmax

ymax

ymin

(14)

U N I V E R S I T Ä T

Implementierung

bool Polygon2D::in_out( Vector2D pixel) const {

Vector2D w, n;

float c;

unsigned int i;

for (i = 0; i < mPoints.size(); i++) {

n.setX( mPoints[(i+1)%mPoints.size()].y() - mPoints[i].y());

n.setY(-(mPoints[(i+1)%mPoints.size()].x() - mPoints[i].x()));

w = pixel - mPoints[i];

c = dot( w, n);

if (c > 0) {// alles außerhalb, Abbruch return false;

} }

return true;

}

Poly_fill.vcproj

(15)

U N I V E R S I T Ä T KOBLENZ · LANDAU

Beispiele

(16)

U N I V E R S I T Ä T

Konkaves Polygon

P

0

P

1

P

2

P

3

A B

n

0

n

1

n

2

n

4

C D

n

3

P

4

+ - - + 2

+ - +

- 3

out in out out

- -

- D

- -

- C

- -

- B

- -

- A

4 1

0

Ergebnis:

(17)

U N I V E R S I T Ä T KOBLENZ · LANDAU

Fazit

 Mit Hilfe der In/Out Routine lässt sich ein Algorithmus zum Füllen von Flächen leicht implementieren.

 Dieser setzt allerdings konvexe Polygone voraus

 Dieser Algorithmus ist sehr ineffizient, da viele „leere“

Pixel der Bounding-Box betrachtet werden

 Besser wäre, nur die Pixel innerhalb des Polygonzugs zu betrachten

 Vorteil: jedes Pixel lässt sich unabhängig von den anderen Pixeln betrachten, was das Prinzip

interessant macht für Multi-Processing (ultimativ 1

Prozessor für jedes Pixel)

(18)

U N I V E R S I T Ä T

Polygone füllen

 Vorheriger Ansatz mit in/out- Test hatte das Problem, dass alle Pixel in der Boundig-Box getestet wurden.

 Besser: Scanline-Orientiert.

 Man „scant“ das Bild entlang von Linien von y

min

nach y

max

 Für jede Scanline bestimmt man die „Spans“, also den x

min

und x

max

Wert der

horizontalen Linie und füllt die dazwischen liegenden Pixel.

y max

y min

x

span

x

min

x

max

(19)

U N I V E R S I T Ä T KOBLENZ · LANDAU

Scan-Konvertierung

 Dieses Vorgehen wird auch Scan-Konvertierung genannt.

 Es nutzt ein wichtiges Prinzip der Computergraphik aus, die Kohärenz

 Die Idee dabei ist: die Berechnungen für benachbarte Pixel sind ähnlich. Man tastet sich in kleinen Schritten durch das Bild und geht davon aus, dass sich

zwischen 2 Pixeln recht wenig ändert (gleiche

Sichtbarkeit, gleiche Beleuchtung…), was sehr wichtig

ist für die Effizienz vieler CG-Algorithmen.

(20)

U N I V E R S I T Ä T

Implementierung

1. Berechne y

min

, y

max

2. Schleife über alle y-Werte zwischen y

min

und y

max

3. Berechne spans: Schneide alle Kanten mit der y-Linie und sortiere die x-Werte

4. Fülle die Pixel innerhalb der spans

y

x

span

x

min

x

max

y max

y min

(21)

U N I V E R S I T Ä T KOBLENZ · LANDAU

Spanberechnung

 Für jede Kante wird wieder die Geradengleichung

aufgestellt (y gegeben):

y

x

min

span

x x

max

y max

y min A

B

( B A )

t A

X = + ⋅ −

 

 

⋅ −

 +

 

= 

 

 

y y

x x

y x

a b

a t b

a a y

x

y y

y

a b

a t y

= −

1 0 ≤ t

Schnittpunkt gültig, wenn:

)

( x x

x t b a

a

x = + ⋅ −

(22)

U N I V E R S I T Ä T

Klasse für Span

#ifndef _SPAN2D_H

#define _SPAN2D_H class Span2D

{

public:

Span2D();

~Span2D();

void setXmin(int);

void setXmax(int);

int xmin();

int xmax();

private:

int mXmin, mXmax;

};

#endif

Span2D Polygon2D::computeSpan( int y) const { float ax, ay, bx, by, x;

Vector2D min, max;

float t;

Span2D span;

computeBoundingBox( min, max);

span.setXmax(0);

span.setXmin(max.x());

for (unsigned int i = 0; i < mPoints.size(); i++) { ax = mPoints[i].x();

ay = mPoints[i].y();

bx = mPoints[(i+1)%mPoints.size()].x();

by = mPoints[(i+1)%mPoints.size()].y();

if (ay == by) continue;

t = (float)(y - ay) / (by - ay);

if (t >= 0.0 && t <= 1.0) { x = ax + t*(bx-ax);

if (x < span.xmin()) span.setXmin(x);

if (x > span.xmax()) span.setXmax(x);

} }

(23)

U N I V E R S I T Ä T KOBLENZ · LANDAU

Implementierung

void Polygon2D::fill() const { Vector2D min, max;

Span2D span;

//nur füllen wenn mehr als zwei Punkte if (mPoints.size() < 3) {

return;

}

computeBoundingBox( min, max);

glBegin(GL_POINTS);

for (int y = (int) min.y(); y <= (int) max.y(); y++) { span = computeSpan(y); // xmin, max

for (int x = span.xmin(); x <= span.xmax(); x++) { glVertex2i(x,y);

} }

glEnd();

} Poly_fill.vcproj

(24)

U N I V E R S I T Ä T

Farben für die Eckpunkte?

 Im Prinzip interpolieren wird die x,y-Koordinaten entlang der Kanten und spans durch Berechnung des

Geradenparameter t ∈ (0,1)

 Dadurch können auch

beliebige andere Parameter der Eckpunkte (z.B. Farben, Normalen etc.) interpoliert werden.

 Man spricht hier auch von der bilinearen Interpolation

(linear: auf einer Geraden, bilinear: auf einer Ebene)

y

x t l

t r

y max

y min

F 2

t

F 3

F 1

) (

: F F 2 t F 3 F 2 links l = + l ⋅ −

) (

: F F 1 t F 2 F 1 rechts r = + r ⋅ −

) (

: F F l t F r F l

span = + ⋅ −

(25)

U N I V E R S I T Ä T KOBLENZ · LANDAU

Beispiele

(26)

U N I V E R S I T Ä T

Implementierung

#ifndef _SPAN2D_H

#define _SPAN2D_H class Span2D

{

public:

Span2D();

~Span2D();

//get/set-Methoden void setXmin(int);

void setXmax(int);

void setRmin(float);

void setRmax(float);

void setGmin(float);

void setGmax(float);

void setBmin(float);

void setBmax(float);

int xmin();

int xmax();

float rmin();

float rmax();

float gmin();

float gmax();

float bmin();

float bmax();

private:

int mXmin, mXmax;

float mRmin, mRmax, mGmin, mGmax, mBmin, mBmax;

};

#endif

(27)

U N I V E R S I T Ä T KOBLENZ · LANDAU

Implementierung

void Polygon2D::fill() const { Vector2D min,max;

Span2D span;

float t, r, g, b;

computeBoundingBox( min, max); // ymin, ymax glBegin(GL_POINTS);

for (int y = (int) min.y(); y <= (int) max.y(); y++) { span = computeSpan( y); // xmin, max

for (int x = span.xmin(); x <= span.xmax(); x++) { if (span.xmax() == span.xmin())

t = 0;

else

t = (float)(x-span.xmin())/(span.xmax()-span.xmin());

r = span.rmin() + t*(span.rmax()-span.rmin());

g = span.gmin() + t*(span.gmax()-span.gmin());

b = span.bmin() + t*(span.bmax()-span.bmin());

glColor3f( r, g, b);

glVertex2i( x, y);

} }

glEnd();

}

Poly_fill.vcproj

Span erweitert um Farbe

(28)

U N I V E R S I T Ä T

Konkave Polygone

 Der Algorithmus lässt sich leicht für konkave Polygone erweitern.

 Für jede Scanline gibt es nicht nur einen Span, sondern eine Liste von

Spans, genauer: eine Reihe von x-Koordinaten, die

aufsteigend sortiert werden.

1 3

2 7 13 x

7 9 y

11

A B

C D

E F span 1

x

min

x

max

span 2

x

min

x

max

(29)

U N I V E R S I T Ä T KOBLENZ · LANDAU

Implementierung

Span muß erweitert werden, so daß Liste von Spans ermöglicht wird.

void Compute_spans( int y) {

Für alle Kanten {

Bestimme x,r,g,b für Start/Endpunkt der Kante;

Wenn Kante nicht waagrecht, berechne t;

Wenn (t>=0.0 && t<=1.0) {

Berechne x,r,g,b mit Hilfe von t;

Insert_span (x, r, g, b);

// Einsortieren in Spanliste bzgl. x }

} }

(30)

U N I V E R S I T Ä T

Impl. II

void fill_polygon() {

compute_bounding_box();

Schleife über alle y-Scanlines zwischen ymin und ymax;

{

Compute_spans(y);

Nimm 2 Elemente xmin und xmax aus Spanliste, solange welche vorhanden;

{

Schleife über alle x zw. xmin und xmax {

Berechne t-Parameter für x;

Interpolieren r,g,b mit Hilfe von t;

Fülle Pixel an Stelle x,y mit r,g,b;

} } } }

Poly_fill.vcproj

(31)

U N I V E R S I T Ä T KOBLENZ · LANDAU

Beispiele

(32)

U N I V E R S I T Ä T

Probleme

 Die Anzahl der Schnittpunkte ist nicht unbedingt gerade…

 Idee: „Vorzeichen“ der Kanten miterfassen (genauer: wenn im Umlaufsinn der Endpunkt

größeres y-Koordinate hat, als der Startpunkt, dann „+“ sonst

„–“).

 Wenn neuer Punkt in Spanliste eingefügt wird, wird überprüft, ob der Punkt schon da ist:

2 4

2

+

+

− +

− 4

2

2

Falls ja und Vorzeichen sind gleich, dann wird er ignoriert

Falls ja und Vorzeichen sind

nicht gleich, dann eingefügt

(33)

U N I V E R S I T Ä T KOBLENZ · LANDAU

Polygone und Flächen in OpenGL

(34)

U N I V E R S I T Ä T

GLUT: Tastatur Callback

void keyboard( unsigned char key, int x, int y) {

switch (key) { case '1':

show = 1;

glutPostRedisplay();

break;

case '2':

show = 2;

glutPostRedisplay();

break;

default:

break;

} }

 key liefert die gedrückte Taste

 x, y die aktuelle Mausposition

(35)

U N I V E R S I T Ä T KOBLENZ · LANDAU

Primitivtypen in OpenGL

5.

3.

4. 2.

1.

GL_POINTS

5.

3.

4. 2.

1.

GL_LINE_STRIP

5.

3.

4. 2.

1.

GL_LINE_LOOP

5.

3.

4. 2.

1.

GL_POLYGON

1.

3.

2. 4.

5.

GL_LINES

6.

1.

3.

4. 2.

5.

GL_QUADS

8.

1.

2.

3. 4.

6.

GL_TRIANGLES

5.

6.

7.

Mehrfachprimitive

primitive.c

(36)

U N I V E R S I T Ä T

Füllmuster

 Analog zu den Linien:

glPolygonStipple( GLuchar * pattern );

 muß auch aktiviert werden

glEnable(GL_POLYGON_STIPPLE);

 feste Größe: 32x32

 abgelegt als Bitmuster von links unten nach rechts

oben

(37)

U N I V E R S I T Ä T KOBLENZ · LANDAU

Zusätzliche Eckpunktattribute

 State machine: an jedem Eckpunkt wird der aktuelle Zustand verwendet, d.h. erst muß die Farbe etc.

definiert werden, dann der Eckpunkt

glBegin(GL_POLYGON);

glColor3f(1,0,0);

glVertex3f(0,0,0);

glVertex3f(1,0,0);

glVertex3f(.5,1,0);

glEnd();

(38)

U N I V E R S I T Ä T

Zusätzliche Eckpunktattribute

 Änderungen pro Eckpunkt möglich

glBegin(GL_POLYGON);

glColor3f(0,0,1);

glVertex3f(0,0,0);

glColor3f(0,0,1);

glVertex3f(1,0,0);

glColor3f(1,0,0);

glVertex3f(.5,1,0);

glEnd();

(39)

U N I V E R S I T Ä T KOBLENZ · LANDAU

Farbinterpolation

 Die Farbe muß nicht interpoliert werden

 glShadeModel( {GL_FLAT,GL_SMOOTH} ); bestimmt, ob interpoliert wird

 bei GL_FLAT bestimmt die Farbe des letzten Eckpunktes (Ausnahme GL_POLYGON: erster)

1.

5.

4.

3.

2.

6.

1.

5.

4.

3.

2.

6.

GL_FLAT

GL_SMOOTH

(40)

U N I V E R S I T Ä T

Polygone….

 … werden in Dreiecke zerlegt und als Dreiecke dargestellt.

 Bi-lineare Interpolation nicht mehr eindeutig

 Abhängig davon, wie die Dreieckskante verläuft

r g r g

r g

r g

Gouraud.c

v1 v2 v1

v4 v3 v4

v2 v3

DrawPolygon(v1,v2,v3,v4)

DrawPolygon(v2,v3,v4,v1)

(41)

U N I V E R S I T Ä T KOBLENZ · LANDAU

GLUT: Idle und Special Funktion

void main(…) {

glutIdleFunc(idle);

glutSpecialFunc(special);

}

 IDLE Funktion

Wird immer aufgerufen, wenn der Windowmanager

„nichts zu tun hat“.

Gute Verwendung:

automatische Objektbewegung

 SPECIAL Funktion

Sondertasten wie z.B.

Pfeil-/Cursortasten.

void special( int key, int x, int y) {

switch (key) {

case GLUT_KEY_UP : speed += 0.001f;

break;

case GLUT_KEY_DOWN : speed -= 0.001f;

break;

} }

void idle( void) {

beta += 5.0;

glutPostRedisplay();

}

(42)

U N I V E R S I T Ä T

Front-/Backbuffer

 Erlaubt flackerfreie Animationen

zeichnen swap

zeichnen

Statt wie bisher:

glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);

glFlush(); Benötigt man:

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);

(43)

U N I V E R S I T Ä T KOBLENZ · LANDAU

Tiefen-Puffer

 Für jedes Pixel: finde/zeichne das vorderste Polygon

… kann direkt mit Hilfe der z- Koordinate entschieden

werden

 Für jedes Pixel (x,y)

gibt es einen Farbeintrag im Framebuffer

gibt es einen z-Eintrag im Z- Buffer

 Vorgehen

Initialisiere anfangs Z-Buffer mit größtem, maximalen Wert

Schreibe rgb-Wert in

Framebuffer und z-Wert in Z- Buffer für (x,y) nur, wenn aktueller z-Wert kleiner ist, als der für das Pixel bereits Eingetragene

function setpixel( int x, int y, rgb c, float z) if (z < z-buffer[x, y])

{

z-buffer[x, y]= z;

screen[x, y] = c;

}

(44)

U N I V E R S I T Ä T

Tiefen-Puffer in OpenGL

 Glut-Fenster anmelden

glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);

 Einschalten

glEnable(GL_DEPTH_TEST);

 Wichtig: nicht nur Bildspeicher, sondern auch Tiefenpuffer löschen

glClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

proj_z.vcproj

Referenzen

ÄHNLICHE DOKUMENTE

b) Geben Sie einen Algorithmus zum Rendern einer beliebigen Szene aus Dreiecken an, der einen Overdraw von 1 f¨ ur alle Pixel erreichen.. Aufgabe 2 (Z-Buffer: Wireframe-Darstellung

  Problem: manchmal werden vertikal übereinander liegende Pixel gesetzt → unterschiedliche scheinbare

  Clipping = teilweise sichtbare Objekte (Linien / Polygone) müssen gegen Window / Viewport geclippt werden.   Resultat = maximales Teil-Objekt, das vollständig im

  Lineare Algebra: Vektoren und Vektorräume, Matrizen..

2.  Betrachte nur die Folge der grünen Zellen = Zellen, die an ihrer linken Kante von der Linie geschnitten werden.

[r]

  Clipping = teilweise sichtbare Objekte (Linien / Polygone) müssen gegen Window / Viewport geclippt werden.   Resultat = maximales Teil-Objekt, das vollständig im

 Peter Shirley: Fundamentals of Computer Graphics, A K Peters LTD, Second Edition 2005.