add scene render system, add proper HDR environments, try load texture from mesh file
This commit is contained in:
@ -3,9 +3,7 @@
|
||||
//
|
||||
|
||||
#include "EditorLayer.h"
|
||||
|
||||
#include "ImGuizmo.h"
|
||||
#include "Prism/Core/KeyCodes.h"
|
||||
|
||||
namespace Prism
|
||||
{
|
||||
@ -19,7 +17,6 @@ namespace Prism
|
||||
ImGui::Text(name.c_str());
|
||||
ImGui::NextColumn();
|
||||
ImGui::PushItemWidth(-1);
|
||||
|
||||
std::string id = "##" + name;
|
||||
ImGui::Checkbox(id.c_str(), &value);
|
||||
|
||||
@ -88,6 +85,25 @@ namespace Prism
|
||||
}
|
||||
|
||||
|
||||
void Property(const std::string& name, glm::vec2& value, float min, float max, PropertyFlag flags)
|
||||
{
|
||||
ImGui::Text(name.c_str());
|
||||
ImGui::NextColumn();
|
||||
ImGui::PushItemWidth(-1);
|
||||
|
||||
std::string id = "##" + name;
|
||||
ImGui::SliderFloat2(id.c_str(), glm::value_ptr(value), min, max);
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::NextColumn();
|
||||
}
|
||||
|
||||
void Property(const std::string& name, glm::vec2& value, PropertyFlag flags)
|
||||
{
|
||||
Property(name, value, -1.0f, 1.0f, flags);
|
||||
}
|
||||
|
||||
|
||||
static void ImGuiShowHelpMarker(const char* desc)
|
||||
{
|
||||
ImGui::TextDisabled("(?)");
|
||||
@ -102,8 +118,7 @@ namespace Prism
|
||||
}
|
||||
|
||||
EditorLayer::EditorLayer()
|
||||
: 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))
|
||||
: m_SceneType(SceneType::Model)
|
||||
{
|
||||
}
|
||||
|
||||
@ -113,114 +128,83 @@ namespace Prism
|
||||
|
||||
void EditorLayer::OnAttach()
|
||||
{
|
||||
// RenderPass
|
||||
FramebufferSpecification geoFramebufferSpec;
|
||||
geoFramebufferSpec.Width = 1280;
|
||||
geoFramebufferSpec.Height = 720;
|
||||
geoFramebufferSpec.Format = FramebufferFormat::RGBA16F;
|
||||
geoFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f };
|
||||
auto environment = Environment::Load("assets/env/birchwood_4k.hdr");
|
||||
|
||||
RenderPassSpecification geoRenderPassSpec;
|
||||
geoRenderPassSpec.TargetFramebuffer = FrameBuffer::Create(geoFramebufferSpec);
|
||||
m_GeoPass = RenderPass::Create(geoRenderPassSpec);
|
||||
// Model Scene
|
||||
{
|
||||
m_Scene = CreateRef<Scene>("Model Scene");
|
||||
m_Scene->SetCamera(Camera(glm::perspectiveFov(glm::radians(45.0f), 1280.0f, 720.0f, 0.1f, 10000.0f)));
|
||||
|
||||
m_Scene->SetEnvironment(environment);
|
||||
|
||||
FramebufferSpecification compFramebufferSpec;
|
||||
compFramebufferSpec.Width = 1280;
|
||||
compFramebufferSpec.Height = 720;
|
||||
compFramebufferSpec.Format = FramebufferFormat::RGBA8;
|
||||
compFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f };
|
||||
m_MeshEntity = m_Scene->CreateEntity();
|
||||
|
||||
RenderPassSpecification compRenderPassSpec;
|
||||
compRenderPassSpec.TargetFramebuffer = FrameBuffer::Create(compFramebufferSpec);
|
||||
m_CompositePass = RenderPass::Create(compRenderPassSpec);
|
||||
const auto mesh = CreateRef<Mesh>("assets/models/m1911/m1911.fbx");
|
||||
//auto mesh = CreateRef<Mesh>("assets/meshes/cerberus/CerberusMaterials.fbx");
|
||||
// auto mesh = CreateRef<Mesh>("assets/models/m1911/M1911Materials.fbx");
|
||||
m_MeshEntity->SetMesh(mesh);
|
||||
|
||||
/*
|
||||
m_Framebuffer.reset(FrameBuffer::Create(1280, 720, FramebufferFormat::RGBA16F));
|
||||
m_FinalPresentBuffer.reset(FrameBuffer::Create(1280, 720, FramebufferFormat::RGBA8));
|
||||
*/
|
||||
m_MeshMaterial = mesh->GetMaterial();
|
||||
}
|
||||
|
||||
m_QuadShader = Shader::Create("assets/shaders/quad.glsl");
|
||||
m_HDRShader = Shader::Create("assets/shaders/hdr.glsl");
|
||||
// Sphere Scene
|
||||
{
|
||||
m_SphereScene = CreateRef<Scene>("PBR Sphere Scene");
|
||||
m_SphereScene->SetCamera(Camera(glm::perspectiveFov(glm::radians(45.0f), 1280.0f, 720.0f, 0.1f, 10000.0f)));
|
||||
|
||||
m_Mesh = CreateRef<Mesh>("assets/models/m1911/m1911.fbx");
|
||||
m_MeshMaterial = CreateRef<MaterialInstance>(m_Mesh->GetMaterial());
|
||||
m_SphereScene->SetEnvironment(environment);
|
||||
|
||||
m_SphereMesh = CreateRef<Mesh>("assets/models/Sphere1m.fbx");
|
||||
m_PlaneMesh = CreateRef<Mesh>("assets/models/Plane1m.fbx");
|
||||
auto sphereMesh = CreateRef<Mesh>("assets/models/Sphere1m.fbx");
|
||||
m_SphereBaseMaterial = sphereMesh->GetMaterial();
|
||||
|
||||
m_GridShader = Shader::Create("assets/shaders/Grid.glsl");
|
||||
m_GridMaterial = MaterialInstance::Create(Material::Create(m_GridShader));
|
||||
m_GridMaterial->Set("u_Scale", m_GridScale);
|
||||
m_GridMaterial->Set("u_Res", m_GridSize);
|
||||
float x = -4.0f;
|
||||
float roughness = 0.0f;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
auto sphereEntity = m_SphereScene->CreateEntity();
|
||||
|
||||
Ref<MaterialInstance> mi = CreateRef<MaterialInstance>(m_SphereBaseMaterial);
|
||||
mi->Set("u_Metalness", 1.0f);
|
||||
mi->Set("u_Roughness", roughness);
|
||||
x += 1.1f;
|
||||
roughness += 0.15f;
|
||||
m_MetalSphereMaterialInstances.push_back(mi);
|
||||
|
||||
sphereEntity->SetMesh(sphereMesh);
|
||||
sphereEntity->SetMaterial(mi);
|
||||
sphereEntity->Transform() = glm::translate(glm::mat4(1.0f), glm::vec3(x, 0.0f, 0.0f));
|
||||
}
|
||||
|
||||
x = -4.0f;
|
||||
roughness = 0.0f;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
auto sphereEntity = m_SphereScene->CreateEntity();
|
||||
|
||||
Ref<MaterialInstance> mi(new MaterialInstance(m_SphereBaseMaterial));
|
||||
mi->Set("u_Metalness", 0.0f);
|
||||
mi->Set("u_Roughness", roughness);
|
||||
x += 1.1f;
|
||||
roughness += 0.15f;
|
||||
m_DielectricSphereMaterialInstances.push_back(mi);
|
||||
|
||||
sphereEntity->SetMesh(sphereMesh);
|
||||
sphereEntity->SetMaterial(mi);
|
||||
sphereEntity->Transform() = glm::translate(glm::mat4(1.0f), glm::vec3(x, 1.2f, 0.0f));
|
||||
}
|
||||
}
|
||||
|
||||
m_ActiveScene = m_Scene;
|
||||
m_SceneHierarchyPanel = CreateScope<SceneHierarchyPanel>(m_ActiveScene);
|
||||
|
||||
m_PlaneMesh.reset(new Mesh("assets/models/Plane1m.obj"));
|
||||
|
||||
// Editor
|
||||
m_CheckerboardTex.reset(Texture2D::Create("assets/editor/Checkerboard.tga"));
|
||||
|
||||
// Environment
|
||||
m_EnvironmentCubeMap.reset(
|
||||
TextureCube::Create("assets/textures/environments/Arches_E_PineTree_Radiance.tga"));
|
||||
m_EnvironmentIrradiance.reset(
|
||||
TextureCube::Create("assets/textures/environments/Arches_E_PineTree_Irradiance.tga"));
|
||||
m_BRDFLUT.reset(Texture2D::Create("assets/textures/BRDF_LUT.tga"));
|
||||
|
||||
|
||||
float x = -4.0f;
|
||||
float roughness = 0.0f;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
Ref<MaterialInstance> mi = CreateRef<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.125f;
|
||||
m_MetalSphereMaterialInstances.push_back(mi);
|
||||
}
|
||||
|
||||
x = -4.0f;
|
||||
roughness = 0.0f;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
Ref<MaterialInstance> mi = CreateRef<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.125f;
|
||||
m_DielectricSphereMaterialInstances.push_back(mi);
|
||||
}
|
||||
|
||||
// Create Quad
|
||||
static float QuadVertex[] = {
|
||||
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
|
||||
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
|
||||
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
|
||||
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f
|
||||
};
|
||||
static uint32_t QuadIndices[] = {
|
||||
0, 1, 2, 2, 3, 0
|
||||
};
|
||||
|
||||
m_FullscreenQuadVertexArray = VertexArray::Create();
|
||||
auto quadVB = VertexBuffer::Create(QuadVertex, sizeof(float) * sizeof(QuadVertex));
|
||||
quadVB->SetLayout({
|
||||
{ ShaderDataType::Float3, "a_Position" },
|
||||
{ ShaderDataType::Float2, "a_TexCoord" }
|
||||
});
|
||||
|
||||
auto quadIB = IndexBuffer::Create(QuadIndices, sizeof(QuadIndices) * sizeof(uint32_t));
|
||||
m_FullscreenQuadVertexArray->AddVertexBuffer(quadVB);
|
||||
m_FullscreenQuadVertexArray->SetIndexBuffer(quadIB);
|
||||
|
||||
m_CheckerboardTex = Texture2D::Create("assets/editor/Checkerboard.tga");
|
||||
|
||||
// lights
|
||||
m_Light.Direction = {-0.5f, -0.5f, 1.0f};
|
||||
m_Light.Radiance = {1.0f, 1.0f, 1.0f};
|
||||
|
||||
|
||||
m_Transform = glm::scale(glm::mat4(1.0f), glm::vec3(m_MeshScale));
|
||||
}
|
||||
|
||||
void EditorLayer::OnDetach()
|
||||
@ -232,62 +216,28 @@ namespace Prism
|
||||
{
|
||||
// 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::BeginRenderPass(m_GeoPass);
|
||||
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();
|
||||
*/
|
||||
m_FullscreenQuadVertexArray->Bind();
|
||||
Renderer::DrawIndexed(m_FullscreenQuadVertexArray->GetIndexBuffer()->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);
|
||||
m_SphereBaseMaterial->Set("u_AlbedoColor", m_AlbedoInput.Color);
|
||||
m_SphereBaseMaterial->Set("lights", m_Light);
|
||||
m_SphereBaseMaterial->Set("u_RadiancePrefilter", m_RadiancePrefilter ? 1.0f : 0.0f);
|
||||
m_SphereBaseMaterial->Set("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f);
|
||||
m_SphereBaseMaterial->Set("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f);
|
||||
m_SphereBaseMaterial->Set("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f);
|
||||
m_SphereBaseMaterial->Set("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f);
|
||||
m_SphereBaseMaterial->Set("u_EnvMapRotation", m_EnvMapRotation);
|
||||
|
||||
|
||||
if (m_AlbedoInput.TextureMap)
|
||||
@ -299,56 +249,7 @@ namespace Prism
|
||||
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, m_Transform, 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();
|
||||
Renderer::EndRenderPass();
|
||||
|
||||
Renderer::BeginRenderPass(m_CompositePass);
|
||||
// m_FinalPresentBuffer->Bind();
|
||||
m_HDRShader->Bind();
|
||||
m_HDRShader->SetFloat("u_Exposure", m_Exposure);
|
||||
// m_Framebuffer->BindTexture();
|
||||
m_GeoPass->GetSpecification().TargetFramebuffer->BindTexture();
|
||||
/*
|
||||
m_VertexBuffer->Bind();
|
||||
m_IndexBuffer->Bind();
|
||||
*/
|
||||
m_FullscreenQuadVertexArray->Bind();
|
||||
Renderer::DrawIndexed(m_FullscreenQuadVertexArray->GetIndexBuffer()->GetCount(), false);
|
||||
// m_FinalPresentBuffer->Unbind();
|
||||
Renderer::EndRenderPass();
|
||||
m_ActiveScene->OnUpdate(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
@ -493,25 +394,39 @@ namespace Prism
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
|
||||
m_SceneHierarchyPanel->OnImGuiRender();
|
||||
ImGui::End();
|
||||
|
||||
#endif
|
||||
|
||||
// Editor Panel ------------------------------------------------------------------------------
|
||||
ImGui::Begin("Model");
|
||||
ImGui::RadioButton("Spheres", (int*)&m_Scene, (int)Scene::Spheres);
|
||||
|
||||
if (ImGui::RadioButton("Spheres", (int*)&m_SceneType, (int)SceneType::Spheres))
|
||||
m_ActiveScene = m_SphereScene;
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Model", (int*)&m_Scene, (int)Scene::Model);
|
||||
if (ImGui::RadioButton("Model", (int*)&m_SceneType, (int)SceneType::Model))
|
||||
m_ActiveScene = m_Scene;
|
||||
|
||||
ImGui::Begin("Environment");
|
||||
|
||||
if (ImGui::Button("Load Environment Map"))
|
||||
{
|
||||
std::string filename = Application::Get().OpenFile("*.hdr");
|
||||
if (!filename.empty())
|
||||
m_ActiveScene->SetEnvironment(Environment::Load(filename));
|
||||
}
|
||||
|
||||
ImGui::SliderFloat("Skybox LOD", &m_Scene->GetSkyboxLod(), 0.0f, 11.0f);
|
||||
|
||||
|
||||
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("Exposure", m_ActiveScene->GetCamera().GetExposure(), 0.0f, 5.0f);
|
||||
|
||||
Property("Radiance Prefiltering", m_RadiancePrefilter);
|
||||
Property("Env Map Rotation", m_EnvMapRotation, -360.0f, 360.0f);
|
||||
@ -523,16 +438,22 @@ namespace Prism
|
||||
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;
|
||||
auto mesh = m_MeshEntity->GetMesh();
|
||||
std::string fullpath = mesh ? 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 = Application::Get().OpenFile("");
|
||||
if (filename != "")
|
||||
m_Mesh.reset(new Mesh(filename));
|
||||
if (!filename.empty())
|
||||
{
|
||||
auto newMesh = CreateRef<Mesh>(filename);
|
||||
// m_MeshMaterial.reset(new MaterialInstance(newMesh->GetMaterial()));
|
||||
// m_MeshEntity->SetMaterial(m_MeshMaterial);
|
||||
m_MeshEntity->SetMesh(newMesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::Separator();
|
||||
@ -561,8 +482,8 @@ namespace Prism
|
||||
if (ImGui::IsItemClicked())
|
||||
{
|
||||
std::string filename = Application::Get().OpenFile("");
|
||||
if (filename != "")
|
||||
m_AlbedoInput.TextureMap.reset(Texture2D::Create(filename, m_AlbedoInput.SRGB));
|
||||
if (!filename.empty())
|
||||
m_AlbedoInput.TextureMap = Texture2D::Create(filename, m_AlbedoInput.SRGB);
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
@ -571,8 +492,7 @@ namespace Prism
|
||||
if (ImGui::Checkbox("sRGB##AlbedoMap", &m_AlbedoInput.SRGB))
|
||||
{
|
||||
if (m_AlbedoInput.TextureMap)
|
||||
m_AlbedoInput.TextureMap.reset(
|
||||
Texture2D::Create(m_AlbedoInput.TextureMap->GetPath(), m_AlbedoInput.SRGB));
|
||||
m_AlbedoInput.TextureMap = Texture2D::Create(m_AlbedoInput.TextureMap->GetPath(), m_AlbedoInput.SRGB);
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
ImGui::SameLine();
|
||||
@ -602,8 +522,8 @@ namespace Prism
|
||||
if (ImGui::IsItemClicked())
|
||||
{
|
||||
std::string filename = Application::Get().OpenFile("");
|
||||
if (filename != "")
|
||||
m_NormalInput.TextureMap.reset(Texture2D::Create(filename));
|
||||
if (!filename.empty())
|
||||
m_NormalInput.TextureMap = Texture2D::Create(filename);
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
@ -633,8 +553,8 @@ namespace Prism
|
||||
if (ImGui::IsItemClicked())
|
||||
{
|
||||
std::string filename = Application::Get().OpenFile("");
|
||||
if (filename != "")
|
||||
m_MetalnessInput.TextureMap.reset(Texture2D::Create(filename));
|
||||
if (!filename.empty())
|
||||
m_MetalnessInput.TextureMap = Texture2D::Create(filename);
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
@ -666,8 +586,8 @@ namespace Prism
|
||||
if (ImGui::IsItemClicked())
|
||||
{
|
||||
std::string filename = Application::Get().OpenFile("");
|
||||
if (filename != "")
|
||||
m_RoughnessInput.TextureMap.reset(Texture2D::Create(filename));
|
||||
if (!filename.empty())
|
||||
m_RoughnessInput.TextureMap = Texture2D::Create(filename);
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
@ -701,42 +621,25 @@ namespace Prism
|
||||
ImGui::Begin("Viewport");
|
||||
auto viewportSize = ImGui::GetContentRegionAvail();
|
||||
|
||||
m_GeoPass->GetSpecification().TargetFramebuffer->Resize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
||||
m_CompositePass->GetSpecification().TargetFramebuffer->Resize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
||||
|
||||
// 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((ImTextureRef)m_CompositePass->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID(), viewportSize, { 0, 1 }, { 1, 0 });
|
||||
SceneRenderer::SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
||||
m_ActiveScene->GetCamera().SetProjectionMatrix(glm::perspectiveFov(glm::radians(45.0f), viewportSize.x, viewportSize.y, 0.1f, 10000.0f));
|
||||
m_ActiveScene->GetCamera().SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
||||
ImGui::Image((ImTextureRef)SceneRenderer::GetFinalColorBufferRendererID(), viewportSize, { 0, 1 }, { 1, 0 });
|
||||
|
||||
// ImGuizmo
|
||||
if (m_GizmoType != -1)
|
||||
{
|
||||
const float rw = (float)ImGui::GetWindowWidth();
|
||||
const float rh = (float)ImGui::GetWindowHeight();
|
||||
const auto rw = (float)ImGui::GetWindowWidth();
|
||||
const auto rh = (float)ImGui::GetWindowHeight();
|
||||
ImGuizmo::SetOrthographic(false);
|
||||
ImGuizmo::SetDrawlist();
|
||||
ImGuizmo::SetRect(ImGui::GetWindowPos().x, ImGui::GetWindowPos().y, rw, rh);
|
||||
ImGuizmo::Manipulate(glm::value_ptr(m_Camera.GetViewMatrix()), glm::value_ptr(m_Camera.GetProjectionMatrix()), (ImGuizmo::OPERATION)m_GizmoType, ImGuizmo::LOCAL, glm::value_ptr(m_Transform));
|
||||
const auto& camera = m_ActiveScene->GetCamera();
|
||||
ImGuizmo::Manipulate(glm::value_ptr(camera.GetViewMatrix()), glm::value_ptr(camera.GetProjectionMatrix()), (ImGuizmo::OPERATION)m_GizmoType, ImGuizmo::LOCAL, glm::value_ptr(m_MeshEntity->Transform()));
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -6,120 +6,110 @@
|
||||
#define EDITORLAYER_H
|
||||
|
||||
#include "Prism.h"
|
||||
#include "Prism/Editor/SceneHierachyPanel.h"
|
||||
|
||||
namespace Prism
|
||||
{
|
||||
class EditorLayer : public Layer
|
||||
{
|
||||
public:
|
||||
EditorLayer();
|
||||
virtual ~EditorLayer();
|
||||
|
||||
virtual void OnAttach() override;
|
||||
virtual void OnDetach() override;
|
||||
virtual void OnUpdate(TimeStep deltaTime) override;
|
||||
virtual void OnImGuiRender() override;
|
||||
virtual void OnEvent(Event& e) override;
|
||||
|
||||
private:
|
||||
bool OnKeyPressedEvent(KeyPressedEvent& e);
|
||||
|
||||
private:
|
||||
float m_ClearColor[4];
|
||||
|
||||
// Ref<FrameBuffer> m_Framebuffer, m_FinalPresentBuffer;
|
||||
Ref<RenderPass> m_GeoPass, m_CompositePass;
|
||||
|
||||
/*
|
||||
Ref<VertexBuffer> m_VertexBuffer;
|
||||
Ref<IndexBuffer> m_IndexBuffer;
|
||||
*/
|
||||
Ref<VertexArray> m_FullscreenQuadVertexArray;
|
||||
Ref<TextureCube> m_EnvironmentCubeMap, m_EnvironmentIrradiance;
|
||||
|
||||
Camera m_Camera;
|
||||
|
||||
Ref<Shader> m_QuadShader;
|
||||
Ref<Shader> m_HDRShader;
|
||||
Ref<Shader> m_GridShader;
|
||||
Ref<Mesh> m_Mesh;
|
||||
Ref<Mesh> m_SphereMesh, m_PlaneMesh;
|
||||
Ref<Texture2D> m_BRDFLUT;
|
||||
|
||||
Ref<MaterialInstance> m_MeshMaterial;
|
||||
Ref<MaterialInstance> m_GridMaterial;
|
||||
|
||||
std::vector<Ref<MaterialInstance>> m_MetalSphereMaterialInstances;
|
||||
std::vector<Ref<MaterialInstance>> m_DielectricSphereMaterialInstances;
|
||||
|
||||
float m_GridScale = 16.025f, m_GridSize = 0.025f;
|
||||
float m_MeshScale = 1.0f;
|
||||
|
||||
Ref<Shader> m_Shader;
|
||||
Ref<Shader> m_PBRShader;
|
||||
|
||||
// Imguizmo
|
||||
int m_GizmoType = -1; // -1 = no gizmo
|
||||
glm::mat4 m_Transform;
|
||||
|
||||
|
||||
struct AlbedoInput
|
||||
class EditorLayer : public Layer
|
||||
{
|
||||
glm::vec3 Color = { 0.972f, 0.96f, 0.915f }; // Silver, from https://docs.unrealengine.com/en-us/Engine/Rendering/Materials/PhysicallyBased
|
||||
Ref<Texture2D> TextureMap;
|
||||
bool SRGB = true;
|
||||
bool UseTexture = false;
|
||||
public:
|
||||
EditorLayer();
|
||||
virtual ~EditorLayer();
|
||||
|
||||
virtual void OnAttach() override;
|
||||
virtual void OnDetach() override;
|
||||
virtual void OnUpdate(TimeStep deltaTime) override;
|
||||
virtual void OnImGuiRender() override;
|
||||
virtual void OnEvent(Event& e) override;
|
||||
|
||||
private:
|
||||
bool OnKeyPressedEvent(KeyPressedEvent& e);
|
||||
|
||||
private:
|
||||
Scope<SceneHierarchyPanel> m_SceneHierarchyPanel;
|
||||
|
||||
Ref<Scene> m_Scene;
|
||||
Ref<Scene> m_SphereScene;
|
||||
Ref<Scene> m_ActiveScene;
|
||||
|
||||
Entity* m_MeshEntity = nullptr;
|
||||
|
||||
Ref<Shader> m_BrushShader;
|
||||
Ref<Mesh> m_PlaneMesh;
|
||||
Ref<Material> m_SphereBaseMaterial;
|
||||
|
||||
Ref<Material> m_MeshMaterial;
|
||||
|
||||
Ref<RenderPass> m_GeoPass, m_CompositePass;
|
||||
|
||||
Ref<MaterialInstance> m_GridMaterial;
|
||||
|
||||
std::vector<Ref<MaterialInstance>> m_MetalSphereMaterialInstances;
|
||||
std::vector<Ref<MaterialInstance>> m_DielectricSphereMaterialInstances;
|
||||
|
||||
float m_GridScale = 16.025f, m_GridSize = 0.025f;
|
||||
float m_MeshScale = 1.0f;
|
||||
|
||||
|
||||
// Imguizmo
|
||||
int m_GizmoType = -1; // -1 = no gizmo
|
||||
|
||||
|
||||
struct AlbedoInput
|
||||
{
|
||||
glm::vec3 Color = { 0.972f, 0.96f, 0.915f }; // Silver, from https://docs.unrealengine.com/en-us/Engine/Rendering/Materials/PhysicallyBased
|
||||
Ref<Texture2D> TextureMap;
|
||||
bool SRGB = true;
|
||||
bool UseTexture = false;
|
||||
};
|
||||
AlbedoInput m_AlbedoInput;
|
||||
|
||||
struct NormalInput
|
||||
{
|
||||
Ref<Texture2D> TextureMap;
|
||||
bool UseTexture = false;
|
||||
};
|
||||
NormalInput m_NormalInput;
|
||||
|
||||
struct MetalnessInput
|
||||
{
|
||||
float Value = 1.0f;
|
||||
Ref<Texture2D> TextureMap;
|
||||
bool UseTexture = false;
|
||||
};
|
||||
MetalnessInput m_MetalnessInput;
|
||||
|
||||
struct RoughnessInput
|
||||
{
|
||||
float Value = 0.5f;
|
||||
Ref<Texture2D> TextureMap;
|
||||
bool UseTexture = false;
|
||||
};
|
||||
RoughnessInput m_RoughnessInput;
|
||||
|
||||
|
||||
struct Light
|
||||
{
|
||||
glm::vec3 Direction;
|
||||
glm::vec3 Radiance;
|
||||
};
|
||||
Light m_Light;
|
||||
float m_LightMultiplier = 0.3f;
|
||||
|
||||
// PBR params
|
||||
bool m_RadiancePrefilter = false;
|
||||
|
||||
float m_EnvMapRotation = 0.0f;
|
||||
|
||||
enum class SceneType : uint32_t
|
||||
{
|
||||
Spheres = 0, Model = 1
|
||||
};
|
||||
SceneType m_SceneType;
|
||||
|
||||
// Editor resources
|
||||
Ref<Texture2D> m_CheckerboardTex;
|
||||
};
|
||||
AlbedoInput m_AlbedoInput;
|
||||
|
||||
struct NormalInput
|
||||
{
|
||||
Ref<Texture2D> TextureMap;
|
||||
bool UseTexture = false;
|
||||
};
|
||||
NormalInput m_NormalInput;
|
||||
|
||||
struct MetalnessInput
|
||||
{
|
||||
float Value = 1.0f;
|
||||
Ref<Texture2D> TextureMap;
|
||||
bool UseTexture = false;
|
||||
};
|
||||
MetalnessInput m_MetalnessInput;
|
||||
|
||||
struct RoughnessInput
|
||||
{
|
||||
float Value = 0.5f;
|
||||
Ref<Texture2D> TextureMap;
|
||||
bool UseTexture = false;
|
||||
};
|
||||
RoughnessInput m_RoughnessInput;
|
||||
|
||||
|
||||
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
|
||||
Ref<Texture2D> m_CheckerboardTex;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
BIN
Editor/assets/env/birchwood_4k.hdr
vendored
Normal file
BIN
Editor/assets/env/birchwood_4k.hdr
vendored
Normal file
Binary file not shown.
BIN
Editor/assets/meshes/Sphere1m.fbx
Normal file
BIN
Editor/assets/meshes/Sphere1m.fbx
Normal file
Binary file not shown.
BIN
Editor/assets/meshes/cerberus/Cerberus.blend
Normal file
BIN
Editor/assets/meshes/cerberus/Cerberus.blend
Normal file
Binary file not shown.
BIN
Editor/assets/meshes/cerberus/Cerberus.blend1
Normal file
BIN
Editor/assets/meshes/cerberus/Cerberus.blend1
Normal file
Binary file not shown.
BIN
Editor/assets/meshes/cerberus/CerberusMaterials.fbx
Normal file
BIN
Editor/assets/meshes/cerberus/CerberusMaterials.fbx
Normal file
Binary file not shown.
BIN
Editor/assets/meshes/cerberus/Textures/Cerberus_A.png
Normal file
BIN
Editor/assets/meshes/cerberus/Textures/Cerberus_A.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 MiB |
BIN
Editor/assets/meshes/cerberus/Textures/Cerberus_M.png
Normal file
BIN
Editor/assets/meshes/cerberus/Textures/Cerberus_M.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.5 MiB |
BIN
Editor/assets/meshes/cerberus/Textures/Cerberus_N.png
Normal file
BIN
Editor/assets/meshes/cerberus/Textures/Cerberus_N.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 MiB |
BIN
Editor/assets/meshes/cerberus/Textures/Cerberus_R.png
Normal file
BIN
Editor/assets/meshes/cerberus/Textures/Cerberus_R.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 MiB |
BIN
Editor/assets/meshes/cerberus/cerberus.fbx
Normal file
BIN
Editor/assets/meshes/cerberus/cerberus.fbx
Normal file
Binary file not shown.
BIN
Editor/assets/models/m1911/M1911.blend
Normal file
BIN
Editor/assets/models/m1911/M1911.blend
Normal file
Binary file not shown.
BIN
Editor/assets/models/m1911/M1911.blend1
Normal file
BIN
Editor/assets/models/m1911/M1911.blend1
Normal file
Binary file not shown.
BIN
Editor/assets/models/m1911/M1911Materials.fbx
Normal file
BIN
Editor/assets/models/m1911/M1911Materials.fbx
Normal file
Binary file not shown.
71
Editor/assets/models/m1911/imgui.ini
Normal file
71
Editor/assets/models/m1911/imgui.ini
Normal file
@ -0,0 +1,71 @@
|
||||
[Window][DockSpace Demo]
|
||||
Pos=0,0
|
||||
Size=2560,1387
|
||||
Collapsed=0
|
||||
|
||||
[Window][Debug##Default]
|
||||
Pos=55,90
|
||||
Size=400,400
|
||||
Collapsed=0
|
||||
|
||||
[Window][Renderer]
|
||||
Pos=2047,1141
|
||||
Size=285,134
|
||||
Collapsed=0
|
||||
|
||||
[Window][Model]
|
||||
Pos=1772,24
|
||||
Size=788,577
|
||||
Collapsed=0
|
||||
DockId=0x00000001,0
|
||||
|
||||
[Window][Environment]
|
||||
Pos=1772,603
|
||||
Size=788,784
|
||||
Collapsed=0
|
||||
DockId=0x00000002,0
|
||||
|
||||
[Window][Viewport]
|
||||
Pos=421,24
|
||||
Size=1349,1363
|
||||
Collapsed=0
|
||||
DockId=0x00000003,0
|
||||
|
||||
[Window][Mesh Debug]
|
||||
Pos=2055,471
|
||||
Size=505,916
|
||||
Collapsed=0
|
||||
DockId=0x00000002,1
|
||||
|
||||
[Window][ImGui Demo]
|
||||
ViewportPos=276,66
|
||||
ViewportId=0x080FC883
|
||||
Size=1923,1168
|
||||
Collapsed=0
|
||||
|
||||
[Window][Mesh Hierarchy]
|
||||
Pos=0,24
|
||||
Size=419,1363
|
||||
Collapsed=0
|
||||
DockId=0x00000005,1
|
||||
|
||||
[Window][Scene Hierarchy]
|
||||
Pos=0,24
|
||||
Size=419,1363
|
||||
Collapsed=0
|
||||
DockId=0x00000005,0
|
||||
|
||||
[Window][Properties]
|
||||
Pos=107,1086
|
||||
Size=188,127
|
||||
Collapsed=0
|
||||
|
||||
[Docking][Data]
|
||||
DockSpace ID=0xFA06BC56 Window=0x4647B76E Pos=0,47 Size=2560,1363 Split=X
|
||||
DockNode ID=0x00000005 Parent=0xFA06BC56 SizeRef=419,1363 Selected=0x9A68760C
|
||||
DockNode ID=0x00000006 Parent=0xFA06BC56 SizeRef=2139,1363 Split=X
|
||||
DockNode ID=0x00000003 Parent=0x00000006 SizeRef=1349,876 CentralNode=1 HiddenTabBar=1 Selected=0x995B0CF8
|
||||
DockNode ID=0x00000004 Parent=0x00000006 SizeRef=788,876 Split=Y Selected=0x16545DDD
|
||||
DockNode ID=0x00000001 Parent=0x00000004 SizeRef=705,577 Selected=0x16545DDD
|
||||
DockNode ID=0x00000002 Parent=0x00000004 SizeRef=705,784 Selected=0xC0BA51F5
|
||||
|
||||
103
Editor/assets/shaders/EnvironmentIrradiance.glsl
Normal file
103
Editor/assets/shaders/EnvironmentIrradiance.glsl
Normal file
@ -0,0 +1,103 @@
|
||||
#type compute
|
||||
#version 450 core
|
||||
// Physically Based Rendering
|
||||
// Copyright (c) 2017-2018 Michał Siejak
|
||||
|
||||
// Computes diffuse irradiance cubemap convolution for image-based lighting.
|
||||
// Uses quasi Monte Carlo sampling with Hammersley sequence.
|
||||
|
||||
const float PI = 3.141592;
|
||||
const float TwoPI = 2 * PI;
|
||||
const float Epsilon = 0.00001;
|
||||
|
||||
const uint NumSamples = 64 * 1024;
|
||||
const float InvNumSamples = 1.0 / float(NumSamples);
|
||||
|
||||
layout(binding=0) uniform samplerCube inputTexture;
|
||||
layout(binding=0, rgba16f) restrict writeonly uniform imageCube outputTexture;
|
||||
|
||||
// Compute Van der Corput radical inverse
|
||||
// See: http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
|
||||
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
|
||||
}
|
||||
|
||||
// Sample i-th point from Hammersley point set of NumSamples points total.
|
||||
vec2 sampleHammersley(uint i)
|
||||
{
|
||||
return vec2(i * InvNumSamples, radicalInverse_VdC(i));
|
||||
}
|
||||
|
||||
// Uniformly sample point on a hemisphere.
|
||||
// Cosine-weighted sampling would be a better fit for Lambertian BRDF but since this
|
||||
// compute shader runs only once as a pre-processing step performance is not *that* important.
|
||||
// See: "Physically Based Rendering" 2nd ed., section 13.6.1.
|
||||
vec3 sampleHemisphere(float u1, float u2)
|
||||
{
|
||||
const float u1p = sqrt(max(0.0, 1.0 - u1*u1));
|
||||
return vec3(cos(TwoPI*u2) * u1p, sin(TwoPI*u2) * u1p, u1);
|
||||
}
|
||||
|
||||
vec3 GetCubeMapTexCoord()
|
||||
{
|
||||
vec2 st = gl_GlobalInvocationID.xy / vec2(imageSize(outputTexture));
|
||||
vec2 uv = 2.0 * vec2(st.x, 1.0 - st.y) - vec2(1.0);
|
||||
|
||||
vec3 ret;
|
||||
if (gl_GlobalInvocationID.z == 0) ret = vec3( 1.0, uv.y, -uv.x);
|
||||
else if (gl_GlobalInvocationID.z == 1) ret = vec3( -1.0, uv.y, uv.x);
|
||||
else if (gl_GlobalInvocationID.z == 2) ret = vec3( uv.x, 1.0, -uv.y);
|
||||
else if (gl_GlobalInvocationID.z == 3) ret = vec3( uv.x, -1.0, uv.y);
|
||||
else if (gl_GlobalInvocationID.z == 4) ret = vec3( uv.x, uv.y, 1.0);
|
||||
else if (gl_GlobalInvocationID.z == 5) ret = vec3(-uv.x, uv.y, -1.0);
|
||||
return normalize(ret);
|
||||
}
|
||||
|
||||
// Compute orthonormal basis for converting from tanget/shading space to world space.
|
||||
void computeBasisVectors(const vec3 N, out vec3 S, out vec3 T)
|
||||
{
|
||||
// Branchless select non-degenerate T.
|
||||
T = cross(N, vec3(0.0, 1.0, 0.0));
|
||||
T = mix(cross(N, vec3(1.0, 0.0, 0.0)), T, step(Epsilon, dot(T, T)));
|
||||
|
||||
T = normalize(T);
|
||||
S = normalize(cross(N, T));
|
||||
}
|
||||
|
||||
// Convert point from tangent/shading space to world space.
|
||||
vec3 tangentToWorld(const vec3 v, const vec3 N, const vec3 S, const vec3 T)
|
||||
{
|
||||
return S * v.x + T * v.y + N * v.z;
|
||||
}
|
||||
|
||||
layout(local_size_x=32, local_size_y=32, local_size_z=1) in;
|
||||
void main(void)
|
||||
{
|
||||
vec3 N = GetCubeMapTexCoord();
|
||||
|
||||
vec3 S, T;
|
||||
computeBasisVectors(N, S, T);
|
||||
|
||||
// Monte Carlo integration of hemispherical irradiance.
|
||||
// As a small optimization this also includes Lambertian BRDF assuming perfectly white surface (albedo of 1.0)
|
||||
// so we don't need to normalize in PBR fragment shader (so technically it encodes exitant radiance rather than irradiance).
|
||||
vec3 irradiance = vec3(0);
|
||||
for(uint i = 0; i < NumSamples; i++)
|
||||
{
|
||||
vec2 u = sampleHammersley(i);
|
||||
vec3 Li = tangentToWorld(sampleHemisphere(u.x, u.y), N, S, T);
|
||||
float cosTheta = max(0.0, dot(Li, N));
|
||||
|
||||
// PIs here cancel out because of division by pdf.
|
||||
irradiance += 2.0 * textureLod(inputTexture, Li, 0).rgb * cosTheta;
|
||||
}
|
||||
irradiance /= vec3(NumSamples);
|
||||
|
||||
imageStore(outputTexture, ivec3(gl_GlobalInvocationID), vec4(irradiance, 1.0));
|
||||
}
|
||||
159
Editor/assets/shaders/EnvironmentMipFilter.glsl
Normal file
159
Editor/assets/shaders/EnvironmentMipFilter.glsl
Normal file
@ -0,0 +1,159 @@
|
||||
#type compute
|
||||
#version 450 core
|
||||
// Physically Based Rendering
|
||||
// Copyright (c) 2017-2018 Michał Siejak
|
||||
|
||||
// Pre-filters environment cube map using GGX NDF importance sampling.
|
||||
// Part of specular IBL split-sum approximation.
|
||||
|
||||
const float PI = 3.141592;
|
||||
const float TwoPI = 2 * PI;
|
||||
const float Epsilon = 0.00001;
|
||||
|
||||
const uint NumSamples = 1024;
|
||||
const float InvNumSamples = 1.0 / float(NumSamples);
|
||||
|
||||
const int NumMipLevels = 1;
|
||||
layout(binding = 0) uniform samplerCube inputTexture;
|
||||
layout(binding = 0, rgba16f) restrict writeonly uniform imageCube outputTexture[NumMipLevels];
|
||||
|
||||
// Roughness value to pre-filter for.
|
||||
layout(location=0) uniform float roughness;
|
||||
|
||||
#define PARAM_LEVEL 0
|
||||
#define PARAM_ROUGHNESS roughness
|
||||
|
||||
// Compute Van der Corput radical inverse
|
||||
// See: http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
|
||||
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
|
||||
}
|
||||
|
||||
// Sample i-th point from Hammersley point set of NumSamples points total.
|
||||
vec2 sampleHammersley(uint i)
|
||||
{
|
||||
return vec2(i * InvNumSamples, radicalInverse_VdC(i));
|
||||
}
|
||||
|
||||
// Importance sample GGX normal distribution function for a fixed roughness value.
|
||||
// This returns normalized half-vector between Li & Lo.
|
||||
// For derivation see: http://blog.tobias-franke.eu/2014/03/30/notes_on_importance_sampling.html
|
||||
vec3 sampleGGX(float u1, float u2, float roughness)
|
||||
{
|
||||
float alpha = roughness * roughness;
|
||||
|
||||
float cosTheta = sqrt((1.0 - u2) / (1.0 + (alpha*alpha - 1.0) * u2));
|
||||
float sinTheta = sqrt(1.0 - cosTheta*cosTheta); // Trig. identity
|
||||
float phi = TwoPI * u1;
|
||||
|
||||
// Convert to Cartesian upon return.
|
||||
return vec3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
vec3 GetCubeMapTexCoord()
|
||||
{
|
||||
vec2 st = gl_GlobalInvocationID.xy / vec2(imageSize(outputTexture[PARAM_LEVEL]));
|
||||
vec2 uv = 2.0 * vec2(st.x, 1.0 - st.y) - vec2(1.0);
|
||||
|
||||
vec3 ret;
|
||||
if (gl_GlobalInvocationID.z == 0) ret = vec3( 1.0, uv.y, -uv.x);
|
||||
else if (gl_GlobalInvocationID.z == 1) ret = vec3( -1.0, uv.y, uv.x);
|
||||
else if (gl_GlobalInvocationID.z == 2) ret = vec3( uv.x, 1.0, -uv.y);
|
||||
else if (gl_GlobalInvocationID.z == 3) ret = vec3( uv.x, -1.0, uv.y);
|
||||
else if (gl_GlobalInvocationID.z == 4) ret = vec3( uv.x, uv.y, 1.0);
|
||||
else if (gl_GlobalInvocationID.z == 5) ret = vec3(-uv.x, uv.y, -1.0);
|
||||
return normalize(ret);
|
||||
}
|
||||
|
||||
// Compute orthonormal basis for converting from tanget/shading space to world space.
|
||||
void computeBasisVectors(const vec3 N, out vec3 S, out vec3 T)
|
||||
{
|
||||
// Branchless select non-degenerate T.
|
||||
T = cross(N, vec3(0.0, 1.0, 0.0));
|
||||
T = mix(cross(N, vec3(1.0, 0.0, 0.0)), T, step(Epsilon, dot(T, T)));
|
||||
|
||||
T = normalize(T);
|
||||
S = normalize(cross(N, T));
|
||||
}
|
||||
|
||||
// Convert point from tangent/shading space to world space.
|
||||
vec3 tangentToWorld(const vec3 v, const vec3 N, const vec3 S, const vec3 T)
|
||||
{
|
||||
return S * v.x + T * v.y + N * v.z;
|
||||
}
|
||||
|
||||
layout(local_size_x=32, local_size_y=32, local_size_z=1) in;
|
||||
void main(void)
|
||||
{
|
||||
// Make sure we won't write past output when computing higher mipmap levels.
|
||||
ivec2 outputSize = imageSize(outputTexture[PARAM_LEVEL]);
|
||||
if(gl_GlobalInvocationID.x >= outputSize.x || gl_GlobalInvocationID.y >= outputSize.y) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Solid angle associated with a single cubemap texel at zero mipmap level.
|
||||
// This will come in handy for importance sampling below.
|
||||
vec2 inputSize = vec2(textureSize(inputTexture, 0));
|
||||
float wt = 4.0 * PI / (6 * inputSize.x * inputSize.y);
|
||||
|
||||
// Approximation: Assume zero viewing angle (isotropic reflections).
|
||||
vec3 N = GetCubeMapTexCoord();
|
||||
vec3 Lo = N;
|
||||
|
||||
vec3 S, T;
|
||||
computeBasisVectors(N, S, T);
|
||||
|
||||
vec3 color = vec3(0);
|
||||
float weight = 0;
|
||||
|
||||
// Convolve environment map using GGX NDF importance sampling.
|
||||
// Weight by cosine term since Epic claims it generally improves quality.
|
||||
for(uint i = 0; i < NumSamples; i++) {
|
||||
vec2 u = sampleHammersley(i);
|
||||
vec3 Lh = tangentToWorld(sampleGGX(u.x, u.y, PARAM_ROUGHNESS), N, S, T);
|
||||
|
||||
// Compute incident direction (Li) by reflecting viewing direction (Lo) around half-vector (Lh).
|
||||
vec3 Li = 2.0 * dot(Lo, Lh) * Lh - Lo;
|
||||
|
||||
float cosLi = dot(N, Li);
|
||||
if(cosLi > 0.0) {
|
||||
// Use Mipmap Filtered Importance Sampling to improve convergence.
|
||||
// See: https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch20.html, section 20.4
|
||||
|
||||
float cosLh = max(dot(N, Lh), 0.0);
|
||||
|
||||
// GGX normal distribution function (D term) probability density function.
|
||||
// Scaling by 1/4 is due to change of density in terms of Lh to Li (and since N=V, rest of the scaling factor cancels out).
|
||||
float pdf = ndfGGX(cosLh, PARAM_ROUGHNESS) * 0.25;
|
||||
|
||||
// Solid angle associated with this sample.
|
||||
float ws = 1.0 / (NumSamples * pdf);
|
||||
|
||||
// Mip level to sample from.
|
||||
float mipLevel = max(0.5 * log2(ws / wt) + 1.0, 0.0);
|
||||
|
||||
color += textureLod(inputTexture, Li, mipLevel).rgb * cosLi;
|
||||
weight += cosLi;
|
||||
}
|
||||
}
|
||||
color /= weight;
|
||||
|
||||
imageStore(outputTexture[PARAM_LEVEL], ivec3(gl_GlobalInvocationID), vec4(color, 1.0));
|
||||
}
|
||||
39
Editor/assets/shaders/EquirectangularToCubeMap.glsl
Normal file
39
Editor/assets/shaders/EquirectangularToCubeMap.glsl
Normal file
@ -0,0 +1,39 @@
|
||||
#type compute
|
||||
#version 450 core
|
||||
|
||||
// Converts equirectangular (lat-long) projection texture into a cubemap
|
||||
|
||||
const float PI = 3.141592;
|
||||
|
||||
layout(binding = 0) uniform sampler2D u_EquirectangularTex;
|
||||
layout(binding = 0, rgba16f) restrict writeonly uniform imageCube o_CubeMap;
|
||||
|
||||
vec3 GetCubeMapTexCoord()
|
||||
{
|
||||
vec2 st = gl_GlobalInvocationID.xy / vec2(imageSize(o_CubeMap));
|
||||
vec2 uv = 2.0 * vec2(st.x, 1.0 - st.y) - vec2(1.0);
|
||||
|
||||
vec3 ret;
|
||||
if (gl_GlobalInvocationID.z == 0) ret = vec3( 1.0, uv.y, -uv.x);
|
||||
else if (gl_GlobalInvocationID.z == 1) ret = vec3( -1.0, uv.y, uv.x);
|
||||
else if (gl_GlobalInvocationID.z == 2) ret = vec3( uv.x, 1.0, -uv.y);
|
||||
else if (gl_GlobalInvocationID.z == 3) ret = vec3( uv.x, -1.0, uv.y);
|
||||
else if (gl_GlobalInvocationID.z == 4) ret = vec3( uv.x, uv.y, 1.0);
|
||||
else if (gl_GlobalInvocationID.z == 5) ret = vec3(-uv.x, uv.y, -1.0);
|
||||
return normalize(ret);
|
||||
}
|
||||
|
||||
layout(local_size_x = 32, local_size_y = 32, local_size_z = 1) in;
|
||||
void main()
|
||||
{
|
||||
vec3 cubeTC = GetCubeMapTexCoord();
|
||||
|
||||
// Calculate sampling coords for equirectangular texture
|
||||
// https://en.wikipedia.org/wiki/Spherical_coordinate_system#Cartesian_coordinates
|
||||
float phi = atan(cubeTC.z, cubeTC.x);
|
||||
float theta = acos(cubeTC.y);
|
||||
vec2 uv = vec2(phi / (2.0 * PI) + 0.5, theta / PI);
|
||||
|
||||
vec4 color = texture(u_EquirectangularTex, uv);
|
||||
imageStore(o_CubeMap, ivec3(gl_GlobalInvocationID), color);
|
||||
}
|
||||
@ -1,18 +1,19 @@
|
||||
// Simple Texture Shader
|
||||
// Grid Shader
|
||||
|
||||
#type vertex
|
||||
#version 430
|
||||
|
||||
layout(location = 0) in vec3 a_Position;
|
||||
layout(location = 4) in vec2 a_TexCoord;
|
||||
layout(location = 1) in vec2 a_TexCoord;
|
||||
|
||||
uniform mat4 u_MVP;
|
||||
uniform mat4 u_ViewProjection;
|
||||
uniform mat4 u_Transform;
|
||||
|
||||
out vec2 v_TexCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 position = u_MVP * vec4(a_Position, 1.0);
|
||||
vec4 position = u_ViewProjection * u_Transform * vec4(a_Position, 1.0);
|
||||
gl_Position = position;
|
||||
|
||||
v_TexCoord = a_TexCoord;
|
||||
@ -28,11 +29,6 @@ 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);
|
||||
|
||||
@ -22,7 +22,7 @@ layout(location = 5) in ivec4 a_BoneIndices;
|
||||
layout(location = 6) in vec4 a_BoneWeights;
|
||||
|
||||
uniform mat4 u_ViewProjectionMatrix;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform mat4 u_Transform;
|
||||
|
||||
const int MAX_BONES = 100;
|
||||
uniform mat4 u_BoneTransforms[100];
|
||||
@ -38,21 +38,20 @@ out VertexOutput
|
||||
|
||||
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];
|
||||
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.WorldPosition = vec3(u_Transform * 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.WorldNormals = mat3(u_Transform) * 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;
|
||||
gl_Position = u_ViewProjectionMatrix * u_Transform * localPosition;
|
||||
}
|
||||
|
||||
#type fragment
|
||||
@ -63,7 +62,6 @@ const float Epsilon = 0.00001;
|
||||
|
||||
const int LightCount = 1;
|
||||
|
||||
|
||||
// Constant normal incidence Fresnel factor for all dielectrics.
|
||||
const vec3 Fdielectric = vec3(0.04);
|
||||
|
||||
@ -290,12 +288,7 @@ vec3 IBL(vec3 F0, vec3 Lr)
|
||||
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);
|
||||
vec3 specularIrradiance = textureLod(u_EnvRadianceTex, RotateVectorAboutY(u_EnvMapRotation, Lr), (m_Params.Roughness * m_Params.Roughness) * u_EnvRadianceTexLevels).rgb;
|
||||
|
||||
// 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;
|
||||
@ -329,7 +322,7 @@ void main()
|
||||
// Fresnel reflectance, metals use albedo
|
||||
vec3 F0 = mix(Fdielectric, m_Params.Albedo, m_Params.Metalness);
|
||||
|
||||
vec3 lightContribution = Lighting(F0);
|
||||
vec3 lightContribution = vec3(0.0);//Lighting(F0);
|
||||
vec3 iblContribution = IBL(F0, Lr);
|
||||
|
||||
color = vec4(lightContribution + iblContribution, 1.0);
|
||||
319
Editor/assets/shaders/PBRShader_Static.glsl
Normal file
319
Editor/assets/shaders/PBRShader_Static.glsl
Normal file
@ -0,0 +1,319 @@
|
||||
// -----------------------------
|
||||
// -- 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_Transform;
|
||||
|
||||
out VertexOutput
|
||||
{
|
||||
vec3 WorldPosition;
|
||||
vec3 Normal;
|
||||
vec2 TexCoord;
|
||||
mat3 WorldNormals;
|
||||
mat3 WorldTransform;
|
||||
vec3 Binormal;
|
||||
} vs_Output;
|
||||
|
||||
void main()
|
||||
{
|
||||
vs_Output.WorldPosition = vec3(u_Transform * 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_Transform) * mat3(a_Tangent, a_Binormal, a_Normal);
|
||||
vs_Output.WorldTransform = mat3(u_Transform);
|
||||
vs_Output.Binormal = a_Binormal;
|
||||
|
||||
gl_Position = u_ViewProjectionMatrix * u_Transform * 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;
|
||||
mat3 WorldTransform;
|
||||
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 = textureLod(u_EnvRadianceTex, RotateVectorAboutY(u_EnvMapRotation, Lr), (m_Params.Roughness * m_Params.Roughness) * u_EnvRadianceTexLevels).rgb;
|
||||
|
||||
// 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);
|
||||
}
|
||||
33
Editor/assets/shaders/Skybox.glsl
Normal file
33
Editor/assets/shaders/Skybox.glsl
Normal file
@ -0,0 +1,33 @@
|
||||
// Skybox shader
|
||||
|
||||
#type vertex
|
||||
#version 430
|
||||
|
||||
layout(location = 0) in vec3 a_Position;
|
||||
|
||||
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;
|
||||
uniform float u_TextureLod;
|
||||
|
||||
in vec3 v_Position;
|
||||
|
||||
void main()
|
||||
{
|
||||
finalColor = textureLod(u_Texture, v_Position, u_TextureLod);
|
||||
}
|
||||
@ -8,7 +8,7 @@ out vec2 v_TexCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 position = vec4(a_Position.xy, 1.0, 1.0);
|
||||
vec4 position = vec4(a_Position.xy, 0.0, 1.0);
|
||||
v_TexCoord = a_TexCoord;
|
||||
gl_Position = position;
|
||||
}
|
||||
|
||||
@ -22,11 +22,14 @@ void main()
|
||||
|
||||
layout(location = 0) out vec4 finalColor;
|
||||
|
||||
//uniform vec4 u_Color;
|
||||
uniform vec4 u_Color;
|
||||
|
||||
in vec3 v_Normal;
|
||||
|
||||
void main()
|
||||
{
|
||||
finalColor = vec4(0.8, 0.0, 0.8, 1.0);
|
||||
|
||||
|
||||
finalColor = vec4((v_Normal * 0.5 + 0.5), 1.0);// * u_Color.xyz, 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);
|
||||
}
|
||||
BIN
Editor/assets/textures/debug/DebugCubeMap.tga
Normal file
BIN
Editor/assets/textures/debug/DebugCubeMap.tga
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.0 MiB |
Reference in New Issue
Block a user