构建一个球体对象
BallData.h
#ifndef VULKANEXBASE_BALLDATA_H
#define VULKANEXBASE_BALLDATA_H//防止重复引用
class BallData
{
public:
static float* vdata;//顶点数据数组首地址指针
static int dataByteCount;//顶点数据所占总字节数
static int vCount;//顶点数量
static void genBallData(float angleSpan);//生成顶点数据的方法
};
#endif
BallData.cpp
#include "BallData.h"
#include <vector>
#include <math.h>
#include <string.h>
float* BallData::vdata;//顶点数据数组首地址指针
int BallData::dataByteCount;//顶点数据所占总字节数
int BallData::vCount;//顶点数量
//主要包括两个方法toRadians和genBallData。toRadians方法的功能为将角度转换为弧度
float toRadians(float degree)
{//角度转换成弧度的方法
return (float)(degree*3.1415926535898 / 180.0);
}
void BallData::genBallData(float angleSpan)
{//生成球面上各个小三角形顶点数据的方法
const float r = 1.0f;//球的半径
std::vector<float> alVertix;//存放顶点坐标值的vector
//的angleSpan为将球面进行经纬度方向拆分的单位角度,此角度值越小,拆分得就越细,绘制出来的形状也越接近于球。
//用双层for循环将球按照一定的角度跨度(angleSpan)沿经度、纬度方向进行拆分。每次循环到一组纬度、经度时都将对应顶点看作一个小四边形的左上侧点,然后按照规律计算出小四边形中其他3个顶点的坐标,最后按照需要将用于卷绕成两个三角形的6个顶点的坐标依次存入vector列表。
for (float vAngle = -90; vAngle < 90; vAngle = vAngle + angleSpan)
{//垂直方向切分
for (float hAngle = 0; hAngle <= 360; hAngle = hAngle + angleSpan)
{//水平方向切分
//行首先计算出了顶点数量、顶点数据总字节数,然后将拆分的顶点坐标数据转存进数据数组中
float x0 = (float)(r * cos(toRadians(vAngle)) * cos(toRadians(hAngle)));
float y0 = (float)(r * cos(toRadians(vAngle)) * sin(toRadians(hAngle)));
float z0 = (float)(r *sin(toRadians(vAngle)));
float x1 = (float)(r * cos(toRadians(vAngle)) * cos(toRadians(hAngle + angleSpan)));
float y1 = (float)(r * cos(toRadians(vAngle)) *sin(toRadians(hAngle + angleSpan)));
float z1 = (float)(r * sin(toRadians(vAngle)));
float x2 = (float)(r*cos(toRadians(vAngle + angleSpan)) * cos(toRadians(hAngle + angleSpan)));
float y2 = (float)(r*cos(toRadians(vAngle + angleSpan)) * sin(toRadians(hAngle + angleSpan)));
float z2 = (float)(r * sin(toRadians(vAngle + angleSpan)));
float x3 = (float)(r * cos(toRadians(vAngle + angleSpan)) * cos(toRadians(hAngle)));
float y3 = (float)(r * cos(toRadians(vAngle + angleSpan)) * sin(toRadians(hAngle)));
float z3 = (float)(r * sin(toRadians(vAngle + angleSpan)));
alVertix.push_back(x1); alVertix.push_back(y1); alVertix.push_back(z1);
alVertix.push_back(x3); alVertix.push_back(y3); alVertix.push_back(z3);
alVertix.push_back(x0); alVertix.push_back(y0); alVertix.push_back(z0);
alVertix.push_back(x1); alVertix.push_back(y1); alVertix.push_back(z1);
alVertix.push_back(x2); alVertix.push_back(y2); alVertix.push_back(z2);
alVertix.push_back(x3); alVertix.push_back(y3); alVertix.push_back(z3);
}
}
//首先计算出了顶点数量、顶点数据总字节数,然后将拆分的顶点坐标数据转存进数据数组中。
vCount = alVertix.size() / 3;//顶点的数量为坐标值数量的1/3,因为一个顶点有3个坐标分量
dataByteCount = alVertix.size() * sizeof(float);//计算顶点数据总字节数
vdata = new float[alVertix.size()];//创建存放顶点数据的数组
int index = 0;//辅助数组索引
for (int i = 0; i<vCount; i++)
{//将顶点数据存储到数组中
vdata[index++] = alVertix[i * 3 + 0];//保存顶点位置X分量
vdata[index++] = alVertix[i * 3 + 1];//保存顶点位置Y分量
vdata[index++] = alVertix[i * 3 + 2];//保存顶点位置Z分量
}
}
createDrawableObject
//创建绘制用物体
void MyVulkanManager::createDrawableObject()
{
//ShaderQueueSuit_Common类中用于设置顶点着色器输入属性信息的initVertexAttributeInfo方法的相关代码
BallData::genBallData(9);//生成球的顶点数据和法向量数据
ballForDraw = new DrawableObjectCommonLight(BallData::vdata, BallData::dataByteCount, BallData::vCount, device, memoryroperties);//创建绘制用球
}
initVertexAttributeInfo
void ShaderQueueSuit_Common::initVertexAttributeInfo()
{
//设置了所需顶点输入绑定描述结构体实例的几项属性值
vertexBinding.binding = 0;//对应绑定点
vertexBinding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; //数据输入频率为每顶点
//的顶点输入数据仅包含球面顶点的x、y、z位置坐标,因此每组数据的跨度字节数为3倍浮点数字节数。
vertexBinding.stride = sizeof(float) * 3;//每组数据的跨度字节数
//设置了顶点输入属性的绑定点、位置索引、数据格式及偏移量
vertexAttribs[0].binding = 0;//第1个顶点输入属性的绑定点
vertexAttribs[0].location = 0;//第1个顶点输入属性的位置索引
//。同时顶点输入属性只有一个,类型为VK_FORMAT_R32G32B32_SFLOAT表示3个浮点数。
vertexAttribs[0].format = VK_FORMAT_R32G32B32_SFLOAT;//第1个顶点输入属性的数据格式
vertexAttribs[0].offset = 0;//第1个顶点输入属性的偏移量
}
create_pipe_line
void ShaderQueueSuit_Common::create_pipe_line(VkDevice& device, VkRenderPass& renderPass)
{
//,这部分代码主要是使用了前面步骤设置好的顶点输入绑定描述结构体和顶点输入属性描述结构体实例。故这里的顶点输入绑定描述数量、顶点输入属性数量应该与前面步骤中的一致。
#define NUM_DYNAMIC_STATES 1 /*Viewport + Scissor*/
//VkDynamicState dynamicStateEnables[VK_DYNAMIC_STATE_RANGE_SIZE];//动态状态启用标志
VkDynamicState dynamicStateEnables[NUM_DYNAMIC_STATES];//动态状态启用标志
memset(dynamicStateEnables, 0, sizeof dynamicStateEnables); //设置所有标志为false
dynamicStateEnables[0] = VK_DYNAMIC_STATE_VIEWPORT; //视口为动态设置
VkPipelineVertexInputStateCreateInfo vi;//管线顶点数据输入状态创建信息
vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vi.pNext = NULL;//自定义数据的指针
vi.flags = 0;//供将来使用的标志
vi.vertexBindingDescriptionCount = 1;//顶点输入绑定描述数量 //这里
vi.pVertexBindingDescriptions = &vertexBinding;//顶点输入绑定描述列表
vi.vertexAttributeDescriptionCount = 1;//顶点输入属性数量
vi.pVertexAttributeDescriptions = vertexAttribs;//顶点输入属性描述列表
VkPipelineInputAssemblyStateCreateInfo ia;
ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
ia.pNext = NULL;
ia.flags = 0;
ia.primitiveRestartEnable = VK_FALSE;
ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; //这里
}
vertshadertext.vert
#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变量vposition传递给片元着色器的相关代码
out gl_PerVertex { vec4 gl_Position;}; //输出接口块
void main() { //主函数
gl_Position = myConstantVals.mvp * vec4(pos,1.0); //计算顶点最终位置
vcolor=color;//传递顶点颜色给片元着色器
}
的commonTexLight.frag˙ȼ
#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 (location = 0) in vec3 vcolor;//顶点着色器传入的顶点颜色数据
layout (location = 0) out vec4 outColor;//输出到渲染管线的片元颜色值
void main()
{
outColor=vec4(vcolor.rgb,1.0);//将顶点着色器传递过来的颜色值输出
}