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 方法本章暂时不讲
当然在这里你需要任意一张图片,注意:图片的宽高必须是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);
}
最后我们只需要调用glBindTexture之前绑定的纹理就好,它会自动把纹理赋值给片段着色器的采样器
glBindTexture(GL_TEXTURE_2D, texture);
shaderYellow.Use();
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
完整代码:其中 Shader.h 可以在上一章找到代码,没有改动,两个着色器的代码在上面
#include
#include
#define GLEW_STATIC
#include
#include"Shader.h"
#include
#include
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/