add material sphere preview, add ssr, improve shadow
This commit is contained in:
@ -15,9 +15,12 @@
|
|||||||
#include "Prism/Core/Input.h"
|
#include "Prism/Core/Input.h"
|
||||||
#include "Prism/Core/Math/Math.h"
|
#include "Prism/Core/Math/Math.h"
|
||||||
#include "Prism/Editor/AssetEditorPanel.h"
|
#include "Prism/Editor/AssetEditorPanel.h"
|
||||||
|
#include "Prism/Editor/DefaultAssetEditors/PBRMaterialAssetEditor.h"
|
||||||
#include "Prism/Editor/PhysicsSettingsWindow.h"
|
#include "Prism/Editor/PhysicsSettingsWindow.h"
|
||||||
|
#include "Prism/Asset/AssetsManager.h"
|
||||||
#include "Prism/Physics/Physics3D.h"
|
#include "Prism/Physics/Physics3D.h"
|
||||||
#include "Prism/Renderer/Renderer2D.h"
|
#include "Prism/Renderer/Renderer2D.h"
|
||||||
|
#include "Prism/Renderer/Renderer3D.h"
|
||||||
#include "Prism/Script/ScriptEngine.h"
|
#include "Prism/Script/ScriptEngine.h"
|
||||||
#include "Prism/Script/ScriptWrappers.h"
|
#include "Prism/Script/ScriptWrappers.h"
|
||||||
|
|
||||||
@ -55,6 +58,7 @@ namespace Prism
|
|||||||
SceneRenderer::GetOptions().ShowGrid = true;
|
SceneRenderer::GetOptions().ShowGrid = true;
|
||||||
|
|
||||||
AssetEditorPanel::RegisterDefaultEditors();
|
AssetEditorPanel::RegisterDefaultEditors();
|
||||||
|
PBRMaterialEditor::InitPreviewRenderer();
|
||||||
FileSystem::StartWatching();
|
FileSystem::StartWatching();
|
||||||
|
|
||||||
m_ConsolePanel = CreateScope<ConsolePanel>();
|
m_ConsolePanel = CreateScope<ConsolePanel>();
|
||||||
@ -73,6 +77,8 @@ namespace Prism
|
|||||||
|
|
||||||
void EditorLayer::OnUpdate(const TimeStep deltaTime)
|
void EditorLayer::OnUpdate(const TimeStep deltaTime)
|
||||||
{
|
{
|
||||||
|
FileSystem::ProcessPendingEvents();
|
||||||
|
|
||||||
auto [x, y] = GetMouseViewportSpace();
|
auto [x, y] = GetMouseViewportSpace();
|
||||||
|
|
||||||
SceneRenderer::SetFocusPoint({ x * 0.5f + 0.5f, y * 0.5f + 0.5f });
|
SceneRenderer::SetFocusPoint({ x * 0.5f + 0.5f, y * 0.5f + 0.5f });
|
||||||
@ -166,6 +172,25 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto editingAsset = PBRMaterialEditor::GetEditingAsset();
|
||||||
|
if (editingAsset && (editingAsset->PreviewIsDirty || !editingAsset->PreviewTexture))
|
||||||
|
{
|
||||||
|
PBRMaterialEditor::RenderMaterialPreview(editingAsset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool renderedPreviewThisFrame = false;
|
||||||
|
AssetsManager::ForEachAsset<PBRMaterialAsset>([&](Ref<PBRMaterialAsset> mat)
|
||||||
|
{
|
||||||
|
if (renderedPreviewThisFrame) return;
|
||||||
|
if (mat->PreviewIsDirty || !mat->PreviewTexture)
|
||||||
|
{
|
||||||
|
PBRMaterialEditor::RenderMaterialPreview(mat);
|
||||||
|
renderedPreviewThisFrame = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorLayer::OnImGuiRender()
|
void EditorLayer::OnImGuiRender()
|
||||||
@ -1484,6 +1509,14 @@ namespace Prism
|
|||||||
|
|
||||||
m_EditorCamera = EditorCamera(glm::perspectiveFov(glm::radians(45.0f), 1280.0f, 720.0f, 0.1f, 1000.0f));
|
m_EditorCamera = EditorCamera(glm::perspectiveFov(glm::radians(45.0f), 1280.0f, 720.0f, 0.1f, 1000.0f));
|
||||||
m_SelectionContext.clear();
|
m_SelectionContext.clear();
|
||||||
|
|
||||||
|
// new Scene with a default sky light
|
||||||
|
auto newEntity = m_EditorScene->CreateEntity("Sky Light");
|
||||||
|
auto& slc = newEntity.AddComponent<SkyLightComponent>();
|
||||||
|
slc.DynamicSky = true;
|
||||||
|
|
||||||
|
Ref<TextureCube> preethamEnv = Renderer3D::CreatePreethamSky(slc.TurbidityAzimuthInclination);
|
||||||
|
slc.SceneEnvironment = Ref<Environment>::Create(preethamEnv, preethamEnv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorLayer::OpenScene()
|
void EditorLayer::OpenScene()
|
||||||
|
|||||||
BIN
Editor/assets/editor/model.png
Normal file
BIN
Editor/assets/editor/model.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
BIN
Editor/assets/editor/texture.png
Normal file
BIN
Editor/assets/editor/texture.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
@ -1,4 +1,4 @@
|
|||||||
// -----------------------------
|
// -----------------------------
|
||||||
// -- Based on Hazel PBR shader --
|
// -- Based on Hazel PBR shader --
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// Note: this shader is still very much in progress. There are likely many bugs and future additions that will go in.
|
// Note: this shader is still very much in progress. There are likely many bugs and future additions that will go in.
|
||||||
@ -28,8 +28,6 @@ uniform mat4 u_ViewProjectionMatrix;
|
|||||||
uniform mat4 u_ViewMatrix;
|
uniform mat4 u_ViewMatrix;
|
||||||
uniform mat4 u_Transform;
|
uniform mat4 u_Transform;
|
||||||
|
|
||||||
uniform mat4 u_LightSpaceMatrix;
|
|
||||||
|
|
||||||
out VertexOutput
|
out VertexOutput
|
||||||
{
|
{
|
||||||
vec3 WorldPosition;
|
vec3 WorldPosition;
|
||||||
@ -39,7 +37,7 @@ out VertexOutput
|
|||||||
mat3 WorldTransform;
|
mat3 WorldTransform;
|
||||||
vec3 Binormal;
|
vec3 Binormal;
|
||||||
vec3 ViewPosition;
|
vec3 ViewPosition;
|
||||||
vec4 FragPosLightSpace;
|
float ViewZ;
|
||||||
} vs_Output;
|
} vs_Output;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
@ -58,9 +56,8 @@ void main()
|
|||||||
vs_Output.WorldTransform = mat3(u_Transform);
|
vs_Output.WorldTransform = mat3(u_Transform);
|
||||||
vs_Output.Binormal = a_Binormal;
|
vs_Output.Binormal = a_Binormal;
|
||||||
|
|
||||||
vs_Output.FragPosLightSpace = u_LightSpaceMatrix * u_Transform * localPosition;
|
|
||||||
|
|
||||||
vs_Output.ViewPosition = vec3(u_ViewMatrix * vec4(vs_Output.WorldPosition, 1.0));
|
vs_Output.ViewPosition = vec3(u_ViewMatrix * vec4(vs_Output.WorldPosition, 1.0));
|
||||||
|
vs_Output.ViewZ = vs_Output.ViewPosition.z;
|
||||||
|
|
||||||
// gl_Position = u_ViewProjectionMatrix * u_Transform * vec4(a_Position, 1.0);
|
// gl_Position = u_ViewProjectionMatrix * u_Transform * vec4(a_Position, 1.0);
|
||||||
gl_Position = u_ViewProjectionMatrix * u_Transform * localPosition;
|
gl_Position = u_ViewProjectionMatrix * u_Transform * localPosition;
|
||||||
@ -76,7 +73,8 @@ const int LightCount = 1;
|
|||||||
const vec3 Fdielectric = vec3(0.04);
|
const vec3 Fdielectric = vec3(0.04);
|
||||||
|
|
||||||
layout(location = 0) out vec4 color;
|
layout(location = 0) out vec4 color;
|
||||||
layout(location = 1) out vec4 o_BloomColor;
|
layout(location = 1) out vec4 o_MaterialInfo;
|
||||||
|
layout(location = 2) out vec4 o_BloomColor;
|
||||||
|
|
||||||
struct DirectionalLight {
|
struct DirectionalLight {
|
||||||
vec3 Direction;
|
vec3 Direction;
|
||||||
@ -113,7 +111,7 @@ in VertexOutput
|
|||||||
mat3 WorldTransform;
|
mat3 WorldTransform;
|
||||||
vec3 Binormal;
|
vec3 Binormal;
|
||||||
vec3 ViewPosition;
|
vec3 ViewPosition;
|
||||||
vec4 FragPosLightSpace;
|
float ViewZ;
|
||||||
} vs_Input;
|
} vs_Input;
|
||||||
|
|
||||||
|
|
||||||
@ -156,7 +154,15 @@ uniform float u_MetalnessTexToggle;
|
|||||||
uniform float u_RoughnessTexToggle;
|
uniform float u_RoughnessTexToggle;
|
||||||
|
|
||||||
// shadow
|
// shadow
|
||||||
uniform sampler2D u_ShadowMap;
|
const int CSM_CASCADE_COUNT = 4;
|
||||||
|
uniform sampler2D u_ShadowMap[4];
|
||||||
|
uniform mat4 u_LightSpaceMatrix0;
|
||||||
|
uniform mat4 u_LightSpaceMatrix1;
|
||||||
|
uniform mat4 u_LightSpaceMatrix2;
|
||||||
|
uniform mat4 u_LightSpaceMatrix3;
|
||||||
|
uniform vec4 u_CascadeSplits;
|
||||||
|
uniform float u_ShadowFar;
|
||||||
|
uniform float u_ShadowNear;
|
||||||
uniform float u_ShadowBias;
|
uniform float u_ShadowBias;
|
||||||
uniform float u_ShadowSoftness;
|
uniform float u_ShadowSoftness;
|
||||||
uniform float u_ShadowIntensity;
|
uniform float u_ShadowIntensity;
|
||||||
@ -362,23 +368,54 @@ vec3 IBL(vec3 F0, vec3 Lr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// shadow
|
// shadow
|
||||||
float calculateShadow(vec4 fragPosLightSpace, vec3 normal, vec3 lightDir)
|
int selectCascade(float viewZ)
|
||||||
{
|
{
|
||||||
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
float depth = -viewZ;
|
||||||
projCoords = projCoords * 0.5 + 0.5;
|
float linearDepth = (depth - u_ShadowNear) / (u_ShadowFar - u_ShadowNear);
|
||||||
|
if (linearDepth < u_CascadeSplits.x) return 0;
|
||||||
|
if (linearDepth < u_CascadeSplits.y) return 1;
|
||||||
|
if (linearDepth < u_CascadeSplits.z) return 2;
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
if (projCoords.z > 1.0 || projCoords.x < 0.0 || projCoords.x > 1.0 ||
|
mat4 getLightSpaceMatrix(int cascade)
|
||||||
projCoords.y < 0.0 || projCoords.y > 1.0)
|
{
|
||||||
return 0.0;
|
if (cascade == 0) return u_LightSpaceMatrix0;
|
||||||
|
else if (cascade == 1) return u_LightSpaceMatrix1;
|
||||||
|
else if (cascade == 2) return u_LightSpaceMatrix2;
|
||||||
|
else return u_LightSpaceMatrix3;
|
||||||
|
}
|
||||||
|
|
||||||
float closestDepth = texture(u_ShadowMap, projCoords.xy).r;
|
float getCascadeSplit(int cascade)
|
||||||
float currentDepth = projCoords.z;
|
{
|
||||||
|
if (cascade == 0) return u_CascadeSplits.x;
|
||||||
|
else if (cascade == 1) return u_CascadeSplits.y;
|
||||||
|
else if (cascade == 2) return u_CascadeSplits.z;
|
||||||
|
else return u_CascadeSplits.w;
|
||||||
|
}
|
||||||
|
|
||||||
float bias = max(u_ShadowBias * (1.0 - dot(normal, lightDir)), u_ShadowBias * 0.1);
|
float sampleShadow(int cascade, vec2 uv, float compareDepth, float bias)
|
||||||
|
{
|
||||||
|
float depth;
|
||||||
|
if (cascade == 0) depth = texture(u_ShadowMap[0], uv).r;
|
||||||
|
else if (cascade == 1) depth = texture(u_ShadowMap[1], uv).r;
|
||||||
|
else if (cascade == 2) depth = texture(u_ShadowMap[2], uv).r;
|
||||||
|
else depth = texture(u_ShadowMap[3], uv).r;
|
||||||
|
return (compareDepth - bias) > depth ? 1.0 : 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 getTexelSize(int cascade)
|
||||||
|
{
|
||||||
|
if (cascade == 0) return 1.0 / vec2(textureSize(u_ShadowMap[0], 0));
|
||||||
|
else if (cascade == 1) return 1.0 / vec2(textureSize(u_ShadowMap[1], 0));
|
||||||
|
else if (cascade == 2) return 1.0 / vec2(textureSize(u_ShadowMap[2], 0));
|
||||||
|
else return 1.0 / vec2(textureSize(u_ShadowMap[3], 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
float pcfShadow(int cascade, vec3 projCoords, float bias)
|
||||||
|
{
|
||||||
|
vec2 texelSize = getTexelSize(cascade);
|
||||||
int pcfRange = clamp(int(u_ShadowSoftness), 0, 3);
|
int pcfRange = clamp(int(u_ShadowSoftness), 0, 3);
|
||||||
|
|
||||||
vec2 texelSize = 1.0 / textureSize(u_ShadowMap, 0);
|
|
||||||
float shadow = 0.0;
|
float shadow = 0.0;
|
||||||
int samples = 0;
|
int samples = 0;
|
||||||
|
|
||||||
@ -387,34 +424,57 @@ float calculateShadow(vec4 fragPosLightSpace, vec3 normal, vec3 lightDir)
|
|||||||
for (int y = -pcfRange; y <= pcfRange; ++y)
|
for (int y = -pcfRange; y <= pcfRange; ++y)
|
||||||
{
|
{
|
||||||
vec2 offset = vec2(x, y) * texelSize;
|
vec2 offset = vec2(x, y) * texelSize;
|
||||||
float pcfDepth = texture(u_ShadowMap, projCoords.xy + offset).r;
|
shadow += sampleShadow(cascade, projCoords.xy + offset, projCoords.z, bias);
|
||||||
shadow += (currentDepth - bias) > pcfDepth ? 1.0 : 0.0;
|
|
||||||
samples++;
|
samples++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
shadow /= float(samples);
|
return shadow / float(samples);
|
||||||
return shadow * u_ShadowIntensity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float calculateCSMShadow(vec3 worldPos, vec3 normal, vec3 lightDir, float viewZ)
|
||||||
float ComputeShadow(vec4 fragPosLightSpace, float NdotL)
|
|
||||||
{
|
{
|
||||||
if (u_ShadowEnabled == 0) return 1.0;
|
int cascade = selectCascade(viewZ);
|
||||||
|
|
||||||
|
vec4 fragPosLightSpace = getLightSpaceMatrix(cascade) * vec4(worldPos, 1.0);
|
||||||
|
|
||||||
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
||||||
projCoords = projCoords * 0.5 + 0.5;
|
projCoords = projCoords * 0.5 + 0.5;
|
||||||
|
|
||||||
if (projCoords.x < 0.0 || projCoords.x > 1.0 ||
|
if (projCoords.z > 1.0 || projCoords.x < 0.0 || projCoords.x > 1.0 ||
|
||||||
projCoords.y < 0.0 || projCoords.y > 1.0 ||
|
projCoords.y < 0.0 || projCoords.y > 1.0)
|
||||||
projCoords.z > 1.0) return 1.0;
|
return 0.0;
|
||||||
|
|
||||||
float closestDepth = texture(u_ShadowMap, projCoords.xy).r;
|
float bias = max(u_ShadowBias * (1.0 - dot(normal, lightDir)), u_ShadowBias * 0.1);
|
||||||
float currentDepth = projCoords.z;
|
float shadow = pcfShadow(cascade, projCoords, bias);
|
||||||
|
|
||||||
float bias = max(u_ShadowBias * (1.0 - NdotL), u_ShadowBias * 0.5);
|
float cascadeEdge = 0.0;
|
||||||
|
if (cascade < CSM_CASCADE_COUNT - 1)
|
||||||
|
{
|
||||||
|
float depth = -viewZ;
|
||||||
|
float linearDepth = (depth - u_ShadowNear) / (u_ShadowFar - u_ShadowNear);
|
||||||
|
float splitDist = getCascadeSplit(cascade);
|
||||||
|
float prevSplit = (cascade > 0) ? getCascadeSplit(cascade - 1) : 0.0;
|
||||||
|
float blendStart = splitDist - (splitDist - prevSplit) * 0.1;
|
||||||
|
if (linearDepth > blendStart)
|
||||||
|
{
|
||||||
|
cascadeEdge = (linearDepth - blendStart) / (splitDist - blendStart);
|
||||||
|
|
||||||
float shadow = (currentDepth - bias) > closestDepth ? 1.0 : 0.0;
|
int nextCascade = cascade + 1;
|
||||||
return mix(1.0, 1.0 - u_ShadowIntensity, shadow);
|
vec4 fragPosNext = getLightSpaceMatrix(nextCascade) * vec4(worldPos, 1.0);
|
||||||
|
|
||||||
|
vec3 projCoordsNext = fragPosNext.xyz / fragPosNext.w;
|
||||||
|
projCoordsNext = projCoordsNext * 0.5 + 0.5;
|
||||||
|
|
||||||
|
if (!(projCoordsNext.z > 1.0 || projCoordsNext.x < 0.0 || projCoordsNext.x > 1.0 ||
|
||||||
|
projCoordsNext.y < 0.0 || projCoordsNext.y > 1.0))
|
||||||
|
{
|
||||||
|
float nextShadow = pcfShadow(nextCascade, projCoordsNext, bias);
|
||||||
|
shadow = mix(shadow, nextShadow, cascadeEdge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return shadow * u_ShadowIntensity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -442,7 +502,7 @@ void main()
|
|||||||
|
|
||||||
float shadowFactor = 1.0;
|
float shadowFactor = 1.0;
|
||||||
if (u_ShadowEnabled > 0.5) {
|
if (u_ShadowEnabled > 0.5) {
|
||||||
float shadow = calculateShadow(vs_Input.FragPosLightSpace, m_Params.Normal, u_DirectionalLights.Direction);
|
float shadow = calculateCSMShadow(vs_Input.WorldPosition, m_Params.Normal, u_DirectionalLights.Direction, vs_Input.ViewZ);
|
||||||
shadowFactor = 1.0 - shadow;
|
shadowFactor = 1.0 - shadow;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,4 +531,6 @@ void main()
|
|||||||
// Bloom
|
// Bloom
|
||||||
float brightness = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
|
float brightness = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
|
||||||
o_BloomColor = brightness > u_BloomThreshold ? color : vec4(0.0, 0.0, 0.0, 1.0);
|
o_BloomColor = brightness > u_BloomThreshold ? color : vec4(0.0, 0.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
o_MaterialInfo = vec4(m_Params.Metalness, m_Params.Roughness, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// -----------------------------
|
// -----------------------------
|
||||||
// -- Based on Hazel PBR shader --
|
// -- Based on Hazel PBR shader --
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// Note: this shader is still very much in progress. There are likely many bugs and future additions that will go in.
|
// Note: this shader is still very much in progress. There are likely many bugs and future additions that will go in.
|
||||||
@ -22,8 +22,6 @@ uniform mat4 u_ViewProjectionMatrix;
|
|||||||
uniform mat4 u_ViewMatrix;
|
uniform mat4 u_ViewMatrix;
|
||||||
uniform mat4 u_Transform;
|
uniform mat4 u_Transform;
|
||||||
|
|
||||||
uniform mat4 u_LightSpaceMatrix;
|
|
||||||
|
|
||||||
out VertexOutput
|
out VertexOutput
|
||||||
{
|
{
|
||||||
vec3 WorldPosition;
|
vec3 WorldPosition;
|
||||||
@ -33,7 +31,7 @@ out VertexOutput
|
|||||||
mat3 WorldTransform;
|
mat3 WorldTransform;
|
||||||
vec3 Binormal;
|
vec3 Binormal;
|
||||||
vec3 ViewPosition;
|
vec3 ViewPosition;
|
||||||
vec4 FragPosLightSpace;
|
float ViewZ;
|
||||||
} vs_Output;
|
} vs_Output;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
@ -45,9 +43,8 @@ void main()
|
|||||||
vs_Output.WorldTransform = mat3(u_Transform);
|
vs_Output.WorldTransform = mat3(u_Transform);
|
||||||
vs_Output.Binormal = a_Binormal;
|
vs_Output.Binormal = a_Binormal;
|
||||||
|
|
||||||
vs_Output.FragPosLightSpace = u_LightSpaceMatrix * u_Transform * vec4(a_Position, 1.0);
|
|
||||||
|
|
||||||
vs_Output.ViewPosition = vec3(u_ViewMatrix * vec4(vs_Output.WorldPosition, 1.0));
|
vs_Output.ViewPosition = vec3(u_ViewMatrix * vec4(vs_Output.WorldPosition, 1.0));
|
||||||
|
vs_Output.ViewZ = vs_Output.ViewPosition.z;
|
||||||
|
|
||||||
gl_Position = u_ViewProjectionMatrix * u_Transform * vec4(a_Position, 1.0);
|
gl_Position = u_ViewProjectionMatrix * u_Transform * vec4(a_Position, 1.0);
|
||||||
}
|
}
|
||||||
@ -62,7 +59,8 @@ const int LightCount = 1;
|
|||||||
const vec3 Fdielectric = vec3(0.04);
|
const vec3 Fdielectric = vec3(0.04);
|
||||||
|
|
||||||
layout(location = 0) out vec4 color;
|
layout(location = 0) out vec4 color;
|
||||||
layout(location = 1) out vec4 o_BloomColor;
|
layout(location = 1) out vec4 o_MaterialInfo;
|
||||||
|
layout(location = 2) out vec4 o_BloomColor;
|
||||||
|
|
||||||
struct DirectionalLight {
|
struct DirectionalLight {
|
||||||
vec3 Direction;
|
vec3 Direction;
|
||||||
@ -100,7 +98,7 @@ in VertexOutput
|
|||||||
mat3 WorldTransform;
|
mat3 WorldTransform;
|
||||||
vec3 Binormal;
|
vec3 Binormal;
|
||||||
vec3 ViewPosition;
|
vec3 ViewPosition;
|
||||||
vec4 FragPosLightSpace;
|
float ViewZ;
|
||||||
} vs_Input;
|
} vs_Input;
|
||||||
|
|
||||||
uniform DirectionalLight u_DirectionalLights;
|
uniform DirectionalLight u_DirectionalLights;
|
||||||
@ -143,7 +141,15 @@ uniform float u_MetalnessTexToggle;
|
|||||||
uniform float u_RoughnessTexToggle;
|
uniform float u_RoughnessTexToggle;
|
||||||
|
|
||||||
// shadow
|
// shadow
|
||||||
uniform sampler2D u_ShadowMap;
|
const int CSM_CASCADE_COUNT = 4;
|
||||||
|
uniform sampler2D u_ShadowMap[4];
|
||||||
|
uniform mat4 u_LightSpaceMatrix0;
|
||||||
|
uniform mat4 u_LightSpaceMatrix1;
|
||||||
|
uniform mat4 u_LightSpaceMatrix2;
|
||||||
|
uniform mat4 u_LightSpaceMatrix3;
|
||||||
|
uniform vec4 u_CascadeSplits;
|
||||||
|
uniform float u_ShadowFar;
|
||||||
|
uniform float u_ShadowNear;
|
||||||
uniform float u_ShadowBias;
|
uniform float u_ShadowBias;
|
||||||
uniform float u_ShadowSoftness;
|
uniform float u_ShadowSoftness;
|
||||||
uniform float u_ShadowIntensity;
|
uniform float u_ShadowIntensity;
|
||||||
@ -347,23 +353,54 @@ vec3 IBL(vec3 F0, vec3 Lr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// shadow
|
// shadow
|
||||||
float calculateShadow(vec4 fragPosLightSpace, vec3 normal, vec3 lightDir)
|
int selectCascade(float viewZ)
|
||||||
{
|
{
|
||||||
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
float depth = -viewZ;
|
||||||
projCoords = projCoords * 0.5 + 0.5;
|
float linearDepth = (depth - u_ShadowNear) / (u_ShadowFar - u_ShadowNear);
|
||||||
|
if (linearDepth < u_CascadeSplits.x) return 0;
|
||||||
|
if (linearDepth < u_CascadeSplits.y) return 1;
|
||||||
|
if (linearDepth < u_CascadeSplits.z) return 2;
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
if (projCoords.z > 1.0 || projCoords.x < 0.0 || projCoords.x > 1.0 ||
|
mat4 getLightSpaceMatrix(int cascade)
|
||||||
projCoords.y < 0.0 || projCoords.y > 1.0)
|
{
|
||||||
return 0.0;
|
if (cascade == 0) return u_LightSpaceMatrix0;
|
||||||
|
else if (cascade == 1) return u_LightSpaceMatrix1;
|
||||||
|
else if (cascade == 2) return u_LightSpaceMatrix2;
|
||||||
|
else return u_LightSpaceMatrix3;
|
||||||
|
}
|
||||||
|
|
||||||
float closestDepth = texture(u_ShadowMap, projCoords.xy).r;
|
float getCascadeSplit(int cascade)
|
||||||
float currentDepth = projCoords.z;
|
{
|
||||||
|
if (cascade == 0) return u_CascadeSplits.x;
|
||||||
|
else if (cascade == 1) return u_CascadeSplits.y;
|
||||||
|
else if (cascade == 2) return u_CascadeSplits.z;
|
||||||
|
else return u_CascadeSplits.w;
|
||||||
|
}
|
||||||
|
|
||||||
float bias = max(u_ShadowBias * (1.0 - dot(normal, lightDir)), u_ShadowBias * 0.1);
|
float sampleShadow(int cascade, vec2 uv, float compareDepth, float bias)
|
||||||
|
{
|
||||||
|
float depth;
|
||||||
|
if (cascade == 0) depth = texture(u_ShadowMap[0], uv).r;
|
||||||
|
else if (cascade == 1) depth = texture(u_ShadowMap[1], uv).r;
|
||||||
|
else if (cascade == 2) depth = texture(u_ShadowMap[2], uv).r;
|
||||||
|
else depth = texture(u_ShadowMap[3], uv).r;
|
||||||
|
return (compareDepth - bias) > depth ? 1.0 : 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 getTexelSize(int cascade)
|
||||||
|
{
|
||||||
|
if (cascade == 0) return 1.0 / vec2(textureSize(u_ShadowMap[0], 0));
|
||||||
|
else if (cascade == 1) return 1.0 / vec2(textureSize(u_ShadowMap[1], 0));
|
||||||
|
else if (cascade == 2) return 1.0 / vec2(textureSize(u_ShadowMap[2], 0));
|
||||||
|
else return 1.0 / vec2(textureSize(u_ShadowMap[3], 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
float pcfShadow(int cascade, vec3 projCoords, float bias)
|
||||||
|
{
|
||||||
|
vec2 texelSize = getTexelSize(cascade);
|
||||||
int pcfRange = clamp(int(u_ShadowSoftness), 0, 3);
|
int pcfRange = clamp(int(u_ShadowSoftness), 0, 3);
|
||||||
|
|
||||||
vec2 texelSize = 1.0 / textureSize(u_ShadowMap, 0);
|
|
||||||
float shadow = 0.0;
|
float shadow = 0.0;
|
||||||
int samples = 0;
|
int samples = 0;
|
||||||
|
|
||||||
@ -372,34 +409,57 @@ float calculateShadow(vec4 fragPosLightSpace, vec3 normal, vec3 lightDir)
|
|||||||
for (int y = -pcfRange; y <= pcfRange; ++y)
|
for (int y = -pcfRange; y <= pcfRange; ++y)
|
||||||
{
|
{
|
||||||
vec2 offset = vec2(x, y) * texelSize;
|
vec2 offset = vec2(x, y) * texelSize;
|
||||||
float pcfDepth = texture(u_ShadowMap, projCoords.xy + offset).r;
|
shadow += sampleShadow(cascade, projCoords.xy + offset, projCoords.z, bias);
|
||||||
shadow += (currentDepth - bias) > pcfDepth ? 1.0 : 0.0;
|
|
||||||
samples++;
|
samples++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
shadow /= float(samples);
|
return shadow / float(samples);
|
||||||
return shadow * u_ShadowIntensity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float calculateCSMShadow(vec3 worldPos, vec3 normal, vec3 lightDir, float viewZ)
|
||||||
float ComputeShadow(vec4 fragPosLightSpace, float NdotL)
|
|
||||||
{
|
{
|
||||||
if (u_ShadowEnabled == 0) return 1.0;
|
int cascade = selectCascade(viewZ);
|
||||||
|
|
||||||
|
vec4 fragPosLightSpace = getLightSpaceMatrix(cascade) * vec4(worldPos, 1.0);
|
||||||
|
|
||||||
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
||||||
projCoords = projCoords * 0.5 + 0.5;
|
projCoords = projCoords * 0.5 + 0.5;
|
||||||
|
|
||||||
if (projCoords.x < 0.0 || projCoords.x > 1.0 ||
|
if (projCoords.z > 1.0 || projCoords.x < 0.0 || projCoords.x > 1.0 ||
|
||||||
projCoords.y < 0.0 || projCoords.y > 1.0 ||
|
projCoords.y < 0.0 || projCoords.y > 1.0)
|
||||||
projCoords.z > 1.0) return 1.0;
|
return 0.0;
|
||||||
|
|
||||||
float closestDepth = texture(u_ShadowMap, projCoords.xy).r;
|
float bias = max(u_ShadowBias * (1.0 - dot(normal, lightDir)), u_ShadowBias * 0.1);
|
||||||
float currentDepth = projCoords.z;
|
float shadow = pcfShadow(cascade, projCoords, bias);
|
||||||
|
|
||||||
float bias = max(u_ShadowBias * (1.0 - NdotL), u_ShadowBias * 0.5);
|
float cascadeEdge = 0.0;
|
||||||
|
if (cascade < CSM_CASCADE_COUNT - 1)
|
||||||
|
{
|
||||||
|
float depth = -viewZ;
|
||||||
|
float linearDepth = (depth - u_ShadowNear) / (u_ShadowFar - u_ShadowNear);
|
||||||
|
float splitDist = getCascadeSplit(cascade);
|
||||||
|
float prevSplit = (cascade > 0) ? getCascadeSplit(cascade - 1) : 0.0;
|
||||||
|
float blendStart = splitDist - (splitDist - prevSplit) * 0.1;
|
||||||
|
if (linearDepth > blendStart)
|
||||||
|
{
|
||||||
|
cascadeEdge = (linearDepth - blendStart) / (splitDist - blendStart);
|
||||||
|
|
||||||
float shadow = (currentDepth - bias) > closestDepth ? 1.0 : 0.0;
|
int nextCascade = cascade + 1;
|
||||||
return mix(1.0, 1.0 - u_ShadowIntensity, shadow);
|
vec4 fragPosNext = getLightSpaceMatrix(nextCascade) * vec4(worldPos, 1.0);
|
||||||
|
|
||||||
|
vec3 projCoordsNext = fragPosNext.xyz / fragPosNext.w;
|
||||||
|
projCoordsNext = projCoordsNext * 0.5 + 0.5;
|
||||||
|
|
||||||
|
if (!(projCoordsNext.z > 1.0 || projCoordsNext.x < 0.0 || projCoordsNext.x > 1.0 ||
|
||||||
|
projCoordsNext.y < 0.0 || projCoordsNext.y > 1.0))
|
||||||
|
{
|
||||||
|
float nextShadow = pcfShadow(nextCascade, projCoordsNext, bias);
|
||||||
|
shadow = mix(shadow, nextShadow, cascadeEdge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return shadow * u_ShadowIntensity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -428,7 +488,7 @@ void main()
|
|||||||
// Shadow
|
// Shadow
|
||||||
float shadowFactor = 1.0;
|
float shadowFactor = 1.0;
|
||||||
if (u_ShadowEnabled > 0.5) {
|
if (u_ShadowEnabled > 0.5) {
|
||||||
float shadow = calculateShadow(vs_Input.FragPosLightSpace, m_Params.Normal, u_DirectionalLights.Direction);
|
float shadow = calculateCSMShadow(vs_Input.WorldPosition, m_Params.Normal, u_DirectionalLights.Direction, vs_Input.ViewZ);
|
||||||
shadowFactor = 1.0 - shadow;
|
shadowFactor = 1.0 - shadow;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,4 +519,6 @@ void main()
|
|||||||
// Bloom
|
// Bloom
|
||||||
float brightness = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
|
float brightness = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
|
||||||
o_BloomColor = brightness > u_BloomThreshold ? color : vec4(0.0, 0.0, 0.0, 1.0);
|
o_BloomColor = brightness > u_BloomThreshold ? color : vec4(0.0, 0.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
o_MaterialInfo = vec4(m_Params.Metalness, m_Params.Roughness, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|||||||
207
Editor/assets/shaders/SSR.glsl
Normal file
207
Editor/assets/shaders/SSR.glsl
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
#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, 0.0, 1.0);
|
||||||
|
v_TexCoord = a_TexCoord;
|
||||||
|
gl_Position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
#type fragment
|
||||||
|
#version 430
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 o_Color;
|
||||||
|
|
||||||
|
in vec2 v_TexCoord;
|
||||||
|
|
||||||
|
uniform sampler2D u_ColorTexture;
|
||||||
|
uniform sampler2D u_DepthTexture;
|
||||||
|
uniform sampler2D u_MaterialInfoTexture;
|
||||||
|
|
||||||
|
uniform mat4 u_Projection;
|
||||||
|
uniform mat4 u_InvProjection;
|
||||||
|
|
||||||
|
uniform vec2 u_ScreenSize;
|
||||||
|
uniform float u_CameraNear;
|
||||||
|
uniform float u_CameraFar;
|
||||||
|
|
||||||
|
uniform int u_Steps = 64;
|
||||||
|
uniform float u_Thickness = 0.5;
|
||||||
|
uniform float u_MaxDistance = 30.0;
|
||||||
|
uniform float u_Intensity = 1.0;
|
||||||
|
|
||||||
|
float LinearizeDepth(float depth)
|
||||||
|
{
|
||||||
|
float z = depth * 2.0 - 1.0;
|
||||||
|
return (2.0 * u_CameraNear * u_CameraFar) / (u_CameraFar + u_CameraNear - z * (u_CameraFar - u_CameraNear));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 ReconstructViewPos(vec2 tc, float depth)
|
||||||
|
{
|
||||||
|
float z = depth * 2.0 - 1.0;
|
||||||
|
vec4 clipPos = vec4(tc * 2.0 - 1.0, z, 1.0);
|
||||||
|
vec4 viewPos4 = u_InvProjection * clipPos;
|
||||||
|
return viewPos4.xyz / viewPos4.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 ReconstructNormalFromDepth(vec2 tc, float depth)
|
||||||
|
{
|
||||||
|
vec2 texelSize = 1.0 / u_ScreenSize;
|
||||||
|
|
||||||
|
vec2 tcL = tc - vec2(texelSize.x, 0.0);
|
||||||
|
vec2 tcR = tc + vec2(texelSize.x, 0.0);
|
||||||
|
vec2 tcB = tc - vec2(0.0, texelSize.y);
|
||||||
|
vec2 tcT = tc + vec2(0.0, texelSize.y);
|
||||||
|
|
||||||
|
float depthL = texture(u_DepthTexture, tcL).r;
|
||||||
|
float depthR = texture(u_DepthTexture, tcR).r;
|
||||||
|
float depthB = texture(u_DepthTexture, tcB).r;
|
||||||
|
float depthT = texture(u_DepthTexture, tcT).r;
|
||||||
|
|
||||||
|
vec3 pL = ReconstructViewPos(tcL, depthL);
|
||||||
|
vec3 pR = ReconstructViewPos(tcR, depthR);
|
||||||
|
vec3 pB = ReconstructViewPos(tcB, depthB);
|
||||||
|
vec3 pT = ReconstructViewPos(tcT, depthT);
|
||||||
|
|
||||||
|
vec3 dx = pR - pL;
|
||||||
|
vec3 dy = pT - pB;
|
||||||
|
|
||||||
|
return normalize(cross(dx, dy));
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
float depth = texture(u_DepthTexture, v_TexCoord).r;
|
||||||
|
|
||||||
|
if (depth >= 1.0)
|
||||||
|
{
|
||||||
|
o_Color = vec4(0.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 matInfo = texture(u_MaterialInfoTexture, v_TexCoord);
|
||||||
|
float metalness = matInfo.r;
|
||||||
|
float roughness = matInfo.g;
|
||||||
|
|
||||||
|
if (roughness > 0.9)
|
||||||
|
{
|
||||||
|
o_Color = vec4(0.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 viewPos = ReconstructViewPos(v_TexCoord, depth);
|
||||||
|
vec3 normal = ReconstructNormalFromDepth(v_TexCoord, depth);
|
||||||
|
|
||||||
|
vec3 viewDir = normalize(-viewPos);
|
||||||
|
float NdotV = max(dot(normal, viewDir), 0.0);
|
||||||
|
|
||||||
|
vec3 reflectDir = reflect(-viewDir, normal);
|
||||||
|
|
||||||
|
if (dot(reflectDir, normal) < 0.0)
|
||||||
|
{
|
||||||
|
o_Color = vec4(0.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 rayOrigin = viewPos + normal * 0.02;
|
||||||
|
vec3 rayEnd = rayOrigin + reflectDir * u_MaxDistance;
|
||||||
|
|
||||||
|
vec4 p0 = u_Projection * vec4(rayOrigin, 1.0);
|
||||||
|
vec4 p1 = u_Projection * vec4(rayEnd, 1.0);
|
||||||
|
|
||||||
|
float k0 = 1.0 / p0.w;
|
||||||
|
float k1 = 1.0 / p1.w;
|
||||||
|
|
||||||
|
p0.xyz *= k0;
|
||||||
|
p1.xyz *= k1;
|
||||||
|
|
||||||
|
vec3 v0 = rayOrigin * k0;
|
||||||
|
vec3 v1 = rayEnd * k1;
|
||||||
|
|
||||||
|
vec2 s0 = p0.xy * 0.5 + 0.5;
|
||||||
|
vec2 s1 = p1.xy * 0.5 + 0.5;
|
||||||
|
|
||||||
|
vec2 sDelta = s1 - s0;
|
||||||
|
float screenDist = length(sDelta * u_ScreenSize);
|
||||||
|
|
||||||
|
if (screenDist < 1.0)
|
||||||
|
{
|
||||||
|
o_Color = vec4(0.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float divisions = min(screenDist, float(u_Steps));
|
||||||
|
vec3 dV = (v1 - v0) / divisions;
|
||||||
|
float dK = (k1 - k0) / divisions;
|
||||||
|
vec2 dS = sDelta / divisions;
|
||||||
|
|
||||||
|
vec3 curV = v0;
|
||||||
|
float curK = k0;
|
||||||
|
vec2 curS = s0;
|
||||||
|
|
||||||
|
vec2 hitUV = vec2(0.0);
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < int(divisions); i++)
|
||||||
|
{
|
||||||
|
curV += dV;
|
||||||
|
curK += dK;
|
||||||
|
curS += dS;
|
||||||
|
|
||||||
|
if (curS.x < 0.0 || curS.x > 1.0 || curS.y < 0.0 || curS.y > 1.0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
float sampleDepth = texture(u_DepthTexture, curS).r;
|
||||||
|
float surfDepth = LinearizeDepth(sampleDepth);
|
||||||
|
float rayDepth = -curV.z / curK;
|
||||||
|
|
||||||
|
float depthDiff = rayDepth - surfDepth;
|
||||||
|
|
||||||
|
if (depthDiff > 0.0 && depthDiff < u_Thickness)
|
||||||
|
{
|
||||||
|
hitUV = curS;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
o_Color = vec4(0.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 hitNormal = ReconstructNormalFromDepth(hitUV, texture(u_DepthTexture, hitUV).r);
|
||||||
|
if (dot(hitNormal, -reflectDir) < 0.0)
|
||||||
|
{
|
||||||
|
o_Color = vec4(0.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 reflectColor = texture(u_ColorTexture, hitUV).rgb;
|
||||||
|
|
||||||
|
float dist = distance(viewPos, ReconstructViewPos(hitUV, texture(u_DepthTexture, hitUV).r));
|
||||||
|
float fadeFactor = 1.0 - smoothstep(u_MaxDistance * 0.5, u_MaxDistance, dist);
|
||||||
|
|
||||||
|
float edgeFade = 1.0;
|
||||||
|
edgeFade *= smoothstep(0.0, 0.15, hitUV.x);
|
||||||
|
edgeFade *= smoothstep(0.0, 0.15, hitUV.y);
|
||||||
|
edgeFade *= smoothstep(0.0, 0.15, 1.0 - hitUV.x);
|
||||||
|
edgeFade *= smoothstep(0.0, 0.15, 1.0 - hitUV.y);
|
||||||
|
|
||||||
|
vec3 F0 = mix(vec3(0.04), reflectColor, metalness);
|
||||||
|
vec3 Fresnel = F0 + (1.0 - F0) * pow(1.0 - NdotV, 5.0);
|
||||||
|
|
||||||
|
float roughnessFade = 1.0 - roughness * roughness;
|
||||||
|
|
||||||
|
vec3 ssrContrib = reflectColor * Fresnel * fadeFactor * edgeFade * roughnessFade * u_Intensity;
|
||||||
|
float ssrAlpha = length(Fresnel) * fadeFactor * edgeFade * roughnessFade;
|
||||||
|
|
||||||
|
o_Color = vec4(ssrContrib, ssrAlpha);
|
||||||
|
}
|
||||||
85
Editor/assets/shaders/SSRBlur.glsl
Normal file
85
Editor/assets/shaders/SSRBlur.glsl
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#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, 0.0, 1.0);
|
||||||
|
v_TexCoord = a_TexCoord;
|
||||||
|
gl_Position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
#type fragment
|
||||||
|
#version 430
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 o_Color;
|
||||||
|
|
||||||
|
in vec2 v_TexCoord;
|
||||||
|
|
||||||
|
uniform sampler2D u_SSRTexture;
|
||||||
|
uniform sampler2D u_DepthTexture;
|
||||||
|
uniform sampler2D u_MaterialInfoTexture;
|
||||||
|
|
||||||
|
uniform vec2 u_ScreenSize;
|
||||||
|
uniform float u_BlurRadius = 4.0;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec2 texelSize = 1.0 / u_ScreenSize;
|
||||||
|
|
||||||
|
vec4 center = texture(u_SSRTexture, v_TexCoord);
|
||||||
|
if (center.a <= 0.001)
|
||||||
|
{
|
||||||
|
o_Color = vec4(0.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float roughness = texture(u_MaterialInfoTexture, v_TexCoord).g;
|
||||||
|
float effectiveBlurRadius = max(u_BlurRadius * roughness * roughness, 1.0);
|
||||||
|
|
||||||
|
float centerDepth = texture(u_DepthTexture, v_TexCoord).r;
|
||||||
|
vec3 result = vec3(0.0);
|
||||||
|
float totalWeight = 0.0;
|
||||||
|
|
||||||
|
const int kRadius = 6;
|
||||||
|
float sigma = effectiveBlurRadius * 0.5;
|
||||||
|
|
||||||
|
for (int x = -kRadius; x <= kRadius; x++)
|
||||||
|
{
|
||||||
|
for (int y = -kRadius; y <= kRadius; y++)
|
||||||
|
{
|
||||||
|
vec2 offset = vec2(float(x), float(y)) * texelSize * effectiveBlurRadius / float(kRadius);
|
||||||
|
vec2 sampleUV = v_TexCoord + offset;
|
||||||
|
|
||||||
|
if (sampleUV.x < 0.0 || sampleUV.x > 1.0 || sampleUV.y < 0.0 || sampleUV.y > 1.0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
float sampleDepth = texture(u_DepthTexture, sampleUV).r;
|
||||||
|
float depthDiff = abs(centerDepth - sampleDepth);
|
||||||
|
|
||||||
|
float depthWeight = exp(-depthDiff * 200.0);
|
||||||
|
|
||||||
|
float spatialWeight = exp(-(float(x * x + y * y)) / (2.0 * sigma * sigma));
|
||||||
|
|
||||||
|
vec4 sampleColor = texture(u_SSRTexture, sampleUV);
|
||||||
|
|
||||||
|
float alphaWeight = sampleColor.a > 0.01 ? 1.0 : 0.0;
|
||||||
|
|
||||||
|
float weight = spatialWeight * depthWeight * alphaWeight;
|
||||||
|
|
||||||
|
result += sampleColor.rgb * weight;
|
||||||
|
totalWeight += weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalWeight > 0.0)
|
||||||
|
result /= totalWeight;
|
||||||
|
else
|
||||||
|
result = center.rgb;
|
||||||
|
|
||||||
|
o_Color = vec4(result, center.a);
|
||||||
|
}
|
||||||
@ -49,6 +49,9 @@ uniform int u_TextureSamples;
|
|||||||
uniform bool u_EnableBloom;
|
uniform bool u_EnableBloom;
|
||||||
uniform float u_BloomThreshold;
|
uniform float u_BloomThreshold;
|
||||||
|
|
||||||
|
uniform bool u_EnableSSR;
|
||||||
|
uniform sampler2D u_SSRTexture;
|
||||||
|
|
||||||
const float uFar = 1.0;
|
const float uFar = 1.0;
|
||||||
|
|
||||||
vec4 SampleTexture(sampler2D tex, vec2 texCoord)
|
vec4 SampleTexture(sampler2D tex, vec2 texCoord)
|
||||||
@ -94,6 +97,12 @@ void main()
|
|||||||
color += bloomColor;
|
color += bloomColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (u_EnableSSR)
|
||||||
|
{
|
||||||
|
vec4 ssrSample = texture(u_SSRTexture, v_TexCoord);
|
||||||
|
color += ssrSample.rgb * ssrSample.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
float exposure = 1.0f;
|
float exposure = 1.0f;
|
||||||
if(u_EnableAutoExposure)
|
if(u_EnableAutoExposure)
|
||||||
|
|||||||
@ -91,6 +91,7 @@ namespace Prism
|
|||||||
Ref<Texture2D> RoughnessTexture;
|
Ref<Texture2D> RoughnessTexture;
|
||||||
|
|
||||||
bool IsDirty = true;
|
bool IsDirty = true;
|
||||||
|
bool PreviewIsDirty = true;
|
||||||
|
|
||||||
Ref<Texture2D> PreviewTexture;
|
Ref<Texture2D> PreviewTexture;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -149,6 +149,7 @@ namespace Prism
|
|||||||
out << YAML::EndMap;
|
out << YAML::EndMap;
|
||||||
|
|
||||||
PM_CORE_INFO("Save Asset change...");
|
PM_CORE_INFO("Save Asset change...");
|
||||||
|
FileSystem::NotifyFileWriting(asset->FilePath);
|
||||||
std::ofstream fout(asset->FilePath);
|
std::ofstream fout(asset->FilePath);
|
||||||
fout << out.c_str();
|
fout << out.c_str();
|
||||||
}
|
}
|
||||||
@ -421,7 +422,9 @@ namespace Prism
|
|||||||
out << YAML::Key << "Type" << YAML::Value << (int)asset->Type;
|
out << YAML::Key << "Type" << YAML::Value << (int)asset->Type;
|
||||||
out << YAML::EndMap;
|
out << YAML::EndMap;
|
||||||
|
|
||||||
std::ofstream fout(asset->FilePath + ".meta");
|
std::string metaPath = asset->FilePath + ".meta";
|
||||||
|
FileSystem::NotifyFileWriting(metaPath);
|
||||||
|
std::ofstream fout(metaPath);
|
||||||
fout << out.c_str();
|
fout << out.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -434,7 +437,9 @@ namespace Prism
|
|||||||
out << YAML::Key << "Type" << YAML::Value << (int)asset->Type;
|
out << YAML::Key << "Type" << YAML::Value << (int)asset->Type;
|
||||||
out << YAML::EndMap;
|
out << YAML::EndMap;
|
||||||
|
|
||||||
std::ofstream fout(asset->FilePath + ".meta");
|
std::string metaPath = asset->FilePath + ".meta";
|
||||||
|
FileSystem::NotifyFileWriting(metaPath);
|
||||||
|
std::ofstream fout(metaPath);
|
||||||
fout << out.c_str();
|
fout << out.c_str();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -13,8 +13,6 @@
|
|||||||
#include <yaml-cpp/yaml.h>
|
#include <yaml-cpp/yaml.h>
|
||||||
|
|
||||||
#include "AssetSerializer.h"
|
#include "AssetSerializer.h"
|
||||||
#include "Prism/Core/Application.h"
|
|
||||||
#include "Prism/Core/KeyCodes.h"
|
|
||||||
#include "Prism/Renderer/SceneEnvironment.h"
|
#include "Prism/Renderer/SceneEnvironment.h"
|
||||||
#include "Prism/Script/ScriptEngine.h"
|
#include "Prism/Script/ScriptEngine.h"
|
||||||
#include "Prism/Utilities/StringUtils.h"
|
#include "Prism/Utilities/StringUtils.h"
|
||||||
@ -237,7 +235,9 @@ namespace Prism
|
|||||||
asset->FileName = Utils::RemoveExtension(Utils::GetFilename(asset->FilePath));
|
asset->FileName = Utils::RemoveExtension(Utils::GetFilename(asset->FilePath));
|
||||||
asset->Extension = Utils::GetFilename(filename);
|
asset->Extension = Utils::GetFilename(filename);
|
||||||
asset->ParentDirectory = directoryHandle;
|
asset->ParentDirectory = directoryHandle;
|
||||||
asset->Handle = std::hash<std::string>()(asset->FilePath + std::to_string(Application::Get().GetTime()));
|
do {
|
||||||
|
asset->Handle = AssetHandle();
|
||||||
|
} while (s_LoadedAssets.find(asset->Handle) != s_LoadedAssets.end());
|
||||||
|
|
||||||
asset->IsDataLoaded = true;
|
asset->IsDataLoaded = true;
|
||||||
s_LoadedAssets[asset->Handle] = asset;
|
s_LoadedAssets[asset->Handle] = asset;
|
||||||
@ -259,6 +259,21 @@ namespace Prism
|
|||||||
return s_LoadedAssets.find(assetHandle) != s_LoadedAssets.end() && s_LoadedAssets[assetHandle]->Type == type;
|
return s_LoadedAssets.find(assetHandle) != s_LoadedAssets.end() && s_LoadedAssets[assetHandle]->Type == type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void AssetsManager::ForEachAsset(const std::function<void(Ref<T>)>& callback)
|
||||||
|
{
|
||||||
|
for (auto& [handle, asset] : s_LoadedAssets)
|
||||||
|
{
|
||||||
|
if (asset->Type == AssetType::Material && asset->IsDataLoaded)
|
||||||
|
{
|
||||||
|
Ref<T> typed = asset.As<T>();
|
||||||
|
if (typed)
|
||||||
|
callback(typed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template PRISM_API void AssetsManager::ForEachAsset<PBRMaterialAsset>(const std::function<void(Ref<PBRMaterialAsset>)>&);
|
||||||
|
|
||||||
|
|
||||||
std::string AssetsManager::StripExtras(const std::string& filename)
|
std::string AssetsManager::StripExtras(const std::string& filename)
|
||||||
{
|
{
|
||||||
@ -383,11 +398,19 @@ namespace Prism
|
|||||||
case FileSystemAction::Modified:
|
case FileSystemAction::Modified:
|
||||||
{
|
{
|
||||||
if (!e.IsDirectory)
|
if (!e.IsDirectory)
|
||||||
|
{
|
||||||
|
AssetHandle existingHandle = GetAssetHandleFromFilePath(e.FilePath);
|
||||||
|
if (existingHandle && s_LoadedAssets[existingHandle]->IsDataLoaded)
|
||||||
|
{
|
||||||
|
if (s_AssetsChangeCallback)
|
||||||
|
s_AssetsChangeCallback();
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
Ref<Asset> asset = ImportAsset(e.FilePath, parentHandle);
|
Ref<Asset> asset = ImportAsset(e.FilePath, parentHandle);
|
||||||
if (asset->Type == AssetType::Script)
|
if (asset->Type == AssetType::Script)
|
||||||
isCharpFile = true;
|
isCharpFile = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -454,28 +477,10 @@ namespace Prism
|
|||||||
s_AssetsChangeCallback();
|
s_AssetsChangeCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetHandle AssetsManager::FindParentHandleInChildren(Ref<Directory>& dir, const std::string& dirName)
|
|
||||||
{
|
|
||||||
if (dir->FileName == dirName)
|
|
||||||
return dir->Handle;
|
|
||||||
|
|
||||||
for (const AssetHandle& childHandle : dir->ChildDirectories)
|
|
||||||
{
|
|
||||||
Ref<Directory> child = GetAsset<Directory>(childHandle);
|
|
||||||
AssetHandle dirHandle = FindParentHandleInChildren(child, dirName);
|
|
||||||
|
|
||||||
if (IsAssetHandleValid(dirHandle))
|
|
||||||
return dirHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetHandle AssetsManager::FindParentHandle(const std::string& filepath)
|
AssetHandle AssetsManager::FindParentHandle(const std::string& filepath)
|
||||||
{
|
{
|
||||||
const std::vector<std::string> parts = Utils::SplitString(filepath, "/\\");
|
std::string parentPath = std::filesystem::path(filepath).parent_path().string();
|
||||||
const std::string& parentFolder = parts[parts.size() - 2];
|
std::replace(parentPath.begin(), parentPath.end(), '\\', '/');
|
||||||
Ref<Directory> assetsDirectory = GetAsset<Directory>(GetAssetHandleFromFilePath("assets"));
|
return GetAssetHandleFromFilePath(parentPath);
|
||||||
return FindParentHandleInChildren(assetsDirectory, parentFolder);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -63,6 +63,9 @@ namespace Prism
|
|||||||
|
|
||||||
static bool IsAssetType(AssetHandle assetHandle, AssetType type);
|
static bool IsAssetType(AssetHandle assetHandle, AssetType type);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static void ForEachAsset(const std::function<void(Ref<T>)>& callback);
|
||||||
|
|
||||||
static std::string StripExtras(const std::string& filename);
|
static std::string StripExtras(const std::string& filename);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -78,7 +81,6 @@ namespace Prism
|
|||||||
|
|
||||||
static void OnFileSystemChanged(FileSystemChangedEvent e);
|
static void OnFileSystemChanged(FileSystemChangedEvent e);
|
||||||
|
|
||||||
static AssetHandle FindParentHandleInChildren(Ref<Directory>& dir, const std::string& dirName);
|
|
||||||
static AssetHandle FindParentHandle(const std::string& filepath);
|
static AssetHandle FindParentHandle(const std::string& filepath);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -165,7 +165,11 @@ namespace Prism
|
|||||||
Renderer::Submit([=]() { glViewport(0, 0, width, height); });
|
Renderer::Submit([=]() { glViewport(0, 0, width, height); });
|
||||||
auto& fbs = FrameBufferPool::GetGlobal()->GetAll();
|
auto& fbs = FrameBufferPool::GetGlobal()->GetAll();
|
||||||
for (auto& fb : fbs)
|
for (auto& fb : fbs)
|
||||||
|
{
|
||||||
|
if (fb->GetSpecification().NoResize)
|
||||||
|
continue;
|
||||||
fb->Resize(width, height);
|
fb->Resize(width, height);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -29,13 +29,19 @@ namespace Prism
|
|||||||
m_AssetIconMap["hdr"] = AssetsManager::GetAsset<Texture2D>("assets/editor/file.png");
|
m_AssetIconMap["hdr"] = AssetsManager::GetAsset<Texture2D>("assets/editor/file.png");
|
||||||
m_AssetIconMap["fbx"] = AssetsManager::GetAsset<Texture2D>("assets/editor/fbx.png");
|
m_AssetIconMap["fbx"] = AssetsManager::GetAsset<Texture2D>("assets/editor/fbx.png");
|
||||||
m_AssetIconMap["obj"] = AssetsManager::GetAsset<Texture2D>("assets/editor/obj.png");
|
m_AssetIconMap["obj"] = AssetsManager::GetAsset<Texture2D>("assets/editor/obj.png");
|
||||||
|
m_AssetIconMap["fbx"] = AssetsManager::GetAsset<Texture2D>("assets/editor/fbx.png");
|
||||||
|
m_AssetIconMap["dae"] = AssetsManager::GetAsset<Texture2D>("assets/editor/model.png");
|
||||||
m_AssetIconMap["wav"] = AssetsManager::GetAsset<Texture2D>("assets/editor/wav.png");
|
m_AssetIconMap["wav"] = AssetsManager::GetAsset<Texture2D>("assets/editor/wav.png");
|
||||||
m_AssetIconMap["cs"] = AssetsManager::GetAsset<Texture2D>("assets/editor/csc.png");
|
m_AssetIconMap["cs"] = AssetsManager::GetAsset<Texture2D>("assets/editor/csc.png");
|
||||||
m_AssetIconMap["png"] = AssetsManager::GetAsset<Texture2D>("assets/editor/png.png");
|
m_AssetIconMap["png"] = AssetsManager::GetAsset<Texture2D>("assets/editor/png.png");
|
||||||
|
m_AssetIconMap["jpg"] = AssetsManager::GetAsset<Texture2D>("assets/editor/texture.png");
|
||||||
|
m_AssetIconMap["jepg"] = AssetsManager::GetAsset<Texture2D>("assets/editor/texture.png");
|
||||||
|
m_AssetIconMap["bmp"] = AssetsManager::GetAsset<Texture2D>("assets/editor/texture.png");
|
||||||
|
m_AssetIconMap["tga"] = AssetsManager::GetAsset<Texture2D>("assets/editor/texture.png");
|
||||||
|
m_AssetIconMap["scene"] = AssetsManager::GetAsset<Texture2D>("assets/editor/scene.png");
|
||||||
m_AssetIconMap["blend"] = AssetsManager::GetAsset<Texture2D>("assets/editor/blend.png");
|
m_AssetIconMap["blend"] = AssetsManager::GetAsset<Texture2D>("assets/editor/blend.png");
|
||||||
|
|
||||||
// TODO: get a logo for this project
|
m_AssetIconMap["wav"] = AssetsManager::GetAsset<Texture2D>("assets/editor/wav.png");
|
||||||
m_AssetIconMap["scene"] = AssetsManager::GetAsset<Texture2D>("assets/editor/asset.png");
|
|
||||||
|
|
||||||
m_AssetIconMap["pmat"] = AssetsManager::GetAsset<Texture2D>("assets/editor/asset.png");
|
m_AssetIconMap["pmat"] = AssetsManager::GetAsset<Texture2D>("assets/editor/asset.png");
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
//
|
//
|
||||||
// Created by Atdunbg on 2026/2/14.
|
// Created by Atdunbg on 2026/2/14.
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -13,6 +13,7 @@
|
|||||||
#include "Prism/Renderer/Renderer3D.h"
|
#include "Prism/Renderer/Renderer3D.h"
|
||||||
#include "Prism/Renderer/RenderPass.h"
|
#include "Prism/Renderer/RenderPass.h"
|
||||||
#include "Prism/Renderer/RHI/RHICommandBuffer.h"
|
#include "Prism/Renderer/RHI/RHICommandBuffer.h"
|
||||||
|
#include "Prism/Renderer/SceneRenderer.h"
|
||||||
#include "Prism/Scene/Scene.h"
|
#include "Prism/Scene/Scene.h"
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
@ -22,9 +23,6 @@ namespace Prism
|
|||||||
ed::Config config;
|
ed::Config config;
|
||||||
config.SettingsFile = "";
|
config.SettingsFile = "";
|
||||||
m_EditorContext = ed::CreateEditor(&config);
|
m_EditorContext = ed::CreateEditor(&config);
|
||||||
|
|
||||||
// TODO: function don't work
|
|
||||||
// InitPreviewResources();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PBRMaterialEditor::~PBRMaterialEditor()
|
PBRMaterialEditor::~PBRMaterialEditor()
|
||||||
@ -101,110 +99,110 @@ namespace Prism
|
|||||||
AssetSerializer::SerializeAsset(m_Asset);
|
AssetSerializer::SerializeAsset(m_Asset);
|
||||||
}
|
}
|
||||||
m_Asset = static_cast<Ref<PBRMaterialAsset>>(asset);
|
m_Asset = static_cast<Ref<PBRMaterialAsset>>(asset);
|
||||||
LoadAssetToGraph(); // 加载资产数据到节点图
|
s_EditingAsset = m_Asset;
|
||||||
|
LoadAssetToGraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PBRMaterialEditor::InitPreviewResources()
|
static Ref<RenderPass> s_PreviewRenderPass;
|
||||||
|
static Ref<Mesh> s_PreviewSphere;
|
||||||
|
static Ref<Material> s_PreviewBaseMaterial;
|
||||||
|
static Ref<MaterialInstance> s_PreviewMaterialInstance;
|
||||||
|
static Ref<TextureCube> s_PreviewEnvRadiance;
|
||||||
|
static Ref<TextureCube> s_PreviewEnvIrradiance;
|
||||||
|
static constexpr float s_PreviewFOV = 45.0f;
|
||||||
|
static constexpr float s_PreviewNear = 0.1f;
|
||||||
|
static constexpr float s_PreviewFar = 100.0f;
|
||||||
|
static constexpr glm::vec3 s_PreviewCameraPos = glm::vec3(2.0f, 1.5f, 3.0f);
|
||||||
|
static constexpr glm::vec3 s_PreviewCameraTarget = glm::vec3(0.0f);
|
||||||
|
|
||||||
|
void PBRMaterialEditor::InitPreviewRenderer()
|
||||||
{
|
{
|
||||||
// 创建离屏 Framebuffer(例如 512x512)
|
|
||||||
FramebufferSpecification fbSpec;
|
FramebufferSpecification fbSpec;
|
||||||
fbSpec.Width = 512;
|
fbSpec.Width = 512;
|
||||||
fbSpec.Height = 512;
|
fbSpec.Height = 512;
|
||||||
fbSpec.NoResize = true;
|
fbSpec.NoResize = true;
|
||||||
fbSpec.Attachments = { FramebufferTextureFormat::RGBA16F, FramebufferTextureFormat::DEPTH24STENCIL8 };
|
fbSpec.Attachments = { FramebufferTextureFormat::RGBA16F, FramebufferTextureFormat::DEPTH24STENCIL8 };
|
||||||
fbSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f };
|
fbSpec.ClearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||||
Ref<FrameBuffer> previewFrameBuffer = FrameBuffer::Create(fbSpec);
|
Ref<FrameBuffer> previewFrameBuffer = FrameBuffer::Create(fbSpec);
|
||||||
|
|
||||||
RenderPassSpecification rpSpec;
|
RenderPassSpecification rpSpec;
|
||||||
rpSpec.TargetFramebuffer = previewFrameBuffer;
|
rpSpec.TargetFramebuffer = previewFrameBuffer;
|
||||||
m_PreviewRenderPass = RenderPass::Create(rpSpec);
|
s_PreviewRenderPass = RenderPass::Create(rpSpec);
|
||||||
|
|
||||||
m_PreviewSphere = MeshFactory::CreateSphere(0.5f);
|
s_PreviewSphere = MeshFactory::CreateSphere(1.5f);
|
||||||
|
|
||||||
auto pbrShader = Shader::Create("assets/shaders/PBRShader_Static.glsl"); // 你的 PBR Shader 路径
|
auto pbrShader = Shader::Create("assets/shaders/PBRShader_Static.glsl");
|
||||||
auto material = Material::Create(pbrShader);
|
s_PreviewBaseMaterial = Material::Create(pbrShader);
|
||||||
m_PreviewMaterialInstance = MaterialInstance::Create(material);
|
s_PreviewMaterialInstance = MaterialInstance::Create(s_PreviewBaseMaterial);
|
||||||
|
|
||||||
|
auto [radiance, irradiance] = Renderer3D::CreateEnvironmentMap("assets/env/birchwood_4k.hdr");
|
||||||
|
s_PreviewEnvRadiance = radiance;
|
||||||
|
s_PreviewEnvIrradiance = irradiance;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PBRMaterialEditor::RenderPreview()
|
Ref<PBRMaterialAsset> PBRMaterialEditor::s_EditingAsset;
|
||||||
{
|
|
||||||
if (!m_Asset || !m_PreviewSphere) return;
|
void PBRMaterialEditor::RenderMaterialPreview(Ref<PBRMaterialAsset> materialAsset)
|
||||||
|
{
|
||||||
|
if (!materialAsset || !s_PreviewSphere) return;
|
||||||
|
|
||||||
|
auto matInst = s_PreviewMaterialInstance;
|
||||||
|
matInst->Set("u_AlbedoColor", materialAsset->AlbedoColor);
|
||||||
|
matInst->Set("u_Metalness", materialAsset->Metalness);
|
||||||
|
matInst->Set("u_Roughness", materialAsset->Roughness);
|
||||||
|
matInst->Set("u_AlbedoTexToggle", materialAsset->AlbedoTexToggle);
|
||||||
|
matInst->Set("u_NormalTexToggle", materialAsset->NormalTexToggle);
|
||||||
|
matInst->Set("u_MetalnessTexToggle", materialAsset->MetalnessTexToggle);
|
||||||
|
matInst->Set("u_RoughnessTexToggle", materialAsset->RoughnessTexToggle);
|
||||||
|
|
||||||
|
matInst->Set("u_AlbedoTexture", materialAsset->AlbedoTexture);
|
||||||
|
matInst->Set("u_NormalTexture", materialAsset->NormalTexture);
|
||||||
|
matInst->Set("u_MetalnessTexture", materialAsset->MetalnessTexture);
|
||||||
|
matInst->Set("u_RoughnessTexture", materialAsset->RoughnessTexture);
|
||||||
|
|
||||||
|
float aspect = (float)s_PreviewRenderPass->GetSpecification().TargetFramebuffer->GetWidth() /
|
||||||
|
(float)s_PreviewRenderPass->GetSpecification().TargetFramebuffer->GetHeight();
|
||||||
|
glm::mat4 projection = glm::perspective(glm::radians(s_PreviewFOV), aspect, s_PreviewNear, s_PreviewFar);
|
||||||
|
glm::mat4 view = glm::lookAt(s_PreviewCameraPos, s_PreviewCameraTarget, glm::vec3(0,1,0));
|
||||||
|
glm::mat4 viewProjection = projection * view;
|
||||||
|
|
||||||
|
auto baseMaterial = s_PreviewBaseMaterial;
|
||||||
|
baseMaterial->Set("u_ViewProjectionMatrix", viewProjection);
|
||||||
|
baseMaterial->Set("u_ViewMatrix", view);
|
||||||
|
baseMaterial->Set("u_CameraPosition", s_PreviewCameraPos);
|
||||||
|
baseMaterial->Set("u_IBLContribution", 0.4f);
|
||||||
|
baseMaterial->Set("u_EnvRadianceTex", s_PreviewEnvRadiance);
|
||||||
|
baseMaterial->Set("u_EnvIrradianceTex", s_PreviewEnvIrradiance);
|
||||||
|
baseMaterial->Set("u_BRDFLUTTexture", Renderer3D::GetBRDFLUT());
|
||||||
|
|
||||||
// 构建简化的光照环境(一个方向光,无阴影)
|
|
||||||
LightEnvironment lightEnv;
|
LightEnvironment lightEnv;
|
||||||
lightEnv.DirectionalLights.Direction = glm::normalize(glm::vec3(-0.5f, -1.0f, -0.8f));
|
lightEnv.DirectionalLights.Direction = glm::normalize(glm::vec3(-0.5f, -1.0f, -0.8f));
|
||||||
lightEnv.DirectionalLights.Radiance = glm::vec3(1.0f);
|
lightEnv.DirectionalLights.Radiance = glm::vec3(1.0f);
|
||||||
lightEnv.DirectionalLights.Intensity = 2.0f;
|
lightEnv.DirectionalLights.Intensity = 3.0f;
|
||||||
lightEnv.DirectionalLights.CastShadows = false;
|
lightEnv.DirectionalLights.CastShadows = false;
|
||||||
lightEnv.PointLightCount = 0;
|
lightEnv.PointLightCount = 0;
|
||||||
lightEnv.SpotLightCount = 0;
|
lightEnv.SpotLightCount = 0;
|
||||||
|
|
||||||
// 构建相机矩阵
|
baseMaterial->Set("u_DirectionalLights", lightEnv.DirectionalLights);
|
||||||
float aspect = (float)m_PreviewRenderPass->GetSpecification().TargetFramebuffer->GetWidth() / (float)m_PreviewRenderPass->GetSpecification().TargetFramebuffer->GetHeight();
|
baseMaterial->Set("u_PointLightCount", 0);
|
||||||
glm::mat4 projection = glm::perspective(glm::radians(m_PreviewFOV), aspect, m_PreviewNear, m_PreviewFar);
|
baseMaterial->Set("u_SpotLightCount", 0);
|
||||||
glm::mat4 view = glm::lookAt(m_PreviewCameraPos, m_PreviewCameraTarget, glm::vec3(0,1,0));
|
baseMaterial->Set("u_ShadowEnabled", false);
|
||||||
glm::mat4 viewProjection = projection * view;
|
|
||||||
glm::vec3 cameraPos = m_PreviewCameraPos;
|
|
||||||
|
|
||||||
// 准备材质参数
|
Renderer::BeginRenderPass(s_PreviewRenderPass);
|
||||||
auto matInst = m_PreviewMaterialInstance;
|
Renderer::SubmitMesh(s_PreviewSphere, glm::mat4(1.0f), matInst);
|
||||||
matInst->Set("u_AlbedoColor", m_Asset->AlbedoColor);
|
Renderer::EndRenderPass();
|
||||||
matInst->Set("u_Metalness", m_Asset->Metalness);
|
|
||||||
matInst->Set("u_Roughness", m_Asset->Roughness);
|
|
||||||
matInst->Set("u_AlbedoTexToggle", m_Asset->AlbedoTexToggle);
|
|
||||||
matInst->Set("u_NormalTexToggle", m_Asset->NormalTexToggle);
|
|
||||||
matInst->Set("u_MetalnessTexToggle", m_Asset->MetalnessTexToggle);
|
|
||||||
matInst->Set("u_RoughnessTexToggle", m_Asset->RoughnessTexToggle);
|
|
||||||
|
|
||||||
|
if (!materialAsset->PreviewTexture)
|
||||||
if (m_Asset->AlbedoTexture) matInst->Set("u_AlbedoTexture", m_Asset->AlbedoTexture);
|
materialAsset->PreviewTexture = Texture2D::Create(TextureFormat::RGBA16F, 512, 512);
|
||||||
if (m_Asset->NormalTexture) matInst->Set("u_NormalTexture", m_Asset->NormalTexture);
|
|
||||||
if (m_Asset->MetalnessTexture) matInst->Set("u_MetalnessTexture", m_Asset->MetalnessTexture);
|
|
||||||
if (m_Asset->RoughnessTexture) matInst->Set("u_RoughnessTexture", m_Asset->RoughnessTexture);
|
|
||||||
|
|
||||||
// 设置通用 Uniform(与 GeometryPass 类似)
|
|
||||||
matInst->Set("u_ViewProjectionMatrix", viewProjection);
|
|
||||||
matInst->Set("u_ViewMatrix", view);
|
|
||||||
matInst->Set("u_CameraPosition", cameraPos);
|
|
||||||
|
|
||||||
// 环境光
|
|
||||||
matInst->Set("u_EnvRadianceTex", Renderer3D::GetBlackCubeTexture());
|
|
||||||
matInst->Set("u_EnvIrradianceTex", Renderer3D::GetBlackCubeTexture());
|
|
||||||
matInst->Set("u_IBLContribution", 0.0f); // 关闭 IBL,仅用方向光
|
|
||||||
|
|
||||||
// 灯光数据
|
|
||||||
matInst->Set("u_DirectionalLights", lightEnv.DirectionalLights);
|
|
||||||
matInst->Set("u_PointLightCount", 0);
|
|
||||||
matInst->Set("u_SpotLightCount", 0);
|
|
||||||
|
|
||||||
// 禁用阴影
|
|
||||||
matInst->Set("u_ShadowEnabled", false);
|
|
||||||
|
|
||||||
// 开始渲染
|
|
||||||
Renderer::BeginRenderPass(m_PreviewRenderPass);
|
|
||||||
|
|
||||||
auto cmd = Renderer::GetCommandBuffer();
|
auto cmd = Renderer::GetCommandBuffer();
|
||||||
auto& fb = m_PreviewRenderPass->GetSpecification().TargetFramebuffer;
|
auto fb = s_PreviewRenderPass->GetSpecification().TargetFramebuffer;
|
||||||
|
auto tex = materialAsset->PreviewTexture;
|
||||||
Renderer::Submit([cmd]() {
|
Renderer::Submit([cmd, fb, tex]() {
|
||||||
cmd->Clear(glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
|
|
||||||
});
|
|
||||||
|
|
||||||
Renderer::SubmitMesh(m_PreviewSphere, glm::mat4(1.0f), matInst);
|
|
||||||
|
|
||||||
if (!m_Asset->PreviewTexture)
|
|
||||||
{
|
|
||||||
m_Asset->PreviewTexture = Texture2D::Create(TextureFormat::RGBA16F, 512, 512);
|
|
||||||
}
|
|
||||||
auto& tex = m_Asset->PreviewTexture;
|
|
||||||
|
|
||||||
|
|
||||||
Renderer::Submit([cmd, &fb, tex]()
|
|
||||||
{
|
|
||||||
cmd->ResolveMultisampleTexture(fb, tex);
|
cmd->ResolveMultisampleTexture(fb, tex);
|
||||||
});
|
});
|
||||||
|
|
||||||
Renderer::EndRenderPass();
|
materialAsset->PreviewIsDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PBRMaterialEditor::Render()
|
void PBRMaterialEditor::Render()
|
||||||
@ -215,27 +213,24 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
if (ImGui::BeginTabItem("Basic Edit panel"))
|
if (ImGui::BeginTabItem("Basic Edit panel"))
|
||||||
{
|
{
|
||||||
|
if (m_Asset->PreviewTexture)
|
||||||
|
{
|
||||||
|
float previewSize = 256.0f;
|
||||||
|
ImGui::Image((ImTextureID)(intptr_t)m_Asset->PreviewTexture->GetRendererID(),
|
||||||
|
ImVec2(previewSize, previewSize), ImVec2(0, 1), ImVec2(1, 0));
|
||||||
|
}
|
||||||
RenderBasicEditorPanel();
|
RenderBasicEditorPanel();
|
||||||
ImGui::EndTabItem();
|
ImGui::EndTabItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::BeginTabItem("Graph Node Edit"))
|
if (ImGui::BeginTabItem("Graph Node Edit"))
|
||||||
{
|
{
|
||||||
// TODO: using ImGui Node Editor impl
|
|
||||||
RenderNodeEditorPanel();
|
RenderNodeEditorPanel();
|
||||||
ImGui::EndTabItem();
|
ImGui::EndTabItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndTabBar();
|
ImGui::EndTabBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this function don't work
|
|
||||||
/*
|
|
||||||
if (m_Asset->IsDirty)
|
|
||||||
{
|
|
||||||
RenderPreview();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -252,21 +247,21 @@ namespace Prism
|
|||||||
|
|
||||||
if (ImGui::ColorEdit3("Color##Albedo", glm::value_ptr(material->AlbedoColor)))
|
if (ImGui::ColorEdit3("Color##Albedo", glm::value_ptr(material->AlbedoColor)))
|
||||||
{
|
{
|
||||||
m_Asset->IsDirty = true;
|
MarkDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool useAlbedoMap = (material->AlbedoTexToggle > 0.5f);
|
bool useAlbedoMap = (material->AlbedoTexToggle > 0.5f);
|
||||||
if (ImGui::Checkbox("Use Texture##Albedo", &useAlbedoMap))
|
if (ImGui::Checkbox("Use Texture##Albedo", &useAlbedoMap))
|
||||||
{
|
{
|
||||||
material->AlbedoTexToggle = useAlbedoMap ? 1.0f : 0.0f;
|
material->AlbedoTexToggle = useAlbedoMap ? 1.0f : 0.0f;
|
||||||
m_Asset->IsDirty = true;
|
MarkDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawTextureSlot(material->AlbedoTexture, [&](const Ref<Texture2D>& newTex)
|
DrawTextureSlot(material->AlbedoTexture, [&](const Ref<Texture2D>& newTex)
|
||||||
{
|
{
|
||||||
material->AlbedoTexture = newTex;
|
material->AlbedoTexture = newTex;
|
||||||
material->AlbedoTexToggle = true;
|
material->AlbedoTexToggle = true;
|
||||||
m_Asset->IsDirty = true;
|
MarkDirty();
|
||||||
});
|
});
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Text("Albedo Texture");
|
ImGui::Text("Albedo Texture");
|
||||||
@ -283,14 +278,14 @@ namespace Prism
|
|||||||
if (ImGui::Checkbox("Use Texture##Normal", &useNormalMap))
|
if (ImGui::Checkbox("Use Texture##Normal", &useNormalMap))
|
||||||
{
|
{
|
||||||
material->NormalTexToggle = useNormalMap ? 1.0f : 0.0f;
|
material->NormalTexToggle = useNormalMap ? 1.0f : 0.0f;
|
||||||
m_Asset->IsDirty = true;
|
MarkDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawTextureSlot(material->NormalTexture, [&](const Ref<Texture2D>& newTex)
|
DrawTextureSlot(material->NormalTexture, [&](const Ref<Texture2D>& newTex)
|
||||||
{
|
{
|
||||||
material->NormalTexture = newTex;
|
material->NormalTexture = newTex;
|
||||||
material->NormalTexToggle = true;
|
material->NormalTexToggle = true;
|
||||||
m_Asset->IsDirty = true;
|
MarkDirty();
|
||||||
});
|
});
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Text("Normal Texture");
|
ImGui::Text("Normal Texture");
|
||||||
@ -306,21 +301,21 @@ namespace Prism
|
|||||||
if (ImGui::SliderFloat("Value##Metalness", &material->Metalness, 0.0f, 1.0f))
|
if (ImGui::SliderFloat("Value##Metalness", &material->Metalness, 0.0f, 1.0f))
|
||||||
{
|
{
|
||||||
// 自动保存
|
// 自动保存
|
||||||
m_Asset->IsDirty = true;
|
MarkDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool useMetalnessMap = (material->MetalnessTexToggle > 0.5f);
|
bool useMetalnessMap = (material->MetalnessTexToggle > 0.5f);
|
||||||
if (ImGui::Checkbox("Use Texture##Metalness", &useMetalnessMap))
|
if (ImGui::Checkbox("Use Texture##Metalness", &useMetalnessMap))
|
||||||
{
|
{
|
||||||
material->MetalnessTexToggle = useMetalnessMap ? 1.0f : 0.0f;
|
material->MetalnessTexToggle = useMetalnessMap ? 1.0f : 0.0f;
|
||||||
m_Asset->IsDirty = true;
|
MarkDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawTextureSlot(material->MetalnessTexture, [&](const Ref<Texture2D>& newTex)
|
DrawTextureSlot(material->MetalnessTexture, [&](const Ref<Texture2D>& newTex)
|
||||||
{
|
{
|
||||||
material->MetalnessTexture = newTex;
|
material->MetalnessTexture = newTex;
|
||||||
material->MetalnessTexToggle = true;
|
material->MetalnessTexToggle = true;
|
||||||
m_Asset->IsDirty = true;
|
MarkDirty();
|
||||||
});
|
});
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Text("Metalness Texture");
|
ImGui::Text("Metalness Texture");
|
||||||
@ -336,21 +331,21 @@ namespace Prism
|
|||||||
if (ImGui::SliderFloat("Value##Roughness", &material->Roughness, 0.0f, 1.0f))
|
if (ImGui::SliderFloat("Value##Roughness", &material->Roughness, 0.0f, 1.0f))
|
||||||
{
|
{
|
||||||
// 自动保存
|
// 自动保存
|
||||||
m_Asset->IsDirty = true;
|
MarkDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool useRoughnessMap = (material->RoughnessTexToggle > 0.5f);
|
bool useRoughnessMap = (material->RoughnessTexToggle > 0.5f);
|
||||||
if (ImGui::Checkbox("Use Texture##Roughness", &useRoughnessMap))
|
if (ImGui::Checkbox("Use Texture##Roughness", &useRoughnessMap))
|
||||||
{
|
{
|
||||||
material->RoughnessTexToggle = useRoughnessMap ? 1.0f : 0.0f;
|
material->RoughnessTexToggle = useRoughnessMap ? 1.0f : 0.0f;
|
||||||
m_Asset->IsDirty = true;
|
MarkDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawTextureSlot(material->RoughnessTexture, [&](const Ref<Texture2D>& newTex)
|
DrawTextureSlot(material->RoughnessTexture, [&](const Ref<Texture2D>& newTex)
|
||||||
{
|
{
|
||||||
material->RoughnessTexture = newTex;
|
material->RoughnessTexture = newTex;
|
||||||
material->RoughnessTexToggle = true;
|
material->RoughnessTexToggle = true;
|
||||||
m_Asset->IsDirty = true;
|
MarkDirty();
|
||||||
});
|
});
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Text("Roughness Texture");
|
ImGui::Text("Roughness Texture");
|
||||||
@ -413,7 +408,7 @@ namespace Prism
|
|||||||
if (ImGui::Button("Compile to Asset"))
|
if (ImGui::Button("Compile to Asset"))
|
||||||
{
|
{
|
||||||
CompileMaterialToAsset();
|
CompileMaterialToAsset();
|
||||||
m_Asset->IsDirty = true;
|
MarkDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
ed::Begin("MaterialNodeEditor");
|
ed::Begin("MaterialNodeEditor");
|
||||||
@ -453,7 +448,7 @@ namespace Prism
|
|||||||
|
|
||||||
void PBRMaterialEditor::DrawOutputNode()
|
void PBRMaterialEditor::DrawOutputNode()
|
||||||
{
|
{
|
||||||
const float nodeWidth = 240.0f;
|
const float nodeWidth = 100.0f;
|
||||||
|
|
||||||
ed::PushStyleVar(ed::StyleVar_NodePadding, ImVec4(8, 4, 8, 8));
|
ed::PushStyleVar(ed::StyleVar_NodePadding, ImVec4(8, 4, 8, 8));
|
||||||
ed::BeginNode(ed::NodeId(OUTPUT_NODE_ID));
|
ed::BeginNode(ed::NodeId(OUTPUT_NODE_ID));
|
||||||
@ -462,8 +457,17 @@ namespace Prism
|
|||||||
ImGui::BeginGroup();
|
ImGui::BeginGroup();
|
||||||
float headerMaxY = DrawNodeHeader("PBR Material Output", nodeWidth);
|
float headerMaxY = DrawNodeHeader("PBR Material Output", nodeWidth);
|
||||||
|
|
||||||
// TODO: this will add preview texture
|
if (m_Asset->PreviewTexture)
|
||||||
|
{
|
||||||
|
float previewWidth = nodeWidth;
|
||||||
|
float previewHeight = nodeWidth;
|
||||||
|
ImGui::Image((ImTextureID)(intptr_t)m_Asset->PreviewTexture->GetRendererID(),
|
||||||
|
ImVec2(previewWidth, previewHeight), ImVec2(0, 1), ImVec2(1, 0));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ImGui::Dummy(ImVec2(nodeWidth, 128));
|
ImGui::Dummy(ImVec2(nodeWidth, 128));
|
||||||
|
}
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
|
|
||||||
// 输入引脚
|
// 输入引脚
|
||||||
@ -501,14 +505,14 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
ImGui::SetNextItemWidth(80);
|
ImGui::SetNextItemWidth(80);
|
||||||
if (ImGui::SliderFloat("##metallic", &m_Asset->Metalness, 0.0f, 1.0f))
|
if (ImGui::SliderFloat("##metallic", &m_Asset->Metalness, 0.0f, 1.0f))
|
||||||
m_Asset->IsDirty = true;
|
MarkDirty();
|
||||||
});
|
});
|
||||||
|
|
||||||
drawInputPin(Roughness, "Roughness", [&]()
|
drawInputPin(Roughness, "Roughness", [&]()
|
||||||
{
|
{
|
||||||
ImGui::SetNextItemWidth(80);
|
ImGui::SetNextItemWidth(80);
|
||||||
if (ImGui::SliderFloat("##roughness", &m_Asset->Roughness, 0.0f, 1.0f))
|
if (ImGui::SliderFloat("##roughness", &m_Asset->Roughness, 0.0f, 1.0f))
|
||||||
m_Asset->IsDirty = true;
|
MarkDirty();
|
||||||
});
|
});
|
||||||
|
|
||||||
drawInputPin(AO, "AO", [&]()
|
drawInputPin(AO, "AO", [&]()
|
||||||
@ -582,7 +586,7 @@ namespace Prism
|
|||||||
if (AssetsManager::IsAssetType(handle, AssetType::Texture))
|
if (AssetsManager::IsAssetType(handle, AssetType::Texture))
|
||||||
{
|
{
|
||||||
textureHandle = handle;
|
textureHandle = handle;
|
||||||
m_Asset->IsDirty = true;
|
MarkDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::EndDragDropTarget();
|
ImGui::EndDragDropTarget();
|
||||||
@ -647,7 +651,7 @@ namespace Prism
|
|||||||
if (ed::AcceptNewItem(GetPinColor(pinType), 2.0f))
|
if (ed::AcceptNewItem(GetPinColor(pinType), 2.0f))
|
||||||
{
|
{
|
||||||
m_Links.push_back({m_NextLinkId++, start, end});
|
m_Links.push_back({m_NextLinkId++, start, end});
|
||||||
m_Asset->IsDirty = true;
|
MarkDirty();
|
||||||
CompileMaterialToAsset();
|
CompileMaterialToAsset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -672,7 +676,7 @@ namespace Prism
|
|||||||
int id = (int)linkId.Get();
|
int id = (int)linkId.Get();
|
||||||
m_Links.erase(std::remove_if(m_Links.begin(), m_Links.end(),
|
m_Links.erase(std::remove_if(m_Links.begin(), m_Links.end(),
|
||||||
[id](const Link& l) { return l.ID == id; }), m_Links.end());
|
[id](const Link& l) { return l.ID == id; }), m_Links.end());
|
||||||
m_Asset->IsDirty = true;
|
MarkDirty();
|
||||||
CompileMaterialToAsset();
|
CompileMaterialToAsset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -692,7 +696,7 @@ namespace Prism
|
|||||||
m_TextureNodes.erase(std::remove_if(m_TextureNodes.begin(), m_TextureNodes.end(),
|
m_TextureNodes.erase(std::remove_if(m_TextureNodes.begin(), m_TextureNodes.end(),
|
||||||
[id](const TextureNode& n) { return n.ID == id; }),
|
[id](const TextureNode& n) { return n.ID == id; }),
|
||||||
m_TextureNodes.end());
|
m_TextureNodes.end());
|
||||||
m_Asset->IsDirty = true;
|
MarkDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -728,7 +732,7 @@ namespace Prism
|
|||||||
ImVec2 canvasPos = ed::ScreenToCanvas(mousePos);
|
ImVec2 canvasPos = ed::ScreenToCanvas(mousePos);
|
||||||
int newId = m_NextNodeId++;
|
int newId = m_NextNodeId++;
|
||||||
m_TextureNodes.push_back({newId, dropHandle, canvasPos.x, canvasPos.y});
|
m_TextureNodes.push_back({newId, dropHandle, canvasPos.x, canvasPos.y});
|
||||||
m_Asset->IsDirty = true;
|
MarkDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::EndDragDropTarget();
|
ImGui::EndDragDropTarget();
|
||||||
@ -773,7 +777,7 @@ namespace Prism
|
|||||||
m_TextureNodes.erase(std::remove_if(m_TextureNodes.begin(), m_TextureNodes.end(),
|
m_TextureNodes.erase(std::remove_if(m_TextureNodes.begin(), m_TextureNodes.end(),
|
||||||
[id](const TextureNode& n) { return n.ID == id; }),
|
[id](const TextureNode& n) { return n.ID == id; }),
|
||||||
m_TextureNodes.end());
|
m_TextureNodes.end());
|
||||||
m_Asset->IsDirty = true;
|
MarkDirty();
|
||||||
CompileMaterialToAsset();
|
CompileMaterialToAsset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -790,7 +794,7 @@ namespace Prism
|
|||||||
if (ImGui::BeginPopup("AlbedoColorPicker"))
|
if (ImGui::BeginPopup("AlbedoColorPicker"))
|
||||||
{
|
{
|
||||||
if (ImGui::ColorPicker3("##picker", glm::value_ptr(m_Asset->AlbedoColor)))
|
if (ImGui::ColorPicker3("##picker", glm::value_ptr(m_Asset->AlbedoColor)))
|
||||||
m_Asset->IsDirty = true;
|
MarkDirty();
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -841,7 +845,7 @@ namespace Prism
|
|||||||
m_Asset->RoughnessTexture = getTexture(GetLinkedTextureHandle(InputPinID(Roughness)));
|
m_Asset->RoughnessTexture = getTexture(GetLinkedTextureHandle(InputPinID(Roughness)));
|
||||||
m_Asset->RoughnessTexToggle = m_Asset->RoughnessTexture ? 1.0f : 0.0f;
|
m_Asset->RoughnessTexToggle = m_Asset->RoughnessTexture ? 1.0f : 0.0f;
|
||||||
|
|
||||||
m_Asset->IsDirty = true;
|
MarkDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PBRMaterialEditor::LoadAssetToGraph()
|
void PBRMaterialEditor::LoadAssetToGraph()
|
||||||
|
|||||||
@ -25,29 +25,18 @@ namespace Prism
|
|||||||
Ref<Asset> GetAsset() override { return m_Asset; }
|
Ref<Asset> GetAsset() override { return m_Asset; }
|
||||||
void SetAsset(const Ref<Asset>& asset) override;
|
void SetAsset(const Ref<Asset>& asset) override;
|
||||||
|
|
||||||
|
static void InitPreviewRenderer();
|
||||||
|
static void RenderMaterialPreview(Ref<PBRMaterialAsset> materialAsset);
|
||||||
|
static Ref<PBRMaterialAsset> GetEditingAsset() { return s_EditingAsset; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ref<PBRMaterialAsset> m_Asset;
|
Ref<PBRMaterialAsset> m_Asset;
|
||||||
ed::EditorContext* m_EditorContext = nullptr;
|
ed::EditorContext* m_EditorContext = nullptr;
|
||||||
|
static Ref<PBRMaterialAsset> s_EditingAsset;
|
||||||
|
|
||||||
// 预览贴图
|
|
||||||
Ref<RenderPass> m_PreviewRenderPass;
|
|
||||||
Ref<Mesh> m_PreviewSphere;
|
|
||||||
Ref<MaterialInstance> m_PreviewMaterialInstance;
|
|
||||||
|
|
||||||
// camera 相关
|
|
||||||
glm::vec3 m_PreviewCameraPos = glm::vec3(3.0f, 2.0f, 5.0f);
|
|
||||||
glm::vec3 m_PreviewCameraTarget = glm::vec3(0.0f);
|
|
||||||
float m_PreviewFOV = 45.0f;
|
|
||||||
float m_PreviewNear = 0.1f;
|
|
||||||
float m_PreviewFar = 100.0f;
|
|
||||||
|
|
||||||
void InitPreviewResources();
|
|
||||||
void RenderPreview();
|
|
||||||
|
|
||||||
|
|
||||||
// 原有渲染函数
|
|
||||||
void Render() override;
|
void Render() override;
|
||||||
void RenderBasicEditorPanel();
|
void RenderBasicEditorPanel();
|
||||||
|
void MarkDirty() { m_Asset->IsDirty = true; m_Asset->PreviewIsDirty = true; }
|
||||||
|
|
||||||
// ---------- 节点编辑器相关 ----------
|
// ---------- 节点编辑器相关 ----------
|
||||||
void RenderNodeEditorPanel(); // 新的节点编辑器面板
|
void RenderNodeEditorPanel(); // 新的节点编辑器面板
|
||||||
|
|||||||
@ -405,6 +405,21 @@ namespace Prism
|
|||||||
glUseProgram(programID);
|
glUseProgram(programID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLCommandBuffer::BindVertexArray(const uint32_t vao) const
|
||||||
|
{
|
||||||
|
glBindVertexArray(vao);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLCommandBuffer::BindVertexBuffer(const uint32_t vbo) const
|
||||||
|
{
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLCommandBuffer::BindIndexBuffer(const uint32_t ibo) const
|
||||||
|
{
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
||||||
|
}
|
||||||
|
|
||||||
void OpenGLCommandBuffer::BindStorageBuffer(const uint32_t binding, const Ref<StorageBuffer>& ref) const
|
void OpenGLCommandBuffer::BindStorageBuffer(const uint32_t binding, const Ref<StorageBuffer>& ref) const
|
||||||
{
|
{
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, binding, ref->GetRendererID());
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, binding, ref->GetRendererID());
|
||||||
@ -426,6 +441,37 @@ namespace Prism
|
|||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLCommandBuffer::ResolveMultisampleTexture(const Ref<FrameBuffer>& src, uint32_t attachmentIndex, const Ref<Texture>& dst) const
|
||||||
|
{
|
||||||
|
uint32_t resolveFBO;
|
||||||
|
glGenFramebuffers(1, &resolveFBO);
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFBO);
|
||||||
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst->GetRendererID(), 0);
|
||||||
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, src->GetRendererID());
|
||||||
|
glReadBuffer(GL_COLOR_ATTACHMENT0 + attachmentIndex);
|
||||||
|
glBlitFramebuffer(0, 0, src->GetWidth(), src->GetHeight(),
|
||||||
|
0, 0, src->GetWidth(), src->GetHeight(),
|
||||||
|
GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||||
|
glDeleteFramebuffers(1, &resolveFBO);
|
||||||
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLCommandBuffer::ResolveMultisampleDepth(const Ref<FrameBuffer>& src, const Ref<Texture>& dst) const
|
||||||
|
{
|
||||||
|
uint32_t resolveFBO;
|
||||||
|
glGenFramebuffers(1, &resolveFBO);
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFBO);
|
||||||
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, dst->GetRendererID(), 0);
|
||||||
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, src->GetRendererID());
|
||||||
|
glBlitFramebuffer(0, 0, src->GetWidth(), src->GetHeight(),
|
||||||
|
0, 0, src->GetWidth(), src->GetHeight(),
|
||||||
|
GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
|
||||||
|
glDeleteFramebuffers(1, &resolveFBO);
|
||||||
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void OpenGLCommandBuffer::CopyFrameToTexture(const Ref<FrameBuffer>& src, const Ref<Texture>& dst) const
|
void OpenGLCommandBuffer::CopyFrameToTexture(const Ref<FrameBuffer>& src, const Ref<Texture>& dst) const
|
||||||
{
|
{
|
||||||
uint32_t tempFBO;
|
uint32_t tempFBO;
|
||||||
|
|||||||
@ -85,10 +85,15 @@ namespace Prism
|
|||||||
void ProgramUniform1f(uint32_t program, int32_t location, float value) const override;
|
void ProgramUniform1f(uint32_t program, int32_t location, float value) const override;
|
||||||
|
|
||||||
void UseProgram(uint32_t programID) const override;
|
void UseProgram(uint32_t programID) const override;
|
||||||
|
void BindVertexArray(uint32_t vao) const override;
|
||||||
|
void BindVertexBuffer(uint32_t vbo) const override;
|
||||||
|
void BindIndexBuffer(uint32_t ibo) const override;
|
||||||
|
|
||||||
void BindStorageBuffer(uint32_t binding, const Ref<StorageBuffer>& ref) const override;
|
void BindStorageBuffer(uint32_t binding, const Ref<StorageBuffer>& ref) const override;
|
||||||
|
|
||||||
void ResolveMultisampleTexture(const Ref<FrameBuffer>& src, const Ref<Texture>& dst) const override;
|
void ResolveMultisampleTexture(const Ref<FrameBuffer>& src, const Ref<Texture>& dst) const override;
|
||||||
|
void ResolveMultisampleTexture(const Ref<FrameBuffer>& src, uint32_t attachmentIndex, const Ref<Texture>& dst) const override;
|
||||||
|
void ResolveMultisampleDepth(const Ref<FrameBuffer>& src, const Ref<Texture>& dst) const override;
|
||||||
|
|
||||||
void CopyFrameToTexture(const Ref<FrameBuffer>& src, const Ref<Texture>& dst) const override;
|
void CopyFrameToTexture(const Ref<FrameBuffer>& src, const Ref<Texture>& dst) const override;
|
||||||
|
|
||||||
|
|||||||
@ -20,6 +20,7 @@ namespace Prism {
|
|||||||
virtual void Invalidate() override;
|
virtual void Invalidate() override;
|
||||||
|
|
||||||
virtual void Bind() override;
|
virtual void Bind() override;
|
||||||
|
virtual RendererID GetVertexArrayRendererID() const override { return m_VertexArrayRendererID; }
|
||||||
private:
|
private:
|
||||||
PipelineSpecification m_Specification;
|
PipelineSpecification m_Specification;
|
||||||
uint32_t m_VertexArrayRendererID = 0;
|
uint32_t m_VertexArrayRendererID = 0;
|
||||||
|
|||||||
@ -20,6 +20,8 @@ namespace Prism
|
|||||||
case TextureFormat::RGBA16F: return GL_RGBA16F;
|
case TextureFormat::RGBA16F: return GL_RGBA16F;
|
||||||
case TextureFormat::RG8: return GL_RG8;
|
case TextureFormat::RG8: return GL_RG8;
|
||||||
case TextureFormat::RG16F: return GL_RG16F;
|
case TextureFormat::RG16F: return GL_RG16F;
|
||||||
|
case TextureFormat::DEPTH24STENCIL8: return GL_DEPTH24_STENCIL8;
|
||||||
|
case TextureFormat::DEPTH32F: return GL_DEPTH_COMPONENT32F;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -31,6 +33,8 @@ namespace Prism
|
|||||||
case TextureFormat::RGBA16F: return GL_RGBA16F;
|
case TextureFormat::RGBA16F: return GL_RGBA16F;
|
||||||
case TextureFormat::RG8: return GL_RG8;
|
case TextureFormat::RG8: return GL_RG8;
|
||||||
case TextureFormat::RG16F: return GL_RG16F;
|
case TextureFormat::RG16F: return GL_RG16F;
|
||||||
|
case TextureFormat::DEPTH24STENCIL8: return GL_DEPTH24_STENCIL8;
|
||||||
|
case TextureFormat::DEPTH32F: return GL_DEPTH_COMPONENT32F;
|
||||||
default: return 0;
|
default: return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -42,6 +46,8 @@ namespace Prism
|
|||||||
case TextureFormat::RGBA16F: return GL_RGBA;
|
case TextureFormat::RGBA16F: return GL_RGBA;
|
||||||
case TextureFormat::RG8: return GL_RG;
|
case TextureFormat::RG8: return GL_RG;
|
||||||
case TextureFormat::RG16F: return GL_RG;
|
case TextureFormat::RG16F: return GL_RG;
|
||||||
|
case TextureFormat::DEPTH24STENCIL8: return GL_DEPTH_STENCIL;
|
||||||
|
case TextureFormat::DEPTH32F: return GL_DEPTH_COMPONENT;
|
||||||
default: return 0;
|
default: return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -51,6 +57,8 @@ namespace Prism
|
|||||||
case TextureFormat::RGB:
|
case TextureFormat::RGB:
|
||||||
case TextureFormat::RGBA: return GL_UNSIGNED_BYTE;
|
case TextureFormat::RGBA: return GL_UNSIGNED_BYTE;
|
||||||
case TextureFormat::RGBA16F: return GL_HALF_FLOAT;
|
case TextureFormat::RGBA16F: return GL_HALF_FLOAT;
|
||||||
|
case TextureFormat::DEPTH24STENCIL8: return GL_UNSIGNED_INT_24_8;
|
||||||
|
case TextureFormat::DEPTH32F: return GL_FLOAT;
|
||||||
default: return 0;
|
default: return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,3 @@
|
|||||||
//
|
|
||||||
// Created by Atdunbg on 2026/1/21.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
|
|
||||||
#include "Prism/Utilities/FileSystem.h"
|
#include "Prism/Utilities/FileSystem.h"
|
||||||
@ -22,7 +18,12 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
FileSystem::FileSystemChangedCallbackFn FileSystem::s_Callback;
|
FileSystem::FileSystemChangedCallbackFn FileSystem::s_Callback;
|
||||||
|
|
||||||
std::atomic<bool> FileSystem::s_IgnoreNextChange = false;
|
std::mutex FileSystem::s_EventQueueMutex;
|
||||||
|
std::vector<FileSystemChangedEvent> FileSystem::s_PendingEvents;
|
||||||
|
|
||||||
|
std::mutex FileSystem::s_RecentWritesMutex;
|
||||||
|
std::unordered_map<std::string, std::chrono::steady_clock::time_point> FileSystem::s_RecentWrites;
|
||||||
|
|
||||||
efsw::FileWatcher* FileSystem::s_FileWatcher = nullptr;
|
efsw::FileWatcher* FileSystem::s_FileWatcher = nullptr;
|
||||||
PrismFileWatcherListener* FileSystem::s_Listener = nullptr;
|
PrismFileWatcherListener* FileSystem::s_Listener = nullptr;
|
||||||
|
|
||||||
@ -35,10 +36,6 @@ namespace Prism
|
|||||||
efsw::Action action,
|
efsw::Action action,
|
||||||
std::string oldFilepath = "") override
|
std::string oldFilepath = "") override
|
||||||
{
|
{
|
||||||
// 如果引擎自身操作设置了忽略标志,则跳过本次事件
|
|
||||||
if (FileSystem::s_IgnoreNextChange.load())
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::string fullPath = (std::filesystem::path(dir) / filepath).string();
|
std::string fullPath = (std::filesystem::path(dir) / filepath).string();
|
||||||
|
|
||||||
fullPath = Utils::NormalizePath(fullPath);
|
fullPath = Utils::NormalizePath(fullPath);
|
||||||
@ -46,16 +43,13 @@ namespace Prism
|
|||||||
FileSystemChangedEvent e;
|
FileSystemChangedEvent e;
|
||||||
e.FilePath = fullPath;
|
e.FilePath = fullPath;
|
||||||
e.NewName = Utils::GetFilename(filepath);
|
e.NewName = Utils::GetFilename(filepath);
|
||||||
e.OldName = Utils::GetFilename(oldFilepath); // efsw 在重命名时会提供旧文件名
|
e.OldName = Utils::GetFilename(oldFilepath);
|
||||||
e.IsDirectory = false; // 稍后根据实际情况判断
|
e.IsDirectory = false;
|
||||||
|
|
||||||
// 判断是否为目录(可能抛出异常,使用 error_code 版本)
|
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
if (std::filesystem::is_directory(fullPath, ec))
|
if (std::filesystem::is_directory(fullPath, ec))
|
||||||
e.IsDirectory = true;
|
e.IsDirectory = true;
|
||||||
// 如果 ec 有错误(文件可能已被删除),保持 false
|
|
||||||
|
|
||||||
// 映射 efsw 动作到你的枚举
|
|
||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case efsw::Actions::Add:
|
case efsw::Actions::Add:
|
||||||
@ -71,12 +65,13 @@ namespace Prism
|
|||||||
e.Action = FileSystemAction::Rename;
|
e.Action = FileSystemAction::Rename;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return; // 忽略未知事件
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 调用外部回调(需确保线程安全)
|
{
|
||||||
if (FileSystem::s_Callback)
|
std::lock_guard<std::mutex> lock(FileSystem::s_EventQueueMutex);
|
||||||
FileSystem::s_Callback(e);
|
FileSystem::s_PendingEvents.push_back(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -96,7 +91,6 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建描述文字
|
|
||||||
if (!patterns.empty()) {
|
if (!patterns.empty()) {
|
||||||
description = "Custom files (";
|
description = "Custom files (";
|
||||||
for (size_t i = 0; i < patterns.size(); ++i) {
|
for (size_t i = 0; i < patterns.size(); ++i) {
|
||||||
@ -105,7 +99,6 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
description += ")";
|
description += ")";
|
||||||
|
|
||||||
// 准备 C 字符串数组
|
|
||||||
for (const auto& p : patterns) {
|
for (const auto& p : patterns) {
|
||||||
patternCstrs.push_back(p.c_str());
|
patternCstrs.push_back(p.c_str());
|
||||||
}
|
}
|
||||||
@ -113,12 +106,12 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char* result = tinyfd_openFileDialog(
|
const char* result = tinyfd_openFileDialog(
|
||||||
"Open File", // title
|
"Open File",
|
||||||
"", // default open path
|
"",
|
||||||
static_cast<int>(patternCstrs.size()), // filter count
|
static_cast<int>(patternCstrs.size()),
|
||||||
patternCstrs.empty() ? nullptr : patternCstrs.data(), // filter pattern
|
patternCstrs.empty() ? nullptr : patternCstrs.data(),
|
||||||
description.c_str(), // filter description
|
description.c_str(),
|
||||||
0 // 0 is single select, 1 is Multiple select
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
return result ? std::string(result) : std::string();
|
return result ? std::string(result) : std::string();
|
||||||
@ -176,13 +169,11 @@ namespace Prism
|
|||||||
std::string cmd;
|
std::string cmd;
|
||||||
if (std::filesystem::is_directory(absPath))
|
if (std::filesystem::is_directory(absPath))
|
||||||
{
|
{
|
||||||
// 打开目录
|
|
||||||
cmd = absPath.string();
|
cmd = absPath.string();
|
||||||
ShellExecuteA(nullptr, "open", "explorer.exe", cmd.c_str(), NULL, SW_SHOW);
|
ShellExecuteA(nullptr, "open", "explorer.exe", cmd.c_str(), NULL, SW_SHOW);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 打开并选中文件
|
|
||||||
cmd = "/select, \"" + absPath.string() + "\"";
|
cmd = "/select, \"" + absPath.string() + "\"";
|
||||||
ShellExecuteA(nullptr, "open", "explorer.exe", cmd.c_str(), NULL, SW_SHOW);
|
ShellExecuteA(nullptr, "open", "explorer.exe", cmd.c_str(), NULL, SW_SHOW);
|
||||||
}
|
}
|
||||||
@ -225,21 +216,20 @@ namespace Prism
|
|||||||
|
|
||||||
std::string FileSystem::Rename(const std::string& filepath, const std::string& newName)
|
std::string FileSystem::Rename(const std::string& filepath, const std::string& newName)
|
||||||
{
|
{
|
||||||
s_IgnoreNextChange = true;
|
|
||||||
const std::filesystem::path p = filepath;
|
const std::filesystem::path p = filepath;
|
||||||
std::string newFilePath = p.parent_path().string() + "/" + newName + p.extension().string();
|
std::string newFilePath = p.parent_path().string() + "/" + newName + p.extension().string();
|
||||||
|
NotifyFileWriting(filepath);
|
||||||
|
NotifyFileWriting(newFilePath);
|
||||||
MoveFileA(filepath.c_str(), newFilePath.c_str());
|
MoveFileA(filepath.c_str(), newFilePath.c_str());
|
||||||
s_IgnoreNextChange = false;
|
|
||||||
return newFilePath;
|
return newFilePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool FileSystem::PrismDeleteFile(const std::string& filepath)
|
bool FileSystem::PrismDeleteFile(const std::string& filepath)
|
||||||
{
|
{
|
||||||
s_IgnoreNextChange = true;
|
NotifyFileWriting(filepath);
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
const bool removed = std::filesystem::remove(filepath, ec);
|
const bool removed = std::filesystem::remove(filepath, ec);
|
||||||
s_IgnoreNextChange = false;
|
|
||||||
if (!removed || ec)
|
if (!removed || ec)
|
||||||
{
|
{
|
||||||
PM_CORE_ERROR("Delete failed: {}", ec.message());
|
PM_CORE_ERROR("Delete failed: {}", ec.message());
|
||||||
@ -250,14 +240,56 @@ namespace Prism
|
|||||||
|
|
||||||
bool FileSystem::PrismMoveFile(const std::string& filepath, const std::string& dest)
|
bool FileSystem::PrismMoveFile(const std::string& filepath, const std::string& dest)
|
||||||
{
|
{
|
||||||
s_IgnoreNextChange = true;
|
NotifyFileWriting(filepath);
|
||||||
std::filesystem::path p = filepath;
|
std::filesystem::path p = filepath;
|
||||||
const std::string destFilePath = dest + "/" + p.filename().string();
|
const std::string destFilePath = dest + "/" + p.filename().string();
|
||||||
|
NotifyFileWriting(destFilePath);
|
||||||
const BOOL result = MoveFileA(filepath.c_str(), destFilePath.c_str());
|
const BOOL result = MoveFileA(filepath.c_str(), destFilePath.c_str());
|
||||||
s_IgnoreNextChange = false;
|
|
||||||
return result != 0;
|
return result != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FileSystem::ProcessPendingEvents()
|
||||||
|
{
|
||||||
|
std::vector<FileSystemChangedEvent> events;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(s_EventQueueMutex);
|
||||||
|
events.swap(s_PendingEvents);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto now = std::chrono::steady_clock::now();
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(s_RecentWritesMutex);
|
||||||
|
for (auto it = s_RecentWrites.begin(); it != s_RecentWrites.end(); )
|
||||||
|
{
|
||||||
|
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - it->second).count();
|
||||||
|
if (elapsed > 2000)
|
||||||
|
it = s_RecentWrites.erase(it);
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& e : events)
|
||||||
|
{
|
||||||
|
if (e.Action == FileSystemAction::Modified)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(s_RecentWritesMutex);
|
||||||
|
if (s_RecentWrites.find(e.FilePath) != s_RecentWrites.end())
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_Callback)
|
||||||
|
s_Callback(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSystem::NotifyFileWriting(const std::string& filepath)
|
||||||
|
{
|
||||||
|
std::string normalized = Utils::NormalizePath(filepath);
|
||||||
|
std::lock_guard<std::mutex> lock(s_RecentWritesMutex);
|
||||||
|
s_RecentWrites[normalized] = std::chrono::steady_clock::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void FileSystem::StartWatching()
|
void FileSystem::StartWatching()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -144,6 +144,13 @@ namespace Prism
|
|||||||
|
|
||||||
const AABB& GetBoundingBox() const { return m_BoundingBox; }
|
const AABB& GetBoundingBox() const { return m_BoundingBox; }
|
||||||
|
|
||||||
|
void Bind()
|
||||||
|
{
|
||||||
|
m_VertexBuffer->Bind();
|
||||||
|
m_Pipeline->Bind();
|
||||||
|
m_IndexBuffer->Bind();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void TraverseNodes(const aiNode* node, const glm::mat4& parentTransform = glm::mat4(1.0f), uint32_t level = 0);
|
void TraverseNodes(const aiNode* node, const glm::mat4& parentTransform = glm::mat4(1.0f), uint32_t level = 0);
|
||||||
|
|
||||||
|
|||||||
@ -56,13 +56,13 @@ namespace Prism
|
|||||||
constexpr uint32_t latitudeBands = 30;
|
constexpr uint32_t latitudeBands = 30;
|
||||||
constexpr float longitudeBands = 30;
|
constexpr float longitudeBands = 30;
|
||||||
|
|
||||||
for (float latitude = 0.0f; latitude <= latitudeBands; latitude++)
|
for (uint32_t latitude = 0; latitude <= latitudeBands; latitude++)
|
||||||
{
|
{
|
||||||
const float theta = latitude * M_PI / latitudeBands;
|
const float theta = latitude * M_PI / latitudeBands;
|
||||||
const float sinTheta = glm::sin(theta);
|
const float sinTheta = glm::sin(theta);
|
||||||
float cosTheta = glm::cos(theta);
|
float cosTheta = glm::cos(theta);
|
||||||
|
|
||||||
for (float longitude = 0.0f; longitude <= longitudeBands; longitude++)
|
for (uint32_t longitude = 0; longitude <= static_cast<uint32_t>(longitudeBands); longitude++)
|
||||||
{
|
{
|
||||||
const float phi = longitude * 2 * M_PI / longitudeBands;
|
const float phi = longitude * 2 * M_PI / longitudeBands;
|
||||||
const float sinPhi = glm::sin(phi);
|
const float sinPhi = glm::sin(phi);
|
||||||
@ -71,6 +71,7 @@ namespace Prism
|
|||||||
Vertex vertex;
|
Vertex vertex;
|
||||||
vertex.Normal = { cosPhi * sinTheta, cosTheta, sinPhi * sinTheta };
|
vertex.Normal = { cosPhi * sinTheta, cosTheta, sinPhi * sinTheta };
|
||||||
vertex.Position = { radius * vertex.Normal.x, radius * vertex.Normal.y, radius * vertex.Normal.z };
|
vertex.Position = { radius * vertex.Normal.x, radius * vertex.Normal.y, radius * vertex.Normal.z };
|
||||||
|
vertex.Texcoord = { (float)longitude / (float)longitudeBands, (float)latitude / (float)latitudeBands };
|
||||||
vertices.push_back(vertex);
|
vertices.push_back(vertex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,8 +25,8 @@ namespace Prism {
|
|||||||
|
|
||||||
virtual void Invalidate() = 0;
|
virtual void Invalidate() = 0;
|
||||||
|
|
||||||
// TEMP: remove this when render command buffers are a thing
|
|
||||||
virtual void Bind() = 0;
|
virtual void Bind() = 0;
|
||||||
|
virtual RendererID GetVertexArrayRendererID() const = 0;
|
||||||
|
|
||||||
static Ref<Pipeline> Create(const PipelineSpecification& spec);
|
static Ref<Pipeline> Create(const PipelineSpecification& spec);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -113,9 +113,14 @@ namespace Prism {
|
|||||||
virtual int32_t GetUniformLocation(uint32_t program, const std::string& name) const = 0;
|
virtual int32_t GetUniformLocation(uint32_t program, const std::string& name) const = 0;
|
||||||
|
|
||||||
virtual void UseProgram(uint32_t programID) const = 0;
|
virtual void UseProgram(uint32_t programID) const = 0;
|
||||||
|
virtual void BindVertexArray(uint32_t vao) const = 0;
|
||||||
|
virtual void BindVertexBuffer(uint32_t vbo) const = 0;
|
||||||
|
virtual void BindIndexBuffer(uint32_t ibo) const = 0;
|
||||||
virtual void BindStorageBuffer(uint32_t binding, const Ref<StorageBuffer>& ref) const = 0;
|
virtual void BindStorageBuffer(uint32_t binding, const Ref<StorageBuffer>& ref) const = 0;
|
||||||
|
|
||||||
virtual void ResolveMultisampleTexture(const Ref<FrameBuffer>& src, const Ref<Texture>& dst) const = 0;
|
virtual void ResolveMultisampleTexture(const Ref<FrameBuffer>& src, const Ref<Texture>& dst) const = 0;
|
||||||
|
virtual void ResolveMultisampleTexture(const Ref<FrameBuffer>& src, uint32_t attachmentIndex, const Ref<Texture>& dst) const = 0;
|
||||||
|
virtual void ResolveMultisampleDepth(const Ref<FrameBuffer>& src, const Ref<Texture>& dst) const = 0;
|
||||||
|
|
||||||
|
|
||||||
virtual void CopyFrameToTexture(const Ref<FrameBuffer>& src, const Ref<Texture>& dst) const = 0;
|
virtual void CopyFrameToTexture(const Ref<FrameBuffer>& src, const Ref<Texture>& dst) const = 0;
|
||||||
|
|||||||
@ -7,6 +7,9 @@
|
|||||||
#include "Prism/Core/Timer.h"
|
#include "Prism/Core/Timer.h"
|
||||||
#include "Prism/Scene/Scene.h"
|
#include "Prism/Scene/Scene.h"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
#include "Renderer.h"
|
#include "Renderer.h"
|
||||||
#include "Renderer2D.h"
|
#include "Renderer2D.h"
|
||||||
#include "SceneRenderer.h"
|
#include "SceneRenderer.h"
|
||||||
@ -19,6 +22,8 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
struct Renderer3DData
|
struct Renderer3DData
|
||||||
{
|
{
|
||||||
|
static constexpr int CSM_CASCADE_COUNT = 4;
|
||||||
|
|
||||||
struct SceneInfo
|
struct SceneInfo
|
||||||
{
|
{
|
||||||
SceneRendererCamera SceneCamera;
|
SceneRendererCamera SceneCamera;
|
||||||
@ -42,16 +47,20 @@ namespace Prism
|
|||||||
struct ShadowData
|
struct ShadowData
|
||||||
{
|
{
|
||||||
Ref<Shader> ShadowMapShader, ShadowMapAnimShader;
|
Ref<Shader> ShadowMapShader, ShadowMapAnimShader;
|
||||||
Ref<RenderPass> ShadowMapRenderPass;
|
Ref<RenderPass> ShadowMapRenderPass[CSM_CASCADE_COUNT];
|
||||||
|
|
||||||
bool ShadowEnabled = true;
|
bool ShadowEnabled = true;
|
||||||
float ShadowBias = 0.001f;
|
float ShadowBias = 0.001f;
|
||||||
float ShadowIntensity = 1.0f;
|
float ShadowIntensity = 1.0f;
|
||||||
int ShadowSoftness = 1;
|
int ShadowSoftness = 1;
|
||||||
|
|
||||||
// Dynamic shadow mapping
|
float CascadeSplitLambda = 0.95f;
|
||||||
glm::vec3 SceneCenter{ 0.0f };
|
float ShadowFarOverride = 200.0f;
|
||||||
glm::vec3 SceneBounds{ 50.0f }; // Default bounds
|
float ShadowFar = 200.0f;
|
||||||
|
float ShadowDepthExtend = 50.0f;
|
||||||
|
float CascadeSplits[CSM_CASCADE_COUNT];
|
||||||
|
glm::mat4 LightSpaceMatrices[CSM_CASCADE_COUNT];
|
||||||
|
|
||||||
float OrthoSize = 100.0f;
|
float OrthoSize = 100.0f;
|
||||||
}ShadowData;
|
}ShadowData;
|
||||||
|
|
||||||
@ -93,7 +102,7 @@ namespace Prism
|
|||||||
|
|
||||||
RendererID ShadowMapSampler;
|
RendererID ShadowMapSampler;
|
||||||
|
|
||||||
glm::mat4 LightMatrices;
|
glm::mat4 LightMatrices[CSM_CASCADE_COUNT];
|
||||||
|
|
||||||
bool EnableBloom = false;
|
bool EnableBloom = false;
|
||||||
float BloomThreshold = 1.5f;
|
float BloomThreshold = 1.5f;
|
||||||
@ -130,6 +139,23 @@ namespace Prism
|
|||||||
float FadeDistance = 500.0f;
|
float FadeDistance = 500.0f;
|
||||||
}GridData;
|
}GridData;
|
||||||
|
|
||||||
|
struct SSRData
|
||||||
|
{
|
||||||
|
bool EnableSSR = false;
|
||||||
|
float Intensity = 1.0f;
|
||||||
|
float MaxDistance = 30.0f;
|
||||||
|
float Thickness = 0.5f;
|
||||||
|
int Steps = 64;
|
||||||
|
float BlurRadius = 4.0f;
|
||||||
|
|
||||||
|
Ref<Shader> SSRShader;
|
||||||
|
Ref<Shader> SSRBlurShader;
|
||||||
|
Ref<RenderPass> SSRRenderPass;
|
||||||
|
Ref<RenderPass> SSRBlurRenderPass;
|
||||||
|
Ref<Texture2D> SSRDepthTexture;
|
||||||
|
Ref<Texture2D> SSRMaterialInfoTexture;
|
||||||
|
} SSRData;
|
||||||
|
|
||||||
SceneRendererOptions Options;
|
SceneRendererOptions Options;
|
||||||
|
|
||||||
Ref<TextureCube> BlackCubeTexture;
|
Ref<TextureCube> BlackCubeTexture;
|
||||||
@ -159,7 +185,7 @@ namespace Prism
|
|||||||
//////////////// GeoPass ////////////////
|
//////////////// GeoPass ////////////////
|
||||||
{
|
{
|
||||||
FramebufferSpecification geoFramebufferSpec;
|
FramebufferSpecification geoFramebufferSpec;
|
||||||
geoFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA32F, FramebufferTextureFormat::DEPTH24STENCIL8 };
|
geoFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA32F, FramebufferTextureFormat::RGBA8, FramebufferTextureFormat::DEPTH24STENCIL8 };
|
||||||
geoFramebufferSpec.Samples = 8;
|
geoFramebufferSpec.Samples = 8;
|
||||||
geoFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f };
|
geoFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f };
|
||||||
|
|
||||||
@ -226,9 +252,12 @@ namespace Prism
|
|||||||
shadowMapFramebufferSpec.ClearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
|
shadowMapFramebufferSpec.ClearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||||
shadowMapFramebufferSpec.NoResize = true;
|
shadowMapFramebufferSpec.NoResize = true;
|
||||||
|
|
||||||
|
for (int i = 0; i < Renderer3DData::CSM_CASCADE_COUNT; i++)
|
||||||
|
{
|
||||||
RenderPassSpecification shadowMapRenderPassSpec;
|
RenderPassSpecification shadowMapRenderPassSpec;
|
||||||
shadowMapRenderPassSpec.TargetFramebuffer = FrameBuffer::Create(shadowMapFramebufferSpec);
|
shadowMapRenderPassSpec.TargetFramebuffer = FrameBuffer::Create(shadowMapFramebufferSpec);
|
||||||
s_Data.ShadowData.ShadowMapRenderPass = RenderPass::Create(shadowMapRenderPassSpec);
|
s_Data.ShadowData.ShadowMapRenderPass[i] = RenderPass::Create(shadowMapRenderPassSpec);
|
||||||
|
}
|
||||||
|
|
||||||
auto cmd = Renderer::GetCommandBuffer();
|
auto cmd = Renderer::GetCommandBuffer();
|
||||||
|
|
||||||
@ -237,6 +266,7 @@ namespace Prism
|
|||||||
desc.MagFilter = FilterMode::Linear;
|
desc.MagFilter = FilterMode::Linear;
|
||||||
desc.WrapU = WrapMode::ClampToEdge;
|
desc.WrapU = WrapMode::ClampToEdge;
|
||||||
desc.WrapV = WrapMode::ClampToEdge;
|
desc.WrapV = WrapMode::ClampToEdge;
|
||||||
|
desc.BorderColor = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||||
s_Data.ShadowMapSampler = Renderer::GetDevice()->CreateSampler(desc);
|
s_Data.ShadowMapSampler = Renderer::GetDevice()->CreateSampler(desc);
|
||||||
}
|
}
|
||||||
/////////////////////////////////////////////
|
/////////////////////////////////////////////
|
||||||
@ -244,6 +274,29 @@ namespace Prism
|
|||||||
s_Data.CompositeShader = Shader::Create("assets/shaders/SceneComposite.glsl");
|
s_Data.CompositeShader = Shader::Create("assets/shaders/SceneComposite.glsl");
|
||||||
s_Data.BRDFLUT = Texture2D::Create("assets/textures/BRDF_LUT.tga", false, true);
|
s_Data.BRDFLUT = Texture2D::Create("assets/textures/BRDF_LUT.tga", false, true);
|
||||||
|
|
||||||
|
//////////////// SSR ////////////////
|
||||||
|
{
|
||||||
|
FramebufferSpecification ssrFramebufferSpec;
|
||||||
|
ssrFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA16F };
|
||||||
|
ssrFramebufferSpec.ClearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||||
|
|
||||||
|
RenderPassSpecification ssrRenderPassSpec;
|
||||||
|
ssrRenderPassSpec.TargetFramebuffer = FrameBuffer::Create(ssrFramebufferSpec);
|
||||||
|
s_Data.SSRData.SSRRenderPass = RenderPass::Create(ssrRenderPassSpec);
|
||||||
|
|
||||||
|
FramebufferSpecification ssrBlurFramebufferSpec;
|
||||||
|
ssrBlurFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA16F };
|
||||||
|
ssrBlurFramebufferSpec.ClearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||||
|
|
||||||
|
RenderPassSpecification ssrBlurRenderPassSpec;
|
||||||
|
ssrBlurRenderPassSpec.TargetFramebuffer = FrameBuffer::Create(ssrBlurFramebufferSpec);
|
||||||
|
s_Data.SSRData.SSRBlurRenderPass = RenderPass::Create(ssrBlurRenderPassSpec);
|
||||||
|
|
||||||
|
s_Data.SSRData.SSRShader = Shader::Create("assets/shaders/SSR.glsl");
|
||||||
|
s_Data.SSRData.SSRBlurShader = Shader::Create("assets/shaders/SSRBlur.glsl");
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
|
||||||
// Grid
|
// Grid
|
||||||
// const auto gridShader = Shader::Create("assets/shaders/Grid.glsl");
|
// const auto gridShader = Shader::Create("assets/shaders/Grid.glsl");
|
||||||
const auto gridShader = Shader::Create("assets/shaders/InfiniteGrid.glsl");
|
const auto gridShader = Shader::Create("assets/shaders/InfiniteGrid.glsl");
|
||||||
@ -284,6 +337,11 @@ namespace Prism
|
|||||||
s_Data.BloomBlurPass[0]->GetSpecification().TargetFramebuffer->Resize(width, height);
|
s_Data.BloomBlurPass[0]->GetSpecification().TargetFramebuffer->Resize(width, height);
|
||||||
s_Data.BloomBlurPass[1]->GetSpecification().TargetFramebuffer->Resize(width, height);
|
s_Data.BloomBlurPass[1]->GetSpecification().TargetFramebuffer->Resize(width, height);
|
||||||
s_Data.BloomBlendPass->GetSpecification().TargetFramebuffer->Resize(width, height);
|
s_Data.BloomBlendPass->GetSpecification().TargetFramebuffer->Resize(width, height);
|
||||||
|
|
||||||
|
if (s_Data.SSRData.SSRRenderPass)
|
||||||
|
s_Data.SSRData.SSRRenderPass->GetSpecification().TargetFramebuffer->Resize(width, height);
|
||||||
|
if (s_Data.SSRData.SSRBlurRenderPass)
|
||||||
|
s_Data.SSRData.SSRBlurRenderPass->GetSpecification().TargetFramebuffer->Resize(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer3D::BeginScene(const Scene* scene, const SceneRendererCamera& camera)
|
void Renderer3D::BeginScene(const Scene* scene, const SceneRendererCamera& camera)
|
||||||
@ -468,6 +526,10 @@ namespace Prism
|
|||||||
return s_Data.BlackTexture;
|
return s_Data.BlackTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ref<Texture2D> Renderer3D::GetBRDFLUT()
|
||||||
|
{
|
||||||
|
return s_Data.BRDFLUT;
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer3D::FlushDrawList(Ref<RenderPass>& outRenderPass)
|
void Renderer3D::FlushDrawList(Ref<RenderPass>& outRenderPass)
|
||||||
{
|
{
|
||||||
@ -493,6 +555,12 @@ namespace Prism
|
|||||||
|
|
||||||
ResolveMSAA();
|
ResolveMSAA();
|
||||||
|
|
||||||
|
if (s_Data.SSRData.EnableSSR)
|
||||||
|
{
|
||||||
|
SSRPass();
|
||||||
|
SSRBlurPass();
|
||||||
|
}
|
||||||
|
|
||||||
BloomBlurPass();
|
BloomBlurPass();
|
||||||
|
|
||||||
GridPass();
|
GridPass();
|
||||||
@ -589,43 +657,106 @@ namespace Prism
|
|||||||
|
|
||||||
if (!s_Data.ShadowData.ShadowEnabled || directionalLights.Intensity == 0.0f || !directionalLights.CastShadows)
|
if (!s_Data.ShadowData.ShadowEnabled || directionalLights.Intensity == 0.0f || !directionalLights.CastShadows)
|
||||||
{
|
{
|
||||||
Renderer::BeginRenderPass(s_Data.ShadowData.ShadowMapRenderPass);
|
for (int i = 0; i < Renderer3DData::CSM_CASCADE_COUNT; i++)
|
||||||
|
{
|
||||||
|
Renderer::BeginRenderPass(s_Data.ShadowData.ShadowMapRenderPass[i]);
|
||||||
Renderer::EndRenderPass();
|
Renderer::EndRenderPass();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float shadowOrthoSize = s_Data.ShadowData.OrthoSize;
|
const auto& sceneCamera = s_Data.SceneData.SceneCamera;
|
||||||
const float shadowNear = 0.1f;
|
const float cameraNear = sceneCamera.Camera.GetNear();
|
||||||
const float shadowFar = shadowOrthoSize * 6.0f;
|
const float cameraFar = sceneCamera.Camera.GetFar();
|
||||||
|
const float shadowFar = glm::min(s_Data.ShadowData.ShadowFarOverride, cameraFar);
|
||||||
|
s_Data.ShadowData.ShadowFar = shadowFar;
|
||||||
|
const float lambda = s_Data.ShadowData.CascadeSplitLambda;
|
||||||
|
const glm::mat4 cameraProj = sceneCamera.Camera.GetProjectionMatrix();
|
||||||
|
const glm::mat4 cameraView = sceneCamera.ViewMatrix;
|
||||||
|
const glm::mat4 cameraInvViewProj = glm::inverse(cameraProj * cameraView);
|
||||||
|
|
||||||
const glm::vec3 lightDir = glm::normalize(directionalLights.Direction);
|
const glm::vec3 lightDir = glm::normalize(directionalLights.Direction);
|
||||||
|
|
||||||
const glm::vec3 cameraPos = glm::inverse(s_Data.SceneData.SceneCamera.ViewMatrix)[3];
|
|
||||||
glm::vec3 shadowCenter = cameraPos;
|
|
||||||
shadowCenter.y = 0.0f;
|
|
||||||
|
|
||||||
glm::vec3 lightUp = glm::vec3(0.0f, 1.0f, 0.0f);
|
glm::vec3 lightUp = glm::vec3(0.0f, 1.0f, 0.0f);
|
||||||
if (glm::abs(lightDir.y) > 0.9f)
|
if (glm::abs(lightDir.y) > 0.9f)
|
||||||
lightUp = glm::vec3(1.0f, 0.0f, 0.0f);
|
lightUp = glm::vec3(1.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
const glm::vec3 lightPos = shadowCenter + lightDir * (shadowOrthoSize * 3.0f);
|
glm::vec4 fullFrustumCorners[8];
|
||||||
const glm::mat4 lightView = glm::lookAt(lightPos, shadowCenter, lightUp);
|
glm::vec4 ndcCorners[8] = {
|
||||||
const glm::mat4 lightProj = glm::ortho(
|
{-1.0f, -1.0f, -1.0f, 1.0f}, {1.0f, -1.0f, -1.0f, 1.0f},
|
||||||
-shadowOrthoSize, shadowOrthoSize,
|
{1.0f, 1.0f, -1.0f, 1.0f}, {-1.0f, 1.0f, -1.0f, 1.0f},
|
||||||
-shadowOrthoSize, shadowOrthoSize,
|
{-1.0f, -1.0f, 1.0f, 1.0f}, {1.0f, -1.0f, 1.0f, 1.0f},
|
||||||
shadowNear, shadowFar
|
{1.0f, 1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f, 1.0f}
|
||||||
);
|
};
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
fullFrustumCorners[i] = cameraInvViewProj * ndcCorners[i];
|
||||||
|
fullFrustumCorners[i] /= fullFrustumCorners[i].w;
|
||||||
|
}
|
||||||
|
|
||||||
const glm::mat4 lightSpaceMatrix = lightProj * lightView;
|
for (int cascade = 0; cascade < Renderer3DData::CSM_CASCADE_COUNT; cascade++)
|
||||||
s_Data.LightMatrices = lightSpaceMatrix;
|
{
|
||||||
|
float splitDist = float(cascade + 1) / float(Renderer3DData::CSM_CASCADE_COUNT);
|
||||||
|
float logSplit = cameraNear * std::pow(shadowFar / cameraNear, splitDist);
|
||||||
|
float linearSplit = cameraNear + (shadowFar - cameraNear) * splitDist;
|
||||||
|
float splitZ = lambda * logSplit + (1.0f - lambda) * linearSplit;
|
||||||
|
|
||||||
|
s_Data.ShadowData.CascadeSplits[cascade] = (splitZ - cameraNear) / (shadowFar - cameraNear);
|
||||||
|
|
||||||
|
float prevSplitZ = (cascade == 0) ? cameraNear :
|
||||||
|
cameraNear + (shadowFar - cameraNear) * s_Data.ShadowData.CascadeSplits[cascade - 1];
|
||||||
|
float nextSplitZ = splitZ;
|
||||||
|
|
||||||
|
float prevRatio = (cameraFar == cameraNear) ? 0.0f :
|
||||||
|
(prevSplitZ - cameraNear) / (cameraFar - cameraNear);
|
||||||
|
float nextRatio = (cameraFar == cameraNear) ? 0.0f :
|
||||||
|
(nextSplitZ - cameraNear) / (cameraFar - cameraNear);
|
||||||
|
|
||||||
|
glm::vec4 frustumCorners[8];
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
glm::vec3 ray = glm::vec3(fullFrustumCorners[i + 4]) - glm::vec3(fullFrustumCorners[i]);
|
||||||
|
frustumCorners[i] = glm::vec4(glm::vec3(fullFrustumCorners[i]) + ray * prevRatio, 1.0f);
|
||||||
|
frustumCorners[i + 4] = glm::vec4(glm::vec3(fullFrustumCorners[i]) + ray * nextRatio, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 center = glm::vec3(0.0f);
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
center += glm::vec3(frustumCorners[i]);
|
||||||
|
center /= 8.0f;
|
||||||
|
|
||||||
|
glm::mat4 lightView = glm::lookAt(center + lightDir, center, lightUp);
|
||||||
|
|
||||||
|
float minX = std::numeric_limits<float>::max();
|
||||||
|
float maxX = std::numeric_limits<float>::lowest();
|
||||||
|
float minY = std::numeric_limits<float>::max();
|
||||||
|
float maxY = std::numeric_limits<float>::lowest();
|
||||||
|
float minZ = std::numeric_limits<float>::max();
|
||||||
|
float maxZ = std::numeric_limits<float>::lowest();
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
glm::vec4 lsCorner = lightView * frustumCorners[i];
|
||||||
|
minX = glm::min(minX, lsCorner.x);
|
||||||
|
maxX = glm::max(maxX, lsCorner.x);
|
||||||
|
minY = glm::min(minY, lsCorner.y);
|
||||||
|
maxY = glm::max(maxY, lsCorner.y);
|
||||||
|
minZ = glm::min(minZ, lsCorner.z);
|
||||||
|
maxZ = glm::max(maxZ, lsCorner.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::mat4 lightProj = glm::ortho(minX, maxX, minY, maxY, -maxZ - s_Data.ShadowData.ShadowDepthExtend, -minZ);
|
||||||
|
|
||||||
|
glm::mat4 lightSpaceMatrix = lightProj * lightView;
|
||||||
|
s_Data.ShadowData.LightSpaceMatrices[cascade] = lightSpaceMatrix;
|
||||||
|
s_Data.LightMatrices[cascade] = lightSpaceMatrix;
|
||||||
|
|
||||||
Renderer::Submit([cmd]()
|
Renderer::Submit([cmd]()
|
||||||
{
|
{
|
||||||
cmd->SetCullMode(CullMode::Back);
|
cmd->SetCullMode(CullMode::Back);
|
||||||
});
|
});
|
||||||
|
|
||||||
Renderer::BeginRenderPass(s_Data.ShadowData.ShadowMapRenderPass);
|
Renderer::BeginRenderPass(s_Data.ShadowData.ShadowMapRenderPass[cascade]);
|
||||||
|
|
||||||
for (auto& dc : s_Data.ShadowPassDrawList)
|
for (auto& dc : s_Data.ShadowPassDrawList)
|
||||||
{
|
{
|
||||||
@ -641,6 +772,7 @@ namespace Prism
|
|||||||
|
|
||||||
Renderer::EndRenderPass();
|
Renderer::EndRenderPass();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Renderer3D::GeometryPass()
|
void Renderer3D::GeometryPass()
|
||||||
@ -743,10 +875,22 @@ namespace Prism
|
|||||||
// baseMaterial->Set("u_DirectionalLights", s_Data.SceneData.ActiveLight);
|
// baseMaterial->Set("u_DirectionalLights", s_Data.SceneData.ActiveLight);
|
||||||
|
|
||||||
// shadow
|
// shadow
|
||||||
baseMaterial->Set("u_LightSpaceMatrix", s_Data.LightMatrices);
|
|
||||||
baseMaterial->Set("u_ShadowEnabled", s_Data.ShadowData.ShadowEnabled);
|
baseMaterial->Set("u_ShadowEnabled", s_Data.ShadowData.ShadowEnabled);
|
||||||
if (s_Data.ShadowData.ShadowEnabled)
|
if (s_Data.ShadowData.ShadowEnabled)
|
||||||
{
|
{
|
||||||
|
baseMaterial->Set("u_LightSpaceMatrix0", s_Data.LightMatrices[0]);
|
||||||
|
baseMaterial->Set("u_LightSpaceMatrix1", s_Data.LightMatrices[1]);
|
||||||
|
baseMaterial->Set("u_LightSpaceMatrix2", s_Data.LightMatrices[2]);
|
||||||
|
baseMaterial->Set("u_LightSpaceMatrix3", s_Data.LightMatrices[3]);
|
||||||
|
baseMaterial->Set("u_ShadowFar", s_Data.ShadowData.ShadowFar);
|
||||||
|
baseMaterial->Set("u_ShadowNear", sceneCamera.Camera.GetNear());
|
||||||
|
glm::vec4 cascadeSplits(
|
||||||
|
s_Data.ShadowData.CascadeSplits[0],
|
||||||
|
s_Data.ShadowData.CascadeSplits[1],
|
||||||
|
s_Data.ShadowData.CascadeSplits[2],
|
||||||
|
s_Data.ShadowData.CascadeSplits[3]
|
||||||
|
);
|
||||||
|
baseMaterial->Set("u_CascadeSplits", cascadeSplits);
|
||||||
baseMaterial->Set("u_ShadowBias", s_Data.ShadowData.ShadowBias);
|
baseMaterial->Set("u_ShadowBias", s_Data.ShadowData.ShadowBias);
|
||||||
baseMaterial->Set("u_ShadowIntensity", s_Data.ShadowData.ShadowIntensity);
|
baseMaterial->Set("u_ShadowIntensity", s_Data.ShadowData.ShadowIntensity);
|
||||||
baseMaterial->Set("u_ShadowSoftness", (float)s_Data.ShadowData.ShadowSoftness);
|
baseMaterial->Set("u_ShadowSoftness", (float)s_Data.ShadowData.ShadowSoftness);
|
||||||
@ -754,9 +898,11 @@ namespace Prism
|
|||||||
auto rd = baseMaterial->FindResourceDeclaration("u_ShadowMap");
|
auto rd = baseMaterial->FindResourceDeclaration("u_ShadowMap");
|
||||||
if (rd)
|
if (rd)
|
||||||
{
|
{
|
||||||
auto reg = rd->GetRegister();
|
uint32_t baseReg = rd->GetRegister();
|
||||||
auto tex = s_Data.ShadowData.ShadowMapRenderPass->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID();
|
for (int i = 0; i < Renderer3DData::CSM_CASCADE_COUNT; i++)
|
||||||
|
{
|
||||||
|
uint32_t reg = baseReg + i;
|
||||||
|
auto tex = s_Data.ShadowData.ShadowMapRenderPass[i]->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID();
|
||||||
Renderer::Submit([reg, tex, cmd]() mutable
|
Renderer::Submit([reg, tex, cmd]() mutable
|
||||||
{
|
{
|
||||||
cmd->BindTextureUnit(reg, tex);
|
cmd->BindTextureUnit(reg, tex);
|
||||||
@ -764,6 +910,7 @@ namespace Prism
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Renderer::SubmitMesh(dc.mesh, dc.Transform, dc.MaterialInstances);
|
Renderer::SubmitMesh(dc.mesh, dc.Transform, dc.MaterialInstances);
|
||||||
}
|
}
|
||||||
@ -832,18 +979,31 @@ namespace Prism
|
|||||||
baseMaterial->Set("u_ShadowEnabled", s_Data.ShadowData.ShadowEnabled);
|
baseMaterial->Set("u_ShadowEnabled", s_Data.ShadowData.ShadowEnabled);
|
||||||
if (s_Data.ShadowData.ShadowEnabled)
|
if (s_Data.ShadowData.ShadowEnabled)
|
||||||
{
|
{
|
||||||
baseMaterial->Set("u_LightSpaceMatrix", s_Data.LightMatrices);
|
baseMaterial->Set("u_LightSpaceMatrix0", s_Data.LightMatrices[0]);
|
||||||
|
baseMaterial->Set("u_LightSpaceMatrix1", s_Data.LightMatrices[1]);
|
||||||
|
baseMaterial->Set("u_LightSpaceMatrix2", s_Data.LightMatrices[2]);
|
||||||
|
baseMaterial->Set("u_LightSpaceMatrix3", s_Data.LightMatrices[3]);
|
||||||
|
baseMaterial->Set("u_ShadowFar", s_Data.ShadowData.ShadowFar);
|
||||||
|
baseMaterial->Set("u_ShadowNear", sceneCamera.Camera.GetNear());
|
||||||
|
glm::vec4 cascadeSplits(
|
||||||
|
s_Data.ShadowData.CascadeSplits[0],
|
||||||
|
s_Data.ShadowData.CascadeSplits[1],
|
||||||
|
s_Data.ShadowData.CascadeSplits[2],
|
||||||
|
s_Data.ShadowData.CascadeSplits[3]
|
||||||
|
);
|
||||||
|
baseMaterial->Set("u_CascadeSplits", cascadeSplits);
|
||||||
baseMaterial->Set("u_ShadowBias", s_Data.ShadowData.ShadowBias);
|
baseMaterial->Set("u_ShadowBias", s_Data.ShadowData.ShadowBias);
|
||||||
baseMaterial->Set("u_ShadowIntensity", s_Data.ShadowData.ShadowIntensity);
|
baseMaterial->Set("u_ShadowIntensity", s_Data.ShadowData.ShadowIntensity);
|
||||||
baseMaterial->Set("u_ShadowSoftness", (float)s_Data.ShadowData.ShadowSoftness);
|
baseMaterial->Set("u_ShadowSoftness", (float)s_Data.ShadowData.ShadowSoftness);
|
||||||
|
|
||||||
|
|
||||||
auto rd = baseMaterial->FindResourceDeclaration("u_ShadowMap");
|
auto rd = baseMaterial->FindResourceDeclaration("u_ShadowMap");
|
||||||
if (rd)
|
if (rd)
|
||||||
{
|
{
|
||||||
auto reg = rd->GetRegister();
|
uint32_t baseReg = rd->GetRegister();
|
||||||
auto tex = s_Data.ShadowData.ShadowMapRenderPass->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID();
|
for (int i = 0; i < Renderer3DData::CSM_CASCADE_COUNT; i++)
|
||||||
|
{
|
||||||
|
uint32_t reg = baseReg + i;
|
||||||
|
auto tex = s_Data.ShadowData.ShadowMapRenderPass[i]->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID();
|
||||||
Renderer::Submit([reg, tex, cmd]() mutable
|
Renderer::Submit([reg, tex, cmd]() mutable
|
||||||
{
|
{
|
||||||
cmd->BindTextureUnit(reg, tex);
|
cmd->BindTextureUnit(reg, tex);
|
||||||
@ -851,6 +1011,7 @@ namespace Prism
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Renderer::SubmitMesh(dc.mesh, dc.Transform, dc.MaterialInstances);
|
Renderer::SubmitMesh(dc.mesh, dc.Transform, dc.MaterialInstances);
|
||||||
}
|
}
|
||||||
@ -1070,6 +1231,7 @@ namespace Prism
|
|||||||
s_Data.CompositeShader->SetFloat("u_ManualExposure", s_Data.SceneData.SceneCamera.Camera.GetExposure());
|
s_Data.CompositeShader->SetFloat("u_ManualExposure", s_Data.SceneData.SceneCamera.Camera.GetExposure());
|
||||||
s_Data.CompositeShader->SetInt("u_TextureSamples", s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetSpecification().Samples);
|
s_Data.CompositeShader->SetInt("u_TextureSamples", s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetSpecification().Samples);
|
||||||
s_Data.CompositeShader->SetBool("u_EnableBloom", s_Data.EnableBloom);
|
s_Data.CompositeShader->SetBool("u_EnableBloom", s_Data.EnableBloom);
|
||||||
|
s_Data.CompositeShader->SetBool("u_EnableSSR", s_Data.SSRData.EnableSSR);
|
||||||
|
|
||||||
|
|
||||||
// Fog
|
// Fog
|
||||||
@ -1093,6 +1255,12 @@ namespace Prism
|
|||||||
s_Data.CompositeShader->SetInt("u_BloomTexture", 2);
|
s_Data.CompositeShader->SetInt("u_BloomTexture", 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (s_Data.SSRData.EnableSSR)
|
||||||
|
{
|
||||||
|
s_Data.SSRData.SSRBlurRenderPass->GetSpecification().TargetFramebuffer->BindTexture(0, 3);
|
||||||
|
s_Data.CompositeShader->SetInt("u_SSRTexture", 3);
|
||||||
|
}
|
||||||
|
|
||||||
Renderer::SubmitFullscreenQuad(false);
|
Renderer::SubmitFullscreenQuad(false);
|
||||||
|
|
||||||
auto depthFB = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
|
auto depthFB = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
|
||||||
@ -1110,6 +1278,85 @@ namespace Prism
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Renderer3D::SSRPass()
|
||||||
|
{
|
||||||
|
auto srcFB = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
|
||||||
|
const uint32_t width = srcFB->GetWidth();
|
||||||
|
const uint32_t height = srcFB->GetHeight();
|
||||||
|
|
||||||
|
if (!s_Data.SSRData.SSRDepthTexture ||
|
||||||
|
s_Data.SSRData.SSRDepthTexture->GetWidth() != width ||
|
||||||
|
s_Data.SSRData.SSRDepthTexture->GetHeight() != height)
|
||||||
|
{
|
||||||
|
s_Data.SSRData.SSRDepthTexture = Texture2D::Create(TextureFormat::DEPTH24STENCIL8, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!s_Data.SSRData.SSRMaterialInfoTexture ||
|
||||||
|
s_Data.SSRData.SSRMaterialInfoTexture->GetWidth() != width ||
|
||||||
|
s_Data.SSRData.SSRMaterialInfoTexture->GetHeight() != height)
|
||||||
|
{
|
||||||
|
s_Data.SSRData.SSRMaterialInfoTexture = Texture2D::Create(TextureFormat::RGBA, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cmd = Renderer::GetCommandBuffer();
|
||||||
|
|
||||||
|
Renderer::Submit([srcFB, depthTex = s_Data.SSRData.SSRDepthTexture, cmd]() {
|
||||||
|
cmd->ResolveMultisampleDepth(srcFB, depthTex);
|
||||||
|
});
|
||||||
|
|
||||||
|
Renderer::Submit([srcFB, matTex = s_Data.SSRData.SSRMaterialInfoTexture, cmd]() {
|
||||||
|
cmd->ResolveMultisampleTexture(srcFB, 1, matTex);
|
||||||
|
});
|
||||||
|
|
||||||
|
Renderer::BeginRenderPass(s_Data.SSRData.SSRRenderPass);
|
||||||
|
|
||||||
|
s_Data.SSRData.SSRShader->Bind();
|
||||||
|
s_Data.SSRData.SSRShader->SetInt("u_ColorTexture", 0);
|
||||||
|
s_Data.SSRData.SSRShader->SetInt("u_DepthTexture", 1);
|
||||||
|
s_Data.SSRData.SSRShader->SetInt("u_MaterialInfoTexture", 2);
|
||||||
|
|
||||||
|
s_Data.ResolvedHDRTexture->Bind(0);
|
||||||
|
s_Data.SSRData.SSRDepthTexture->Bind(1);
|
||||||
|
s_Data.SSRData.SSRMaterialInfoTexture->Bind(2);
|
||||||
|
|
||||||
|
const auto& sceneCamera = s_Data.SceneData.SceneCamera;
|
||||||
|
const auto cameraProjection = sceneCamera.Camera.GetProjectionMatrix();
|
||||||
|
|
||||||
|
s_Data.SSRData.SSRShader->SetMat4("u_Projection", cameraProjection);
|
||||||
|
s_Data.SSRData.SSRShader->SetMat4("u_InvProjection", glm::inverse(cameraProjection));
|
||||||
|
s_Data.SSRData.SSRShader->SetFloat2("u_ScreenSize", glm::vec2((float)width, (float)height));
|
||||||
|
s_Data.SSRData.SSRShader->SetFloat("u_CameraNear", sceneCamera.Camera.GetNear());
|
||||||
|
s_Data.SSRData.SSRShader->SetFloat("u_CameraFar", sceneCamera.Camera.GetFar());
|
||||||
|
s_Data.SSRData.SSRShader->SetInt("u_Steps", s_Data.SSRData.Steps);
|
||||||
|
s_Data.SSRData.SSRShader->SetFloat("u_MaxDistance", s_Data.SSRData.MaxDistance);
|
||||||
|
s_Data.SSRData.SSRShader->SetFloat("u_Thickness", s_Data.SSRData.Thickness);
|
||||||
|
s_Data.SSRData.SSRShader->SetFloat("u_Intensity", s_Data.SSRData.Intensity);
|
||||||
|
|
||||||
|
Renderer::SubmitFullscreenQuad(nullptr);
|
||||||
|
Renderer::EndRenderPass();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer3D::SSRBlurPass()
|
||||||
|
{
|
||||||
|
Renderer::BeginRenderPass(s_Data.SSRData.SSRBlurRenderPass);
|
||||||
|
|
||||||
|
s_Data.SSRData.SSRBlurShader->Bind();
|
||||||
|
s_Data.SSRData.SSRBlurShader->SetInt("u_SSRTexture", 0);
|
||||||
|
s_Data.SSRData.SSRBlurShader->SetInt("u_DepthTexture", 1);
|
||||||
|
s_Data.SSRData.SSRBlurShader->SetInt("u_MaterialInfoTexture", 2);
|
||||||
|
|
||||||
|
s_Data.SSRData.SSRRenderPass->GetSpecification().TargetFramebuffer->BindTexture();
|
||||||
|
s_Data.SSRData.SSRDepthTexture->Bind(1);
|
||||||
|
s_Data.SSRData.SSRMaterialInfoTexture->Bind(2);
|
||||||
|
|
||||||
|
auto srcFB = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
|
||||||
|
s_Data.SSRData.SSRBlurShader->SetFloat2("u_ScreenSize", glm::vec2((float)srcFB->GetWidth(), (float)srcFB->GetHeight()));
|
||||||
|
s_Data.SSRData.SSRBlurShader->SetFloat("u_BlurRadius", s_Data.SSRData.BlurRadius);
|
||||||
|
|
||||||
|
Renderer::SubmitFullscreenQuad(nullptr);
|
||||||
|
Renderer::EndRenderPass();
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer3D::ResolveMSAA()
|
void Renderer3D::ResolveMSAA()
|
||||||
{
|
{
|
||||||
auto srcFB = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
|
auto srcFB = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
|
||||||
@ -1190,23 +1437,75 @@ namespace Prism
|
|||||||
|
|
||||||
if (UI::BeginTreeNode("Shadows", false))
|
if (UI::BeginTreeNode("Shadows", false))
|
||||||
{
|
{
|
||||||
if (UI::BeginTreeNode("Shadow Map", false))
|
|
||||||
{
|
|
||||||
|
|
||||||
UI::BeginPropertyGrid();
|
UI::BeginPropertyGrid();
|
||||||
UI::Property("EnableMap", s_Data.ShadowData.ShadowEnabled);
|
UI::Property("Enable", s_Data.ShadowData.ShadowEnabled);
|
||||||
UI::Property("ShadowBias", s_Data.ShadowData.ShadowBias, 0.01f);
|
UI::PropertySlider("Bias", s_Data.ShadowData.ShadowBias, 0.0f, 0.1f);
|
||||||
UI::PropertySlider("ShadowSoftness", s_Data.ShadowData.ShadowSoftness, 0, 3);
|
UI::PropertySlider("Softness", s_Data.ShadowData.ShadowSoftness, 0, 3);
|
||||||
UI::Property("ShadowIntensity", s_Data.ShadowData.ShadowIntensity, 0.01f);
|
UI::PropertySlider("Intensity", s_Data.ShadowData.ShadowIntensity, 0.0f, 2.0f);
|
||||||
UI::Property("Ortho Size", s_Data.ShadowData.OrthoSize);
|
|
||||||
// UI::Property("Shadow Distance", s_Data.ShadowD0ata.ShadowDistance);
|
|
||||||
UI::EndPropertyGrid();
|
UI::EndPropertyGrid();
|
||||||
|
|
||||||
auto fb = s_Data.ShadowData.ShadowMapRenderPass->GetSpecification().TargetFramebuffer;
|
if (UI::BeginTreeNode("Cascade Settings", false))
|
||||||
|
{
|
||||||
|
UI::BeginPropertyGrid();
|
||||||
|
UI::PropertySlider("Split Lambda", s_Data.ShadowData.CascadeSplitLambda, 0.0f, 1.0f);
|
||||||
|
UI::PropertySlider("Shadow Far", s_Data.ShadowData.ShadowFarOverride, 1.0f, 1000.0f);
|
||||||
|
UI::PropertySlider("Depth Extend", s_Data.ShadowData.ShadowDepthExtend, 0.0f, 200.0f);
|
||||||
|
UI::EndPropertyGrid();
|
||||||
|
|
||||||
|
float cameraNear = s_Data.SceneData.SceneCamera.Camera.GetNear();
|
||||||
|
float shadowFar = s_Data.ShadowData.ShadowFar;
|
||||||
|
float totalRange = shadowFar - cameraNear;
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("Cascade Splits (world distance):");
|
||||||
|
for (int i = 0; i < Renderer3DData::CSM_CASCADE_COUNT; i++)
|
||||||
|
{
|
||||||
|
float splitWorld = cameraNear + s_Data.ShadowData.CascadeSplits[i] * totalRange;
|
||||||
|
float splitPct = s_Data.ShadowData.CascadeSplits[i] * 100.0f;
|
||||||
|
ImGui::Text(" Cascade %d: %.2f (%.1f%%)", i, splitWorld, splitPct);
|
||||||
|
}
|
||||||
|
|
||||||
|
float barWidth = ImGui::GetContentRegionAvail().x;
|
||||||
|
float barHeight = 20.0f;
|
||||||
|
ImDrawList* drawList = ImGui::GetWindowDrawList();
|
||||||
|
ImVec2 cursor = ImGui::GetCursorScreenPos();
|
||||||
|
|
||||||
|
ImU32 colors[4] = {
|
||||||
|
IM_COL32(70, 130, 180, 255),
|
||||||
|
IM_COL32(60, 179, 113, 255),
|
||||||
|
IM_COL32(218, 165, 32, 255),
|
||||||
|
IM_COL32(205, 92, 92, 255)
|
||||||
|
};
|
||||||
|
|
||||||
|
float prevSplit = 0.0f;
|
||||||
|
for (int i = 0; i < Renderer3DData::CSM_CASCADE_COUNT; i++)
|
||||||
|
{
|
||||||
|
float splitPct = s_Data.ShadowData.CascadeSplits[i];
|
||||||
|
float x0 = cursor.x + prevSplit * barWidth;
|
||||||
|
float x1 = cursor.x + splitPct * barWidth;
|
||||||
|
drawList->AddRectFilled(ImVec2(x0, cursor.y), ImVec2(x1, cursor.y + barHeight), colors[i]);
|
||||||
|
char label[16];
|
||||||
|
snprintf(label, sizeof(label), "C%d", i);
|
||||||
|
drawList->AddText(ImVec2((x0 + x1) * 0.5f - 8.0f, cursor.y + 2.0f), IM_COL32(255, 255, 255, 255), label);
|
||||||
|
prevSplit = splitPct;
|
||||||
|
}
|
||||||
|
drawList->AddRect(ImVec2(cursor.x, cursor.y), ImVec2(cursor.x + barWidth, cursor.y + barHeight), IM_COL32(200, 200, 200, 255));
|
||||||
|
ImGui::Dummy(ImVec2(barWidth, barHeight));
|
||||||
|
|
||||||
|
UI::EndTreeNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UI::BeginTreeNode("Shadow Map", false))
|
||||||
|
{
|
||||||
|
float size = ImGui::GetContentRegionAvail().x;
|
||||||
|
for (int i = 0; i < Renderer3DData::CSM_CASCADE_COUNT; i++)
|
||||||
|
{
|
||||||
|
auto fb = s_Data.ShadowData.ShadowMapRenderPass[i]->GetSpecification().TargetFramebuffer;
|
||||||
auto id = fb->GetDepthAttachmentRendererID();
|
auto id = fb->GetDepthAttachmentRendererID();
|
||||||
|
|
||||||
float size = ImGui::GetContentRegionAvail().x; // (float)fb->GetWidth() * 0.5f, (float)fb->GetHeight() * 0.5f
|
ImGui::Text("Cascade %d", i);
|
||||||
ImGui::Image((ImTextureID)id, { size, size }, { 0, 1 }, { 1, 0 });
|
ImGui::Image((ImTextureID)id, { size, size }, { 0, 1 }, { 1, 0 });
|
||||||
|
}
|
||||||
UI::EndTreeNode();
|
UI::EndTreeNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1265,6 +1564,33 @@ namespace Prism
|
|||||||
UI::EndTreeNode();
|
UI::EndTreeNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (UI::BeginTreeNode("SSR", false))
|
||||||
|
{
|
||||||
|
UI::BeginPropertyGrid();
|
||||||
|
UI::Property("Enable SSR", s_Data.SSRData.EnableSSR);
|
||||||
|
if (s_Data.SSRData.EnableSSR)
|
||||||
|
{
|
||||||
|
UI::Property("Intensity", s_Data.SSRData.Intensity, 0.01f, 0.0f, 5.0f);
|
||||||
|
UI::Property("Max Distance", s_Data.SSRData.MaxDistance, 0.1f, 1.0f, 200.0f);
|
||||||
|
UI::Property("Thickness", s_Data.SSRData.Thickness, 0.01f, 0.01f, 5.0f);
|
||||||
|
UI::PropertySlider("Steps", s_Data.SSRData.Steps, 1, 128);
|
||||||
|
UI::Property("Blur Radius", s_Data.SSRData.BlurRadius, 0.1f, 0.0f, 10.0f);
|
||||||
|
}
|
||||||
|
UI::EndPropertyGrid();
|
||||||
|
|
||||||
|
if (s_Data.SSRData.EnableSSR)
|
||||||
|
{
|
||||||
|
auto fb = s_Data.SSRData.SSRBlurRenderPass->GetSpecification().TargetFramebuffer;
|
||||||
|
const auto id = fb->GetColorAttachmentRendererID();
|
||||||
|
const float size = ImGui::GetContentRegionAvail().x;
|
||||||
|
float w = size;
|
||||||
|
float h = w / ((float)fb->GetWidth() / (float)fb->GetHeight());
|
||||||
|
ImGui::Image((ImTextureID)id, { w, h }, { 0, 1 }, { 1, 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
UI::EndTreeNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,6 +55,7 @@ namespace Prism
|
|||||||
static SceneRendererOptions& GetOptions();
|
static SceneRendererOptions& GetOptions();
|
||||||
static Ref<TextureCube> GetBlackCubeTexture();
|
static Ref<TextureCube> GetBlackCubeTexture();
|
||||||
static Ref<Texture2D> GetBlackTexture();
|
static Ref<Texture2D> GetBlackTexture();
|
||||||
|
static Ref<Texture2D> GetBRDFLUT();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void FlushDrawList(Ref<RenderPass>& outRenderPass);
|
static void FlushDrawList(Ref<RenderPass>& outRenderPass);
|
||||||
@ -62,6 +63,8 @@ namespace Prism
|
|||||||
static void AutoExposurePass();
|
static void AutoExposurePass();
|
||||||
static void ShadowMapPass();
|
static void ShadowMapPass();
|
||||||
static void GeometryPass();
|
static void GeometryPass();
|
||||||
|
static void SSRPass();
|
||||||
|
static void SSRBlurPass();
|
||||||
static void BloomBlurPass();
|
static void BloomBlurPass();
|
||||||
static void GridPass();
|
static void GridPass();
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,8 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
case TextureFormat::RGB: return 3;
|
case TextureFormat::RGB: return 3;
|
||||||
case TextureFormat::RGBA: return 4;
|
case TextureFormat::RGBA: return 4;
|
||||||
|
case TextureFormat::DEPTH24STENCIL8: return 4;
|
||||||
|
case TextureFormat::DEPTH32F: return 4;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,8 @@ namespace Prism
|
|||||||
RGBA16F = 3,
|
RGBA16F = 3,
|
||||||
RG8 = 4,
|
RG8 = 4,
|
||||||
RG16F = 5,
|
RG16F = 5,
|
||||||
|
DEPTH24STENCIL8 = 6,
|
||||||
|
DEPTH32F = 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class TextureWrap
|
enum class TextureWrap
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
//
|
|
||||||
// Created by Atdunbg on 2026/1/21.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef PRISM_FILESYSTEM_H
|
#ifndef PRISM_FILESYSTEM_H
|
||||||
#define PRISM_FILESYSTEM_H
|
#define PRISM_FILESYSTEM_H
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <mutex>
|
||||||
|
#include <vector>
|
||||||
|
#include <chrono>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
|
||||||
namespace efsw
|
namespace efsw
|
||||||
@ -50,8 +50,17 @@ namespace Prism
|
|||||||
static void StartWatching();
|
static void StartWatching();
|
||||||
static void StopWatching();
|
static void StopWatching();
|
||||||
|
|
||||||
|
static void ProcessPendingEvents();
|
||||||
|
|
||||||
|
static void NotifyFileWriting(const std::string& filepath);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::atomic<bool> s_IgnoreNextChange;
|
static std::mutex s_EventQueueMutex;
|
||||||
|
static std::vector<FileSystemChangedEvent> s_PendingEvents;
|
||||||
|
|
||||||
|
static std::mutex s_RecentWritesMutex;
|
||||||
|
static std::unordered_map<std::string, std::chrono::steady_clock::time_point> s_RecentWrites;
|
||||||
|
|
||||||
static efsw::FileWatcher* s_FileWatcher;
|
static efsw::FileWatcher* s_FileWatcher;
|
||||||
static class PrismFileWatcherListener* s_Listener;
|
static class PrismFileWatcherListener* s_Listener;
|
||||||
static FileSystemChangedCallbackFn s_Callback;
|
static FileSystemChangedCallbackFn s_Callback;
|
||||||
|
|||||||
Reference in New Issue
Block a user