载入中...
搜索中...
未找到
Exposure.cpp
浏览该文件的文档.
1#include "graphics/Exposure.h"
2
3#include <algorithm>
4#include <string>
5#include <utility>
6#include <vector>
7
8#include "common/Exception.h"
10#include "graphics/Canvas.h"
11#include "graphics/Color.h"
12#include "graphics/Graphics.h"
13#include "graphics/Shader.h"
14#include "graphics/Texture.h"
16#include "graphics/shaders/exposure_adapt_frag_spv.inc"
17#include "graphics/shaders/exposure_apply_frag_spv.inc"
18#include "graphics/shaders/exposure_meter_frag_spv.inc"
19
20namespace eve::graphics {
21namespace {
22
23std::vector<uint32_t> copySpv(const uint32_t *data, size_t count) {
24 return std::vector<uint32_t>(data, data + count);
25}
26
27Shader *newPostShader(Graphics *gfx, const uint32_t *spv, size_t count, const char *wgsl) {
28 Shader *shader = gfx->getBackendName() == "webgpu"
29 ? gfx->newShaderFromWgsl({}, std::string(shaders::kPostCommon) + wgsl)
30 : gfx->newShaderFromSpv({}, copySpv(spv, count));
31 if (!shader || !shader->gpuHandle) throw eve::Exception("Exposure: failed to create shader");
32 return shader;
33}
34
35} // namespace
36
37Exposure::Exposure(Graphics *gfx) : gfx_(gfx) {
38 if (!gfx_) throw eve::Exception("Exposure: null graphics");
39 meterShader_ = newPostShader(gfx_, exposure_meter_frag_spv, exposure_meter_frag_spv_count,
41 meterShader_->declareFloat("minEV");
42 meterShader_->declareFloat("maxEV");
43
44 adaptShader_ = newPostShader(gfx_, exposure_adapt_frag_spv, exposure_adapt_frag_spv_count,
46 adaptShader_->declareFloat("deltaSeconds");
47 adaptShader_->declareFloat("darkSpeed");
48 adaptShader_->declareFloat("brightSpeed");
49 adaptShader_->declareFloat("resetHistory");
50
51 applyShader_ = newPostShader(gfx_, exposure_apply_frag_spv, exposure_apply_frag_spv_count,
53 applyShader_->declareFloat("manualExposure");
54 applyShader_->declareFloat("automatic");
55 applyShader_->declareFloat("colorFilterR");
56 applyShader_->declareFloat("colorFilterG");
57 applyShader_->declareFloat("colorFilterB");
58 applyShader_->declareFloat("vignette");
59 applyShader_->declareFloat("lensDistortion");
60 applyShader_->declareFloat("liftR");
61 applyShader_->declareFloat("liftG");
62 applyShader_->declareFloat("liftB");
63 applyShader_->declareFloat("inverseGammaR");
64 applyShader_->declareFloat("inverseGammaG");
65 applyShader_->declareFloat("inverseGammaB");
66 applyShader_->declareFloat("gainR");
67 applyShader_->declareFloat("gainG");
68 applyShader_->declareFloat("gainB");
69 applyShader_->declareFloat("vignetteSmoothness");
70 applyShader_->declareFloat("lensScale");
71}
72
73void Exposure::ensureTargets(int width, int height) {
74 width = std::max(width, 1);
75 height = std::max(height, 1);
76 if (!meter_) {
77 meter_ = gfx_->newHDRCanvas(1, 1);
78 historyA_ = gfx_->newHDRCanvas(1, 1);
79 historyB_ = gfx_->newHDRCanvas(1, 1);
80 historyRead_ = historyA_;
81 historyWrite_ = historyB_;
82 }
83 if (!output_ || width_ != width || height_ != height) {
84 output_ = gfx_->newHDRCanvas(width, height);
85 width_ = width;
86 height_ = height;
87 historyValid_ = false;
88 }
89 if (!meter_ || !historyRead_ || !historyWrite_ || !output_)
90 throw eve::Exception("Exposure: failed to allocate HDR targets");
91}
92
93Texture *Exposure::apply(Texture *source, float manualExposure, bool automatic, float minEV,
94 float maxEV, const glm::vec3& colorFilter, const glm::vec3& lift,
95 const glm::vec3& inverseGamma, const glm::vec3& gain, float vignette,
96 float vignetteSmoothness, float lensDistortion, float lensScale,
97 Texture *meterSource,
98 float deltaSeconds) {
99 if (!source) throw eve::Exception("Exposure.apply: null source");
100 ensureTargets(source->getWidth(), source->getHeight());
101 Canvas *previousCanvas = gfx_->getCanvas();
102 Texture *exposureTexture = source;
103 if (!meterSource) meterSource = source;
104
105 if (automatic) {
106 meterShader_->sendFloat("minEV", std::min(minEV, maxEV));
107 meterShader_->sendFloat("maxEV", std::max(minEV, maxEV));
108 meter_->clear(Color(0.f, 0.f, 0.f, 1.f), {}, {});
109 gfx_->setCanvas(meter_);
110 gfx_->drawTexturedRectShaderUV(meterSource, meterShader_, 0.f, 0.f, 1.f, 1.f, 0.f, 0.f,
111 1.f, 1.f, Color(1.f, 1.f, 1.f, 1.f), false,
113
114 adaptShader_->sendFloat("deltaSeconds", std::clamp(deltaSeconds, 0.f, 0.25f));
115 adaptShader_->sendFloat("darkSpeed", 1.5f);
116 adaptShader_->sendFloat("brightSpeed", 3.f);
117 adaptShader_->sendFloat("resetHistory", historyValid_ ? 0.f : 1.f);
118 historyWrite_->clear(Color(1.f, 0.f, 0.f, 1.f), {}, {});
119 gfx_->setCanvas(historyWrite_);
120 Texture *meterTexture = meter_->getTexture();
121 Texture *previousExposure = historyValid_ ? historyRead_->getTexture() : meterTexture;
122 gfx_->drawTexturedRectShaderDepthMotion(meterTexture, previousExposure, meterTexture,
123 adaptShader_, 0.f, 0.f, 1.f, 1.f,
124 Color(1.f, 1.f, 1.f, 1.f));
125 exposureTexture = historyWrite_->getTexture();
126 historyValid_ = true;
127 std::swap(historyRead_, historyWrite_);
128 }
129
130 applyShader_->sendFloat("manualExposure", std::max(manualExposure, 0.f));
131 applyShader_->sendFloat("automatic", automatic ? 1.f : 0.f);
132 applyShader_->sendFloat("colorFilterR", std::max(colorFilter.r, 0.f));
133 applyShader_->sendFloat("colorFilterG", std::max(colorFilter.g, 0.f));
134 applyShader_->sendFloat("colorFilterB", std::max(colorFilter.b, 0.f));
135 applyShader_->sendFloat("vignette", std::clamp(vignette, 0.0F, 1.0F));
136 applyShader_->sendFloat("lensDistortion", std::clamp(lensDistortion, 0.0F, 1.0F));
137 applyShader_->sendFloat("liftR", lift.r);
138 applyShader_->sendFloat("liftG", lift.g);
139 applyShader_->sendFloat("liftB", lift.b);
140 applyShader_->sendFloat("inverseGammaR", std::max(inverseGamma.r, 0.001F));
141 applyShader_->sendFloat("inverseGammaG", std::max(inverseGamma.g, 0.001F));
142 applyShader_->sendFloat("inverseGammaB", std::max(inverseGamma.b, 0.001F));
143 applyShader_->sendFloat("gainR", gain.r);
144 applyShader_->sendFloat("gainG", gain.g);
145 applyShader_->sendFloat("gainB", gain.b);
146 applyShader_->sendFloat("vignetteSmoothness", std::clamp(vignetteSmoothness, 0.01F, 1.0F));
147 applyShader_->sendFloat("lensScale", std::clamp(lensScale, 0.01F, 5.0F));
148 output_->clear(Color(0.f, 0.f, 0.f, 0.f), {}, {});
149 gfx_->setCanvas(output_);
150 gfx_->drawTexturedRectShaderDepthMotion(source, exposureTexture, source, applyShader_, 0.f, 0.f,
151 float(width_), float(height_),
152 Color(1.f, 1.f, 1.f, 1.f));
153 gfx_->setCanvas(previousCanvas);
154 Texture *result = output_->getTexture();
155 if (!result) throw eve::Exception("Exposure: output texture missing");
156 return result;
157}
158
159} // namespace eve::graphics
std::uint32_t height
std::uint32_t width
Shader * shader
std::uint32_t count
const UnitySourceAsset & source
EVENGINE_API_FOUNDATION public API.
Definition Exception.h:13
Canvas public API.
Definition Canvas.h:17
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.
Texture * apply(Texture *source, float manualExposure, bool automatic, float minEV, float maxEV, const glm::vec3 &colorFilter, const glm::vec3 &lift, const glm::vec3 &inverseGamma, const glm::vec3 &gain, float vignette, float vignetteSmoothness, float lensDistortion, float lensScale, Texture *meterSource=nullptr, float deltaSeconds=1.f/60.f)
Apply manual and optional automatic exposure to a linear HDR source.
Definition Exposure.cpp:93
Exposure(Graphics *gfx)
Create cross-backend exposure shaders and 1x1 history targets.
Definition Exposure.cpp:37
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 void drawTexturedRectShaderDepthMotion(Texture *color, Texture *depth, Texture *motion, Shader *shader, float x, float y, float w, float h, const Color &tint)=0
Post draw with color, depth/history and motion/reactive textures.
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 * kExposureMeter
constexpr const char * kPostCommon
constexpr const char * kExposureAdapt
constexpr const char * kExposureApply
卡牌游戏 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