OpenGL基础8:SOIL库

一、SOIL

SOIL是简易OpenGL图像库(Simple OpenGL Image Library)的缩写,它支持大多数流行的图像格式,关于SOIL的介绍应该很多,这里就不说了,我们先装上

OpenGL环境配置(超全整合版)SOIL库可以从这篇文章中的链接中下载到,有个叫做imple OpenGL Image Library的文件夹就是了,打开后将其src文件夹中的SOIL.h放到老位置(C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.25.28610\include),并用你当前的vs打开projects文件夹中的VC9解决方案,直接生成解决方案打出release包(注意选择x86或32),之后在原目录下的release文件夹中将SOIL.lib拉出来一样放入老位置(C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.25.28610\lib\x86)好了搞定,我们可以再次打开VS了,这次是打开你的项目

打开项目后,菜单→项目→属性,进入如下界面,附加依赖项中添加SOIL.lib即可完成环境配置,当然你也可以将之前的glew32.lib也顺便加进去,这样就无需在代码的最开始 #pragma comment(lib,"glew32.lib") 

搞定之后随意输入一份代码测试以下有没有问题,如果出现无法解析的XX方法错误,请试下使用VC8编译生成.lib文件而并非VC9

二、简单应用

如下图:我们用 OpenGL基础5:第一个正方形 这一篇文章中的代码进行扩展,让这个正方形拥有纹理

我们之前给顶点加上了位置属性和颜色属性,那么我们现在再加上第三个属性:纹理属性

GLfloat vertices[] =
{
    -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
    0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
    -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
    0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f
};
GLuint indices[] =
{
    0, 1, 2,        //用前3个顶点绘制第一个三角形
    1, 2, 3         //用后3个顶点绘制第二个三角形
};

前3个参数是位置,中间3个参数是颜色,后面两个参数就是纹理坐标了,上面的4个纹理坐标正好对应着4个角,(其中(0, 0)为左下角)一样注意调整 glVertexAttribPointer 方法的步长和偏移

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
glEnableVertexAttribArray(2);

其中可以看到,我们设置了纹理坐标的位置值是2,顶点着色器当然要改

#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec4 color;
layout (location = 2) in vec2 texture;
out vec4 colorIn;
out vec2 texIn;
void main()
{
    gl_Position = vec4(position, 1.0);
    colorIn = color;
    texIn = texture;
}

顶点着色器的修改非常容易理解,生成创建绑定的方式也和前面EBO、VBO非常相似:

GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);

之后就是纹理生成部分了:

int picWidth, picHeight;
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);
unsigned char* image = SOIL_load_image("timg.jpg", &picWidth, &picHeight, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, picWidth, picHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(image);
glBindTexture(GL_TEXTURE_2D, 0);

前面的4个 glTexParameteri 方法本章暂时不讲

  • SOIL_load_image:获取图片文件,第1个参数为图片的路径,第2个参数和第3个参数需要两个int指针,SOIL会返回图片的宽度和高度到其中,第4个参数指定图片的通道(Channel)数量,目前为0就好,最后一个参数告诉SOIL如何来加载图片:目前只需要关注图片的RGB值
  • glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, picWidth, picHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, image):第3个参数为纹理存储格式,目前图像只有RGB值,因此们也把纹理储存为RGB值,第4个参数和第5个参数为宽和高,我们用自己图片的宽和高就可以了,上面的方法也有给你赋值,第7个参数和第8个参数定义了源图的格式和数据类型,这里表示我们使用RGB值加载这个图像,并把它们储存为char(byte)数组,第9个参数就是我们需要的图片。其它参数暂时不需要理解

当然在这里你需要任意一张图片,注意:图片的宽高必须是2次幂(例如512 * 512,1024 * 256等),否则会出现压缩问题,后果比较严重,你也可以自己用工具修改图片的大小

片段着色器修改如下:

#version 330 core
out vec4 color;
in vec4 colorIn;
in vec2 texIn;
uniform sampler2D texOut;
void main()
{
    color = texture(texOut, texIn);
}
  • uniform sampler2D ourTexture:将纹理添加到片段着色器中,其中sampler为采样器,是一个供纹理对象使用的内建数据类型
  • color = texture(texOut, texIn):采样纹理的颜色,第1个参数是纹理采样器,第2个参数是对应的纹理坐标。texture函数会使用之前设置的纹理参数对相应的颜色值进行采样,这个片段着色器输出的就是当前纹理坐标上插值过滤后得到的最终颜色

最后我们只需要调用glBindTexture之前绑定的纹理就好,它会自动把纹理赋值给片段着色器的采样器

glBindTexture(GL_TEXTURE_2D, texture);
shaderYellow.Use();
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

完整代码:其中 Shader.h 可以在上一章找到代码,没有改动,两个着色器的代码在上面

#include<iostream>
#include<opengl/glew.h>
#define GLEW_STATIC
#include<GLFW/glfw3.h>
#include"Shader.h"
#include<opengl/freeglut.h>
#include<SOIL.h>

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
const GLuint WIDTH = 800, HEIGHT = 600;

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

    GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
    glfwMakeContextCurrent(window);
    glfwSetKeyCallback(window, key_callback);
    glewExperimental = GL_TRUE;
    glewInit();

    int width, height;
    glfwGetFramebufferSize(window, &width, &height);
    glViewport(0, 0, width, height);

    Shader shaderYellow("VShader.txt", "FShaderY.txt");

    GLfloat vertices[] =
    {
        -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
        0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
        -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
        0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f
    };
    GLuint indices[] =
    {
        0, 1, 2,        //用前3个顶点绘制第一个三角形
        1, 2, 3         //用后3个顶点绘制第二个三角形
    };
    GLuint VBO, EBO, VAO, texture;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);
    glGenTextures(1, &texture);

    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBindTexture(GL_TEXTURE_2D, texture);


    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
    glEnableVertexAttribArray(2);

    int picWidth, picHeight;
    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);
    unsigned char* image = SOIL_load_image("timg.jpg", &picWidth, &picHeight, 0, SOIL_LOAD_RGB);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, picWidth, picHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
    glGenerateMipmap(GL_TEXTURE_2D);
    SOIL_free_image_data(image);
    glBindTexture(GL_TEXTURE_2D, 0);

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

    while (!glfwWindowShouldClose(window))
    {
        glfwPollEvents();
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glBindTexture(GL_TEXTURE_2D, texture);
        shaderYellow.Use();
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        glBindVertexArray(0);
        glfwSwapBuffers(window);
    }
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);
    glfwTerminate();
    return 0;
}

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
}

参考:https://learnopengl.com/

原创文章 1134 获赞 1439 访问量 61万+

猜你喜欢

转载自blog.csdn.net/Jaihk662/article/details/106005748