Jump to content
  • Advertisement
Sign in to follow this  
staticVoid2

texture mapping bug

This topic is 3805 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

hi, I've recently just noticed that my texture mapping function has a slight bug, see if you can notice, i've underlined the places there are offsets in the pixels: Free Image Hosting at www.ImageShack.us you can't notice it much here, but when you get up close it jumps all over the place. the code I use is really just the same as chris heckers although I've changed a few things like determining which side the middle vertice is on. here's the source code I'm using, it must be somthing wrong im my code, I don't think a bug in chris heckers code would have gone unnoticed.
struct EdgeI {
   EdgeI(const Gradients &gradients, Vertex *vertices, int Top, int Bottom);
   inline void Step();
   float X, XStep;
   int Y, Height;
   float OneOverZ, OneOverZStep;
   float UOverZ, UOverZStep;
   float VOverZ, VOverZStep;
};

EdgeI::EdgeI(const Gradients &gradients, Vertex *vertices, int Top, int Bottom)
{
   Y = ceil(vertices[Top].v.y);
   int YEnd = ceil(vertices[Bottom].v.y);
   Height = YEnd - Y;

   float YPrestep = Y - vertices[Top].v.y;

   float RealHeight = vertices[Bottom].v.y - vertices[Top].v.y;
   float RealWidth = vertices[Bottom].v.x - vertices[Top].v.x;

   X = ((RealWidth * YPrestep)/RealHeight) + vertices[Top].v.x;
   XStep = RealWidth/RealHeight;
   float XPrestep = X - vertices[Top].v.x;

   OneOverZ = gradients.aOneOverZ[Top] +
                 (YPrestep * gradients.dOneOverZdY) +
                 (XPrestep * gradients.dOneOverZdX);

   OneOverZStep = (XStep * gradients.dOneOverZdX) + gradients.dOneOverZdY;


   UOverZ = gradients.aUOverZ[Top] +
               (YPrestep * gradients.dUOverZdY) +
               (XPrestep * gradients.dUOverZdX);

   UOverZStep = (XStep * gradients.dUOverZdX) + gradients.dUOverZdY;

   VOverZ = gradients.aVOverZ[Top] +
               (YPrestep * gradients.dVOverZdY) +
               (XPrestep * gradients.dVOverZdX);

   VOverZStep = (XStep * gradients.dVOverZdX) + gradients.dVOverZdY;
}

inline void EdgeI::Step()
{
   X += XStep;
   Y++;
   Height--;
   OneOverZ += OneOverZStep;
   UOverZ += UOverZStep;
   VOverZ += VOverZStep;
}



struct Gradients {
   Gradients(Vertex *vertices);
   float aOneOverZ[3];
   float aUOverZ[3];
   float aVOverZ[3];
   float dOneOverZdX, dOneOverZdY;
   float dUOverZdX, dUOverZdY;
   float dVOverZdX, dVOverZdY;
};

Gradients::Gradients(Vertex *vertices)
{
   int Counter;

   float OneOverdX = 1/ ((vertices[1].v.x - vertices[2].v.x) *
                         (vertices[0].v.y - vertices[2].v.y) -
                         (vertices[0].v.x - vertices[2].v.x) *
                         (vertices[1].v.y - vertices[2].v.y));

   float OneOverdY = -OneOverdX;

	for(Counter = 0;Counter < 3;Counter++) {
		const float OneOverZ = 1/vertices[Counter].v.z;
		aOneOverZ[Counter] = OneOverZ;
		aUOverZ[Counter] = vertices[Counter].tc.u * OneOverZ;
		aVOverZ[Counter] = vertices[Counter].tc.v * OneOverZ;
	}

	dOneOverZdX = OneOverdX * (((aOneOverZ[1] - aOneOverZ[2]) *
					                (vertices[0].v.y - vertices[2].v.y)) -
					               ((aOneOverZ[0] - aOneOverZ[2]) *
					                (vertices[1].v.y - vertices[2].v.y)));


	dOneOverZdY = OneOverdY * (((aOneOverZ[1] - aOneOverZ[2]) *
										 (vertices[0].v.x - vertices[2].v.x)) -
										((aOneOverZ[0] - aOneOverZ[2]) *
										 (vertices[1].v.x - vertices[2].v.x)));

	dUOverZdX = OneOverdX * (((aUOverZ[1] - aUOverZ[2]) *
									  (vertices[0].v.y - vertices[2].v.y)) -
								    ((aUOverZ[0] - aUOverZ[2]) *
									  (vertices[1].v.y - vertices[2].v.y)));

	dUOverZdY = OneOverdY * (((aUOverZ[1] - aUOverZ[2]) *
									  (vertices[0].v.x - vertices[2].v.x)) -
									 ((aUOverZ[0] - aUOverZ[2]) *
									  (vertices[1].v.x - vertices[2].v.x)));

	dVOverZdX = OneOverdX * (((aVOverZ[1] - aVOverZ[2]) *
									  (vertices[0].v.y - vertices[2].v.y)) -
									 ((aVOverZ[0] - aVOverZ[2]) *
									  (vertices[1].v.y - vertices[2].v.y)));

	dVOverZdY = OneOverdY * (((aVOverZ[1] - aVOverZ[2]) *
									  (vertices[0].v.x - vertices[2].v.x)) -
									 ((aVOverZ[0] - aVOverZ[2]) *
									  (vertices[1].v.x - vertices[2].v.x)));

}


void Rasterizer::DrawScanLine(const Gradients &gradients, EdgeI *pLeft, EdgeI *pRight, UINT *texture, int text_pitch, UINT *screen_ptr, int mem_pitch)
{
   int XStart = ceil(pLeft->X);
   float XPrestep = XStart - pLeft->X;
   int Width = ceil(pRight->X) - XStart;

   float OneOverZ = pLeft->OneOverZ + (gradients.dOneOverZdX * XPrestep);
   float UOverZ = pLeft->UOverZ + (gradients.dUOverZdX * XPrestep);
   float VOverZ = pLeft->VOverZ + (gradients.dVOverZdX * XPrestep);

   screen_ptr += XStart;

   *screen_ptr = 0;

   if(Width > 0)
      while(Width--) {
			float Z = 1/OneOverZ;
         int U = UOverZ * Z;
         int V = VOverZ * Z;
         *(screen_ptr++) = *(texture + (V * text_pitch) + U);
         OneOverZ += gradients.dOneOverZdX;
         UOverZ += gradients.dUOverZdX;
         VOverZ += gradients.dVOverZdX;
      }

}

void Rasterizer::CHPerspective(Vertex *vertices, UINT *texture, int text_pitch, UINT *video_buffer, int mem_pitch)
{
   int Top, Middle, Bottom;
   float Y0 = vertices[0].v.y;
   float Y1 = vertices[1].v.y;
   float Y2 = vertices[2].v.y;



   if(Y0 < Y1) {
      if(Y2 < Y0) {
			Top = 2; Middle = 0; Bottom = 1;
      } else {
         Top = 0;
         if(Y1 < Y2) {
            Middle = 1; Bottom = 2;
         } else {
            Middle = 2; Bottom = 1;
         }
      }
   } else {
      if(Y2 < Y1) {
         Top = 2; Middle = 1; Bottom = 0;
      } else {
         Top = 1;
         if(Y0 < Y2) {
            Middle = 0; Bottom = 2;
         } else {
            Middle = 2; Bottom = 0;
         }
      }
   }

   Gradients gradients(vertices);
   EdgeI TopToBottom(gradients, vertices, Top, Bottom);
   EdgeI TopToMiddle(gradients, vertices, Top, Middle);
   EdgeI MiddleToBottom(gradients, vertices, Middle, Bottom);
   int MiddleIsLeft;
   EdgeI *pLeft, *pRight;

   if(TopToBottom.XStep > TopToMiddle.XStep) {
      MiddleIsLeft = 1;
      pLeft = &TopToMiddle; pRight = &TopToBottom;
   } else {
      MiddleIsLeft = 0;
      pLeft = &TopToBottom; pRight = &TopToMiddle;
   }

   int Height = TopToMiddle.Height;
   UINT *screen_ptr = video_buffer;
   screen_ptr += TopToBottom.Y * mem_pitch;

   while(Height--) {
      DrawScanLine(gradients, pLeft, pRight, texture, text_pitch, screen_ptr, mem_pitch);
      screen_ptr += mem_pitch;
      TopToMiddle.Step();
      TopToBottom.Step();
   }

   if(MiddleIsLeft) {
      pLeft = &MiddleToBottom; pRight = &TopToBottom;
   } else {
      pLeft = &TopToBottom; pRight = &MiddleToBottom;
   }

   Height = MiddleToBottom.Height;

   while(Height--) {
      DrawScanLine(gradients, pLeft, pRight, texture, text_pitch, screen_ptr, mem_pitch);
      screen_ptr += mem_pitch;
      MiddleToBottom.Step();
      TopToBottom.Step();
   }

}




any help would be appreciated. [Edited by - staticVoid2 on March 20, 2008 4:03:07 PM]

Share this post


Link to post
Share on other sites
Advertisement
Is there a true need for a custom texture mapping function, or would an established API like OpenGL or DirectX do..?

The problem you're experiencing is probably because of lacking or faulty perspective correction. Early PSone games (and PC aswell) suffered from this in the early 20's.

Share this post


Link to post
Share on other sites
This bug is actually in the original code aswell, I thought it was maybe just my version but I copied the code from the website and it's giving the same result.

Share this post


Link to post
Share on other sites
I think it's actually the floating point precision, because the difference of the uv coordinates at each vertex is getting smaller when you get closer up and the difference in xy is staying the same(when clipping anyway) then the interpolant value for u and v between vertices will get smaller and smaller, its value could be somthing like eg. 0.00000000000000000068398098, and would loose precision. could someone verify this? and is there any way, in visual c++, to change floating point precision without having to replace all "float" with "double"?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!