OpenGL光栅化画直线代码

代码中把画直线算法(Bresenham 直线算法)封装为一个函数,把画直线算法生成的像素点覆盖vertices[]数组中的点,并通过glDrawArrays(GL_POINTS, 0, counts)画出来,counts为直线上像素点的个数。

具体要求为程序中用户给定直线两个端点的坐标(斜率在0到1之间),然后在窗口中画出直线

存档一下主要代码

// Bresenham直线算法
void drawLineBresenham(int x0, int y0, int x1, int y1, std::vector<float>& vertices) {
	int dx = abs(x1 - x0);
	int dy = abs(y1 - y0);
	int sx = (x0 < x1) ? 1 : -1;
	int sy = (y0 < y1) ? 1 : -1;
	int err = dx - dy;

	while (true) {
		// 添加当前点到vertices数组
		vertices.push_back(x0);
		vertices.push_back(y0);
		vertices.push_back(1.0f); // red color
		vertices.push_back(0.0f);
		vertices.push_back(0.0f);

		if (x0 == x1 && y0 == y1) break;
		int e2 = err * 2;
		if (e2 > -dy) {
			err -= dy;
			x0 += sx;
		}
		if (e2 < dx) {
			err += dx;
			y0 += sy;
		}
	}
}

int main()
{
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

#ifdef __APPLE__
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X
#endif

	GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
	if (window == NULL)
	{
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);
	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
	glfwSetMouseButtonCallback(window, mouse_button_callback);

	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		std::cout << "Failed to initialize GLAD" << std::endl;
		return -1;
	}

	Shader ourShader("3.3.shader.vert", "3.3.shader.frag"); // you can name your shader files however you like
	std::vector<float> vertices;

	// 用户给定的直线端点
	int x0 = 50, y0 = 50;
	int x1 = 750, y1 = 550;

	// 使用Bresenham算法计算直线上的像素点
	drawLineBresenham(x0, y0, x1, y1, vertices);

	unsigned int VBO, VAO;
	glGenVertexArrays(1, &VAO);
	glGenBuffers(1, &VBO);
	glBindVertexArray(VAO);

	glBindBuffer(GL_ARRAY_BUFFER, VBO);

	int t = sizeof(vertices);
	t = t * sizeof(float);
	glBufferData(GL_ARRAY_BUFFER, sizeof(float)* vertices.size(), &vertices[0], GL_STATIC_DRAW);

	// position attribute
	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
	// color attribute
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(2 * sizeof(float)));
	glEnableVertexAttribArray(1);

	glm::mat4 proj = glm::ortho(0.0f, 800.0f, 0.0f, 600.0f, 0.1f, 100.0f);

	glm::mat4 model = glm::mat4(1.0f);
	glm::mat4 view = glm::mat4(1.0f);

	while (!glfwWindowShouldClose(window))
	{

		processInput(window);

		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		ourShader.use();
		glm::mat4 proj = glm::ortho(0.0f, 800.0f, 0.0f, 600.0f, 0.1f, 100.0f);

		glm::mat4 model = glm::translate(glm::mat4(1.0f), glm::vec3(0.0, 0.0, -10.0));
		glm::mat4 view = glm::mat4(1.0f);

		unsigned int modelLoc = glGetUniformLocation(ourShader.ID, "model");
		unsigned int viewLoc = glGetUniformLocation(ourShader.ID, "view");
		unsigned int projectLoc = glGetUniformLocation(ourShader.ID, "projection");
		glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
		glUniformMatrix4fv(viewLoc, 1, GL_FALSE, &view[0][0]);
		glUniformMatrix4fv(projectLoc, 1, GL_FALSE, glm::value_ptr(proj));

		glBindVertexArray(VAO);
		glDrawArrays(GL_POINTS, 0, vertices.size() / 5);  // count = number of points in vertices
		glfwSwapBuffers(window);
		glfwPollEvents();
	}

	glDeleteVertexArrays(1, &VAO);
	glDeleteBuffers(1, &VBO);

	glfwTerminate();
	return 0;
}

void processInput(GLFWwindow *window)
{
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
		glfwSetWindowShouldClose(window, true);
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
	glViewport(0, 0, width, height);
}

void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
	if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS)
	{
		double* x_pos = new double;
		double* y_pos = new double;
		glfwGetCursorPos(window, x_pos, y_pos);
		double x = *x_pos;
		double y = *y_pos;
	}
}

程序中用户给定直线两个端点的坐标(需要处理所有斜率),然后在窗口中画出直线。


// 计算直线的像素点并更新 vertices 数组
void bresenhamLine(int x1, int y1, int x2, int y2, std::vector<float>& vertices) {
	int dx = x2 - x1;
	int dy = y2 - y1;
	int dx1 = 2 * abs(dx);
	int dy1 = 2 * abs(dy);
	int twody1 = 2 * dy1;
	int twodx1 = 2 * dx1;

	int x = x1;
	int y = y1;

	int xEnd, yEnd;

	if (dx >= dy) { // 处理水平或者接近水平的情况
		if (x1 > x2) {
			std::swap(x1, x2);
			std::swap(y1, y2);
		}
		x = x1;
		y = y1;
		xEnd = x2;

		if (dy < 0) {
			dy1 = -dy1;
		}

		int slope1 = dy1 - dx1;

		for (; x <= xEnd; x++) {
			vertices.push_back(x);
			vertices.push_back(y);
			vertices.push_back(1.0f);  // 红色
			vertices.push_back(0.0f);  // 绿色
			vertices.push_back(0.0f);  // 蓝色

			if (slope1 >= 0) {
				y += (y2 > y1) ? 1 : -1;
				slope1 -= twodx1;
			}
			slope1 += dy1;
		}
	}
	else { // 处理竖直或者接近竖直的情况
		if (y1 > y2) {
			std::swap(x1, x2);
			std::swap(y1, y2);
		}
		x = x1;
		y = y1;
		yEnd = y2;

		if (dx < 0) {
			dx1 = -dx1;
		}

		int slope2 = dx1 - dy1;

		for (; y <= yEnd; y++) {
			vertices.push_back(x);
			vertices.push_back(y);
			vertices.push_back(1.0f);  // 红色
			vertices.push_back(0.0f);  // 绿色
			vertices.push_back(0.0f);  // 蓝色

			if (slope2 >= 0) {
				x += (x2 > x1) ? 1 : -1;
				slope2 -= twodx1;
			}
			slope2 += dy1;
		}
	}
}

// 主程序
int main()
{
	if (!glfwInit()) {
		std::cout << "Failed to initialize GLFW" << std::endl;
		return -1;
	}

	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	GLFWwindow* window = glfwCreateWindow(800, 600, "Bresenham Line", NULL, NULL);
	if (!window) {
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
		std::cout << "Failed to initialize GLAD" << std::endl;
		return -1;
	}

	// 设置视口
	glViewport(0, 0, 800, 600);

	// 设置着色器
	const char* vertexShaderSource = R"(
    #version 330 core
    layout(location = 0) in vec2 aPos;
    layout(location = 1) in vec3 aColor;
    out vec3 vertexColor;
    uniform mat4 projection;
    void main()
    {
        gl_Position = projection * vec4(aPos, 0.0, 1.0);
        vertexColor = aColor;
    })";

	const char* fragmentShaderSource = R"(
    #version 330 core
    in vec3 vertexColor;
    out vec4 FragColor;
    void main()
    {
        FragColor = vec4(vertexColor, 1.0f);
    })";

	// 编译着色器
	unsigned int vertexShader, fragmentShader;
	vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
	glCompileShader(vertexShader);

	fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
	glCompileShader(fragmentShader);

	unsigned int shaderProgram = glCreateProgram();
	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentShader);
	glLinkProgram(shaderProgram);
	glUseProgram(shaderProgram);

	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);

	// 创建顶点数据
	std::vector<float> vertices;

	// 初始直线端点(可以设置一个默认值)
	int x0 = 100, y0 = 100;
	int x1 = 700, y1 = 500;

	// 使用Bresenham算法计算直线上的像素点
	bresenhamLine(x0, y0, x1, y1, vertices);

	unsigned int VBO, VAO;
	glGenVertexArrays(1, &VAO);
	glGenBuffers(1, &VBO);

	glBindVertexArray(VAO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_STATIC_DRAW);

	// 设置顶点属性指针
	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(2 * sizeof(float)));
	glEnableVertexAttribArray(1);

	// 投影矩阵
	glm::mat4 projection = glm::ortho(0.0f, 800.0f, 600.0f, 0.0f, -1.0f, 1.0f);
	unsigned int projLoc = glGetUniformLocation(shaderProgram, "projection");
	glUniformMatrix4fv(projLoc, 1, GL_FALSE, &projection[0][0]);

	// 渲染循环
	while (!glfwWindowShouldClose(window)) {
		glClear(GL_COLOR_BUFFER_BIT);

		// 检查用户输入,更新直线端点
		int new_x0, new_y0, new_x1, new_y1;
		std::cout << "Enter first point (x0, y0): ";
		std::cin >> new_x0 >> new_y0;
		std::cout << "Enter second point (x1, y1): ";
		std::cin >> new_x1 >> new_y1;

		// 更新直线端点并重新计算 Bresenham 直线
		vertices.clear();
		bresenhamLine(new_x0, new_y0, new_x1, new_y1, vertices);

		glUseProgram(shaderProgram);

		glBindVertexArray(VAO);
		glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_STATIC_DRAW);

		glDrawArrays(GL_POINTS, 0, vertices.size() / 5); // 每个顶点包含5个浮点数:坐标+颜色

		glfwSwapBuffers(window);
		glfwPollEvents();
	}

	glDeleteVertexArrays(1, &VAO);
	glDeleteBuffers(1, &VBO);

	glfwTerminate();
	return 0;
}

void processInput(GLFWwindow *window)
{
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
		glfwSetWindowShouldClose(window, true);
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
	glViewport(0, 0, width, height);
}

void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
	if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS)
	{
		x_pos = new double;
		y_pos = new double;
		glfwGetCursorPos(window, x_pos, y_pos);
		double x = *x_pos;
		double y = *y_pos;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

这辈子秃头是不可能的

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值