Documentation

Post Processing

Π’ этом Ρ€Π°Π·Π΄Π΅Π»Π΅ ΠΎΠΏΠΈΡΡ‹Π²Π°ΡŽΡ‚ΡΡ эффСкты постобработки, доступныС Π² Wudgine.

БистСма постобработки

Wudgine ΠΏΡ€Π΅Π΄Π»Π°Π³Π°Π΅Ρ‚ ΠΌΠΎΡ‰Π½ΡƒΡŽ систСму постобработки для ΡƒΠ»ΡƒΡ‡ΡˆΠ΅Π½ΠΈΡ Π²ΠΈΠ·ΡƒΠ°Π»ΡŒΠ½ΠΎΠ³ΠΎ качСства Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π°. Π­Ρ„Ρ„Π΅ΠΊΡ‚Ρ‹ постобработки ΠΏΡ€ΠΈΠΌΠ΅Π½ΡΡŽΡ‚ΡΡ ΠΊ Ρ„ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠΌΡƒ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΡŽ послС Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ основного Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π° сцСны.

Π‘Ρ‚Π΅ΠΊ постобработки

// ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ стСка постобработки
auto& postProcess = renderer.getPostProcessStack();

// Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ эффСктов
postProcess.addEffect<BloomEffect>();
postProcess.addEffect<TonemappingEffect>();
postProcess.addEffect<ColorGradingEffect>();
postProcess.addEffect<VignetteEffect>();

// Настройка порядка эффСктов
postProcess.setEffectOrder({
    PostProcessEffectType::Bloom,
    PostProcessEffectType::SSAO,
    PostProcessEffectType::Tonemapping,
    PostProcessEffectType::ColorGrading,
    PostProcessEffectType::Vignette
});

// Π’ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅/ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ эффСктов
postProcess.enableEffect(PostProcessEffectType::Bloom, true);
postProcess.enableEffect(PostProcessEffectType::Vignette, false);

ΠžΡΠ½ΠΎΠ²Π½Ρ‹Π΅ эффСкты

Bloom

Bloom создаСт эффСкт свСчСния Π²ΠΎΠΊΡ€ΡƒΠ³ ярких областСй изобраТСния, имитируя рассСиваниС свСта Π² ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΈΠ²Π΅ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹.

// Настройка эффСкта Bloom
auto& bloom = postProcess.addEffect<BloomEffect>();
bloom.setThreshold(1.0f);      // ΠŸΠΎΡ€ΠΎΠ³ яркости для Π½Π°Ρ‡Π°Π»Π° эффСкта
bloom.setIntensity(0.5f);      // Π˜Π½Ρ‚Π΅Π½ΡΠΈΠ²Π½ΠΎΡΡ‚ΡŒ эффСкта
bloom.setScatter(0.7f);        // РассСиваниС свСчСния
bloom.setRadius(4);            // Радиус размытия

Tonemapping

Π’ΠΎΠ½ΠΌΠ°ΠΏΠΏΠΈΠ½Π³ ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΡƒΠ΅Ρ‚ HDR (High Dynamic Range) ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ Π² LDR (Low Dynamic Range) для отобраТСния Π½Π° стандартных ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€Π°Ρ….

// Настройка эффСкта Tonemapping
auto& tonemap = postProcess.addEffect<TonemappingEffect>();
tonemap.setOperator(TonemappingOperator::ACES); // ACES, Reinhard, Uncharted2, Filmic
tonemap.setExposure(1.0f);                      // Экспозиция
tonemap.setGamma(2.2f);                         // Π“Π°ΠΌΠΌΠ°-коррСкция
  • ACES: ΠšΠΈΠ½Π΅ΠΌΠ°Ρ‚ΠΎΠ³Ρ€Π°Ρ„ΠΈΡ‡Π΅ΡΠΊΠΈΠΉ Ρ‚ΠΎΠ½ΠΌΠ°ΠΏΠΏΠΈΠ½Π³ с Ρ…ΠΎΡ€ΠΎΡˆΠ΅ΠΉ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π΅ΠΉ Ρ†Π²Π΅Ρ‚ΠΎΠ²
  • Reinhard: ΠŸΡ€ΠΎΡΡ‚ΠΎΠΉ ΠΈ быстрый ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ с мягким сТатиСм
  • Uncharted2: ΠžΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ с Ρ…ΠΎΡ€ΠΎΡˆΠ΅ΠΉ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π΅ΠΉ Π΄Π΅Ρ‚Π°Π»Π΅ΠΉ Π² тСнях
  • Filmic: ΠžΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ с кинСматографичСским внСшним Π²ΠΈΠ΄ΠΎΠΌ

Color Grading

Color Grading позволяСт Π½Π°ΡΡ‚Ρ€Π°ΠΈΠ²Π°Ρ‚ΡŒ Ρ†Π²Π΅Ρ‚ΠΎΠ²ΡƒΡŽ Π³Π°ΠΌΠΌΡƒ изобраТСния для создания ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½ΠΎΠ³ΠΎ настроСния ΠΈΠ»ΠΈ атмосфСры.

// Настройка эффСкта Color Grading
auto& colorGrading = postProcess.addEffect<ColorGradingEffect>();
colorGrading.setContrast(1.1f);                 // ΠšΠΎΠ½Ρ‚Ρ€Π°ΡΡ‚
colorGrading.setSaturation(1.2f);               // ΠΠ°ΡΡ‹Ρ‰Π΅Π½Π½ΠΎΡΡ‚ΡŒ
colorGrading.setGain(Vector3(1.0f, 1.0f, 1.0f)); // УсилСниС RGB
colorGrading.setOffset(Vector3(0.0f, 0.0f, 0.1f)); // Π‘ΠΌΠ΅Ρ‰Π΅Π½ΠΈΠ΅ RGB
colorGrading.setLUT("assets/textures/luts/cinematic.png"); // ΠŸΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ LUT

LUT (Look-Up Table)

Π’Π°Π±Π»ΠΈΡ†Π° прСобразования Ρ†Π²Π΅Ρ‚ΠΎΠ² для быстрого ΠΈ Ρ‚ΠΎΡ‡Π½ΠΎΠ³ΠΎ примСнСния Ρ†Π²Π΅Ρ‚ΠΎΠ²Ρ‹Ρ… схСм.

Π¦Π²Π΅Ρ‚ΠΎΠ²Ρ‹Π΅ ΠΊΡ€ΠΈΠ²Ρ‹Π΅

Настройка ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Ρ… ΠΊΠ°Π½Π°Π»ΠΎΠ² RGB для Ρ‚ΠΎΡ‡Π½ΠΎΠ³ΠΎ контроля Π½Π°Π΄ Ρ†Π²Π΅Ρ‚Π°ΠΌΠΈ.

Depth of Field

Depth of Field (Π³Π»ΡƒΠ±ΠΈΠ½Π° рСзкости) ΠΈΠΌΠΈΡ‚ΠΈΡ€ΡƒΠ΅Ρ‚ эффСкт фокусировки ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹, размывая ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹, находящиСся Π²Π½Π΅ фокуса.

// Настройка эффСкта Depth of Field
auto& dof = postProcess.addEffect<DepthOfFieldEffect>();
dof.setFocalDistance(10.0f);   // РасстояниС фокусировки
dof.setFocalLength(50.0f);     // ЀокусноС расстояниС
dof.setAperture(2.8f);         // Π”ΠΈΠ°Ρ„Ρ€Π°Π³ΠΌΠ° (f-число)
dof.setBokehShape(BokehShape::Hexagon); // Π€ΠΎΡ€ΠΌΠ° Π±ΠΎΠΊΠ΅

Motion Blur

Motion Blur создаСт эффСкт размытия двиТСния, добавляя Ρ€Π΅Π°Π»ΠΈΠ·ΠΌ быстро двиТущимся ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°ΠΌ.

// Настройка эффСкта Motion Blur
auto& motionBlur = postProcess.addEffect<MotionBlurEffect>();
motionBlur.setIntensity(0.3f);         // Π˜Π½Ρ‚Π΅Π½ΡΠΈΠ²Π½ΠΎΡΡ‚ΡŒ размытия
motionBlur.setSampleCount(8);          // ΠšΠΎΠ»ΠΈΡ‡Π΅ΡΡ‚Π²ΠΎ сэмплов
motionBlur.setVelocityScale(1.0f);     // ΠœΠ°ΡΡˆΡ‚Π°Π± скорости
// Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° Motion Blur ΠΊ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρƒ
auto& motionVector = entity.addComponent<MotionVectorComponent>();
motionVector.setVelocityMultiplier(1.0f);

Screen Space Ambient Occlusion (SSAO)

SSAO добавляСт рСалистичныС мягкиС Ρ‚Π΅Π½ΠΈ Π² ΡƒΠ³Π»Π°Ρ… ΠΈ щСлях ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ², ΡƒΠ»ΡƒΡ‡ΡˆΠ°Ρ восприятиС Π³Π»ΡƒΠ±ΠΈΠ½Ρ‹ сцСны.

// Настройка эффСкта SSAO
auto& ssao = postProcess.addEffect<SSAOEffect>();
ssao.setRadius(0.5f);          // Радиус эффСкта
ssao.setSampleCount(16);       // ΠšΠΎΠ»ΠΈΡ‡Π΅ΡΡ‚Π²ΠΎ сэмплов
ssao.setPower(2.0f);           // Π‘ΠΈΠ»Π° эффСкта
ssao.setBias(0.025f);          // Π‘ΠΌΠ΅Ρ‰Π΅Π½ΠΈΠ΅ для прСдотвращСния Π°Ρ€Ρ‚Π΅Ρ„Π°ΠΊΡ‚ΠΎΠ²
ssao.setBlurSize(4);           // Π Π°Π·ΠΌΠ΅Ρ€ размытия

Π”Ρ€ΡƒΠ³ΠΈΠ΅ эффСкты

Π’ΠΈΠ½ΡŒΠ΅Ρ‚ΠΊΠ°

Π—Π°Ρ‚Π΅ΠΌΠ½Π΅Π½ΠΈΠ΅ ΠΊΡ€Π°Π΅Π² экрана для фокусировки внимания Π½Π° Ρ†Π΅Π½Ρ‚Ρ€Π΅.

Π₯роматичСская абСррация

Π˜ΠΌΠΈΡ‚Π°Ρ†ΠΈΡ оптичСского искаТСния, Ρ€Π°Π·Π΄Π΅Π»ΡΡŽΡ‰Π΅Π³ΠΎ Ρ†Π²Π΅Ρ‚ΠΎΠ²Ρ‹Π΅ ΠΊΠ°Π½Π°Π»Ρ‹.

Π—Π΅Ρ€Π½ΠΈΡΡ‚ΠΎΡΡ‚ΡŒ ΠΏΠ»Π΅Π½ΠΊΠΈ

Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ ΡˆΡƒΠΌΠ° для ΠΈΠΌΠΈΡ‚Π°Ρ†ΠΈΠΈ зСрнистости Ρ„ΠΎΡ‚ΠΎΠΏΠ»Π΅Π½ΠΊΠΈ.

Π‘ΠΊΠ°Π½Π»Π°ΠΉΠ½Ρ‹

Π˜ΠΌΠΈΡ‚Π°Ρ†ΠΈΡ Π»ΠΈΠ½ΠΈΠΉ Ρ€Π°Π·Π²Π΅Ρ€Ρ‚ΠΊΠΈ старых ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€ΠΎΠ².

ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠ΅ эффСкты

Wudgine позволяСт ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠ΅ эффСкты постобработки:

// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ эффСкта
class MyCustomEffect : public PostProcessEffect {
public:
    MyCustomEffect() {
        // Π—Π°Π³Ρ€ΡƒΠ·ΠΊΠ° ΡˆΠ΅ΠΉΠ΄Π΅Ρ€Π°
        shader = ShaderProgram::create("assets/shaders/post/custom_effect");
        
        // Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ²
        addParameter("intensity", 1.0f);
        addParameter("color", Vector3(1.0f, 0.5f, 0.2f));
    }
    
    void render(const RenderContext& context) override {
        // Настройка ΡˆΠ΅ΠΉΠ΄Π΅Ρ€Π°
        shader.bind();
        shader.setUniform("u_Intensity", getParameter<float>("intensity"));
        shader.setUniform("u_Color", getParameter<Vector3>("color"));
        shader.setUniform("u_SourceTexture", context.sourceTexture, 0);
        
        // Π Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³ эффСкта
        renderFullscreenQuad();
    }
    
private:
    ShaderProgram shader;
};

// ИспользованиС ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ эффСкта
auto& customEffect = postProcess.addEffect<MyCustomEffect>();
customEffect.setParameter("intensity", 0.8f);
customEffect.setParameter("color", Vector3(0.2f, 0.8f, 1.0f));

ΠŸΡ€ΠΎΡ„ΠΈΠ»ΠΈ постобработки

Wudgine позволяСт ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΠΈ ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΡ„ΠΈΠ»ΠΈ постобработки для Ρ€Π°Π·Π½Ρ‹Ρ… ситуаций:

// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΏΡ€ΠΎΡ„ΠΈΠ»Π΅ΠΉ постобработки
auto& postProcess = renderer.getPostProcessStack();

// ΠŸΡ€ΠΎΡ„ΠΈΠ»ΡŒ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ
auto defaultProfile = postProcess.createProfile("Default");
defaultProfile->addEffect<BloomEffect>().setIntensity(0.3f);
defaultProfile->addEffect<TonemappingEffect>().setOperator(TonemappingOperator::ACES);

// ΠŸΡ€ΠΎΡ„ΠΈΠ»ΡŒ для ΠΏΠΎΠ΄Π²ΠΎΠ΄Π½Ρ‹Ρ… сцСн
auto underwaterProfile = postProcess.createProfile("Underwater");
underwaterProfile->addEffect<BloomEffect>().setIntensity(0.2f);
underwaterProfile->addEffect<ColorGradingEffect>().setLUT("assets/textures/luts/underwater.png");
underwaterProfile->addEffect<DistortionEffect>().setIntensity(0.05f);
underwaterProfile->addEffect<VignetteEffect>().setIntensity(0.4f);

// ΠŸΡ€ΠΎΡ„ΠΈΠ»ΡŒ для Π½ΠΎΡ‡Π½ΠΎΠ³ΠΎ видСния
auto nightVisionProfile = postProcess.createProfile("NightVision");
nightVisionProfile->addEffect<ColorGradingEffect>().setGain(Vector3(0.0f, 1.2f, 0.0f));
nightVisionProfile->addEffect<NoiseEffect>().setIntensity(0.1f);
nightVisionProfile->addEffect<VignetteEffect>().setIntensity(0.7f);

// ΠŸΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΏΡ€ΠΎΡ„ΠΈΠ»Π΅ΠΉ
postProcess.setActiveProfile("Default");
// ПозТС Π² ΠΈΠ³Ρ€Π΅
postProcess.setActiveProfile("Underwater");
// ΠŸΠ»Π°Π²Π½Ρ‹ΠΉ ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ ΠΌΠ΅ΠΆΠ΄Ρƒ профилями
postProcess.blendToProfile("NightVision", 2.0f); // ΠŸΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ Π·Π° 2 сСкунды

Π‘Π»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ шаги

Π’Π΅ΠΏΠ΅Ρ€ΡŒ, ΠΊΠΎΠ³Π΄Π° Π²Ρ‹ ознакомились с систСмой постобработки Wudgine, Ρ€Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡƒΠ΅ΠΌ:

ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π°

Π˜Π·ΡƒΡ‡ΠΈΡ‚Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π° для ΠΏΠΎΠ²Ρ‹ΡˆΠ΅Π½ΠΈΡ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ.

ECS: Π“Π»ΡƒΠ±ΠΎΠΊΠΎΠ΅ ΠΏΠΎΠ³Ρ€ΡƒΠΆΠ΅Π½ΠΈΠ΅

ΠŸΠΎΠ·Π½Π°ΠΊΠΎΠΌΡŒΡ‚Π΅ΡΡŒ с Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€ΠΎΠΉ Entity-Component-System.

Wudgine β€’ Β© 2025