From 2424d2a082ac3cdb91cdc77df30277d78e1b2d14 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 12 Dec 2012 03:10:05 -0600 Subject: [PATCH] A little bit of postprocess shader tinkering. --- indra/llrender/llpostprocess.cpp | 309 +++++++++--------- indra/llrender/llpostprocess.h | 49 ++- .../shaders/class1/effects/VignetteF.glsl | 54 +++ .../shaders/class1/effects/colorFilterF.glsl | 9 +- .../windlight/postprocesseffects.xml | 12 + indra/newview/llviewershadermgr.cpp | 25 +- .../xui/en-us/floater_post_process.xml | 67 ++++ 7 files changed, 340 insertions(+), 185 deletions(-) create mode 100644 indra/newview/app_settings/shaders/class1/effects/VignetteF.glsl diff --git a/indra/llrender/llpostprocess.cpp b/indra/llrender/llpostprocess.cpp index c1415e3f6..c533701b0 100644 --- a/indra/llrender/llpostprocess.cpp +++ b/indra/llrender/llpostprocess.cpp @@ -49,12 +49,63 @@ extern LLGLSLShader gPostNightVisionProgram; extern LLGLSLShader gPostGaussianBlurProgram; extern LLGLSLShader gPostPosterizeProgram; extern LLGLSLShader gPostMotionBlurProgram; +extern LLGLSLShader gPostVignetteProgram; static const unsigned int NOISE_SIZE = 512; static const char * const XML_FILENAME = "postprocesseffects.xml"; -template<> LLSD LLPostProcessShader::LLShaderSetting::getDefaultValue() +class LLPostProcessShader : public IPostProcessShader, public LLRefCount +{ +public: + LLPostProcessShader(const std::string& enable_name, LLGLSLShader& shader, bool enabled = false) : + mShader(shader), mEnabled(enable_name,enabled) + { + addSetting(mEnabled); + } + /*virtual*/ bool isEnabled() const {return mShader.mProgramObject && mEnabled;} + /*virtual*/ void bindShader() {mShader.bind();} + /*virtual*/ void unbindShader() {mShader.unbind();} + /*virtual*/ LLGLSLShader& getShader() {return mShader;} + + /*virtual*/ LLSD getDefaults(); //See IPostProcessShader::getDefaults + /*virtual*/ void loadSettings(const LLSD& settings); //See IPostProcessShader::loadSettings + /*virtual*/ void addSetting(IShaderSettingBase& setting) { mSettings.push_back(&setting); } +protected: + template + struct LLShaderSetting : public IShaderSettingBase + { + LLShaderSetting(const std::string& name, T def) : + mValue(def), mDefault(def), mSettingName(name) {} + operator T() const { return mValue; } + T get() const { return mValue; } + /*virtual*/ const std::string& getName() const { return mSettingName; } //See LLShaderSettingBase::getName + /*virtual*/ LLSD getDefaultValue() const { return mDefault; } //See LLShaderSettingBase::getDefaultValue + /*virtual*/ void setValue(const LLSD& value) { mValue = value; } //See LLShaderSettingBase::setValue + private: + const std::string mSettingName; //LLSD key names as found in postprocesseffects.xml. eg 'contrast_base' + T mValue; //The member variable mentioned above. + T mDefault; //Set via ctor. Value is inserted into the defaults LLSD list if absent from postprocesseffects.xml + }; +private: + std::vector mSettings; //Contains a list of all the 'settings' this shader uses. Manually add via push_back in ctor. + LLGLSLShader& mShader; + LLShaderSetting mEnabled; +}; + +//helpers +class LLPostProcessSinglePassColorShader : public LLPostProcessShader +{ +public: + LLPostProcessSinglePassColorShader(const std::string& enable_name, LLGLSLShader& shader, bool enabled = false) : + LLPostProcessShader(enable_name, shader, enabled) {} + /*virtual*/ S32 getColorChannel() const {return 0;} + /*virtual*/ S32 getDepthChannel() const {return -1;} + /*virtual*/ bool draw(U32 pass) {return pass == 1;} + /*virtual*/ void postDraw() {} +}; + +template<> LLSD LLPostProcessShader::LLShaderSetting::getDefaultValue() const { return mDefault.getValue(); } @@ -66,223 +117,181 @@ template<> void LLPostProcessShader::LLShaderSetting::setValue(const LLSD LLPostProcessShader::getDefaults() { LLSD defaults; - for(std::vector::iterator it=mSettings.begin();it!=mSettings.end();++it) + for(std::vector::iterator it=mSettings.begin();it!=mSettings.end();++it) { - defaults[(*it)->mSettingName]=(*it)->getDefaultValue(); + defaults[(*it)->getName()]=(*it)->getDefaultValue(); } return defaults; } void LLPostProcessShader::loadSettings(const LLSD& settings) { - for(std::vector::iterator it=mSettings.begin();it!=mSettings.end();++it) + for(std::vector::iterator it=mSettings.begin();it!=mSettings.end();++it) { - LLSD value = settings[(*it)->mSettingName]; + LLSD value = settings[(*it)->getName()]; (*it)->setValue(value); } } -class LLColorFilterShader : public LLPostProcessShader +class LLColorFilterShader : public LLPostProcessSinglePassColorShader { private: - LLShaderSetting mEnabled; LLShaderSetting mGamma, mBrightness, mContrast, mSaturation; LLShaderSetting mContrastBase; public: - LLColorFilterShader() : - mEnabled("enable_color_filter",false), + LLColorFilterShader() : + LLPostProcessSinglePassColorShader("enable_color_filter",gPostColorFilterProgram), mGamma("gamma",1.f), mBrightness("brightness",1.f), mContrast("contrast",1.f), mSaturation("saturation",1.f), mContrastBase("contrast_base",LLVector4(1.f,1.f,1.f,0.5f)) { - mSettings.push_back(&mEnabled); - mSettings.push_back(&mGamma); - mSettings.push_back(&mBrightness); - mSettings.push_back(&mContrast); - mSettings.push_back(&mSaturation); - mSettings.push_back(&mContrastBase); + addSetting(mGamma); + addSetting(mBrightness); + addSetting(mContrast); + addSetting(mSaturation); + addSetting(mContrastBase); } - bool isEnabled() { return mEnabled && gPostColorFilterProgram.mProgramObject; } - S32 getColorChannel() { return 0; } - S32 getDepthChannel() { return -1; } - - QuadType bind() + /*virtual*/ QuadType preDraw() { - if(!isEnabled()) - return QUAD_NONE; - /// CALCULATING LUMINANCE (Using NTSC lum weights) /// http://en.wikipedia.org/wiki/Luma_%28video%29 static const float LUMINANCE_R = 0.299f; static const float LUMINANCE_G = 0.587f; static const float LUMINANCE_B = 0.114f; - gPostColorFilterProgram.bind(); + getShader().uniform1f("gamma", mGamma); + getShader().uniform1f("brightness", mBrightness); + getShader().uniform1f("contrast", mContrast); + float baseI = (mContrastBase.get()[VX] + mContrastBase.get()[VY] + mContrastBase.get()[VZ]) / 3.0f; + baseI = mContrastBase.get()[VW] / llmax(baseI,0.001f); + float baseR = mContrastBase.get()[VX] * baseI; + float baseG = mContrastBase.get()[VY] * baseI; + float baseB = mContrastBase.get()[VZ] * baseI; + getShader().uniform3fv("contrastBase", 1, LLVector3(baseR, baseG, baseB).mV); + getShader().uniform1f("saturation", mSaturation); - gPostColorFilterProgram.uniform1f("gamma", mGamma); - gPostColorFilterProgram.uniform1f("brightness", mBrightness); - gPostColorFilterProgram.uniform1f("contrast", mContrast); - float baseI = (mContrastBase.mValue[VX] + mContrastBase.mValue[VY] + mContrastBase.mValue[VZ]) / 3.0f; - baseI = mContrastBase.mValue[VW] / ((baseI < 0.001f) ? 0.001f : baseI); - float baseR = mContrastBase.mValue[VX] * baseI; - float baseG = mContrastBase.mValue[VY] * baseI; - float baseB = mContrastBase.mValue[VZ] * baseI; - gPostColorFilterProgram.uniform3fv("contrastBase", 1, LLVector3(baseR, baseG, baseB).mV); - gPostColorFilterProgram.uniform1f("saturation", mSaturation); - gPostColorFilterProgram.uniform3fv("lumWeights", 1, LLVector3(LUMINANCE_R, LUMINANCE_G, LUMINANCE_B).mV); return QUAD_NORMAL; } - bool draw(U32 pass) {return pass == 1;} - void unbind() - { - gPostColorFilterProgram.unbind(); - } }; -class LLNightVisionShader : public LLPostProcessShader +class LLNightVisionShader : public LLPostProcessSinglePassColorShader { private: - LLShaderSetting mEnabled; LLShaderSetting mBrightnessMult, mNoiseStrength; public: LLNightVisionShader() : - mEnabled("enable_night_vision",false), + LLPostProcessSinglePassColorShader("enable_night_vision",gPostNightVisionProgram), mBrightnessMult("brightness_multiplier",3.f), mNoiseStrength("noise_strength",.4f) { - mSettings.push_back(&mEnabled); - mSettings.push_back(&mBrightnessMult); - mSettings.push_back(&mNoiseStrength); + addSetting(mBrightnessMult); + addSetting(mNoiseStrength); } - bool isEnabled() { return mEnabled && gPostNightVisionProgram.mProgramObject; } - S32 getColorChannel() { return 0; } - S32 getDepthChannel() { return -1; } - QuadType bind() + /*virtual*/ QuadType preDraw() { - if(!isEnabled()) - return QUAD_NONE; - - gPostNightVisionProgram.bind(); - LLPostProcess::getInstance()->bindNoise(1); - - gPostNightVisionProgram.uniform1f("brightMult", mBrightnessMult); - gPostNightVisionProgram.uniform1f("noiseStrength", mNoiseStrength); - + + getShader().uniform1f("brightMult", mBrightnessMult); + getShader().uniform1f("noiseStrength", mNoiseStrength); + return QUAD_NOISE; - } - bool draw(U32 pass) {return pass == 1;} - void unbind() +}; + +class LLPosterizeShader : public LLPostProcessSinglePassColorShader +{ +private: + LLShaderSetting mNumLayers; +public: + LLPosterizeShader() : LLPostProcessSinglePassColorShader("enable_posterize",gPostPosterizeProgram), + mNumLayers("posterize_layers",2) { - gPostNightVisionProgram.unbind(); + addSetting(mNumLayers); + } + /*virtual*/ QuadType preDraw() + { + getShader().uniform1i("layerCount", mNumLayers); + return QUAD_NORMAL; + } +}; + +class LLVignetteShader : public LLPostProcessSinglePassColorShader +{ +private: + LLShaderSetting mStrength, mRadius, mDarkness, mDesaturation, mChromaticAberration; +public: + LLVignetteShader() : LLPostProcessSinglePassColorShader("enable_vignette",gPostVignetteProgram), + mStrength("vignette_strength",.85f), + mRadius("vignette_radius",.7f), + mDarkness("vignette_darkness",1.f), + mDesaturation("vignette_desaturation",1.5f), + mChromaticAberration("vignette_chromatic_aberration",.05f) + { + addSetting(mStrength); + addSetting(mRadius); + addSetting(mDarkness); + addSetting(mDesaturation); + addSetting(mChromaticAberration); + } + /*virtual*/ QuadType preDraw() + { + LLVector2 screen_rect = LLPostProcess::getInstance()->getDimensions(); + getShader().uniform1f("vignette_strength", mStrength); + getShader().uniform1f("vignette_radius", mRadius); + getShader().uniform1f("vignette_darkness", mDarkness); + getShader().uniform1f("vignette_desaturation", mDesaturation); + getShader().uniform1f("vignette_chromatic_aberration", mChromaticAberration); + getShader().uniform2fv("screen_res", 1, screen_rect.mV); + return QUAD_NORMAL; } }; class LLGaussBlurShader : public LLPostProcessShader { private: - LLShaderSetting mEnabled; LLShaderSetting mNumPasses; GLint mPassLoc; public: - LLGaussBlurShader() : - mEnabled("enable_gauss_blur",false), + LLGaussBlurShader() : LLPostProcessShader("enable_gauss_blur",gPostGaussianBlurProgram), mNumPasses("gauss_blur_passes",2), mPassLoc(0) { - mSettings.push_back(&mEnabled); - mSettings.push_back(&mNumPasses); + addSetting(mNumPasses); } - bool isEnabled() { return mEnabled && mNumPasses && gPostGaussianBlurProgram.mProgramObject; } - S32 getColorChannel() { return 0; } - S32 getDepthChannel() { return -1; } - QuadType bind() + /*virtual*/ bool isEnabled() const { return LLPostProcessShader::isEnabled() && mNumPasses.get(); } + /*virtual*/ S32 getColorChannel() const { return 0; } + /*virtual*/ S32 getDepthChannel() const { return -1; } + /*virtual*/ QuadType preDraw() { - if(!isEnabled()) - return QUAD_NONE; - - gPostGaussianBlurProgram.bind(); - - mPassLoc = gPostGaussianBlurProgram.getUniformLocation("horizontalPass"); - + mPassLoc = getShader().getUniformLocation("horizontalPass"); return QUAD_NORMAL; } - bool draw(U32 pass) + /*virtual*/ bool draw(U32 pass) { if((S32)pass > mNumPasses*2) return false; glUniform1iARB(mPassLoc, (pass-1) % 2); return true; } - void unbind() - { - gPostGaussianBlurProgram.unbind(); - } -}; - -class LLPosterizeShader : public LLPostProcessShader -{ -private: - LLShaderSetting mEnabled; - LLShaderSetting mNumLayers; -public: - LLPosterizeShader() : - mEnabled("enable_posterize",false), - mNumLayers("posterize_layers",2) - { - mSettings.push_back(&mEnabled); - mSettings.push_back(&mNumLayers); - } - bool isEnabled() { return mEnabled && gPostPosterizeProgram.mProgramObject; } - S32 getColorChannel() { return 0; } - S32 getDepthChannel() { return -1; } - QuadType bind() - { - if(!isEnabled()) - return QUAD_NONE; - - gPostPosterizeProgram.bind(); - - gPostPosterizeProgram.uniform1i("layerCount", mNumLayers); - - return QUAD_NORMAL; - } - bool draw(U32 pass) - { - return pass == 1; - } - void unbind() - { - gPostPosterizeProgram.unbind(); - } + /*virtual*/ void postDraw() {} }; class LLMotionShader : public LLPostProcessShader { private: - LLShaderSetting mEnabled; LLShaderSetting mStrength; public: - LLMotionShader() : - mEnabled("enable_motionblur",false), - mStrength("blur_strength",false) + LLMotionShader() : LLPostProcessShader("enable_motionblur",gPostMotionBlurProgram), + mStrength("blur_strength",1) { - mSettings.push_back(&mEnabled); - mSettings.push_back(&mStrength); + addSetting(mStrength); } - bool isEnabled() { return mEnabled && gPostMotionBlurProgram.mProgramObject; } - S32 getColorChannel() { return 0; } - S32 getDepthChannel() { return 1; } - QuadType bind() + /*virtual*/ S32 getColorChannel() const { return 0; } + /*virtual*/ S32 getDepthChannel() const { return 1; } + /*virtual*/ QuadType preDraw() { - if(!isEnabled()) - { - return QUAD_NONE; - } - glh::matrix4f inv_proj(gGLModelView); inv_proj.mult_left(gGLProjection); inv_proj = inv_proj.inverse(); @@ -291,22 +300,18 @@ public: LLVector2 screen_rect = LLPostProcess::getInstance()->getDimensions(); - gPostMotionBlurProgram.bind(); - gPostMotionBlurProgram.uniformMatrix4fv("prev_proj", 1, GL_FALSE, prev_proj.m); - gPostMotionBlurProgram.uniformMatrix4fv("inv_proj", 1, GL_FALSE, inv_proj.m); - gPostMotionBlurProgram.uniform2fv("screen_res", 1, screen_rect.mV); - gPostMotionBlurProgram.uniform1i("blur_strength", mStrength); + getShader().uniformMatrix4fv("prev_proj", 1, GL_FALSE, prev_proj.m); + getShader().uniformMatrix4fv("inv_proj", 1, GL_FALSE, inv_proj.m); + getShader().uniform2fv("screen_res", 1, screen_rect.mV); + getShader().uniform1i("blur_strength", mStrength); return QUAD_NORMAL; } - bool draw(U32 pass) + /*virtual*/ bool draw(U32 pass) { return pass == 1; } - void unbind() - { - gPostMotionBlurProgram.unbind(); - } + /*virtual*/ void postDraw() {} }; LLPostProcess::LLPostProcess(void) : @@ -320,12 +325,12 @@ LLPostProcess::LLPostProcess(void) : mAllEffectInfo(LLSD::emptyMap()) { mShaders.push_back(new LLMotionShader()); + mShaders.push_back(new LLVignetteShader()); mShaders.push_back(new LLColorFilterShader()); mShaders.push_back(new LLNightVisionShader()); mShaders.push_back(new LLGaussBlurShader()); mShaders.push_back(new LLPosterizeShader()); - /* Do nothing. Needs to be updated to use our current shader system, and to work with the move into llrender.*/ std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME)); LL_DEBUGS2("AppInit", "Shaders") << "Loading PostProcess Effects settings from " << pathName << LL_ENDL; @@ -547,20 +552,19 @@ void LLPostProcess::doEffects(void) void LLPostProcess::applyShaders(void) { - QuadType quad; bool primary_rendertarget = 1; for(std::list >::iterator it=mShaders.begin();it!=mShaders.end();++it) { - if((quad = (*it)->bind()) != QUAD_NONE) + if((*it)->isEnabled()) { S32 color_channel = (*it)->getColorChannel(); S32 depth_channel = (*it)->getDepthChannel(); - if(depth_channel >= 0) gGL.getTexUnit(depth_channel)->bindManual(LLTexUnit::TT_RECT_TEXTURE, mDepthTexture); - U32 pass = 1; + (*it)->bindShader(); + QuadType quad = (*it)->preDraw(); while((*it)->draw(pass++)) { mRenderTarget[!primary_rendertarget].bindTarget(); @@ -573,7 +577,8 @@ void LLPostProcess::applyShaders(void) if(mRenderTarget[0].getFBO()) primary_rendertarget = !primary_rendertarget; } - (*it)->unbind(); + (*it)->postDraw(); + (*it)->unbindShader(); } } //Only need to copy to framebuffer if FBOs are supported, else we've already been drawing to the framebuffer to begin with. diff --git a/indra/llrender/llpostprocess.h b/indra/llrender/llpostprocess.h index 9ecd9e293..6c3da675e 100644 --- a/indra/llrender/llpostprocess.h +++ b/indra/llrender/llpostprocess.h @@ -38,57 +38,48 @@ #include "llrendertarget.h" class LLSD; +class LLGLSLShader; typedef enum _QuadType { - QUAD_NONE, QUAD_NORMAL, QUAD_NOISE } QuadType; //LLPostProcessShader is an attempt to encapsulate the shaders a little better. -class LLPostProcessShader : public LLRefCount //Abstract. PostProcess shaders derive off of this common base. +class IPostProcessShader //Abstract. PostProcess shaders derive off of this common base. { protected: //LLShaderSetting is used to associate key names to member variables to avoid LLSD lookups when drawing. //It also facilitates automating the assigning of defaults to, as well as parsing from, the effects LLSD list. //This replaces the entire old PostProcessTweaks structure. More will be done in the future to move into a more //xml-driven configuration. - struct LLShaderSettingBase + struct IShaderSettingBase { - LLShaderSettingBase(const char* name) : mSettingName(name) {} - const char* mSettingName; //LLSD key names as found in postprocesseffects.xml. eg 'contrast_base' - virtual LLSD getDefaultValue() = 0; //Converts the member variable as an LLSD. Used to set defaults absent in postprocesseffects.xml + virtual ~IShaderSettingBase() {} //virtual dtor. + virtual const std::string& getName() const = 0; //Returns the name of this setting + virtual LLSD getDefaultValue() const = 0; //Converts the member variable as an LLSD. Used to set defaults absent in postprocesseffects.xml virtual void setValue(const LLSD& value) = 0; //Connects the LLSD element to the member variable. Used when loading effects (such as default) }; - template - struct LLShaderSetting : public LLShaderSettingBase - { - LLShaderSetting(const char* setting_name, T def) : LLShaderSettingBase(setting_name), mValue(def), mDefault(def) {} - T mValue; //The member variable mentioned above. - T mDefault; //Set via ctor. Value is inserted into the defaults LLSD list if absent from postprocesseffects.xml - LLSD getDefaultValue() { return mDefault; } //See LLShaderSettingBase::getDefaultValue - void setValue(const LLSD& value) { mValue = value; } //See LLShaderSettingBase::setValue - operator T() { return mValue; } //Typecast operator overload so this object can be handled as if it was whatever T represents. - }; - std::vector mSettings; //Contains a list of all the 'settings' this shader uses. Manually add via push_back in ctor. public: - virtual ~LLPostProcessShader() {}; - virtual bool isEnabled() = 0; //Returning false avoids bind/draw/unbind calls. If no shaders are enabled, framebuffer copying is skipped. - virtual S32 getColorChannel() = 0; //If color buffer is used in this shader returns > -1 to cue LLPostProcess on copying it from the framebuffer. - virtual S32 getDepthChannel() = 0; //If depth buffer is used in this shader returns > -1 to cue LLPostProcess on copying it from the framebuffer. - virtual QuadType bind() = 0; //Bind shader and textures, set up attribs. Returns the 'type' of quad to be drawn. + virtual ~IPostProcessShader() {} //virtual dtor. + virtual bool isEnabled() const = 0; //Returning false avoids bind/draw/unbind calls. If no shaders are enabled, framebuffer copying is skipped. + virtual S32 getColorChannel() const = 0; //If color buffer is used in this shader returns > -1 to cue LLPostProcess on copying it from the framebuffer. + virtual S32 getDepthChannel() const = 0; //If depth buffer is used in this shader returns > -1 to cue LLPostProcess on copying it from the framebuffer. + virtual void bindShader() = 0; + virtual void unbindShader() = 0; + virtual LLGLSLShader& getShader() = 0; + + virtual QuadType preDraw() = 0; //Bind shader and textures, set up attribs. Returns the 'type' of quad to be drawn. virtual bool draw(U32 pass) = 0; //returning false means finished. Used to update per-pass attributes and such. LLPostProcess will call //drawOrthoQuad when this returns true, increment pass, then call this again, and keep repeating this until false is returned. - virtual void unbind() = 0; //Unbind shader and textures. + virtual void postDraw() = 0; //Done drawing.. - LLSD getDefaults(); //Returns a full LLSD kvp list filled with default values. - void loadSettings(const LLSD& settings); //Parses the effects LLSD list and sets the member variables linked to them (via LLShaderSetting::setValue()) + virtual LLSD getDefaults() = 0; //Returns a full LLSD kvp list filled with default values. + virtual void loadSettings(const LLSD& settings) = 0; //Parses the effects LLSD list and sets the member variables linked to them (via LLShaderSetting::setValue()) + virtual void addSetting(IShaderSettingBase& setting) = 0; }; -//LLVector4 does not implicitly convert to and from LLSD, so template specilizations are necessary. -template<> LLSD LLPostProcessShader::LLShaderSetting::getDefaultValue(); -template<> void LLPostProcessShader::LLShaderSetting::setValue(const LLSD& value); - +class LLPostProcessShader; class LLPostProcess : public LLSingleton { private: diff --git a/indra/newview/app_settings/shaders/class1/effects/VignetteF.glsl b/indra/newview/app_settings/shaders/class1/effects/VignetteF.glsl new file mode 100644 index 000000000..ad989e1a0 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/effects/VignetteF.glsl @@ -0,0 +1,54 @@ +/** + * @file colorFilterF.glsl + * + * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#extension GL_ARB_texture_rectangle : enable + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2DRect tex0; +uniform float vignette_strength; //0 - 1 +uniform float vignette_radius; //0 - 8 +uniform float vignette_darkness; //0 - 1 +uniform float vignette_desaturation; //0 - 10 +uniform float vignette_chromatic_aberration; //0 - .1 +uniform vec2 screen_res; + +VARYING vec2 vary_texcoord0; + +float luminance(vec3 color) +{ + /// CALCULATING LUMINANCE (Using NTSC lum weights) + /// http://en.wikipedia.org/wiki/Luma_%28video%29 + return dot(color, vec3(0.299, 0.587, 0.114)); +} + +void main(void) +{ + vec3 color = texture2DRect(tex0, vary_texcoord0).rgb; + vec2 norm_texcood = (vary_texcoord0/screen_res); + vec2 offset = norm_texcood-vec2(.5); + float vignette = clamp(pow(1 - dot(offset,offset),vignette_radius) + 1-vignette_strength, 0.0, 1.0); + float inv_vignette = 1-vignette; + + //vignette chromatic aberration (g + vec2 shift = screen_res * offset * vignette_chromatic_aberration * inv_vignette; + float g = texture2DRect(tex0,vary_texcoord0-shift).g; + float b = texture2DRect(tex0,vary_texcoord0-2*shift).b; + color.gb = vec2(g,b); + + //vignette 'black' overlay. + color = mix(color * vignette, color, 1-vignette_darkness); + + //vignette desaturation + color = mix(vec3(luminance(color)), color, clamp(1-inv_vignette*vignette_desaturation,0,1)); + + frag_color = vec4(color,1.0); +} diff --git a/indra/newview/app_settings/shaders/class1/effects/colorFilterF.glsl b/indra/newview/app_settings/shaders/class1/effects/colorFilterF.glsl index e03b83113..6acd277bb 100644 --- a/indra/newview/app_settings/shaders/class1/effects/colorFilterF.glsl +++ b/indra/newview/app_settings/shaders/class1/effects/colorFilterF.glsl @@ -25,6 +25,13 @@ uniform float gamma; VARYING vec2 vary_texcoord0; +float luminance(vec3 color) +{ + /// CALCULATING LUMINANCE (Using NTSC lum weights) + /// http://en.wikipedia.org/wiki/Luma_%28video%29 + return dot(color, vec3(0.299, 0.587, 0.114)); +} + void main(void) { vec3 color = vec3(texture2DRect(tex0, vary_texcoord0.st)); @@ -39,7 +46,7 @@ void main(void) color = mix(contrastBase, color, contrast); /// Modulate saturation - color = mix(vec3(dot(color, lumWeights)), color, saturation); + color = mix(vec3(luminance(color)), color, saturation); frag_color = vec4(color, 1.0); } diff --git a/indra/newview/app_settings/windlight/postprocesseffects.xml b/indra/newview/app_settings/windlight/postprocesseffects.xml index b5b173b40..5a498009c 100644 --- a/indra/newview/app_settings/windlight/postprocesseffects.xml +++ b/indra/newview/app_settings/windlight/postprocesseffects.xml @@ -177,6 +177,8 @@ enable_posterize 0 enable_motionblur + 0 + enable_vignette 0 gauss_blur_passes 2 @@ -194,6 +196,16 @@ 10 blur_strength 10 + vignette_strength + 0.85 + vignette_radius + 0.7 + vignette_darkness + 1.0 + vignette_desaturation + 1.0 + vignette_chromatic_aberration + 0.01 \ No newline at end of file diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 0cd49f717..39ee7ce5e 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -172,7 +172,8 @@ LLGLSLShader gPostNightVisionProgram(LLViewerShaderMgr::SHADER_EFFECT); //Not LLGLSLShader gPostGaussianBlurProgram(LLViewerShaderMgr::SHADER_EFFECT); //Not in mShaderList LLGLSLShader gPostPosterizeProgram(LLViewerShaderMgr::SHADER_EFFECT); //Not in mShaderList LLGLSLShader gPostMotionBlurProgram(LLViewerShaderMgr::SHADER_EFFECT); //Not in mShaderList - +LLGLSLShader gPostVignetteProgram(LLViewerShaderMgr::SHADER_EFFECT); //Not in mShaderList + // Deferred rendering shaders LLGLSLShader gDeferredImpostorProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredWaterProgram(LLViewerShaderMgr::SHADER_DEFERRED); //calculatesAtmospherics @@ -908,7 +909,6 @@ BOOL LLViewerShaderMgr::loadShadersEffects() shaderUniforms.push_back("contrast"); shaderUniforms.push_back("contrastBase"); shaderUniforms.push_back("saturation"); - shaderUniforms.push_back("lumWeights"); gPostColorFilterProgram.mName = "Color Filter Shader (Post)"; gPostColorFilterProgram.mShaderFiles.clear(); @@ -929,7 +929,6 @@ BOOL LLViewerShaderMgr::loadShadersEffects() shaderUniforms.reserve(3); shaderUniforms.push_back("brightMult"); shaderUniforms.push_back("noiseStrength"); - shaderUniforms.push_back("lumWeights"); gPostNightVisionProgram.mName = "Night Vision Shader (Post)"; gPostNightVisionProgram.mShaderFiles.clear(); @@ -998,6 +997,26 @@ BOOL LLViewerShaderMgr::loadShadersEffects() gPostMotionBlurProgram.uniform1i("tex1", 1); } } + + { + vector shaderUniforms; + shaderUniforms.reserve(3); + shaderUniforms.push_back("vignette_darkness"); + shaderUniforms.push_back("vignette_radius"); + shaderUniforms.push_back("screen_res"); + + gPostVignetteProgram.mName = "Vignette Shader (Post)"; + gPostVignetteProgram.mShaderFiles.clear(); + gPostVignetteProgram.mShaderFiles.push_back(make_pair("effects/VignetteF.glsl", GL_FRAGMENT_SHADER_ARB)); + gPostVignetteProgram.mShaderFiles.push_back(make_pair("interface/onetexturenocolorV.glsl", GL_VERTEX_SHADER_ARB)); + gPostVignetteProgram.mShaderLevel = mVertexShaderLevel[SHADER_EFFECT]; + if(gPostVignetteProgram.createShader(NULL, &shaderUniforms)) + { + gPostVignetteProgram.bind(); + gPostVignetteProgram.uniform1i("tex0", 0); + } + } + #endif return success; diff --git a/indra/newview/skins/default/xui/en-us/floater_post_process.xml b/indra/newview/skins/default/xui/en-us/floater_post_process.xml index 234652667..705350960 100644 --- a/indra/newview/skins/default/xui/en-us/floater_post_process.xml +++ b/indra/newview/skins/default/xui/en-us/floater_post_process.xml @@ -184,6 +184,73 @@ max_val="30" min_val="1" mouse_opaque="true" name="blur_strength" show_text="true" value="0.7" width="200" /> + + + + Strength + + + + Radius + + + + Darkness + + + + Desaturation Strength + + + + Chromatic Aberration + + +