游戏引擎学习记录(1)- 渲染(OpenGL)- 三角形

前言

秋招连连碰壁,意识到自己图形学知识薄弱,特此开博记录从0开始的图形学学习记录。本文环境配置为NCLGL(学校自研OpenGL,在原来的基础上有一定的重新封装,但主体仍然基于OpenGL)。使用NCLGL静态库,方便学习及环境配置。

环境&代码库

GitHub链接:kfj24/NCLGL-based-on-OpenGL-Game-Engine · GitHub 同步可能有不及时的地方

第一课 三角形

基本上所有的图形api教程第一课都是教如何绘制三角形。作为所有精美图像最基础的图元这是非常重要的。先大概说一下渲染管线的流程:

获得定点数据 ->Vertex Shader ->曲面细分着色器(后期考虑,前期暂不考虑,是部分可编程的管线)->图元装配(组合成图元)->几何着色器 ->剪裁 ->透视 ->view port(视口变换)->光栅化(插值)

定点是空间中的点,它们构成了一切几何体。在绘制之前,必须通过将定点数据复制到图形内存中进行缓冲。OpenGL对于每种类型的定点属性都将对应顶点缓冲区对象的一个,并且把它们组合到一个顶点数组对象中。例如他是否是整数、浮点数以及每个定点占用多少字节等等。当这些定点数据被缓存到显卡RAM中,并且创建了顶点数组的对象,OpenGL就用它来绘制Mash。

选择定点数组对象的模式有助于接下来的操作。首先我们绘制一个三角形,后续我们会进一步讨论绘制四边形的问题。先介绍下三种定点数组对象:VBO VAO和EBO

VBO(Vertex Buffer Objects) 顶点缓冲对象

VBO是在显卡RAM中开辟的一块内存缓冲区,用于存储顶点的各类属性信息,例如坐标、法向量和顶点颜色数据等等。渲染时直接从VBO中取出,不需要通过CPU传输数据,效率更高。

可以开辟很多个VBO进行使用,因为每个VBO有自己的唯一ID,标志着他的显存地址。

VBO的使用比较简单:

GLuint vbo;//创建vbo的显存空间并分配ID
glGenBuffers(1,&vbo);
glBindBuffer(GL_ARRAY_BUFFER,vbo);//通过分配的ID绑定
glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),virtices,GL_STATIC_DRAW);//把数据传输到显存缓冲区

这里说一下glBindBuffer的第一个参数,他指定了绑定对象的数据类型,有以下可选:

GL_ARRAY_BUFFER

GL_ELEMENT_ARRAY_BUFFER (EBO,后续会讲)

GL_PIXEL_PACK_BUFFER

GL_PIXEL_UNPACK_BUFFER

之后通过glVertexAttribPointer解释定点数据即可。

VAO(Vertex Array Object)顶点数组对象

本文绘制三角形选用了VAO开辟内存。简单来说,VBO用多个对象决定定点的多个属性,VAO用一个对象就可以决定他的多个属性,他是一个保存了所有顶点数据的组合,存储了定点数据的格式以及定点数据所需的VBO对象的引用。用图片可以更直观理解一下:

 这可以简单理解为三个的Buffer。第一个buffer存储了三个不同点的坐标,buffer2比较混乱,包含两个不同的属性:顶点坐标和颜色。buffer3就更混乱了,它包含两种不同的属性:坐标和法向量。

这些都是有效的顶点缓冲区,但是他们没有逻辑,随心所欲的存储属性。为了告诉OpenGL顶点的属性到底在缓冲区的哪个位置,我们选择用VAO来解释他们。

 VAO会告诉OpenGL顶点属性究竟在哪里,给他一个步幅值,正确的让他从一个定点数据到另一个顶点的数据。VAO存储用于每个顶点属性的偏移量和步幅,以及他们来源的缓冲区,以及他们应该有多少个元素。以上边三个buffer举例:

 

EBO(Element Buffer Object)索引缓冲对象

EBO与VBO类似,也是显存中的一块内存缓冲区,他为了解决一个顶点多次重复调用的问题,减少内存空间浪费。他通过顶点的位置索引来调用顶点,而不是重复记录重复的定点信息。

举个例子,如果绘制一个三角形的三个坐标是(0,0) (1,0) (0.5,1),然后在这个三角形右侧道理的绘制一个相连接的三角形组成平行四边形,那平行四边形的最后一个顶点是(1.5,1),如果简单使用VBO进行调用的话,需要对中间重复的两个顶点 (1,0) (0.5,1)进行重复调用,但如果使用EBO的方法,仅仅存取四个顶点,通过索引进行调用和绘制,就能节省两个顶点的空间。用法只需要在glBindBuffer和glBufferData两个函数的第一个参数设置为GL_ELEMENT_ARRAY_BUFFER即可。

实现

由于环境使用了学校的NCLGL对OpenGL做了简单封装,因此实现并不和大多OpenGL相同。

首先在Mesh类中创建一个GenerateTriangle()函数。Mesh类由顶点数据组成。对选择不同的缓冲对象方法做了重新封装。可以在后续重新定义VBO EBO VAO。bufferObject数组使用枚举定义顶点缓冲区、纹理缓冲区、切线空间等等不同的缓冲区。

通过定义colours和vertices两个属性加载进入vbo实现获得顶点数据,注释部分是后续实现平行四边形的:

Mesh* Mesh::GenerateTriangle()
{
	Mesh* m = new Mesh();
	m->numVertices = 6; //初始化一个三个顶点的数组 numVertices是定点的个数
	m->vertices = new Vector3[m->numVertices]; //new初始化vertices顶点数组
	//设置定点参数
	m->vertices[0] = Vector3(0.0f, 0.5f, 0.0f);
	m->vertices[1] = Vector3(0.5f, -0.5f, 0.0f);
	m->vertices[2] = Vector3(-0.5f, -0.5f, 0.0f);
	/*
	m->vertices[3] = Vector3(1.0f, 0.5f, 0.0f);
	m->vertices[4] = Vector3(0.0f, 0.5f, 0.0f);
	m->vertices[5] = Vector3(0.5f, -0.5f, 0.0f);
	*/
	//设置颜色参数 RGBA 透明度为1.0f
	m->colours = new Vector4[m->numVertices];
	m->colours[0] = Vector4(1.0f, 0.0f, 0.0f, 1.0f);//红
	m->colours[1] = Vector4(0.0f, 1.0f, 0.0f, 1.0f);//绿
	m->colours[2] = Vector4(0.0f, 0.0f, 1.0f, 1.0f);//蓝
	/*
	m->colours[3] = Vector4(1.0f, 0.0f, 0.0f, 1.0f);
	m->colours[4] = Vector4(1.0f, 0.0f, 0.0f, 1.0f);//红
	m->colours[5] = Vector4(0.0f, 1.0f, 0.0f, 1.0f);//绿
	*/
	m->BufferData(); //将数据复制进入VBO
	return m;

}

片段着色器包含basicVertex.glsl和colorFragment.glsl两个文件,他们通过shader类中的LoadShaderFile()方法加载glsl语言:

//basicVertex.glsl
#version 330 core
in vec3 position;
in vec4 colour;
out Vertex{
	vec4 colour;
} OUT;

void main(void){
	gl_Position = vec4(position,1.0);
	OUT.colour = colour;
}



//colourFragment.glsl
#version 330 core

in Vertex{
	vec4 colour;
} IN;

out vec4 fragColour;
void main(void){
	fragColour = IN.colour;
}

之后的每个练习都会独立包含一个renderer.h和renderer.cpp文件,代码如下:

//Renderer.h
#pragma once
#include "../nclgl/OGLRenderer.h"
class Renderer :public OGLRenderer {
public:
	Renderer(Window& parent);
	virtual ~Renderer(void);//析构函数虚化防止内存泄漏
	virtual void RenderScene();

protected:
	Mesh* triangle;
	Shader* basicShader;
};
//Renderer.cpp

#include "Renderer.h"
Renderer::Renderer(Window& parent) : OGLRenderer(parent) {
	triangle = Mesh::GenerateTriangle();
	basicShader = new Shader("basicVertex.glsl", "colourFragment.glsl");

	if (!basicShader->LoadSuccess()) {
		return;
	}
	init = true;
}
Renderer::~Renderer(void) {
	delete triangle;
	delete basicShader;
}
void Renderer::RenderScene() {
	glClearColor(0.2f, 0.2f, 0.2f, 1.0f); //初始化屏幕颜色 大概是灰色
	glClear(GL_COLOR_BUFFER_BIT); 
	BindShader(basicShader);
	triangle->Draw();
}

这里讲一下glClearColor和glClear,glClearColor就是设置清除颜色,在这里设置为灰色。glClear把窗口清除为当前颜色。两者结合使用。

结果:

 可以发现对每个顶点设置了颜色,同时颜色在光栅化阶段进行了平滑差值,有渐变的效果。

平行四边形的实现,要记得使用6个顶点进行加载,并不是4个顶点。如果要使用四个顶点,不要使用VBO或VAO,使用EBO进行索引操作,对索引值进行组合,也能达到一样的效果。

平行四边形结果:

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值