Skip to main content
3 of 6
added 422 characters in body
user avatar
user avatar

How to rasterize a line when the background color is not always white?

I've to rasterize a line taking into account not only the background color of the screen, which is white, but also the color of other objects in the scene. In my case, I've just another object, a sphere, which is actually visualized using a ray tracing technique.

So far the code that I have seems only to consider the white background color of the screen and not also the color of the sphere.

So here's the code:

  // ray tracing of the sphere
  // here we initialize the z-buffer's elements to -1.0 zBuffer that you find below
  ...

  //
  // rasterize a line
  //

  // line from p1 to p2 in LOCAL coordinates
  Point3d p1 (-1.0, 0.0, 0.0);
  Point3d p2 ( 1.0, 0.0, 0.0);

  // transformations...
    Matrix4d S  = Matrix4d::scaling (5.0, 1.0, 1.0);
    Matrix4d R1 = Matrix4d::rotation (0.5,'z');
    Matrix4d R2 = Matrix4d::rotation (tau,'x');
    Matrix4d T  = Matrix4d::translation (0.0, 0.0, 8.0);    

  Matrix4d M  = T*R2*R1*S;

  p1 = M*p1;
  p2 = M*p2;

  // screen coordinates
  double x1 = ( X + p1.x()/p1.z() ) / s - 0.5;
  double y1 = ( Y - p1.y()/p1.z() ) / s - 0.5;
  double x2 = ( X + p2.x()/p2.z() ) / s - 0.5;
  double y2 = ( Y - p2.y()/p2.z() ) / s - 0.5;

  //
  // line rasterization algorithm with anti-aliasing and z-test
  // (for lines with slope between -1 and 1)
  //
  int x  = round(x1);
  int y  = round(y1);

  double I0 = 1.0;
  double m = (y2-y1) / (x2-x1);

  bool up = true;
  if (y2 < y1) {
    m = -m;
    I0 = 0.0;
    up = false;
  }

  int nextY;
  double z;
  for ( ; x<=x2; x++) {
    if (up)
      nextY = y+1;
    else
      nextY = y-1;

    // barycentric coordinates of the current point: (1-lambda, lambda),
    // i.e.: x = (1-lambda) x1 + lambda x2
    double lambda = (x-x1) / (x2-x1);

    // perspectively correct linear interpolation of z-values
    z = p1.z()*p2.z() / ( (1.0-lambda)*p2.z() + lambda*p1.z() );

    if ( (zBuffer[x+y*w] < 0) || z < zBuffer[x+y*w] ) {
      int I = (int) 255*I0;
        image->setPixel( x, y,     qRgb( 255-I, 255, 255-I ) );
        image->setPixel( x, nextY, qRgb(     I, 255,     I ) );
    }

    if (m > I0) {
      y  = nextY;
      I0 += 1.0;
    }
    I0 -= m;
  }


  // repaint canvas
  repaint();
} 

Now the output is not as expected, because one of the pixels of the lines on the sphere is coloured white. Of course we notice this immediately! The idea is to make a smoother line that considers not only the colour of the background but also the colour of the sphere.

I thought I need to interpolate colours, but I'm not sure which ones and how to do it. I know that the basic idea of interpolation is to find an intermediate colour between two (or more) colours ($C_1, C_2$) using a formula as follows:

$$(1 - \alpha) C_1 + \alpha * C_2$$

Now the problem is that I don't know what's exactly $\alpha$ and which colours would be $C_1$ and $C_2$. I thought $\alpha$ could be the lambda variable in the code above, but this is more than a guess than a conclusion after a logical reasoning.

Moreover, I guessed that the colours $C_1$ and $C_2$ are respectively the color of the pixel before the rasterization of the line (i.e. in the ray tracing part), which can also be the color of the sphere, if that pixel is covered by the sphere, or the background color, i.e. white in my case.

Any help is appreciated.

To give you an idea, this is the wrong output:

enter image description here

and this should be the correct one:

enter image description here

Note (if you zoom in) that the line in the first picture is not that smooth over the sphere, because one of the pixels (at least) is colored for the background color white.

user4718