home dev games gallery work
Lewpen.com»Research & Development»3D Graphics»Java 3D Engine»3D Panoramas»Panorama Viewer

Panorama Viewer

Placing the viewpoint inside the cube and making the faces of the cube textured
Applet failed to run. No Java plug-in was found.

Perspective correct textured triangles

This is my routine for perspective texturemapping the triangles:
  //---- tri_persp

  //  Array of flattened 256x256 32-bit RGB texture bitmaps
  //  In the case of Lewpen.com panorama viewer, the dimensions are tex[6][65536]

  int[][] tex;

  //  Arguments for tri_persp - co-ordinates and texture co-ords of each corner

  float tri_x1, tri_y1, tri_z1, tri_u1, tri_v1;
  float tri_x2, tri_y2, tri_z2, tri_u2, tri_v2;
  float tri_x3, tri_y3, tri_z3, tri_u3, tri_v3;

  public void tri_persp(int texnum)
  {
    if(tri_z1 < 0) return;
    if(tri_z2 < 0) return;
    if(tri_z3 < 0) return;

    int[] tex = this.tex[texnum];

    tri_u1 = 256-tri_u1;
    tri_u2 = 256-tri_u2;
    tri_u3 = 256-tri_u3;

    int i, j;

    //  Don't draw if backfacing

    if((tri_x2-tri_x1)*(tri_y3-tri_y1) < (tri_x3-tri_x1)*(tri_y2-tri_y1)) return;

    //- Sort points

    float t;

    if(tri_y2 < tri_y1)
    {
        t = tri_x1; tri_x1 = tri_x2; tri_x2 = t;
        t = tri_y1; tri_y1 = tri_y2; tri_y2 = t;
        t = tri_z1; tri_z1 = tri_z2; tri_z2 = t;
        t = tri_u1; tri_u1 = tri_u2; tri_u2 = t;
        t = tri_v1; tri_v1 = tri_v2; tri_v2 = t;
    }

    if(tri_y3 < tri_y2)
    {
        t = tri_x2; tri_x2 = tri_x3; tri_x3 = t;
        t = tri_y2; tri_y2 = tri_y3; tri_y3 = t;
        t = tri_z2; tri_z2 = tri_z3; tri_z3 = t;
        t = tri_u2; tri_u2 = tri_u3; tri_u3 = t;
        t = tri_v2; tri_v2 = tri_v3; tri_v3 = t;
    }

    if(tri_y2 < tri_y1)
    {
        t = tri_x1; tri_x1 = tri_x2; tri_x2 = t;
        t = tri_y1; tri_y1 = tri_y2; tri_y2 = t;
        t = tri_z1; tri_z1 = tri_z2; tri_z2 = t;
        t = tri_u1; tri_u1 = tri_u2; tri_u2 = t;
        t = tri_v1; tri_v1 = tri_v2; tri_v2 = t;
    }

    //- Divide by z to do perspective correction

    tri_u1 /= tri_z1; tri_u2 /= tri_z2; tri_u3 /= tri_z3;
    tri_v1 /= tri_z1; tri_v2 /= tri_z2; tri_v3 /= tri_z3;

    tri_z1 = 1.0f/tri_z1; tri_z2 = 1.0f/tri_z2; tri_z3 = 1.0f/tri_z3;

    //- Work out deltas along edges

    float dx12 = (tri_x2-tri_x1)/(tri_y2-tri_y1), dx23 = (tri_x3-tri_x2)/(tri_y3-tri_y2), dx13 = (tri_x3-tri_x1)/(tri_y3-tri_y1);
    float dz12 = (tri_z2-tri_z1)/(tri_y2-tri_y1), dz23 = (tri_z3-tri_z2)/(tri_y3-tri_y2), dz13 = (tri_z3-tri_z1)/(tri_y3-tri_y1);
    float du12 = (tri_u2-tri_u1)/(tri_y2-tri_y1), du23 = (tri_u3-tri_u2)/(tri_y3-tri_y2), du13 = (tri_u3-tri_u1)/(tri_y3-tri_y1);
    float dv12 = (tri_v2-tri_v1)/(tri_y2-tri_y1), dv23 = (tri_v3-tri_v2)/(tri_y3-tri_y2), dv13 = (tri_v3-tri_v1)/(tri_y3-tri_y1);

    //- Round to pixel and clip to top & bottom of screen

    int y1 = (int)tri_y1; if(y1 < tri_y1) y1++;
    int y2 = (int)tri_y2; if(y2 < tri_y2) y2++;
    int y3 = (int)tri_y3; if(y3 < tri_y3) y3++;

    if(y1 < clip_y1) y1 = clip_y1;
    if(y2 < clip_y1) y2 = clip_y1;
    if(y3 < clip_y1) y3 = clip_y1;

    if(y1 > clip_y2) y1 = clip_y2;
    if(y2 > clip_y2) y2 = clip_y2;
    if(y3 > clip_y2) y3 = clip_y2;

    if(y3 <= y1) return;

    //- Calculate horizontal and vertical deltas for parameters

    float d = (tri_x3-tri_x1)*(tri_y2-tri_y1) - (tri_y3-tri_y1)*(tri_x2-tri_x1);

    float dzx = ( (tri_y2-tri_y1)*(tri_z3-tri_z1) + (tri_y1-tri_y3)*(tri_z2-tri_z1) ) / d;
    float dzy = ( (tri_x1-tri_x2)*(tri_z3-tri_z1) + (tri_x3-tri_x1)*(tri_z2-tri_z1) ) / d;

    float dux = ( (tri_y2-tri_y1)*(tri_u3-tri_u1) + (tri_y1-tri_y3)*(tri_u2-tri_u1) ) / d;
    float duy = ( (tri_x1-tri_x2)*(tri_u3-tri_u1) + (tri_x3-tri_x1)*(tri_u2-tri_u1) ) / d;

    float dvx = ( (tri_y2-tri_y1)*(tri_v3-tri_v1) + (tri_y1-tri_y3)*(tri_v2-tri_v1) ) / d;
    float dvy = ( (tri_x1-tri_x2)*(tri_v3-tri_v1) + (tri_x3-tri_x1)*(tri_v2-tri_v1) ) / d;

    //- See if we need to flip triangle horizontally

    boolean side13onleft = dx13 < dx12;

    //- Draw top of triangle

    float xa, xb, dxa, dxb;

    if(side13onleft)
    {
      xa = tri_x1 + dx13 * (y1-tri_y1);
      xb = tri_x1 + dx12 * (y1-tri_y1);
      dxa = dx13;
      dxb = dx12;
    }
    else
    {
      xa = tri_x1 + dx12 * (y1-tri_y1);
      xb = tri_x1 + dx13 * (y1-tri_y1);
      dxa = dx12;
      dxb = dx13;
    }

    float zl = tri_z1 - tri_x1*dzx + (y1-tri_y1)*dzy;
    float ul = tri_u1 - tri_x1*dux + (y1-tri_y1)*duy;
    float vl = tri_v1 - tri_x1*dvx + (y1-tri_y1)*dvy;

    for(j=y1; j<y2; j++)
    {
      int xai = (int)xa; if(xai < xa) xai++;
      int xbi = (int)xb; if(xbi < xb) xbi++;

      if(xai < clip_x1) xai = clip_x1;
      if(xbi < clip_x1) xbi = clip_x1;
      if(xai > clip_x2) xai = clip_x2;
      if(xbi > clip_x2) xbi = clip_x2;

      float z = zl + xai*dzx;
      float u = ul + xai*dux;
      float v = vl + xai*dvx;

      int o = j*w+xai;

      for(i=xai; i<xbi; i++)
      {
        //  Perspective per-pixel divide by Z happens here
        buf[o++] = tex[ ( (((int)(v/z))<<8) + ((int)(u/z)) ) & 0xFFFF ];
                //  use (((int)u)<<16)+(((int)v)<<8) for linear.
        z += dzx;
        u += dux;
        v += dvx;
      }

      xa += dxa; xb += dxb;

      zl += dzy;
      ul += duy;
      vl += dvy;
    }

    //- Draw bottom of triangle

    if(side13onleft)
    {
      xb = tri_x2 + dx23 * (y2-tri_y2);
      dxb = dx23;
    }
    else
    {
      xa = tri_x2 + dx23 * (y2-tri_y2);
      dxa = dx23;
    }

    for(j=y2; j<y3; j++)
    {
      int xai = (int)xa; if(xai < xa) xai++;
      int xbi = (int)xb; if(xbi < xb) xbi++;

      if(xai < clip_x1) xai = clip_x1;
      if(xbi < clip_x1) xbi = clip_x1;
      if(xai > clip_x2) xai = clip_x2;
      if(xbi > clip_x2) xbi = clip_x2;

      float z = zl + xai*dzx;
      float u = ul + xai*dux;
      float v = vl + xai*dvx;

      int o = j*w+xai;

      for(i=xai; i<xbi; i++)
      {
        //  Perspective per-pixel divide by Z happens here
        buf[o++] = tex[ ( (((int)(v/z))<<8) + ((int)(u/z)) ) & 0xFFFF ];
                //  use (((int)u)<<16)+(((int)v)<<8) for linear.
        z += dzx;
        u += dux;
        v += dvx;
      }

      xa += dxa; xb += dxb;

      zl += dzy;
      ul += duy;
      vl += dvy;
    }

  }

Files

Source
panorama.html 1,989 bytes
Related Articles

Instead of rotating the cube the texture can be warped and the cube and view point can remain static

This is a barebones renderer for one object, with a software solid triangle rasteriser

Games

The Dodge Game
Flatspace

2-Player Games:

Quake 2D
Meteora

Puzzle Games:

Mini Tetris
Sudoku Solver

Development

3D Graphics:

3D Graphics Articles
WebGL Examples
OpenGL Examples
Flash 3D Engine
Java 3D Engine

Development:

Programming Articles
Game Development Examples

Work

Portfolio
Clients
Startups & Projects
Expertise

Links

CubeLogix Studios
PHP Charts & Graphs
Local Legends Football