Jump to content
  • Advertisement
Sign in to follow this  
dawidjoubert

LERP colour line (gourand shading - algorith)

This topic is 4518 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 am having trouble making a line function that renders a fade from one colour to another. Here is my output at the moment: tempo.jpg Here is the relevant code
struct CColor4f
{
	float r,g,b,a;
	CColor4f() {r=g=b=a=1.0f;};
	CColor4f(float rr,float gg,float bb,float aa = 1.0f) {r=rr;g=gg;b=bb;a=aa;};

	unsigned int GetColor()
	{
		if (a < 0.0f) a = 0.0f;
		if (r < 0.0f) r = 0.0f;
		if (g < 0.0f) g = 0.0f;
		if (b < 0.0f) b = 0.0f;
		if (a > 1.0f) a = 1.0f;
		if (r > 1.0f) r = 1.0f;
		if (g > 1.0f) g = 1.0f;
		if (b > 1.0f) b = 1.0f;
		return ((unsigned int(255.0f*a)) << 24) + ((unsigned int(255.0f*r))<< 16) + ((unsigned int(255.0f*g))<< 8) +(unsigned int(255.0f*b));
	};
	CColor4f operator-(CColor4f n)
	{
		return CColor4f(r-n.r,g-n.g,b-n.b,a-n.a);
	};
	CColor4f operator+(CColor4f n)
	{
		return CColor4f(r+n.r,g+n.g,b+n.b,a+n.a);
	};
	CColor4f operator*(float m)
	{
		return CColor4f(r*m,g*m,b*m,a*m);	
	};
	CColor4f operator/(float m)
	{
		return CColor4f(r/m,g/m,b/m,a/m);	
	};
};

// Render a double colour line
void putLine(int x1,int y1,CColor4f *c1,int x2,int y2,CColor4f *c2)
{
	CColor4f *tempColor;
	int t;
	// Make sure x1 is smaller than x2
	if (x1 > x2) 
	{	// Swap input
		t = y1;	
		y1 = y2;
		y2 = t;
		t=x1;
		x1 = x2; 
		x2 = t; 
		tempColor=c1;
		c1=c2;
		c2=tempColor;
	};

	// Cancel absurd case
	if (x1 >= g_iWidth) return;
	if (x2 < 0) return;

	bool divideByZero = false;

	// Find the gradient of the slope
	float deltaX = float(x2-x1);
	float slope1 = float(y2-y1)/deltaX;
	float c = float(y1) - float(x1)*slope1;

	// check if the intersection of the line and the y axis has a larger and smaller x respectively
	//y = mx+c,x = y-c/m
	/*float temp = (y1 - c) / slope1;
	if (*/

	if (x1 == x2) 
	{	
		divideByZero = true;
		slope1 = 10.0f;
	}

	if (fabs(slope1)  < 1.0f)
	{
		int sx,ex;

		// Clip our drawing range
		if (x1 < 0) sx = 0;
			else sx = x1;
		if (x2 >= g_iWidth) ex = g_iWidth-1;
			else ex = x2;

		// Okay now we need to find the slope of each colour!
		CColor4f deltaC = (*c2-*c1)/deltaX;

		unsigned int *start = (g_puiScreen) + (y2 * g_iScreenMultiple);
		for (int x=sx;x < ex;x++)
		{
			int lineoffset = int(float(x)*slope1+c) * (g_iScreenMultiple);
			g_puiScreen[lineoffset + x] = (*c1 + deltaC * float(x)).GetColor(); // Colour = Colour1 + (Colour2-Colour1) * x/deltaX
																					// Colour = Colour1 + (Colour2-Colour1)/deltaX * x
		//	putPixel(x,float(x)*slope1+c,color);
		}
	}
	else
	{
		int sy,ey;
		// Make sure y1 is smaller than y2
		if (y1 > y2) 
		{	
			t = y1;
			y1 = y2;
			y2 = t;
			t=x1;
			x1 = x2;
			x2 = t;
			tempColor=c1;
			c1=c2;
			c2=tempColor;
		};
		float deltaY = float(y2-y1);
		// Clip our drawing range
		if (y1 < 0) sy = 0;
			else sy = y1;
		if (y2 >= g_iHeight) ey = g_iHeight-1;
			else ey = y2;
		if (divideByZero) slope1 = 0;
			else slope1 = 1.0f / slope1;	// Inverse slope

		// Okay now we need to find the slope of each colour!
		CColor4f deltaC = (*c2-*c1)/deltaY;

		for (int y=sy;y < ey;y++)
		{
			int lineoffset = y * (g_iScreenMultiple);
			g_puiScreen[lineoffset + int((float(y)-c)*slope1)] = (*c1 + deltaC * float(y)).GetColor(); // Colour = Colour1 + (Colour2-Colour1) * y/deltaY
																											// Colour = Colour1 + (Colour2-Colour1)/deltaY * y
		}
	}

};

As you can see I have tried to patch the error a bit by adding
		if (a < 0.0f) a = 0.0f;
		if (r < 0.0f) r = 0.0f;
		if (g < 0.0f) g = 0.0f;
		if (b < 0.0f) b = 0.0f;
		if (a > 1.0f) a = 1.0f;
		if (r > 1.0f) r = 1.0f;
		if (g > 1.0f) g = 1.0f;
		if (b > 1.0f) b = 1.0f;
Without it this is how the render looks: tempo2.jpg

Share this post


Link to post
Share on other sites
Advertisement
1). After a quick look, I don't like this line:

return ((unsigned int(255.0f*a)) << 24) + ((unsigned int(255.0f*r))<< 16) + ((unsigned int(255.0f*g))<< 8) +(unsigned int(255.0f*b));


Casting a float to an int is going to lose you some precision. I'm not sure if this is your problem, but it can't be good.

I think you're making it more difficult than it actually is. To fade from one color to the other, you can just use a LERP equation:

newColor = (1 - currentLinePercent)startColor + (currentLinePercent * endColor)

- newColor (r,g,b) is the color of your line.
- currentLinePercent is the line number you're on divided by the total lines in the quarter circle (as based on your pictures).
- startColor and endColor are obvious. Both are (r,g,b) triplets.

2). Capping the alpha/r/g/b values to the 0-1 range is a good idea.

3). Use [ source ] [ /source ] tags instead of [ code ] [ /code ] tags. It makes it easier to read :)

Share this post


Link to post
Share on other sites
Quote:
Original post by Doggan
1). After a quick look, I don't like this line:

return ((unsigned int(255.0f*a)) << 24) + ((unsigned int(255.0f*r))<< 16) + ((unsigned int(255.0f*g))<< 8) +(unsigned int(255.0f*b));


Casting a float to an int is going to lose you some precision. I'm not sure if this is your problem, but it can't be good.
3). Use [ source ] [ /source ] tags instead of [ code ] [ /code ] tags. It makes it easier to read :)


How do I get rid of the type casting?

// Here is my improved version, It still type casts but now handles the wrapping correctly

unsigned int ret;
char mr,mg,ma,mb;
mr = char(twopower8f*r);
mg = char(twopower8f*g);
mb = char(twopower8f*b);
ma = char(twopower8f*a);
__asm
{
//mov edi,[ret] // Get the memory address of ret
mov ah,ma
mov al,mr
shl eax,16
mov ah,mg
mov al,mb

// Okay so my colour is now stored in eax
mov ret,eax
}
return ret;




Okay but I am seriously considering changing from using floats to bytes for the storage of the colours





PS Thanks your percentage thing works...

[Edited by - dawidjoubert on April 5, 2006 9:52:55 AM]

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!