画家+Z-buffer算法

#include <GL/glut.h>
#include <iostream>
#include <cmath>
#include <conio.h>
using namespace std;

float* pixel; //定义像素点颜色指针,方便自定义三角形颜色,同时代替帧缓冲器
const int width = 600, length = 600;//窗口大小
float plane[3]; //存储空间直角坐标系平面方程系数ABC
float zBuff[length][width];//数组代替深度缓冲器,存储深度值

void init(void)
{
	glClearColor(1.0, 1.0, 0.0, 1.0);
	glMatrixMode(GL_PROJECTION);
	gluOrtho2D(0.0, 200.0, 0.0, 200.0);
}

void setPixel(int x, int y, float z, float r, float g, float b)
{
	if (z > zBuff[y][x])//如果(z(x,y)大于z缓存在(x,y)的值)
	{
		zBuff[y][x] = z;//把z(x,y)存入z缓存中(x,y)处
		pixel[3 * y * width + x * 3 + 0] = r;
		pixel[3 * y * width + x * 3 + 1] = g;
		pixel[3 * y * width + x * 3 + 2] = b;
	}
}

void zPlane(float x[], float y[], float z[])//计算出Ax + By + Cz + D = 0中的ABC系数
{
	float x1 = x[0];
	float x2 = x[1];
	float x3 = x[2];
	float y1 = y[0];
	float y2 = y[1];
	float y3 = y[2];
	float z1 = z[0];
	float z2 = z[1];
	float z3 = z[2];
	float temp = x1 * (y2 * z3 - y3 * z2) - y1 * (x2 * z3 - x3 * z2) + z1 * (x2 * y3 - x3 * y2);
	float A = (y3 * z2 - y2 * z3 + y1 * z3 - y3 * z1 + y2 * z1 - y1 * z2) / temp;
	float B = (x2 * z3 - x3 * z2 + x3 * z1 - x1 * z3 + x1 * z2 - x2 * z1) / temp;
	float C = (x3 * y2 - x2 * y3 + x1 * y3 - x3 * y1 + x2 * y1 - x1 * y2) / temp;
	plane[0] = A;
	plane[1] = B;
	plane[2] = C;
}

float Zs(float x, float y)
{
	float z = 0;
	z = (-plane[0] * x - plane[1] * y - 1) / plane[2];//由Ax + By + Cz + D = 0得,为了方便令D = 1
	return z;
}

//画三角形(画三角形部分是用的之前多边形代码改的,就不写注释了)
void triangleDraw(float x0, float y0, float z0, float x1, float y1, float z1, float x2, float y2, float z2, float r, float g, float b)
{
	float X[3];//存储三点顶点的x坐标,下同
	X[0] = x0;
	X[1] = x1;
	X[2] = x2;
	float Y[3];
	Y[0] = y0;
	Y[1] = y1;
	Y[2] = y2;
	float Z[3];
	Z[0] = z0;
	Z[1] = z1;
	Z[2] = z2;
	zPlane(X, Y, Z);//计算系数

	//顶点排序
	float xTemp[3], yTemp[3], zTemp[3];
	for (int i = 0; i < 3; i++)
	{
		xTemp[i] = X[i];
		yTemp[i] = Y[i];
		zTemp[i] = Z[i];
	}
	//找到三角形最小的y扫描线
	float temp = Y[0];
	int n = 0;
	for (int i = 1; i < 3; i++)
	{
		if (Y[i] < temp)
		{
			temp = Y[i];
			n = i;
		}
	}
	Y[0] = yTemp[n];
	X[0] = xTemp[n];
	Z[0] = zTemp[n];
	float yMin = temp;
	float xMin = xTemp[n];

	for (int i = 0, a = 0; i < 3; i++)
	{
		if (temp < yTemp[i])
		{
			a++;
			Y[a] = yTemp[i];
			X[a] = xTemp[i];
			Z[a] = zTemp[i];
			temp = yTemp[i];
		}
		else if (yTemp[i] >= yMin)
		{
			if (xTemp[i] != xMin)
			{
				float t1, t2, t3;
				t1 = Y[a];
				t2 = X[a];
				t3 = Z[a];
				Y[a] = yTemp[i];
				X[a] = xTemp[i];
				Z[a] = zTemp[i];
				Y[a + 1] = t1;
				X[a + 1] = t2;
				Z[a + 1] = t3;
				a++;
				yTemp[n] = yMin;
			}
		}
	}

	float y = Y[0];
	float xL = X[0], xR = X[0];
	float k1 = (y1 - y0) / (x1 - x0);//计算三角形边的斜率
	float k2 = (y2 - y1) / (x2 - x1);
	float k3 = (y2 - y0) / (x2 - x0);

	if (Y[0] != Y[1])
	{
		while (y < Y[2])
		{
			y++;
			if (y != Y[1])
			{
				xL = xL + 1 / k1;
				xR = xR + 1 / k3;

				for (int i = xL; i <= xR; i++)
				{
					setPixel(i, y, Zs(i, y), r, g, b);//填充像素
				}
			}
			else if (y == Y[1])
			{
				xL = xL + 1 / k1;
				xR = xR + 1 / k3;
				for (int i = xL; i <= xR; i++)
				{
					setPixel(i, y, Zs(i, y), r, g, b);
				}
				k1 = k2;
			}
		}
	}
	else if (Y[0] == Y[1])
	{
		xR = x1;
		for (int i = x0; i <= xR; i++)
		{
			setPixel(i, y, Zs(i, y), r, g, b);
		}
		while (y < Y[2])
		{
			y++;
			xL = xL + 1 / k1;
			xR = xR + 1 / k3;
			for (int i = xL; i <= xR; i++)
			{
				setPixel(i, y, Zs(i, y), r, g, b);
			}
		}
	}
}

void display(void)
{
	glClear(GL_COLOR_BUFFER_BIT);  // 清理窗口缓存
	glLoadIdentity();
	glDrawPixels(width, length, GL_RGB, GL_FLOAT, pixel);//初始化背景色
	glFlush();
}

void buffer(int argc, char** argv) {//同一平面按作图顺序作画
	glutInit(&argc, argv);                         // 初始化
	glutInitWindowSize(width, length);      // 设置显示窗口的大小
	glutCreateWindow("z-buffer算法");
	//           x0   y0  z0  x1   y1   z1  x2   y2    z2  r  g    b
	triangleDraw(100, 130, 3, 30, 300, 3, 180, 300, 6, 0, 0.3, 1); //蓝
	triangleDraw(120, 180, 5, 60, 340, 5, 600, 400, 4, 1, 0.8, 0); //黄
	triangleDraw(450, 220, 3, 0, 360, 3, 420, 460, 6, 1, 0, 1); //粉
	init();
	glutDisplayFunc(display);       // 发送图形到显示窗口
	glutMainLoop();                  // 循环显示图像,防闪退
}

void draw(int argc, char** argv) {//通过z缓冲器存储深度
	glutInit(&argc, argv);                         // 初始化
	glutInitWindowSize(width, length);      // 设置显示窗口的大小
	glutCreateWindow("画家算法");
	//           x0   y0  z0  x1   y1   z1  x2   y2    z2  r  g    b
	triangleDraw(120, 180, 3, 60, 340, 3, 600, 400, 3, 1, 0.8, 0); //黄
	triangleDraw(100, 130, 3, 30, 300, 3, 180, 300, 3, 0, 0.3, 1); //蓝	
	triangleDraw(450, 220, 3, 0, 360, 3, 420, 460, 3, 1, 0, 1); //粉
	init();
	glutDisplayFunc(display);       // 发送图形到显示窗口
	glutMainLoop();                     // 循环显示图像,防闪退
}

int main()
{
	float x0[9], y0[9], z0[9], x1[9], y1[9], z1[9], x2[9], y2[9], z2[9], r[9], g[9], b[9];
	int flag;
	for (int i = 0; i < length; i++)
	{
		for (int j = 0; j < width; j++)
		{
			zBuff[i][j] = -0xffffffff;//定义最小深度值 
		}
	}
	pixel = new float[3 * width * length];//定义像素点
	cout << "按序号输入算法类型(1或2)" << endl << "1.画家算法 2.Z-buffer算法:" << endl;
	cin >> flag;
	if (flag == 1)
		draw(NULL, NULL);
	else if(flag == 2)
		buffer(NULL,NULL);
	return 0;
}

posted @ 2020-08-17 15:28  TdFoil  阅读(960)  评论(0)    收藏  举报