add vertexarray, move Sandbox::Demolayer code to EditorLayer
@ -1,658 +0,0 @@
|
||||
//
|
||||
// Created by sfd on 25-11-21.
|
||||
//
|
||||
|
||||
#include "DemoLayer.h"
|
||||
|
||||
#include "Prism/Renderer/Renderer.h"
|
||||
#include "Prism/Renderer/Shader.h"
|
||||
|
||||
|
||||
namespace {
|
||||
enum class PropertyFlag
|
||||
{
|
||||
None = 0, ColorProperty = 1
|
||||
};
|
||||
|
||||
void Property(const std::string& name, bool& value)
|
||||
{
|
||||
ImGui::Text(name.c_str());
|
||||
ImGui::NextColumn();
|
||||
ImGui::PushItemWidth(-1);
|
||||
|
||||
std::string id = "##" + name;
|
||||
ImGui::Checkbox(id.c_str(), &value);
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::NextColumn();
|
||||
}
|
||||
|
||||
void Property(const std::string& name, float& value, float min = -1.0f, float max = 1.0f, PropertyFlag flags = PropertyFlag::None)
|
||||
{
|
||||
ImGui::Text(name.c_str());
|
||||
ImGui::NextColumn();
|
||||
ImGui::PushItemWidth(-1);
|
||||
|
||||
std::string id = "##" + name;
|
||||
ImGui::SliderFloat(id.c_str(), &value, min, max);
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::NextColumn();
|
||||
}
|
||||
|
||||
|
||||
void Property(const std::string& name, glm::vec3& value, float min = -1.0f, float max = 1.0f, PropertyFlag flags = PropertyFlag::None)
|
||||
{
|
||||
ImGui::Text(name.c_str());
|
||||
ImGui::NextColumn();
|
||||
ImGui::PushItemWidth(-1);
|
||||
|
||||
std::string id = "##" + name;
|
||||
if ((int)flags & (int)PropertyFlag::ColorProperty)
|
||||
ImGui::ColorEdit3(id.c_str(), glm::value_ptr(value), ImGuiColorEditFlags_NoInputs);
|
||||
else
|
||||
ImGui::SliderFloat3(id.c_str(), glm::value_ptr(value), min, max);
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::NextColumn();
|
||||
}
|
||||
|
||||
void Property(const std::string& name, glm::vec3& value, PropertyFlag flags)
|
||||
{
|
||||
Property(name, value, -1.0f, 1.0f, flags);
|
||||
}
|
||||
|
||||
|
||||
void Property(const std::string& name, glm::vec4& value, float min = -1.0f, float max = 1.0f, PropertyFlag flags = PropertyFlag::None)
|
||||
{
|
||||
ImGui::Text(name.c_str());
|
||||
ImGui::NextColumn();
|
||||
ImGui::PushItemWidth(-1);
|
||||
|
||||
std::string id = "##" + name;
|
||||
if ((int)flags & (int)PropertyFlag::ColorProperty)
|
||||
ImGui::ColorEdit4(id.c_str(), glm::value_ptr(value), ImGuiColorEditFlags_NoInputs);
|
||||
else
|
||||
ImGui::SliderFloat4(id.c_str(), glm::value_ptr(value), min, max);
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::NextColumn();
|
||||
}
|
||||
|
||||
void Property(const std::string& name, glm::vec4& value, PropertyFlag flags)
|
||||
{
|
||||
Property(name, value, -1.0f, 1.0f, flags);
|
||||
}
|
||||
|
||||
|
||||
static void ImGuiShowHelpMarker(const char* desc)
|
||||
{
|
||||
ImGui::TextDisabled("(?)");
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
||||
ImGui::TextUnformatted(desc);
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DemoLayer::DemoLayer()
|
||||
: m_ClearColor{ 0.1f, 0.1f, 0.1f, 1.0f }, m_Scene(Scene::Model),
|
||||
m_Camera(glm::perspectiveFov(glm::radians(45.0f), 1280.0f, 720.0f, 0.1f, 10000.0f))
|
||||
{
|
||||
}
|
||||
|
||||
DemoLayer::~DemoLayer()
|
||||
{
|
||||
}
|
||||
|
||||
void DemoLayer::OnAttach()
|
||||
{
|
||||
|
||||
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"));
|
||||
|
||||
// Environment
|
||||
m_EnvironmentCubeMap.reset(Prism::TextureCube::Create("assets/textures/environments/Arches_E_PineTree_Radiance.tga"));
|
||||
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"));
|
||||
|
||||
|
||||
float x = -4.0f;
|
||||
float roughness = 0.0f;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
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)));
|
||||
x += 1.1f;
|
||||
roughness += 0.15f;
|
||||
m_MetalSphereMaterialInstances.push_back(mi);
|
||||
}
|
||||
|
||||
x = -4.0f;
|
||||
roughness = 0.0f;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
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)));
|
||||
x += 1.1f;
|
||||
roughness += 0.15f;
|
||||
m_DielectricSphereMaterialInstances.push_back(mi);
|
||||
}
|
||||
// Create Quad
|
||||
x = -1;
|
||||
float y = -1;
|
||||
float width = 2, height = 2;
|
||||
struct QuadVertex
|
||||
{
|
||||
glm::vec3 Position;
|
||||
glm::vec2 TexCoord;
|
||||
};
|
||||
|
||||
QuadVertex* data = new QuadVertex[4];
|
||||
|
||||
data[0].Position = glm::vec3(x, y, 0);
|
||||
data[0].TexCoord = glm::vec2(0, 0);
|
||||
|
||||
data[1].Position = glm::vec3(x + width, y, 0);
|
||||
data[1].TexCoord = glm::vec2(1, 0);
|
||||
|
||||
data[2].Position = glm::vec3(x + width, y + height, 0);
|
||||
data[2].TexCoord = glm::vec2(1, 1);
|
||||
|
||||
data[3].Position = glm::vec3(x, y + height, 0);
|
||||
data[3].TexCoord = glm::vec2(0, 1);
|
||||
|
||||
m_VertexBuffer.reset(Prism::VertexBuffer::Create());
|
||||
m_VertexBuffer->SetData(data, 4 * sizeof(QuadVertex));
|
||||
|
||||
uint32_t* indices = new uint32_t[6] { 0, 1, 2, 2, 3, 0, };
|
||||
m_IndexBuffer.reset(Prism::IndexBuffer::Create());
|
||||
m_IndexBuffer->SetData(indices, 6 * sizeof(uint32_t));
|
||||
|
||||
m_Light.Direction = { -0.5f, -0.5f, 1.0f };
|
||||
m_Light.Radiance = { 1.0f, 1.0f, 1.0f };
|
||||
}
|
||||
|
||||
void DemoLayer::OnDetach()
|
||||
{
|
||||
}
|
||||
|
||||
void DemoLayer::OnUpdate(const Prism::TimeStep deltaTime)
|
||||
{
|
||||
{
|
||||
// THINGS TO LOOK AT:
|
||||
// - BRDF LUT
|
||||
// - Cubemap mips and filtering
|
||||
// - Tonemapping and proper HDR pipeline
|
||||
using namespace Prism;
|
||||
using namespace glm;
|
||||
|
||||
m_Camera.Update(deltaTime);
|
||||
auto viewProjection = m_Camera.GetProjectionMatrix() * m_Camera.GetViewMatrix();
|
||||
|
||||
m_Framebuffer->Bind();
|
||||
Renderer::Clear(m_ClearColor[0], m_ClearColor[1], m_ClearColor[2], m_ClearColor[3]);
|
||||
|
||||
m_QuadShader->Bind();
|
||||
m_QuadShader->SetMat4("u_InverseVP", inverse(viewProjection));
|
||||
m_EnvironmentCubeMap->Bind(0);
|
||||
m_VertexBuffer->Bind();
|
||||
m_IndexBuffer->Bind();
|
||||
Renderer::DrawIndexed(m_IndexBuffer->GetCount(), false);
|
||||
|
||||
|
||||
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_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);
|
||||
|
||||
|
||||
|
||||
if (m_AlbedoInput.TextureMap)
|
||||
m_MeshMaterial->Set("u_AlbedoTexture", m_AlbedoInput.TextureMap);
|
||||
if (m_NormalInput.TextureMap)
|
||||
m_MeshMaterial->Set("u_NormalTexture", m_NormalInput.TextureMap);
|
||||
if (m_MetalnessInput.TextureMap)
|
||||
m_MeshMaterial->Set("u_MetalnessTexture", m_MetalnessInput.TextureMap);
|
||||
if (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());
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
else if (m_Scene == Scene::Model)
|
||||
{
|
||||
if (m_Mesh)
|
||||
{
|
||||
m_Mesh->Render(deltaTime, scale(mat4(1.0f), vec3(m_MeshScale)), m_MeshMaterial);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
m_HDRShader->Bind();
|
||||
m_HDRShader->SetFloat("u_Exposure", m_Exposure);
|
||||
m_Framebuffer->BindTexture();
|
||||
m_VertexBuffer->Bind();
|
||||
m_IndexBuffer->Bind();
|
||||
Renderer::DrawIndexed(m_IndexBuffer->GetCount(), false);
|
||||
m_FinalPresentBuffer->Unbind();
|
||||
}
|
||||
}
|
||||
|
||||
void DemoLayer::OnImGuiRender()
|
||||
{
|
||||
#define ENABLE_DOCKSPACE 1
|
||||
|
||||
#if ENABLE_DOCKSPACE
|
||||
|
||||
static bool p_open = true;
|
||||
static bool opt_fullscreen = true;
|
||||
static bool opt_padding = false;
|
||||
static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None;
|
||||
|
||||
// We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into,
|
||||
// because it would be confusing to have two docking targets within each others.
|
||||
ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
|
||||
if (opt_fullscreen)
|
||||
{
|
||||
const ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||
ImGui::SetNextWindowPos(viewport->WorkPos);
|
||||
ImGui::SetNextWindowSize(viewport->WorkSize);
|
||||
ImGui::SetNextWindowViewport(viewport->ID);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
||||
window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
|
||||
window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
|
||||
}
|
||||
else
|
||||
{
|
||||
dockspace_flags &= ~ImGuiDockNodeFlags_PassthruCentralNode;
|
||||
}
|
||||
|
||||
// When using ImGuiDockNodeFlags_PassthruCentralNode, DockSpace() will render our background
|
||||
// and handle the pass-thru hole, so we ask Begin() to not render a background.
|
||||
if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode)
|
||||
window_flags |= ImGuiWindowFlags_NoBackground;
|
||||
|
||||
// Important: note that we proceed even if Begin() returns false (aka window is collapsed).
|
||||
// This is because we want to keep our DockSpace() active. If a DockSpace() is inactive,
|
||||
// all active windows docked into it will lose their parent and become undocked.
|
||||
// We cannot preserve the docking relationship between an active window and an inactive docking, otherwise
|
||||
// any change of dockspace/settings would lead to windows being stuck in limbo and never being visible.
|
||||
if (!opt_padding)
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
|
||||
ImGui::Begin("DockSpace Demo", &p_open, window_flags);
|
||||
if (!opt_padding)
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
if (opt_fullscreen)
|
||||
ImGui::PopStyleVar(2);
|
||||
|
||||
// Submit the DockSpace
|
||||
// REMINDER: THIS IS A DEMO FOR ADVANCED USAGE OF DockSpace()!
|
||||
// MOST REGULAR APPLICATIONS WILL SIMPLY WANT TO CALL DockSpaceOverViewport(). READ COMMENTS ABOVE.
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
|
||||
{
|
||||
ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
|
||||
ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
|
||||
}
|
||||
|
||||
// Show demo options and help
|
||||
if (ImGui::BeginMenuBar())
|
||||
{
|
||||
if (ImGui::BeginMenu("Options"))
|
||||
{
|
||||
// Disabling fullscreen would allow the window to be moved to the front of other windows,
|
||||
// which we can't undo at the moment without finer window depth/z control.
|
||||
ImGui::MenuItem("Fullscreen", NULL, &opt_fullscreen);
|
||||
ImGui::MenuItem("Padding", NULL, &opt_padding);
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::MenuItem("Flag: NoDockingOverCentralNode", "", (dockspace_flags & ImGuiDockNodeFlags_NoDockingOverCentralNode) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoDockingOverCentralNode; }
|
||||
if (ImGui::MenuItem("Flag: NoDockingSplit", "", (dockspace_flags & ImGuiDockNodeFlags_NoDockingSplit) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoDockingSplit; }
|
||||
if (ImGui::MenuItem("Flag: NoUndocking", "", (dockspace_flags & ImGuiDockNodeFlags_NoUndocking) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoUndocking; }
|
||||
if (ImGui::MenuItem("Flag: NoResize", "", (dockspace_flags & ImGuiDockNodeFlags_NoResize) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoResize; }
|
||||
if (ImGui::MenuItem("Flag: AutoHideTabBar", "", (dockspace_flags & ImGuiDockNodeFlags_AutoHideTabBar) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_AutoHideTabBar; }
|
||||
if (ImGui::MenuItem("Flag: PassthruCentralNode", "", (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode) != 0, opt_fullscreen)) { dockspace_flags ^= ImGuiDockNodeFlags_PassthruCentralNode; }
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::MenuItem("Close", NULL, false, p_open != false))
|
||||
p_open = false;
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::BeginMenu("Help"))
|
||||
{
|
||||
ImGui::TextUnformatted(
|
||||
"This demo has nothing to do with enabling docking!" "\n"
|
||||
"This demo only demonstrate the use of ImGui::DockSpace() which allows you to manually\ncreate a docking node _within_ another window." "\n"
|
||||
"Most application can simply call ImGui::DockSpaceOverViewport() and be done with it.");
|
||||
ImGui::Separator();
|
||||
ImGui::TextUnformatted("When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!" "\n"
|
||||
"- Drag from window title bar or their tab to dock/undock." "\n"
|
||||
"- Drag from window menu button (upper-left button) to undock an entire node (all windows)." "\n"
|
||||
"- Hold SHIFT to disable docking (if io.ConfigDockingWithShift == false, default)" "\n"
|
||||
"- Hold SHIFT to enable docking (if io.ConfigDockingWithShift == true)");
|
||||
ImGui::Separator();
|
||||
ImGui::TextUnformatted("More details:"); ImGui::Bullet(); ImGui::SameLine(); ImGui::TextLinkOpenURL("Docking Wiki page", "https://github.com/ocornut/imgui/wiki/Docking");
|
||||
ImGui::BulletText("Read comments in ShowExampleAppDockSpace()");
|
||||
ImGui::EndMenu();
|
||||
|
||||
}
|
||||
|
||||
ImGuiShowHelpMarker(
|
||||
"You can _always_ dock _any_ window into another by holding the SHIFT key while moving a window. Try it now!" "\n"
|
||||
"This demo app has nothing to do with it!" "\n\n"
|
||||
"This demo app only demonstrate the use of ImGui::DockSpace() which allows you to manually create a docking node _within_ another window. This is useful so you can decorate your main application window (e.g. with a menu bar)." "\n\n"
|
||||
"ImGui::DockSpace() comes with one hard constraint: it needs to be submitted _before_ any window which may be docked into it. Therefore, if you use a dock spot as the central point of your application, you'll probably want it to be part of the very first window you are submitting to imgui every frame." "\n\n"
|
||||
"(NB: because of this constraint, the implicit \"Debug\" window can not be docked into an explicit DockSpace() node, because that window is submitted as part of the NewFrame() call. An easy workaround is that you can create your own implicit \"Debug##2\" window after calling DockSpace() and leave it in the window stack for anyone to use.)"
|
||||
);
|
||||
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
|
||||
#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);
|
||||
|
||||
ImGui::Begin("Environment");
|
||||
|
||||
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("Radiance Prefiltering", m_RadiancePrefilter);
|
||||
Property("Env Map Rotation", m_EnvMapRotation, -360.0f, 360.0f);
|
||||
|
||||
ImGui::Columns(1);
|
||||
|
||||
ImGui::End();
|
||||
|
||||
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"))
|
||||
{
|
||||
std::string filename = Prism::Application::Get().OpenFile("");
|
||||
if (filename != "")
|
||||
m_Mesh.reset(new Prism::Mesh(filename));
|
||||
}
|
||||
}
|
||||
ImGui::Separator();
|
||||
|
||||
// Textures ------------------------------------------------------------------------------
|
||||
{
|
||||
// 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())
|
||||
{
|
||||
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::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);
|
||||
}
|
||||
}
|
||||
|
||||
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::Separator();
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
void DemoLayer::OnEvent(Prism::Event& e)
|
||||
{
|
||||
Layer::OnEvent(e);
|
||||
}
|
||||
@ -1,115 +0,0 @@
|
||||
//
|
||||
// Created by sfd on 25-11-21.
|
||||
//
|
||||
|
||||
#ifndef DEMOLAYER_H
|
||||
#define DEMOLAYER_H
|
||||
|
||||
#include "Prism.h"
|
||||
#include "Prism/Renderer/Camera.h"
|
||||
#include "Prism/Renderer/FrameBuffer.h"
|
||||
#include "Prism/Renderer/Material.h"
|
||||
#include "Prism/Renderer/Mesh.h"
|
||||
|
||||
class DemoLayer : public Prism::Layer
|
||||
{
|
||||
public:
|
||||
DemoLayer();
|
||||
virtual ~DemoLayer();
|
||||
|
||||
virtual void OnAttach() override;
|
||||
virtual void OnDetach() override;
|
||||
virtual void OnUpdate(Prism::TimeStep deltaTime) override;
|
||||
virtual void OnImGuiRender() override;
|
||||
virtual void OnEvent(Prism::Event& e) override;
|
||||
|
||||
private:
|
||||
float m_ClearColor[4];
|
||||
|
||||
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::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;
|
||||
|
||||
float m_GridScale = 16.025f, m_GridSize = 0.025f;
|
||||
float m_MeshScale = 1.0f;
|
||||
|
||||
Prism::Ref<Prism::Shader> m_Shader;
|
||||
Prism::Ref<Prism::Shader> m_PBRShader;
|
||||
|
||||
struct AlbedoInput
|
||||
{
|
||||
glm::vec3 Color = { 0.972f, 0.96f, 0.915f }; // Silver, from https://docs.unrealengine.com/en-us/Engine/Rendering/Materials/PhysicallyBased
|
||||
Prism::Ref<Prism::Texture2D> TextureMap;
|
||||
bool SRGB = true;
|
||||
bool UseTexture = false;
|
||||
};
|
||||
AlbedoInput m_AlbedoInput;
|
||||
|
||||
struct NormalInput
|
||||
{
|
||||
Prism::Ref<Prism::Texture2D> TextureMap;
|
||||
bool UseTexture = false;
|
||||
};
|
||||
NormalInput m_NormalInput;
|
||||
|
||||
struct MetalnessInput
|
||||
{
|
||||
float Value = 1.0f;
|
||||
Prism::Ref<Prism::Texture2D> TextureMap;
|
||||
bool UseTexture = false;
|
||||
};
|
||||
MetalnessInput m_MetalnessInput;
|
||||
|
||||
struct RoughnessInput
|
||||
{
|
||||
float Value = 0.5f;
|
||||
Prism::Ref<Prism::Texture2D> TextureMap;
|
||||
bool UseTexture = false;
|
||||
};
|
||||
RoughnessInput m_RoughnessInput;
|
||||
|
||||
Prism::Ref<Prism::FrameBuffer> m_Framebuffer, m_FinalPresentBuffer;
|
||||
|
||||
Prism::Ref<Prism::VertexBuffer> m_VertexBuffer;
|
||||
Prism::Ref<Prism::IndexBuffer> m_IndexBuffer;
|
||||
Prism::Ref<Prism::TextureCube> m_EnvironmentCubeMap, m_EnvironmentIrradiance;
|
||||
|
||||
Prism::Camera m_Camera;
|
||||
|
||||
struct Light
|
||||
{
|
||||
glm::vec3 Direction;
|
||||
glm::vec3 Radiance;
|
||||
};
|
||||
Light m_Light;
|
||||
float m_LightMultiplier = 0.3f;
|
||||
|
||||
// PBR params
|
||||
float m_Exposure = 1.0f;
|
||||
|
||||
bool m_RadiancePrefilter = false;
|
||||
|
||||
float m_EnvMapRotation = 0.0f;
|
||||
|
||||
enum class Scene : uint32_t
|
||||
{
|
||||
Spheres = 0, Model = 1
|
||||
};
|
||||
Scene m_Scene;
|
||||
|
||||
// Editor resources
|
||||
Prism::Ref<Prism::Texture2D> m_CheckerboardTex;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif //DEMOLAYER_H
|
||||
|
Before Width: | Height: | Size: 12 KiB |
@ -1,23 +0,0 @@
|
||||
# Blender v2.78 (sub 0) OBJ File: ''
|
||||
# www.blender.org
|
||||
v 10.000000 -10.000000 -9.999999
|
||||
v 10.000000 -10.000000 10.000000
|
||||
v -10.000001 -10.000000 9.999998
|
||||
v -9.999996 -10.000000 -10.000004
|
||||
v 10.000005 10.000000 -9.999994
|
||||
v 9.999993 10.000000 10.000006
|
||||
v -10.000004 10.000000 9.999996
|
||||
v -9.999999 10.000000 -10.000000
|
||||
vn 0.0000 1.0000 -0.0000
|
||||
vn 0.0000 -1.0000 0.0000
|
||||
vn -1.0000 -0.0000 -0.0000
|
||||
vn 0.0000 0.0000 -1.0000
|
||||
vn 1.0000 0.0000 0.0000
|
||||
vn -0.0000 -0.0000 1.0000
|
||||
s off
|
||||
f 1//1 4//1 3//1 2//1
|
||||
f 5//2 6//2 7//2 8//2
|
||||
f 1//3 2//3 6//3 5//3
|
||||
f 2//4 3//4 7//4 6//4
|
||||
f 3//5 4//5 8//5 7//5
|
||||
f 5//6 8//6 4//6 1//6
|
||||
@ -1,17 +0,0 @@
|
||||
# Blender v2.80 (sub 75) OBJ File: 'Plane1m.blend'
|
||||
# www.blender.org
|
||||
mtllib Plane1m.mtl
|
||||
o Plane
|
||||
v -0.500000 0.000000 0.500000
|
||||
v 0.500000 0.000000 0.500000
|
||||
v -0.500000 0.000000 -0.500000
|
||||
v 0.500000 0.000000 -0.500000
|
||||
vt 1.000000 0.000000
|
||||
vt 0.000000 1.000000
|
||||
vt 0.000000 0.000000
|
||||
vt 1.000000 1.000000
|
||||
vn 0.0000 1.0000 0.0000
|
||||
usemtl None
|
||||
s off
|
||||
f 2/1/1 3/2/1 1/3/1
|
||||
f 2/1/1 4/4/1 3/2/1
|
||||
|
Before Width: | Height: | Size: 4.5 MiB |
|
Before Width: | Height: | Size: 3.6 MiB |
|
Before Width: | Height: | Size: 2.7 MiB |
|
Before Width: | Height: | Size: 2.2 MiB |
@ -1,49 +0,0 @@
|
||||
// Simple Texture Shader
|
||||
|
||||
#type vertex
|
||||
#version 430
|
||||
|
||||
layout(location = 0) in vec3 a_Position;
|
||||
layout(location = 4) in vec2 a_TexCoord;
|
||||
|
||||
uniform mat4 u_MVP;
|
||||
|
||||
out vec2 v_TexCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 position = u_MVP * vec4(a_Position, 1.0);
|
||||
gl_Position = position;
|
||||
|
||||
v_TexCoord = a_TexCoord;
|
||||
}
|
||||
|
||||
#type fragment
|
||||
#version 430
|
||||
|
||||
layout(location = 0) out vec4 color;
|
||||
|
||||
uniform float u_Scale;
|
||||
uniform float u_Res;
|
||||
|
||||
in vec2 v_TexCoord;
|
||||
|
||||
/*void main()
|
||||
{
|
||||
color = texture(u_Texture, v_TexCoord * 8.0);
|
||||
}*/
|
||||
|
||||
float grid(vec2 st, float res)
|
||||
{
|
||||
vec2 grid = fract(st);
|
||||
return step(res, grid.x) * step(res, grid.y);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
float scale = u_Scale;
|
||||
float resolution = u_Res;
|
||||
|
||||
float x = grid(v_TexCoord * scale, resolution);
|
||||
color = vec4(vec3(0.2), 0.5) * (1.0 - x);
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
#type vertex
|
||||
#version 430 core
|
||||
|
||||
layout(location = 0) in vec3 a_Position;
|
||||
layout(location = 1) in vec3 a_Normal;
|
||||
|
||||
uniform mat4 u_MVP;
|
||||
|
||||
out vec3 v_Normal;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = u_MVP * vec4(a_Position, 1.0);
|
||||
v_Normal = a_Normal;
|
||||
}
|
||||
|
||||
#type fragment
|
||||
#version 430 core
|
||||
|
||||
layout(location = 0) out vec4 o_Color;
|
||||
|
||||
uniform vec4 u_Color;
|
||||
in vec3 v_Normal;
|
||||
|
||||
void main()
|
||||
{
|
||||
o_Color = u_Color * vec4(v_Normal * 0.5 + 0.5, 1.0f);
|
||||
// o_Color = vec4(0.6, 0.7, 0.8, 1.0);
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
#type vertex
|
||||
#version 430
|
||||
|
||||
layout(location = 0) in vec3 a_Position;
|
||||
layout(location = 1) in vec2 a_TexCoord;
|
||||
|
||||
out vec2 v_TexCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 position = vec4(a_Position.xy, 1.0, 1.0);
|
||||
v_TexCoord = a_TexCoord;
|
||||
gl_Position = position;
|
||||
}
|
||||
|
||||
#type fragment
|
||||
#version 430
|
||||
|
||||
in vec2 v_TexCoord;
|
||||
|
||||
uniform sampler2D u_Texture;
|
||||
|
||||
layout(location=0) out vec4 outColor;
|
||||
|
||||
uniform float u_Exposure;
|
||||
|
||||
void main()
|
||||
{
|
||||
const float gamma = 2.2;
|
||||
const float pureWhite = 1.0;
|
||||
|
||||
vec3 color = texture(u_Texture, v_TexCoord).rgb * u_Exposure;
|
||||
// Reinhard tonemapping operator.
|
||||
// see: "Photographic Tone Reproduction for Digital Images", eq. 4
|
||||
float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722));
|
||||
float mappedLuminance = (luminance * (1.0 + luminance / (pureWhite * pureWhite))) / (1.0 + luminance);
|
||||
|
||||
// Scale color by ratio of average luminances.
|
||||
vec3 mappedColor = (mappedLuminance / luminance) * color;
|
||||
|
||||
// Gamma correction.
|
||||
outColor = vec4(pow(mappedColor, vec3(1.0/gamma)), 1.0);
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
// Simple Textured Quad Shader
|
||||
|
||||
#type vertex
|
||||
#version 430
|
||||
|
||||
layout(location = 0) in vec3 a_Position;
|
||||
layout(location = 1) in vec2 a_TexCoord;
|
||||
|
||||
uniform mat4 u_InverseVP;
|
||||
|
||||
out vec3 v_Position;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 position = vec4(a_Position.xy, 1.0, 1.0);
|
||||
gl_Position = position;
|
||||
|
||||
v_Position = (u_InverseVP * position).xyz;
|
||||
}
|
||||
|
||||
#type fragment
|
||||
#version 430
|
||||
|
||||
layout(location = 0) out vec4 finalColor;
|
||||
|
||||
uniform samplerCube u_Texture;
|
||||
|
||||
in vec3 v_Position;
|
||||
|
||||
void main()
|
||||
{
|
||||
finalColor = textureLod(u_Texture, v_Position, 0.0);
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
#type vertex
|
||||
#version 430
|
||||
|
||||
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_Bitangent;
|
||||
layout(location = 4) in vec2 a_TexCoord;
|
||||
|
||||
uniform mat4 u_MVP;
|
||||
|
||||
out vec3 v_Normal;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = u_MVP * vec4(a_Position, 1.0);
|
||||
v_Normal = a_Normal;
|
||||
}
|
||||
|
||||
#type fragment
|
||||
#version 430
|
||||
|
||||
layout(location = 0) out vec4 finalColor;
|
||||
|
||||
//uniform vec4 u_Color;
|
||||
|
||||
in vec3 v_Normal;
|
||||
|
||||
void main()
|
||||
{
|
||||
finalColor = vec4((v_Normal * 0.5 + 0.5), 1.0);// * u_Color.xyz, 1.0);
|
||||
}
|
||||
@ -1,336 +0,0 @@
|
||||
// -----------------------------
|
||||
// -- 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;
|
||||
|
||||
layout(location = 5) in ivec4 a_BoneIndices;
|
||||
layout(location = 6) in vec4 a_BoneWeights;
|
||||
|
||||
uniform mat4 u_ViewProjectionMatrix;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
|
||||
const int MAX_BONES = 100;
|
||||
uniform mat4 u_BoneTransforms[100];
|
||||
|
||||
out VertexOutput
|
||||
{
|
||||
vec3 WorldPosition;
|
||||
vec3 Normal;
|
||||
vec2 TexCoord;
|
||||
mat3 WorldNormals;
|
||||
vec3 Binormal;
|
||||
} vs_Output;
|
||||
|
||||
void main()
|
||||
{
|
||||
mat4 boneTransform = u_BoneTransforms[a_BoneIndices[0]] * a_BoneWeights[0];
|
||||
boneTransform += u_BoneTransforms[a_BoneIndices[1]] * a_BoneWeights[1];
|
||||
boneTransform += u_BoneTransforms[a_BoneIndices[2]] * a_BoneWeights[2];
|
||||
boneTransform += u_BoneTransforms[a_BoneIndices[3]] * a_BoneWeights[3];
|
||||
|
||||
vec4 localPosition = boneTransform * vec4(a_Position, 1.0);
|
||||
|
||||
vs_Output.WorldPosition = vec3(u_ModelMatrix * boneTransform * vec4(a_Position, 1.0));
|
||||
vs_Output.Normal = mat3(boneTransform) * 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 = mat3(boneTransform) * a_Binormal;
|
||||
|
||||
//gl_Position = u_ViewProjectionMatrix * u_ModelMatrix * vec4(a_Position, 1.0);
|
||||
gl_Position = u_ViewProjectionMatrix * u_ModelMatrix * localPosition;
|
||||
}
|
||||
|
||||
#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);
|
||||
}
|
||||
@ -1,321 +0,0 @@
|
||||
// -----------------------------
|
||||
// -- 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);
|
||||
}
|
||||
|
Before Width: | Height: | Size: 192 KiB |
|
Before Width: | Height: | Size: 256 KiB |
|
Before Width: | Height: | Size: 256 KiB |
|
Before Width: | Height: | Size: 256 KiB |
|
Before Width: | Height: | Size: 15 MiB |
|
Before Width: | Height: | Size: 6.5 MiB |
|
Before Width: | Height: | Size: 19 MiB |
|
Before Width: | Height: | Size: 11 MiB |
|
Before Width: | Height: | Size: 576 KiB |
|
Before Width: | Height: | Size: 22 MiB |