Reorganize directory layout: editor panels/, grouped shaders, drop stale header
- App/editor: move 7 panels into panels/ (Editor core stays at root) - shaders/: group into pbr/ post/ debug/ env/ (runtime load paths updated) - Delete outdated duplicate Engine/src/Renderer/VulkanAssetUploader.h
This commit is contained in:
Vendored
+54
@@ -0,0 +1,54 @@
|
||||
#version 450
|
||||
|
||||
// IBL ④:BRDF 积分 LUT(2D,纯数学,与环境内容无关)。
|
||||
// (NdotV, roughness) → (F 缩放 A, F 偏置 B):specular = prefiltered·(F·A + B)。
|
||||
// 与环境切换无关,但随生成链一起跑(GPU 亚毫秒级),省去跨环境缓存。
|
||||
|
||||
#include "ibl_common.glsl"
|
||||
|
||||
layout(local_size_x = 8, local_size_y = 8) in;
|
||||
|
||||
layout(set = 0, binding = 0, rg16f) uniform restrict writeonly image2D outLut;
|
||||
|
||||
const uint SAMPLES = 128;
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 gid = ivec2(gl_GlobalInvocationID);
|
||||
if (gid.x >= imageSize(outLut).x || gid.y >= imageSize(outLut).y) return;
|
||||
|
||||
vec2 uv = (vec2(gid) + 0.5) / vec2(imageSize(outLut));
|
||||
float nDotV = uv.x;
|
||||
float roughness = uv.y;
|
||||
|
||||
// V 在以 N 为 +Z 的切线空间里(积分只依赖这两角度)
|
||||
vec3 V = vec3(sqrt(1.0 - nDotV * nDotV), 0.0, nDotV);
|
||||
vec3 Nz = vec3(0.0, 0.0, 1.0);
|
||||
|
||||
float a = 0.0, b = 0.0;
|
||||
float k = roughness * roughness * 0.5; // IBL 版 Smith k
|
||||
|
||||
for (uint i = 0u; i < SAMPLES; ++i) {
|
||||
vec3 H = iblImportanceSampleGGX(iblHammersley(i, SAMPLES), Nz, roughness);
|
||||
vec3 L = normalize(2.0 * dot(V, H) * H - V);
|
||||
|
||||
float lDotN = L.z;
|
||||
float nDotL = max(lDotN, 0.0);
|
||||
float nDotH = max(H.z, 0.0);
|
||||
float vDotH = max(dot(V, H), 0.0);
|
||||
if (nDotL <= 0.0) continue;
|
||||
|
||||
float g = (nDotV / (nDotV * (1.0 - k) + k)) *
|
||||
(nDotL / (nDotL * (1.0 - k) + k));
|
||||
// 高 roughness 时部分样本 H.z 恰为 0(g 也为 0),0/0 = NaN
|
||||
// 会累进 LUT——分母钳 epsilon(与 CPU 版一致)
|
||||
float gVis = g * vDotH / max(nDotH * nDotV, 1e-6);
|
||||
float fc = 1.0 - vDotH;
|
||||
float f = fc * fc * fc * fc * fc; // (1-vDotH)⁵
|
||||
|
||||
a += (1.0 - f) * gVis;
|
||||
b += f * gVis;
|
||||
}
|
||||
|
||||
imageStore(outLut, gid, vec4(a / float(SAMPLES), b / float(SAMPLES), 0.0, 1.0));
|
||||
}
|
||||
Vendored
+60
@@ -0,0 +1,60 @@
|
||||
// ibl_common:IBL compute 预积分共享数学(与原 CPU 实现逐式对齐)。
|
||||
//
|
||||
// 被 4 个 .comp 包含(glslc 相对 include)。改造自 Cubemap.cpp 的
|
||||
// CPU 积分路径——公式一致保证视觉无回归,可直接对比验证。
|
||||
|
||||
#ifndef IBL_COMMON_GLSL
|
||||
#define IBL_COMMON_GLSL
|
||||
|
||||
const float IBL_PI = 3.14159265358979;
|
||||
|
||||
// ---- GL/Vulkan cube 面方向表(与 GL spec 立方体选择表互逆)----
|
||||
// (u,v)∈[0,1](u 向右 v 向下)→ s,t∈[-1,1] → 单位方向
|
||||
vec3 iblFaceDir(uint face, float u, float v)
|
||||
{
|
||||
float s = u * 2.0 - 1.0;
|
||||
float t = v * 2.0 - 1.0;
|
||||
vec3 dir;
|
||||
if (face == 0u) dir = vec3( 1.0, -t, -s); // +X(面片顶行 = +Y)
|
||||
else if (face == 1u) dir = vec3(-1.0, -t, s); // -X
|
||||
else if (face == 2u) dir = vec3( s, 1.0, t); // +Y
|
||||
else if (face == 3u) dir = vec3( s,-1.0, -t); // -Y
|
||||
else if (face == 4u) dir = vec3( s, -t, 1.0); // +Z
|
||||
else dir = vec3(-s, -t,-1.0); // -Z
|
||||
return normalize(dir); // equirect 查表要求单位方向
|
||||
}
|
||||
|
||||
// 单位方向 → 等距柱状 uv。行 0 = 天顶(+Y):v = acos(y)/π,
|
||||
// 与 stbi 行序一致;u 经度环绕交给采样器 S = eRepeat 处理接缝
|
||||
vec2 iblDirToEquirectUv(vec3 dir)
|
||||
{
|
||||
float u = atan(dir.z, dir.x) / (2.0 * IBL_PI) + 0.5;
|
||||
float v = acos(clamp(dir.y, -1.0, 1.0)) / IBL_PI;
|
||||
return vec2(u, v);
|
||||
}
|
||||
|
||||
// van der Corput 基底反转。硬件位反转指令替代 CPU 手写交换链;
|
||||
// 整数值转浮点(不是位型重解读),序列与 CPU 版一致
|
||||
vec2 iblHammersley(uint i, uint n)
|
||||
{
|
||||
return vec2(float(i) / float(n),
|
||||
float(bitfieldReverse(i)) * 2.3283064365386963e-10);
|
||||
}
|
||||
|
||||
// GGX NDF 按概率密度取半程向量 H(切线空间 → 世界)
|
||||
vec3 iblImportanceSampleGGX(vec2 xi, vec3 N, float roughness)
|
||||
{
|
||||
float a = roughness * roughness;
|
||||
float phi = 2.0 * IBL_PI * xi.x;
|
||||
float cosTheta = sqrt((1.0 - xi.y) / (1.0 + (a * a - 1.0) * xi.y));
|
||||
float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
|
||||
|
||||
vec3 H = vec3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta);
|
||||
|
||||
vec3 up = abs(N.z) > 0.999 ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0);
|
||||
vec3 T = normalize(cross(up, N));
|
||||
vec3 B = cross(N, T);
|
||||
return normalize(T * H.x + B * H.y + N * H.z);
|
||||
}
|
||||
|
||||
#endif // IBL_COMMON_GLSL
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
#version 450
|
||||
|
||||
// IBL ①:等距柱状 HDR → 环境 cube(6 面重采样)。
|
||||
// 替代原 CPU 逐像素 SampleEquirect 双线性查表——GPU 上直接用硬件
|
||||
// 线性过滤采样(经度接缝由 S=eRepeat 处理),观感与 CPU 版一致。
|
||||
// 输出为 image2DArray(layer = face),图像本体带 CUBE_COMPATIBLE,
|
||||
// 采样端另建 eCube view。
|
||||
|
||||
#include "ibl_common.glsl"
|
||||
|
||||
layout(local_size_x = 8, local_size_y = 8) in;
|
||||
|
||||
layout(set = 0, binding = 0) uniform sampler2D equirect;
|
||||
layout(set = 0, binding = 1, rgba16f) uniform restrict writeonly image2DArray outCube;
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec3 gid = ivec3(gl_GlobalInvocationID);
|
||||
ivec2 size = imageSize(outCube).xy;
|
||||
if (gid.x >= size.x || gid.y >= size.y) return;
|
||||
|
||||
vec2 uv = (vec2(gid.xy) + 0.5) / vec2(size);
|
||||
vec3 dir = iblFaceDir(uint(gid.z), uv.x, uv.y);
|
||||
vec3 rgb = texture(equirect, iblDirToEquirectUv(dir)).rgb;
|
||||
|
||||
imageStore(outCube, gid, vec4(rgb, 1.0));
|
||||
}
|
||||
Vendored
+48
@@ -0,0 +1,48 @@
|
||||
#version 450
|
||||
|
||||
// IBL ②:环境 cube → 漫反射辐照度 cube(半球 Lambert 卷积)。
|
||||
// E = ∫ L·cosθ·sinθ dθ dφ,切线基 up×N 构造。64×32 = 2048 采样/像素
|
||||
// (与 CPU 版同级精度),32² 低频输出上 GPU 耗时可忽略。
|
||||
|
||||
#include "ibl_common.glsl"
|
||||
|
||||
layout(local_size_x = 8, local_size_y = 8) in;
|
||||
|
||||
layout(set = 0, binding = 0) uniform samplerCube env;
|
||||
layout(set = 0, binding = 1, rgba16f) uniform restrict writeonly image2DArray outCube;
|
||||
|
||||
const int PHI_STEPS = 64;
|
||||
const int THETA_STEPS = 32;
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec3 gid = ivec3(gl_GlobalInvocationID);
|
||||
ivec2 size = imageSize(outCube).xy;
|
||||
if (gid.x >= size.x || gid.y >= size.y) return;
|
||||
|
||||
vec2 uv = (vec2(gid.xy) + 0.5) / vec2(size);
|
||||
vec3 N = iblFaceDir(uint(gid.z), uv.x, uv.y);
|
||||
|
||||
vec3 up = abs(N.y) > 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
|
||||
vec3 T = normalize(cross(up, N));
|
||||
vec3 B = cross(N, T);
|
||||
|
||||
float dPhi = 2.0 * IBL_PI / float(PHI_STEPS);
|
||||
float dTheta = 0.5 * IBL_PI / float(THETA_STEPS);
|
||||
|
||||
vec3 irradiance = vec3(0.0);
|
||||
for (int p = 0; p < PHI_STEPS; ++p) {
|
||||
float phi = (float(p) + 0.5) * dPhi;
|
||||
for (int t = 0; t < THETA_STEPS; ++t) {
|
||||
float theta = (float(t) + 0.5) * dTheta;
|
||||
float sinT = sin(theta);
|
||||
float cosT = cos(theta);
|
||||
vec3 sampleDir = T * (sinT * cos(phi)) +
|
||||
B * (sinT * sin(phi)) +
|
||||
N * cosT;
|
||||
irradiance += texture(env, sampleDir).rgb * (cosT * sinT);
|
||||
}
|
||||
}
|
||||
|
||||
imageStore(outCube, gid, vec4(irradiance * (dPhi * dTheta), 1.0));
|
||||
}
|
||||
Vendored
+44
@@ -0,0 +1,44 @@
|
||||
#version 450
|
||||
|
||||
// IBL ③:环境 cube → pre-filtered cube(GGX 重要性采样,split-sum 镜面端)。
|
||||
// R(N) ≈ Σ L·NdotL / Σ NdotL。每 mip 一次 dispatch(storage view 必须
|
||||
// 单 mip),roughness 经 push constant 传入;256 采样统一(高 roughness
|
||||
// 分布更宽,取 CPU 版采样数上限保证收敛)。
|
||||
|
||||
#include "ibl_common.glsl"
|
||||
|
||||
layout(local_size_x = 8, local_size_y = 8) in;
|
||||
|
||||
layout(set = 0, binding = 0) uniform samplerCube env;
|
||||
layout(set = 0, binding = 1, rgba16f) uniform restrict writeonly image2DArray outCube;
|
||||
|
||||
layout(push_constant) uniform Push {
|
||||
float roughness;
|
||||
} pc;
|
||||
|
||||
const uint SAMPLES = 256;
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec3 gid = ivec3(gl_GlobalInvocationID);
|
||||
ivec2 size = imageSize(outCube).xy;
|
||||
if (gid.x >= size.x || gid.y >= size.y) return;
|
||||
|
||||
vec2 uv = (vec2(gid.xy) + 0.5) / vec2(size);
|
||||
vec3 N = iblFaceDir(uint(gid.z), uv.x, uv.y);
|
||||
vec3 V = N; // split-sum 约定:V 沿 N
|
||||
|
||||
vec3 acc = vec3(0.0);
|
||||
float weight = 0.0;
|
||||
for (uint i = 0u; i < SAMPLES; ++i) {
|
||||
vec3 H = iblImportanceSampleGGX(iblHammersley(i, SAMPLES), N, pc.roughness);
|
||||
vec3 L = normalize(2.0 * dot(V, H) * H - V);
|
||||
float nDotL = max(dot(N, L), 0.0);
|
||||
if (nDotL > 0.0) {
|
||||
acc += texture(env, L).rgb * nDotL;
|
||||
weight += nDotL;
|
||||
}
|
||||
}
|
||||
|
||||
imageStore(outCube, gid, vec4(weight > 0.0 ? acc / weight : vec3(0.0), 1.0));
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
#version 450
|
||||
|
||||
// Shadow pass fragment:depth-only,无输出。
|
||||
// 深度写入由深度附件 + 光栅化完成(含管线深度 bias)。
|
||||
|
||||
void main() {
|
||||
}
|
||||
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
#version 450
|
||||
|
||||
// Shadow pass vertex:光源视角写深度。
|
||||
// GPUDriven:模型矩阵经 gl_InstanceIndex 从实例缓冲取(与 Forward
|
||||
// 共用同一份数据),push 只带 lightVP(全 pass 一次)。
|
||||
// 骨骼蒙皮与 Forward 同一套数据(binding 3/4),阴影与主体形变一致。
|
||||
|
||||
layout(location = 0) in vec3 inPosition;
|
||||
layout(location = 4) in uvec4 inBoneIds; // 骨骼槽(palette 下标)
|
||||
layout(location = 5) in vec4 inWeights; // 蒙皮权重(无骨骼顶点 = (1,0,0,0))
|
||||
|
||||
layout(std430, set = 0, binding = 1) readonly buffer ObjectBuffer {
|
||||
mat4 models[];
|
||||
} objects;
|
||||
|
||||
// 骨骼蒙皮:与 simple_shader.vert 同布局(Set0 binding 3/4)
|
||||
layout(std430, set = 0, binding = 3) readonly buffer SkinOffsetBuffer {
|
||||
uint skinBases[];
|
||||
} skinOffsets;
|
||||
|
||||
layout(std430, set = 0, binding = 4) readonly buffer SkinPaletteBuffer {
|
||||
mat4 bones[];
|
||||
} skinPalettes;
|
||||
|
||||
layout(push_constant) uniform PushConstants {
|
||||
mat4 lightVP;
|
||||
} pc;
|
||||
|
||||
mat4 SkinMatrix() {
|
||||
uint base = skinOffsets.skinBases[gl_InstanceIndex];
|
||||
return skinPalettes.bones[base + inBoneIds.x] * inWeights.x +
|
||||
skinPalettes.bones[base + inBoneIds.y] * inWeights.y +
|
||||
skinPalettes.bones[base + inBoneIds.z] * inWeights.z +
|
||||
skinPalettes.bones[base + inBoneIds.w] * inWeights.w;
|
||||
}
|
||||
|
||||
void main() {
|
||||
mat4 skin = SkinMatrix();
|
||||
vec3 skinnedPos = (skin * vec4(inPosition, 1.0)).xyz;
|
||||
gl_Position = pc.lightVP * objects.models[gl_InstanceIndex] * vec4(skinnedPos, 1.0);
|
||||
}
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
#version 450
|
||||
|
||||
// 天空盒像素:NDC → 世界方向 → cube 采样。
|
||||
// invVP = inverse(projNoJitter × mat4(mat3(view))):去掉平移的视图,
|
||||
// 反投影结果即"相机相对"的世界方向,normalize 后直接采样 cube。
|
||||
|
||||
layout(location = 0) in vec2 fragUV;
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
layout(set = 0, binding = 0) uniform samplerCube envMap;
|
||||
|
||||
// push 与 skybox.vert 一致声明(VUID-08878)
|
||||
layout(push_constant) uniform PushConstants {
|
||||
mat4 invVP;
|
||||
} pc;
|
||||
|
||||
void main() {
|
||||
vec4 target = pc.invVP * vec4(fragUV * 2.0 - 1.0, 1.0, 1.0);
|
||||
vec3 dir = normalize(target.xyz / target.w);
|
||||
outColor = vec4(texture(envMap, dir).rgb, 1.0);
|
||||
}
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
#version 450
|
||||
|
||||
// 天空盒顶点:全屏三角形(无顶点缓冲),UV 交给 fragment 反投影。
|
||||
// 方向在 fragment 逐像素计算(invVP 是投影变换,对 NDC 线性插值方向
|
||||
// 不精确;UV 插值是仿射的,逐像素重建方向零误差)。
|
||||
|
||||
layout(location = 0) out vec2 fragUV;
|
||||
|
||||
// push 与 skybox.frag 一致声明(VUID-08878:shader object 接口一致)
|
||||
layout(push_constant) uniform PushConstants {
|
||||
mat4 invVP;
|
||||
} pc;
|
||||
|
||||
void main() {
|
||||
vec2 p = vec2(
|
||||
float((gl_VertexIndex << 1) & 2),
|
||||
float(gl_VertexIndex & 2));
|
||||
fragUV = p;
|
||||
// 远平面:z = 1(Vulkan [0,1] 深度),无深度附件,只关心覆盖屏幕
|
||||
gl_Position = vec4(p * 2.0 - 1.0, 1.0, 1.0);
|
||||
}
|
||||
Reference in New Issue
Block a user