三角形条带与扇面
三角形条带
BeltData.h
#ifndef VULKANEXBASE_BELTDATA_H
#define VULKANEXBASE_BELTDATA_H
class BeltData
{
public:
static float* vdata;
static int dataByteCount;
static int vCount;
static double toRadians(double d);
static void genVertexData();
};
#endif
BeltData.cpp
#include <../main_task/BeltData.h>
#include <vector>
#include <math.h>
#include <string.h>
#include "BeltData.h"
const double PI=3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170680;
float* BeltData::vdata;
int BeltData::dataByteCount;
int BeltData::vCount;
double BeltData::toRadians(double d)
{
double e=d*PI/180;
return e;
}
void BeltData::genVertexData(){ //生成顶点数据的方法
int n = 6; //条带切割份数
//始化了计算三角形条带顶点数据所需的各个辅助变量并创建了顶点数据存储数组。
vCount=2*(n+1); //计算顶点数量
dataByteCount=vCount*6* sizeof(float); //计算顶点数据所占总字节数
float angdegBegin = -90; //设置条带起始度数
float angdegEnd = 90; //设置条带结束度数
float angdegSpan = (angdegEnd-angdegBegin)/n; //计算条带每份度数
vdata=new float[vCount*6]; //创建顶点数据数组
int count=0; //辅助索引
//行为生成三角形条带顶点位置及顶点颜色数据的代码
for(float angdeg=angdegBegin; angdeg<=angdegEnd; angdeg+=angdegSpan) {
double angrad=toRadians(angdeg); //计算当前弧度
vdata[count++]=(float) (-0.6f*50*sin(angrad)); //此切割角度第1个顶点的x坐标
vdata[count++]=(float) (0.6f*50*cos(angrad)); //此切割角度第1个顶点的y坐标
vdata[count++]=0; //此切割角度第1个顶点的z坐标
vdata[count++]=1; //此切割角度第1个顶点颜色R分量
vdata[count++]=1; //此切割角度第1个顶点颜色G分量
vdata[count++]=1; //此切割角度第1个顶点颜色B分量
vdata[count++]=(float) (-50*sin(angrad)); //此切割角度第2个顶点的x坐标
vdata[count++]=(float) (50*cos(angrad)); //此切割角度第2个顶点的y坐标
vdata[count++]=0; //此切割角度第2个顶点的z坐标
vdata[count++]=0; //此切割角度第2个顶点颜色R分量
vdata[count++]=1; //此切割角度第2个顶点颜色G分量
vdata[count++]=1; //此切割角度第2个顶点颜色B分量
}}
CircleData.cpp
#include "CircleData.h"
#include "BeltData.h"
#include <vector>
#include <math.h>
#include <string.h>
float* CircleData::vdata;
int CircleData::dataByteCount;
int CircleData::vCount;
void CircleData::genVertexData(){
//初始化了计算扇面顶点数据所需的各个辅助变量并创建了顶点数据存储数组
int n = 10; //扇形切割份数
vCount=n+2; //顶点数量
dataByteCount=vCount*6* sizeof(float); //顶点数据所占总字节数
vdata=new float[vCount*6]; //创建顶点数据数组
float angdegSpan=360.0f/n; //扇形每份度数
int count=0; //辅助索引
//给出了扇面中心点的坐标及颜色数据
vdata[count++] = 0; //第一个顶点X坐标
vdata[count++] = 0; //第一个顶点Y坐标
vdata[count++] = 0; //第一个顶点Z坐标
vdata[count++] = 1; //第一个顶点颜色R分量
vdata[count++] = 1; //第一个顶点颜色G分量
vdata[count++] = 1; //第一个顶点颜色B分量
//循环生成了扇面周围一圈顶点的坐标及颜色数据
for(float angdeg=0; ceil(angdeg)<=360; angdeg+=angdegSpan) { //循环生成周围其他顶点的数据
double angrad=BeltData::toRadians(angdeg); //当前弧度
vdata[count++]=(float) (-50*sin(angrad)); //当前顶点x坐标
vdata[count++]=(float) (50*cos(angrad)); //当前顶点y坐标
vdata[count++]=0; //当前顶点z坐标
vdata[count++] = 0; //当前顶点颜色R分量
vdata[count++] = 1; //当前顶点颜色G分量
vdata[count++] = 0; //当前顶点颜色B分量
}}
shade
#version 400
#extension GL_ARB_separate_shader_objects : enable//启动GL_ARB_separate_shader_objects
#extension GL_ARB_shading_language_420pack : enable//启动GL_ARB_shading_language_420pack
layout (push_constant) uniform constantVals
{ //推送常量块
mat4 mvp;//总变换矩阵
} myConstantVals;
layout (location = 0) in vec3 pos;//传入的物体坐标系顶点位置
layout (location = 1) in vec3 color;//传入的顶点颜色
layout (location = 0) out vec3 vcolor;//传到片元着色器的顶点颜色
out gl_PerVertex { vec4 gl_Position;}; //输出接口块
void main()
{ //主函数
gl_Position = myConstantVals.mvp * vec4(pos,1.0); //计算顶点最终位置
vcolor=color;//传递顶点颜色给片元着色器
}
BeltData2.cpp
#include <../main_task/BeltData.h>
#include <vector>
#include <math.h>
#include <string.h>
#include "BeltData.h"
const double PI=3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170680;
float* BeltData::vdata;
int BeltData::dataByteCount;
int BeltData::vCount;
double BeltData::toRadians(double d)
{
double e=d*PI/180;
return e;
}
void BeltData::genVertexData(){ //生成顶点数据的方法
int n1 = 3; //第一个条带切割份数
int n2 = 5; //第二个条带切割份数
vCount = 2 * (n1 + n2 + 2) + 2; //计算总顶点数
dataByteCount=vCount*6* sizeof(float); //计算顶点数据所占总字节数 //计算条带每份度数
vdata=new float[vCount*6]; //创建顶点数据数组
float angdegBegin1 = 0; //第一个条带起始度数
float angdegEnd1 = 90; //第一个条带结束度数
float angdegSpan1 = (angdegEnd1 - angdegBegin1) / n1; //第一个条带每份度数
float angdegBegin2 = 180; //第二个条带起始度数
float angdegEnd2 = 270; //第二个条带结束度数
float angdegSpan2 = (angdegEnd2 - angdegBegin2) / n2; //第二个条带每份度数
int count=0; //辅助索引
for (float angdeg = angdegBegin1; angdeg <= angdegEnd1; angdeg += angdegSpan1) {
double angrad=toRadians(angdeg); //计算当前弧度
vdata[count++] = (float)(-0.6f * 80 * sin(angrad)); //外围大圆上的点X坐标
vdata[count++] = (float)(0.6f * 80 * cos(angrad)); //外围大圆上的点Y坐标
vdata[count++]=0; //此切割角度第1个顶点的z坐标
vdata[count++]=1; //此切割角度第1个顶点颜色R分量
vdata[count++]=1; //此切割角度第1个顶点颜色G分量
vdata[count++]=1; //此切割角度第1个顶点颜色B分量
vdata[count++] = (float)(-80 * sin(angrad)); //内圈小圆上的点X坐标
vdata[count++] = (float)(80 * cos(angrad)); //内圈小圆上的点Y坐标
vdata[count++]=0; //此切割角度第2个顶点的z坐标
vdata[count++]=0; //此切割角度第2个顶点颜色R分量
vdata[count++]=1; //此切割角度第2个顶点颜色G分量
vdata[count++]=1; //此切割角度第2个顶点颜色B分量
}
vdata[count++] = vdata[count - 6]; //重复第一批三角形的最后一个顶点数据
vdata[count++] = vdata[count - 6];
vdata[count++] = 0;
vdata[count++] = 1;
vdata[count++] = 0;
vdata[count++] = 0;
//第2个条带数据的生成与第一个条带相似
//初始化了计算条带顶点数据的辅助变量,包括顶点数量、顶点数据总字节数、两个条带度数范围以及条带分割的每份度数等,同时还创建了顶点数据数组。
for (float angdeg = angdegBegin2; angdeg <= angdegEnd2; angdeg += angdegSpan2) {
double angrad = toRadians(angdeg); //当前弧度
if (angdeg == angdegBegin2) { //重复第二批三角形的第一个顶点数据
vdata[count++] = (float)(-0.6f * 80 * sin(angrad)); //顶点X坐标
vdata[count++] = (float)(0.6f * 80 * cos(angrad)); //顶点Y坐标
vdata[count++] = 0; //顶点Z坐标
vdata[count++] = 0;
vdata[count++] = 1;
vdata[count++] = 0; //顶点颜色
}
//大圆上的点
vdata[count++] = (float)(-0.6f * 80 * sin(angrad));//顶点坐标
vdata[count++] = (float)(0.6f * 80 * cos(angrad));
vdata[count++] = 0;
vdata[count++] = 1;
vdata[count++] = 1;
vdata[count++] = 1;
//小圆上的点
vdata[count++] = (float)(-80 * sin(angrad));//顶点坐标
vdata[count++] = (float)(80 * cos(angrad));
vdata[count++] = 0;
vdata[count++] = 0;
vdata[count++] = 1;
vdata[count++] = 1;
}
}
相比于上一个案例主要是改变了顶点的位置。物体不再是整体由一批连续三角形组成,而是分两批连续三角形组成。第一批的最后一个顶点和第二批的第一个顶点在顶点序列中重复了
索引法绘制
vkCmdDraw前面的案例中都是调用vkCmdDraw方法来执行物体的绘制,此方法是按照传入渲染管线的顶点本身的顺序及选用的绘制方式将顶点组织成图元进行绘制的,也可以称之为顶点法。
vkCmdDrawIndexed方法在绘制时不但要将顶点序列传入渲染管线,还需要将索引序列传入渲染管线。绘制时管线根据索引序列中的索引值从顶点序列中取出对应的顶点,并根据当前选用的绘制方式组织成图元进行绘制,图4-33很好地说明了这个问题。
采用索引法(vkCmdDrawIndexed)进行绘制时可以有效地减少重复顶点数据,有重复时只需要提供重复的索引号即可。。而每个索引值只需要一个整数,相比一个顶点数据需要3个(也可能是更多的)整数或浮点数可以节省不少空间。
CircleData.h
#ifndef VULKANEXBASE_BELTDATA_H
#define VULKANEXBASE_BELTDATA_H
#include <cstdint>
//代码为在CircleData类头文件中添加的服务于索引数据的相关变量,包括索引数据指针、总字节数和索引数量。
class CircleData
{
public:
static float* vdata;
static int dataByteCount;
static int vCount;
static uint16_t* idata; //索引数据指针
static int indexByteCount; //索引数据所占总字节数
static int iCount; //索引数量
static double toRadians(double d);
static void genVertexData();
};
#endif //TRIANGLESTRIP_CIRCLEDATA_H
#include <../main_task/CircleData.h>
#include <vector>
#include <math.h>
#include <string.h>
const double PI=3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170680;
float* CircleData::vdata;
int CircleData::dataByteCount;
int CircleData::vCount;
uint16_t* CircleData::idata;
int CircleData::indexByteCount;
int CircleData::iCount;
double CircleData::toRadians(double d)
{
double e=d*PI/180;
return e;
}
//主要功能为生成要绘制的物体的顶点位置、颜色数据及绘制所需的索引数据。
void CircleData::genVertexData(){
int n = 10; //扇形切割份数
vCount=n+2; //顶点数量
dataByteCount=vCount*6* sizeof(float); //顶点数据所占总字节数
vdata=new float[vCount*6]; //创建顶点数据数组
float angdegSpan=360.0f/n; //扇形每份度数
int count=0; //辅助索引
vdata[count++] = 0; vdata[count++] = 0; vdata[count++] = 0; //第一个顶点的坐标
vdata[count++] = 1; vdata[count++] = 1; vdata[count++] = 1; //第一个顶点的颜色
for(float angdeg=0; ceil(angdeg)<=360; angdeg+=angdegSpan) { //循环生成周围其他顶点的数据
double angrad = toRadians(angdeg); //当前弧度
vdata[count++] = (float)(-30 * sin(angrad)); //顶点x 坐标
vdata[count++] = (float)(30 * cos(angrad)); //顶点y 坐标
vdata[count++]=0; //当前顶点z坐标
vdata[count++] = 0; vdata[count++] = 1; vdata[count++] = 0; //顶点颜色
}
iCount = 12; //索引数量
indexByteCount = iCount * sizeof(uint16_t); //索引数据所占总字节数
idata = new uint16_t[iCount]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1 }; //索引数据数组
}
用于生成物体数据的CircleData类后,还需要对物体绘制类DrawableObjectCommon进行修改,使其能够创建索引缓冲。首先要介绍的是对DrawableObjectCommon类声明的修改,主要是添加了与创建索引缓冲相关的变量和方法,并对drawSelf方法签名进行了修改,具体代码如下。
DrawableObjectCommonLight函数
//创建顶点数据缓冲、索引数据缓冲所需的诸多变量,对构造函数和绘制方法的签名进行了修改
//,添加了索引数据相关的入口参数,并提供了用于创建顶点数据缓冲、索引数据缓冲的两个方法。
//行用于接收逻辑设备指针、顶点数据数组首地址指针、顶点数量、索引数据数组首地址指针、索引数量等,并保存到对应成员变量中。
DrawableObjectCommonLight::DrawableObjectCommonLight( //构造函数
float* vdataIn, int dataByteCount, int vCountIn, //传入的顶点数据相关参数
uint16_t* idataIn, int indexByteCount, int iCountIn, //传入的索引数据相关参数
VkDevice& device, VkPhysicalDeviceMemoryProperties& memoryroperties)
{
pushConstantData = new float[16]; //推送常量数据数组的初始化
//用于接收逻辑设备指针、顶点数据数组首地址指针、顶点数量、索引数据数组首地址指针、索引数量等,并保存到对应成员变量中。
this->devicePointer = &device;
this->vdata = vdataIn;
this->vCount = vCountIn;
this->idata = idataIn; //接收索引数据数组首地址指针并保存
this->iCount = iCountIn; //接收索引数量并保存
//调用相关方法分别创建顶点数据缓冲和索引数据缓冲,其中createVertexBuffer方法就是将之前创建顶点数据缓冲的过程封装而来。
//createIndexBuffer方法基本也是如此,需要注意的是创建索引缓冲时需要将缓冲创建信息结构体中的index_buf_info.usage设置为VK_BUFFER_USAGE_INDEX_BUFFER_BIT。
//用相关方法分别创建顶点数据缓冲和索引数据缓冲,其中createVertexBuffer方法就是将之前创建顶点数据缓冲的过程封装而来。
//createIndexBuffer方法基本也是如此,需要注意的是创建索引缓冲时需要将缓冲创建信息结构体中的index_buf_info.usage设置为VK_BUFFER_USAGE_INDEX_BUFFER_BIT。
createVertexBuffer(dataByteCount, device, memoryroperties); //调用方法创建顶点数据缓冲
createIndexBuffer(indexByteCount, device, memoryroperties); //调用方法创建索引数据缓冲
}
createVertexBuffer(dataByteCount, device, memoryroperties); //调用方法创建顶点数据缓冲
void DrawableObjectCommonLight::createVertexBuffer(int dataByteCount, VkDevice& device, VkPhysicalDeviceMemoryProperties& memoryroperties)
{
VkBufferCreateInfo buf_info = {};//构建缓冲创建信息结构体实例
buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;//设置结构体类型
buf_info.pNext = NULL;//自定义数据的指针
buf_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;//缓冲的用途为顶点数据
buf_info.size = dataByteCount;//设置数据总字节数
buf_info.queueFamilyIndexCount = 0;//队列家族数量
buf_info.pQueueFamilyIndices = NULL;//队列家族索引列表
buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;//共享模式
buf_info.flags = 0;//标志
VkResult result = vkCreateBuffer(device, &buf_info, NULL, &vertexDatabuf);//创建缓冲
assert(result == VK_SUCCESS);//检查缓冲创建是否成功
VkMemoryRequirements mem_reqs;//缓冲内存需求
vkGetBufferMemoryRequirements(device, vertexDatabuf, &mem_reqs);//获取缓冲内存需求
assert(dataByteCount <= mem_reqs.size);//检查内存需求获取是否正确
VkMemoryAllocateInfo alloc_info = {};//构建内存分配信息结构体实例
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;//结构体类型
alloc_info.pNext = NULL;//自定义数据的指针
alloc_info.memoryTypeIndex = 0;//内存类型索引
alloc_info.allocationSize = mem_reqs.size;//内存总字节数
VkFlags requirements_mask = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;//需要的内存类型掩码
bool flag = memoryTypeFromProperties(memoryroperties, mem_reqs.memoryTypeBits, requirements_mask, &alloc_info.memoryTypeIndex);//获取所需内存类型索引
if (flag)
{
printf("确定内存类型成功 类型索引为%d\n", alloc_info.memoryTypeIndex);
}
else
{
printf("确定内存类型失败!\n");
}
result = vkAllocateMemory(device, &alloc_info, NULL, &vertexDataMem);//为顶点数据缓冲分配内存
assert(result == VK_SUCCESS);
uint8_t *pData;//CPU访问时的辅助指针
result = vkMapMemory(device, vertexDataMem, 0, mem_reqs.size, 0, (void **)&pData);//将设备内存映射为CPU可访问
assert(result == VK_SUCCESS);//检查映射是否成功
memcpy(pData, vdata, dataByteCount);//将顶点数据拷贝进设备内存
vkUnmapMemory(device, vertexDataMem);//解除内存映射
result = vkBindBufferMemory(device, vertexDatabuf, vertexDataMem, 0);//绑定内存与缓冲
assert(result == VK_SUCCESS);
vertexDataBufferInfo.buffer = vertexDatabuf;//指定数据缓冲
vertexDataBufferInfo.offset = 0;//数据缓冲起始偏移量
vertexDataBufferInfo.range = mem_reqs.size;//数据缓冲所占字节数
}
DrawableObjectCommonLight::createIndexBuffer
void DrawableObjectCommonLight::createIndexBuffer(int indexByteCount, VkDevice& device, VkPhysicalDeviceMemoryProperties& memoryroperties)
{
//创建Buffer创建信息实例,为创建索引数据Buffer服务
VkBufferCreateInfo index_buf_info = {};
index_buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
index_buf_info.pNext = NULL;
index_buf_info.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
index_buf_info.size = indexByteCount;
index_buf_info.queueFamilyIndexCount = 0;
index_buf_info.pQueueFamilyIndices = NULL;
index_buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
index_buf_info.flags = 0;
VkResult result = vkCreateBuffer(device, &index_buf_info, NULL, &indexDatabuf);
assert(result == VK_SUCCESS);
//获取内存需求
VkMemoryRequirements index_mem_reqs;
vkGetBufferMemoryRequirements(device, indexDatabuf, &index_mem_reqs);
assert(indexByteCount <= index_mem_reqs.size);
//内存分配信息
VkMemoryAllocateInfo index_alloc_info = {};
index_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
index_alloc_info.pNext = NULL;
index_alloc_info.memoryTypeIndex = 0;
index_alloc_info.allocationSize = index_mem_reqs.size;
VkFlags index_requirements_mask = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
//获取所需内存类型索引
bool index_flag = memoryTypeFromProperties(memoryroperties, index_mem_reqs.memoryTypeBits, index_requirements_mask, &index_alloc_info.memoryTypeIndex);
if (index_flag)
{
printf("确定内存类型成功 类型索引为%d\n", index_alloc_info.memoryTypeIndex);
}
else
{
printf("确定内存类型失败!\n");
}
//为顶点数据缓冲分配内存
result = vkAllocateMemory(device, &index_alloc_info, NULL, &indexDataMem);
assert(result == VK_SUCCESS);
uint8_t *index_pData;
//将显存映射为CPU可访问
result = vkMapMemory(device, indexDataMem, 0, index_mem_reqs.size, 0, (void **)&index_pData);
assert(result == VK_SUCCESS);
//将顶点数据拷贝进显存
memcpy(index_pData, idata, indexByteCount);
//解除内存映射
vkUnmapMemory(device, indexDataMem);
//绑定内存与缓冲
result = vkBindBufferMemory(device, indexDatabuf, indexDataMem, 0);
assert(result == VK_SUCCESS);
//记录Buffer Info
indexDataBufferInfo.buffer = indexDatabuf;
indexDataBufferInfo.offset = 0;
indexDataBufferInfo.range = index_mem_reqs.size;
}
接下来介绍物体的绘制方法——drawSelf,其主要功能为将命令缓冲与管线、管线布局、描述集、顶点数据、索引数据进行绑定并执行绘制,具体代码如下。
void DrawableObjectCommonLight::drawSelf(VkCommandBuffer& cmd, VkPipelineLayout& pipelineLayout, VkPipeline& pipeline, VkDescriptorSet* desSetPointer, uint32_t sIndex, uint32_t eIndex)
{
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);//将当前使用的命令缓冲与指定管线绑定
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, desSetPointer, 0, NULL);//将命令缓冲、管线布局、描述集绑定
const VkDeviceSize offsetsVertex[1] = { 0 };//顶点数据偏移量数组
vkCmdBindVertexBuffers(//将顶点数据与当前使用的命令缓冲绑定
cmd, //当前使用的命令缓冲
0, //顶点数据缓冲在列表中的首索引
1, //绑定顶点缓冲的数量
&(vertexDatabuf), //绑定的顶点数据缓冲列表
offsetsVertex //各个顶点数据缓冲的内部偏移量
);
float* mvp = MatrixState3D::getFinalMatrix(); //获取总变换矩阵
memcpy(pushConstantData, mvp, sizeof(float) * 16); //将总变换矩阵拷贝入内存
vkCmdPushConstants(cmd, pipelineLayout, //将常量数据送入管线
VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(float) * 16, pushConstantData);
// 调用vkCmdBindIndexBuffer方法将索引数据缓冲与使用的命令缓冲绑定。
//调用vkCmdDrawIndexed方法执行索引绘制,由sIndex与eIndex确定了实际参与绘制的索引数量和范围。
vkCmdBindIndexBuffer( //将顶点数据与当前使用的命令缓冲绑定
cmd, //当前使用的命令缓冲
indexDatabuf, //索引数据缓冲
0, //索引数据缓冲首索引
VK_INDEX_TYPE_UINT16); //索引数据类型
//调用vkCmdDrawIndexed方法执行索引绘制,
vkCmdDrawIndexed( //执行索引绘制 //
cmd, //当前使用的命令缓冲
eIndex - sIndex, //索引数量 //由sIndex与eIndex确定了实际参与绘制的索引数量和范围。
1, //需要绘制的实例数量
sIndex, //绘制用起始索引
0, //顶点数据偏移量
0); //需要绘制的第1 个实例的索引
}
绘制方法
void MyVulkanManager::drawObject()
{
FPSUtil::init();//初始化FPS计算
while (MyVulkanManager::loopDrawFlag)//每循环一次绘制一帧画面
{
FPSUtil::calFPS();//计算FPS
FPSUtil::before();//一帧开始
//获取交换链中的当前帧索引
VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAcquiredSemaphore, VK_NULL_HANDLE, ¤tBuffer);
//为渲染通道设置当前帧缓冲
rp_begin.framebuffer = framebuffers[currentBuffer];
vkResetCommandBuffer(cmdBuffer, 0);//恢复命令缓冲到初始状态
result = vkBeginCommandBuffer(cmdBuffer, &cmd_buf_info);//启动命令缓冲
MyVulkanManager::flushUniformBuffer();//将当前帧相关数据送入一致变量缓冲
MyVulkanManager::flushTexToDesSet();//更新绘制用描述集
vkCmdBeginRenderPass(cmdBuffer, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);//启动渲染通道
MatrixState3D::pushMatrix(); //保护现场
MatrixState3D::rotate(xAngle, 1, 0, 0); //绕X轴旋转xAngle
MatrixState3D::rotate(yAngle, 0, 1, 0); //绕Y轴旋转yAngle
MatrixState3D::pushMatrix(); //保护现场
MatrixState3D::translate(0, 50, 0); //沿Y 轴正方向平移50
cirForDraw->drawSelf(cmdBuffer, sqsCL->pipelineLayout, //绘制正十边形
sqsCL->pipeline, &(sqsCL->descSet[0]), 0, CircleData::iCount);
MatrixState3D::popMatrix(); //恢复现场
MatrixState3D::pushMatrix(); //保护现场
MatrixState3D::translate(0, -50, 0); //沿Y 轴负方向平移50
cirForDraw->drawSelf(cmdBuffer, sqsCL->pipelineLayout, //绘制扇形
sqsCL->pipeline, &(sqsCL->descSet[0]), 0, CircleData::iCount / 2 + 1);
MatrixState3D::popMatrix(); //恢复现场
MatrixState3D::popMatrix();
vkCmdEndRenderPass(cmdBuffer);//结束渲染通道
result = vkEndCommandBuffer(cmdBuffer);//结束命令缓冲
submit_info[0].waitSemaphoreCount = 1;//等待的信号量数量
submit_info[0].pWaitSemaphores = &imageAcquiredSemaphore;//等待的信号量列表
result = vkQueueSubmit(queueGraphics, 1, submit_info, taskFinishFence);//提交命令缓冲
do { //等待渲染完毕
result =vkWaitForFences(device, 1, &taskFinishFence, VK_TRUE, FENCE_TIMEOUT);
} while (result == VK_TIMEOUT);
vkResetFences(device, 1, &taskFinishFence);//重置栅栏
present.pImageIndices = ¤tBuffer;//指定此次呈现的交换链图像索引
result =vkQueuePresentKHR(queueGraphics, &present);//执行呈现
FPSUtil::after(60);//限制FPS不超过指定的值
}
}