Textur
Normaler
Computer Graphics
Børre Stenseth
JOGL>Ball

Football

What

"Buckyball" is a known phenomena from mathematics [1] , nature [2] and the soccer field. The form of the buckyball is described by the golden ratio (1.61803399...). This number is calculated as the ratio between two adjacent numbers in the Fibonacci series. The number is used in many arguments in mathematics and it is found in many natural forms in nature [3] . The number often appears as a key number when forms are packed or compressed. It is also used in aesthetics as a "natural" or well-balanced ratio, for instance between the length and height of a rectangle.

Buckyball is a well known concept for chemists. It describes the position of 60 carbon atoms in the corners of the figure. The figure has its name from R. Buckminster Fuller [4] .

Geometri

buckyflat

A buckyball has 60 corners, 20 polygons with 6 corners (hexagons) and 12 polygons with 5 corners (pentagons). The illustration is from GoldenNumber.net [5]

The data that is used to draw a buckyball in this module is:

_oneBall.java

When we draw a figure based on surfaces described by a set of polygons, we will have to calculate normals and we will have to determine what is in (back) and what is out(front). We must index the corners in a consistent way. In OpenGL context this means that we must describe the corners clockwise (GL_CW) or counterclockwise(GL_CW). The direction has only meaning when we decide a point of observation. One way to do this is to decide that we look at a polygon from what we decide to call the front, usually the outside.

gl.glFrontFace(GL.GL_CW)
gl.glFrontFace(GL.GL_CCW)

When we hav made these decisions we can calculate normals on all polygons, (or polygon corners) by means of the cross product for vectors.

normal6=new float[20][3];
for (int ix = 0; ix < 20; ix++)
{
    float ax = p6[ix][2][0] - p6[ix][0][0];
    float ay = p6[ix][2][1] - p6[ix][0][1];
    float az = p6[ix][2][2] - p6[ix][0][2];
    float bx = p6[ix][3][0] - p6[ix][0][0];
    float by = p6[ix][3][1] - p6[ix][0][1];
    float bz = p6[ix][3][2] - p6[ix][0][2];
    float x = ay * bz - az * by;
    float y = az * bx - ax * bz;
    float z = ax * by - ay * bx;
    float l=(float)Math.sqrt(x*x+y*y+z*z);
    normal6[ix][0]=x/l;
    normal6[ix][1]=y/l;
    normal6[ix][2]=z/l;
}
normal5=new float[12][3];
for (int ix = 0; ix < 12; ix++)
{
    float ax = p5[ix][2][0] - p5[ix][0][0];
    float ay = p5[ix][2][1] - p5[ix][0][1];
    float az = p5[ix][2][2] - p5[ix][0][2];
    float bx = p5[ix][3][0] - p5[ix][0][0];
    float by = p5[ix][3][1] - p5[ix][0][1];
    float bz = p5[ix][3][2] - p5[ix][0][2];
    float x = ay * bz - az * by;
    float y = az * bx - ax * bz;
    float z = ax * by - ay * bx;
    float l=(float)Math.sqrt(x*x+y*y+z*z);
    normal5[ix][0]=x/l;
    normal5[ix][1]=y/l;
    normal5[ix][2]=z/l;
}

This makes the drawing straight forward:

public void drawMe(GL gl)
{
    int mode = GL.GL_POLYGON;//GL.GL_LINE_STRIP;
    // 20 polygons with 6 edges
    stdMaterials.setMaterial(gl, stdMaterials.MAT_WARM_WHITE, GL.GL_FRONT);
    for (int p = 0; p < 20; p++)
    {
        gl.glBegin(mode);
        gl.glNormal3f(normal6[p][0], normal6[p][1], normal6[p][2]);
        for (int ix = 0; ix < 6; ix++)
            gl.glVertex3f(p6[p][ix][0], p6[p][ix][1], p6[p][ix][2]);
        gl.glEnd();
    }
    // 12 polygons with 5 edges
    stdMaterials.setMaterial(gl, stdMaterials.MAT_RUBY, GL.GL_FRONT);
    for (int p = 0; p < 12; p++)
    {
        gl.glBegin(mode);
        gl.glNormal3f(normal5[p][0], normal5[p][1], normal5[p][2]);
        for (int ix = 0; ix < 5; ix++)
           gl.glVertex3f(p5[p][ix][0], p5[p][ix][1], p5[p][ix][2]);
        gl.glEnd();
    }
}

Texture

We will add texture to all hexagons. We start out with a qudratic image and want to find which coordinates in the image we want to map to the hexagons corners.

one6p

p0d/3 , 0
p12d/3 , 0
p2d-(d/3)cos(60) , (d/3)sin(60)
p3d-(2d/3)cos(60) , (2d/3)sin(60)
p4(2d/3)cos(60) , (2d/3)sin(60)
p5(d/3)cos(60) , (d/3)sin(60)

where d is the side in the triangle, and the square. When we map coordinates in a bitmap, as in the algorithm below, d always has the value 1, independant of the dimension of the bitmap measure in pixels. A texture has a logical dimension of 1 x 1.

ronald

Since OpenGL (versions before 2.1) only accepts textures with format: 2n*2m, we will compose the image such that the part we want to include fits inside the triangle in question.
ronalball

Texture mapping can be prepared in the array tex6:

// calculate texture points
  float d=1.0f;
  float cos60=(float)Math.cos(Math.PI/3.0);//60 degrees
  float sin60=(float)Math.sin(Math.PI/3.0);
  tex6=new float[6][2];
  tex6[0][0]=d/3.0f;                   tex6[0][1]=0.0f;
  tex6[1][0]=2.0f*d/3.0f;              tex6[1][1]=0.0f;
  tex6[2][0]=d-(d/3.0f)*cos60;         tex6[2][1]=(d/3.0f)*sin60;
  tex6[3][0]=d-(2.0f*d/3.0f)*cos60;    tex6[3][1]=(2.0f*d/3.0f)*sin60;
  tex6[4][0]=(2.0f*d/3.0f)*cos60;      tex6[4][1]=(2.0f*d/3.0f)*sin60;
  tex6[5][0]=(d/3.0f)*cos60;           tex6[5][1]=(d/3.0f)*sin60;
  // load textures
  textures=new TextureReader.Texture[3];
  try {
          textures[0] = TextureReader.readTexture("images/Marrakech.jpg");
          textures[1] = TextureReader.readTexture("images/chesspiece.gif");
          textures[2] = TextureReader.readTexture("images/ronaldinho.jpg");
      }
  catch (IOException ex) {
          System.out.println(ex.getMessage());
      }

Rendering:

public void drawMeTextured(GL gl,int tIx)
{
    int mode = GL.GL_POLYGON;//GL.GL_LINE_STRIP;
    if(tIx <0) tIx=0;
    if(tIx >=textures.length) tIx=textures.length-1;
    gl.glTexParameteri(GL.GL_TEXTURE_2D,GL.GL_TEXTURE_WRAP_S,GL.GL_CLAMP);
    gl.glTexParameteri(GL.GL_TEXTURE_2D,GL.GL_TEXTURE_WRAP_T,GL.GL_CLAMP);
    gl.glTexParameteri(GL.GL_TEXTURE_2D,GL.GL_TEXTURE_MAG_FILTER,GL.GL_NEAREST);
    gl.glTexParameteri(GL.GL_TEXTURE_2D,GL.GL_TEXTURE_MIN_FILTER,GL.GL_NEAREST);
    gl.glTexEnvi(GL.GL_TEXTURE_ENV,GL.GL_TEXTURE_ENV_MODE,GL.GL_MODULATE);
    gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT,GL.GL_NICEST);
    gl.glDisable(GL.GL_TEXTURE_2D);
    gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB,
                    textures[tIx].getWidth(),textures[tIx].getHeight(), 0,
                    GL.GL_RGB, GL.GL_UNSIGNED_BYTE,
                    textures[tIx].getPixels());
    gl.glEnable(GL.GL_TEXTURE_2D);
    // 20 polygons with 6 edges
    stdMaterials.setMaterial(gl, stdMaterials.MAT_WARM_WHITE, GL.GL_FRONT);
    for (int p = 0; p < 20; p++)
    {
        gl.glBegin(mode);
        gl.glNormal3f(normal6[p][0], normal6[p][1], normal6[p][2]);
        for (int ix = 0; ix < 6; ix++)
        {
            gl.glTexCoord2f(tex6[ix][0], tex6[ix][1]);
            gl.glVertex3f(p6[p][ix][0], p6[p][ix][1], p6[p][ix][2]);
        }
        gl.glEnd();
    }
    // 12 polygons with 5 edges
    stdMaterials.setMaterial(gl, stdMaterials.MAT_RUBY, GL.GL_FRONT);
    for (int p = 0; p < 12; p++)
    {
        gl.glBegin(mode);
        gl.glNormal3f(normal5[p][0], normal5[p][1], normal5[p][2]);
        for (int ix = 0; ix < 5; ix++)
           gl.glVertex3f(p5[p][ix][0], p5[p][ix][1], p5[p][ix][2]);
        gl.glEnd();
    }
}
  • The program project: https://svnit.hiof.no/svn/psource/JOGL/bucky
References
  1. Constructing a Buckyball with Mathematicareference.wolfram.com/legacy/v5/Demos/Notebooks/BuckyballConstruction.html24-05-2009
  1. Buckyballs – a new sphere of sciencewww.science.org.au/nova/024/024key.htm24-05-2009
  1. Fibonacci Numbers and the Golden Sectionwww.mcs.surrey.ac.uk/Personal/R.Knott/Fibonacci/fib.html24-05-2009
  1. R. Buckminster Fullerwww.newciv.org/whole/bucky.html24-05-2009
  1. Bucky BallsGOLDENNUMBER.NETwww.goldennumber.net/bucky-balls/14-07-2016
Maintainance

B Stenseth, May 2009

JOGL>Ball
til toppen