PART ONE
codes.cpp
#include <stdio.h>
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <iostream>
using namespace std;
#define width 222
#define height 207
#define num 2 //计数器
struct Vector3f {
GLfloat x;
GLfloat y;
GLfloat z;
};
struct Color {
GLubyte r;
GLubyte g;
GLubyte b;
GLubyte a;
};
Color interp_color(Color c0, Color c1, float i)
{
Color c;
c.r = (1 - i) * c0.r + i * c1.r;
c.g = (1 - i) * c0.g + i * c1.g;
c.b = (1 - i) * c0.b + i * c1.b;
c.a = (1 - i) * c0.a + i * c1.a;
return c;
}
GLubyte image[height][width][4];
void initLines()
{
//定义NDC下的顶点数据
Vector3f points[num]{
{0.0f,0.5f,0.0f},
{0.5f,0.0f,0.0f},
};
//定义颜色数据
Color color[num]{
{255,0,0,0},
{0,255,0,0}
};
//将NDC坐标转换成屏幕坐标
for (int i = 0; i < num; i++)
{
points[i].x = (points[i].x + 1.0f) * (width / 2 - 1);
points[i].y = (points[i].y + 1.0f) * (height / 2 - 1);
points[i].z = 0; //zbuffer统一设置为0
}
for (int i = 0; i < num; i += 2) { //num=2 启用GL_LINES
//定义线的起点
int start = i;
int start_x = (int)points[start].x;
int start_y = (int)points[start].y;
Color c0 = color[start];
//定义线的终点 两两相邻取点
int end;
int end_x;
int end_y;
Color c1;
if (i == num - 1) {
end_x = (int)points[0].x;
end_y = (int)points[0].y;
c1 = color[0];
}
else {
end = i + 1;
end_x = (int)points[end].x;
end_y = (int)points[end].y;
c1 = color[end];
}
//对点进行x轴排序
if (start_x > end_x) {
swap(start_x, end_x);
swap(start_y, end_y);
swap(c0, c1);
}
//斜率法画线
float delta_x = end_x - start_x;
float delta_y = end_y - start_y;
float lineWidth = 1.0f;//线宽设置为1
//颜色插值画线
if (delta_x == 0) {
if (delta_y < 0) {
swap(start_y, end_y);
swap(c0, c1);
}
for (int y = start_y, x = start_x; y <= end_y; y++) {
//插值系数i根据y轴计算
float i = (float)(y - start_y) / (end_y - start_y);
Color icolor = interp_color(c0,c1,i);
image[y][x][0] = icolor.r;
image[y][x][1] = icolor.g;
image[y][x][2] = icolor.b;
image[y][x][3] = icolor.a;
}
}
else {
float gradient = (float)delta_y / delta_x;
for (int x = start_x; x <= end_x; x++) {
//插值系数i根据x轴计算
float i = (float)(x-start_x) /(end_x - start_x);
Color icolor = interp_color(c0, c1, i);
//直线斜率公式
int y = (int)(gradient * (x - start_x) + start_y);
image[y][x][0] = icolor.r;
image[y][x][1] = icolor.g;
image[y][x][2] = icolor.b;
image[y][x][3] = icolor.a;
}
}
}
}
void render()
{
glClear(GL_COLOR_BUFFER_BIT);
glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, image);
glutSwapBuffers();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(width, height);
glutInitWindowPosition(200, 100);
int id = glutCreateWindow("彩色线段");
GLenum err = glewInit();
if (err != GLEW_OK) {
fprintf(stderr, "Error: '%s'\n", glewGetErrorString(err));
return 1;
}
initLines();
glutDisplayFunc(render);
glutMainLoop();
return 0;
}
部分二
代码分析
1、在initLines()函数中,利用顶点索引坐标start和end在color[num]中进行顶点颜色的采样,得到点对{start:end}对应的颜色属性{c0:c1}。在根据x轴对顶点进行排序时,颜色属性同步处理。在“delta_x == 0”时,如果“delta_y < 0”,颜色属性亦同步处理,否则根据y轴坐标获取插值系数“i”。又因为已经采样出点对{start:end}对应的颜色属性{c0:c1},故可以利用颜色属性{c0:c1}、插值系数“i”,在函数interp_color( , , )中完成颜色的插值interp_color(c0, c1, i),得到不同像素点对应的颜色属性icolor,将线段覆盖的像素对应的颜色属性icolor写入image[height][width][4]。
2、在render()中,利用glDrawPixels(, , , , image)完成对image[height][width][4]中像素信息的绘制,之后SwapBuffer显示到屏幕。