openGL using textures

Sampling: using texture coordinates to get texture color

Sampler: clip shaders should also be able to access texture objects, but how can texture objects be passed to clip shaders? GLSL has a built-in data type for texture objects, called sampler, which uses texture type as suffix, such as sampler1D, sampler3D, or sampler2D. You can simply declare a uniform sampler2D to add a texture to the fragment shader, and later assign the texture to the uniform. OpenGL guarantees at least 16 texture units for your use, that is, you can activate from GL? Texture0 to GL? Textrue15. They are all defined in order, so you can also get GL? Texture8 through GL? Texture0 + 8, which is very useful when we need to cycle some texture units.

#version 330 core
out vec4 FragColor;

in vec3 ourColor;
in vec2 TexCoord;
uniform float mixValue;

// Sampler: solves how to pass texture objects to clip shaders
//Texture unit·
uniform sampler2D texture1;


//The output of this clip shader is the color (filtered) on the texture's (interpolated) texture coordinates.
void main()
{
	FragColor = texture(texture1, TexCoord) * vec4(ourColor, 1.0f);

}

 

Texture unit: a fragment shader can have multiple textures. The location value of a texture is usually called texture unit. Only one texture's default texture unit is 0. The default is the active texture unit. When there are multiple textures, the texture unit should be activated first, After the texture unit is activated, the next glBindTexture function call will bind the texture to the currently activated texture unit. When binding, the texture will be automatically assigned to the segment shader vertex sampler, and the texture unit GL_TEXTURE0 is always activated by default.

 

Clip shader program:

#version 330 core
out vec4 FragColor;

in vec3 ourColor;
in vec2 TexCoord;
uniform float mixValue;

// Sampler: solves how to pass texture objects to clip shaders
//Texture unit·
uniform sampler2D texture1;
uniform sampler2D texture2;


//The output of this clip shader is the color (filtered) on the texture's (interpolated) texture coordinates.
void main()
{
	FragColor = mix(texture(texture1, TexCoord), texture(texture2, vec2(1.0 - TexCoord.x, TexCoord.y)), mixValue);

}

Activate texture program:

		glActiveTexture(GL_TEXTURE0);
		//The texture will be bound to the currently active texture unit, so the texture and texture unit will be linked together
		glBindTexture(GL_TEXTURE_2D, texture1);
		glActiveTexture(GL_TEXTURE1);
		glBindTexture(GL_TEXTURE_2D, texture2);

Picture and texture coordinate system:

Texture coordinates: on the x and y axes, the range is between 0 and 1 (note that we are using 2D texture images). Using texture coordinates to get texture colors is called sampling.
Texture coordinates start at (0, 0), that is, the lower left corner of the texture image, and start at (1, 1), that is, the upper right corner of the texture image.

 

Picture coordinates: in OpenGL, the y-axis 0.0 coordinate is required to be at the bottom of the picture, but the y-axis 0.0 coordinate of the picture is usually at the top. STB? Image. H can help us flip the y-axis when the image is loaded, just add the following statement before loading any image:

stbi_set_flip_vertically_on_load(true);

You can also process the y-axis of texture coordinates in the vertex shader: TexCoord = vec2(aTexCoord.x,1- aTexCoord.y);

Vertex attribute distribution:

Shader header file:

#ifndef SHADER_H
#define SHADER_H

#include <glad/glad.h>
#include <glm/glm.hpp>

#include <string>
#include <fstream>
#include <sstream>
#include <iostream>

class ShaderTest
{
public:
	unsigned int ID;
	// constructor generates the shader on the fly
	// ------------------------------------------------------------------------
	ShaderTest(const char* vertexPath, const char* fragmentPath, const char* geometryPath = nullptr)
	{
		// 1. retrieve the vertex/fragment source code from filePath
		std::string vertexCode;
		std::string fragmentCode;
		std::string geometryCode;
		std::ifstream vShaderFile;
		std::ifstream fShaderFile;
		std::ifstream gShaderFile;
		// ensure ifstream objects can throw exceptions:
		vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
		fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
		gShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
		try
		{
			// open files
			vShaderFile.open(vertexPath);
			fShaderFile.open(fragmentPath);
			std::stringstream vShaderStream, fShaderStream;
			// read file's buffer contents into streams
			vShaderStream << vShaderFile.rdbuf();
			fShaderStream << fShaderFile.rdbuf();
			// close file handlers
			vShaderFile.close();
			fShaderFile.close();
			// convert stream into string
			vertexCode = vShaderStream.str();
			fragmentCode = fShaderStream.str();
			// if geometry shader path is present, also load a geometry shader
			if (geometryPath != nullptr)
			{
				gShaderFile.open(geometryPath);
				std::stringstream gShaderStream;
				gShaderStream << gShaderFile.rdbuf();
				gShaderFile.close();
				geometryCode = gShaderStream.str();
			}
		}
		catch (std::ifstream::failure e)
		{
			std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
		}
		const char* vShaderCode = vertexCode.c_str();
		const char * fShaderCode = fragmentCode.c_str();
		// 2. compile shaders
		unsigned int vertex, fragment;
		// vertex shader
		vertex = glCreateShader(GL_VERTEX_SHADER);
		glShaderSource(vertex, 1, &vShaderCode, NULL);
		glCompileShader(vertex);
		checkCompileErrors(vertex, "VERTEX");
		// fragment Shader
		fragment = glCreateShader(GL_FRAGMENT_SHADER);
		glShaderSource(fragment, 1, &fShaderCode, NULL);
		glCompileShader(fragment);
		checkCompileErrors(fragment, "FRAGMENT");
		// if geometry shader is given, compile geometry shader
		unsigned int geometry;
		if (geometryPath != nullptr)
		{
			const char * gShaderCode = geometryCode.c_str();
			geometry = glCreateShader(GL_GEOMETRY_SHADER);
			glShaderSource(geometry, 1, &gShaderCode, NULL);
			glCompileShader(geometry);
			checkCompileErrors(geometry, "GEOMETRY");
		}
		// shader Program
		ID = glCreateProgram();
		glAttachShader(ID, vertex);
		glAttachShader(ID, fragment);
		if (geometryPath != nullptr)
			glAttachShader(ID, geometry);
		glLinkProgram(ID);
		checkCompileErrors(ID, "PROGRAM");
		// delete the shaders as they're linked into our program now and no longer necessery
		glDeleteShader(vertex);
		glDeleteShader(fragment);
		if (geometryPath != nullptr)
			glDeleteShader(geometry);

	}
	// activate the shader
	// ------------------------------------------------------------------------
	void use()
	{
		glUseProgram(ID);
	}
	void deleteProgram()
	{
		glDeleteProgram(ID);
	}
	// utility uniform functions
	// ------------------------------------------------------------------------
	void setBool(const std::string &name, bool value) const
	{
		glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
	}
	// ------------------------------------------------------------------------
	void setInt(const std::string &name, int value) const
	{
		glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
	}
	// ------------------------------------------------------------------------
	void setFloat(const std::string &name, float value) const
	{
		glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
	}
	// ------------------------------------------------------------------------
	void setVec2(const std::string &name, const glm::vec2 &value) const
	{
		glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
	}
	void setVec2(const std::string &name, float x, float y) const
	{
		glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y);
	}
	// ------------------------------------------------------------------------
	void setVec3(const std::string &name, const glm::vec3 &value) const
	{
		glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
	}
	void setVec3(const std::string &name, float x, float y, float z) const
	{
		glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z);
	}
	// ------------------------------------------------------------------------
	void setVec4(const std::string &name, const glm::vec4 &value) const
	{
		glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
	}
	void setVec4(const std::string &name, float x, float y, float z, float w)
	{
		glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w);
	}
	// ------------------------------------------------------------------------
	void setMat2(const std::string &name, const glm::mat2 &mat) const
	{
		glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
	}
	// ------------------------------------------------------------------------
	void setMat3(const std::string &name, const glm::mat3 &mat) const
	{
		glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
	}
	// ------------------------------------------------------------------------
	void setMat4(const std::string &name, const glm::mat4 &mat) const
	{
		glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
	}

private:
	// utility function for checking shader compilation/linking errors.
	// ------------------------------------------------------------------------
	void checkCompileErrors(GLuint shader, std::string type)
	{
		GLint success;
		GLchar infoLog[1024];
		if (type != "PROGRAM")
		{
			glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
			if (!success)
			{
				glGetShaderInfoLog(shader, 1024, NULL, infoLog);
				std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
			}
		}
		else
		{
			glGetProgramiv(shader, GL_LINK_STATUS, &success);
			if (!success)
			{
				glGetProgramInfoLog(shader, 1024, NULL, infoLog);
				std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
			}
		}
	}
};
#endif

Main program:

#define STB_IMAGE_IMPLEMENTATION
#include"STB_IMAGE/stb_image.h"
#include<glad/glad.h>
#include<GLFW/glfw3.h>
#include <ShaderTest.h>
#include <iostream>


void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);

const unsigned int WINDOW_WIDTH = 800;
const unsigned int WINDOW_HEIGHT = 600;



int  main()
{
	//1 instantiate GLFW window
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	//Create a window object
	GLFWwindow* window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "TestWindows", NULL, NULL);
	if (!window)
	{
		std::cout << "Failed to create Windows" << std::endl;
		//Release resources
		glfwTerminate();
		return -1;

	}
	//Keep context
	glfwMakeContextCurrent(window);
	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

	//Initialize GLAD
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		std::cout << "Failed to initialize GLAD" << std::endl;
		return -1;
	}



	//vertex data
	float vertexDatas[] = {
	 //----Location color texture coordinates-
	 0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f,   // Right upper
	 0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f,   // lower right
	-0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f,   // Left lower
	-0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f    // Left upper
	};

	unsigned int indices[] = { // Note that the index starts from 0! 
		0, 1, 3, // First triangle
		1, 2, 3  // Second triangle
	};

	//2 create VAO,VBO,EBO
	unsigned int VAOID, VBOId, EBOID;
	glGenVertexArrays(1, &VAOID);  //The first parameter is the number of objects
	glGenBuffers(1, &VBOId);
	glGenBuffers(1, &EBOID);

	//Binding VAO
	glBindVertexArray(VAOID);

	//Bind to vertex buffer object
	glBindBuffer(GL_ARRAY_BUFFER, VBOId);
	//copy vertex data to buffer memory
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertexDatas), vertexDatas, GL_STATIC_COPY);

	//Copy the index array into an index buffer for OpenGL to use
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBOID);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

	//Parse vertex data and assign data to the vertex attribute array corresponding to 1
	//The first parameter is the vertex attribute, as opposed to the shader program location
	//Positional attribute
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
	//Enable vertex attributes, disabled by default//
	glEnableVertexAttribArray(0);  //Parameters: vertex attribute values

	//Color property
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
	//Enable property, disabled by default//
	glEnableVertexAttribArray(1);  //Parameters: vertex attribute values

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

	//Unbind VBO,VAO, do not need to unbind EBO (EBO cannot unbind when VAO is bound
	glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind VBO, the second parameter is to unbind and return to the original value
	glBindVertexArray(0); // The first parameter of unbind VAO is to unbind and return to the original value



	//3. Create shader
	ShaderTest shaderTest("vertexshader_Shader.vs", "fragementShader_Shader.fs");

	//4. Load texture
	unsigned int textureId;
	glGenTextures(1, &textureId);
	glBindTexture(GL_TEXTURE_2D, textureId);

	//Set texture wrapping
	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);

	//Load picture information
	int width, height, channels;

	unsigned char* data = stbi_load("F:/C++project/LibsInclude/src/face1.jpeg", &width, &height, &channels, 0);
	if (data) 
	{
		//Generate texture
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
		//Set multi-level fade mode
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else
	{
		std::cout << "Failed to load texture" << std::endl;
	}

	//Free memory
	stbi_image_free(data);


	//Circular rendering
	while (!glfwWindowShouldClose(window))
	{
		//input
		processInput(window);

		//rending
	
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, textureId);
		//Activate shader program
		shaderTest.use();
		glBindVertexArray(VAOID);
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

		//Swap color buffer
		glfwSwapBuffers(window);
		//Check whether the event is triggered
		glfwPollEvents();
	}

	//Delete VBO, VAO
	glDeleteVertexArrays(1, &VAOID);
	glDeleteBuffers(1, &VBOId);
	glDeleteBuffers(1, &EBOID);

	//Delete program object
	shaderTest.deleteProgram();

	//Release resources
	glfwTerminate();
	return 0;


}

//Callback function, the viewport changes when the window changes
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
	glViewport(0, 0, width, height);
}

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

Result:

Tags: Programming Fragment Attribute Windows

Posted on Sun, 22 Mar 2020 01:03:21 -0700 by dsantamassino