我们来用Qt和OpenGL绘制一个倒影,先看一下显示效果:
绘制方法比较简单,步骤如下:
绘制部分的关键代码如下:
// 开启深度测试
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
// 开启蒙版测试
glEnable(GL_STENCIL_TEST);
glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glClearColor(100.0f / 255.0f, 100.0f / 255.0f, 100.0f / 255.0f, 1.0f);
glClearStencil(0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// 绘制灯光
m_pCamera->activeCamera(m_pLightShaderProgram);
drawLight();
// 使用shader
m_pShaderProgram->bind();
// 设置光的信息
m_pShaderProgram->setUniformValue("lightMaterial.enabled", true);
m_pShaderProgram->setUniformValue("lightMaterial.direction", m_light.lightPos);
m_pShaderProgram->setUniformValue("lightMaterial.ambient", m_light.ambientColor);
m_pShaderProgram->setUniformValue("lightMaterial.diffuse", m_light.diffuesColor);
m_pShaderProgram->setUniformValue("lightMaterial.specular", m_light.specularColor);
m_pShaderProgram->setUniformValue("objectMaterial.shininess", 32.0f);
// 設置眼睛的位置
if (m_pCamera)
{
QVector3D cameraPos = m_pCamera->getCameraPostion();
m_pShaderProgram->setUniformValue("M_ViewPostion", cameraPos);
}
// 设置视图矩阵和投影矩阵
m_pCamera->activeCamera(m_pShaderProgram);
// ======================= 以下为真正的绘制部分 ======================
glStencilMask(0x00);
// 绘制盒子
drawTwoBox();
// 写入蒙版缓冲区
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilMask(0xFF);
// 绘制地板
glDepthMask(GL_FALSE);
drawFloor();
glDepthMask(GL_TRUE);
// 绘制盒子的倒影
glStencilFunc(GL_EQUAL, 1, 0xFF);
glStencilMask(0x00);
drawInvertedBox();
glStencilMask(0xFF);
m_pShaderProgram->release();
因为这里的地板足够的长,因此这里的蒙版缓冲相关的设置的效果没有那么的明显,如果我们把地板改的小一点,就会有下面的效果:
倒影会根据地板的大小而显示应该显示的大小,这正是我们想要的效果。因为只有绘制地板的区域将蒙版缓冲区写入了1,而绘制倒影的时候,也只有蒙版缓冲区为1的片段才会通过蒙版测试。
绘制倒影的箱子,只需要设置模型矩阵的缩放时,将Y轴缩放-1倍,就是实现了倒影的效果
void drawBox(const QVector3D& pos, bool isInverted)
{
QMatrix4x4 mat;
mat.translate(pos);
mat.rotate(m_angle, QVector3D(0.0f, 1.0f, 0.0f));
if (isInverted)
mat.scale(1.0f, -1.0f, 1.0f);
// 设置模型矩阵
m_pShaderProgram->setUniformValue("M", mat);
// 绘制箱子
m_pMesh->draw();
}
最后的,将倒影的箱子变灰一点,这里我直接对每个片段乘以了一个向量 (0.2, 0.2, 0.2)
shader中的直接乘以这个设置的向量即可:
gl_FragColor = vec4((ambient + diffuse) * objectFactor, 1.0);
CPU中设置该向量:
void drawInvertedBox(void)
{
m_pShaderProgram->setUniformValue("objectFactor", QVector3D(0.2f, 0.2f, 0.2f));
// 绘制盒子
drawBox(QVector3D(0.0f, -2.5f, 0.0f), true);
drawBox(QVector3D(2.0f, -2.5f, 2.0f), true);
}
完整代码下载-第17个样例(目前实现了20个样例,持续更新中):
https://github.com/douzhongqiang/QtLearnOpenGL
代码中用到了Assimp的库,我这里提供了编译好的VS2019 x64的库
https://download.csdn.net/download/douzhq/15137709