9#include "graphics/shaders/ao_ssao_frag_spv.inc"
10#include "graphics/shaders/ao_hbao_frag_spv.inc"
11#include "graphics/shaders/ao_gtao_frag_spv.inc"
12#include "graphics/shaders/ao_blur_frag_spv.inc"
13#include "graphics/shaders/ao_overlay_frag_spv.inc"
14#include "graphics/shaders/ao_from_depth_frag_spv.inc"
21#include <glm/gtc/matrix_transform.hpp>
26void declareComputeCommon(Shader *sh,
bool horizonStyle) {
27 sh->declareMatrix(
"invViewProj");
28 sh->declareFloat(
"nearZ");
29 sh->declareFloat(
"farZ");
30 sh->declareFloat(
"radius");
31 sh->declareFloat(
"bias");
32 sh->declareFloat(
"intensity");
33 sh->declareFloat(
"power");
35 sh->declareFloat(
"dirCount");
36 sh->declareFloat(
"stepCount");
38 sh->declareFloat(
"sampleCount");
40 sh->declareFloat(
"texelW");
41 sh->declareFloat(
"texelH");
44Shader *createSsaoShader(Graphics *gfx) {
46 std::vector<uint32_t>
frag(ao_ssao_frag_spv, ao_ssao_frag_spv + ao_ssao_frag_spv_count);
47 std::vector<uint32_t>
vert;
48 Shader *sh = gfx->newShaderFromSpv(
vert,
frag);
49 declareComputeCommon(sh,
false);
50 sh->sendMatrix(
"invViewProj", glm::mat4(1.f));
51 sh->sendFloat(
"nearZ", 0.1f);
52 sh->sendFloat(
"farZ", 100.f);
53 sh->sendFloat(
"radius", 0.75f);
54 sh->sendFloat(
"bias", 0.025f);
55 sh->sendFloat(
"intensity", 1.f);
56 sh->sendFloat(
"power", 1.5f);
57 sh->sendFloat(
"sampleCount", 16.f);
58 sh->sendFloat(
"texelW", 1.f / 256.f);
59 sh->sendFloat(
"texelH", 1.f / 256.f);
63Shader *createHbaoShader(Graphics *gfx) {
65 std::vector<uint32_t>
frag(ao_hbao_frag_spv, ao_hbao_frag_spv + ao_hbao_frag_spv_count);
66 std::vector<uint32_t>
vert;
67 Shader *sh = gfx->newShaderFromSpv(
vert,
frag);
68 declareComputeCommon(sh,
true);
69 sh->sendMatrix(
"invViewProj", glm::mat4(1.f));
70 sh->sendFloat(
"nearZ", 0.1f);
71 sh->sendFloat(
"farZ", 100.f);
72 sh->sendFloat(
"radius", 0.75f);
73 sh->sendFloat(
"bias", 0.025f);
74 sh->sendFloat(
"intensity", 1.f);
75 sh->sendFloat(
"power", 1.5f);
76 sh->sendFloat(
"dirCount", 6.f);
77 sh->sendFloat(
"stepCount", 6.f);
78 sh->sendFloat(
"texelW", 1.f / 256.f);
79 sh->sendFloat(
"texelH", 1.f / 256.f);
83Shader *createGtaoShader(Graphics *gfx) {
85 std::vector<uint32_t>
frag(ao_gtao_frag_spv, ao_gtao_frag_spv + ao_gtao_frag_spv_count);
86 std::vector<uint32_t>
vert;
87 Shader *sh = gfx->newShaderFromSpv(
vert,
frag);
88 declareComputeCommon(sh,
true);
89 sh->declareFloat(
"thickness");
90 sh->sendMatrix(
"invViewProj", glm::mat4(1.f));
91 sh->sendFloat(
"nearZ", 0.1f);
92 sh->sendFloat(
"farZ", 100.f);
93 sh->sendFloat(
"radius", 0.75f);
94 sh->sendFloat(
"bias", 0.025f);
95 sh->sendFloat(
"intensity", 1.f);
96 sh->sendFloat(
"power", 1.5f);
97 sh->sendFloat(
"dirCount", 6.f);
98 sh->sendFloat(
"stepCount", 6.f);
99 sh->sendFloat(
"texelW", 1.f / 256.f);
100 sh->sendFloat(
"texelH", 1.f / 256.f);
101 sh->sendFloat(
"thickness", 0.5f);
105Shader *createBlurShader(Graphics *gfx) {
106 if (!gfx)
throw eve::Exception(
"AmbientOcclusion: null graphics");
107 std::vector<uint32_t>
frag(ao_blur_frag_spv, ao_blur_frag_spv + ao_blur_frag_spv_count);
108 std::vector<uint32_t>
vert;
109 Shader *sh = gfx->newShaderFromSpv(
vert,
frag);
110 sh->declareFloat(
"texelW");
111 sh->declareFloat(
"texelH");
112 sh->declareFloat(
"depthSigma");
113 sh->declareFloat(
"spatialKernel");
114 sh->sendFloat(
"texelW", 1.f / 256.f);
115 sh->sendFloat(
"texelH", 1.f / 256.f);
116 sh->sendFloat(
"depthSigma", 0.05f);
117 sh->sendFloat(
"spatialKernel", 2.f);
121Shader *createOverlayShader(Graphics *gfx) {
122 if (!gfx)
throw eve::Exception(
"AmbientOcclusion: null graphics");
123 std::vector<uint32_t>
frag(ao_overlay_frag_spv, ao_overlay_frag_spv + ao_overlay_frag_spv_count);
124 std::vector<uint32_t>
vert;
125 Shader *sh = gfx->newShaderFromSpv(
vert,
frag);
126 sh->declareFloat(
"intensity");
127 sh->declareFloat(
"power");
128 sh->sendFloat(
"intensity", 1.f);
129 sh->sendFloat(
"power", 1.f);
133Shader *createFromDepthShader(Graphics *gfx) {
134 if (!gfx)
throw eve::Exception(
"AmbientOcclusion: null graphics");
135 std::vector<uint32_t>
frag(ao_from_depth_frag_spv,
136 ao_from_depth_frag_spv + ao_from_depth_frag_spv_count);
137 Shader *sh = gfx->newShaderFromSpv({},
frag);
138 if (!sh || !sh->gpuHandle)
139 throw eve::Exception(
"AmbientOcclusion: failed to create from-depth shader");
140 declareComputeCommon(sh,
false);
141 sh->sendMatrix(
"invViewProj", glm::mat4(1.f));
142 sh->sendFloat(
"nearZ", 0.1f);
143 sh->sendFloat(
"farZ", 100.f);
144 sh->sendFloat(
"radius", 0.75f);
145 sh->sendFloat(
"bias", 0.025f);
146 sh->sendFloat(
"intensity", 0.55f);
147 sh->sendFloat(
"power", 1.35f);
148 sh->sendFloat(
"sampleCount", 16.f);
149 sh->sendFloat(
"texelW", 1.f / 256.f);
150 sh->sendFloat(
"texelH", 1.f / 256.f);
151 sh->declareFloat(
"hasNormal");
152 sh->sendFloat(
"hasNormal", 0.f);
159 ssaoShader_ = createSsaoShader(gfx);
160 hbaoShader_ = createHbaoShader(gfx);
161 gtaoShader_ = createGtaoShader(gfx);
162 blurShader_ = createBlurShader(gfx);
163 overlayShader_ = createOverlayShader(gfx);
164 fromDepthShader_ = createFromDepthShader(gfx);
165 applyQualityDefaults();
170Shader *AmbientOcclusion::activeComputeShader()
const {
171 if (mode_ ==
"hbao")
return hbaoShader_;
172 if (mode_ ==
"gtao")
return gtaoShader_;
178void AmbientOcclusion::applyQualityDefaults() {
179 if (quality_ ==
"low") {
182 if (mode_ ==
"hbao" || mode_ ==
"gtao") {
188 }
else if (quality_ ==
"high") {
191 if (mode_ ==
"hbao" || mode_ ==
"gtao") {
201 if (mode_ ==
"hbao" || mode_ ==
"gtao") {
217 applyQualityDefaults();
223 else if (mode ==
"gtao")
227 applyQualityDefaults();
231 invViewProj_ = invViewProj;
232 ssaoShader_->
sendMatrix(
"invViewProj", invViewProj_);
233 hbaoShader_->
sendMatrix(
"invViewProj", invViewProj_);
234 gtaoShader_->
sendMatrix(
"invViewProj", invViewProj_);
235 if (fromDepthShader_) fromDepthShader_->
sendMatrix(
"invViewProj", invViewProj_);
239 float targetZ,
float upX,
float upY,
float upZ,
float fovYDeg,
240 float aspect,
float nearZ,
float farZ) {
241 nearZ_ = nearZ > 1e-4f ? nearZ : 0.1f;
242 farZ_ = farZ > nearZ_ ? farZ : nearZ_ + 1.f;
243 const float aspectSafe = aspect > 1e-4f ? aspect : 1.f;
244 const float fovRad = fovYDeg * 0.017453292519943295f;
245 const glm::mat4
view =
246 glm::lookAtRH(glm::vec3(eyeX, eyeY, eyeZ), glm::vec3(targetX, targetY, targetZ),
247 glm::vec3(upX, upY, upZ));
256 if (fromDepthShader_) {
257 fromDepthShader_->
sendFloat(
"nearZ", nearZ_);
258 fromDepthShader_->
sendFloat(
"farZ", farZ_);
263 radius_ = radius > 1e-4f ? radius : 1e-4f;
268 bias_ = bias < 0.f ? 0.f : bias;
273 intensity_ = intensity < 0.f ? 0.f : intensity;
275 if (overlayShader_) overlayShader_->
sendFloat(
"intensity", intensity_);
285 if (gtaoShader_ && gtaoShader_->
hasUniform(
"thickness"))
286 gtaoShader_->
sendFloat(
"thickness", thickness_);
315 if (
active->getFromVar(
name, &
v,
sizeof(
v)) ==
int(
sizeof(
v)))
return v;
326 for (
Shader *sh : {ssaoShader_, hbaoShader_, gtaoShader_}) {
327 if (sh && sh->hasUniform(
name)) {
329 if (sh->getFromVar(
name, &
v,
sizeof(
v)) == int(
sizeof(
v)))
return v;
336 if (mode_ ==
"hbao" || mode_ ==
"gtao") {
337 const int dirs = int(std::lround(
getFloat(
"dirCount")));
338 const int steps = int(std::lround(
getFloat(
"stepCount")));
341 return int(std::lround(
getFloat(
"sampleCount")));
345 if (fullSize < 1)
return 1;
346 const float ds = std::max(downscale_, 1.f);
347 return std::max(1,
int(std::floor(
float(fullSize) / ds)));
354 shader->sendMatrix(
"invViewProj", invViewProj_);
355 shader->sendFloat(
"nearZ", nearZ_);
356 shader->sendFloat(
"farZ", farZ_);
357 shader->sendFloat(
"radius", radius_);
358 shader->sendFloat(
"bias", bias_);
359 shader->sendFloat(
"intensity", intensity_);
360 shader->sendFloat(
"power", power_);
363 if (
shader->hasUniform(
"thickness"))
shader->sendFloat(
"thickness", thickness_);
366void AmbientOcclusion::drawFullscreen(Graphics *gfx, Texture *source, Shader *
shader) {
367 if (!gfx)
throw eve::Exception(
"AmbientOcclusion: null graphics");
368 if (!source)
throw eve::Exception(
"AmbientOcclusion: null source texture");
370 const float dw = gfx->getCanvas() ? float(gfx->getCanvas()->getWidth()) : float(gfx->getWidth());
372 gfx->getCanvas() ? float(gfx->getCanvas()->getHeight()) : float(gfx->getHeight());
373 gfx->drawTexturedRectShader(source,
shader, 0.f, 0.f, dw, dh,
Color(1.f, 1.f, 1.f, 1.f));
377 if (!linearDepth)
throw eve::Exception(
"AmbientOcclusion.compute: null depth");
378 Shader *sh = activeComputeShader();
380 drawFullscreen(gfx, linearDepth, sh);
384 if (!gfx)
throw eve::Exception(
"AmbientOcclusion.computeTo: null graphics");
385 if (!dest)
throw eve::Exception(
"AmbientOcclusion.computeTo: null dest");
389 gfx->
setCanvas(prev == gfx ?
nullptr : prev);
393 if (!aoMap)
throw eve::Exception(
"AmbientOcclusion.blur: null aoMap");
396 drawFullscreen(gfx, aoMap, blurShader_);
400 if (!gfx)
throw eve::Exception(
"AmbientOcclusion.blurTo: null graphics");
401 if (!dest)
throw eve::Exception(
"AmbientOcclusion.blurTo: null dest");
405 gfx->
setCanvas(prev == gfx ?
nullptr : prev);
409 if (!aoMap)
throw eve::Exception(
"AmbientOcclusion.applyOverlay: null aoMap");
410 overlayShader_->
sendFloat(
"intensity", intensity_);
416 drawFullscreen(gfx, aoMap, overlayShader_);
420 if (!gfx)
throw eve::Exception(
"AmbientOcclusion.applyOverlayTo: null graphics");
421 if (!dest)
throw eve::Exception(
"AmbientOcclusion.applyOverlayTo: null dest");
425 gfx->
setCanvas(prev == gfx ?
nullptr : prev);
433 if (!gfx)
throw eve::Exception(
"AmbientOcclusion.applyFromGBuffer: null graphics");
434 if (!hwDepth)
throw eve::Exception(
"AmbientOcclusion.applyFromGBuffer: null hwDepth");
435 if (!fromDepthShader_)
throw eve::Exception(
"AmbientOcclusion.applyFromGBuffer: missing shader");
436 fromDepthShader_->
sendFloat(
"hasNormal", worldNormal ? 1.f : 0.f);
437 uploadComputeCommon(fromDepthShader_, hwDepth->
getWidth(), hwDepth->
getHeight());
444 Color(1.f, 1.f, 1.f, 1.f));
446 drawFullscreen(gfx, hwDepth, fromDepthShader_);
451 if (!gfx)
throw eve::Exception(
"AmbientOcclusion.applyFromDepthTo: null graphics");
452 if (!dest)
throw eve::Exception(
"AmbientOcclusion.applyFromDepthTo: null dest");
456 gfx->
setCanvas(prev == gfx ?
nullptr : prev);
460 float (*depth01)(
int x,
int y,
void *userdata),
462 if (!gfx)
throw eve::Exception(
"AmbientOcclusion.newLinearDepthTexture: null graphics");
464 throw eve::Exception(
"AmbientOcclusion.newLinearDepthTexture: invalid size");
465 if (!depth01)
throw eve::Exception(
"AmbientOcclusion.newLinearDepthTexture: null depth fn");
466 std::vector<uint8_t> rgba(
size_t(
width) *
size_t(
height) * 4);
469 float d = depth01(
x,
y, userdata);
470 if (
d < 0.f)
d = 0.f;
471 if (
d > 1.f)
d = 1.f;
472 const uint8_t
b = uint8_t(std::lround(
d * 255.f));
473 const size_t i = size_t(
y *
width +
x) * 4;
void applyFromDepthTo(Graphics *gfx, Texture *linearDepth, Canvas *dest)
void applyFromDepth(Graphics *gfx, Texture *hwDepth)
One-pass SSAO overlay for the 3D swapchain path. Samples hardware D32 (Vulkan NDC z in ....
int resolutionFor(int fullSize) const
Downscale helper: returns floor(dim / downscale), at least 1. Callers create AO canvases at this size...
void setIntensity(float intensity)
void setFloat(const std::string &name, float value)
void computeTo(Graphics *gfx, Texture *linearDepth, Canvas *dest)
AmbientOcclusion(Graphics *gfx)
void setCamera(float eyeX, float eyeY, float eyeZ, float targetX, float targetY, float targetZ, float upX, float upY, float upZ, float fovYDeg, float aspect, float nearZ, float farZ)
Camera for depth reconstruction (RH + ZO). Builds inv(viewProj) and near/far used by compute*.
void setMode(const std::string &mode)
"ssao" | "hbao" | "gtao".
void blurTo(Graphics *gfx, Texture *aoMap, Canvas *dest)
void setInvViewProj(const glm::mat4 &invViewProj)
bool hasParam(const std::string &name) const
void setPower(float power)
void applyFromGBuffer(Graphics *gfx, Texture *hwDepth, Texture *worldNormal)
void setThickness(float thickness)
Shader * getShader() const
Texture * newLinearDepthTexture(Graphics *gfx, int width, int height, float(*depth01)(int x, int y, void *userdata), void *userdata)
Build an RGBA8 texture with linear depth in R (G=B=R, A=255). Owned by Graphics (same convention as V...
float getFloat(const std::string &name) const
void setQuality(const std::string &quality)
"low" | "medium" | "high" (unknown → medium).
float getIntensity() const
int getSampleCount() const
void compute(Graphics *gfx, Texture *linearDepth)
Compute AO into the currently bound canvas / screen. Output RGB = AO (1=open), A = depth01.
void blur(Graphics *gfx, Texture *aoMap)
Bilateral blur of an AO map (RGB=AO, A=depth).
void applyOverlayTo(Graphics *gfx, Texture *aoMap, Canvas *dest)
void applyOverlay(Graphics *gfx, Texture *aoMap)
Darken the current target with AO: black + alpha=(1-ao)*intensity. Draw over an already-rendered scen...
void setRadius(float radius)
virtual int getWidth() const =0
virtual int getHeight() const =0
virtual Canvas * getCanvas() const =0
virtual Texture * newTexture(int width, int height, const uint8_t *rgba, bool repeatU=false, bool repeatV=false)=0
virtual void setCanvas(Canvas *canvas)=0
nullptr or this → screen. Switching flushes pending draws to the previous target.
virtual void drawTexturedRectShaderDepth(Texture *color, Texture *depth, Shader *shader, float x, float y, float w, float h, const Color &tint)=0
Fullscreen/post draw sampling color at binding 0 and depth at binding 1 (hardware D32,...
bool hasUniform(const std::string &name) const
void sendFloat(const std::string &name, float x)
void sendMatrix(const std::string &name, const glm::mat4 &m)
int getFromVar(const std::string &name, void *data, size_t size) const
GPU texture created via Graphics::newTexture. Owns GPU resources through an opaque backend handle.
卡牌游戏 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.
glm::vec4 Color
RGBA color used by every graphics draw call. Lives inside eve::graphics so including a graphics heade...