【OpenGL蓝宝书】Chapter 5. Data

一、Buffers

1. OpenGL在4.5为所有的glGen*()函数增加了glCreate*()版本。二者区别如下:

glGen*()只有在bind之后才会生成真正的object,而glCreate*()在create时立刻生成真正object。

所以,想调用glNamedBufferStorage()之类带Named的函数,要么先bind一次buffer,要么直接在创建buffer时用glCreate*()的版本。

1.1 数据初始化

可用glNamedBufferStorage()/glBufferStorage()或者glNamedBufferData()/glBufferdata().

    Storage()不能对同一个buffer做两次。Data()可以。

    Storage()最后一个参数flag有GL_DYNAMIC_STORAGE_BIT则允许后续subdata()更新数据。

1.2 数据更新

可用glNamedBufferSubData()/glBufferSubData()。

若初始化数据时是Storage(),则Storage的flag需有GL_DYNAMIC_STORAGE_BIT。

 

2. OpenGL4.5同样为VAO引入了诸多操作,这里介绍放置数据的规则。

第一种:separate,SoA,structure of arrays。部分函数和注释见example1。

example1:

static const float positions[] =
{
	 0.25, -0.25, 0.5, 1.0,
	- 0.25, -0.25, 0.5, 1.0,
	 0.25,  0.25, 0.5, 1.0
};
static const float colors[] =
{
	1.0f, 0.0f, 0.0f,
	0, 1, 0,
	0, 0, 1
};


glCreateVertexArrays(1, &vao);

GLuint buffers[2];
glCreateBuffers(2, buffers);


glNamedBufferStorage(buffers[0], sizeof(positions), positions, NULL);
glVertexArrayVertexBuffer(vao, 13, buffers[0], 0, sizeof(vmath::vec4));    // 该vao的13号buffer binding point
glVertexArrayAttribFormat(vao, 11, 4, GL_FLOAT, GL_FALSE, 0);    // 该vao的11号attribute index
glVertexArrayAttribBinding(vao, 11, 13);    // 当该vao bind的时候,11号attribute从13号buffer binding拿数据。
glEnableVertexArrayAttrib(vao, 11);    // 启用该vao的11号attribute。vs的location从这里拿。

glNamedBufferStorage(buffers[1], sizeof(colors), colors, NULL);
glVertexArrayVertexBuffer(vao, 1, buffers[1], 0, sizeof(vmath::vec3));
glVertexArrayAttribFormat(vao, 1, 3, GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribBinding(vao, 1, 1);
glEnableVertexArrayAttrib(vao, 1);

glBindVertexArray(vao);

3. 也可以将所有data放到一个struct里,只用1个buffer。(interleave,交错。AoS,array of structures)

example2:

		static const float vertices[] =
		{
			//positions					//colors
			 0.25, -0.25, 0.5, 1.0,		1.0f, 0.0f, 0.0f,
			-0.25, -0.25, 0.5, 1.0,		0, 1, 0,
			 0.25,  0.25, 0.5, 1.0,		0, 0, 1
		};


        glCreateVertexArrays(1, &vao);

		GLuint buffer;
		glCreateBuffers(1, &buffer);


		glNamedBufferStorage(buffer, sizeof(vertices), vertices, NULL);
		glVertexArrayVertexBuffer(vao, 9, buffer, 0, sizeof(vmath::vec4) + sizeof(vmath::vec3));    // 将buffer bind到vao的9号 binding point

		glVertexArrayAttribFormat(vao, 5, 4, GL_FLOAT, GL_FALSE, 0);    // 5号attribute从头开始取
		glVertexArrayAttribBinding(vao, 5, 9);    //5号attribute去9号binding point取
		glEnableVertexArrayAttrib(vao, 5);

		glVertexArrayAttribFormat(vao, 1, 3, GL_FLOAT, GL_FALSE, sizeof(vmath::vec4));    // 1号attribute从sizeof(vmath::vec4)的地方开始取
		glVertexArrayAttribBinding(vao, 1, 9);    //1号attribute去9号binding point取
		glEnableVertexArrayAttrib(vao, 1);

		
        glBindVertexArray(vao);

二、uniform block

在shader中,有些数据对所有顶点是通用的(如MVP矩阵)。我们可以分别通过glUniform*()将他们分别传入shader,也可以通过uniform block将他们一次性传入。

shader example:

#version 420 core                      
                                      
                                       
layout (std140, binding = 2) uniform UB
{										
	vec3 translate;						
	int  scale;							
}ub;                                   

其中std140声明了UB的内存布局为标准布局,binding = 2声明了这个shader将来要去uniform binding point = 2 的地方取buffer。

 

然后在opengl中,创建buffer并给数据,与之前差不多:

typedef struct UBSTRUCT
{
	vmath::vec3 translate;
	int scale;
}ubstruct;

...

static const ubstruct translates = { vmath::vec3(0.1, 0.1, 0), 5 };

...

GLuint ubo;
glCreateBuffers(1, &ubo);
//glNamedBufferStorage(ubo, sizeof(translates), &translates, NULL);
glNamedBufferData(ubo, sizeof(translates), &translates, GL_STATIC_DRAW);

 

最后,需要将这个buffer bind到GL_UNIFORM_BUFFER的某个binding point。这里将ubo bind到2号 uniform binding point,这样所有layout(binding = 2)的uniform block都将来这个buffer取data。

将该buffer绑定至GL_UNIFORM_BUFFER的2号binding point:

glBindBufferBase(GL_UNIFORM_BUFFER, 2, ubo);
//glBindBufferRange(GL_UNIFORM_BUFFER, 2, ubo, 0, sizeof(translates));    // 可以将一个ubo内不同数据绑定至不同binding point

三、atomic counter

说白了它就是一个buffer。GL_ATOMIC_COUNTER_BUFFER。有自己的index。(就像GL_UNIFORM_BUFFER有自己的index一样)

生成、绑定完全类似。

在shader中,声明为 layout (binding = 3, offset = 0) uniform atomic_uint counter;表示GL_ATOMIC_COUNTER_BUFFER的3号binding point, offset为0。

在shader中,可调用三种方法:

uint atomicCounter(atomic_uint c);
 
// 减一并返回新值
uint atomicCounterDecrement(atomic_uint c); 
 
//加一并返回旧值
uint atomicCounterIncrement(atomic_uint c);

atomic counter若在fragmentshader中使用,可以观测pixel的绘制顺序(将counter处理为颜色)。此法需要在渲染循环中每次清零atomic counter buffer。

四、Texture

1. 创建texture:同样有两个版本。glCreateTextures()/glGenTextures()。

glCreateTextures()需要指明target,glGenTextures()不用,但是需要bind到某个target之后才会生成真正的texture object。

glCreateTexture()之后,使用glTextureStorage2D()初始化内存空间,或者

glGenTexture()之后,bind到某个target,使用glTexStorage2D()初始化空间。

1.1 初始化texture

glTextureStorage2D()/glTexStorage2D()中有个参数,指明有几个mipmap。该函数对所有mipmap初始化。

1.2 往texture灌数据

glTextureSubImage2D()直接往texture object灌,或者glTexSubImage2D()往当前target灌。

2. 创建sampler

若不创建sampler,则OpenGL会自动为每个texture生成sampler。

使用非默认sampler的好处在于,不用对每张贴图进行环绕方式等设置,只用对sampler进行设置即可。

(一个是.cpp这里的sampler,一个是shader那里的sampler,他们是一一对应的。shader端的sampler以uniform的形式存在)

glCreateSamplers(1, &sampler);
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glBindSampler(5, sampler);    // 绑定至5号uniform binding point

其中对GL_TEXTURE_MIN_FILTER的设置才会启用mipmap,否则texture只会从level0的mipmap采样。

GL_TEXTURE_MAG_FILTER不需要设置mipmap之间的采样。

2.1 绑定texture

首先:每个texture unit都有自己的GL_TEXTURE_2D等,glActiveTexture(GL_TEXTUREi)之后,所有对target的设置都将是对GL_TEXTUREi的target上的texture设置。默认激活的是GL_TEXTURE0。

不使用sampler:直接设置texture并使用glActiveTexture(GL_TEXTUREi), glBindTexture(GL_TEXTURE_2D)将之bind至 i 号texture binding point 的 GL_TEXTURE_2D。

使用了sampler:texture就直接用数字指定绑定的texture unit,即:

glBindTextureUnit(5, texture);

注意:在shader里,sampler声明成uniform,但是它的 layout (binding = x) 与 uniform block 的 layout (binding = x)不冲突,前者是texture binding point,后者是uniform buffer 的binding point.

2.2 生成mipmap

两种方法。glGenerateMipmap(GL_TEXTURE_2D);或者glGenerateTextureMipmap(texture);前者对target上的texture,后者直接对texture

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值