Vulkan_Shader_Day04-s—推式常量(push constants)

在着色器中使用推式常量(push constants)

为了能够更好的进行下部分投光物的练习,我们先创建十个相同大小,位置不同的箱子,故可使用push constants来实时更新不同位置创建箱子。

简介

当我们向着色器提供数据时,通常使用uniform缓冲区,存储(storage)缓冲区或其他类型的描述符资源。 遗憾的是,更新此类资源可能不太方便,尤其是当我们需要提供频繁更改的数据时。

为此,引入了推式常量。 通过它们,我们可以通过更新描述符资源以简化和快速的方式提供数据。 但是,我们需要适应更小的可用空间。

在GLSL着色器中访问推送常量类似于使用统一缓冲区。

怎么做呢?

  1. 创建一个着色器文件。

  2. 定义uniform块:

    1.提供push_constant布局限定符: layout( push_constant )
    2.使用uniform限定符
    3.提供块的唯一名称
    4.在大括号内,定义一组统一变量
    5.指定块实例的名称。

  3. 在void main()函数内部,使用块实例名称访问uniform变量: < instance name >.< variable name >

这个怎么运作呢?
按照与GLSL着色器中指定的uniform块类似的方式定义和访问推送常量,但是我们需要记住一些差异:

  1. 我们需要在块的定义之前使用布局(push_constant)限定符
  2. 我们必须为块指定实例名称
  3. 我们每个着色器只能定义一个这样的块
  4. 我们通过在名称前加上块的实例名来访问push常量变量: < instance name >.< variable name >

注意:
推送常量对于提供频繁更改的少量数据非常有用,例如转换矩阵或当前时间值 - 更新推送常量块应该比更新描述符资源(如uniform缓冲区)快得多。 我们只需要记住比描述符资源小得多的数据大小。 规范要求推送常量至少存储128个字节的数据。 每个硬件平台可以允许更多存储,但可能不会大得多。

提示:推送常量可以存储至少128个字节的数据。

一、循环创建模型

首先我们定是十个不同的位置:

glm::vec3 cubePositions[] = {
	glm::vec3(0.0f,  0.0f,  0.0f),
	glm::vec3(2.0f,  5.0f, -15.0f),
	glm::vec3(-1.5f, -2.2f, -2.5f),
	glm::vec3(-3.8f, -2.0f, -12.3f),
	glm::vec3(2.4f, -0.4f, -3.5f),
	glm::vec3(-1.7f,  3.0f, -7.5f),
	glm::vec3(1.3f, -2.0f, -2.5f),
	glm::vec3(1.5f,  2.0f, -2.5f),
	glm::vec3(1.5f,  0.2f, -1.5f),
	glm::vec3(-1.3f,  1.0f, -1.5f)
};

在创建createCommandBuffers函数中循环十次创建正方体,并将位置实时推送到顶点着色器中:

void createCommandBuffers() {
		...
			for (size_t j = 0; j < 10; j++)
			{
				glm::vec3 pos = cubePositions[j];
				vkCmdPushConstants(commandBuffers[i], pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::vec3), &pos);
			    vkCmdDrawIndexed(commandBuffers[i], static_cast<uint32_t>(indices.size()), 1, 0, 0, 0);
			}
        ...
	}

在运行代码之前,我们还需要在创建管线布局中将VkPipelineLayoutCreateInfo结构体的pPushConstantRanges和pushConstantRangeCount填充完整.

void createGraphicsPipeline() {
		...
		VkPushConstantRange pushConstantRange{};
		pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
		pushConstantRange.offset = 0;
		pushConstantRange.size = sizeof(glm::vec3);

		...
		pipelineLayoutInfo.pushConstantRangeCount = 1; // Optional
		pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange; // Optional

		if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) {
			throw std::runtime_error("failed to create pipeline layout!");
		}

		...
	}

接下来我们在顶点着色器中使用使用推式常量:

...
layout(push_constant) uniform PushConsts {
	vec3 objPos;
} pushConsts;

void main() {
    gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition + pushConsts.objPos, 1.0);
	fragPos =vec3( ubo.model * vec4(inPosition+ pushConsts.objPos, 1.0));;
    ...
}

这儿将位置推送到顶点着色器中,并实时更新,编译着色器及程序运行,可得到下图:
在这里插入图片描述
下一阶段,我们将继续来研究光照中的投光物。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章