第四课,OpenGL的纹理

头文件

#include "stb_image.h"

用于对不同格式图片的读取。

添加纹理坐标数据

纹理坐标为载入纹理的范围位置,即图片的宽高范围都在0~1之间,根据填入的小数来确定纹理载入的位置

GLfloat vertices[] = {
        //location(顶点坐标)     color         texture coords(纹理坐标)
        -1.0f,  0.0f, 0.0f,    1.0f, 0.0f, 0.0f,     0.0f, 1.0f,  //左中--左上
        -1.0f, -1.0f, 0.0f,    0.0f, 0.0f, 1.0f,     0.0f, 0.0f,  //左下--左下
         0.0f, -1.0f, 0.0f,    0.0f, 1.0f, 0.0f,     1.0f, 0.0f,  //中下--右下
};

若 纹理坐标 >1.0, 或 纹理坐标 < 0.0 ,则会以设定的纹理围绕方式重复。(纹理围绕方式将在下方解释)

将纹理坐标传入着色器

glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);

创建纹理对象

GLuint texture1;
    glGenTextures(1, &texture1);//将texture1定义为纹理
    glBindTexture(GL_TEXTURE_2D, texture1);//将texture与2D纹理绑定

设置纹理围绕方式

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

第一个参数: 纹理目标
GL_TEXTURE_1D, GL_TEXTURE_1D_ARRAY,
GL_TEXTURE_2D, GL_TEXTURE_2D_ARRAY,
GL_TEXTURE_2D_MULTISAMPLE,
GL_TEXTURE_2D_MULTISAMPLE_ARRAY,
GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP,
GL_TEXTURE_CUBE_MAP_ARRAY, or GL_TEXTURE_RECTANGLE.

第二个参数: 设置的选项与应用的纹理轴
GL_DEPTH_STENCIL_TEXTURE_MODE,
GL_TEXTURE_BASE_LEVEL,
GL_TEXTURE_COMPARE_FUNC, GL_TEXTURE_COMPARE_MODE,
GL_TEXTURE_LOD_BIAS,

GL_TEXTURE_MIN_FILTER, GL_TEXTURE_MAG_FILTER,
//过滤方式 在下方会说明

GL_TEXTURE_MIN_LOD, GL_TEXTURE_MAX_LOD, GL_TEXTURE_MAX_LEVEL,
GL_TEXTURE_SWIZZLE_R, GL_TEXTURE_SWIZZLE_G,
GL_TEXTURE_SWIZZLE_B, GL_TEXTURE_SWIZZLE_A,

GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T, or GL_TEXTURE_WRAP_R.
//WRAP选项–纹理围绕轴 为该小结(设置纹理围绕方式)内容

第三个参数: 设置的选项与应用的纹理轴

WRAP选项–纹理围绕轴围绕方式

环绕方式 描述
GL_REPEAT 对纹理的默认行为。重复纹理图像。
GL_MIRRORED_REPEAT 和GL_REPEAT一样,但每次重复图片是镜像放置的。
GL_CLAMP_TO_EDGE 纹理坐标会被约束在0到1之间,超出的部分会重复纹理坐标的边缘,产生一种边缘被拉伸的效果。
GL_CLAMP_TO_BORDER 超出的坐标为用户指定的边缘颜色。

更多查看https://khronos.org/registry/OpenGL-Refpages/gl4/官方文档

过滤方式

// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

filter 过滤器 , linear 线性的(非官方)。

第一二个参数同上
第三个参数:

参数 描述
GL_NEAREST 返回距离指定纹理坐标最近的纹理元素的值。
GL_LINEAR 返回最接近指定纹理坐标的纹理元素的加权平均值。根据GL_TEXTURE_WRAP_S和GL_TEXTURE_WRAP_T的值,以及确切的映射,这些可以包括从纹理的其他部分包装或重复的项。

加载图片, 创建纹理和生成纹理映射

flip 翻转 ,vertically垂直的

int width, height, nrChannels;
stbi_set_flip_vertically_on_load(true); // y轴翻转纹理
//水平翻转要在片段着色器中设置。
unsigned char* data = stbi_load("./container.jpg", &width, &height, &nrChannels, 0);//获取图片宽高和颜色通道的个数
if (data)
{
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
    //当前绑定的纹理对象就会被附加上纹理图像。
    glGenerateMipmap(GL_TEXTURE_2D);//为当前绑定的纹理自动生成所有需要的多级渐远纹理。
}
else
{
    std::cout << "Failed to load texture" << std::endl;
}

glTexImage2D(纹理目标,多级渐远纹理的级别,储存为何种格式,宽,高,0,源图的格式,数据类型,真正的图像数据)

释放图像的内存

stbi_image_free(data);

混合纹理

创建第二个纹理
GLuint texture2;
    glGenTextures(1, &texture2);//传入引用,初始化texture2
    glBindTexture(GL_TEXTURE_2D, texture2);
    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);
    //glTexParameteri(纹理维度,改变类型,改变值);
    stbi_set_flip_vertically_on_load(true);
    data = stbi_load("./awesomeface.png", &width, &height, &nrChannels, 0);
    if (data)
    {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);//png格式加载为GL_RGBA格式
        glGenerateMipmap(GL_TEXTURE_2D);
    }
    else
    {
        std::cout << "Failed to load texture" << std::endl;
    }
    stbi_image_free(data);
告诉opengl每个采样器与哪个纹理联系

给纹理采样器分配一个位置值(默认纹理单元是0,所以多个纹理单元需要分配)
OpenGL至少保证有16个纹理单元供你使用 (对着色器的操作)

PVPCShader.use(); //激活要绑定的着色器后才可分配
PVPCShader.setInt("sampler1", 0);//将着色器中texture1采样器分配到GL_TEXTURE0
PVPCShader.setInt("sampler2", 1);//将着色器中texture2采样器分配到GL_TEXTURE1

将纹理与纹理单元联系(与着色器无关)
不需要在联系时激活着色器,在使用时激活即可。(即PVPCShader.use()可在此代码之后)

glActiveTexture(GL_TEXTURE0);// 在绑定纹理之前先激活纹理单元
glBindTexture(GL_TEXTURE_2D, texture1);//绑定这个纹理到当前激活的纹理单元
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);

着色器

PVPCShader.use();
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 2*3);//数量必须为3的倍数

在glDrawArray函数中调用着色器。以GL_TRIANGLES绘制顶点,从第0个数据开始向后绘制2*3个顶点。

顶点着色器
#version 330 core

layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;

out vec3 outColor;
out vec2 TexCoord;

void main()
{
    gl_Position = vec4(aPos, 1.0);
    outColor = aColor;
    TexCoord = aTexCoord;
}
片段着色器
#version 330 core
out vec4 FragColor;

in vec3 outColor;
in vec2 TexCoord;

uniform sampler2D sampler1;//保证在分配采样器时的名称与该名称一致
uniform sampler2D sampler2;//否则会出现一些无提示的错误,不容易发现

void main()
{
FragColor = mix(texture(sampler1, TexCoord), texture(sampler2, TexCoord),0.8) * vec4(outColor, 1.0f);
}

FragColor 输出的最终片段颜色
mix(texture1,texture2, double). //以double的比例混合两个纹理
texture(sampler1, TexCoord);// texture纹理(图片处理方式,图片纹理覆盖点);
*号 用于颜色和纹理的混合。

数据走向

#mermaid-svg-AnB1jdFwFkWSe0Dz .label{font-family:\’trebuchet ms\’, verdana, arial;font-family:var(–mermaid-font-family);fill:#333;color:#333}#mermaid-svg-AnB1jdFwFkWSe0Dz .label text{fill:#333}#mermaid-svg-AnB1jdFwFkWSe0Dz .node rect,#mermaid-svg-AnB1jdFwFkWSe0Dz .node circle,#mermaid-svg-AnB1jdFwFkWSe0Dz .node ellipse,#mermaid-svg-AnB1jdFwFkWSe0Dz .node polygon,#mermaid-svg-AnB1jdFwFkWSe0Dz .node path{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-AnB1jdFwFkWSe0Dz .node .label{text-align:center;fill:#333}#mermaid-svg-AnB1jdFwFkWSe0Dz .node.clickable{cursor:pointer}#mermaid-svg-AnB1jdFwFkWSe0Dz .arrowheadPath{fill:#333}#mermaid-svg-AnB1jdFwFkWSe0Dz .edgePath .path{stroke:#333;stroke-width:1.5px}#mermaid-svg-AnB1jdFwFkWSe0Dz .flowchart-link{stroke:#333;fill:none}#mermaid-svg-AnB1jdFwFkWSe0Dz .edgeLabel{background-color:#e8e8e8;text-align:center}#mermaid-svg-AnB1jdFwFkWSe0Dz .edgeLabel rect{opacity:0.9}#mermaid-svg-AnB1jdFwFkWSe0Dz .edgeLabel span{color:#333}#mermaid-svg-AnB1jdFwFkWSe0Dz .cluster rect{fill:#ffffde;stroke:#aa3;stroke-width:1px}#mermaid-svg-AnB1jdFwFkWSe0Dz .cluster text{fill:#333}#mermaid-svg-AnB1jdFwFkWSe0Dz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\’trebuchet ms\’, verdana, arial;font-family:var(–mermaid-font-family);font-size:12px;background:#ffffde;border:1px solid #aa3;border-radius:2px;pointer-events:none;z-index:100}#mermaid-svg-AnB1jdFwFkWSe0Dz .actor{stroke:#ccf;fill:#ECECFF}#mermaid-svg-AnB1jdFwFkWSe0Dz text.actor>tspan{fill:#000;stroke:none}#mermaid-svg-AnB1jdFwFkWSe0Dz .actor-line{stroke:grey}#mermaid-svg-AnB1jdFwFkWSe0Dz .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333}#mermaid-svg-AnB1jdFwFkWSe0Dz .messageLine1{stroke-width:1.5;stroke-dasharray:2, 2;stroke:#333}#mermaid-svg-AnB1jdFwFkWSe0Dz #arrowhead path{fill:#333;stroke:#333}#mermaid-svg-AnB1jdFwFkWSe0Dz .sequenceNumber{fill:#fff}#mermaid-svg-AnB1jdFwFkWSe0Dz #sequencenumber{fill:#333}#mermaid-svg-AnB1jdFwFkWSe0Dz #crosshead path{fill:#333;stroke:#333}#mermaid-svg-AnB1jdFwFkWSe0Dz .messageText{fill:#333;stroke:#333}#mermaid-svg-AnB1jdFwFkWSe0Dz .labelBox{stroke:#ccf;fill:#ECECFF}#mermaid-svg-AnB1jdFwFkWSe0Dz .labelText,#mermaid-svg-AnB1jdFwFkWSe0Dz .labelText>tspan{fill:#000;stroke:none}#mermaid-svg-AnB1jdFwFkWSe0Dz .loopText,#mermaid-svg-AnB1jdFwFkWSe0Dz .loopText>tspan{fill:#000;stroke:none}#mermaid-svg-AnB1jdFwFkWSe0Dz .loopLine{stroke-width:2px;stroke-dasharray:2, 2;stroke:#ccf;fill:#ccf}#mermaid-svg-AnB1jdFwFkWSe0Dz .note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-AnB1jdFwFkWSe0Dz .noteText,#mermaid-svg-AnB1jdFwFkWSe0Dz .noteText>tspan{fill:#000;stroke:none}#mermaid-svg-AnB1jdFwFkWSe0Dz .activation0{fill:#f4f4f4;stroke:#666}#mermaid-svg-AnB1jdFwFkWSe0Dz .activation1{fill:#f4f4f4;stroke:#666}#mermaid-svg-AnB1jdFwFkWSe0Dz .activation2{fill:#f4f4f4;stroke:#666}#mermaid-svg-AnB1jdFwFkWSe0Dz .mermaid-main-font{font-family:\”trebuchet ms\”, verdana, arial;font-family:var(–mermaid-font-family)}#mermaid-svg-AnB1jdFwFkWSe0Dz .section{stroke:none;opacity:0.2}#mermaid-svg-AnB1jdFwFkWSe0Dz .section0{fill:rgba(102,102,255,0.49)}#mermaid-svg-AnB1jdFwFkWSe0Dz .section2{fill:#fff400}#mermaid-svg-AnB1jdFwFkWSe0Dz .section1,#mermaid-svg-AnB1jdFwFkWSe0Dz .section3{fill:#fff;opacity:0.2}#mermaid-svg-AnB1jdFwFkWSe0Dz .sectionTitle0{fill:#333}#mermaid-svg-AnB1jdFwFkWSe0Dz .sectionTitle1{fill:#333}#mermaid-svg-AnB1jdFwFkWSe0Dz .sectionTitle2{fill:#333}#mermaid-svg-AnB1jdFwFkWSe0Dz .sectionTitle3{fill:#333}#mermaid-svg-AnB1jdFwFkWSe0Dz .sectionTitle{text-anchor:start;font-size:11px;text-height:14px;font-family:\’trebuchet ms\’, verdana, arial;font-family:var(–mermaid-font-family)}#mermaid-svg-AnB1jdFwFkWSe0Dz .grid .tick{stroke:#d3d3d3;opacity:0.8;shape-rendering:crispEdges}#mermaid-svg-AnB1jdFwFkWSe0Dz .grid .tick text{font-family:\’trebuchet ms\’, verdana, arial;font-family:var(–mermaid-font-family)}#mermaid-svg-AnB1jdFwFkWSe0Dz .grid path{stroke-width:0}#mermaid-svg-AnB1jdFwFkWSe0Dz .today{fill:none;stroke:red;stroke-width:2px}#mermaid-svg-AnB1jdFwFkWSe0Dz .task{stroke-width:2}#mermaid-svg-AnB1jdFwFkWSe0Dz .taskText{text-anchor:middle;font-family:\’trebuchet ms\’, verdana, arial;font-family:var(–mermaid-font-family)}#mermaid-svg-AnB1jdFwFkWSe0Dz .taskText:not([font-size]){font-size:11px}#mermaid-svg-AnB1jdFwFkWSe0Dz .taskTextOutsideRight{fill:#000;text-anchor:start;font-size:11px;font-family:\’trebuchet ms\’, verdana, arial;font-family:var(–mermaid-font-family)}#mermaid-svg-AnB1jdFwFkWSe0Dz .taskTextOutsideLeft{fill:#000;text-anchor:end;font-size:11px}#mermaid-svg-AnB1jdFwFkWSe0Dz .task.clickable{cursor:pointer}#mermaid-svg-AnB1jdFwFkWSe0Dz .taskText.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-AnB1jdFwFkWSe0Dz .taskTextOutsideLeft.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-AnB1jdFwFkWSe0Dz .taskTextOutsideRight.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-AnB1jdFwFkWSe0Dz .taskText0,#mermaid-svg-AnB1jdFwFkWSe0Dz .taskText1,#mermaid-svg-AnB1jdFwFkWSe0Dz .taskText2,#mermaid-svg-AnB1jdFwFkWSe0Dz .taskText3{fill:#fff}#mermaid-svg-AnB1jdFwFkWSe0Dz .task0,#mermaid-svg-AnB1jdFwFkWSe0Dz .task1,#mermaid-svg-AnB1jdFwFkWSe0Dz .task2,#mermaid-svg-AnB1jdFwFkWSe0Dz .task3{fill:#8a90dd;stroke:#534fbc}#mermaid-svg-AnB1jdFwFkWSe0Dz .taskTextOutside0,#mermaid-svg-AnB1jdFwFkWSe0Dz .taskTextOutside2{fill:#000}#mermaid-svg-AnB1jdFwFkWSe0Dz .taskTextOutside1,#mermaid-svg-AnB1jdFwFkWSe0Dz .taskTextOutside3{fill:#000}#mermaid-svg-AnB1jdFwFkWSe0Dz .active0,#mermaid-svg-AnB1jdFwFkWSe0Dz .active1,#mermaid-svg-AnB1jdFwFkWSe0Dz .active2,#mermaid-svg-AnB1jdFwFkWSe0Dz .active3{fill:#bfc7ff;stroke:#534fbc}#mermaid-svg-AnB1jdFwFkWSe0Dz .activeText0,#mermaid-svg-AnB1jdFwFkWSe0Dz .activeText1,#mermaid-svg-AnB1jdFwFkWSe0Dz .activeText2,#mermaid-svg-AnB1jdFwFkWSe0Dz .activeText3{fill:#000 !important}#mermaid-svg-AnB1jdFwFkWSe0Dz .done0,#mermaid-svg-AnB1jdFwFkWSe0Dz .done1,#mermaid-svg-AnB1jdFwFkWSe0Dz .done2,#mermaid-svg-AnB1jdFwFkWSe0Dz .done3{stroke:grey;fill:#d3d3d3;stroke-width:2}#mermaid-svg-AnB1jdFwFkWSe0Dz .doneText0,#mermaid-svg-AnB1jdFwFkWSe0Dz .doneText1,#mermaid-svg-AnB1jdFwFkWSe0Dz .doneText2,#mermaid-svg-AnB1jdFwFkWSe0Dz .doneText3{fill:#000 !important}#mermaid-svg-AnB1jdFwFkWSe0Dz .crit0,#mermaid-svg-AnB1jdFwFkWSe0Dz .crit1,#mermaid-svg-AnB1jdFwFkWSe0Dz .crit2,#mermaid-svg-AnB1jdFwFkWSe0Dz .crit3{stroke:#f88;fill:red;stroke-width:2}#mermaid-svg-AnB1jdFwFkWSe0Dz .activeCrit0,#mermaid-svg-AnB1jdFwFkWSe0Dz .activeCrit1,#mermaid-svg-AnB1jdFwFkWSe0Dz .activeCrit2,#mermaid-svg-AnB1jdFwFkWSe0Dz .activeCrit3{stroke:#f88;fill:#bfc7ff;stroke-width:2}#mermaid-svg-AnB1jdFwFkWSe0Dz .doneCrit0,#mermaid-svg-AnB1jdFwFkWSe0Dz .doneCrit1,#mermaid-svg-AnB1jdFwFkWSe0Dz .doneCrit2,#mermaid-svg-AnB1jdFwFkWSe0Dz .doneCrit3{stroke:#f88;fill:#d3d3d3;stroke-width:2;cursor:pointer;shape-rendering:crispEdges}#mermaid-svg-AnB1jdFwFkWSe0Dz .milestone{transform:rotate(45deg) scale(0.8, 0.8)}#mermaid-svg-AnB1jdFwFkWSe0Dz .milestoneText{font-style:italic}#mermaid-svg-AnB1jdFwFkWSe0Dz .doneCritText0,#mermaid-svg-AnB1jdFwFkWSe0Dz .doneCritText1,#mermaid-svg-AnB1jdFwFkWSe0Dz .doneCritText2,#mermaid-svg-AnB1jdFwFkWSe0Dz .doneCritText3{fill:#000 !important}#mermaid-svg-AnB1jdFwFkWSe0Dz .activeCritText0,#mermaid-svg-AnB1jdFwFkWSe0Dz .activeCritText1,#mermaid-svg-AnB1jdFwFkWSe0Dz .activeCritText2,#mermaid-svg-AnB1jdFwFkWSe0Dz .activeCritText3{fill:#000 !important}#mermaid-svg-AnB1jdFwFkWSe0Dz .titleText{text-anchor:middle;font-size:18px;fill:#000;font-family:\’trebuchet ms\’, verdana, arial;font-family:var(–mermaid-font-family)}#mermaid-svg-AnB1jdFwFkWSe0Dz g.classGroup text{fill:#9370db;stroke:none;font-family:\’trebuchet ms\’, verdana, arial;font-family:var(–mermaid-font-family);font-size:10px}#mermaid-svg-AnB1jdFwFkWSe0Dz g.classGroup text .title{font-weight:bolder}#mermaid-svg-AnB1jdFwFkWSe0Dz g.clickable{cursor:pointer}#mermaid-svg-AnB1jdFwFkWSe0Dz g.classGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-AnB1jdFwFkWSe0Dz g.classGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-AnB1jdFwFkWSe0Dz .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5}#mermaid-svg-AnB1jdFwFkWSe0Dz .classLabel .label{fill:#9370db;font-size:10px}#mermaid-svg-AnB1jdFwFkWSe0Dz .relation{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-AnB1jdFwFkWSe0Dz .dashed-line{stroke-dasharray:3}#mermaid-svg-AnB1jdFwFkWSe0Dz #compositionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-AnB1jdFwFkWSe0Dz #compositionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-AnB1jdFwFkWSe0Dz #aggregationStart{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-AnB1jdFwFkWSe0Dz #aggregationEnd{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-AnB1jdFwFkWSe0Dz #dependencyStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-AnB1jdFwFkWSe0Dz #dependencyEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-AnB1jdFwFkWSe0Dz #extensionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-AnB1jdFwFkWSe0Dz #extensionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-AnB1jdFwFkWSe0Dz .commit-id,#mermaid-svg-AnB1jdFwFkWSe0Dz .commit-msg,#mermaid-svg-AnB1jdFwFkWSe0Dz .branch-label{fill:lightgrey;color:lightgrey;font-family:\’trebuchet ms\’, verdana, arial;font-family:var(–mermaid-font-family)}#mermaid-svg-AnB1jdFwFkWSe0Dz .pieTitleText{text-anchor:middle;font-size:25px;fill:#000;font-family:\’trebuchet ms\’, verdana, arial;font-family:var(–mermaid-font-family)}#mermaid-svg-AnB1jdFwFkWSe0Dz .slice{font-family:\’trebuchet ms\’, verdana, arial;font-family:var(–mermaid-font-family)}#mermaid-svg-AnB1jdFwFkWSe0Dz g.stateGroup text{fill:#9370db;stroke:none;font-size:10px;font-family:\’trebuchet ms\’, verdana, arial;font-family:var(–mermaid-font-family)}#mermaid-svg-AnB1jdFwFkWSe0Dz g.stateGroup text{fill:#9370db;fill:#333;stroke:none;font-size:10px}#mermaid-svg-AnB1jdFwFkWSe0Dz g.statediagram-cluster .cluster-label text{fill:#333}#mermaid-svg-AnB1jdFwFkWSe0Dz g.stateGroup .state-title{font-weight:bolder;fill:#000}#mermaid-svg-AnB1jdFwFkWSe0Dz g.stateGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-AnB1jdFwFkWSe0Dz g.stateGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-AnB1jdFwFkWSe0Dz .transition{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-AnB1jdFwFkWSe0Dz .stateGroup .composit{fill:white;border-bottom:1px}#mermaid-svg-AnB1jdFwFkWSe0Dz .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px}#mermaid-svg-AnB1jdFwFkWSe0Dz .state-note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-AnB1jdFwFkWSe0Dz .state-note text{fill:black;stroke:none;font-size:10px}#mermaid-svg-AnB1jdFwFkWSe0Dz .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.7}#mermaid-svg-AnB1jdFwFkWSe0Dz .edgeLabel text{fill:#333}#mermaid-svg-AnB1jdFwFkWSe0Dz .stateLabel text{fill:#000;font-size:10px;font-weight:bold;font-family:\’trebuchet ms\’, verdana, arial;font-family:var(–mermaid-font-family)}#mermaid-svg-AnB1jdFwFkWSe0Dz .node circle.state-start{fill:black;stroke:black}#mermaid-svg-AnB1jdFwFkWSe0Dz .node circle.state-end{fill:black;stroke:white;stroke-width:1.5}#mermaid-svg-AnB1jdFwFkWSe0Dz #statediagram-barbEnd{fill:#9370db}#mermaid-svg-AnB1jdFwFkWSe0Dz .statediagram-cluster rect{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-AnB1jdFwFkWSe0Dz .statediagram-cluster rect.outer{rx:5px;ry:5px}#mermaid-svg-AnB1jdFwFkWSe0Dz .statediagram-state .divider{stroke:#9370db}#mermaid-svg-AnB1jdFwFkWSe0Dz .statediagram-state .title-state{rx:5px;ry:5px}#mermaid-svg-AnB1jdFwFkWSe0Dz .statediagram-cluster.statediagram-cluster .inner{fill:white}#mermaid-svg-AnB1jdFwFkWSe0Dz .statediagram-cluster.statediagram-cluster-alt .inner{fill:#e0e0e0}#mermaid-svg-AnB1jdFwFkWSe0Dz .statediagram-cluster .inner{rx:0;ry:0}#mermaid-svg-AnB1jdFwFkWSe0Dz .statediagram-state rect.basic{rx:5px;ry:5px}#mermaid-svg-AnB1jdFwFkWSe0Dz .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#efefef}#mermaid-svg-AnB1jdFwFkWSe0Dz .note-edge{stroke-dasharray:5}#mermaid-svg-AnB1jdFwFkWSe0Dz .statediagram-note rect{fill:#fff5ad;stroke:#aa3;stroke-width:1px;rx:0;ry:0}:root{–mermaid-font-family: \’\”trebuchet ms\”, verdana, arial\’;–mermaid-font-family: \”Comic Sans MS\”, \”Comic Sans\”, cursive}#mermaid-svg-AnB1jdFwFkWSe0Dz .error-icon{fill:#522}#mermaid-svg-AnB1jdFwFkWSe0Dz .error-text{fill:#522;stroke:#522}#mermaid-svg-AnB1jdFwFkWSe0Dz .edge-thickness-normal{stroke-width:2px}#mermaid-svg-AnB1jdFwFkWSe0Dz .edge-thickness-thick{stroke-width:3.5px}#mermaid-svg-AnB1jdFwFkWSe0Dz .edge-pattern-solid{stroke-dasharray:0}#mermaid-svg-AnB1jdFwFkWSe0Dz .edge-pattern-dashed{stroke-dasharray:3}#mermaid-svg-AnB1jdFwFkWSe0Dz .edge-pattern-dotted{stroke-dasharray:2}#mermaid-svg-AnB1jdFwFkWSe0Dz .marker{fill:#333}#mermaid-svg-AnB1jdFwFkWSe0Dz .marker.cross{stroke:#333}

:root { –mermaid-font-family: \”trebuchet ms\”, verdana, arial;}
#mermaid-svg-AnB1jdFwFkWSe0Dz {
color: rgba(0, 0, 0, 0.75);
font: ;
}

传入
联系
联系
联系
联系
联系
混合纹理
纹理坐标数据texture coords
着色器
纹理对象texture
设置纹理方式
添加纹理图片
GL_TEXTURE 0-15
使用setInt联系
使用glBindTexture联系
输出最终图像

主代码

#include <iostream>
//包含命名空间std

#include <glad/glad.h>
#include <GLFW/glfw3.h>
//glad需要在glfw之前,因为GLAD的头文件包含了正确的OpenGL头文件,glfw依赖于OpenGL
#include "stb_image.h"
#include "Shader.h"//着色器设置
#include "call_back.h"//回调函数设置

int main(){
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    
    // glfw window creation
    //---------------------
    GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
    if (window == nullptr) {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);
    glfwSetKeyCallback(window, key_callback);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    
    //glad初始化(GLAD是用来管理OpenGL的函数指针的)
    //load all OpenGL function pointers
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    设置视口
    //int width, height;
    //glfwGetFramebufferSize(window, &width, &height);
    //glViewport(0, 0, width, height);

    //生成着色器
    Shader PVPCShader("./Normal.vs","./setcolor.fs");
    Shader ChangingColorShader("./Normal.vs", "./Changing.fs");


    /*
    第一组数据处理----两个填充三角形************************
    */

    //添加顶点数据
    GLfloat vertices[] = {
        //location(顶点坐标)     color         texture coords(纹理坐标)
        -1.0f,  0.0f, 0.0f,    1.0f, 0.0f, 0.0f,  0.0f, 2.0f,  //左中--左上
        -1.0f, -1.0f, 0.0f,    0.0f, 0.0f, 1.0f,  0.0f, 0.0f,  //左下--左下
         0.0f, -1.0f, 0.0f,    0.0f, 1.0f, 0.0f,  1.0f, 0.0f,  //中下--右下
         0.0f,  0.0f, 0.0f,    0.3f, 0.3f, 0.3f,  1.0f, 2.0f,  //居中--右上
        -1.0f,  0.0f, 0.0f,    1.0f, 0.0f, 0.0f,  0.0f, 2.0f,  //左中--左上
         0.0f, -1.0f, 0.0f,    0.0f, 1.0f, 0.0f,  1.0f, 0.0f,  //中下--右下
    };

    //set up buffers and configure vertex attributes
    //设置缓存区配置顶点属性
    GLuint VBO, VAO;
    glGenBuffers(1, &VBO);//获取一个buffer名为VBO
    glGenVertexArrays(1, &VAO); // 获取一个VertexArrays名为VAO
    
    glBindVertexArray(VAO);//绑定VAO为当前使用顶点数组
    
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(0));
    glEnableVertexAttribArray(0);//启用顶点属性,0号位
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
    glEnableVertexAttribArray(2);

    //加载创建纹理
    //------------
    GLuint texture1;
    //texture 1
    //-----------
    glGenTextures(1, &texture1);
    glBindTexture(GL_TEXTURE_2D, texture1);
    // set the texture wrapping parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    // set texture filtering parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    // load image, create texture and generate mipmaps(纹理映射)
    int width, height, nrChannels;
    stbi_set_flip_vertically_on_load(true); // y轴翻转纹理
    unsigned char* data = stbi_load("./container.jpg", &width, &height, &nrChannels, 0);//获取图片宽高和颜色通道的个数
    if (data)
    {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
        //glTexImage2D(纹理目标,多级渐远纹理的级别,储存为何种格式,宽,高,0,源图的格式,数据类型,真正的图像数据)
        //当前绑定的纹理对象就会被附加上纹理图像。
        glGenerateMipmap(GL_TEXTURE_2D);//为当前绑定的纹理自动生成所有需要的多级渐远纹理。
    }
    else
    {
        std::cout << "Failed to load texture" << std::endl;
    }
    stbi_image_free(data);//释放图像的内存

    //纹理2
    GLuint texture2;
    glGenTextures(1, &texture2);//传入引用,初始化texture2
    glBindTexture(GL_TEXTURE_2D, texture2);
    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);
    //glTexParameteri(纹理维度,改变类型,改变值);
    stbi_set_flip_vertically_on_load(true);
    unsigned char* data2 = stbi_load("./awesomeface.png", &width, &height, &nrChannels, 0);
    if (data2)
    {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);//png格式加载为GL_RGBA格式
        glGenerateMipmap(GL_TEXTURE_2D);
    }
    else
    {
        std::cout << "Failed to load texture" << std::endl;
    }
    stbi_image_free(data2);
    //给纹理采样器分配一个位置值(默认纹理单元是0,所以多个纹理单元需要分配)
    //OpenGL至少保证有16个纹理单元供你使用
    PVPCShader.use(); //激活要绑定的着色器后才可分配
    PVPCShader.setInt("sampler1", 0);//将着色器中texture1采样器分配到GL_TEXTURE0
    PVPCShader.setInt("sampler2", 1);//将着色器中texture2采样器分配到GL_TEXTURE1



    /*
    第二组数据处理----两个线框三角形************************************
    */

    //使用索引数据存储点的顺序,用IBO索引缓冲对象管理
    GLfloat vertices1[] = {
    0.5f, 0.5f, 0.0f,   // 右上角
    0.5f, -0.5f, 0.0f,  // 右下角
    -0.5f, -0.5f, 0.0f, // 左下角
    -0.5f, 0.5f, 0.0f   // 左上角
    };
    unsigned int indices1[] = { // 注意索引从0开始! 
        0, 1, 3, // 第一个三角形
        1, 2, 3  // 第二个三角形
    };
    
    
    //设置缓存区配置顶点属性
    GLuint VBO1,EBO1,VAO1;
    //生成三类对象,不分先后顺序
    glGenBuffers(1, &EBO1);
    glGenBuffers(1, &VBO1);
    glGenVertexArrays(1, &VAO1);
    //绑定三类对象
    glBindVertexArray(VAO1);//VAO必须为第一
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO1);
    glBindBuffer(GL_ARRAY_BUFFER, VBO1);
    //绑定缓冲数据
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices1), vertices1, GL_STATIC_DRAW);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices1), indices1, GL_STATIC_DRAW);
    
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);


    //Loop
    while (!glfwWindowShouldClose(window)){//检查glfw是否被要求退出
        glfwPollEvents();
        //检查有没有触发什么事件,然后调用对应的回调函数.
        
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
  
        PVPCShader.use();
        glActiveTexture(GL_TEXTURE0);// 在绑定纹理之前先激活纹理单元
        glBindTexture(GL_TEXTURE_2D, texture1);//绑定这个纹理到当前激活的纹理单元
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, texture2);

       
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);//设置为填充模式(默认)
        glBindVertexArray(VAO);
        glDrawArrays(GL_TRIANGLES, 0, 2*3);//数量必须为3的倍数

        float timeValue = glfwGetTime();
        float greenValue = (sin(timeValue) / 2.0f) + 0.5f;

        ChangingColorShader.use();//设置uniform值前必须先使用程序。
        ChangingColorShader.setVec3("Color", 0.0f, greenValue, 0.0f);//Color赋值RGB
        
        //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);//设置为线框模式
        glBindVertexArray(VAO1);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        glfwSwapBuffers(window);
        //交换颜色缓冲
    }
    //Game Loop

    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteVertexArrays(1, &VAO1);
    glDeleteBuffers(1, &VBO1);
    glDeleteBuffers(1, &EBO1);
    glDeleteProgram(PVPCShader.ID);

    glfwTerminate();
    //释放GLFW分配的内存。

    return 0;
}

运行结果

在这里插入图片描述

解决png格式黑边问题,经测试估计是fragColor显示问题出错,因为即使alpha值为0,png图像透明处依旧显示颜色。

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
使用glBlendFunc的三种alpha处理方式可以处理不同情况的计算。
具体使用细节还待完善!!!

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容