从零开始的openGL--cs游戏(14) 延迟渲染G缓冲。

请添加图片描述

window类中定义G缓冲

#ifndef Window_H
#define Window_H
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>

using namespace std;
class Scene;
class Time;
class Input;
class Shader;
enum class Key;
void Resize(GLFWwindow* window, int width, int height);
void mouseCallback(GLFWwindow* window, double xpos, double ypos);
void stbi_set_flip_vertically_on_load2(bool b);
class Window
{
    
    
public:
	static Window* Instance;
	Window(int width, int height);

	~Window();
	void InitEvent();
	void InitInput();
	void InitResource();
	void Mainloop();
	void InitGbuffer();
	int Width, Height;
	void SetDeltaTime(float time);
	void SetStartTime(float time);
	void SetCurTime(float time);
	void InitScene();
	void renderQuad();
	void Log(string str);
	unsigned int gBuffer;
	unsigned int g_positionMap;
	unsigned int g_albedoMap;
	unsigned int g_specularMap;
	unsigned int g_normalMap;
	unsigned int g_height_ao_metallic_roughnessMap;
	unsigned int rboDepth;

	unsigned int quadVAO = 0;
	unsigned int quadVBO;
	GLFWwindow* window_ptr;
private:
	void KeyDown(Key key);
	void KeyUp(Key key);
	Scene* m_scene;
	Input* _input;
	Shader* _gBufferShader;
};
#endif

---------------------------------
#include "Window.h"
#include "Scene.h"
#include "Time.h"
#include "Input.h"
#include "EventCenter.h"
#include "ResourceManager.h"
#include <boost/bind/bind.hpp>
#include "Shader.h"
#include <stb_image.h>
Window* Window::Instance = NULL;
Window::Window(int width, int height)
{
    
    
	Width = width;
	Height = height;
	// glfw: initialize and configure
	// ------------------------------
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

#ifdef __APPLE__
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);


#endif

	// glfw window creation
	// --------------------
	window_ptr = glfwCreateWindow(width, height, "CSGame", NULL, NULL);
	if (window_ptr == NULL)
	{
    
    
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return;
	}
	glfwMakeContextCurrent(window_ptr);
	glfwSetFramebufferSizeCallback(window_ptr, Resize);
	glfwSetCursorPosCallback(window_ptr, mouseCallback);

	// glad: load all OpenGL function pointers
	// ---------------------------------------
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
    
    
		std::cout << "Failed to initialize GLAD" << std::endl;
		return;
	}
	Window::Instance = this;
}

Window::~Window()
{
    
    
	glfwTerminate();
}

void Window::InitEvent()
{
    
    
	EventCenter::Instance->AddEvent<string>("Log", boost::bind(&Window::Log, this, placeholders::_1));
	EventCenter::Instance->AddEvent<Key>("KeyDown", boost::bind(&Window::KeyDown, this, placeholders::_1));
	EventCenter::Instance->AddEvent<Key>("KeyUp", boost::bind(&Window::KeyUp, this, placeholders::_1));
}

void Window::InitInput()
{
    
    
	_input = new Input();
}

void Window::InitResource()
{
    
    
	
	ResourceManager::LoadShader("Shader/cube_vs.vs", "Shader/cube_fs.fs", nullptr, "CubeShader");
	ResourceManager::LoadShader("Shader/model.vs", "Shader/model.fs", nullptr, "ModelShader");
	ResourceManager::LoadShader("Shader/g_skeleton_model.vs", "Shader/g_skeleton_model.fs", nullptr, "SkeletonModelShader");
	ResourceManager::LoadShader("Shader/gBuffer.vs", "Shader/gBuffer.fs", nullptr, "GBufferShader");
	_gBufferShader = ResourceManager::GetShaderP("GBufferShader");
	ResourceManager::LoadTexture("Texture/map.jpeg", false, "map");
}

void Resize(GLFWwindow* window, int width, int height)
{
    
    
	glfwGetWindowSize(window, &width, &height);
	if (width != Window::Instance->Width || Window::Instance->Height)
	{
    
    
		Window::Instance->Width = width;
		Window::Instance->Height = height;
		glViewport(0, 0, width, height);
		printf("resized \n");
	}
}
void mouseCallback(GLFWwindow* window, double xpos, double ypos)
{
    
    
	Input::xoffset = xpos - Input::xpos;
	Input::yoffset = ypos - Input::ypos;

	Input::xpos = xpos;
	Input::ypos = ypos;
}

void Window::Mainloop()
{
    
    
	
	// tell stb_image.h to flip loaded texture's on the y-axis (before loading model).
	stbi_set_flip_vertically_on_load2(true);
	glEnable(GL_DEPTH_TEST);

	InitGbuffer();
	InitResource();
	InitEvent();
	InitInput();
	InitScene();
	float starTime = glfwGetTime();
	float currentFrame, lastFrame = starTime;
	SetStartTime(starTime);

	while (!glfwWindowShouldClose(Window::window_ptr))
	{
    
    
		currentFrame = glfwGetTime();
		SetCurTime(currentFrame);
		float deltaTime = currentFrame - lastFrame;
		lastFrame = currentFrame;
		SetDeltaTime(deltaTime);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glClearColor(0.05f, 0.05f, 0.05f, 1.0f);
		glBindFramebuffer(GL_FRAMEBUFFER, gBuffer);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		_input->Update();
		//for each frame 

		Scene::Instace->Update();
		Scene::Instace->LateUpdate();
		Scene::Instace->Render();
		glBindFramebuffer(GL_FRAMEBUFFER, 0);

		// 2. lighting pass: calculate lighting by iterating over a screen filled quad pixel-by-pixel using the gbuffer's content.
		// -----------------------------------------------------------------------------------------------------------------------
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		_gBufferShader->Use();
		glActiveTexture(GL_TEXTURE0);
		glUniform1i(glGetUniformLocation(_gBufferShader->ID, "gPosition"), 0);
		// and finally bind the texture
		glBindTexture(GL_TEXTURE_2D, g_positionMap);
		glActiveTexture(GL_TEXTURE1);
		glUniform1i(glGetUniformLocation(_gBufferShader->ID, "gAlbedoMap"), 1);
		glBindTexture(GL_TEXTURE_2D, g_albedoMap);
		glActiveTexture(GL_TEXTURE2);
		glUniform1i(glGetUniformLocation(_gBufferShader->ID, "gSpecularMap"), 2);
		glBindTexture(GL_TEXTURE_2D, g_specularMap);
		glActiveTexture(GL_TEXTURE3);
		glUniform1i(glGetUniformLocation(_gBufferShader->ID, "gNormalMap"), 3);
		glBindTexture(GL_TEXTURE_2D, g_normalMap);
		glActiveTexture(GL_TEXTURE4);
		glUniform1i(glGetUniformLocation(_gBufferShader->ID, "gHeightAoMetallicRoughnessMap"), 4);
		glBindTexture(GL_TEXTURE_2D, g_height_ao_metallic_roughnessMap);
		renderQuad();
		// all drawing goes here ..
		glfwSwapBuffers(window_ptr);
		glfwPollEvents();
	}
}

void Window::InitGbuffer()
{
    
    
	glGenFramebuffers(1, &gBuffer);
	glBindFramebuffer(GL_FRAMEBUFFER, gBuffer);

	//位置缓冲
	glGenTextures(1, &g_positionMap);
	glBindTexture(GL_TEXTURE_2D, g_positionMap);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, Width, Height, 0, GL_RGB, GL_FLOAT, NULL);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, g_positionMap, 0);

	//颜色缓冲
	glGenTextures(1, &g_albedoMap);
	glBindTexture(GL_TEXTURE_2D, g_albedoMap);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, GL_RGBA, GL_FLOAT, NULL);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, g_albedoMap, 0);

	//高光颜色缓冲
	glGenTextures(1, &g_specularMap);
	glBindTexture(GL_TEXTURE_2D, g_specularMap);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, Width, Height, 0, GL_RGB, GL_FLOAT, NULL);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, g_specularMap, 0);

	//法线缓冲
	glGenTextures(1, &g_normalMap);
	glBindTexture(GL_TEXTURE_2D, g_normalMap);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, Width, Height, 0, GL_RGB, GL_FLOAT, NULL);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, g_normalMap, 0);

	//高度缓冲,AO缓冲 ,光泽度缓冲,粗糙度缓冲
	glGenTextures(1, &g_height_ao_metallic_roughnessMap);
	glBindTexture(GL_TEXTURE_2D, g_height_ao_metallic_roughnessMap);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, GL_RGBA, GL_FLOAT, NULL);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, GL_TEXTURE_2D, g_height_ao_metallic_roughnessMap, 0);


	unsigned int attachments[5] = {
    
     GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2,
	GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4,};
	glDrawBuffers(5, attachments);

	glGenRenderbuffers(1, &rboDepth);
	glBindRenderbuffer(GL_RENDERBUFFER, rboDepth);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, Width, Height);
	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboDepth);
	// finally check if framebuffer is complete
	if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
		std::cout << "Framebuffer not complete!" << std::endl;
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void Window::SetDeltaTime(float time)
{
    
    
	Time::_deltaTime = time;
}

void Window::SetStartTime(float time)
{
    
    
	Time::_startTime = time;
}

void Window::SetCurTime(float time)
{
    
    
	Time::_curTime = time;
}

void Window::InitScene()
{
    
    
	m_scene = Scene::Init();
}

void Window::renderQuad()
{
    
    
	if (quadVAO == 0)
	{
    
    
		float quadVertices[] = {
    
    
			// positions        // texture Coords
			-1.0f,  1.0f, 0.0f, 0.0f, 1.0f,
			-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
			 1.0f,  1.0f, 0.0f, 1.0f, 1.0f,
			 1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
		};
		// setup plane VAO
		glGenVertexArrays(1, &quadVAO);
		glGenBuffers(1, &quadVBO);
		glBindVertexArray(quadVAO);
		glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
		glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, 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(quadVAO);
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
	glBindVertexArray(0);
}

void Window::Log(string str)
{
    
    
	cout << str << endl;
}

void Window::KeyDown(Key key)
{
    
    
	Log(to_string((int)key));
}

void Window::KeyUp(Key key)
{
    
    
	Log(to_string((int)key));
}

void stbi_set_flip_vertically_on_load2(bool b)
{
    
    
	stbi_set_flip_vertically_on_load(b);
}


那么场景中的物体要使用专门的shader

#version 430 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
layout (location = 3) in vec3 Tangent;
layout (location = 4) in vec3 Bitangent;
layout (location = 5) in ivec4 BoneIDs;
layout (location = 6) in vec4 Weights;

out vec2 TexCoords;
out vec3 WorldPos;
out vec3 Normal;

layout(std140 , binding = 0) uniform PV
{
    
    
	mat4 projection;
	mat4 view;
};
uniform mat4 model;

const int MAX_BONES = 100; // Max number of bones
uniform mat4 gBones[MAX_BONES]; // Bone transformations 
void main()
{
    
    
    mat4 BoneTransform = gBones[ BoneIDs[0] ] * Weights[0];
	BoneTransform += gBones[ BoneIDs[1] ] * Weights[1];
    BoneTransform += gBones[ BoneIDs[2] ] * Weights[2];
    BoneTransform += gBones[ BoneIDs[3] ] * Weights[3];

	// Transformed vertex position 
	vec4 tPos = BoneTransform * vec4(aPos, 1.0);
    TexCoords = aTexCoords;
    WorldPos = vec3(model * tPos);
    Normal = mat3(model) * aNormal;   

    //gl_Position =  projection * view * vec4(WorldPos, 1.0);
    gl_Position =  projection * view * model * tPos;
}

-----------------------
#version 430 core
layout (location = 0) out vec3 gPosition;
layout (location = 1) out vec4 gAlbedoMap;
layout (location = 2) out vec3 gSpecularMap;
layout (location = 3) out vec3 gNormalMap;
layout (location = 4) out vec4 gHeightAoMetallicRoughnessMap;


in vec2 TexCoords;
in vec3 WorldPos;
in vec3 Normal;

// material parameters
uniform sampler2D albedoMap;
uniform sampler2D specularMap;
uniform sampler2D normalMap;
uniform sampler2D heightMap;
uniform sampler2D aoMap;
uniform sampler2D metallicMap;
uniform sampler2D roughnessMap;
uniform float use_albedoMap;
uniform float use_specularMap;
uniform float use_normalMap;
uniform float use_heightMap;
uniform float use_aoMap;
uniform float use_metallicMap;
uniform float use_roughnessMap;

void main()
{
    
    	
    gPosition = WorldPos;
    gAlbedoMap = vec4(texture(albedoMap, TexCoords).rgb ,1.0f);
    gNormalMap =  (1.0 - use_normalMap) *  Normal + use_normalMap * (texture(normalMap, TexCoords).rgb);
    gSpecularMap =  (1.0 - use_specularMap) *  vec3(0.8f,0.8f,0.8f) + use_specularMap * (texture(specularMap, TexCoords).rgb);  

    float height = (1.0 - use_heightMap) * 0.5f +  use_heightMap * texture(heightMap, TexCoords).r;
    float metallic  = (1.0 - use_metallicMap) * 0.3f +  use_metallicMap * texture(metallicMap, TexCoords).r;
    float roughness = (1.0 - use_roughnessMap) * 0.2f +  use_roughnessMap * texture(roughnessMap, TexCoords).r;
    float ao        = (1.0 - use_albedoMap) * 0.2f +  use_albedoMap * texture(aoMap, TexCoords).r;

    gHeightAoMetallicRoughnessMap = vec4(height ,ao ,metallic ,roughness);
}

最后是G缓冲的shader

#version 430 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoords;

out vec2 TexCoords;

void main()
{
    
    
    TexCoords = aTexCoords;
    gl_Position = vec4(aPos, 1.0);
}
--------------------------#version 430 core
out vec4 FragColor;

in vec2 TexCoords;

uniform sampler2D gPosition;
uniform sampler2D gAlbedoMap;
uniform sampler2D gSpecularMap;
uniform sampler2D gNormalMap;
uniform sampler2D gHeightAoMetallicRoughnessMap;

layout(std140 , binding = 1) uniform BaseLight
{
    
    
	vec4 lightDir;
	vec4 color;
	vec4 ambient;
};
layout(std140 , binding = 2) uniform BaseView
{
    
    
	vec3 viewPos;
};
// lights

const float PI = 3.14159265359;
// ----------------------------------------------------------------------------
// Easy trick to get tangent-normals to world-space to keep PBR code simplified.
// Don't worry if you don't get what's going on; you generally want to do normal 
// mapping the usual way for performance anways; I do plan make a note of this 
// technique somewhere later in the normal mapping tutorial.
vec3 getNormalFromMap()
{
    
    
    vec3 tangentNormal = texture(gNormalMap, TexCoords).xyz * 2.0 - 1.0;

    vec3 Q1  = dFdx(texture(gPosition, TexCoords).rgb);
    vec3 Q2  = dFdy(texture(gPosition, TexCoords).rgb);
    vec2 st1 = dFdx(TexCoords);
    vec2 st2 = dFdy(TexCoords);

    vec3 N   = normalize(texture(gNormalMap, TexCoords).rgb);
    vec3 T  = normalize(Q1*st2.t - Q2*st1.t);
    vec3 B  = -normalize(cross(N, T));
    mat3 TBN = mat3(T, B, N);

    return normalize(TBN * tangentNormal);
}
// ----------------------------------------------------------------------------
float DistributionGGX(vec3 N, vec3 H, float roughness)
{
    
    
    float a = roughness*roughness;
    float a2 = a*a;
    float NdotH = max(dot(N, H), 0.0);
    float NdotH2 = NdotH*NdotH;

    float nom   = a2;
    float denom = (NdotH2 * (a2 - 1.0) + 1.0);
    denom = PI * denom * denom;

    return nom / denom;
}
// ----------------------------------------------------------------------------
float GeometrySchlickGGX(float NdotV, float roughness)
{
    
    
    float r = (roughness + 1.0);
    float k = (r*r) / 8.0;

    float nom   = NdotV;
    float denom = NdotV * (1.0 - k) + k;

    return nom / denom;
}
// ----------------------------------------------------------------------------
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
{
    
    
    float NdotV = max(dot(N, V), 0.0);
    float NdotL = max(dot(N, L), 0.0);
    float ggx2 = GeometrySchlickGGX(NdotV, roughness);
    float ggx1 = GeometrySchlickGGX(NdotL, roughness);

    return ggx1 * ggx2;
}
// ----------------------------------------------------------------------------
vec3 fresnelSchlick(float cosTheta, vec3 F0)
{
    
    
    return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
}
// ----------------------------------------------------------------------------
void main()
{
    
    	
    vec3 albedo     = pow(texture(gAlbedoMap, TexCoords).rgb, vec3(2.2));
    float metallic  = texture(gHeightAoMetallicRoughnessMap, TexCoords).b;
    float roughness = texture(gHeightAoMetallicRoughnessMap, TexCoords).a;
    float ao        = texture(gHeightAoMetallicRoughnessMap, TexCoords).g;
    vec3 WorldPos = texture(gPosition, TexCoords).rgb;

    vec3 N = getNormalFromMap();
    vec3 V = normalize(viewPos - WorldPos);

    // calculate reflectance at normal incidence; if dia-electric (like plastic) use F0 
    // of 0.04 and if it's a metal, use the albedo color as F0 (metallic workflow)    
    vec3 F0 = vec3(0.04); 
    F0 = mix(F0, albedo, metallic);

    // reflectance equation
    vec3 Lo = vec3(0.0);
    vec3 L = normalize(-lightDir.xyz);
        vec3 H = normalize(V + L);
        //float distance = length(lightPositions[i] - WorldPos);
        //float attenuation = 1.0 / (distance * distance);
        float attenuation = 1.0;
        vec3 radiance = color.xyz * attenuation;
        
        // Cook-Torrance BRDF
        float NDF = DistributionGGX(N, H, roughness);   
        float G   = GeometrySmith(N, V, L, roughness);      
        vec3 F    = fresnelSchlick(max(dot(H, V), 0.0), F0);
           
        vec3 numerator    = NDF * G * F; 
        float denominator = 4 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.0001; // + 0.0001 to prevent divide by zero
        vec3 specular = numerator / denominator;
        
        // kS is equal to Fresnel
        vec3 kS = F;
        // for energy conservation, the diffuse and specular light can't
        // be above 1.0 (unless the surface emits light); to preserve this
        // relationship the diffuse component (kD) should equal 1.0 - kS.
        vec3 kD = vec3(1.0) - kS;
        // multiply kD by the inverse metalness such that only non-metals 
        // have diffuse lighting, or a linear blend if partly metal (pure metals
        // have no diffuse light).
        kD *= 1.0 - metallic;	  

        // scale light by NdotL
        float NdotL = max(dot(N, L), 0.0);        

        // add to outgoing radiance Lo
        Lo += (kD * albedo / PI + specular) * radiance * NdotL;  // note that we already multiplied the BRDF by the Fresnel (kS) so we won't multiply by kS again 
    
    // ambient lighting (note that the next IBL tutorial will replace 
    // this ambient lighting with environment lighting).
    vec3 ambient2 = ambient.xyz * albedo * ao;
    
    vec3 color2 = ambient2 + Lo;

    // HDR tonemapping
    color2 = color2 / (color2 + vec3(1.0));
    // gamma correct
    color2 = pow(color2, vec3(1.0/2.2));
    FragColor = vec4(color2, 1.0);
}--

猜你喜欢

转载自blog.csdn.net/qq_41041725/article/details/121998626
今日推荐