7#include <glm/gtc/matrix_transform.hpp>
13glm::mat4 cascadeVP(
const glm::vec3 &
lightDir,
const glm::vec3 &
eye,
const glm::vec3 &
target,
14 const glm::vec3 &
up,
float fovYRad,
float aspect,
float nearZ,
float farZ,
15 float *texelWorldOut,
float *zRangeOut) {
19 const glm::mat4 inv = glm::inverse(
proj *
view);
24 for (
int z = 0;
z < 2; ++
z)
25 for (
int y = 0;
y < 2; ++
y)
26 for (
int x = 0;
x < 2; ++
x) {
27 const glm::vec4 ndc(
x ? 1.f : -1.f,
y ? 1.f : -1.f,
z ? 1.f : 0.f, 1.f);
28 glm::vec4
w = inv * ndc;
30 corners[
idx++] = glm::vec3(
w);
33 glm::vec3 worldCenter(0.f);
34 for (
int i = 0; i < 8; ++i) worldCenter += corners[i];
35 worldCenter *= 0.125f;
37 for (
int i = 0; i < 8; ++i)
38 radius = std::max(
radius, glm::length(corners[i] - worldCenter));
40 glm::vec3 L = glm::normalize(
lightDir);
41 if (glm::length(L) < 1e-6f) L = glm::vec3(0.f, 1.f, 0.f);
42 glm::vec3 lightUp(0.f, 1.f, 0.f);
43 if (std::abs(glm::dot(L, lightUp)) > 0.95f) lightUp = glm::vec3(0.f, 0.f, 1.f);
47 const glm::mat4 lightView = glm::lookAtRH(L * 50.f, glm::vec3(0.f), lightUp);
49 glm::vec3 minB(1e9f), maxB(-1e9f);
50 for (
int i = 0; i < 8; ++i) {
51 const glm::vec3 lp = glm::vec3(lightView * glm::vec4(corners[i], 1.f));
52 minB = glm::min(minB, lp);
53 maxB = glm::max(maxB, lp);
55 glm::vec3 centerLS = glm::vec3(lightView * glm::vec4(worldCenter, 1.f));
57 const float zPad = (maxB.z - minB.z) * 0.1f + 0.5f;
63 if (zRangeOut) *zRangeOut = std::max(-minB.z - (-maxB.z), 1e-3f);
68 const float texelWorld = (2.f *
radius) / mapSize;
69 if (texelWorldOut) *texelWorldOut = texelWorld;
71 auto snap = [&](
float v) {
return std::floor(
v / texelWorld) * texelWorld; };
72 centerLS.x = snap(centerLS.x);
73 centerLS.y = snap(centerLS.y);
75 const glm::mat4 lightProj =
77 centerLS.y +
radius, -maxB.z, -minB.z);
78 return lightProj * lightView;
84 const glm::vec3 &
target,
const glm::vec3 &
up,
float fovYRad,
85 float aspect,
float nearZ,
float farZ,
float bias,
float strength) {
88 const float n = std::max(nearZ, 1e-3f);
89 const float fCam = std::max(farZ,
n + 1e-2f);
91 const float ratio =
f /
n;
96 const float logS =
n * std::pow(ratio,
p);
97 const float uniS =
n + (
f -
n) *
p;
104 float texelWorld = 0.f;
107 cascadeVP(lightDirTowardSurface,
eye,
target,
up, fovYRad, aspect, splits[i],
108 splits[i + 1], &texelWorld, &zRange);
112 const float autoNdc = std::clamp((0.6f * texelWorld) / zRange, 1e-5f, 0.01f);
113 cascadeNdc[i] = std::max(std::max(0.f,
bias), autoNdc);
114 cascadeTexel[i] = texelWorld;
116 const float perceptualStrength = std::sqrt(std::clamp(
strength, 0.f, 1.f));
117 out.ubo.splits = glm::vec4(splits[1], splits[2], splits[3], perceptualStrength);
118 out.ubo.cascadeBias = glm::vec4(cascadeNdc[0], cascadeNdc[1], cascadeNdc[2], 0.f);
119 out.ubo.cascadeTexel = glm::vec4(cascadeTexel[0], cascadeTexel[1], cascadeTexel[2], 0.f);
120 out.ubo.bias = glm::vec4(cascadeNdc[0], 1.f, 1.f, 0.02f);
卡牌游戏 UI 工具模块:工厂 + 脚本绑定入口。 功能参考 ycarowr/UiCard:扇形手牌布局、抽牌/洗牌、悬浮放大、拖拽到落牌区、 敌方手牌(背面/偷看)、费用不足置灰,以及可实时调节的布局...
glm::mat4 perspectiveVulkanRH_ZO(float fovyRad, float aspect, float zNear, float zFar)
Right-handed, zero-to-one depth perspective for Vulkan swapchains.
ShadowUpload buildDirectionalCSM(const glm::vec3 &lightDirTowardSurface, const glm::vec3 &eye, const glm::vec3 &target, const glm::vec3 &up, float fovYRad, float aspect, float nearZ, float farZ, float bias, float strength)
Build 3 cascade light view-proj matrices for a directional light.
glm::mat4 orthoVulkanRH_ZO(float left, float right, float bottom, float top, float zNear, float zFar)
Ortho vulkan rh zo.
static constexpr float kSplitLambda
static constexpr int kMapSize
static constexpr float kMaxDistance
static constexpr int kCascades