opengl 纹理实现

参考教程

LearnOpenGL强烈推荐,个人觉得比B站上的视频教程要好,讲的也更加清晰。

代码

顶点着色器

#version 460 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 ainVColor;
layout (location = 2) in vec2 ainTextureCoord;
out vec3 aVColor;
out vec2 aVTextureCoord;
void main()
{
   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
   aVColor=ainVColor;
   aVTextureCoord=ainTextureCoord;
};

片段着色器

#version 460 core
in vec3 aVColor;
in vec2 aVTextureCoord;
uniform sampler2D  textureUnit1;
uniform sampler2D  textureUnit2;
out vec4 FragColor;
void main()
{
	FragColor = mix(texture(textureUnit1,aVTextureCoord),texture(textureUnit2,aVTextureCoord),0.5) * vec4(aVColor,1.0);
};

着色器类

#ifndef SHADER_H
#define SHADER_H
#include <fstream>
#include <sstream>
#include <iostream>
#include <string>
#include <glad/glad.h>
using namespace std;

class  Shader
{
	unsigned int id=-1;
public:
	 Shader(const char * vertexShaderSourceFile,const char * fragmentShaderSourceFile);
	~ Shader();
	void use();
	void setBool(const char * uniformName, bool uniformValue) const;
	void setInt(const  char* uniformName,  int uniformValue) const ;
	void setFloat( const char* uniformName,  float uniformValue) const;
	unsigned int getId() const;
};

 Shader:: Shader(const char* vertexShaderSourceFile, const char* fragmentShaderSourceFile)
{
     // 1. 从文件路径中获取顶点/片段着色器
     string vertexCode;
     string fragmentCode;
     ifstream vShaderFile;
     ifstream fShaderFile;
     // 保证ifstream对象可以抛出异常:
     vShaderFile.exceptions(ifstream::failbit | ifstream::badbit);
     fShaderFile.exceptions(ifstream::failbit | ifstream::badbit);
     try
     {
         // 打开文件
         vShaderFile.open(vertexShaderSourceFile);
         fShaderFile.open(fragmentShaderSourceFile);
         std::stringstream vShaderStream, fShaderStream;
         // 读取文件的缓冲内容到数据流中
         vShaderStream << vShaderFile.rdbuf();
         fShaderStream << fShaderFile.rdbuf();
         // 关闭文件处理器
         vShaderFile.close();
         fShaderFile.close();
         // 转换数据流到string
         vertexCode = vShaderStream.str();
         fragmentCode = fShaderStream.str();
     }
     catch (ifstream::failure e)
     {
         cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << endl;
     }
     unsigned int vertexShader;
     unsigned int fragmentShader;
     vertexShader= glCreateShader(GL_VERTEX_SHADER);
     fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
     const char* vShaderCode = vertexCode.c_str();
     const char* fShaderCode = fragmentCode.c_str();
     glShaderSource(vertexShader, 1, &vShaderCode, NULL);
     glShaderSource(fragmentShader, 1, &fShaderCode, NULL);
     int success;
     char* infoLog = new char[512];
     glCompileShader(vertexShader);
     glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
     if (!success) {
         cout << "顶点着色器编译失败!" << endl;
         glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
         cout << infoLog << endl;
         return;
     }
     glCompileShader(fragmentShader);
     glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
     if (!success) {
         cout << "片段着色器编译失败!" << endl;
         glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
         cout << infoLog << endl;
         return;
     }
     unsigned shaderProgram;
     shaderProgram= glCreateProgram();
     glAttachShader(shaderProgram, vertexShader);
     glAttachShader(shaderProgram, fragmentShader);
     glLinkProgram(shaderProgram);
     glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
     if (!success) {
         cout << "着色器链接失败" << endl;
         glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
         cout << infoLog << endl;
         return;
     }
     delete []infoLog;
     glDeleteShader(vertexShader);
     glDeleteShader(fragmentShader);
     this->id = shaderProgram;
}

 Shader::~ Shader()
{
     //释放着色器程序占用的资源
     glDeleteProgram(this->id);
}

 void Shader::use() 
 {
     glUseProgram(this->id);
 }

void  Shader::setBool(const char* uniformName, bool uniformValue) const
{
    int uniformLocation= glGetUniformLocation(this->id, uniformName);
    if (uniformLocation == -1) {
        cout << "This uniform variable does't exist in this shader program!" << endl;
        return;
    }
    glUniform1i(uniformLocation, (int)uniformValue);
}	

void Shader::setInt(const char* uniformName, int uniformValue) const
{
    int uniformLocation = glGetUniformLocation(this->id, uniformName);
    if (uniformLocation == -1) {
        cout << "This uniform variable does't exist in this shader program!" << endl;
        return;
    }
    glUniform1i(uniformLocation, uniformValue);
}

void Shader::setFloat(const char* uniformName, float uniformValue) const
{
    int uniformLocation = glGetUniformLocation(this->id, uniformName);
    if (uniformLocation == -1) {
        cout << "This uniform variable does't exist in this shader program!" << endl;
        return;
    }
    glUniform1f(uniformLocation, uniformValue);
}

unsigned int Shader::getId() const
{
    return this->id;
}
#endif

主程序

#include <glad/glad.h>
#include <glfw3.h>
#include <iostream>
#include "stb_image.h"
#include "Shader.h"
using namespace std;

void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
	glViewport(0, 0, width, height);
}

void processInput(GLFWwindow* window) {
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		glfwSetWindowShouldClose(window, true);
	}
}

int main() {
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	GLFWwindow* window = glfwCreateWindow(1000, 1000, "Hello OpenGL", NULL, NULL);
	if (window == NULL) {
		cout << "创建窗口失败!" << endl;
		glfwTerminate();
		system("pause");
		return 0;
	}
	glfwMakeContextCurrent(window);
	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
		cout << "GLAD初始化失败!" << endl;
		system("pause");
		return 0;
	}

	//顶点数据:顶点坐标、顶点颜色、顶点纹理坐标
	//注意这里的纹理坐标是基于图像坐标系,即坐标原点在左上角
	float vertices[] = {
		0.5f, 0.5f, 0.0f,1.0f, 0.0f, 0.0f,1.0f,0.0f, // 右上角
		0.5f, -0.5f, 0.0f,0.0f, 1.0f, 0.0f,1.0f,1.0f,  // 右下角
		-0.5f, -0.5f, 0.0f,1.0f, 0.0f, 1.0f,0.0f,1.0f,// 左下角
		-0.5f, 0.5f, 0.0f ,1.0f, 1.0f, 0.0f,0.0f,0.0f // 左上角
	};
	unsigned int indices[] = {
		// 注意索引从0开始! 
		// 此例的索引(0,1,2,3)就是顶点数组vertices的下标,
		// 这样可以由下标代表顶点组合成矩形
		0, 1, 3, // 第一个三角形
		1, 2, 3  // 第二个三角形
	};
	//初始化顶点数组合对象
	unsigned int VAO;
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);
	//初始化顶点缓冲合对象
	unsigned int VBO;
	glGenBuffers(1, &VBO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
	unsigned int EBO;
	glGenBuffers(1, &EBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
	//初始化着色器
	Shader shaderProgram("./vertex.sha","./fragment.sha");
	if (shaderProgram.getId() == -1) {
		cout << "着色器生成失败!" << endl;
		system("pause");
		return 0;
	}
	//顶点数据与着色器顶点属性之间的链接关系
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(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);
	//创建第一个纹理对象
	//初始化纹理对象
	int width, height, nChannels;
	unsigned char* textureData1 = stbi_load("./texture.png",&width,&height,&nChannels,0);
	if (!textureData1) {
		cout << "载入纹理图像失败!" << endl;
		system("pause");
		return 0;
	}
	unsigned int texture1;
	glGenTextures(1, &texture1);
	glBindTexture(GL_TEXTURE_2D, texture1);
	//设置纹理的缠绕方式
	glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	//设置纹理的过滤(重采样方式)
	glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
	glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	//设置纹理图案
	//注意四通道图像一定要以RGBA的形式读取
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData1);
	//生成多级渐远纹理
	glGenerateMipmap(GL_TEXTURE_2D);
	stbi_image_free(textureData1);
	//创建第二个纹理对象
	unsigned char* textureData2 = stbi_load("./face.png", &width, &height, &nChannels, 0);
	if (!textureData2) {
		cout << "载入纹理图像失败!" << endl;
		system("pause");
		return 0;
	}
	unsigned int texture2;
	glGenTextures(1, &texture2);
	glBindTexture(GL_TEXTURE_2D, texture2);
	//设置纹理的缠绕方式
	glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	//设置纹理的过滤(重采样方式)
	glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
	glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	//设置纹理图案
	//注意四通道图像一定要以RGBA的形式读取
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData2);
	//生成多级渐远纹理
	glGenerateMipmap(GL_TEXTURE_2D);
	stbi_image_free(textureData2);
	//将片段着色器多个采样器与纹理对象一一对应起来
	shaderProgram.use();
	shaderProgram.setInt("textureUnit1", 0);
	shaderProgram.setInt("textureUnit2", 1);
	//恢复到初始化状态
	glBindVertexArray(0);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
	glBindTexture(GL_TEXTURE_2D, 0);
	glUseProgram(0);
	while (!glfwWindowShouldClose(window)) {
		processInput(window);
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);
		//激活纹理单元
		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D,texture1);
		//激活纹理单元
		glActiveTexture(GL_TEXTURE1);
		glBindTexture(GL_TEXTURE_2D, texture2);
		//激活着色器
		shaderProgram.use();
		glBindVertexArray(VAO);
		//以线框模式进行绘制
		//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
		//以面模式进行绘制
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
		glfwSwapBuffers(window);
		glfwPollEvents();
	}
	//释放相关资源,退出程序
	glDeleteVertexArrays(1, &VAO);
	glDeleteBuffers(1, &VBO);
	glDeleteBuffers(1, &EBO);
	glDeleteProgram(shaderProgram.getId());
	glDeleteTextures(1, &texture1);
	glDeleteTextures(1, &texture2);
	glfwTerminate();
	system("pause");
	return 1;
}

实现效果

输入

请添加图片描述
请添加图片描述

输出

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值