• OpenGL多层纹理叠加MIX(九1)


    1 前提:两张图片大小一样,进行 MIX混合,两个图片要是24位RGB就都是24位,如果一个是24位RGB,一个是32位RGBA,请加载纹理数据的时候使用同样数量的图层

    (图片来源于网络截图,不商用,仅进行博客demo展示)

            

     再譬如:

       

     

    两个采样器进行采样,之后进行mix混合;参考:(17条消息) OpenGL纹理叠加_LV小猪精的博客-CSDN博客_opengl 纹理叠加

    #include "stdafx.h"
    #include<windows.h>
    #include <glad/glad.h>
    #include <GLFW/glfw3.h>
    #define STB_IMAGE_IMPLEMENTATION
    #include <stb_image.h>
    #include<string>
    #include<fstream>
    #include<sstream>
    #include<iostream>
    
    #include <stdio.h>
    
    // settings
    const unsigned int SCR_WIDTH = 800;
    const unsigned int SCR_HEIGHT = 600;
    unsigned int VBO = 0;
    unsigned int VAO = 0;
    unsigned int EBO = 0;
    unsigned int texturePIC = 0;
    unsigned int texturePIC2 = 0;
    int shaderProgram = 0;
    GLuint texId_bottom = 99;
    GLuint texId_top = 99;
    
    //本地文件夹下有个图片加载到项目上(注意参数列表中的引用表示变量本身,不要用变量的副本)
    void LoadPicture(unsigned int& textureIndex,unsigned int& textureIndex2)
    {
        //返回不同采样器的序号
        glUseProgram(shaderProgram);
        texId_bottom = glGetUniformLocation(shaderProgram, " ourTextureB");
        texId_top = glGetUniformLocation(shaderProgram, "ourTextureT");
    
        glGenTextures(1, &textureIndex);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, textureIndex);
        
        //为bind的纹理设置环绕,过滤方式
        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_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    
        //加载图片生成纹理 :
        stbi_set_flip_vertically_on_load(true);
        //stbi是一个图片载入的开源组件,文件名,宽高,通道数,你期望的通道数(使用的是宽大于高的图片,如果是高>宽,程序需要改否则渲染异常)
        int W, H, channels_in_file, desired_channels = 3;
        unsigned char* data = stbi_load("./3.jpg", &W, &H, &channels_in_file, desired_channels);
        if (channels_in_file == 3)
        {
            //数据生成纹理;根据指定的参数,把输入数据生成一张2D纹理
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, W, H, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
            glUniform1i(texId_bottom,0);
            //生成mipmap数组
            glGenerateMipmap(GL_TEXTURE_2D);
        }
        stbi_image_free(data);
        data = nullptr;
    
        //加载彩虹
        glGenTextures(1, &textureIndex2);
    
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, textureIndex2);
        //为bind的纹理设置环绕,过滤方式
        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_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        //加载图片生成纹理 :
        stbi_set_flip_vertically_on_load(true);
        //stbi是一个图片载入的开源组件,文件名,宽高,通道数,你期望的通道数
        int W2, H2, channels_in_file2, desired_channels2 = 3;
        unsigned char* data2 = stbi_load("./tm.bmp", &W2, &H2, &channels_in_file2, desired_channels2);
        if (channels_in_file2 == 3)
        {
            //数据生成纹理;根据指定的参数,把输入数据生成一张2D纹理
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, W2, H2, 0, GL_RGB, GL_UNSIGNED_BYTE, data2);
            glUniform1i(texId_top, 1);
            //生成mipmap数组
            glGenerateMipmap(GL_TEXTURE_2D);
        }
        stbi_image_free(data2);
        data2 = nullptr;
    
        glUseProgram(0);
    }
    
    
    void render()
    {
        glBindVertexArray(VAO);
        glUseProgram(shaderProgram);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        glUseProgram(0);
        glBindVertexArray(0);
    }
    
    void initmodule()
    {
        //做个一模型;正方形;映射了顶点坐标和纹理坐标的对应关系
        float vertexs[] = {
            //顶点坐标-------纹理坐标
            1.0f,  1.0f, 0.0f,  1.0f, 1.0f,   // 右上
            1.0f, -1.0f, 0.0f,  1.0f, 0.0f,   // 右下
            -1.0f, -1.0f, 0.0f,  0.0f, 0.0f,   // 左下
            -1.0f,  1.0f, 0.0f,  0.0f, 1.0f    // 左上
    
    
        };
        //一个正方形是由两个三角形得来的;记录顶点的索引顺序
        unsigned int indexs[] = {
            0,1,3,
            1,2,3,
        };
    
        //做VAO
        glGenVertexArrays(1, &VAO);
        glBindVertexArray(VAO);
    
        //做VBO
    
        glGenBuffers(1, &VBO);
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        //创建显存空间
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertexs), vertexs, GL_STATIC_DRAW);
    
        //设置索引缓冲
        glGenBuffers(1, &EBO);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexs), indexs, GL_STATIC_DRAW);
        //设置纹理图片
        //加载纹理图片,生成纹理
        LoadPicture(texturePIC, texturePIC2);
        //绑定纹理,OpenGL至少保证有16个纹理单元供你使用,也就是说你可以激活从GL_TEXTURE0到GL_TEXTRUE15
        
        //设置第0个锚点,3个点,不需要归一化,跨度5个float可以读下一个点
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
        //打开顶点
        glEnableVertexAttribArray(0);
        //纹理属性设置,纹理在第一个锚点上(指定顶点数据)你在顶点着色器程序中制定了锚点1的位置对应的是纹理坐标
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
        //打开纹理
        glEnableVertexAttribArray(1);
    
        //解除绑定VBO
        glBindBuffer(GL_ARRAY_BUFFER, 0);
    
        //解绑VAO
        glBindVertexArray(0);
    
    }
    
    void initshader(const char* verpath, const char* fragpath)
    {
        //编译shader,并记录shaderID
        std::string VerCode("");
        std::string fregCode("");
        //读文件
        std::ifstream  vShaderFile;
        std::ifstream  fShaderFile;
    
        vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
        fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
    
        try
        {
            vShaderFile.open(verpath);
            fShaderFile.open(fragpath);
    
            std::stringstream vsstream, fsstream;
            vsstream << vShaderFile.rdbuf();
            fsstream << fShaderFile.rdbuf();
            VerCode = vsstream.str();
            fregCode = fsstream.str();
    
        }
        catch (const std::exception&)
        {
            std::cout << "read file error" << std::endl;
        }
    
        const char* vshader = VerCode.c_str();
        const char* fshader = fregCode.c_str();
    
        //shader 编译连接
        unsigned int vertexID = 0, fragID = 0;
        char infoLog[512];//存储错误信息
        int  successflag = 0;
        vertexID = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertexID, 1, &vshader, NULL);
        glCompileShader(vertexID);
        //获取编译是否成功
        glGetShaderiv(vertexID, GL_COMPILE_STATUS, &successflag);
        if (!successflag)
        {
            glGetShaderInfoLog(vertexID, 512, NULL, infoLog);
            std::string errstr(infoLog);
            std::cout << "v shader err" << infoLog;
        }
        //frag
        fragID = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragID, 1, &fshader, NULL);
        glCompileShader(fragID);
        //获取编译是否成功
        glGetShaderiv(fragID, GL_COMPILE_STATUS, &successflag);
        if (!successflag)
        {
            glGetShaderInfoLog(fragID, 512, NULL, infoLog);
            std::string errstr(infoLog);
            std::cout << "f shader err" << infoLog;
        }
        //链接
        shaderProgram = glCreateProgram();
        glAttachShader(shaderProgram, vertexID);
        glAttachShader(shaderProgram, fragID);
        glLinkProgram(shaderProgram);
        glGetProgramiv(shaderProgram, GL_LINK_STATUS, &successflag);
        if (!successflag)
        {
            glGetShaderInfoLog(shaderProgram, 512, NULL, infoLog);
            std::string errstr(infoLog);
            std::cout << "link error";
        }
    
        //编译完成后,可以把中间的步骤程序删除
        glDeleteShader(vertexID);
        glDeleteShader(fragID);
    }
    void processInput(GLFWwindow *window)
    {
        if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        {
            //将窗口设置为关闭,跳出循环
            glfwSetWindowShouldClose(window, true);
        }
    }
    
    void framebuffer_size_callback(GLFWwindow* window, int width, int height)
    {
        glViewport(0, 0, width, height);
    }
    
    int main()
    {
        //glfw初始化
        glfwInit();
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    
        //glfw创建窗口
        GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
        if (window == NULL)
        {
            printf("创建窗口失败");
            //终止
            glfwTerminate();
            return -1;
        }
        //显示窗口
        glfwMakeContextCurrent(window);
    
        //设置回调,当窗口大小调整后将调用该回调函数
        glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    
        // glad初始化
        if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
        {
            printf("加载失败");
            return -1;
        }
        
        initshader("vertexShader.glsl", "fragmentShader.glsl");
        initmodule();
        // 使用循环达到循环渲染效果
        while (!glfwWindowShouldClose(window))
        {
            //自定义输入事件
            processInput(window);
    
            glClearColor(0.5f, 0.5f, 0.3f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT);
            render();
            //交互缓冲区,否则显示空白
            glfwSwapBuffers(window);
            //输入输出事件,否则无法对窗口进行交互
            glfwPollEvents();
        }
    
        //终止渲染 关闭并清理glfw本地资源
        glfwTerminate();
        return 0;
    }
    #version 330 core
    out vec4 FragColor;
    in vec2 TexCoord;
    
    uniform sampler2D ourTextureB;
    uniform sampler2D ourTextureT;
    void main()
    {
        //FragColor = texture(ourTexture,TexCoord);
        //mix(a,b,factor)=a*(1-factor)+b*factor  作者:__inker https://www.bilibili.com/read/cv10694142/ 出处:bilibili
    FragColor = mix(texture(ourTextureT, TexCoord), texture(ourTextureB, TexCoord), 0.8);
    //FragColor = texture(ourTextureT, TexCoord)*0.7 + texture(ourTextureB, TexCoord)*1;
    
    };
    #version 330 core
    layout(location = 0) in vec3 aPos;
    layout(location = 1) in vec2 texCoord; 
    
    out vec2 TexCoord;
    void main()
    {
       gl_Position = vec4(aPos.x,aPos.y,aPos.z,1.0);
       TexCoord = texCoord;
    };

     

      

     使用小狗狗和彩虹,由于彩虹是透明的,所以直接像素相加也行:

    FragColor = texture(ourTextureT, TexCoord)*0.6+ texture(ourTextureB, TexCoord)*1;

    //本文使用的是mix;blend也可以用于图片叠加、

  • 相关阅读:
    springmvc log4j 配置
    intellij idea maven springmvc 环境搭建
    spring,property not found on type
    intellij idea maven 工程生成可执行的jar
    device eth0 does not seem to be present, delaying initialization
    macos ssh host配置及免密登陆
    centos7 搭建 docker 环境
    通过rest接口获取自增id (twitter snowflake算法)
    微信小程序开发体验
    gitbook 制作 beego 参考手册
  • 原文地址:https://www.cnblogs.com/8335IT/p/16390540.html
Copyright © 2020-2023  润新知