OpenGL接口的基本实现3[转]
目录
普通三角形
//三角形边信息,从y低到高 class Ege { public: int _x1; int _y1; int _x2; int _y2; Ege(int x1,int y1,int x2,int y2) { if (y1 < y2) { _x1 = x1; _y1 = y1; _x2 = x2; _y2 = y2; } else { _x1 = x2; _y1 = y2; _x2 = x1; _y2 = y1; } } }; //水平线段,从x小到大 class Span { public: int _xStart; int _xEnd; int _y; public: Span(int xStart,int xEnd,int y) { if (xStart < xEnd) { _xStart = xStart; _xEnd = xEnd; _y = y; } else { _xStart = _xEnd; _xEnd = _xStart; _y = y; } } }; //绘制从一个边到另一个边的水平线 void drawSpan(const Span& span) { for (int x = span._xStart ; x < span._xEnd; ++ x) { setPixel(x,span._y,_color); } } //通过两条边信息画出一个三角形 e1长边 e2短边 void drawEge(const Ege& e1,const Ege& e2) { //获取最长的一条边的y轴跨度 float yOffset1 = e1._y2 - e1._y1; if (yOffset1 == 0) { return; } //获取另一条边的y轴跨度 float yOffset = e2._y2 - e2._y1; if (yOffset == 0) { return; } //e2边 x方向上最大跨度 float xOffset = e2._x2 - e2._x1; //x水平移动距离 float scale = 0; //看做相似三角形,等比例问题 //增长一个y轴像素,x轴增加多少 float step = 1.0f/yOffset; //e1长边x方向上最大跨度 float xOffset1 = e1._x2 - e1._x1; //起点位置 float scale1 = (float)(e2._y1 - e1._y1)/yOffset1; //增长一个y轴像素, x水平移动距离 float step1 = 1.0f/yOffset1; //y轴以一格像素递增,以短边为基准 for (int y = e2._y1 ; y < e2._y2 ; ++ y) { int x1 = e1._x1 + (int)(scale1 * xOffset1); int x2 = e2._x1 + (int)(scale * xOffset); Span span(x1,x2,y); drawSpan(span); //y轴每增加一个像素,x轴移动等比例的像素单位 scale += step; scale1 += step1; } } //绘制三角形 void drawTriangle(int2 p0,int2 p1,int2 p2) { //由三个定点信息生成三条边 Ege eges[3] = { Ege(p0.x,p0.y,p1.x,p1.y), Ege(p1.x,p1.y,p2.x,p2.y), Ege(p2.x,p2.y,p0.x,p0.y), }; int iMax = 0; //寻找y轴跨度最大的边 //先获取一条边的y轴 int length = eges[0]._y2 - eges[0]._y1; //遍历,获取y轴跨度最大的边 for (int i = 1 ;i < 3 ; ++ i) { int len = eges[i]._y2 - eges[i]._y1; if (len > length) { length = len; iMax = i; } } int iShort1 = (iMax + 1)%3; int iShort2 = (iMax + 2)%3; drawEge(eges[iMax],eges[iShort1]); drawEge(eges[iMax],eges[iShort2]); }
- 输出:
添加颜色
class Span { public: int _xStart; int _xEnd; Rgba _colorStart; Rgba _colorEnd; int _y; public: Span(int xStart, int xEnd, int y, Rgba colorStart, Rgba colorEnd) { if (xStart < xEnd) { _xStart = xStart; _xEnd = xEnd; _colorStart = colorStart; _colorEnd = colorEnd; _y = y; } else { _xStart = _xEnd; _xEnd = _xStart; _colorStart = colorEnd; _colorEnd = colorStart; _y = y; } } }; class Ege { public: int _x1; int _y1; Rgba _color1; int _x2; int _y2; Rgba _color2; Ege(int x1, int y1, Rgba color1, int x2, int y2, Rgba color2) { if (y1 < y2) { _x1 = x1; _y1 = y1; _color1 = color1; _x2 = x2; _y2 = y2; _color2 = color2; } else { _x1 = x2; _y1 = y2; _color1 = color2; _x2 = x1; _y2 = y1; _color2 = color1; } } }; void drawTriangle(int2 p0, int2 p1, int2 p2, Rgba c0, Rgba c1, Rgba c2) { Ege eges[3] = { Ege(p0.x,p0.y,c0, p1.x,p1.y,c1), Ege(p1.x,p1.y,c1, p2.x,p2.y,c2), Ege(p2.x,p2.y,c2, p0.x,p0.y,c0), }; int iMax = 0; int length = eges[0]._y2 - eges[0]._y1; for (int i = 1; i < 3; ++i) { int len = eges[i]._y2 - eges[i]._y1; if (len > length) { length = len; iMax = i; } } int iShort1 = (iMax + 1) % 3; int iShort2 = (iMax + 2) % 3; drawEge(eges[iMax], eges[iShort1]); drawEge(eges[iMax], eges[iShort2]); } void drawEge(const Ege& e1, const Ege& e2) { float yOffset1 = e1._y2 - e1._y1; if (yOffset1 == 0) { return; } float yOffset = e2._y2 - e2._y1; if (yOffset == 0) { return; } float xOffset = e2._x2 - e2._x1; float scale = 0; float step = 1.0f / yOffset; float xOffset1 = e1._x2 - e1._x1; float scale1 = (float)(e2._y1 - e1._y1) / yOffset1; float step1 = 1.0f / yOffset1; for (int y = e2._y1; y < e2._y2; ++y) { int x1 = e1._x1 + (int)(scale1 * xOffset1); int x2 = e2._x1 + (int)(scale * xOffset); Rgba color2 = colorLerp(e2._color1, e2._color2, scale); Rgba color1 = colorLerp(e1._color1, e1._color2, scale1); Span span(x1, x2, y, color1, color2); drawSpan(span); scale += step; scale1 += step1; } } void drawSpan(const Span& span) { float length = span._xEnd - span._xStart; for (int x = span._xStart; x < span._xEnd; ++x) { Rgba color = colorLerp( span._colorStart ,span._colorEnd ,(float)(x - span._xStart) / length ); setPixel(x, span._y, color); } }
- 显示:
- 优化1:
void drawSpan(const Span& span) { float length = span._xEnd - span._xStart; float scale = 0; float step = 1.0f/length; for (int x = span._xStart ; x < span._xEnd; ++ x) { Rgba color = colorLerp( span._colorStart ,span._colorEnd ,scale ); scale += step; setPixel(x,span._y,color); } }
- 优化2:
- 优化3:
- 三角形的点在视图窗口左右两侧外的情况:
void drawSpan(const Span& span) { float length = span._xEnd - span._xStart; float scale = 0; float step = 1.0f/length; int startX = tmax<int>(span._xStart,0); int endX = tmin<int>(span._xEnd,_width); scale += (startX - span._xStart)/length; for (int x = startX ; x < endX; ++ x) { Rgba color = colorLerp( span._colorStart ,span._colorEnd ,scale ); scale += step; setPixelEx(x,span._y,color); } }
- 三角形的点在视图窗口上下两侧外的情况:
void drawEge(const Ege& e1,const Ege& e2) { float yOffset1 = e1._y2 - e1._y1; if (yOffset1 == 0) { return; } float yOffset = e2._y2 - e2._y1; if (yOffset == 0) { return; } float xOffset = e2._x2 - e2._x1; float scale = 0; float step = 1.0f/yOffset; int startY = tmax<int>(e2._y1,0); int endY = tmin<int>(e2._y2,_height); scale += (startY - e2._y1)/yOffset; float xOffset1 = e1._x2 - e1._x1; float scale1 = (float)(e2._y1 - e1._y1)/yOffset1; float step1 = 1.0f/yOffset1; int startY1 = tmax<int>(e1._y1,0); int endY1 = tmin<int>(e1._y2,_height); scale1 += (startY1 - e1._y1)/yOffset1; for (int y = startY ; y < endY ; ++ y) { int x1 = e1._x1 + (int)(scale1 * xOffset1); int x2 = e2._x1 + (int)(scale * xOffset); Rgba color2 = colorLerp(e2._color1,e2._color2,scale); Rgba color1 = colorLerp(e1._color1,e1._color2,scale1); Span span(x1,x2,y,color1,color2); drawSpan(span); scale += step; scale1 += step1; } }