home games dev
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

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

Images

Comments

Related Articles

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

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

Sponsored Links

Toys & Games:

Doggie Doo
Nerf Vortex
Monster High
Lagoona Hydration Station
Milky Bunny
Moshling Tree House
Lego Ninja Go Fire Temple
Fireman Sam Pontypandy Rescue
Rock Elmo
Star Wars Ultimate Force Lightsaber

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
Flash 3D Engine
Java 3D Engine

Development:

Programming Articles
Animation Demos
Game Development Examples

Links

iBuddy Social Network
Local Legends Football
PHP Charts & Graphs
CubeLogix Studios