2021SC@SDUSC
目录
一、Shader介绍
Shader(着色器),是用来实现图形渲染的,实现了图形渲染可以让模型的材质、光滑程度有更好的表现,能让模型在光照下显示出更真实的效果。目前渲染管线一般有两种,一种是固定渲染管线,另一种为可编程渲染管线,Dust3d中使用了可编程渲染管线对模型进行渲染。
渲染管线:渲染管线实现的是将三维模型进行坐标转换、光照计算以及进行贴图,输出三维模型在摄像机下的样子,转换到屏幕空间进行输出。
固定渲染管线:固定渲染管线分为三个阶段。
第一个阶段是应用程序阶段,此阶段在CPU上进行,主要实现的是在视锥中进行可见性判断,将裁剪后的几何体及顶点坐标、法向量、纹理贴图坐标等传给GPU;
第二个阶段是在GPU上进行的几何阶段,该阶段主要负责顶点坐标变换以及光照计算,坐标变换主要需要将三维空间坐标转换为二维平面坐标,光照计算是因为在现实生活中我们可以看到不同的材质对接收到的光照有不同的效果,有的会呈现漫反射效果,有的会呈现镜面反射效果,在此阶段的光照计算就是对物体在光照下呈现的效果的模拟;
第三个阶段是光栅化处理,光栅化处理进行了着色运算和深度测试,计算每个像素点的颜色,实现了渲染。
固定渲染管线就像是在渲染的各种方式上进行开关操作,通过不同的组合来实现不同的渲染效果。
可编程渲染管线:可编程渲染管线正如它的名字,可以通过编程的方式来自定义光照的模式、贴图的方式等,有更高的自由度,同时也能实现比固定渲染管线更好的效果。
二、在Dust3d中的渲染实现
通过向Dust3D中添加法线贴图、基本色、金属度等实现材质的改变,并将相关信息传输到渲染管线中进行渲染
(一)SimpleShaderMesh类
SimpleShaderMesh类中设定了顶点信息、三角面片的信息以及法线的信息
class SimpleShaderMesh
{
public:
SimpleShaderMesh(std::vector<QVector3D> *vertices,
std::vector<std::vector<size_t>> *triangles,
std::vector<std::vector<QVector3D>> *triangleCornerNormals) :
m_vertices(vertices),
m_triangles(triangles),
m_triangleCornerNormals(triangleCornerNormals)
{
}
SimpleShaderMesh(const SimpleShaderMesh &mesh)
{
if (nullptr != mesh.m_vertices)
m_vertices = new std::vector<QVector3D>(*mesh.m_vertices);
if (nullptr != mesh.m_triangles)
m_triangles = new std::vector<std::vector<size_t>>(*mesh.m_triangles);
if (nullptr != mesh.m_triangleCornerNormals)
m_triangleCornerNormals = new std::vector<std::vector<QVector3D>>(*mesh.m_triangleCornerNormals);
}
~SimpleShaderMesh()
{
delete m_vertices;
delete m_triangles;
delete m_triangleCornerNormals;
}
const std::vector<QVector3D> *vertices()
{
return m_vertices;
}
const std::vector<std::vector<size_t>> *triangles()
{
return m_triangles;
}
const std::vector<std::vector<QVector3D>> *triangleCornerNormals()
{
return m_triangleCornerNormals;
}
private:
std::vector<QVector3D> *m_vertices = nullptr;
std::vector<std::vector<size_t>> *m_triangles = nullptr;
std::vector<std::vector<QVector3D>> *m_triangleCornerNormals = nullptr;
};
(二)类SimpleShaderMeshGenerator
1.takeRenderMesh
用于获取需要进行渲染的面片,通过上面的SimpleShaderMesh类可以得知renderMesh中携带着点、面以及法线信息
SimpleShaderMesh *takeRenderMesh()
{
SimpleShaderMesh *renderMesh = m_renderMesh;
m_renderMesh = nullptr;
return renderMesh;
}
2.generate函数
根据顶点、面片以及发现信息生成SimpleShaderMesh;当没有法线信息的时候进行计算,其中triangleNormal是每个点对面的平面的单位法向量
normal(v1,v2,v3):求的是v3-v1、v2-v1所在平面的法向量
void SimpleRenderMeshGenerator::generate()
{
if (nullptr == m_triangleCornerNormals ||
m_triangleCornerNormals->empty()) {
delete m_triangleCornerNormals;
m_triangleCornerNormals = new std::vector<std::vector<QVector3D>>(m_triangles->size());
for (size_t i = 0; i < m_triangles->size(); ++i) {
const auto &triangle = (*m_triangles)[i];
//normal(v1,v2,v3):求v2-v1、v3-v1所在平面的法向量
QVector3D triangleNormal = QVector3D::normal(
(*m_vertices)[triangle[0]],
(*m_vertices)[triangle[1]],
(*m_vertices)[triangle[2]]
);
(*m_triangleCornerNormals)[i] = {triangleNormal,
triangleNormal, triangleNormal
};
}
}
delete m_renderMesh;
m_renderMesh = new SimpleShaderMesh(m_vertices, m_triangles, m_triangleCornerNormals);
m_vertices = nullptr;
m_triangles = nullptr;
m_triangleCornerNormals = nullptr;
}
3.信号-槽机制
信号函数:void finished();
槽函数:void process();
当接收到信号函数finished,就会触发process函数,执行generate函数,生成RenderMesh
void SimpleRenderMeshGenerator::process()
{
generate();
emit finished();
}