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也可以用于图片叠加、

 

posted on 2022-06-19 15:13  邗影  阅读(948)  评论(0编辑  收藏  举报

导航