Panorama Viewer

Placing the viewpoint inside the cube and making the faces of the cube textured

Articles

Java applet, run by CheerpJ. Main class: House

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;
}

}

Source 7 files