9#include "graphics/shaders/ssr_frag_spv.inc"
10#include "graphics/shaders/ssr_temporal_frag_spv.inc"
19Shader *createSsrShader(Graphics *gfx) {
20 std::vector<uint32_t>
frag(ssr_frag_spv, ssr_frag_spv + ssr_frag_spv_count);
21 Shader *sh = gfx->getBackendName() ==
"webgpu"
24 : gfx->newShaderFromSpv({},
frag);
25 sh->declareMatrix(
"invViewProj");
26 sh->declareVec3(
"cameraPos");
27 sh->declareFloat(
"nearZ");
28 sh->declareFloat(
"farZ");
29 sh->declareFloat(
"texelW");
30 sh->declareFloat(
"texelH");
31 sh->declareFloat(
"maxDist");
32 sh->declareFloat(
"stepLen");
33 sh->declareFloat(
"maxSteps");
34 sh->declareFloat(
"thickness");
35 sh->declareFloat(
"strength");
36 sh->declareFloat(
"enabled");
37 sh->declareFloat(
"bias");
38 sh->declareFloat(
"maxRoughness");
39 sh->declareFloat(
"depthPyramidLevels");
43Shader *createSsrTemporalShader(Graphics *gfx) {
44 std::vector<uint32_t>
frag(ssr_temporal_frag_spv,
45 ssr_temporal_frag_spv + ssr_temporal_frag_spv_count);
46 Shader *sh = gfx->getBackendName() ==
"webgpu"
49 : gfx->newShaderFromSpv({},
frag);
50 for (
int i = 0; i < 16; ++i) sh->declareFloat(
"reprojection" + std::to_string(i));
51 sh->declareFloat(
"temporalTexelW");
52 sh->declareFloat(
"temporalTexelH");
53 sh->declareFloat(
"temporalHistoryValid");
54 sh->declareFloat(
"temporalNearZ");
55 sh->declareFloat(
"temporalFarZ");
56 sh->declareFloat(
"temporalCurrentWeight");
57 sh->declareFloat(
"spatialFilterStrength");
58 sh->declareFloat(
"temporalEnergyEncoded");
59 sh->declareFloat(
"spatialStep");
65 ssr_ = createSsrShader(gfx);
66 temporal_ = createSsrTemporalShader(gfx);
77 const glm::mat4 nextViewProj = glm::inverse(
invViewProj);
80 for (
int c = 0;
c < 4; ++
c)
81 for (
int r = 0;
r < 4; ++
r)
82 maxDelta = std::max(maxDelta,
83 std::abs(nextViewProj[
c][
r] - previousViewProj_[
c][
r]));
84 if (maxDelta > 2.f) historyValid_ =
false;
90void ScreenSpaceReflection::ensureHistory(
int width,
int height) {
93 if (!historyA_ || !historyB_ || historyWidth_ !=
width || historyHeight_ !=
height) {
98 historyRead_ = historyA_;
99 historyWrite_ = historyB_;
100 historyWidth_ =
width;
102 historyValid_ =
false;
106void ScreenSpaceReflection::resolveTemporal(Graphics *gfx, Texture *
current,
107 Texture *motionDepth) {
108 if (!
current || !motionDepth || !temporal_)
return;
110 const glm::mat4 currentViewProj = glm::inverse(invViewProj_);
111 const glm::mat4 reprojection = previousViewProj_ * invViewProj_;
112 const float *matrix = &reprojection[0][0];
113 for (
int i = 0; i < 16; ++i)
114 temporal_->
sendFloat(
"reprojection" + std::to_string(i), matrix[i]);
115 temporal_->
sendFloat(
"temporalTexelW", 1.f /
float(historyWidth_));
116 temporal_->
sendFloat(
"temporalTexelH", 1.f /
float(historyHeight_));
117 temporal_->
sendFloat(
"temporalNearZ", nearZ_);
118 temporal_->
sendFloat(
"temporalFarZ", farZ_);
119 temporal_->
sendFloat(
"temporalCurrentWeight", temporalCurrentWeight_);
120 temporal_->
sendFloat(
"temporalEnergyEncoded", 0.f);
124 for (
int pass = 0; pass < spatialPasses; ++pass) {
125 Canvas *
target = (pass & 1) == 0 ? spatialA_ : spatialB_;
126 temporal_->
sendFloat(
"temporalHistoryValid", 0.f);
127 temporal_->
sendFloat(
"spatialFilterStrength", spatialFilterStrength_);
128 temporal_->
sendFloat(
"spatialStep",
float(1 << pass));
130 gfx->drawTexturedRectShaderDepthMotion(
131 filtered, filtered, motionDepth, temporal_, 0.f, 0.f,
float(historyWidth_),
132 float(historyHeight_),
Color(1.f, 1.f, 1.f, 1.f));
133 filtered =
target->getTexture();
136 temporal_->
sendFloat(
"temporalHistoryValid", historyValid_ && viewProjValid_ ? 1.f : 0.f);
137 temporal_->
sendFloat(
"spatialFilterStrength", spatialPasses == 0 ? spatialFilterStrength_ : 0.f);
138 temporal_->
sendFloat(
"spatialStep", 1.f);
139 gfx->setCanvas(historyWrite_);
141 gfx->drawTexturedRectShaderDepthMotion(
142 filtered, history, motionDepth, temporal_, 0.f, 0.f,
float(historyWidth_),
143 float(historyHeight_),
Color(1.f, 1.f, 1.f, 1.f));
144 std::swap(historyRead_, historyWrite_);
145 historyValid_ =
true;
146 viewProjValid_ =
true;
147 previousViewProj_ = currentViewProj;
151 float targetY,
float targetZ,
float upX,
float upY,
152 float upZ,
float fovYDeg,
float aspect,
float nearZ,
154 nearZ_ = nearZ > 1e-4f ? nearZ : 0.1f;
155 farZ_ = farZ > nearZ_ ? farZ : nearZ_ + 1.f;
156 const float aspectSafe = aspect > 1e-4f ? aspect : 1.f;
157 const float fovRad = fovYDeg * 0.017453292519943295f;
158 const glm::vec3
eye(eyeX, eyeY, eyeZ);
159 glm::vec3 forward = glm::vec3(
targetX, targetY, targetZ) -
eye;
160 forward = glm::length(forward) > 1e-5f ? glm::normalize(forward)
161 : glm::vec3(0.f, 0.f, -1.f);
163 (glm::distance(
eye, previousEye_) > std::max(1.f, farZ_ * 0.1f) ||
164 glm::dot(forward, previousForward_) < 0.65f ||
165 std::abs(fovYDeg - previousFovY_) > 3.f ||
166 std::abs(aspectSafe - previousAspect_) > std::max(0.05f, previousAspect_ * 0.1f)))
167 historyValid_ =
false;
169 previousForward_ = forward;
170 previousFovY_ = fovYDeg;
171 previousAspect_ = aspectSafe;
173 const glm::mat4
view =
174 glm::lookAtRH(
eye, glm::vec3(
targetX, targetY, targetZ),
175 glm::vec3(upX, upY, upZ));
183 if (enabled_ !=
enabled) historyValid_ =
false;
185 ssr_->
sendFloat(
"enabled", enabled_ ? 1.f : 0.f);
189 quality_ = quality ==
"low" || quality ==
"medium" || quality ==
"high" ||
193 historyValid_ =
false;
194 if (quality_ ==
"low") {
200 temporalCurrentWeight_ = 0.3f;
201 spatialFilterStrength_ = 0.8f;
202 }
else if (quality_ ==
"high") {
208 temporalCurrentWeight_ = 0.12f;
209 spatialFilterStrength_ = 0.4f;
210 }
else if (quality_ ==
"ultra") {
216 temporalCurrentWeight_ = 0.08f;
217 spatialFilterStrength_ = 0.3f;
224 temporalCurrentWeight_ = 0.16f;
225 spatialFilterStrength_ = 0.5f;
235 setFloat(
"maxRoughness", std::clamp(
v, 0.f, 1.f));
238 const float next = std::clamp(
scale, 0.25f, 1.f);
239 if (std::abs(next - resolutionScale_) < 1e-4f)
return;
240 resolutionScale_ = next;
241 reflection_ =
nullptr;
242 historyValid_ =
false;
251 throw eve::Exception(
"ScreenSpaceReflection.setFloat: missing param '%s'",
name.c_str());
253 if (
name ==
"maxDist" ||
name ==
"stepLen" ||
name ==
"maxSteps" ||
254 name ==
"thickness" ||
name ==
"strength" ||
name ==
"bias" ||
255 name ==
"maxRoughness")
256 historyValid_ =
false;
259 if (
name ==
"maxSteps") maxSteps_ =
value;
260 if (
name ==
"thickness") thickness_ =
value;
261 if (
name ==
"strength") strength_ =
value;
262 if (
name ==
"maxRoughness") maxRoughness_ =
value;
267 throw eve::Exception(
"ScreenSpaceReflection.getFloat: missing param '%s'",
name.c_str());
270 throw eve::Exception(
"ScreenSpaceReflection.getFloat: missing param '%s'",
name.c_str());
273void ScreenSpaceReflection::uploadUniforms(
int width,
int height) {
276 ssr_->
sendMatrix(
"invViewProj", invViewProj_);
284 ssr_->
sendFloat(
"thickness", thickness_);
286 ssr_->
sendFloat(
"enabled", enabled_ ? 1.f : 0.f);
288 ssr_->
sendFloat(
"maxRoughness", maxRoughness_);
289 ssr_->
sendFloat(
"depthPyramidLevels",
float(std::max(depthPyramidLevels_, 0)));
294 if (!gfx)
throw eve::Exception(
"ScreenSpaceReflection: null graphics");
295 if (!dest)
throw eve::Exception(
"ScreenSpaceReflection.applyFromSceneTo: null dest");
299 if (temporalMotionDepth_)
300 resolveTemporal(gfx, dest->
getTexture(), temporalMotionDepth_);
302 historyValid_ =
false;
312 const int targetW = std::max(1,
int(std::lround(
float(fullW) * resolutionScale_)));
313 const int targetH = std::max(1,
int(std::lround(
float(fullH) * resolutionScale_)));
314 if (!reflection_ || reflection_->
getWidth() != targetW ||
323 return historyValid_ && historyRead_ ? historyRead_->
getTexture()
324 : (reflection_ ? reflection_->
getTexture() :
nullptr);
329 if (!gfx)
throw eve::Exception(
"ScreenSpaceReflection: null graphics");
330 if (!sceneColor)
throw eve::Exception(
"ScreenSpaceReflection: null scene color");
331 if (!hwDepth)
throw eve::Exception(
"ScreenSpaceReflection: null depth");
336 Texture *traceDepth = depthPyramid_ && depthPyramidLevels_ > 0 ? depthPyramid_ : hwDepth;
338 worldNormal ? worldNormal : sceneColor,
340 Color(1.f, 1.f, 1.f, 1.f));
graphics::Texture * albedo
std::array< float, 3 > scale
EVENGINE_API_FOUNDATION public API.
virtual int getWidth() const =0
Returns the width.
virtual Texture * getTexture()=0
Sampleable color buffer; screen Canvas returns nullptr.
virtual int getHeight() const =0
Returns the height.
int getPixelHeight() const
Returns the pixel height.
virtual void drawTexturedRectShader4(Texture *color, Texture *depth, Texture *motion, Texture *extra, Shader *shader, float x, float y, float w, float h, const Color &tint)=0
Post draw with four sampled textures at bindings 0, 1, 2 and 3.
int getWidth() const
Returns the width.
virtual Canvas * getCanvas() const =0
Returns the canvas.
virtual void setCanvas(Canvas *canvas)=0
nullptr or this → screen. Switching flushes pending draws to the previous target.
virtual Canvas * newHDRCanvas(int width, int height)=0
Create an engine-internal linear RGBA16F post-process target.
int getPixelWidth() const
Returns the pixel width.
int getHeight() const
Returns the height.
void applyFromSceneTo(Graphics *gfx, Texture *sceneColor, Texture *hwDepth, Texture *worldNormal, Canvas *dest)
Write the SSR result into the currently bound canvas / dest.
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) + near/far.
~ScreenSpaceReflection()
Screen space reflection.
void setQuality(const std::string &quality)
Set "low", "medium", "high" or "ultra" SSR quality preset.
Texture * getReflectionTexture()
The reflection texture from the owned canvas, or nullptr before first apply.
void setMaxDistance(float meters)
Sets the max distance.
void setEnabled(bool enabled)
Enable/disable the pass. When disabled it emits transparent (0 hit).
void setResolutionScale(float scale)
Set internal SSR resolution scale in the range 0.25 to 1.0.
void setThickness(float meters)
Sets the thickness.
void setMaxSteps(int steps)
Sets the max steps.
Canvas * getReflectionCanvas()
Owned reflection canvas (created on first use at the current target size).
void setStepLength(float meters)
Sets the step length.
void setInvViewProj(const glm::mat4 &invViewProj)
Sets the inv view proj.
int getSpatialPassCount() const
Number of explicit A-trous prefilter passes for the active quality.
void setStrength(float strength)
Sets the strength.
ScreenSpaceReflection(Graphics *gfx)
Screen space reflection.
float getFloat(const std::string &name) const
Returns the float.
void setFloat(const std::string &name, float value)
Sets the float.
void applyFromScene(Graphics *gfx, Texture *sceneColor, Texture *hwDepth, Texture *worldNormal, Texture *albedo=nullptr)
Write SSR into the currently bound canvas / screen.
void setMaxRoughness(float roughness)
Skip SSR above this material roughness and rely on reflection backup.
bool hasParam(const std::string &name) const
True when param.
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 * kSsr
constexpr const char * kSsrTemporal
constexpr const char * kScreenEffectCommon
卡牌游戏 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...