opengl-第二章:无shader的2D绘制

绘制教程

1.opengl的绘制策略

推荐阅读:https://learnopengl.com/Getting-started/Hello-Triangle
也称:graphics pipeline
在这里插入图片描述
在opengl里面,将整个绘制流程当做是一个状态机,你可以理解为显卡本身是一个黑板,当我们向里面填顶点数据时,可以通过着色器控制顶点数据去显示。
而当我们填写顶点数据的方法则通常是

	unsigned int VBO;
	glGenBuffers(1, &VBO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

这个时候,数据其实已经写入到显卡里面。而渲染流水线,不过就是对缓存里面的数据进行操作,然后通过显卡提供的指令集最终让显示屏里面的液晶亮起来。

2.本教程基本思路

  1. 本教程不涉及顶点着色器和片元着色器,仅涉及绘制命令
  2. 本教程的基本思路

1. 在CPU里面创建数据(VBO和VAO),并拷贝到GPU
2. 绘制窗口
3. 调用绘制命令绘制三角面

3.顶点数据VBO和VAO

1. 顶点数据包括位置,点的绘制索引

VertexBufferObject(VBO)

1.顶点最重要的属性就是位置属性(x,y,z).所以,这也是VBO最重要的属性。
我们可以定义一个最基本的VBO
		float vertices[] = {
		-0.5f, -0.5f, 0.0f, // left  
		 0.5f, -0.5f, 0.0f, // right 
		 0.0f,  0.5f, 0.0f  ,// top
		 0.5f,  0.5f, 0.0f
	};

在这里插入图片描述
注意,现在数据还是在cpu里面,接下来我们要拷贝到gpu的缓存里面

	unsigned int VBO;
	glGenBuffers(1, &VBO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, 	GL_STATIC_DRAW);
那么,仅通过VBO的数据,我们是否能够绘制三角面呢?答案是不能,这是因为opengl
的内核需要Vertex Array Object对象去进行绘制。
或者你可以理解为,Opengl的绘制指令是通过控制VAO来进行的。
那么,这个时候,你大致可以理解为VAO本身是对VBO的引用。

Vertex Array Object(VAO)

生成VAO可以直接通过以下代码

	unsigned int VAO;
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);
这个时候是否可以直接使用triangle进行绘制了呢?答案是不行的,事实上,对于顶点
数据本身来说,它既可以包含位置信息,也可以包含颜色信息,甚至还能包含其他信
息,比如以下两个VBO
	float vertices[] = {
		-0.5f, -0.5f, 0.0f, // left  
		 0.5f, -0.5f, 0.0f, // right 
	};
		float vertices[] = {
		//pos              //color          //texccord
		-0.5f, -0.5f, 0.0f, 0.5,0.5,0.5,0.0,0.5,
		 0.5f, -0.5f, 0.0f, 0.3,0.2,0.6,0.1,0.3
	};
第一个VBO仅仅包括位置,但是第二个VBO包括了位置,颜色,和纹理分布,显然的我	
们需要通过命令将其进行分开,这个过程叫做“修饰顶点属性”
修饰(设定)顶点属性(状态)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
1. 这串代码其实很容易理解,就是对VBO的数据进行修饰。我们看到的任意一个VBO都是
一维的数组,那么问题来了,我们从哪个地方进行绘制呢?那么第一个参数就是绘制的
起始位置,定义为0.
2. 新的问题,我们的顶点属性数据量不一样,我们人是知道的,但是机器却不知道,所
以,我们需要让机器知道,所以我们定义了3用于表示顶点属性的数据量
3. 另外一个问题,我们希望一个顶点的数据的大小,因为除了浮点数,我们还可以选择
整形数据,短整型数据,所以我们可以定义GL_Float
4. 第四个参数略微有些复杂,现在只需要理解对浮点数类型,将它指派为FL_FALSE就可以了
5. 另外一个重要的问题,我们输入的数据终究是一个一维的,那么怎么切成一个一个的
vertex则需要在这里定义一个gap了,如果我们定义一个vertex数据包括位置,颜色,纹	
理一共七个浮点数,那么这个参数就会变成7 * sizeof(float)
6. 这个参数略微复杂,在这个版本的教程里面我们不会涉及,默认为void* 0
使用顶点属性
在前面的介绍里面,我们定义了一个顶点的数据模型,那么新的问题来了,如果我希望某
些属性可以使用而某些属性不可以使用要怎么做呢?显然gl肯定不会忘记提供一个这样的
API
glEnableVertexAttribArray(0);//让第0个属性可以使用
glDisableVertexAttribArray(0);//让第0个属性不可以使用
其实在原文里面,我们可以发现,在更加复杂的情况下的一个使用

在这里插入图片描述

清除缓存

防止内存泄露,需要将buffer给清理掉
glDeleteBuffers(1, &VBO);

4. 绘制窗口

定义窗口

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <time.h>
#include <iostream>
using namespace std;

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
	glViewport(0, 0, width, height);
}
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
clock_t lastTimes;
GLFWwindow* window ;
int init() {
	lastTimes = clock();
	window = nullptr;
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	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);
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		std::cout << "Failed to initialize GLAD" << std::endl;
		return -1;
	}
}

void draw() {

}
void run() {
	while (!glfwWindowShouldClose(window))
	{
		clock_t now =  clock();
		draw();
		cout << "loop gap = " << now - lastTimes << endl;
		lastTimes = now;
		glfwSwapBuffers(window);
		glfwPollEvents();
	}
}
void shutDown() {
	glfwTerminate();
}
int main()
{
	init();
	run();
	shutDown();
	return 0;
}

注意,我们的绘制函数将会在draw里面进行调用

5.调用绘制命令绘制三角

给一个背景色

没有着色器的三角默认是黑色的,所以你总得给一个背景色
设定状态
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
使用状态
glClear(GL_COLOR_BUFFER_BIT);
值得注意的是,当使用GL_COLOR_BUFFER_BIT时,会直接将当前的帧缓存刷成glClearColor指定的缓存,另外还可以有以下的几种类型,当然,在本教程中并不考虑
#define GL_DEPTH_BUFFER_BIT 0x00000100
#define GL_STENCIL_BUFFER_BIT 0x00000400
#define GL_COLOR_BUFFER_BIT 0x00004000
这个时候我们可以直接draw出一个带墨绿色的窗口
void draw() {
	glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT);
}

在这里插入图片描述

剩下的代码

void draw() {
	glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT);
	//添加数据
	float vertices[] = {
    	-0.5f, -0.5f, 0.0f, // left  
    	 0.5f, -0.5f, 0.0f, // right 
    	 0.0f,  0.5f, 0.0f  ,// top
    	 0.5f,0.5f,0.0f
    };
    
    unsigned int VBO;
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
    unsigned int VAO;
    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

	//调用几何着色器命令

	glDrawArrays(GL_TRIANGLES, 0, 3);//绘制0,1,2连城的三角
	
	//glDrawArrays(GL_TRIANGLES, 1, 4);//绘制1,2,3连城的三角

}

测试结果

在这里插入图片描述

6.完整的代码

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <time.h>
#include <iostream>
using namespace std;

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
	glViewport(0, 0, width, height);
}
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
clock_t lastTimes;
GLFWwindow* window ;
int init() {
	lastTimes = clock();
	window = nullptr;
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	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);
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		std::cout << "Failed to initialize GLAD" << std::endl;
		return -1;
	}
}

void draw() {
	glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT);
	//添加数据
	float vertices[] = {
    	-0.5f, -0.5f, 0.0f, // left  
    	 0.5f, -0.5f, 0.0f, // right 
    	 0.0f,  0.5f, 0.0f  ,// top
    	 0.5f,0.5f,0.0f
    };
    
    unsigned int VBO;
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
    unsigned int VAO;
    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

	//调用几何着色器命令

	glDrawArrays(GL_TRIANGLES, 0, 3);//绘制0,1,2连城的三角
	
	//glDrawArrays(GL_TRIANGLES, 1, 4);//绘制1,2,3连城的三角
}
void run() {
	while (!glfwWindowShouldClose(window))
	{
		clock_t now =  clock();
		draw();
		cout << "loop gap = " << now - lastTimes << endl;
		lastTimes = now;
		glfwSwapBuffers(window);
		glfwPollEvents();
	}
}
void shutDown() {
	glfwTerminate();
}
int main()
{
	init();
	run();
	shutDown();
	return 0;
}


  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值