前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >15.opengl高级-混合

15.opengl高级-混合

作者头像
公号sumsmile
发布2020-06-28 15:51:24
7250
发布2020-06-28 15:51:24
举报
文章被收录于专栏:音视频技术学习笔记

对渲染管线的一点理解:opengl把渲染流程设计成一套“渲染管线”,把相同的操作抽象出来设计成“黑盒”,对开发者透明,把可以定制的操作抽象成API接口,提供给开发者,就像做填空题一样。于是就有了“顶点着色器”、“片元着色器”,开发者不用和复杂的GPU硬件接口打交道,就能实现酷炫的图像效果。

opengl渲染管线简化理解

回归主题
一、丢弃纹理实现纹理混合
1. 增加alpha通道

简单的方式实现纹理混合

代码语言:javascript
复制
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
2. 片元着色器中,加载纹理的4个通道,opengl默认不会处理alpha通道,“discard”关键字可以丢弃片元,不做处理的话,纹理的空白处会很“奇怪”,应该是图元渲染光栅化采样造成的。

错误示例-去掉discard

正确示例-增加discard

代码语言:javascript
复制
void main()
{
    vec4 texColor = texture(texture1, TexCoords);
    if (texColor.a < 0.1)
    {
        discard;
    }
    // FragColor = vec4(vec3(texture(texture1, TexCoords)), 1.0);
    FragColor = texture(texture1, TexCoords);
}
3. 草纹理实现

纹理使用的理解:纹理必须要贴在一个几何表面上,草的纹理不能凭空绘制出来,也是附着在一个正方形上。正方形平移四次绘制,就可以生成4个草的纹理。注意:顶点着色器中position有位移操作,但是纹理不需要再单独进行位移操作 草纹理附着的四边形

代码语言:javascript
复制
  float transparentVertices[] = {
  // positions         // texture Coords (swapped y coordinates because texture is flipped upside down)
  0.0f,  0.5f,  0.0f,  0.0f,  0.0f,
  0.0f, -0.5f,  0.0f,  0.0f,  1.0f,
  1.0f, -0.5f,  0.0f,  1.0f,  1.0f,

  0.0f,  0.5f,  0.0f,  0.0f,  0.0f,
  1.0f, -0.5f,  0.0f,  1.0f,  1.0f,
  1.0f,  0.5f,  0.0f,  1.0f,  0.0f
  };
代码语言:javascript
复制
// 绘制草
glBindVertexArray(transparantVAO);
glBindTexture(GL_TEXTURE_2D, transparentTexture);
for (unsigned int i = 0; i<vegetation.size(); i++) {
  model = glm::mat4(1.0f);
  model = glm::translate(model, vegetation[i]);
  shader.setMat4("model", model);
  glDrawArrays(GL_TRIANGLES, 0, 6);
 }

白色条纹

代码语言:javascript
复制
//        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
//        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

clamp去条纹

二、纹理混合的实现

纹理缓和的计算也不复杂,根据alpha通道值做叠加或减除融合,详细可参考opengl-混合

这里,我们重点看下混合中的问题及解决防范

1. 接口使用:渲染半透明纹理API调用上很简单,两行代码
代码语言:javascript
复制
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2. 混合中的问题:如果运气不好会出现奇怪的叠加效果,前面窗户完全遮挡住了后面的窗户

出现不合理的遮挡

运气好一切OK

运气好

正常运行效果的代码,其实就做了微小的调整,按照窗户从后到前的顺序绘制窗户,上面“不正常效果”是随机绘制

代码语言:javascript
复制
// 窗户纹理位移坐标
 vector<glm::vec3> vegetation
    {
        glm::vec3(0.5f, 0.0f, -0.6f),
        glm::vec3(-1.5f, 0.0f, -0.48f),
        glm::vec3(-0.3f, 0.0f, -0.23f),
        glm::vec3(1.5f, 0.0f, 0.51f),
        glm::vec3(0.0f, 0.0f, 0.7f)
    };
3. 混合问题分析及解决

深度测试并不能智能的分析出哪些片元需要考虑混合,只会“死脑筋”的按照绘制顺序做深度测试,如果先绘制了前面的图形(即使前面的图元有透明的部分),后面绘制的图形进行深度测试会失败会被丢弃,根本没机会进入到后面的混合渲染流程。

所以,按照从后到前顺序(Z坐标由远及近)绘制是没有问题的,那么问题来了,总不能每次手动调整图形绘制的前后顺序吧?

比较简单的处理,通过排序来调整绘制顺序。

注意STL map默认是对key值做升序排序

代码语言:javascript
复制
    vector<glm::vec3> vegetation
    {
        glm::vec3(-1.5f, 0.0f, -0.48f),
        glm::vec3( 1.5f, 0.0f, 0.51f),
        glm::vec3( 0.0f, 0.0f, 0.7f),
        glm::vec3(-0.3f, 0.0f, -2.3f),
        glm::vec3( 0.5f, 0.0f, -0.6f)
    };
    
    std::map<float, glm::vec3> sorted;
    for (unsigned int i = 0; i < vegetation.size(); i++) {
        float distance = glm::length(camera.Position - vegetation[i]);
        sorted[distance] = vegetation[i];
    }
...
省略其他代码
...
 for (std::map<float, glm::vec3>::reverse_iterator it = sorted.rbegin(); it != sorted.rend(); ++it) {
    model = glm::mat4(1.0f);
    model = glm::translate(model, it->second);
    shader.setMat4("model", model);
    glDrawArrays(GL_TRIANGLES, 0, 6);
  }

实现效果正常

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 回归主题
  • 一、丢弃纹理实现纹理混合
    • 1. 增加alpha通道
      • 2. 片元着色器中,加载纹理的4个通道,opengl默认不会处理alpha通道,“discard”关键字可以丢弃片元,不做处理的话,纹理的空白处会很“奇怪”,应该是图元渲染光栅化采样造成的。
        • 3. 草纹理实现
        • 二、纹理混合的实现
          • 1. 接口使用:渲染半透明纹理API调用上很简单,两行代码
            • 2. 混合中的问题:如果运气不好会出现奇怪的叠加效果,前面窗户完全遮挡住了后面的窗户
              • 3. 混合问题分析及解决
              相关产品与服务
              GPU 云服务器
              GPU 云服务器(Cloud GPU Service,GPU)是提供 GPU 算力的弹性计算服务,具有超强的并行计算能力,作为 IaaS 层的尖兵利器,服务于生成式AI,自动驾驶,深度学习训练、科学计算、图形图像处理、视频编解码等场景。腾讯云随时提供触手可得的算力,有效缓解您的计算压力,提升业务效率与竞争力。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档