北外网院网站建设作业,上海哪家公司做网站最好,襄阳教育云平台网站建设,wordpress的中文名称QTOpenGL模板测试和混合
本篇完整工程见gitee:QtOpenGL 对应点的tag#xff0c;由turbolove提供技术支持#xff0c;您可以关注博主或者私信博主
模板测试
当片段着色器处理完一个片段之后#xff0c;模板测试会开始执行。和深度测试一样#xff0c;它可能会丢弃片段OpenGL模板测试和混合
本篇完整工程见gitee:QtOpenGL 对应点的tag由turbolove提供技术支持您可以关注博主或者私信博主
模板测试
当片段着色器处理完一个片段之后模板测试会开始执行。和深度测试一样它可能会丢弃片段接下来被保留的片段会进入深度测试。
通常每个模板的值是8位的所以每个像素/片段一共能有256种不同的模板值。
启用模板缓冲的写入。渲染物体更新模板缓冲的内容。禁用模板缓冲的写入。渲染其它物体这次根据模板缓冲的内容丢弃特定的片段
// 启用模板缓冲
glEnable(GL_STENCIL_TEST);
// 清除模板缓冲
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);glStencilMask(0xFF); // 每一位写入模板缓冲时都保持原样
glStencilMask(0x00); // 每一位在写入模板缓冲时都会变成0禁用写入模板函数
一共有两个函数能够用来配置模板测试 glStenciFunc和glStencilOp
glStencilFunc(GLenum func, GLint ref, GLuint mask)func设置模板测试函数(Stencil Test Function)。这个测试函数将会应用到已储存的模板值上和glStencilFunc函数的ref值上。可用的选项有GL_NEVER、GL_LESS、GL_LEQUAL、GL_GREATER、GL_GEQUAL、GL_EQUAL、GL_NOTEQUAL和GL_ALWAYS。它们的语义和深度缓冲的函数类似。ref设置了模板测试的参考值(Reference Value)。模板缓冲的内容将会与这个值进行比较。mask设置一个掩码它将会与参考值和储存的模板值在测试比较它们之前进行与(AND)运算。初始情况下所有位都为1。
这个函数告诉opengl只要一个片段的模板值等于1它将会通过测试并被绘制否则会被丢弃。但glStencilFunc仅仅描述了OpenGL应该对模板缓冲内筒做什么而不是我们应该如何更新缓冲。
glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)sfail模板测试失败时采取的行为。dpfail模板测试通过但深度测试失败时采取的行为。dppass模板测试和深度测试都通过时采取的行为。
行为描述GL_KEEP保持当前储存的模板值GL_ZERO将模板值设置为0GL_REPLACE将模板值设置为glStencilFunc函数设置的ref值GL_INCR如果模板值小于最大值则将模板值加1GL_INCR_WRAP与GL_INCR一样但如果模板值超过了最大值则归零GL_DECR如果模板值大于最小值则将模板值减1GL_DECR_WRAP与GL_DECR一样但如果模板值小于0则将其设置为最大值GL_INVERT按位翻转当前的模板缓冲值
默认情况下glStencilOp是设置为(GL_KEEP, GL_KEEP, GL_KEEP)的所以不论任何测试的结果是如何模板缓冲都会保留它的值。默认的行为不会更新模板缓冲所以如果你想写入模板缓冲的话你需要至少对其中一个选项设置不同的值。
物体轮廓
在绘制需要添加轮廓的物体之前将模板函数设置为GL_ALWAYS每当物体的片段被渲染时将模板缓冲更新为1。渲染物体。禁用模板写入以及深度测试。将每个物体缩放一点点。使用一个不同的片段着色器输出一个单独的边框颜色。再次绘制物体但只在它们片段的模板值不等于1时才绘制。再次启用模板写入和深度测试。
代码展示
void TurboOpenGLWidget::paintGL()
{model.setToIdentity();view.setToIdentity();projection.setToIdentity();glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glEnable(GL_DEPTH_TEST);glEnable(GL_STENCIL_TEST);glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);glStencilMask(0x00); // 禁止模板缓冲的写入// float time m_time.elapsed() / 50.0;// model.rotate(time, 1.0f, 5.0f, 0.0f);shader_program_.bind();projection.perspective(camera_.getZoom(), float(width() / height()), near_, far_);view camera_.getViewMatrix();shader_program_.setUniformValue(projection, projection);shader_program_.setUniformValue(view, view);shader_program_.setUniformValue(viewPos, camera_.getPosition());shader_program_.setUniformValue(spotLight.ambient, QVector3D(0.7, 0.7, 0.7));shader_program_.setUniformValue(spotLight.diffuse, QVector3D(0.9, 0.9, 0.9)); // 将光照调暗了一些以搭配场景shader_program_.setUniformValue(spotLight.specular, QVector3D(1.0, 1.0, 1.0));shader_program_.setUniformValue(spotLight.position, camera_.getPosition());shader_program_.setUniformValue(spotLight.direction, camera_.getFront());shader_program_.setUniformValue(spotLight.cutOff, (float)cos(12.5f*3.1415926/180));shader_program_.setUniformValue(spotLight.outerCutOff, (float)cos(17.5f*PI/180));shader_program_.setUniformValue(spotLight.constant, 1.0f);shader_program_.setUniformValue(spotLight.linear, 0.09f); // 将光照调暗了一些以搭配场景shader_program_.setUniformValue(spotLight.quadratic, 0.032f);shader_program_.setUniformValue(dirLight.direction, -0.2, -1.0, -0.3);shader_program_.setUniformValue(dirLight.ambient, 0.05, 0.05, 0.05);shader_program_.setUniformValue(dirLight.diffuse, 0.4, 0.4, 0.4); // 将光照调暗了一些以搭配场景shader_program_.setUniformValue(dirLight.specular, 0.5, 0.5, 0.5);shader_program_.setUniformValue(material.shininess, 32.0f);shader_program_.setUniformValue(model, model);m_planeMesh-draw(shader_program_);shader_program_.release();signal_color_program_.bind();signal_color_program_.setUniformValue(projection, projection);signal_color_program_.setUniformValue(view, view);signal_color_program_.release();auto it models_.begin();while(it ! models_.end()){model.setToIdentity();model.translate(it.value().world_pos);model.rotate(it.value().pitch, QVector3D(1.0, 0.0, 0.0));model.rotate(it.value().yaw, QVector3D(0.0, 1.0, 0.0));model.rotate(it.value().roll, QVector3D(0.0, 0.0, 1.0));glStencilFunc(GL_ALWAYS, 1, 0xFF);glStencilMask(0xFF);shader_program_.bind();shader_program_.setUniformValue(model, model);it.value().model-draw(shader_program_);shader_program_.release();if(!it.value().is_selected){it;continue;}glStencilFunc(GL_NOTEQUAL, 1, 0xFF);glStencilMask(0x00);float heightit.value().model-max_y_-it.value().model-min_y_;float widthit.value().model-max_x_-it.value().model-min_x_;if(it.value().model-min_y_0)model.translate(0.0f,height/2,0.0f);model.scale(1.1f,1.00.1*(width/height));if(it.value().model-min_y_0)model.translate(0.0f,-height/2,0.0f);signal_color_program_.bind();signal_color_program_.setUniformValue(model, model);it.value().model-draw(signal_color_program_);signal_color_program_.release();glStencilMask(0xFF);glStencilFunc(GL_ALWAYS, 1, 0xFF);it;}update();
}混合
在OpenGL中混合主要是实现物体透明度的一中技术
丢弃片段
有些图片并不需要半透明只需要根据纹理颜色值显示一部分或者不显示一部分没有中间情况。
discard.frag
#version 330 core
struct Material {sampler2D diffuse;sampler2D specular;float shininess;
};uniform Material material;struct SpotLight {vec3 position;vec3 direction;vec3 ambient;vec3 diffuse;vec3 specular;float constant;float linear;float quadratic;float cutOff;float outerCutOff;
};struct DirLight {vec3 direction;vec3 ambient;vec3 diffuse;vec3 specular;
};uniform DirLight dirLight;
uniform SpotLight spotLight;struct PointLight {vec3 position;float constant;float linear;float quadratic;vec3 ambient;vec3 diffuse;vec3 specular;
};out vec4 FragColor;
uniform vec3 lightPos;
uniform vec3 viewPos;in vec3 Normal;
in vec3 fragPos;
in vec2 TexCoords;void main()
{vec4 texColortexture(material.diffuse,TexCoords);if(texColor.a 0.1) discard;FragColor texColor;
}
discard_program_.bind();
discard_program_.setUniformValue(projection, projection);
discard_program_.setUniformValue(view, view);
discard_program_.setUniformValue(model, model);foreach (auto item, vegetation) {model.setToIdentity();model.translate(item);discard_program_.setUniformValue(model, model);m_discardMesh-draw(discard_program_);
}具体的实现可以在项目中查询到。 混合
虽然直接丢弃片段很好但它不能让我们渲染半透明的图像。我们要么渲染一个片段要么完全丢弃它。要想渲染有多个透明度级别的图像我们需要启用混合(Blending)。和OpenGL大多数的功能一样我们可以启用GL_BLEND来启用混合
glEnable(GL_BLEND);源颜色向量。这是源自纹理的颜色向量。目标颜色向量。这是当前储存在颜色缓冲中的颜色向量。源因子值。指定了alpha值对源颜色的影响。目标因子值。指定了alpha值对目标颜色的影响。
选项值GL_ZERO因子等于GL_ONE因子等于GL_SRC_COLOR因子等于源颜色向量GL_ONE_MINUS_SRC_COLOR因子等于GL_DST_COLOR因子等于目标颜色向量GL_ONE_MINUS_DST_COLOR因子等于GL_SRC_ALPHA因子等于的分量GL_ONE_MINUS_SRC_ALPHA因子等于 的分量GL_DST_ALPHA因子等于的分量GL_ONE_MINUS_DST_ALPHA因子等于 的分量GL_CONSTANT_COLOR因子等于常数颜色向量GL_ONE_MINUS_CONSTANT_COLOR因子等于GL_CONSTANT_ALPHA因子等于的分量GL_ONE_MINUS_CONSTANT_ALPHA因子等于 的分量
为了获得之前两个方形的混合结果我们需要使用源颜色向量的作为源因子使用作为目标因子。这将会产生以下的glBlendFunc
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);也可以使用glBlendFuncSeparate为RGB和alpha通道分别设置不同的选项
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);OpenGL甚至给了我们更多的灵活性允许我们改变方程中源和目标部分的运算符。当前源和目标是相加的但如果愿意的话我们也可以让它们相减。glBlendEquation(GLenum mode)允许我们设置运算符它提供了三个选项
GL_FUNC_ADD默认选项将两个分量相加。GL_FUNC_SUBTRACT将两个分量相减 。GL_FUNC_REVERSE_SUBTRACT将两个分量相减但顺序相反。
融合会存在遮挡问题所以应该按照如下顺序绘制物体。
先绘制所有不透明的物体。对所有透明的物体排序。按顺序绘制所有透明的物体。
代码在项目中查看
效果展示