add static and animation PBR shader, improve [camera renderer material] class
This commit is contained in:
@ -111,13 +111,24 @@ DemoLayer::~DemoLayer()
|
||||
|
||||
void DemoLayer::OnAttach()
|
||||
{
|
||||
m_SimplePBRShader.reset(Prism::Shader::Create("assets/shaders/simplepbr.glsl"));
|
||||
m_QuadShader.reset(Prism::Shader::Create("assets/shaders/quad.glsl"));
|
||||
m_HDRShader.reset(Prism::Shader::Create("assets/shaders/hdr.glsl"));
|
||||
m_GridShader.reset(Prism::Shader::Create("assets/shaders/Grid.glsl"));
|
||||
m_Mesh.reset(new Prism::Mesh("assets/models/m1911/m1911.fbx"));
|
||||
m_SphereMesh.reset(new Prism::Mesh("assets/models/Sphere1m.fbx"));
|
||||
m_PlaneMesh.reset(new Prism::Mesh("assets/models/Plane1m.fbx"));
|
||||
|
||||
m_Framebuffer.reset(Prism::FrameBuffer::Create(1280, 720, Prism::FramebufferFormat::RGBA16F));
|
||||
m_FinalPresentBuffer.reset(Prism::FrameBuffer::Create(1280, 720, Prism::FramebufferFormat::RGBA8));
|
||||
|
||||
m_QuadShader = Prism::Shader::Create("assets/shaders/quad.glsl");
|
||||
m_HDRShader= Prism::Shader::Create("assets/shaders/hdr.glsl");
|
||||
m_GridShader = Prism::Shader::Create("assets/shaders/Grid.glsl");
|
||||
|
||||
m_Mesh = Prism::CreateRef<Prism::Mesh>("assets/models/m1911/m1911.fbx");
|
||||
m_MeshMaterial = Prism::CreateRef<Prism::MaterialInstance>(m_Mesh->GetMaterial());
|
||||
|
||||
m_SphereMesh = Prism::CreateRef<Prism::Mesh>("assets/models/Sphere1m.fbx");
|
||||
m_PlaneMesh = Prism::CreateRef<Prism::Mesh>("assets/models/Plane1m.fbx");
|
||||
|
||||
m_GridShader = Prism::Shader::Create("assets/shaders/Grid.glsl");
|
||||
m_GridMaterial = Prism::MaterialInstance::Create(Prism::Material::Create(m_GridShader));
|
||||
m_GridMaterial->Set("u_Scale", m_GridScale);
|
||||
m_GridMaterial->Set("u_Res", m_GridSize);
|
||||
|
||||
// Editor
|
||||
m_CheckerboardTex.reset(Prism::Texture2D::Create("assets/editor/Checkerboard.tga"));
|
||||
@ -127,16 +138,12 @@ void DemoLayer::OnAttach()
|
||||
m_EnvironmentIrradiance.reset(Prism::TextureCube::Create("assets/textures/environments/Arches_E_PineTree_Irradiance.tga"));
|
||||
m_BRDFLUT.reset(Prism::Texture2D::Create("assets/textures/BRDF_LUT.tga"));
|
||||
|
||||
m_Framebuffer.reset(Prism::FrameBuffer::Create(1280, 720, Prism::FramebufferFormat::RGBA16F));
|
||||
m_FinalPresentBuffer.reset(Prism::FrameBuffer::Create(1280, 720, Prism::FramebufferFormat::RGBA8));
|
||||
|
||||
m_PBRMaterial.reset(new Prism::Material(m_SimplePBRShader));
|
||||
|
||||
float x = -4.0f;
|
||||
float roughness = 0.0f;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
Prism::Ref<Prism::MaterialInstance> mi(new Prism::MaterialInstance(m_PBRMaterial));
|
||||
Prism::Ref<Prism::MaterialInstance> mi = Prism::CreateRef<Prism::MaterialInstance>(m_SphereMesh->GetMaterial());
|
||||
mi->Set("u_Metalness", 1.0f);
|
||||
mi->Set("u_Roughness", roughness);
|
||||
mi->Set("u_ModelMatrix", glm::translate(glm::mat4(1.0f), glm::vec3(x, 0.0f, 0.0f)));
|
||||
@ -149,7 +156,7 @@ void DemoLayer::OnAttach()
|
||||
roughness = 0.0f;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
Prism::Ref<Prism::MaterialInstance> mi(new Prism::MaterialInstance(m_PBRMaterial));
|
||||
Prism::Ref<Prism::MaterialInstance> mi = Prism::CreateRef<Prism::MaterialInstance>(m_SphereMesh->GetMaterial());
|
||||
mi->Set("u_Metalness", 0.0f);
|
||||
mi->Set("u_Roughness", roughness);
|
||||
mi->Set("u_ModelMatrix", translate(glm::mat4(1.0f), glm::vec3(x, 1.2f, 0.0f)));
|
||||
@ -212,10 +219,6 @@ void DemoLayer::OnUpdate(const Prism::TimeStep deltaTime)
|
||||
m_Framebuffer->Bind();
|
||||
Renderer::Clear(m_ClearColor[0], m_ClearColor[1], m_ClearColor[2], m_ClearColor[3]);
|
||||
|
||||
Prism::UniformBufferDeclaration<sizeof(mat4), 1> quadShaderUB;
|
||||
quadShaderUB.Push("u_InverseVP", inverse(viewProjection));
|
||||
m_QuadShader->UploadUniformBuffer(quadShaderUB);
|
||||
|
||||
m_QuadShader->Bind();
|
||||
m_QuadShader->SetMat4("u_InverseVP", inverse(viewProjection));
|
||||
m_EnvironmentCubeMap->Bind(0);
|
||||
@ -224,72 +227,72 @@ void DemoLayer::OnUpdate(const Prism::TimeStep deltaTime)
|
||||
Renderer::DrawIndexed(m_IndexBuffer->GetCount(), false);
|
||||
|
||||
|
||||
m_PBRMaterial->Set("u_AlbedoColor", m_AlbedoInput.Color);
|
||||
m_PBRMaterial->Set("u_Metalness", m_MetalnessInput.Value);
|
||||
m_PBRMaterial->Set("u_Roughness", m_RoughnessInput.Value);
|
||||
m_PBRMaterial->Set("u_ViewProjectionMatrix", viewProjection);
|
||||
m_PBRMaterial->Set("u_ModelMatrix", scale(mat4(1.0f), vec3(m_MeshScale)));
|
||||
m_PBRMaterial->Set("lights", m_Light);
|
||||
m_PBRMaterial->Set("u_CameraPosition", m_Camera.GetPosition());
|
||||
m_PBRMaterial->Set("u_RadiancePrefilter", m_RadiancePrefilter ? 1.0f : 0.0f);
|
||||
m_PBRMaterial->Set("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f);
|
||||
m_PBRMaterial->Set("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f);
|
||||
m_PBRMaterial->Set("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f);
|
||||
m_PBRMaterial->Set("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f);
|
||||
m_PBRMaterial->Set("u_EnvMapRotation", m_EnvMapRotation);
|
||||
m_MeshMaterial->Set("u_AlbedoColor", m_AlbedoInput.Color);
|
||||
m_MeshMaterial->Set("u_Metalness", m_MetalnessInput.Value);
|
||||
m_MeshMaterial->Set("u_Roughness", m_RoughnessInput.Value);
|
||||
m_MeshMaterial->Set("u_ViewProjectionMatrix", viewProjection);
|
||||
m_MeshMaterial->Set("u_ModelMatrix", scale(mat4(1.0f), vec3(m_MeshScale)));
|
||||
m_MeshMaterial->Set("lights", m_Light);
|
||||
m_MeshMaterial->Set("u_CameraPosition", m_Camera.GetPosition());
|
||||
m_MeshMaterial->Set("u_RadiancePrefilter", m_RadiancePrefilter ? 1.0f : 0.0f);
|
||||
m_MeshMaterial->Set("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f);
|
||||
m_MeshMaterial->Set("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f);
|
||||
m_MeshMaterial->Set("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f);
|
||||
m_MeshMaterial->Set("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f);
|
||||
m_MeshMaterial->Set("u_EnvMapRotation", m_EnvMapRotation);
|
||||
|
||||
m_PBRMaterial->Set("u_EnvRadianceTex", m_EnvironmentCubeMap);
|
||||
m_PBRMaterial->Set("u_EnvIrradianceTex", m_EnvironmentIrradiance);
|
||||
m_PBRMaterial->Set("u_BRDFLUTTexture", m_BRDFLUT);
|
||||
/*
|
||||
Prism::UniformBufferDeclaration<sizeof(mat4) * 2 + sizeof(vec3) * 4 + sizeof(float) * 8, 14> simplePbrShaderUB;
|
||||
simplePbrShaderUB.Push("u_ViewProjectionMatrix", viewProjection);
|
||||
simplePbrShaderUB.Push("u_ModelMatrix", mat4(1.0f));
|
||||
simplePbrShaderUB.Push("u_AlbedoColor", m_AlbedoInput.Color);
|
||||
simplePbrShaderUB.Push("u_Metalness", m_MetalnessInput.Value);
|
||||
simplePbrShaderUB.Push("u_Roughness", m_RoughnessInput.Value);
|
||||
simplePbrShaderUB.Push("lights.Direction", m_Light.Direction);
|
||||
simplePbrShaderUB.Push("lights.Radiance", m_Light.Radiance * m_LightMultiplier);
|
||||
simplePbrShaderUB.Push("u_CameraPosition", m_Camera.GetPosition());
|
||||
simplePbrShaderUB.Push("u_RadiancePrefilter", m_RadiancePrefilter ? 1.0f : 0.0f);
|
||||
simplePbrShaderUB.Push("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f);
|
||||
simplePbrShaderUB.Push("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f);
|
||||
simplePbrShaderUB.Push("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f);
|
||||
simplePbrShaderUB.Push("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f);
|
||||
simplePbrShaderUB.Push("u_EnvMapRotation", m_EnvMapRotation);
|
||||
m_SimplePBRShader->UploadUniformBuffer(simplePbrShaderUB);
|
||||
m_MeshMaterial->Set("u_EnvRadianceTex", m_EnvironmentCubeMap);
|
||||
m_MeshMaterial->Set("u_EnvIrradianceTex", m_EnvironmentIrradiance);
|
||||
m_MeshMaterial->Set("u_BRDFLUTTexture", m_BRDFLUT);
|
||||
|
||||
m_SphereMesh->GetMaterial()->Set("u_AlbedoColor", m_AlbedoInput.Color);
|
||||
m_SphereMesh->GetMaterial()->Set("u_Metalness", m_MetalnessInput.Value);
|
||||
m_SphereMesh->GetMaterial()->Set("u_Roughness", m_RoughnessInput.Value);
|
||||
m_SphereMesh->GetMaterial()->Set("u_ViewProjectionMatrix", viewProjection);
|
||||
m_SphereMesh->GetMaterial()->Set("u_ModelMatrix", scale(mat4(1.0f), vec3(m_MeshScale)));
|
||||
m_SphereMesh->GetMaterial()->Set("lights", m_Light);
|
||||
m_SphereMesh->GetMaterial()->Set("u_CameraPosition", m_Camera.GetPosition());
|
||||
m_SphereMesh->GetMaterial()->Set("u_RadiancePrefilter", m_RadiancePrefilter ? 1.0f : 0.0f);
|
||||
m_SphereMesh->GetMaterial()->Set("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f);
|
||||
m_SphereMesh->GetMaterial()->Set("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f);
|
||||
m_SphereMesh->GetMaterial()->Set("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f);
|
||||
m_SphereMesh->GetMaterial()->Set("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f);
|
||||
m_SphereMesh->GetMaterial()->Set("u_EnvMapRotation", m_EnvMapRotation);
|
||||
m_SphereMesh->GetMaterial()->Set("u_EnvRadianceTex", m_EnvironmentCubeMap);
|
||||
m_SphereMesh->GetMaterial()->Set("u_EnvIrradianceTex", m_EnvironmentIrradiance);
|
||||
m_SphereMesh->GetMaterial()->Set("u_BRDFLUTTexture", m_BRDFLUT);
|
||||
|
||||
m_EnvironmentCubeMap->Bind(10);
|
||||
m_EnvironmentIrradiance->Bind(11);
|
||||
m_BRDFLUT->Bind(15);
|
||||
m_SimplePBRShader->Bind();
|
||||
*/
|
||||
|
||||
|
||||
if (m_AlbedoInput.TextureMap)
|
||||
m_PBRMaterial->Set("u_AlbedoTexture", m_AlbedoInput.TextureMap);
|
||||
m_MeshMaterial->Set("u_AlbedoTexture", m_AlbedoInput.TextureMap);
|
||||
if (m_NormalInput.TextureMap)
|
||||
m_PBRMaterial->Set("u_NormalTexture", m_NormalInput.TextureMap);
|
||||
m_MeshMaterial->Set("u_NormalTexture", m_NormalInput.TextureMap);
|
||||
if (m_MetalnessInput.TextureMap)
|
||||
m_PBRMaterial->Set("u_MetalnessTexture", m_MetalnessInput.TextureMap);
|
||||
m_MeshMaterial->Set("u_MetalnessTexture", m_MetalnessInput.TextureMap);
|
||||
if (m_RoughnessInput.TextureMap)
|
||||
m_PBRMaterial->Set("u_RoughnessTexture", m_RoughnessInput.TextureMap);
|
||||
m_MeshMaterial->Set("u_RoughnessTexture", m_RoughnessInput.TextureMap);
|
||||
|
||||
if (m_Scene == Scene::Spheres)
|
||||
{
|
||||
// Metals
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
|
||||
m_SphereMesh->Render(deltaTime, glm::mat4(1.0f), m_MetalSphereMaterialInstances[i]);
|
||||
/*
|
||||
m_MetalSphereMaterialInstances[i]->Bind();
|
||||
m_SphereMesh->Render(deltaTime, m_SimplePBRShader.get());
|
||||
*/
|
||||
}
|
||||
|
||||
// Dielectrics
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
m_SphereMesh->Render(deltaTime, glm::mat4(1.0f), m_DielectricSphereMaterialInstances[i]);
|
||||
/*
|
||||
m_DielectricSphereMaterialInstances[i]->Bind();
|
||||
m_SphereMesh->Render(deltaTime, m_SimplePBRShader.get());
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
@ -297,16 +300,13 @@ void DemoLayer::OnUpdate(const Prism::TimeStep deltaTime)
|
||||
{
|
||||
if (m_Mesh)
|
||||
{
|
||||
m_PBRMaterial->Bind();
|
||||
m_Mesh->Render(deltaTime, m_SimplePBRShader.get());
|
||||
m_Mesh->Render(deltaTime, scale(mat4(1.0f), vec3(m_MeshScale)), m_MeshMaterial);
|
||||
}
|
||||
}
|
||||
|
||||
m_GridShader->Bind();
|
||||
m_GridShader->SetMat4("u_MVP", viewProjection * glm::scale(glm::mat4(1.0f), glm::vec3(16.0f)));
|
||||
m_GridShader->SetFloat("u_Scale", m_GridScale);
|
||||
m_GridShader->SetFloat("u_Res", m_GridSize);
|
||||
m_PlaneMesh->Render(deltaTime, m_GridShader.get());
|
||||
m_GridMaterial->Set("u_MVP", viewProjection * glm::scale(glm::mat4(1.0f), glm::vec3(16.0f)));
|
||||
m_PlaneMesh->Render(deltaTime, m_GridMaterial);
|
||||
|
||||
m_Framebuffer->Unbind();
|
||||
|
||||
m_FinalPresentBuffer->Bind();
|
||||
@ -436,206 +436,216 @@ void DemoLayer::OnImGuiRender()
|
||||
|
||||
#endif
|
||||
|
||||
// Editor Panel ------------------------------------------------------------------------------
|
||||
ImGui::Begin("Model");
|
||||
ImGui::RadioButton("Spheres", (int*)&m_Scene, (int)Scene::Spheres);
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Model", (int*)&m_Scene, (int)Scene::Model);
|
||||
// Editor Panel ------------------------------------------------------------------------------
|
||||
ImGui::Begin("Model");
|
||||
ImGui::RadioButton("Spheres", (int*)&m_Scene, (int)Scene::Spheres);
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Model", (int*)&m_Scene, (int)Scene::Model);
|
||||
|
||||
ImGui::Begin("Environment");
|
||||
ImGui::Begin("Environment");
|
||||
|
||||
ImGui::Columns(2);
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Columns(2);
|
||||
ImGui::AlignTextToFramePadding();
|
||||
|
||||
Property("Light Direction", m_Light.Direction);
|
||||
Property("Light Radiance", m_Light.Radiance, PropertyFlag::ColorProperty);
|
||||
Property("Light Multiplier", m_LightMultiplier, 0.0f, 5.0f);
|
||||
Property("Exposure", m_Exposure, 0.0f, 5.0f);
|
||||
Property("Light Direction", m_Light.Direction);
|
||||
Property("Light Radiance", m_Light.Radiance, PropertyFlag::ColorProperty);
|
||||
Property("Light Multiplier", m_LightMultiplier, 0.0f, 5.0f);
|
||||
Property("Exposure", m_Exposure, 0.0f, 5.0f);
|
||||
|
||||
Property("Radiance Prefiltering", m_RadiancePrefilter);
|
||||
Property("Env Map Rotation", m_EnvMapRotation, -360.0f, 360.0f);
|
||||
Property("Radiance Prefiltering", m_RadiancePrefilter);
|
||||
Property("Env Map Rotation", m_EnvMapRotation, -360.0f, 360.0f);
|
||||
|
||||
ImGui::Columns(1);
|
||||
ImGui::Columns(1);
|
||||
|
||||
ImGui::End();
|
||||
ImGui::End();
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Separator();
|
||||
{
|
||||
ImGui::Text("Mesh");
|
||||
std::string fullpath = m_Mesh ? m_Mesh->GetFilePath() : "None";
|
||||
size_t found = fullpath.find_last_of("/\\");
|
||||
std::string path = found != std::string::npos ? fullpath.substr(found + 1) : fullpath;
|
||||
ImGui::Text(path.c_str()); ImGui::SameLine();
|
||||
if (ImGui::Button("...##Mesh"))
|
||||
{
|
||||
ImGui::Text("Mesh");
|
||||
std::string fullpath = m_Mesh ? m_Mesh->GetFilePath() : "None";
|
||||
size_t found = fullpath.find_last_of("/\\");
|
||||
std::string path = found != std::string::npos ? fullpath.substr(found + 1) : fullpath;
|
||||
ImGui::Text(path.c_str()); ImGui::SameLine();
|
||||
if (ImGui::Button("...##Mesh"))
|
||||
{
|
||||
std::string filename = Prism::Application::Get().OpenFile("");
|
||||
if (filename != "")
|
||||
m_Mesh.reset(new Prism::Mesh(filename));
|
||||
}
|
||||
std::string filename = Prism::Application::Get().OpenFile("");
|
||||
if (filename != "")
|
||||
m_Mesh.reset(new Prism::Mesh(filename));
|
||||
}
|
||||
ImGui::Separator();
|
||||
}
|
||||
ImGui::Separator();
|
||||
|
||||
// Textures ------------------------------------------------------------------------------
|
||||
// Textures ------------------------------------------------------------------------------
|
||||
{
|
||||
// Albedo
|
||||
if (ImGui::CollapsingHeader("Albedo", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
// Albedo
|
||||
if (ImGui::CollapsingHeader("Albedo", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
|
||||
ImGui::Image((ImTextureRef)(m_AlbedoInput.TextureMap ? m_AlbedoInput.TextureMap->GetRendererID() : m_CheckerboardTex->GetRendererID()), ImVec2(64, 64));
|
||||
ImGui::PopStyleVar();
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
|
||||
ImGui::Image((ImTextureRef)(m_AlbedoInput.TextureMap ? m_AlbedoInput.TextureMap->GetRendererID() : m_CheckerboardTex->GetRendererID()), ImVec2(64, 64));
|
||||
ImGui::PopStyleVar();
|
||||
if (ImGui::IsItemHovered())
|
||||
if (m_AlbedoInput.TextureMap)
|
||||
{
|
||||
if (m_AlbedoInput.TextureMap)
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
||||
ImGui::TextUnformatted(m_AlbedoInput.TextureMap->GetPath().c_str());
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::Image((ImTextureRef)m_AlbedoInput.TextureMap->GetRendererID(), ImVec2(384, 384));
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
if (ImGui::IsItemClicked())
|
||||
{
|
||||
std::string filename = Prism::Application::Get().OpenFile("");
|
||||
if (filename != "")
|
||||
m_AlbedoInput.TextureMap.reset(Prism::Texture2D::Create(filename, m_AlbedoInput.SRGB));
|
||||
}
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
||||
ImGui::TextUnformatted(m_AlbedoInput.TextureMap->GetPath().c_str());
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::Image((ImTextureRef)m_AlbedoInput.TextureMap->GetRendererID(), ImVec2(384, 384));
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::BeginGroup();
|
||||
ImGui::Checkbox("Use##AlbedoMap", &m_AlbedoInput.UseTexture);
|
||||
if (ImGui::Checkbox("sRGB##AlbedoMap", &m_AlbedoInput.SRGB))
|
||||
if (ImGui::IsItemClicked())
|
||||
{
|
||||
if (m_AlbedoInput.TextureMap)
|
||||
m_AlbedoInput.TextureMap.reset(Prism::Texture2D::Create(m_AlbedoInput.TextureMap->GetPath(), m_AlbedoInput.SRGB));
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
ImGui::SameLine();
|
||||
ImGui::ColorEdit3("Color##Albedo", glm::value_ptr(m_AlbedoInput.Color), ImGuiColorEditFlags_NoInputs);
|
||||
}
|
||||
}
|
||||
{
|
||||
// Normals
|
||||
if (ImGui::CollapsingHeader("Normals", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
|
||||
ImGui::Image((ImTextureRef)(m_NormalInput.TextureMap ? m_NormalInput.TextureMap->GetRendererID() : m_CheckerboardTex->GetRendererID()), ImVec2(64, 64));
|
||||
ImGui::PopStyleVar();
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
if (m_NormalInput.TextureMap)
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
||||
ImGui::TextUnformatted(m_NormalInput.TextureMap->GetPath().c_str());
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::Image((ImTextureRef)m_NormalInput.TextureMap->GetRendererID(), ImVec2(384, 384));
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
if (ImGui::IsItemClicked())
|
||||
{
|
||||
std::string filename = Prism::Application::Get().OpenFile("");
|
||||
if (filename != "")
|
||||
m_NormalInput.TextureMap.reset(Prism::Texture2D::Create(filename));
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("Use##NormalMap", &m_NormalInput.UseTexture);
|
||||
}
|
||||
}
|
||||
{
|
||||
// Metalness
|
||||
if (ImGui::CollapsingHeader("Metalness", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
|
||||
ImGui::Image((ImTextureRef)(m_MetalnessInput.TextureMap ? m_MetalnessInput.TextureMap->GetRendererID() : m_CheckerboardTex->GetRendererID()), ImVec2(64, 64));
|
||||
ImGui::PopStyleVar();
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
if (m_MetalnessInput.TextureMap)
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
||||
ImGui::TextUnformatted(m_MetalnessInput.TextureMap->GetPath().c_str());
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::Image((ImTextureRef)m_MetalnessInput.TextureMap->GetRendererID(), ImVec2(384, 384));
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
if (ImGui::IsItemClicked())
|
||||
{
|
||||
std::string filename = Prism::Application::Get().OpenFile("");
|
||||
if (filename != "")
|
||||
m_MetalnessInput.TextureMap.reset(Prism::Texture2D::Create(filename));
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("Use##MetalnessMap", &m_MetalnessInput.UseTexture);
|
||||
ImGui::SameLine();
|
||||
ImGui::SliderFloat("Value##MetalnessInput", &m_MetalnessInput.Value, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
{
|
||||
// Roughness
|
||||
if (ImGui::CollapsingHeader("Roughness", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
|
||||
ImGui::Image((ImTextureRef)(m_RoughnessInput.TextureMap ? m_RoughnessInput.TextureMap->GetRendererID() : m_CheckerboardTex->GetRendererID()), ImVec2(64, 64));
|
||||
ImGui::PopStyleVar();
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
if (m_RoughnessInput.TextureMap)
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
||||
ImGui::TextUnformatted(m_RoughnessInput.TextureMap->GetPath().c_str());
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::Image((ImTextureRef)m_RoughnessInput.TextureMap->GetRendererID(), ImVec2(384, 384));
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
if (ImGui::IsItemClicked())
|
||||
{
|
||||
std::string filename = Prism::Application::Get().OpenFile("");
|
||||
if (filename != "")
|
||||
m_RoughnessInput.TextureMap.reset(Prism::Texture2D::Create(filename));
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("Use##RoughnessMap", &m_RoughnessInput.UseTexture);
|
||||
ImGui::SameLine();
|
||||
ImGui::SliderFloat("Value##RoughnessInput", &m_RoughnessInput.Value, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("Shaders"))
|
||||
{
|
||||
auto& shaders = Prism::Shader::GetAllShaders();
|
||||
for (auto& shader : shaders)
|
||||
{
|
||||
if (ImGui::TreeNode(shader->GetName().c_str()))
|
||||
{
|
||||
std::string buttonName = "Reload##" + shader->GetName();
|
||||
if (ImGui::Button(buttonName.c_str()))
|
||||
shader->Reload();
|
||||
ImGui::TreePop();
|
||||
std::string filename = Prism::Application::Get().OpenFile("");
|
||||
if (filename != "")
|
||||
m_AlbedoInput.TextureMap.reset(Prism::Texture2D::Create(filename, m_AlbedoInput.SRGB));
|
||||
}
|
||||
}
|
||||
ImGui::TreePop();
|
||||
ImGui::SameLine();
|
||||
ImGui::BeginGroup();
|
||||
ImGui::Checkbox("Use##AlbedoMap", &m_AlbedoInput.UseTexture);
|
||||
if (ImGui::Checkbox("sRGB##AlbedoMap", &m_AlbedoInput.SRGB))
|
||||
{
|
||||
if (m_AlbedoInput.TextureMap)
|
||||
m_AlbedoInput.TextureMap.reset(Prism::Texture2D::Create(m_AlbedoInput.TextureMap->GetPath(), m_AlbedoInput.SRGB));
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
ImGui::SameLine();
|
||||
ImGui::ColorEdit3("Color##Albedo", glm::value_ptr(m_AlbedoInput.Color), ImGuiColorEditFlags_NoInputs);
|
||||
}
|
||||
}
|
||||
{
|
||||
// Normals
|
||||
if (ImGui::CollapsingHeader("Normals", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
|
||||
ImGui::Image((ImTextureRef)(m_NormalInput.TextureMap ? m_NormalInput.TextureMap->GetRendererID() : m_CheckerboardTex->GetRendererID()), ImVec2(64, 64));
|
||||
ImGui::PopStyleVar();
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
if (m_NormalInput.TextureMap)
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
||||
ImGui::TextUnformatted(m_NormalInput.TextureMap->GetPath().c_str());
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::Image((ImTextureRef)m_NormalInput.TextureMap->GetRendererID(), ImVec2(384, 384));
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
if (ImGui::IsItemClicked())
|
||||
{
|
||||
std::string filename = Prism::Application::Get().OpenFile("");
|
||||
if (filename != "")
|
||||
m_NormalInput.TextureMap.reset(Prism::Texture2D::Create(filename));
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("Use##NormalMap", &m_NormalInput.UseTexture);
|
||||
}
|
||||
}
|
||||
{
|
||||
// Metalness
|
||||
if (ImGui::CollapsingHeader("Metalness", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
|
||||
ImGui::Image((ImTextureRef)(m_MetalnessInput.TextureMap ? m_MetalnessInput.TextureMap->GetRendererID() : m_CheckerboardTex->GetRendererID()), ImVec2(64, 64));
|
||||
ImGui::PopStyleVar();
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
if (m_MetalnessInput.TextureMap)
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
||||
ImGui::TextUnformatted(m_MetalnessInput.TextureMap->GetPath().c_str());
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::Image((ImTextureRef)m_MetalnessInput.TextureMap->GetRendererID(), ImVec2(384, 384));
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
if (ImGui::IsItemClicked())
|
||||
{
|
||||
std::string filename = Prism::Application::Get().OpenFile("");
|
||||
if (filename != "")
|
||||
m_MetalnessInput.TextureMap.reset(Prism::Texture2D::Create(filename));
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("Use##MetalnessMap", &m_MetalnessInput.UseTexture);
|
||||
ImGui::SameLine();
|
||||
ImGui::SliderFloat("Value##MetalnessInput", &m_MetalnessInput.Value, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
{
|
||||
// Roughness
|
||||
if (ImGui::CollapsingHeader("Roughness", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
|
||||
ImGui::Image((ImTextureRef)(m_RoughnessInput.TextureMap ? m_RoughnessInput.TextureMap->GetRendererID() : m_CheckerboardTex->GetRendererID()), ImVec2(64, 64));
|
||||
ImGui::PopStyleVar();
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
if (m_RoughnessInput.TextureMap)
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
||||
ImGui::TextUnformatted(m_RoughnessInput.TextureMap->GetPath().c_str());
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::Image((ImTextureRef)m_RoughnessInput.TextureMap->GetRendererID(), ImVec2(384, 384));
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
if (ImGui::IsItemClicked())
|
||||
{
|
||||
std::string filename = Prism::Application::Get().OpenFile("");
|
||||
if (filename != "")
|
||||
m_RoughnessInput.TextureMap.reset(Prism::Texture2D::Create(filename));
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("Use##RoughnessMap", &m_RoughnessInput.UseTexture);
|
||||
ImGui::SameLine();
|
||||
ImGui::SliderFloat("Value##RoughnessInput", &m_RoughnessInput.Value, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
if (ImGui::TreeNode("Shaders"))
|
||||
{
|
||||
auto& shaders = Prism::Shader::GetAllShaders();
|
||||
for (auto& shader : shaders)
|
||||
{
|
||||
if (ImGui::TreeNode(shader->GetName().c_str()))
|
||||
{
|
||||
std::string buttonName = "Reload##" + shader->GetName();
|
||||
if (ImGui::Button(buttonName.c_str()))
|
||||
shader->Reload();
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
|
||||
ImGui::Begin("Viewport");
|
||||
auto viewportSize = ImGui::GetContentRegionAvail();
|
||||
m_Framebuffer->Resize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
||||
m_FinalPresentBuffer->Resize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
||||
m_Camera.SetProjectionMatrix(glm::perspectiveFov(glm::radians(45.0f), viewportSize.x, viewportSize.y, 0.1f, 10000.0f));
|
||||
ImGui::Image((ImTextureRef)m_FinalPresentBuffer->GetColorAttachmentRendererID(), viewportSize, { 0, 1 }, { 1, 0 });
|
||||
// ImGui::Image((void*)m_Framebuffer->GetColorAttachmentRendererID(), viewportSize, { 0, 1 }, { 1, 0 });
|
||||
ImGui::End();
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::End();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
|
||||
ImGui::Begin("Viewport");
|
||||
auto viewportSize = ImGui::GetContentRegionAvail();
|
||||
m_Framebuffer->Resize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
||||
m_FinalPresentBuffer->Resize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
||||
m_Camera.SetProjectionMatrix(glm::perspectiveFov(glm::radians(45.0f), viewportSize.x, viewportSize.y, 0.1f, 10000.0f));
|
||||
ImGui::Image((ImTextureRef)m_FinalPresentBuffer->GetColorAttachmentRendererID(), viewportSize, { 0, 1 }, { 1, 0 });
|
||||
ImGui::End();
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
ImGui::Begin("Log");
|
||||
const auto& cameraPos = m_Camera.GetPosition();
|
||||
ImGui::Text("cameraPos: (%.2f, %.2f, %.2f)", cameraPos.x, cameraPos.y, cameraPos.z);
|
||||
|
||||
const auto& Direct = m_Camera.GetForwardDirection();
|
||||
ImGui::Text("forward Vec: (%.2f, %.2f, %.2f)", Direct.x, Direct.y, Direct.z);
|
||||
|
||||
const auto& distance = m_Camera.GetDistance();
|
||||
ImGui::Text("distance: %.3f", distance);
|
||||
ImGui::End();
|
||||
|
||||
if (m_Mesh)
|
||||
m_Mesh->OnImGuiRender();
|
||||
|
||||
@ -26,15 +26,16 @@ public:
|
||||
private:
|
||||
float m_ClearColor[4];
|
||||
|
||||
Prism::Ref<Prism::Shader> m_SimplePBRShader;
|
||||
Prism::Scope<Prism::Shader> m_QuadShader;
|
||||
Prism::Scope<Prism::Shader> m_HDRShader;
|
||||
Prism::Scope<Prism::Shader> m_GridShader;
|
||||
Prism::Scope<Prism::Mesh> m_Mesh;
|
||||
Prism::Scope<Prism::Mesh> m_SphereMesh, m_PlaneMesh;
|
||||
Prism::Ref<Prism::Shader> m_QuadShader;
|
||||
Prism::Ref<Prism::Shader> m_HDRShader;
|
||||
Prism::Ref<Prism::Shader> m_GridShader;
|
||||
Prism::Ref<Prism::Mesh> m_Mesh;
|
||||
Prism::Ref<Prism::Mesh> m_SphereMesh, m_PlaneMesh;
|
||||
Prism::Ref<Prism::Texture2D> m_BRDFLUT;
|
||||
|
||||
Prism::Ref<Prism::Material> m_PBRMaterial;
|
||||
Prism::Ref<Prism::MaterialInstance> m_MeshMaterial;
|
||||
Prism::Ref<Prism::MaterialInstance> m_GridMaterial;
|
||||
|
||||
std::vector<Prism::Ref<Prism::MaterialInstance>> m_MetalSphereMaterialInstances;
|
||||
std::vector<Prism::Ref<Prism::MaterialInstance>> m_DielectricSphereMaterialInstances;
|
||||
|
||||
|
||||
@ -174,9 +174,9 @@ void TestLayer::OnAttach()
|
||||
|
||||
m_SkyBoxTextureCube.reset(Prism::TextureCube::Create("assets/textures/environments/Arches_E_PineTree_Radiance.tga"));
|
||||
|
||||
m_SkyboxShader.reset(Prism::Shader::Create("assets/shaders/quad.glsl"));
|
||||
m_Shader.reset(Prism::Shader::Create("assets/shaders/demo.glsl"));
|
||||
m_HDRShader.reset(Prism::Shader::Create("assets/shaders/hdr.glsl"));
|
||||
m_SkyboxShader = Prism::Shader::Create("assets/shaders/quad.glsl");
|
||||
m_Shader = Prism::Shader::Create("assets/shaders/demo.glsl");
|
||||
m_HDRShader = Prism::Shader::Create("assets/shaders/hdr.glsl");
|
||||
|
||||
m_Mesh = std::make_unique<Prism::Mesh>("assets/meshes/cerberus.fbx");
|
||||
}
|
||||
@ -210,7 +210,7 @@ void TestLayer::OnUpdate(Prism::TimeStep deltaTime)
|
||||
|
||||
m_Shader->Bind();
|
||||
|
||||
m_Mesh->Render(deltaTime, m_Shader.get());
|
||||
// m_Mesh->Render(deltaTime, m_Shader);
|
||||
// m_VertexBuffer->Bind();
|
||||
// m_IndexBuffer->Bind();
|
||||
|
||||
|
||||
@ -28,17 +28,17 @@ private:
|
||||
glm::vec4 m_clearColor = glm::vec4(0.1f, 0.1f, 0.1f, 1.0f);
|
||||
glm::vec4 m_TriangleColor = glm::vec4(1.0f);
|
||||
|
||||
std::unique_ptr<Prism::FrameBuffer> m_FrameBuffer, m_FinalPresentBuffer;
|
||||
std::unique_ptr<Prism::VertexBuffer> m_VertexBuffer;
|
||||
std::unique_ptr<Prism::IndexBuffer> m_IndexBuffer;
|
||||
Prism::Ref<Prism::FrameBuffer> m_FrameBuffer, m_FinalPresentBuffer;
|
||||
Prism::Ref<Prism::VertexBuffer> m_VertexBuffer;
|
||||
Prism::Ref<Prism::IndexBuffer> m_IndexBuffer;
|
||||
|
||||
|
||||
std::unique_ptr<Prism::TextureCube> m_SkyBoxTextureCube;
|
||||
Prism::Ref<Prism::TextureCube> m_SkyBoxTextureCube;
|
||||
|
||||
std::unique_ptr<Prism::Shader> m_SkyboxShader;
|
||||
std::unique_ptr<Prism::Shader> m_Shader;
|
||||
std::unique_ptr<Prism::Shader> m_HDRShader;
|
||||
std::unique_ptr<Prism::Mesh> m_Mesh;
|
||||
Prism::Ref<Prism::Shader> m_SkyboxShader;
|
||||
Prism::Ref<Prism::Shader> m_Shader;
|
||||
Prism::Ref<Prism::Shader> m_HDRShader;
|
||||
Prism::Ref<Prism::Mesh> m_Mesh;
|
||||
|
||||
Prism::Camera m_Camera;
|
||||
|
||||
|
||||
@ -18,8 +18,8 @@ public:
|
||||
|
||||
virtual void OnInit() override
|
||||
{
|
||||
PushLayer(new TestLayer());
|
||||
// PushLayer(new DemoLayer());
|
||||
// PushLayer(new TestLayer());
|
||||
PushLayer(new DemoLayer());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -23,7 +23,6 @@ void main()
|
||||
|
||||
layout(location = 0) out vec4 color;
|
||||
|
||||
uniform sampler2D u_Texture;
|
||||
uniform float u_Scale;
|
||||
uniform float u_Res;
|
||||
|
||||
|
||||
321
Sandbox/assets/shaders/simplepbr_Static.glsl
Normal file
321
Sandbox/assets/shaders/simplepbr_Static.glsl
Normal file
@ -0,0 +1,321 @@
|
||||
// -----------------------------
|
||||
// -- Hazel Engine PBR shader --
|
||||
// -----------------------------
|
||||
// Note: this shader is still very much in progress. There are likely many bugs and future additions that will go in.
|
||||
// Currently heavily updated.
|
||||
//
|
||||
// References upon which this is based:
|
||||
// - Unreal Engine 4 PBR notes (https://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf)
|
||||
// - Frostbite's SIGGRAPH 2014 paper (https://seblagarde.wordpress.com/2015/07/14/siggraph-2014-moving-frostbite-to-physically-based-rendering/)
|
||||
// - Michał Siejak's PBR project (https://github.com/Nadrin)
|
||||
// - My implementation from years ago in the Sparky engine (https://github.com/TheCherno/Sparky)
|
||||
#type vertex
|
||||
#version 430 core
|
||||
|
||||
layout(location = 0) in vec3 a_Position;
|
||||
layout(location = 1) in vec3 a_Normal;
|
||||
layout(location = 2) in vec3 a_Tangent;
|
||||
layout(location = 3) in vec3 a_Binormal;
|
||||
layout(location = 4) in vec2 a_TexCoord;
|
||||
|
||||
uniform mat4 u_ViewProjectionMatrix;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
|
||||
out VertexOutput
|
||||
{
|
||||
vec3 WorldPosition;
|
||||
vec3 Normal;
|
||||
vec2 TexCoord;
|
||||
mat3 WorldNormals;
|
||||
vec3 Binormal;
|
||||
} vs_Output;
|
||||
|
||||
void main()
|
||||
{
|
||||
vs_Output.WorldPosition = vec3(u_ModelMatrix * vec4(a_Position, 1.0));
|
||||
vs_Output.Normal = a_Normal;
|
||||
vs_Output.TexCoord = vec2(a_TexCoord.x, 1.0 - a_TexCoord.y);
|
||||
vs_Output.WorldNormals = mat3(u_ModelMatrix) * mat3(a_Tangent, a_Binormal, a_Normal);
|
||||
vs_Output.Binormal = a_Binormal;
|
||||
|
||||
gl_Position = u_ViewProjectionMatrix * u_ModelMatrix * vec4(a_Position, 1.0);
|
||||
}
|
||||
|
||||
#type fragment
|
||||
#version 430 core
|
||||
|
||||
const float PI = 3.141592;
|
||||
const float Epsilon = 0.00001;
|
||||
|
||||
const int LightCount = 1;
|
||||
|
||||
// Constant normal incidence Fresnel factor for all dielectrics.
|
||||
const vec3 Fdielectric = vec3(0.04);
|
||||
|
||||
struct Light {
|
||||
vec3 Direction;
|
||||
vec3 Radiance;
|
||||
};
|
||||
|
||||
in VertexOutput
|
||||
{
|
||||
vec3 WorldPosition;
|
||||
vec3 Normal;
|
||||
vec2 TexCoord;
|
||||
mat3 WorldNormals;
|
||||
vec3 Binormal;
|
||||
} vs_Input;
|
||||
|
||||
layout(location = 0) out vec4 color;
|
||||
|
||||
uniform Light lights;
|
||||
uniform vec3 u_CameraPosition;
|
||||
|
||||
// PBR texture inputs
|
||||
uniform sampler2D u_AlbedoTexture;
|
||||
uniform sampler2D u_NormalTexture;
|
||||
uniform sampler2D u_MetalnessTexture;
|
||||
uniform sampler2D u_RoughnessTexture;
|
||||
|
||||
// Environment maps
|
||||
uniform samplerCube u_EnvRadianceTex;
|
||||
uniform samplerCube u_EnvIrradianceTex;
|
||||
|
||||
// BRDF LUT
|
||||
uniform sampler2D u_BRDFLUTTexture;
|
||||
|
||||
uniform vec3 u_AlbedoColor;
|
||||
uniform float u_Metalness;
|
||||
uniform float u_Roughness;
|
||||
|
||||
uniform float u_EnvMapRotation;
|
||||
|
||||
// Toggles
|
||||
uniform float u_RadiancePrefilter;
|
||||
uniform float u_AlbedoTexToggle;
|
||||
uniform float u_NormalTexToggle;
|
||||
uniform float u_MetalnessTexToggle;
|
||||
uniform float u_RoughnessTexToggle;
|
||||
|
||||
struct PBRParameters
|
||||
{
|
||||
vec3 Albedo;
|
||||
float Roughness;
|
||||
float Metalness;
|
||||
|
||||
vec3 Normal;
|
||||
vec3 View;
|
||||
float NdotV;
|
||||
};
|
||||
|
||||
PBRParameters m_Params;
|
||||
|
||||
// GGX/Towbridge-Reitz normal distribution function.
|
||||
// Uses Disney's reparametrization of alpha = roughness^2
|
||||
float ndfGGX(float cosLh, float roughness)
|
||||
{
|
||||
float alpha = roughness * roughness;
|
||||
float alphaSq = alpha * alpha;
|
||||
|
||||
float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0;
|
||||
return alphaSq / (PI * denom * denom);
|
||||
}
|
||||
|
||||
// Single term for separable Schlick-GGX below.
|
||||
float gaSchlickG1(float cosTheta, float k)
|
||||
{
|
||||
return cosTheta / (cosTheta * (1.0 - k) + k);
|
||||
}
|
||||
|
||||
// Schlick-GGX approximation of geometric attenuation function using Smith's method.
|
||||
float gaSchlickGGX(float cosLi, float NdotV, float roughness)
|
||||
{
|
||||
float r = roughness + 1.0;
|
||||
float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights.
|
||||
return gaSchlickG1(cosLi, k) * gaSchlickG1(NdotV, k);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Shlick's approximation of the Fresnel factor.
|
||||
vec3 fresnelSchlick(vec3 F0, float cosTheta)
|
||||
{
|
||||
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
||||
}
|
||||
|
||||
vec3 fresnelSchlickRoughness(vec3 F0, float cosTheta, float roughness)
|
||||
{
|
||||
return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------
|
||||
// The following code (from Unreal Engine 4's paper) shows how to filter the environment map
|
||||
// for different roughnesses. This is mean to be computed offline and stored in cube map mips,
|
||||
// so turning this on online will cause poor performance
|
||||
float RadicalInverse_VdC(uint bits)
|
||||
{
|
||||
bits = (bits << 16u) | (bits >> 16u);
|
||||
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
|
||||
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
|
||||
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
|
||||
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
|
||||
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
|
||||
}
|
||||
|
||||
vec2 Hammersley(uint i, uint N)
|
||||
{
|
||||
return vec2(float(i)/float(N), RadicalInverse_VdC(i));
|
||||
}
|
||||
|
||||
vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N)
|
||||
{
|
||||
float a = Roughness * Roughness;
|
||||
float Phi = 2 * PI * Xi.x;
|
||||
float CosTheta = sqrt( (1 - Xi.y) / ( 1 + (a*a - 1) * Xi.y ) );
|
||||
float SinTheta = sqrt( 1 - CosTheta * CosTheta );
|
||||
vec3 H;
|
||||
H.x = SinTheta * cos( Phi );
|
||||
H.y = SinTheta * sin( Phi );
|
||||
H.z = CosTheta;
|
||||
vec3 UpVector = abs(N.z) < 0.999 ? vec3(0,0,1) : vec3(1,0,0);
|
||||
vec3 TangentX = normalize( cross( UpVector, N ) );
|
||||
vec3 TangentY = cross( N, TangentX );
|
||||
// Tangent to world space
|
||||
return TangentX * H.x + TangentY * H.y + N * H.z;
|
||||
}
|
||||
|
||||
float TotalWeight = 0.0;
|
||||
|
||||
vec3 PrefilterEnvMap(float Roughness, vec3 R)
|
||||
{
|
||||
vec3 N = R;
|
||||
vec3 V = R;
|
||||
vec3 PrefilteredColor = vec3(0.0);
|
||||
int NumSamples = 1024;
|
||||
for(int i = 0; i < NumSamples; i++)
|
||||
{
|
||||
vec2 Xi = Hammersley(i, NumSamples);
|
||||
vec3 H = ImportanceSampleGGX(Xi, Roughness, N);
|
||||
vec3 L = 2 * dot(V, H) * H - V;
|
||||
float NoL = clamp(dot(N, L), 0.0, 1.0);
|
||||
if (NoL > 0)
|
||||
{
|
||||
PrefilteredColor += texture(u_EnvRadianceTex, L).rgb * NoL;
|
||||
TotalWeight += NoL;
|
||||
}
|
||||
}
|
||||
return PrefilteredColor / TotalWeight;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------
|
||||
|
||||
vec3 RotateVectorAboutY(float angle, vec3 vec)
|
||||
{
|
||||
angle = radians(angle);
|
||||
mat3x3 rotationMatrix ={vec3(cos(angle),0.0,sin(angle)),
|
||||
vec3(0.0,1.0,0.0),
|
||||
vec3(-sin(angle),0.0,cos(angle))};
|
||||
return rotationMatrix * vec;
|
||||
}
|
||||
|
||||
vec3 Lighting(vec3 F0)
|
||||
{
|
||||
vec3 result = vec3(0.0);
|
||||
for(int i = 0; i < LightCount; i++)
|
||||
{
|
||||
vec3 Li = -lights.Direction;
|
||||
vec3 Lradiance = lights.Radiance;
|
||||
vec3 Lh = normalize(Li + m_Params.View);
|
||||
|
||||
// Calculate angles between surface normal and various light vectors.
|
||||
float cosLi = max(0.0, dot(m_Params.Normal, Li));
|
||||
float cosLh = max(0.0, dot(m_Params.Normal, Lh));
|
||||
|
||||
vec3 F = fresnelSchlick(F0, max(0.0, dot(Lh, m_Params.View)));
|
||||
float D = ndfGGX(cosLh, m_Params.Roughness);
|
||||
float G = gaSchlickGGX(cosLi, m_Params.NdotV, m_Params.Roughness);
|
||||
|
||||
vec3 kd = (1.0 - F) * (1.0 - m_Params.Metalness);
|
||||
vec3 diffuseBRDF = kd * m_Params.Albedo;
|
||||
|
||||
// Cook-Torrance
|
||||
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * m_Params.NdotV);
|
||||
|
||||
result += (diffuseBRDF + specularBRDF) * Lradiance * cosLi;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
vec3 IBL(vec3 F0, vec3 Lr)
|
||||
{
|
||||
vec3 irradiance = texture(u_EnvIrradianceTex, m_Params.Normal).rgb;
|
||||
vec3 F = fresnelSchlickRoughness(F0, m_Params.NdotV, m_Params.Roughness);
|
||||
vec3 kd = (1.0 - F) * (1.0 - m_Params.Metalness);
|
||||
vec3 diffuseIBL = m_Params.Albedo * irradiance;
|
||||
|
||||
int u_EnvRadianceTexLevels = textureQueryLevels(u_EnvRadianceTex);
|
||||
float NoV = clamp(m_Params.NdotV, 0.0, 1.0);
|
||||
vec3 R = 2.0 * dot(m_Params.View, m_Params.Normal) * m_Params.Normal - m_Params.View;
|
||||
vec3 specularIrradiance = vec3(0.0);
|
||||
|
||||
if (u_RadiancePrefilter > 0.5)
|
||||
specularIrradiance = PrefilterEnvMap(m_Params.Roughness * m_Params.Roughness, R) * u_RadiancePrefilter;
|
||||
else
|
||||
specularIrradiance = textureLod(u_EnvRadianceTex, RotateVectorAboutY(u_EnvMapRotation, Lr), sqrt(m_Params.Roughness) * u_EnvRadianceTexLevels).rgb * (1.0 - u_RadiancePrefilter);
|
||||
|
||||
// Sample BRDF Lut, 1.0 - roughness for y-coord because texture was generated (in Sparky) for gloss model
|
||||
vec2 specularBRDF = texture(u_BRDFLUTTexture, vec2(m_Params.NdotV, 1.0 - m_Params.Roughness)).rg;
|
||||
vec3 specularIBL = specularIrradiance * (F * specularBRDF.x + specularBRDF.y);
|
||||
|
||||
return kd * diffuseIBL + specularIBL;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
// Standard PBR inputs
|
||||
m_Params.Albedo = u_AlbedoTexToggle > 0.5 ? texture(u_AlbedoTexture, vs_Input.TexCoord).rgb : u_AlbedoColor;
|
||||
m_Params.Metalness = u_MetalnessTexToggle > 0.5 ? texture(u_MetalnessTexture, vs_Input.TexCoord).r : u_Metalness;
|
||||
m_Params.Roughness = u_RoughnessTexToggle > 0.5 ? texture(u_RoughnessTexture, vs_Input.TexCoord).r : u_Roughness;
|
||||
m_Params.Roughness = max(m_Params.Roughness, 0.05); // Minimum roughness of 0.05 to keep specular highlight
|
||||
|
||||
// Normals (either from vertex or map)
|
||||
m_Params.Normal = normalize(vs_Input.Normal);
|
||||
if (u_NormalTexToggle > 0.5)
|
||||
{
|
||||
m_Params.Normal = normalize(2.0 * texture(u_NormalTexture, vs_Input.TexCoord).rgb - 1.0);
|
||||
m_Params.Normal = normalize(vs_Input.WorldNormals * m_Params.Normal);
|
||||
}
|
||||
|
||||
m_Params.View = normalize(u_CameraPosition - vs_Input.WorldPosition);
|
||||
m_Params.NdotV = max(dot(m_Params.Normal, m_Params.View), 0.0);
|
||||
|
||||
// Specular reflection vector
|
||||
vec3 Lr = 2.0 * m_Params.NdotV * m_Params.Normal - m_Params.View;
|
||||
|
||||
// Fresnel reflectance, metals use albedo
|
||||
vec3 F0 = mix(Fdielectric, m_Params.Albedo, m_Params.Metalness);
|
||||
|
||||
vec3 lightContribution = Lighting(F0);
|
||||
vec3 iblContribution = IBL(F0, Lr);
|
||||
|
||||
color = vec4(lightContribution + iblContribution, 1.0);
|
||||
}
|
||||
Reference in New Issue
Block a user