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"
22#include <glm/gtc/matrix_transform.hpp>
27Shader *newAoShader(Graphics *gfx,
const std::vector<uint32_t> &
frag,
const char *wgsl) {
28 if (gfx->getBackendName() ==
"webgpu")
30 return gfx->newShaderFromSpv({},
frag);
33void declareComputeCommon(Shader *sh,
bool horizonStyle) {
34 sh->declareMatrix(
"invViewProj");
35 sh->declareFloat(
"nearZ");
36 sh->declareFloat(
"farZ");
37 sh->declareFloat(
"radius");
38 sh->declareFloat(
"bias");
39 sh->declareFloat(
"intensity");
40 sh->declareFloat(
"power");
42 sh->declareFloat(
"dirCount");
43 sh->declareFloat(
"stepCount");
45 sh->declareFloat(
"sampleCount");
47 sh->declareFloat(
"texelW");
48 sh->declareFloat(
"texelH");
51Shader *createSsaoShader(Graphics *gfx) {
53 std::vector<uint32_t>
frag(ao_ssao_frag_spv, ao_ssao_frag_spv + ao_ssao_frag_spv_count);
55 declareComputeCommon(sh,
false);
56 sh->sendMatrix(
"invViewProj", glm::mat4(1.f));
57 sh->sendFloat(
"nearZ", 0.1f);
58 sh->sendFloat(
"farZ", 100.f);
59 sh->sendFloat(
"radius", 0.75f);
60 sh->sendFloat(
"bias", 0.025f);
61 sh->sendFloat(
"intensity", 1.f);
62 sh->sendFloat(
"power", 1.5f);
63 sh->sendFloat(
"sampleCount", 16.f);
64 sh->sendFloat(
"texelW", 1.f / 256.f);
65 sh->sendFloat(
"texelH", 1.f / 256.f);
69Shader *createHbaoShader(Graphics *gfx) {
71 std::vector<uint32_t>
frag(ao_hbao_frag_spv, ao_hbao_frag_spv + ao_hbao_frag_spv_count);
73 declareComputeCommon(sh,
true);
74 sh->sendMatrix(
"invViewProj", glm::mat4(1.f));
75 sh->sendFloat(
"nearZ", 0.1f);
76 sh->sendFloat(
"farZ", 100.f);
77 sh->sendFloat(
"radius", 0.75f);
78 sh->sendFloat(
"bias", 0.025f);
79 sh->sendFloat(
"intensity", 1.f);
80 sh->sendFloat(
"power", 1.5f);
81 sh->sendFloat(
"dirCount", 6.f);
82 sh->sendFloat(
"stepCount", 6.f);
83 sh->sendFloat(
"texelW", 1.f / 256.f);
84 sh->sendFloat(
"texelH", 1.f / 256.f);
88Shader *createGtaoShader(Graphics *gfx) {
90 std::vector<uint32_t>
frag(ao_gtao_frag_spv, ao_gtao_frag_spv + ao_gtao_frag_spv_count);
92 declareComputeCommon(sh,
true);
93 sh->declareFloat(
"thickness");
94 sh->sendMatrix(
"invViewProj", glm::mat4(1.f));
95 sh->sendFloat(
"nearZ", 0.1f);
96 sh->sendFloat(
"farZ", 100.f);
97 sh->sendFloat(
"radius", 0.75f);
98 sh->sendFloat(
"bias", 0.025f);
99 sh->sendFloat(
"intensity", 1.f);
100 sh->sendFloat(
"power", 1.5f);
101 sh->sendFloat(
"dirCount", 6.f);
102 sh->sendFloat(
"stepCount", 6.f);
103 sh->sendFloat(
"texelW", 1.f / 256.f);
104 sh->sendFloat(
"texelH", 1.f / 256.f);
105 sh->sendFloat(
"thickness", 0.5f);
109Shader *createBlurShader(Graphics *gfx) {
110 if (!gfx)
throw eve::Exception(
"AmbientOcclusion: null graphics");
111 std::vector<uint32_t>
frag(ao_blur_frag_spv, ao_blur_frag_spv + ao_blur_frag_spv_count);
113 sh->declareFloat(
"texelW");
114 sh->declareFloat(
"texelH");
115 sh->declareFloat(
"depthSigma");
116 sh->declareFloat(
"spatialKernel");
117 sh->sendFloat(
"texelW", 1.f / 256.f);
118 sh->sendFloat(
"texelH", 1.f / 256.f);
119 sh->sendFloat(
"depthSigma", 0.05f);
120 sh->sendFloat(
"spatialKernel", 2.f);
124Shader *createOverlayShader(Graphics *gfx) {
125 if (!gfx)
throw eve::Exception(
"AmbientOcclusion: null graphics");
126 std::vector<uint32_t>
frag(ao_overlay_frag_spv, ao_overlay_frag_spv + ao_overlay_frag_spv_count);
128 sh->declareFloat(
"intensity");
129 sh->declareFloat(
"power");
130 sh->sendFloat(
"intensity", 1.f);
131 sh->sendFloat(
"power", 1.f);
135Shader *createFromDepthShader(Graphics *gfx) {
136 if (!gfx)
throw eve::Exception(
"AmbientOcclusion: null graphics");
137 std::vector<uint32_t>
frag(ao_from_depth_frag_spv,
138 ao_from_depth_frag_spv + ao_from_depth_frag_spv_count);
140 if (!sh || !sh->gpuHandle)
141 throw eve::Exception(
"AmbientOcclusion: failed to create from-depth shader");
142 declareComputeCommon(sh,
false);
143 sh->sendMatrix(
"invViewProj", glm::mat4(1.f));
144 sh->sendFloat(
"nearZ", 0.1f);
145 sh->sendFloat(
"farZ", 100.f);
146 sh->sendFloat(
"radius", 0.75f);
147 sh->sendFloat(
"bias", 0.025f);
148 sh->sendFloat(
"intensity", 0.55f);
149 sh->sendFloat(
"power", 1.35f);
150 sh->sendFloat(
"sampleCount", 16.f);
151 sh->sendFloat(
"texelW", 1.f / 256.f);
152 sh->sendFloat(
"texelH", 1.f / 256.f);
153 sh->declareFloat(
"hasNormal");
154 sh->sendFloat(
"hasNormal", 0.f);
161 ssaoShader_ = createSsaoShader(gfx);
162 hbaoShader_ = createHbaoShader(gfx);
163 gtaoShader_ = createGtaoShader(gfx);
164 blurShader_ = createBlurShader(gfx);
165 overlayShader_ = createOverlayShader(gfx);
166 fromDepthShader_ = createFromDepthShader(gfx);
167 applyQualityDefaults();
172Shader *AmbientOcclusion::activeComputeShader()
const {
173 if (mode_ ==
"hbao")
return hbaoShader_;
174 if (mode_ ==
"gtao")
return gtaoShader_;
180void AmbientOcclusion::applyQualityDefaults() {
181 if (quality_ ==
"low") {
184 if (mode_ ==
"hbao" || mode_ ==
"gtao") {
190 }
else if (quality_ ==
"high") {
193 if (mode_ ==
"hbao" || mode_ ==
"gtao") {
203 if (mode_ ==
"hbao" || mode_ ==
"gtao") {
219 applyQualityDefaults();
225 else if (mode ==
"gtao")
229 applyQualityDefaults();
234 ssaoShader_->
sendMatrix(
"invViewProj", invViewProj_);
235 hbaoShader_->
sendMatrix(
"invViewProj", invViewProj_);
236 gtaoShader_->
sendMatrix(
"invViewProj", invViewProj_);
237 if (fromDepthShader_) fromDepthShader_->
sendMatrix(
"invViewProj", invViewProj_);
241 float targetZ,
float upX,
float upY,
float upZ,
float fovYDeg,
242 float aspect,
float nearZ,
float farZ) {
243 nearZ_ = nearZ > 1e-4f ? nearZ : 0.1f;
244 farZ_ = farZ > nearZ_ ? farZ : nearZ_ + 1.f;
245 const float aspectSafe = aspect > 1e-4f ? aspect : 1.f;
246 const float fovRad = fovYDeg * 0.017453292519943295f;
247 const glm::mat4
view =
248 glm::lookAtRH(glm::vec3(eyeX, eyeY, eyeZ), glm::vec3(
targetX, targetY, targetZ),
249 glm::vec3(upX, upY, upZ));
258 if (fromDepthShader_) {
259 fromDepthShader_->
sendFloat(
"nearZ", nearZ_);
260 fromDepthShader_->
sendFloat(
"farZ", farZ_);
275 intensity_ = intensity < 0.f ? 0.f : intensity;
277 if (overlayShader_) overlayShader_->
sendFloat(
"intensity", intensity_);
287 if (gtaoShader_ && gtaoShader_->
hasUniform(
"thickness"))
288 gtaoShader_->
sendFloat(
"thickness", thickness_);
317 if (
active->getFromVar(
name, &
v,
sizeof(
v)) ==
int(
sizeof(
v)))
return v;
328 for (
Shader *sh : {ssaoShader_, hbaoShader_, gtaoShader_}) {
329 if (sh && sh->hasUniform(
name)) {
331 if (sh->getFromVar(
name, &
v,
sizeof(
v)) == int(
sizeof(
v)))
return v;
338 if (mode_ ==
"hbao" || mode_ ==
"gtao") {
339 const int dirs = int(std::lround(
getFloat(
"dirCount")));
343 return int(std::lround(
getFloat(
"sampleCount")));
347 if (fullSize < 1)
return 1;
348 const float ds = std::max(downscale_, 1.f);
349 return std::max(1,
int(std::floor(
float(fullSize) / ds)));
356 shader->sendMatrix(
"invViewProj", invViewProj_);
357 shader->sendFloat(
"nearZ", nearZ_);
358 shader->sendFloat(
"farZ", farZ_);
359 shader->sendFloat(
"radius", radius_);
360 shader->sendFloat(
"bias", bias_);
361 shader->sendFloat(
"intensity", intensity_);
362 shader->sendFloat(
"power", power_);
365 if (
shader->hasUniform(
"thickness"))
shader->sendFloat(
"thickness", thickness_);
368void AmbientOcclusion::drawFullscreen(Graphics *gfx, Texture *
source, Shader *
shader) {
369 if (!gfx)
throw eve::Exception(
"AmbientOcclusion: null graphics");
372 const float dw = gfx->getCanvas() ? float(gfx->getCanvas()->getWidth()) : float(gfx->getWidth());
374 gfx->getCanvas() ? float(gfx->getCanvas()->getHeight()) : float(gfx->getHeight());
375 gfx->drawTexturedRectShader(
source,
shader, 0.f, 0.f, dw, dh,
Color(1.f, 1.f, 1.f, 1.f));
379 if (!linearDepth)
throw eve::Exception(
"AmbientOcclusion.compute: null depth");
380 Shader *sh = activeComputeShader();
382 drawFullscreen(gfx, linearDepth, sh);
386 if (!gfx)
throw eve::Exception(
"AmbientOcclusion.computeTo: null graphics");
387 if (!dest)
throw eve::Exception(
"AmbientOcclusion.computeTo: null dest");
395 if (!aoMap)
throw eve::Exception(
"AmbientOcclusion.blur: null aoMap");
398 drawFullscreen(gfx, aoMap, blurShader_);
402 if (!gfx)
throw eve::Exception(
"AmbientOcclusion.blurTo: null graphics");
403 if (!dest)
throw eve::Exception(
"AmbientOcclusion.blurTo: null dest");
411 if (!aoMap)
throw eve::Exception(
"AmbientOcclusion.applyOverlay: null aoMap");
412 overlayShader_->
sendFloat(
"intensity", intensity_);
418 drawFullscreen(gfx, aoMap, overlayShader_);
422 if (!gfx)
throw eve::Exception(
"AmbientOcclusion.applyOverlayTo: null graphics");
423 if (!dest)
throw eve::Exception(
"AmbientOcclusion.applyOverlayTo: null dest");
435 if (!gfx)
throw eve::Exception(
"AmbientOcclusion.applyFromGBuffer: null graphics");
436 if (!hwDepth)
throw eve::Exception(
"AmbientOcclusion.applyFromGBuffer: null hwDepth");
437 if (!fromDepthShader_)
throw eve::Exception(
"AmbientOcclusion.applyFromGBuffer: missing shader");
438 fromDepthShader_->
sendFloat(
"hasNormal", worldNormal ? 1.f : 0.f);
439 uploadComputeCommon(fromDepthShader_, hwDepth->
getWidth(), hwDepth->
getHeight());
446 Color(1.f, 1.f, 1.f, 1.f));
448 drawFullscreen(gfx, hwDepth, fromDepthShader_);
453 if (!gfx)
throw eve::Exception(
"AmbientOcclusion.applyFromDepthTo: null graphics");
454 if (!dest)
throw eve::Exception(
"AmbientOcclusion.applyFromDepthTo: null dest");
462 float (*depth01)(
int x,
int y,
void *userdata),
464 if (!gfx)
throw eve::Exception(
"AmbientOcclusion.newLinearDepthTexture: null graphics");
466 throw eve::Exception(
"AmbientOcclusion.newLinearDepthTexture: invalid size");
467 if (!depth01)
throw eve::Exception(
"AmbientOcclusion.newLinearDepthTexture: null depth fn");
468 std::vector<uint8_t> rgba(
size_t(
width) *
size_t(
height) * 4);
471 float d = depth01(
x,
y, userdata);
472 if (
d < 0.f)
d = 0.f;
473 if (
d > 1.f)
d = 1.f;
474 const uint8_t
b = uint8_t(std::lround(
d * 255.f));
475 const size_t i = size_t(
y *
width +
x) * 4;
const UnitySourceAsset & source
EVENGINE_API_FOUNDATION public API.
void setBias(float bias)
Sets the bias.
void applyFromDepthTo(Graphics *gfx, Texture *linearDepth, Canvas *dest)
Applies from depth to.
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)
Sets the intensity.
void setFloat(const std::string &name, float value)
Sets the float.
void computeTo(Graphics *gfx, Texture *linearDepth, Canvas *dest)
Computes to.
AmbientOcclusion(Graphics *gfx)
Ambient occlusion.
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".
float getPower() const
Returns the power.
void blurTo(Graphics *gfx, Texture *aoMap, Canvas *dest)
Blur to.
void setInvViewProj(const glm::mat4 &invViewProj)
Sets the inv view proj.
bool hasParam(const std::string &name) const
True when param.
void setPower(float power)
Sets the power.
void applyFromGBuffer(Graphics *gfx, Texture *hwDepth, Texture *worldNormal)
Applies from g buffer.
void setThickness(float thickness)
Sets the thickness.
Shader * getShader() const
Returns the shader.
float getBias() const
Returns the bias.
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...
~AmbientOcclusion()
Ambient occlusion.
float getFloat(const std::string &name) const
Returns the float.
float getRadius() const
Returns the radius.
void setQuality(const std::string &quality)
"low" | "medium" | "high" (unknown → medium).
float getIntensity() const
Returns the intensity.
int getSampleCount() const
Returns the sample count.
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)
Applies overlay to.
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)
Sets the radius.
virtual int getWidth() const =0
Returns the width.
virtual int getHeight() const =0
Returns the height.
int getWidth() const
Returns the width.
virtual Canvas * getCanvas() const =0
Returns the canvas.
virtual Texture * newTexture(int width, int height, const uint8_t *rgba, bool repeatU=false, bool repeatV=false)=0
Creates a texture. @ownership Caller deletes unless documented otherwise.
virtual void setCanvas(Canvas *canvas)=0
nullptr or this → screen. Switching flushes pending draws to the previous target.
int getHeight() const
Returns the height.
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.
int getWidth() const
Returns the width.
int getHeight() const
Returns the height.
constexpr const char * kSsao
constexpr const char * kOverlay
constexpr const char * kBlur
constexpr const char * kGtao
constexpr const char * kAoCommon
constexpr const char * kHbao
constexpr const char * kFromDepth
卡牌游戏 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.
eve::Color Color
RGBA color used by every graphics draw call. Lives inside eve::graphics so including a graphics heade...