OpenGL point sprite

Briefly

Point sprites make OpenGL points rendered using a fragment shader. When running, the fragment coordinates in the point need to be considered. This coordinate is saved by the built-in two-dimensional vector gl_PointCoord. The most common function of this variable is to use it as texture coordinates or to calculate color and coverage.

 

Apply a texture to a point sprite

Points drawn in OpenGL have only one position coordinate. If you want to attach a texture to a point, you need to use the built-in variable gl_PointCoord to query the texels in the texture, so that a textured point sprite can be generated. Environment : OPenGL3.3, glfw, glew.

 

Simple point sprite sample source code

shader

// vertex shader
#version 330 core
layout (location = 0) in vec3 aPos;
 
void main()
{
    gl_Position = vec4(aPos.x, aPos.y, 0, 1.0);
 
 //Set the size of the point sprite
 gl_PointSize = 80;
};

// fragment shader
#version
330 core
uniform sampler2D sprite_texture;
out vec4 FragColor;
 
void main()
{
 FragColor = texture(sprite_texture, gl_PointCoord);
};

application

In the application, a texture object needs to be generated and associated to the shader, which is the same as ordinary texture mapping. Enable point sprite-related functions before drawing, and the drawing type must be GL_POINTS.

Note : There are two ways to draw the size of the point sprite. One is to call the function glPointSize() in the application to set the size of the point. In this way, the size of the point is fixed and will not become smaller with the distance from the camera. . Another is to set it in the vertex shader, using the built-in output variable two gl_PointSize to set, which can perform a linear mapping according to their distance from the near plane.

#define GLFW_STATIC
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
intmain()
{
 //---------------------------------------------------------------------------------
 glfwInit();
 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
 GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", NULL, NULL);
 if (window == NULL)
 {
  std::cout << "Failed to create GLFW window" << std::endl;
  glfwTerminate();
  return -1;
 }
 glfwMakeContextCurrent(window);
 glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
 glewExperimental = GL_TRUE;
 if (glewInit() != GLEW_OK)
 {
  std::cout << "Failed to initialize GLEW" << std::endl;
  return -1;
 }

 glViewport(0, 0, 800, 600);
 //---------------------------------------------------------------------------------
 Shader ourShader("./shader/Points.vs", "./shader/Points.fs");
 float vertices[] = {
  // position // color
  0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // Bottom right
  -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // Bottom left
  0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // top
 };
 
 //---------------Texture 1 ---------------
 unsigned int texture1;
 // create texture
 glGenTextures(1, &texture1);
 //bind texture
 glBindTexture(GL_TEXTURE_2D, texture1);
 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_MAG_FILTER, GL_LINEAR);
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 //The width, height and number of color channels of the image
 int width, height, nrChannels;
 stbi_set_flip_vertically_on_load(true);
 // load texture
 unsigned char *data = stbi_load("bricks2.jpg", &width, &height, &nrChannels, 0);
 //if the load was successful
 if (data)
 {
  // Generate a texture using the loaded image data
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
 }
 else
 {
  std::cout << "Failed to load texture" << std::endl;
 }
 // release image memory
 stbi_image_free(data);

 //create cache object
 unsigned int VBO, VAO;
 glGenVertexArrays(1, &VAO);
 glGenBuffers(1, &VBO);
 //Bind VAO
 glBindVertexArray(VAO);
 //Bind VBO
 glBindBuffer(GL_ARRAY_BUFFER, VBO);
 //copy vertex array to VBO
 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
 // position property, the first parameter is the shader position
 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
 glEnableVertexAttribArray(0);
 // color property
 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
 glEnableVertexAttribArray(1);
 while (!glfwWindowShouldClose(window))
 {
  processInput(window);
  glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
  glClear(GL_COLOR_BUFFER_BIT);
  // point sprite settings
  glEnable(GL_POINT_SPRITE);
  glEnable(GL_PROGRAM_POINT_SIZE);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE);
  // activate the shader
  ourShader.use();
  glBindTexture(GL_TEXTURE_2D, texture1);
  //Bind the vertex buffer object
  glBindVertexArray(VAO);
  // start drawing
  glDrawArrays(GL_POINTS, 0, 3);
  //unbind
  glBindVertexArray(0);

  // swap cache
  glfwSwapBuffers(window);
  //Query io events
  glfwPollEvents();
 }
 // delete vertex array object and vertex buffer object
 glDeleteVertexArrays(1, &VAO);
 glDeleteBuffers(1, &VBO);
 glfwTerminate();
 return 0;
}

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);
 }
}

 Effect


Parse point sprite color and shape

The resolution of textures is limited and we are not limited to just loading data from textures. gl_PointCoord is very accurate. Take gl_PointCoord as the center of the point, and then calculate the distance between the fragment and the center of the point sprite. If it is greater than 0.25, use the discard keyword to reject the fragment, thus generating a circle with a radius of 0.25.

Sample source code

Note: Only need to modify the shader code, the application is the same as above

// vertex shader
#version 330 core
layout (location = 0) in vec3 aPos;

void main()
{
	gl_PointSize = 80;
    gl_Position = vec4(aPos.x, aPos.y, 0, 1.0);
};

// fragment shader
#version 330 core

uniform sampler2D sprite_texture;
out vec4 FragColor;

void main()
{

	const vec4 color1 = vec4(0.6,0.0,0.0,1.0);
	const vec4 color2 = vec4(0.9,0.7,1.0,0.0);

	vec2 temp = gl_PointCoord - vec2(0.5);
	float f = dot(temp, temp);
	
	if(f > 0.25)
	{
		discard;
	}

	FragColor = mix(color1, color2, smoothstep(0.1, 0.25, f));
};

Effect

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325851305&siteId=291194637