add mouse picking, add more hdr environment maps

This commit is contained in:
2025-12-02 12:04:12 +08:00
parent c96eb34af5
commit 5251ae22fb
35 changed files with 488 additions and 269 deletions

View File

@ -149,7 +149,7 @@ namespace Prism
auto secondEntity = m_Scene->CreateEntity("Gun Entity");
secondEntity->Transform() = glm::translate(glm::mat4(1.0f), { 5, 5, 5 }) * glm::scale(glm::mat4(1.0f), {10, 10, 10});
mesh = CreateRef<Mesh>("assets/models/m1911/m1911.fbx");
mesh = CreateRef<Mesh>("assets/models/m1911/m1911Materials.fbx");
secondEntity->SetMesh(mesh);
}
@ -208,9 +208,12 @@ namespace Prism
// Editor
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};
// set lights
auto& light = m_Scene->GetLight();
light.Direction = { -0.5f, -0.5f, 1.0f };
light.Radiance = { 1.0f, 1.0f, 1.0f };
m_CurrentlySelectedTransform = &m_MeshEntity->Transform();
}
void EditorLayer::OnDetach()
@ -228,7 +231,6 @@ namespace Prism
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("lights", m_Light);
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);
@ -236,7 +238,8 @@ namespace Prism
m_MeshMaterial->Set("u_EnvMapRotation", m_EnvMapRotation);
m_SphereBaseMaterial->Set("u_AlbedoColor", m_AlbedoInput.Color);
m_SphereBaseMaterial->Set("lights", m_Light);
// m_SphereBaseMaterial->Set("lights", m_Light);
m_SphereBaseMaterial->Set("lights", m_Scene->GetLight());
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);
@ -264,8 +267,19 @@ namespace Prism
Renderer::BeginRenderPass(SceneRenderer::GetFinalRenderPass(), false);
auto viewProj = m_Scene->GetCamera().GetViewProjection();
Renderer2D::BeginScene(viewProj, false);
// Prism::Renderer2D::DrawQuad({ 0, 0, 0 }, { 4.0f, 5.0f }, { 1.0f, 1.0f, 0.5f, 1.0f });
Renderer::DrawAABB(m_MeshEntity->GetMesh());
Renderer::DrawAABB(m_MeshEntity->GetMesh(), m_MeshEntity->Transform());
Renderer2D::EndScene();
Renderer::EndRenderPass();
}
if (!m_SelectedSubmeshes.empty())
{
Renderer::BeginRenderPass(SceneRenderer::GetFinalRenderPass(), false);
const auto viewProj = m_Scene->GetCamera().GetViewProjection();
Renderer2D::BeginScene(viewProj, false);
const auto& submesh = m_SelectedSubmeshes[0];
Renderer::DrawAABB(submesh.Mesh->BoundingBox, m_MeshEntity->GetTransform() * submesh.Mesh->Transform);
Renderer2D::EndScene();
Renderer::EndRenderPass();
}
@ -441,9 +455,10 @@ namespace Prism
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);
auto& light = m_Scene->GetLight();
Property("Light Direction", light.Direction);
Property("Light Radiance", light.Radiance, PropertyFlag::ColorProperty);
Property("Light Multiplier", light.Multiplier, 0.0f, 5.0f);
Property("Exposure", m_ActiveScene->GetCamera().GetExposure(), 0.0f, 5.0f);
Property("Radiance Prefiltering", m_RadiancePrefilter);
@ -642,6 +657,8 @@ namespace Prism
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
ImGui::Begin("Viewport");
auto viewportOffset = ImGui::GetCursorPos(); // includes tab bar
auto viewportSize = ImGui::GetContentRegionAvail();
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));
@ -649,13 +666,19 @@ namespace Prism
ImGui::Image((ImTextureRef)SceneRenderer::GetFinalColorBufferRendererID(), viewportSize, { 0, 1 }, { 1, 0 });
static int counter = 0;
auto windowSize = ImGui::GetWindowSize();
ImVec2 minBound = ImGui::GetWindowPos();
minBound.x += viewportOffset.x;
minBound.y += viewportOffset.y;
ImVec2 maxBound = { minBound.x + windowSize.x, minBound.y + windowSize.y };
m_ViewportBounds[0] = { minBound.x, minBound.y };
m_ViewportBounds[1] = { maxBound.x, maxBound.y };
m_AllowViewportCameraEvents = ImGui::IsMouseHoveringRect(minBound, maxBound);
// ImGuizmo
if (m_GizmoType != -1)
if (m_GizmoType != -1 && m_CurrentlySelectedTransform)
{
const auto rw = (float)ImGui::GetWindowWidth();
const auto rh = (float)ImGui::GetWindowHeight();
@ -663,7 +686,15 @@ namespace Prism
ImGuizmo::SetDrawlist();
ImGuizmo::SetRect(ImGui::GetWindowPos().x, ImGui::GetWindowPos().y, rw, rh);
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()));
bool snap = Input::IsKeyPressed(PM_KEY_LEFT_CONTROL);
ImGuizmo::Manipulate(glm::value_ptr(camera.GetViewMatrix()),
glm::value_ptr(camera.GetProjectionMatrix()),
(ImGuizmo::OPERATION)m_GizmoType,
ImGuizmo::LOCAL,
glm::value_ptr(m_MeshEntity->Transform()),
nullptr,
snap ? &m_SnapValue : nullptr);
}
ImGui::End();
@ -678,6 +709,7 @@ namespace Prism
EventDispatcher dispatcher(e);
dispatcher.Dispatch<KeyPressedEvent>(PM_BIND_EVENT_FN(EditorLayer::OnKeyPressedEvent));
dispatcher.Dispatch<MouseButtonPressedEvent>(PM_BIND_EVENT_FN(EditorLayer::OnMouseButtonPressedEvent));
}
bool EditorLayer::OnKeyPressedEvent(KeyPressedEvent& e)
@ -714,9 +746,85 @@ namespace Prism
return false;
}
bool EditorLayer::OnMouseButtonPressedEvent(MouseButtonPressedEvent& e)
{
auto [mx, my] = Input::GetMousePosition();
if (e.GetMouseButton() == PM_MOUSE_BUTTON_LEFT && !Input::IsKeyPressed(PM_KEY_LEFT_ALT) && !ImGuizmo::IsOver())
{
auto [mouseX, mouseY] = GetMouseViewportSpace();
if (mouseX > -1.0f && mouseX < 1.0f && mouseY > -1.0f && mouseY < 1.0f)
{
auto [origin, direction] = CastRay(mouseX, mouseY);
m_SelectedSubmeshes.clear();
const auto mesh = m_MeshEntity->GetMesh();
auto& submeshes = mesh->GetSubmeshes();
float lastT = std::numeric_limits<float>::max();
for (uint32_t i = 0; i < submeshes.size(); i++)
{
auto& submesh = submeshes[i];
Ray ray = {
glm::inverse(m_MeshEntity->GetTransform() * submesh.Transform) * glm::vec4(origin, 1.0f),
glm::inverse(glm::mat3(m_MeshEntity->GetTransform()) * glm::mat3(submesh.Transform)) * direction
};
float t;
bool intersects = ray.IntersectsAABB(submesh.BoundingBox, t);
if (intersects)
{
const auto& triangleCache = mesh->GetTriangleCache(i);
for (const auto& triangle : triangleCache)
{
if (ray.IntersectsTriangle(triangle.V0.Position, triangle.V1.Position, triangle.V2.Position, t))
{
PM_CLIENT_WARN("INTERSECTION: {0}, t={1}", submesh.NodeName, t);
m_SelectedSubmeshes.push_back({ &submesh, t });
break;
}
}
}
}
std::sort(m_SelectedSubmeshes.begin(), m_SelectedSubmeshes.end(), [](auto& a, auto& b) { return a.Distance < b.Distance; });
// TODO: Handle mesh being deleted, etc.
if (!m_SelectedSubmeshes.empty())
m_CurrentlySelectedTransform = &m_SelectedSubmeshes[0].Mesh->Transform;
else
m_CurrentlySelectedTransform = &m_MeshEntity->Transform();
}
}
return false;
}
void EditorLayer::ShowBoundingBoxes(bool show, bool onTop)
{
SceneRenderer::GetOptions().ShowBoundingBoxes = show && !onTop;
m_DrawOnTopBoundingBoxes = show && onTop;
}
std::pair<float, float> EditorLayer::GetMouseViewportSpace() const
{
auto [mx, my] = ImGui::GetMousePos(); // Input::GetMousePosition();
mx -= m_ViewportBounds[0].x;
my -= m_ViewportBounds[0].y;
const auto viewportWidth = m_ViewportBounds[1].x - m_ViewportBounds[0].x;
const auto viewportHeight = m_ViewportBounds[1].y - m_ViewportBounds[0].y;
return { (mx / viewportWidth) * 2.0f - 1.0f, ((my / viewportHeight) * 2.0f - 1.0f) * -1.0f };
}
std::pair<glm::vec3, glm::vec3> EditorLayer::CastRay(const float mx, const float my) const
{
glm::vec4 mouseClipPos = { mx, my, -1.0f, 1.0f };
const auto inverseProj = glm::inverse(m_Scene->GetCamera().GetProjectionMatrix());
const auto inverseView = glm::inverse(glm::mat3(m_Scene->GetCamera().GetViewMatrix()));
const glm::vec4 ray = inverseProj * mouseClipPos;
glm::vec3 rayPos = m_Scene->GetCamera().GetPosition();
glm::vec3 rayDir = inverseView * glm::vec3(ray);
return { rayPos, rayDir };
}
}

View File

@ -24,9 +24,14 @@ namespace Prism
private:
bool OnKeyPressedEvent(KeyPressedEvent& e);
bool OnMouseButtonPressedEvent(MouseButtonPressedEvent& e);
void ShowBoundingBoxes(bool show, bool onTop = false);
private:
std::pair<float, float> GetMouseViewportSpace() const;
std::pair<glm::vec3, glm::vec3> CastRay(float mx, float my) const;
private:
Scope<SceneHierarchyPanel> m_SceneHierarchyPanel;
@ -36,25 +41,27 @@ namespace Prism
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
glm::vec2 m_ViewportBounds[2];
int m_GizmoType = -1; // -1 = no gizmo
float m_SnapValue = 0.5f;
struct SelectedSubmesh
{
Submesh* Mesh;
float Distance;
};
std::vector<SelectedSubmesh> m_SelectedSubmeshes;
glm::mat4* m_CurrentlySelectedTransform = nullptr;
// configure button
bool m_AllowViewportCameraEvents = false;
@ -97,14 +104,6 @@ namespace Prism
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;

BIN
Editor/assets/env/pink_sunrise_4k.hdr vendored Normal file

Binary file not shown.

BIN
Editor/assets/env/rooitou_park_4k.hdr vendored Normal file

Binary file not shown.

BIN
Editor/assets/env/venice_dawn_1_4k.hdr vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -46,7 +46,7 @@ void main()
vec4 localPosition = boneTransform * vec4(a_Position, 1.0);
vs_Output.WorldPosition = vec3(u_Transform * boneTransform * vec4(a_Position, 1.0));
vs_Output.Normal = mat3(boneTransform) * a_Normal;
vs_Output.Normal = mat3(u_Transform) * mat3(boneTransform) * 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.Binormal = mat3(boneTransform) * a_Binormal;
@ -68,6 +68,7 @@ const vec3 Fdielectric = vec3(0.04);
struct Light {
vec3 Direction;
vec3 Radiance;
float Multiplier;
};
in VertexOutput
@ -256,7 +257,7 @@ vec3 Lighting(vec3 F0)
for(int i = 0; i < LightCount; i++)
{
vec3 Li = -lights.Direction;
vec3 Lradiance = lights.Radiance;
vec3 Lradiance = lights.Radiance * lights.Multiplier;
vec3 Lh = normalize(Li + m_Params.View);
// Calculate angles between surface normal and various light vectors.
@ -288,7 +289,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 = textureLod(u_EnvRadianceTex, RotateVectorAboutY(u_EnvMapRotation, Lr), (m_Params.Roughness * m_Params.Roughness) * u_EnvRadianceTexLevels).rgb;
vec3 specularIrradiance = textureLod(u_EnvRadianceTex, RotateVectorAboutY(u_EnvMapRotation, Lr), (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;
@ -322,7 +323,7 @@ void main()
// Fresnel reflectance, metals use albedo
vec3 F0 = mix(Fdielectric, m_Params.Albedo, m_Params.Metalness);
vec3 lightContribution = vec3(0.0);//Lighting(F0);
vec3 lightContribution = Lighting(F0);
vec3 iblContribution = IBL(F0, Lr);
color = vec4(lightContribution + iblContribution, 1.0);

View File

@ -57,6 +57,7 @@ const vec3 Fdielectric = vec3(0.04);
struct Light {
vec3 Direction;
vec3 Radiance;
float Multiplier;
};
in VertexOutput
@ -246,7 +247,7 @@ vec3 Lighting(vec3 F0)
for(int i = 0; i < LightCount; i++)
{
vec3 Li = -lights.Direction;
vec3 Lradiance = lights.Radiance;
vec3 Lradiance = lights.Radiance * lights.Multiplier;
vec3 Lh = normalize(Li + m_Params.View);
// Calculate angles between surface normal and various light vectors.
@ -271,15 +272,15 @@ vec3 Lighting(vec3 F0)
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 F = fresnelSchlick(F0, m_Params.NdotV);
vec3 F = fresnelSchlickRoughness(F0, m_Params.NdotV, m_Params.Roughness);
// vec3 F = fresnelSchlickR(F0, m_Params.NdotV);
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;
vec3 specularIrradiance = textureLod(u_EnvRadianceTex, RotateVectorAboutY(u_EnvMapRotation, Lr), (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;
@ -317,5 +318,5 @@ void main()
vec3 iblContribution = IBL(F0, Lr);
color = vec4(lightContribution + iblContribution, 1.0);
color = vec4(iblContribution, 1.0);
// color = vec4(iblContribution, 1.0);
}