点法向量和面法向量
是基于球面开发的,球面属于连续、平滑的曲面,因此面上的每个顶点都有确定的法向量。但现实世界中的物体表面并不都是连续、平滑的,此时对于面上的某些点的法向量计算就不那么直观了.
从图5-18中可以看出,顶点A位于长方体左、上、前3个面的交界处,此处是不光滑的。这种情况下顶点A的法向量有两种处理策略,具体情况如下。某些点的法向量计算就不那么直观了.
在顶点A的位置放置3个不同的顶点,并认为每个顶点仅属于一个面,各个顶点的法向量即为其所属面的法向量。这种策略就是面法向量的策略,比较适合棱角分明的物体。
顶点A的位置仅放置一个顶点,其法向量取其所属所有面法向量的平均值。这种策略就是点法向量策略,比较适合用于由多个小平面搭建平滑曲面的情况。角分明的物体。
首先给出的是采用面法向量策略的案例,中初始化立方体顶点及法向量数据的genData方法,其具体代码如下
CubeData.cpp
#include "CubeData.h"
#include <vector>
#include <math.h>
#include <string.h>
float* CubeData::vdata;
int CubeData::dataByteCount;
int CubeData::vCount;
void CubeData::genData()
{
const float rect = 1.0f;//立方体的边长
std::vector<float> alVertix;//存放顶点坐标的vector
std::vector<float> alNormal;// 存放法向量的vector
alVertix.push_back(rect); alVertix.push_back(rect); alVertix.push_back(rect);//1
alVertix.push_back(-rect); alVertix.push_back(rect); alVertix.push_back(rect);//2
alVertix.push_back(-rect); alVertix.push_back(-rect); alVertix.push_back(rect);//3
alVertix.push_back(rect); alVertix.push_back(rect); alVertix.push_back(rect);//1
alVertix.push_back(-rect); alVertix.push_back(-rect); alVertix.push_back(rect);//3
alVertix.push_back(rect); alVertix.push_back(-rect); alVertix.push_back(rect);// 2'
//后面
alVertix.push_back(rect); alVertix.push_back(rect); alVertix.push_back(-rect);//1
alVertix.push_back(-rect); alVertix.push_back(rect); alVertix.push_back(-rect);//2
alVertix.push_back(-rect); alVertix.push_back(-rect); alVertix.push_back(-rect);//3
alVertix.push_back(rect); alVertix.push_back(rect); alVertix.push_back(-rect);//1
alVertix.push_back(-rect); alVertix.push_back(-rect); alVertix.push_back(-rect);//3
alVertix.push_back(rect); alVertix.push_back(-rect); alVertix.push_back(-rect);// 2'
//左面
alVertix.push_back(-rect); alVertix.push_back(-rect); alVertix.push_back(-rect);//3
alVertix.push_back(-rect); alVertix.push_back(rect); alVertix.push_back(-rect);//2
alVertix.push_back(-rect); alVertix.push_back(rect); alVertix.push_back(rect);//1
alVertix.push_back(-rect); alVertix.push_back(-rect); alVertix.push_back(rect);//3
alVertix.push_back(-rect); alVertix.push_back(-rect); alVertix.push_back(-rect);//2
alVertix.push_back(-rect); alVertix.push_back(rect); alVertix.push_back(rect);//1
//右面
alVertix.push_back(rect); alVertix.push_back(-rect); alVertix.push_back(-rect);//3
alVertix.push_back(rect); alVertix.push_back(rect); alVertix.push_back(-rect);//2
alVertix.push_back(rect); alVertix.push_back(rect); alVertix.push_back(rect);//1
alVertix.push_back(rect); alVertix.push_back(-rect); alVertix.push_back(rect);//3
alVertix.push_back(rect); alVertix.push_back(-rect); alVertix.push_back(-rect);//2
alVertix.push_back(rect); alVertix.push_back(rect); alVertix.push_back(rect);//1
//上面
alVertix.push_back(-rect); alVertix.push_back(rect); alVertix.push_back(-rect);//3
alVertix.push_back(rect); alVertix.push_back(rect); alVertix.push_back(-rect);//2
alVertix.push_back(rect); alVertix.push_back(rect); alVertix.push_back(rect);//1
alVertix.push_back(-rect); alVertix.push_back(rect); alVertix.push_back(rect);//3
alVertix.push_back(-rect); alVertix.push_back(rect); alVertix.push_back(-rect);//2
alVertix.push_back(rect); alVertix.push_back(rect); alVertix.push_back(rect);//1
//下面
alVertix.push_back(-rect); alVertix.push_back(-rect); alVertix.push_back(-rect);//3
alVertix.push_back(rect); alVertix.push_back(-rect); alVertix.push_back(-rect);//2
alVertix.push_back(rect); alVertix.push_back(-rect); alVertix.push_back(rect);//1
alVertix.push_back(-rect); alVertix.push_back(-rect); alVertix.push_back(rect);//3
alVertix.push_back(-rect); alVertix.push_back(-rect); alVertix.push_back(-rect);//2
alVertix.push_back(rect); alVertix.push_back(-rect); alVertix.push_back(rect);//1
//前面
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(1);
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(1);
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(1);
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(1);
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(1);
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(1);
//后面
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(-1);
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(-1);
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(-1);
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(-1);
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(-1);
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(-1);
//左面
alNormal.push_back(-1); alNormal.push_back(0); alNormal.push_back(0);
alNormal.push_back(-1); alNormal.push_back(0); alNormal.push_back(0);
alNormal.push_back(-1); alNormal.push_back(0); alNormal.push_back(0);
alNormal.push_back(-1); alNormal.push_back(0); alNormal.push_back(0);
alNormal.push_back(-1); alNormal.push_back(0); alNormal.push_back(0);
alNormal.push_back(-1); alNormal.push_back(0); alNormal.push_back(0);
//右面
alNormal.push_back(1); alNormal.push_back(0); alNormal.push_back(0);
alNormal.push_back(1); alNormal.push_back(0); alNormal.push_back(0);
alNormal.push_back(1); alNormal.push_back(0); alNormal.push_back(0);
alNormal.push_back(1); alNormal.push_back(0); alNormal.push_back(0);
alNormal.push_back(1); alNormal.push_back(0); alNormal.push_back(0);
alNormal.push_back(1); alNormal.push_back(0); alNormal.push_back(0);
//上面
alNormal.push_back(0); alNormal.push_back(1); alNormal.push_back(0);
alNormal.push_back(0); alNormal.push_back(1); alNormal.push_back(0);
alNormal.push_back(0); alNormal.push_back(1); alNormal.push_back(0);
alNormal.push_back(0); alNormal.push_back(1); alNormal.push_back(0);
alNormal.push_back(0); alNormal.push_back(1); alNormal.push_back(0);
alNormal.push_back(0); alNormal.push_back(1); alNormal.push_back(0);
//下面
alNormal.push_back(0); alNormal.push_back(-1); alNormal.push_back(0);
alNormal.push_back(0); alNormal.push_back(-1); alNormal.push_back(0);
alNormal.push_back(0); alNormal.push_back(-1); alNormal.push_back(0);
alNormal.push_back(0); alNormal.push_back(-1); alNormal.push_back(0);
alNormal.push_back(0); alNormal.push_back(-1); alNormal.push_back(0);
alNormal.push_back(0); alNormal.push_back(-1); alNormal.push_back(0);
vCount = alVertix.size() / 3;// 顶点的数量为坐标值数量的1/3,因为一个顶点有3个坐标
dataByteCount = alVertix.size() * 2 * sizeof(float);//顶点和法向量数据的总字节数
vdata = new float[alVertix.size() * 2];//存放顶点坐标和法向量数据的数组
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 分量
vdata[index++] = alNormal[i * 3 + 0]; //保存顶点法向量X 分量
vdata[index++] = alNormal[i * 3 + 1]; //保存顶点法向量Y 分量
vdata[index++] = alNormal[i * 3 + 2]; //保存顶点法向量Z 分量
}
}
CubeData.cpp
#include "CubeData.h"
#include <vector>
#include <math.h>
#include <string.h>
float* CubeData::vdata;
int CubeData::dataByteCount;
int CubeData::vCount;
void CubeData::genData()
{
const float rect = 1.0f;//立方体的边长
std::vector<float> alVertix;//存放顶点坐标的vector
std::vector<float> alNormal;// 存放法向量的vector
alVertix.push_back(rect); alVertix.push_back(rect); alVertix.push_back(rect);//1
alVertix.push_back(-rect); alVertix.push_back(rect); alVertix.push_back(rect);//2
alVertix.push_back(-rect); alVertix.push_back(-rect); alVertix.push_back(rect);//3
alVertix.push_back(rect); alVertix.push_back(rect); alVertix.push_back(rect);//1
alVertix.push_back(-rect); alVertix.push_back(-rect); alVertix.push_back(rect);//3
alVertix.push_back(rect); alVertix.push_back(-rect); alVertix.push_back(rect);// 2'
//后面
alVertix.push_back(rect); alVertix.push_back(rect); alVertix.push_back(-rect);//1
alVertix.push_back(-rect); alVertix.push_back(rect); alVertix.push_back(-rect);//2
alVertix.push_back(-rect); alVertix.push_back(-rect); alVertix.push_back(-rect);//3
alVertix.push_back(rect); alVertix.push_back(rect); alVertix.push_back(-rect);//1
alVertix.push_back(-rect); alVertix.push_back(-rect); alVertix.push_back(-rect);//3
alVertix.push_back(rect); alVertix.push_back(-rect); alVertix.push_back(-rect);// 2'
//左面
alVertix.push_back(-rect); alVertix.push_back(-rect); alVertix.push_back(-rect);//3
alVertix.push_back(-rect); alVertix.push_back(rect); alVertix.push_back(-rect);//2
alVertix.push_back(-rect); alVertix.push_back(rect); alVertix.push_back(rect);//1
alVertix.push_back(-rect); alVertix.push_back(-rect); alVertix.push_back(rect);//3
alVertix.push_back(-rect); alVertix.push_back(-rect); alVertix.push_back(-rect);//2
alVertix.push_back(-rect); alVertix.push_back(rect); alVertix.push_back(rect);//1
//右面
alVertix.push_back(rect); alVertix.push_back(-rect); alVertix.push_back(-rect);//3
alVertix.push_back(rect); alVertix.push_back(rect); alVertix.push_back(-rect);//2
alVertix.push_back(rect); alVertix.push_back(rect); alVertix.push_back(rect);//1
alVertix.push_back(rect); alVertix.push_back(-rect); alVertix.push_back(rect);//3
alVertix.push_back(rect); alVertix.push_back(-rect); alVertix.push_back(-rect);//2
alVertix.push_back(rect); alVertix.push_back(rect); alVertix.push_back(rect);//1
//上面
alVertix.push_back(-rect); alVertix.push_back(rect); alVertix.push_back(-rect);//3
alVertix.push_back(rect); alVertix.push_back(rect); alVertix.push_back(-rect);//2
alVertix.push_back(rect); alVertix.push_back(rect); alVertix.push_back(rect);//1
alVertix.push_back(-rect); alVertix.push_back(rect); alVertix.push_back(rect);//3
alVertix.push_back(-rect); alVertix.push_back(rect); alVertix.push_back(-rect);//2
alVertix.push_back(rect); alVertix.push_back(rect); alVertix.push_back(rect);//1
//下面
alVertix.push_back(-rect); alVertix.push_back(-rect); alVertix.push_back(-rect);//3
alVertix.push_back(rect); alVertix.push_back(-rect); alVertix.push_back(-rect);//2
alVertix.push_back(rect); alVertix.push_back(-rect); alVertix.push_back(rect);//1
alVertix.push_back(-rect); alVertix.push_back(-rect); alVertix.push_back(rect);//3
alVertix.push_back(-rect); alVertix.push_back(-rect); alVertix.push_back(-rect);//2
alVertix.push_back(rect); alVertix.push_back(-rect); alVertix.push_back(rect);//1
//前面
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(1);
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(1);
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(1);
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(1);
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(1);
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(1);
//后面
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(-1);
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(-1);
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(-1);
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(-1);
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(-1);
alNormal.push_back(0); alNormal.push_back(0); alNormal.push_back(-1);
//左面
alNormal.push_back(-1); alNormal.push_back(0); alNormal.push_back(0);
alNormal.push_back(-1); alNormal.push_back(0); alNormal.push_back(0);
alNormal.push_back(-1); alNormal.push_back(0); alNormal.push_back(0);
alNormal.push_back(-1); alNormal.push_back(0); alNormal.push_back(0);
alNormal.push_back(-1); alNormal.push_back(0); alNormal.push_back(0);
alNormal.push_back(-1); alNormal.push_back(0); alNormal.push_back(0);
//右面
alNormal.push_back(1); alNormal.push_back(0); alNormal.push_back(0);
alNormal.push_back(1); alNormal.push_back(0); alNormal.push_back(0);
alNormal.push_back(1); alNormal.push_back(0); alNormal.push_back(0);
alNormal.push_back(1); alNormal.push_back(0); alNormal.push_back(0);
alNormal.push_back(1); alNormal.push_back(0); alNormal.push_back(0);
alNormal.push_back(1); alNormal.push_back(0); alNormal.push_back(0);
//上面
alNormal.push_back(0); alNormal.push_back(1); alNormal.push_back(0);
alNormal.push_back(0); alNormal.push_back(1); alNormal.push_back(0);
alNormal.push_back(0); alNormal.push_back(1); alNormal.push_back(0);
alNormal.push_back(0); alNormal.push_back(1); alNormal.push_back(0);
alNormal.push_back(0); alNormal.push_back(1); alNormal.push_back(0);
alNormal.push_back(0); alNormal.push_back(1); alNormal.push_back(0);
//下面
alNormal.push_back(0); alNormal.push_back(-1); alNormal.push_back(0);
alNormal.push_back(0); alNormal.push_back(-1); alNormal.push_back(0);
alNormal.push_back(0); alNormal.push_back(-1); alNormal.push_back(0);
alNormal.push_back(0); alNormal.push_back(-1); alNormal.push_back(0);
alNormal.push_back(0); alNormal.push_back(-1); alNormal.push_back(0);
alNormal.push_back(0); alNormal.push_back(-1); alNormal.push_back(0);
vCount = alVertix.size() / 3;// 顶点的数量为坐标值数量的1/3,因为一个顶点有3个坐标
dataByteCount = alVertix.size() * 2 * sizeof(float);//顶点和法向量数据的总字节数
vdata = new float[alVertix.size() * 2];//存放顶点坐标和法向量数据的数组
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 分量
vdata[index++] = alNormal[i * 3 + 0]; //保存顶点法向量X 分量
vdata[index++] = alNormal[i * 3 + 1]; //保存顶点法向量Y 分量
vdata[index++] = alNormal[i * 3 + 2]; //保存顶点法向量Z 分量
}
}
中原始情况下将立方体的几何中心放在了坐标原点,同时立方体的各条棱都与坐标轴平行,故每个顶点的平均法向量就没有必要真正进行求和再平均的计算了,直接采用各个顶点的x、y、z坐标值代替即可。但开发中点平均法向量的计算并不总是像本章的案例一样可以进行简化.
光照的每顶点计算与每片元计算
在顶点着色器中进行光照计算的。在顶点着色器中对每个顶点进行光照计算后得到顶点的最终光照强度,再由管线插值后传入片元着色器以计算片元的颜色,这样一方面效率比较高,另一方面产生的光照效果也不错。
但由于这种计算方式插值的是基于顶点计算后的光照强度,因此并不适用于所有的场景。若光源离被照射物体各个三角形面的距离与三角形的尺寸接近时,这样的计算策略形成的视觉效果就可能很不真实了. 每顶点计算光照的方式在图形学中称之为Gouraud着色,每片元计算光照的方式在图形学中称之为Phong着色。
FlatData.h
#ifndef VULKANEXBASE_BALLDATA_H
#define VULKANEXBASE_BALLDATA_H //防止重复引用
class FlatData {
public:
static float* vdata; //数据数组首地址指针
static int dataByteCount; //数据所占总字节数
static int vCount; //顶点数量
static void genData(); //生成顶点数据的方法
};
#endif
FlatData.cpp
#include "FlatData.h"
#include <vector>
#include <math.h>
#include <string.h>
float* FlatData::vdata; //数据数组首地址指针
int FlatData::dataByteCount; //数据所占总字节数
int FlatData::vCount; //顶点数量
void FlatData::genData() { //顶点数据生成方法
vCount = 6; //顶点数量为6
dataByteCount = vCount * 6 * sizeof(float); //数据所占内存总字节数
vdata = new float[vCount * 6]{ //顶点数据数组
3, 2, 0, 0, 0, 1, -3, 2, 0, 0, 0, 1, //每个顶点6 个数据
-3, -2, 0, 0, 0, 1, 3, -2, 0, 0, 0, 1, //前3 个是顶点位置坐标XYZ 分量
3, 2, 0, 0, 0, 1, -3, -2, 0, 0, 0, 1 }; //后3 个是顶点法向量XYZ 分量
}
该平面物体的顶点坐标与法向量数据都是存储在同一个数组中的。该平面为一个垂直于z轴并且过原点的平面,其法向量与z轴正方向相同。
create_pipeline_layout方法部分相关代码
//创建管线layout
void ShaderQueueSuit_Common::create_pipeline_layout(VkDevice& device)
{
//此方法中主要是更改了一致变量缓冲的目标着色器阶段,将原来的VK_SHADER_STAGE_VERTEX_BIT(顶点着色器阶段)替换为VK_SHADER_STAGE_FRAGMENT _BIT(片元着色器阶段)。
//替换的主要目的是将摄像机位置一致变量、光源位置一致变量和光照强度一致变量送入片元着色器,从而在片元着色器中进行光照计算。GMENT _BIT(片元着色器阶段)。
VkDescriptorSetLayoutBinding layout_bindings[1];//描述集布局绑定数组
layout_bindings[0].binding = 0;//此绑定的绑定点编号
layout_bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;//描述类型
layout_bindings[0].descriptorCount = 1;//描述数量
layout_bindings[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
layout_bindings[0].pImmutableSamplers = NULL;
VkDescriptorSetLayoutCreateInfo descriptor_layout = {}; //构建描述集布局创建信息结构体实例
descriptor_layout.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;//结构体类型
descriptor_layout.pNext = NULL;//自定义数据的指针
descriptor_layout.bindingCount = 1;//描述集布局绑定的数量
descriptor_layout.pBindings = layout_bindings;//描述集布局绑定数组
//调整空间
descLayouts.resize(NUM_DESCRIPTOR_SETS);//调整描述集布局列表尺寸
VkResult result = vkCreateDescriptorSetLayout(device, &descriptor_layout, NULL, descLayouts.data());//创建描述集布局
assert(result == VK_SUCCESS);//检查描述集布局创建是否成功
VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = {};//构建管线布局创建信息结构体实例
pPipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pPipelineLayoutCreateInfo.pNext = NULL;//自定义数据的指针
pPipelineLayoutCreateInfo.pushConstantRangeCount = 0;
pPipelineLayoutCreateInfo.pPushConstantRanges = NULL;
pPipelineLayoutCreateInfo.setLayoutCount = NUM_DESCRIPTOR_SETS;//描述集布局的数量
pPipelineLayoutCreateInfo.pSetLayouts = descLayouts.data();//描述集布局列表
result = vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, NULL, &pipelineLayout);//创建管线布局
assert(result == VK_SUCCESS);//检查创建是否成功
}
commonTextLight.vert
#version 450
#extension GL_ARB_separate_shader_objects : enable//开启separate_shader_objects
#extension GL_ARB_shading_language_420pack : enable //开启shading_language_420pack
layout (push_constant) uniform constantVals {//一致块
mat4 mvp;//最终变换矩阵
mat4 mm;//基本变换矩阵
} myConstantVals;
layout (location = 0) in vec3 pos;//传入的顶点位置
layout (location = 1) in vec3 inNormal; //传入的顶点法向量
//声明的输出变量vposition用于将世界坐标系下的顶点坐标传入片元着色器,以备在片元着色器中计算光照时使用。
layout (location = 1) out vec3 vposition;//输出的顶点位置
layout (location = 2) out vec3 vNormal; //传出的世界坐标系法向量
//。而声明的输出变量objPos用于将物体坐标系下的顶点坐标传入片元着色器,以备计算棋盘着色的时候使用。
layout (location = 3) out vec3 objPos; //传出的物体坐标系顶点坐标
out gl_PerVertex {//输出接口块
vec4 gl_Position;//顶点最终位置
};
//新增的将物体坐标系法向量变换到世界坐标系的normalFromObjectToWorld方法,此方法中的具体操作与前面案例中对应的部分基本相同。
vec3 normalFromObjectToWorld( //将物体坐标系的法向量变换到世界坐标系的方法
in mat4 uMMatrix, //基本变换矩阵
in vec3 normal, //法向量
in vec3 position){ //顶点位置
vec3 normalTarget=position+normal; //计算变换后的法向量
vec3 newNormal=(uMMatrix*vec4(normalTarget,1)).xyz-(uMMatrix*vec4(position,1)).xyz;
newNormal=normalize(newNormal); //对法向量规格化
return newNormal; //返回世界坐标系法向量
}
void main(){//主函数
gl_Position = myConstantVals.mvp * vec4(pos,1.0);//计算顶点最终位置
vposition=(myConstantVals.mm*vec4(pos,1)).xyz; //计算世界坐标系顶点位置
vNormal = normalFromObjectToWorld(myConstantVals.mm,inNormal,pos);//计算世界坐标系法向量
objPos=pos; //传送到片元着色器的物体坐标系顶点位置
}
commonTexLigh.frag
//在片元着色器中执行光照计算时的大部分操作与在顶点着色器中进行光照计算时完全相同。
#version 450
#extension GL_ARB_separate_shader_objects : enable//开启separate_shader_objects
#extension GL_ARB_shading_language_420pack : enable//开启shading_language_420pack
layout (std140,set = 0, binding = 0) uniform bufferVals { //一致块
vec4 uCamera; //摄像机位置
vec4 lightPosition; //光源位置
vec4 lightAmbient; //环境光强度
vec4 lightDiffuse; //散射光强度
vec4 lightSpecular; //镜面光强度
} myBufferVals;
layout (location = 1) in vec3 vposition;//顶点着色器传入的顶点位置
layout (location = 2) in vec3 vNormal; //传入的世界坐标系法向量
layout (location = 3) in vec3 objPos; //传入的物体坐标系顶点位置
layout (location = 0) out vec4 outColor;//输出到渲染管线的片元颜色值
vec4 genBoardColor(vec3 position){
const float height=4.0;//球的半径
const float width=6.0;
vec4 color;//结果颜色
float n = 8.0;//球体外接立方体每个坐标轴方向切分的份数
float spanh = height/n;//每一份的尺寸(小方块的边长)
float spanw = width/n;
//为了保证不出现负数
int i = int((position.x + 10.0)/spanw);//当前片元位置小方块的行数
int j = int((position.y + 10.0)/spanh);//当前片元位置小方块的层数
//计算当前片元行数、层数、列数的和并对2取模
int whichColor = int(mod(float(i+j),2.0));
if(whichColor == 1){ //奇数时为颜色A
color = vec4(0.678,0.231,0.129,1.0);//红色
}
else {//偶数时为白色
color = vec4(1.0,1.0,1.0,1.0);//白色
}
return color;//返回结果颜色
}
vec4 pointLight( //定位光光照计算的方法
//最主要的区别是计算光照时不需要再将法向量由物体坐标系变换到世界坐标系了,直接使用顶点着色器传递过来的世界坐标系中的法向量即可
//因此每片元计算光照与每顶点计算光照并没有本质区别,只是执行光照计算的位置不同、效果与效率不同而已。实际开发中读者应该权衡速度、效果的要求,选用合适的光照计算策略。
in vec3 uCamera, //摄像机位置
in vec3 lightLocation, //光源位置
in vec4 lightAmbient, //环境光强度
in vec4 lightDiffuse, //散射光强度
in vec4 lightSpecular, //镜面光强度
in vec3 normal, //法向量
in vec3 aPosition){ //顶点位置
vec4 ambient; //环境光最终强度
vec4 diffuse; //散射光最终强度
vec4 specular; //镜面光最终强度
ambient=lightAmbient; //直接得出环境光的最终强度
vec3 eye= normalize(uCamera-aPosition); //计算从表面点到摄像机的向量
vec3 vp= normalize(lightLocation.xyz-aPosition); //计算从表面点到光源位置的向量vp
vp=normalize(vp); //格式化vp 向量
vec3 halfVector=normalize(vp+eye); //求视线与vp 向量的半向量
float shininess=10.0; //粗糙度,越小越光滑
float nDotViewPosition=max(0.0,dot(normal,vp)); //求法向量与vp 的点积与0 的最大值
diffuse=lightDiffuse*nDotViewPosition; //计算散射光的最终强度
float nDotViewHalfVector=dot(normal,halfVector); //法向量与半向量的点积
float powerFactor=max(0.0,pow(nDotViewHalfVector,shininess)); //镜面反射光强度因子
specular=lightSpecular*powerFactor; //计算镜面光的最终强度
return ambient+diffuse+specular; //将三个光照通道最终强度值求和返回
}
void main(){//主方法
vec4 lightQD=pointLight( //定位光光照计算的方法
myBufferVals.uCamera.xyz, //摄像机位置
myBufferVals.lightPosition.xyz, //光源位置
myBufferVals.lightAmbient, //环境光强度
myBufferVals.lightDiffuse, //散射光强度
myBufferVals.lightSpecular, //镜面光强度
vNormal, //世界坐标系法向量
vposition ); //世界坐标系顶点位置
outColor=genBoardColor(objPos)*lightQD; //计算片元最终颜色值
}
commonTexLight.vert
#version 400
#extension GL_ARB_separate_shader_objects : enable//开启separate_shader_objects
#extension GL_ARB_shading_language_420pack : enable //开启shading_language_420pack
layout (std140,set = 0, binding = 0) uniform bufferVals {
vec4 uCamera;
vec4 lightPosition;
vec4 lightAmbient;
vec4 lightDiffuse;
vec4 lightSpecular;
} myBufferVals;
layout (push_constant) uniform constantVals {//一致块
mat4 mvp;//最终变换矩阵
mat4 mm;//基本变换矩阵
} myConstantVals;
layout (location = 0) in vec3 pos;//传入的顶点位置
layout (location = 1) in vec3 inNormal; //传入的顶点法向量
layout (location = 0) out vec4 outLightQD;
layout (location = 1) out vec3 vposition;//输出的顶点位置
out gl_PerVertex {//输出接口块
vec4 gl_Position;//顶点最终位置
};
vec4 pointLight(
in mat4 uMMatrix, //基本变换矩阵
in vec3 uCamera,
in vec3 lightLocation,
in vec4 lightAmbient,
in vec4 lightDiffuse,
in vec4 lightSpecular,
in vec3 normal, //法向量
in vec3 aPosition
){
vec4 ambient;
vec4 diffuse;
vec4 specular;
ambient=lightAmbient;
vec3 normalTarget=aPosition+normal;
vec3 newNormal=(uMMatrix*vec4(normalTarget,1)).xyz-(uMMatrix*vec4(aPosition,1)).xyz;
newNormal=normalize(newNormal); //对法向量规格化
vec3 eye= normalize(uCamera-(uMMatrix*vec4(aPosition,1)).xyz);
vec3 vp= normalize(lightLocation-(uMMatrix*vec4(aPosition,1)).xyz);
vp=normalize(vp);
vec3 halfVector=normalize(vp+eye);
float shininess=50.0;
float nDotViewPosition=max(0.0,dot(newNormal,vp));
diffuse=lightDiffuse*nDotViewPosition;
float nDotViewHalfVector=dot(newNormal,halfVector);
float powerFactor=max(0.0,pow(nDotViewHalfVector,shininess));
specular=lightSpecular*powerFactor;
return ambient+diffuse+specular;
}
void main(){//主函数
outLightQD=pointLight(
myConstantVals.mm,
myBufferVals.uCamera.xyz,
myBufferVals.lightPosition.xyz,
myBufferVals.lightAmbient,
myBufferVals.lightDiffuse,
myBufferVals.lightSpecular,
inNormal,
pos
);
gl_Position = myConstantVals.mvp * vec4(pos,1.0);//计算顶点最终位置
vposition=pos;
}
commonTexLight.frag
#version 400
#extension GL_ARB_separate_shader_objects : enable//开启separate_shader_objects
#extension GL_ARB_shading_language_420pack : enable//开启shading_language_420pack
layout (location = 0) in vec4 inLightQD;
layout (location = 1) in vec3 vposition;//顶点着色器传入的顶点位置
layout (location = 0) out vec4 outColor;//输出到渲染管线的片元颜色值
vec4 genBoardColor(vec3 position)
{
const float height=4.0;//球的半径
const float width=6.0;
vec4 color;//结果颜色
float n = 8.0;//球体外接立方体每个坐标轴方向切分的份数
float spanh = height/n;//每一份的尺寸(小方块的边长)
float spanw = width/n;
//为了保证不出现负数
int i = int((position.x + 10.0)/spanw);//当前片元位置小方块的行数
int j = int((position.y + 10.0)/spanh);//当前片元位置小方块的层数
//计算当前片元行数、层数、列数的和并对2取模
int whichColor = int(mod(float(i+j),2.0));
if(whichColor == 1){ //奇数时为颜色A
color = vec4(0.678,0.231,0.129,1.0);//红色
}
else {//偶数时为白色
color = vec4(1.0,1.0,1.0,1.0);//白色
}
return color;//返回结果颜色
}
void main() {
outColor=inLightQD*genBoardColor(vposition);
}