载入中...
搜索中...
未找到
Bloom.cpp
浏览该文件的文档.
1#include "graphics/Bloom.h"
2
3#include <algorithm>
4#include <string>
5#include <vector>
6
7#include "common/Exception.h"
9#include "graphics/Canvas.h"
10#include "graphics/Color.h"
11#include "graphics/Graphics.h"
12#include "graphics/Shader.h"
13#include "graphics/Texture.h"
15#include "graphics/shaders/bloom_downsample_frag_spv.inc"
16#include "graphics/shaders/bloom_upsample_frag_spv.inc"
17
18namespace eve::graphics {
19namespace {
20
21std::vector<uint32_t> copySpv(const uint32_t *data, size_t count) {
22 return std::vector<uint32_t>(data, data + count);
23}
24
25Shader *newPostShader(Graphics *gfx, const uint32_t *spv, size_t count, const char *wgsl) {
26 Shader *shader = gfx->getBackendName() == "webgpu"
27 ? gfx->newShaderFromWgsl({}, std::string(shaders::kPostCommon) + wgsl)
28 : gfx->newShaderFromSpv({}, copySpv(spv, count));
29 if (!shader || !shader->gpuHandle) throw eve::Exception("Bloom: failed to create shader");
30 return shader;
31}
32
33} // namespace
34
35Bloom::Bloom(Graphics *gfx) : gfx_(gfx) {
36 if (!gfx_) throw eve::Exception("Bloom: null graphics");
37 downsample_ = newPostShader(gfx_, bloom_downsample_frag_spv,
38 bloom_downsample_frag_spv_count, shaders::kBloomDownsample);
39 downsample_->declareFloat("texelW");
40 downsample_->declareFloat("texelH");
41 downsample_->declareFloat("firstPass");
42 downsample_->declareFloat("threshold");
43 downsample_->declareFloat("knee");
44
45 upsample_ = newPostShader(gfx_, bloom_upsample_frag_spv, bloom_upsample_frag_spv_count,
47 upsample_->declareFloat("texelW");
48 upsample_->declareFloat("texelH");
49 upsample_->declareFloat("scatter");
50}
51
52void Bloom::ensureTargets(int sourceWidth, int sourceHeight) {
53 sourceWidth = std::max(sourceWidth, 1);
54 sourceHeight = std::max(sourceHeight, 1);
55 if (levels_[0] && sourceWidth_ == sourceWidth && sourceHeight_ == sourceHeight) return;
56
57 sourceWidth_ = sourceWidth;
58 sourceHeight_ = sourceHeight;
59 composite_ = gfx_->newHDRCanvas(sourceWidth, sourceHeight);
60 if (!composite_) throw eve::Exception("Bloom: failed to allocate HDR composite target");
61 int width = sourceWidth;
62 int height = sourceHeight;
63 for (Canvas *&level : levels_) {
64 width = std::max(width / 2, 1);
65 height = std::max(height / 2, 1);
67 if (!level) throw eve::Exception("Bloom: failed to allocate HDR pyramid target");
68 }
69}
70
71void Bloom::configureDownsample(Texture *source, bool firstPass, float threshold) {
72 downsample_->sendFloat("texelW", 1.f / float(std::max(source->getWidth(), 1)));
73 downsample_->sendFloat("texelH", 1.f / float(std::max(source->getHeight(), 1)));
74 downsample_->sendFloat("firstPass", firstPass ? 1.f : 0.f);
75 downsample_->sendFloat("threshold", std::max(threshold, 0.f));
76 downsample_->sendFloat("knee", std::max(threshold * 0.5f, 1e-4f));
77}
78
79void Bloom::configureUpsample(Texture *source, float scatter) {
80 upsample_->sendFloat("texelW", 1.f / float(std::max(source->getWidth(), 1)));
81 upsample_->sendFloat("texelH", 1.f / float(std::max(source->getHeight(), 1)));
82 upsample_->sendFloat("scatter", std::clamp(scatter, 0.5f, 2.f));
83}
84
85Texture *Bloom::build(Texture *source, float threshold, float scatter) {
86 if (!source) throw eve::Exception("Bloom.build: null source");
87 ensureTargets(source->getWidth(), source->getHeight());
88 if (filterSettings_.filter != BloomFilter::KarisTent) return buildGaussian(source, threshold);
89 Canvas *previous = gfx_->getCanvas();
90
92 for (size_t i = 0; i < levels_.size(); ++i) {
93 Canvas *target = levels_[i];
94 target->clear(Color(0.f, 0.f, 0.f, 0.f), {}, {});
95 gfx_->setCanvas(target);
96 configureDownsample(input, i == 0, threshold);
97 gfx_->drawTexturedRectShaderUV(input, downsample_, 0.f, 0.f, float(target->getWidth()),
98 float(target->getHeight()), 0.f, 0.f, 1.f, 1.f,
99 Color(1.f, 1.f, 1.f, 1.f), false, BlendMode::Opaque);
100 input = target->getTexture();
101 if (!input) throw eve::Exception("Bloom: pyramid texture missing");
102 }
103
104 for (size_t i = levels_.size() - 1; i > 0; --i) {
105 Texture *low = levels_[i]->getTexture();
106 Canvas *high = levels_[i - 1];
107 configureUpsample(low, scatter);
108 gfx_->setCanvas(high);
109 gfx_->drawTexturedRectShaderUV(low, upsample_, 0.f, 0.f, float(high->getWidth()),
110 float(high->getHeight()), 0.f, 0.f, 1.f, 1.f,
111 Color(1.f, 1.f, 1.f, 1.f), false, BlendMode::Additive);
112 }
113
114 gfx_->setCanvas(previous);
115 return levels_[0]->getTexture();
116}
117
118Texture *Bloom::apply(Texture *source, float intensity, float threshold, float scatter) {
119 if (!source) throw eve::Exception("Bloom.apply: null source");
120 if (intensity <= 0.f) return source;
121 Texture *bloom = build(source, threshold, scatter);
122 if (filterSettings_.filter != BloomFilter::KarisTent) return compositeGaussian(source, bloom, intensity);
123 Canvas *previous = gfx_->getCanvas();
124 composite_->clear(Color(0.f, 0.f, 0.f, 0.f), {}, {});
125 gfx_->setCanvas(composite_);
126 gfx_->drawTexturedRectShaderUV(source, nullptr, 0.f, 0.f, float(sourceWidth_),
127 float(sourceHeight_), 0.f, 0.f, 1.f, 1.f,
128 Color(1.f, 1.f, 1.f, 1.f), false, BlendMode::Opaque);
129 gfx_->drawTexturedRectShaderUV(bloom, nullptr, 0.f, 0.f, float(sourceWidth_),
130 float(sourceHeight_), 0.f, 0.f, 1.f, 1.f,
131 Color(intensity, intensity, intensity, 1.f), false,
133 gfx_->setCanvas(previous);
134 Texture *result = composite_->getTexture();
135 if (!result) throw eve::Exception("Bloom: composite texture missing");
136 return result;
137}
138
139} // namespace eve::graphics
LogicalId target
EvpackChunkInput input
Definition Evpack.cpp:170
std::uint32_t height
std::uint32_t width
int level
graphics::Canvas * previous
Shader * shader
std::uint32_t count
const UnitySourceAsset & source
EVENGINE_API_FOUNDATION public API.
Definition Exception.h:13
Texture * build(Texture *source, float threshold, float scatter=1.f)
Build the selected bloom pyramid from an HDR source.
Definition Bloom.cpp:85
Bloom(Graphics *gfx)
Create the cross-backend bloom shaders.
Definition Bloom.cpp:35
Texture * apply(Texture *source, float intensity, float threshold, float scatter=1.f)
Add the reconstructed bloom to the HDR source in a full-size target.
Definition Bloom.cpp:118
Canvas public API.
Definition Canvas.h:17
virtual int getWidth() const =0
Returns the width.
virtual void clear(std::optional< Color > color, std::optional< int > stencil, std::optional< double > depth)=0
Clears .
virtual Texture * getTexture()=0
Sampleable color buffer; screen Canvas returns nullptr.
virtual int getHeight() const =0
Returns the height.
virtual void drawTexturedRectShaderUV(Texture *texture, Shader *shader, float x, float y, float w, float h, float u0, float v0, float u1, float v1, const Color &color, bool rotatedUV=false, BlendMode blend=BlendMode::Alpha)=0
UV draw with an explicit Shader (nullptr = default textured pipeline).
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.
void sendFloat(const std::string &name, float x)
Definition Shader.cpp:95
int declareFloat(const std::string &name)
Reserve sequential float slots in the push-constant block. Returns start index.
Definition Shader.cpp:43
GPU texture created via Graphics::newTexture. Owns GPU resources through an opaque backend handle.
Definition Texture.h:18
constexpr const char * kBloomDownsample
constexpr const char * kBloomUpsample
constexpr const char * kPostCommon
卡牌游戏 UI 工具模块:工厂 + 脚本绑定入口。 功能参考 ycarowr/UiCard:扇形手牌布局、抽牌/洗牌、悬浮放大、拖拽到落牌区、 敌方手牌(背面/偷看)、费用不足置灰,以及可实时调节的布局...
Definition Animation.h:25
eve::Color Color
RGBA color used by every graphics draw call. Lives inside eve::graphics so including a graphics heade...
Definition Color.h:13