Kugel: Unterschied zwischen den Versionen

Aus DGL Wiki
Wechseln zu: Navigation, Suche
K
K (Aussen -> Außen)
 
(14 dazwischenliegende Versionen von 5 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
 
==Variante 1==
 
==Variante 1==
Der nachfolgende Code ist ein Port von [http://astronomy.swin.edu.au/~pbourke/opengl/sphere/ http://astronomy.swin.edu.au/~pbourke/opengl/sphere/].  
+
Der nachfolgende Code ist ein Port von [http://local.wasp.uwa.edu.au/~pbourke/miscellaneous/sphere_cylinder/index.html http://local.wasp.uwa.edu.au/~pbourke/miscellaneous/sphere_cylinder/index.html].  
  
 
Neben den Vertexpositionen werden die Normalen und Texturkoordinaten berechnet.
 
Neben den Vertexpositionen werden die Normalen und Texturkoordinaten berechnet.
  
<pascal>procedure CreateSphere(c: TVector3f; r: Single; n: Integer);
+
{{Hinweis|TVector3f ist ein einfaches Feld mit 3 Floats. (array[0..2] of float)}}
 +
 
 +
 
 +
<source lang="pascal">procedure CreateSphere(c: TVector3f; r: Single; n: Integer);
 
const
 
const
 
   TWOPI = PI*2;
 
   TWOPI = PI*2;
Zeile 57: Zeile 60:
 
   glEnd;
 
   glEnd;
 
   end;
 
   end;
end;</pascal>
+
end;</source>
 +
 
 +
 
 +
 
 +
==Variante 2==
 +
'''Der nachfolgende Code ist selbst geschrieben (MatReno)'''
 +
 
 +
Er ermöglicht das Zeichnen einer Kugel, oder beliebigen Halbkugel, mit
 +
Texturkoordinaten und Normalen.
 +
 
 +
 
 +
===Benötigte Typen===
 +
 
 +
<source lang="pascal">
 +
TVector2f : Array [0..1] of Single;
 +
TVector3f : Array [0..2] of Single;
 +
TVector4i : Array [0..3] of Integer;
 +
</source>
 +
 
 +
 
 +
===Zusätzlich benötigte Methoden===
 +
 
 +
<source lang="pascal">
 +
Function VectorAdd(const vector: TVector3f; Value: Single): TVector3f;
 +
Begin
 +
  Result[0] := vector[0] + Value;
 +
  Result[1] := vector[1] + Value;
 +
  Result[2] := vector[2] + Value;
 +
End;
 +
</source>
 +
 
 +
 
 +
<source lang="pascal">
 +
Function VectorMult(const vector: TVector3f; Value: Single): TVector3f;
 +
Begin
 +
  Result[0] := vector[0] * Value;
 +
  Result[1] := vector[1] * Value;
 +
  Result[2] := vector[2] * Value;
 +
End;
 +
</source>
 +
 
 +
 
 +
<source lang="pascal">
 +
Function ToVector2f(x, y: Single): TVector2f;
 +
Begin
 +
  Result[0] := x;
 +
  Result[1] := y;
 +
End;
 +
</source>
 +
 
 +
 
 +
<source lang="pascal">
 +
Function ToVector3f(x, y, z: Single): TVector3f;
 +
Begin
 +
  Result[0] := x;
 +
  Result[1] := y;
 +
  Result[2] := z;
 +
End;
 +
</source>
 +
 
 +
 
 +
<source lang="pascal">
 +
Function ToVector4i(x, y, z, w: Integer): TVector4i;
 +
Begin
 +
  Result[0] := x;
 +
  Result[1] := y;
 +
  Result[2] := z;
 +
  Result[3] := w;
 +
End;
 +
</source>
 +
 
 +
 
 +
===Parametererklärung und Prozedur===
 +
 
 +
radius: Radius der Kugel in OGL-Units
 +
 +
n: Genauigkeit
 +
 
 +
typ: Art (siehe Procedure Kommentar)
 +
 
 +
inverted:
 +
 
 +
= false -> FrontFace außen
 +
 
 +
= true  -> FrontFace innen
 +
 
 +
voffset: Vektor (X, Y, Z) um den die Kugel verschoben wird
 +
 
 +
toffset: Vektor (U, V) um den die Textur verschoben wird
 +
 
 +
tscale: Textur-skalierung
 +
 
 +
 
 +
<source lang="pascal">
 +
Procedure DrawSphereObject(radius: Single; n: word;
 +
                          typ: byte; inverted: boolean;
 +
                          voffset: TVector3f; toffset, tscale: TVector2f);
 +
Var alpha  : TVector2f;  // i*beta around x axis
 +
    SinAlpha: TVector2f;  // sin(alpha)
 +
    CosAlpha: TVector2f;  // cos(alpha)
 +
    beta    : Single;    // DegToRad(360° / n)
 +
    delta  : Single;    // j*beta around z axis
 +
    SinDelta: Single;    // sin(delta)
 +
    CosDelta: Single;    // cos(delta)
 +
    h, q    : word;      // half, quarter
 +
    v      : TVector3f;  // vector for normal and vertex
 +
    border  : TVector4i;  // for-loop borders
 +
    i, j    : Integer;
 +
    k      : Byte;
 +
Begin
 +
  radius := abs(radius);
 +
 
 +
  If (n < 4) Or (Odd(n)) Or (radius = 0) Then Exit;
 +
 
 +
  h := n div 2;
 +
  q := n div 4;
 +
  If (Odd(h)) Then inc(q);
 +
 
 +
  Case typ of
 +
    0: border := ToVector4i(  -h,    h-1, -q, q);  // sphere
 +
    1: border := ToVector4i(  -h,    h-1, -q, 0);  // hemisphere x-
 +
    2: border := ToVector4i(  -h,    h-1,  0, q);  // hemisphere x+
 +
    3: border := ToVector4i(-h-q, -h+q-1, -q, q);  // hemisphere y-
 +
    4: border := ToVector4i(  -q,    q-1, -q, q);  // hemisphere y+
 +
    5: border := ToVector4i(  -h,    -1, -q, q);  // hemisphere z-
 +
    6: border := ToVector4i(  0,    h-1, -q, q);  // hemisphere z+
 +
    else Exit;
 +
  End;
 +
 
 +
  beta := 2*PI / n;
 +
 
 +
    For i:=border[0] to border[1] do Begin
 +
      alpha := ToVector2f(i*beta, (i+1)*beta);
 +
 
 +
      SinAlpha := ToVector2f(sin(alpha[0]), sin(alpha[1]));
 +
      CosAlpha := ToVector2f(cos(alpha[0]), cos(alpha[1]));
 +
 
 +
      glBegin(GL_TRIANGLE_STRIP);
 +
      For j:=border[2] to border[3] do Begin
 +
        delta := j*beta;
 +
 
 +
        SinDelta := sin(delta);
 +
        CosDelta := cos(delta);
 +
 
 +
        If (inverted) Then
 +
          For k:=1 downto 0 do Begin
 +
            v := ToVector3f(-SinDelta, -CosAlpha[k]*CosDelta, -SinAlpha[k]*CosDelta);
 +
            glNormal3fv(@v);
 +
            v := VectorAdd(VectorMult(v, -radius), voffset);
 +
            glTexCoord2f((j/n + 0.25)*tscale[0] + toffset[0], ((i+k)/n)*tscale[1] + toffset[1]);
 +
            glvertex3fv(@v);
 +
          End;
 +
 
 +
        If (not inverted) Then
 +
          For k:=0 to 1 do Begin
 +
            v := ToVector3f(SinDelta, CosAlpha[k]*CosDelta, SinAlpha[k]*CosDelta);
 +
            glNormal3fv(@v);
 +
            v := VectorAdd(VectorMult(v,  radius), voffset);
 +
            glTexCoord2f((j/n + 0.25)*tscale[0] + toffset[0], ((i+k)/n)*tscale[1] + toffset[1]);
 +
            glvertex3fv(@v);
 +
          End
 +
      End;
 +
      glEnd;
 +
  End;
 +
End;
 +
</source>
 +
 
 +
 
 +
===Beispielaufruf===
 +
 
 +
<source lang="pascal">
 +
Const
 +
ONE_VECTOR_2f  : TVector2f = (1, 1);
 +
NULL_VECTOR_2f : TVector2f = (0, 0);
 +
NULL_VECTOR_3f : TVector3f = (0, 0, 0);
 +
</source>
 +
 
 +
 
 +
Um eine Kugel zu rendern muss man z.B. folgendes aufrufen:
 +
<source lang="pascal">
 +
DrawSphereObject(5,
 +
                32,
 +
                0,
 +
                false,
 +
                NULL_VECTOR_3f,
 +
                NULL_VECTOR_2f,
 +
                ONE_VECTOR_2f);
 +
</source>
 +
 
 +
== Alternative ==
  
 +
Als Alternative zu selbstgeschrieben Code bieten sich die [[Quadrik|Quadriken]] an, mit denen sich mit verhältnissmäßig wenigen Aufrufen verschiedene Formen erzeugen lassen.
  
 
[[Kategorie:Technik_oder_Algorithmus]] [[Kategorie:Anleitung]]
 
[[Kategorie:Technik_oder_Algorithmus]] [[Kategorie:Anleitung]]

Aktuelle Version vom 21. März 2012, 15:35 Uhr

Variante 1

Der nachfolgende Code ist ein Port von http://local.wasp.uwa.edu.au/~pbourke/miscellaneous/sphere_cylinder/index.html.

Neben den Vertexpositionen werden die Normalen und Texturkoordinaten berechnet.

Info DGL.png TVector3f ist ein einfaches Feld mit 3 Floats. (array[0..2] of float)


procedure CreateSphere(c: TVector3f; r: Single; n: Integer);
const
  TWOPI = PI*2;
  PID2 = PI/2;
var
  i,j: Integer;
  theta1,theta2,theta3: Single;
  e,p:TVector3f;
begin
  if (r < 0) then r := -r;
  if (n < 0) then n := -n;
  if (n < 4) or (r <= 0) then
  begin
    glBegin(GL_POINTS);
      glVertex3f(c[0],c[1],c[2]);
    glEnd;
    exit;
  end;

  for j:=0 to n div 2 do
  begin
    theta1 := j * TWOPI / n - PID2;
    theta2 := (j + 1) * TWOPI / n - PID2;

    glBegin(GL_QUAD_STRIP);
    for i:=0 to n do
    begin
      theta3 := i * TWOPI / n;

      e[0] := cos(theta2) * cos(theta3);
      e[1] := sin(theta2);
      e[2] := cos(theta2) * sin(theta3);
      p[0] := c[0] + r * e[0];
      p[1] := c[1] + r * e[1];
      p[2] := c[2] + r * e[2];

      glNormal3f(e[0],e[1],e[2]);
      glTexCoord2f(i/n,2*(j+1)/n);
      glVertex3f(p[0],p[1],p[2]);

      e[0] := cos(theta1) * cos(theta3);
      e[1] := sin(theta1);
      e[2] := cos(theta1) * sin(theta3);
      p[0] := c[0] + r * e[0];
      p[1] := c[1] + r * e[1];
      p[2] := c[2] + r * e[2];

      glNormal3f(e[0],e[1],e[2]);
      glTexCoord2f(i/n,2*j/n);
      glVertex3f(p[0],p[1],p[2]);
    end;
   glEnd;
  end;
end;


Variante 2

Der nachfolgende Code ist selbst geschrieben (MatReno)

Er ermöglicht das Zeichnen einer Kugel, oder beliebigen Halbkugel, mit Texturkoordinaten und Normalen.


Benötigte Typen

TVector2f : Array [0..1] of Single;
TVector3f : Array [0..2] of Single;
TVector4i : Array [0..3] of Integer;


Zusätzlich benötigte Methoden

Function VectorAdd(const vector: TVector3f; Value: Single): TVector3f; 
Begin
  Result[0] := vector[0] + Value;
  Result[1] := vector[1] + Value;
  Result[2] := vector[2] + Value;
End;


Function VectorMult(const vector: TVector3f; Value: Single): TVector3f;
Begin
  Result[0] := vector[0] * Value;
  Result[1] := vector[1] * Value;
  Result[2] := vector[2] * Value;
End;


Function ToVector2f(x, y: Single): TVector2f;
Begin
  Result[0] := x;
  Result[1] := y;
End;


Function ToVector3f(x, y, z: Single): TVector3f;
Begin
  Result[0] := x;
  Result[1] := y;
  Result[2] := z;
End;


Function ToVector4i(x, y, z, w: Integer): TVector4i;
Begin
  Result[0] := x;
  Result[1] := y;
  Result[2] := z;
  Result[3] := w;
End;


Parametererklärung und Prozedur

radius: Radius der Kugel in OGL-Units

n: Genauigkeit

typ: Art (siehe Procedure Kommentar)

inverted:

= false -> FrontFace außen

= true -> FrontFace innen

voffset: Vektor (X, Y, Z) um den die Kugel verschoben wird

toffset: Vektor (U, V) um den die Textur verschoben wird

tscale: Textur-skalierung


Procedure DrawSphereObject(radius: Single; n: word; 
                           typ: byte; inverted: boolean; 
                           voffset: TVector3f; toffset, tscale: TVector2f);
Var alpha   : TVector2f;  // i*beta around x axis
    SinAlpha: TVector2f;  // sin(alpha)
    CosAlpha: TVector2f;  // cos(alpha)
    beta    : Single;     // DegToRad(360° / n)
    delta   : Single;     // j*beta around z axis
    SinDelta: Single;     // sin(delta)
    CosDelta: Single;     // cos(delta)
    h, q    : word;       // half, quarter
    v       : TVector3f;  // vector for normal and vertex
    border  : TVector4i;  // for-loop borders
    i, j    : Integer;
    k       : Byte;
Begin
  radius := abs(radius);

  If (n < 4) Or (Odd(n)) Or (radius = 0) Then Exit;

  h := n div 2;
  q := n div 4;
  If (Odd(h)) Then inc(q);

  Case typ of
    0: border := ToVector4i(  -h,    h-1, -q, q);  // sphere
    1: border := ToVector4i(  -h,    h-1, -q, 0);  // hemisphere x-
    2: border := ToVector4i(  -h,    h-1,  0, q);  // hemisphere x+
    3: border := ToVector4i(-h-q, -h+q-1, -q, q);  // hemisphere y-
    4: border := ToVector4i(  -q,    q-1, -q, q);  // hemisphere y+
    5: border := ToVector4i(  -h,     -1, -q, q);  // hemisphere z-
    6: border := ToVector4i(   0,    h-1, -q, q);  // hemisphere z+
    else Exit;
  End;

  beta := 2*PI / n;

    For i:=border[0] to border[1] do Begin
      alpha := ToVector2f(i*beta, (i+1)*beta);

      SinAlpha := ToVector2f(sin(alpha[0]), sin(alpha[1]));
      CosAlpha := ToVector2f(cos(alpha[0]), cos(alpha[1]));

      glBegin(GL_TRIANGLE_STRIP);
      For j:=border[2] to border[3] do Begin
        delta := j*beta;

        SinDelta := sin(delta);
        CosDelta := cos(delta);

        If (inverted) Then
          For k:=1 downto 0 do Begin
            v := ToVector3f(-SinDelta, -CosAlpha[k]*CosDelta, -SinAlpha[k]*CosDelta);
            glNormal3fv(@v);
            v := VectorAdd(VectorMult(v, -radius), voffset);
            glTexCoord2f((j/n + 0.25)*tscale[0] + toffset[0], ((i+k)/n)*tscale[1] + toffset[1]);
            glvertex3fv(@v);
          End;

        If (not inverted) Then
          For k:=0 to 1 do Begin
            v := ToVector3f(SinDelta, CosAlpha[k]*CosDelta, SinAlpha[k]*CosDelta);
            glNormal3fv(@v);
            v := VectorAdd(VectorMult(v,  radius), voffset);
            glTexCoord2f((j/n + 0.25)*tscale[0] + toffset[0], ((i+k)/n)*tscale[1] + toffset[1]);
            glvertex3fv(@v);
          End
      End;
      glEnd;
   End;
End;


Beispielaufruf

Const
ONE_VECTOR_2f  : TVector2f = (1, 1);
NULL_VECTOR_2f : TVector2f = (0, 0);
NULL_VECTOR_3f : TVector3f = (0, 0, 0);


Um eine Kugel zu rendern muss man z.B. folgendes aufrufen:

DrawSphereObject(5, 
                 32, 
                 0, 
                 false, 
                 NULL_VECTOR_3f, 
                 NULL_VECTOR_2f, 
                 ONE_VECTOR_2f);

Alternative

Als Alternative zu selbstgeschrieben Code bieten sich die Quadriken an, mit denen sich mit verhältnissmäßig wenigen Aufrufen verschiedene Formen erzeugen lassen.