openGL learning notes - hybrid

Discard clip: for the rendering of transparent objects, you can discard the clip:

void main()
{             
    vec4 texColor = texture(texture1, TexCoords);
    if(texColor.a < 0.1)
        discard;
    FragColor = texColor;
}

Blend: although it's good to discard the clip directly, it can't render a translucent image. We either render a clip or discard it completely. Blending needs to be enabled

glEnable(GL_BLEND);

Mixed formula:

Through glblendforc (glenum sfactor, glenum dfactor),

But there is occlusion problem:

Cause: when writing the depth buffer, the depth buffer will not check whether the fragment is transparent, so the transparent part will be written to the depth buffer like other values. The result is that the entire quadrilateral of the window is tested for depth regardless of its transparency. Even though the transparent parts should show the windows behind them, the depth test still discards them.

Question: why do transparent objects not block opaque objects, but mix them?

Define rendering order: (back to front)

Rendering principles:

  1. First draw all opaque objects.
  2. Sort all transparent objects.
  3. Draw all transparent objects in order.
Sort transparent objects:
std::map<float, glm::vec3> sorted;
for (unsigned int i = 0; i < windows.size(); i++)
{
    float distance = glm::length(camera.Position - windows[i]);
    sorted[distance] = windows[i];
}

 

Render from far to near:
for(std::map<float,glm::vec3>::reverse_iterator it = sorted.rbegin(); it != sorted.rend(); ++it) 
{
    model = glm::mat4();
    model = glm::translate(model, it->second);              
    shader.setMat4("model", model);
    glDrawArrays(GL_TRIANGLES, 0, 6);
}

 

Main program:

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

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include <ShaderTest.h>
#include <Texture.h>
#include <Camera.h>
#include <iostream>
#include<vector>
#include<map>



void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
unsigned int loadTexture(char const* texturePath);


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

glm::vec3 cameraPos = glm::vec3(-1.0f, -1.0f, 1.5f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);



Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
glm::vec3 lightDiretion(1.2f, 1.0f, 2.0f);
bool firstMouse = true;
double lastX = WINDOW_WIDTH / 2;
double lastY = WINDOW_HEIGHT / 2;
float yaw = -90.0f;
float pitch = 0.0f;
float fov = 45.0f;

float lastTime = 0.0f;
float deltaTime = 0.0f;

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 cubeVertices[] = {
		// positions          // texture Coords
		-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
		 0.5f, -0.5f, -0.5f,  1.0f, 0.0f,
		 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
		 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
		-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
		-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,

		-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
		 0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
		 0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
		 0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
		-0.5f,  0.5f,  0.5f,  0.0f, 1.0f,
		-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,

		-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
		-0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
		-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
		-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
		-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
		-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

		 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
		 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
		 0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
		 0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
		 0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
		 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

		-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
		 0.5f, -0.5f, -0.5f,  1.0f, 1.0f,
		 0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
		 0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
		-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
		-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,

		-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
		 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
		 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
		 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
		-0.5f,  0.5f,  0.5f,  0.0f, 0.0f,
		-0.5f,  0.5f, -0.5f,  0.0f, 1.0f
	};
	float planeVertices[] = {
		// positions          // texture Coords
		 5.0f, -0.5f,  5.0f,  2.0f, 0.0f,
		-5.0f, -0.5f,  5.0f,  0.0f, 0.0f,
		-5.0f, -0.5f, -5.0f,  0.0f, 2.0f,

		 5.0f, -0.5f,  5.0f,  2.0f, 0.0f,
		-5.0f, -0.5f, -5.0f,  0.0f, 2.0f,
		 5.0f, -0.5f, -5.0f,  2.0f, 2.0f
	};

	//grass
	std::vector<glm::vec3> vegetation
	{
		glm::vec3(-1.5f, 0.0f, -0.48f),
		glm::vec3(1.5f, 0.0f, 0.51f),
		glm::vec3(0.0f, 0.0f, 0.7f),
		glm::vec3(-0.3f, 0.0f, -2.3f),
		glm::vec3(0.5f, 0.0f, -0.6f)
	};

	float transparentVertices[] = {
		// positions         // texture Coords (swapped y coordinates because texture is flipped upside down)
		0.0f,  0.5f,  0.0f,  0.0f,  0.0f,
		0.0f, -0.5f,  0.0f,  0.0f,  1.0f,
		1.0f, -0.5f,  0.0f,  1.0f,  1.0f,

		0.0f,  0.5f,  0.0f,  0.0f,  0.0f,
		1.0f, -0.5f,  0.0f,  1.0f,  1.0f,
		1.0f,  0.5f,  0.0f,  1.0f,  0.0f
	};


	//2 create VAO,VBO,EBO
	unsigned int VAOID, VBOId;
	glGenVertexArrays(1, &VAOID);  //The first parameter is the number of objects
	glGenBuffers(1, &VBOId);
	//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(cubeVertices), cubeVertices, GL_STATIC_COPY);

	//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, 5 * sizeof(float), (void*)0);
	//Enable vertex attributes, disabled by default//
	glEnableVertexAttribArray(0);  //Parameters: vertex attribute values

	//Texture attribute
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(1);


	//floor
	unsigned int PlaneVAOID, PlaneVBOID;
	glGenVertexArrays(1, &PlaneVAOID);  //The first parameter is the number of objects
	glGenBuffers(1, &PlaneVBOID);
	//Binding VAO
	glBindVertexArray(PlaneVAOID);
	//Bind to vertex buffer object
	glBindBuffer(GL_ARRAY_BUFFER, PlaneVBOID);
	//copy vertex data to buffer memory
	glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), planeVertices, GL_STATIC_COPY);
	//Positional attribute
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
	//Enable vertex attributes, disabled by default//
	glEnableVertexAttribArray(0);  //Parameters: vertex attribute values

	//Texture attribute
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(1);


	unsigned int GrassVAO, GrassVBO;
	glGenVertexArrays(1, &GrassVAO);
	glGenBuffers(1, &GrassVBO);
	glBindVertexArray(GrassVAO);
	glBindBuffer(GL_ARRAY_BUFFER, GrassVBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(transparentVertices), transparentVertices, GL_STATIC_DRAW);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(1);
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
	glBindVertexArray(0);
	//3. Create shader
	ShaderTest shaderTest("openGL_Blending.vs", "openGL_Blending.fs");

	//4. Texture object
	unsigned int textureId = loadTexture("F:/C++project/LibsInclude/src/marble.jpg");
	unsigned int textureId2 = loadTexture("F:/C++project/LibsInclude/src/metal.png");
	unsigned int GrassTextureID = loadTexture("F:/C++project/LibsInclude/src/grass.png");

	//Index texture cells
	shaderTest.use();

	//Opening depth test
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	shaderTest.setInt("ourTexture", 0);

	//Circular rendering
	while (!glfwWindowShouldClose(window))
	{

		float currentTime = glfwGetTime();
		deltaTime = currentTime - lastTime;
		lastTime = currentTime;
		//input
		processInput(window);
		glfwSetCursorPosCallback(window, mouse_callback);
		glfwSetScrollCallback(window, scroll_callback);

		//Clear color and depth buffers
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		//Sorting transparent objects
		std::map<float, glm::vec3> SortDistance;
		for (unsigned int k = 0; k < vegetation.size(); k++)
		{
			float distance = glm::length(camera.Position - vegetation[k]);
			SortDistance[distance] = vegetation[k];
		}
		//Binding texture units and texture objects
		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, textureId);
		glActiveTexture(GL_TEXTURE1);
		glBindTexture(GL_TEXTURE_2D, textureId2);

		//Activate shader program
		shaderTest.use();
		glm::mat4 model = glm::mat4(1.0f);
		glm::mat4 projection = glm::mat4(1.0f);
		glm::mat4 view = camera.GetViewMatrix();
		projection = glm::perspective(glm::radians(camera.Zoom), (float)WINDOW_WIDTH / (float)WINDOW_HEIGHT, 0.1f, 100.0f);
		shaderTest.setMat4("view", view);
		shaderTest.setMat4("projection", projection);

		glBindVertexArray(VAOID);
		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, textureId);
		model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f));
		shaderTest.setMat4("model", model);
		glDrawArrays(GL_TRIANGLES, 0, 36);

		model = glm::mat4(1.0f);
		model = glm::translate(model, glm::vec3(1.0f, 0.0f, 0.0f));
		shaderTest.setMat4("model", model);
		glDrawArrays(GL_TRIANGLES, 0, 36);
		// floor
		glBindVertexArray(PlaneVAOID);
		glBindTexture(GL_TEXTURE_2D, textureId2);
		shaderTest.setMat4("model", glm::mat4(1.0f));
		glDrawArrays(GL_TRIANGLES, 0, 6);
		glBindVertexArray(0);

		//Flowers and plants
		glBindVertexArray(GrassVAO);
		glBindTexture(GL_TEXTURE_2D, GrassTextureID);
		//Drawing from far to near
		for (std::map<float, glm::vec3>::reverse_iterator it = SortDistance.rbegin(); it != SortDistance.rend(); ++it) {
			model = glm::mat4(1.0f);
			model = glm::translate(model, it->second);
			shaderTest.setMat4("model", model);
			glDrawArrays(GL_TRIANGLES, 0, 6);
		}

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

	//Delete VBO, VAO
	glDeleteVertexArrays(1, &VAOID);
	glDeleteVertexArrays(1, &PlaneVAOID);
	glDeleteVertexArrays(1, &GrassVAO);
	glDeleteBuffers(1, &VBOId);
	glDeleteBuffers(1, &PlaneVBOID);
	glDeleteBuffers(1, &GrassVBO);
	//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)
{
	float moveSpeed = 0.5f * deltaTime;
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
	{
		glfwSetWindowShouldClose(window, true);
	}
	if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
	{
		cameraPos += cameraFront * moveSpeed;
	}
	if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
	{
		cameraPos -= cameraFront * moveSpeed;
	}
	if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
	{
		cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp))* moveSpeed;
	}
	if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
	{
		cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp))* moveSpeed;
	}
}

//Mouse callback
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
	if (firstMouse)
	{
		lastX = xpos;
		lastY = ypos;
		firstMouse = false;
	}

	float xoffset = xpos - lastX;
	float yoffset = lastY - ypos;
	lastX = xpos;
	lastY = ypos;

	camera.ProcessMouseMovement(xoffset, yoffset);
}

//Define cursor callback function
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
	camera.ProcessMouseScroll(yoffset);
}

//Loading texture
unsigned int loadTexture(char const* texturePath)
{
	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);
	//Texture sampling method
	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(texturePath, &width, &height, &channels, 0);
	if (data)
	{
		GLenum imageFormat;
		if (channels == 1)
		{
			imageFormat = GL_RED;
		}
		else if (channels == 3)
		{
			imageFormat = GL_RGB;
		}
		else if (channels == 4)
		{
			imageFormat = GL_RGBA;
		}

		glTexImage2D(GL_TEXTURE_2D, 0, imageFormat, width, height, 0, imageFormat, GL_UNSIGNED_BYTE, data);
		//Set multi-level fade mode
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else
	{
		std::cout << "Failed to load Firsttexture" << std::endl;
		//Free memory
		stbi_image_free(data);
	}
	return textureId;


}

Result:

Keywords: Programming Attribute Windows Fragment

Added by point86 on Mon, 30 Mar 2020 18:27:09 +0300