A little bit of postprocess shader tinkering.
This commit is contained in:
@@ -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<LLVector4>::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<typename T>
|
||||
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<IShaderSettingBase*> mSettings; //Contains a list of all the 'settings' this shader uses. Manually add via push_back in ctor.
|
||||
LLGLSLShader& mShader;
|
||||
LLShaderSetting<bool> 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<LLVector4>::getDefaultValue() const
|
||||
{
|
||||
return mDefault.getValue();
|
||||
}
|
||||
@@ -66,223 +117,181 @@ template<> void LLPostProcessShader::LLShaderSetting<LLVector4>::setValue(const
|
||||
LLSD LLPostProcessShader::getDefaults()
|
||||
{
|
||||
LLSD defaults;
|
||||
for(std::vector<LLShaderSettingBase*>::iterator it=mSettings.begin();it!=mSettings.end();++it)
|
||||
for(std::vector<IShaderSettingBase*>::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<LLShaderSettingBase*>::iterator it=mSettings.begin();it!=mSettings.end();++it)
|
||||
for(std::vector<IShaderSettingBase*>::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<bool> mEnabled;
|
||||
LLShaderSetting<F32> mGamma, mBrightness, mContrast, mSaturation;
|
||||
LLShaderSetting<LLVector4> 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<bool> mEnabled;
|
||||
LLShaderSetting<F32> 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<S32> 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<F32> 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<bool> mEnabled;
|
||||
LLShaderSetting<S32> 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<bool> mEnabled;
|
||||
LLShaderSetting<S32> 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<bool> mEnabled;
|
||||
LLShaderSetting<S32> 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<LLPointer<LLPostProcessShader> >::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.
|
||||
|
||||
@@ -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<typename T>
|
||||
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<LLShaderSettingBase*> 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<LLVector4>::getDefaultValue();
|
||||
template<> void LLPostProcessShader::LLShaderSetting<LLVector4>::setValue(const LLSD& value);
|
||||
|
||||
class LLPostProcessShader;
|
||||
class LLPostProcess : public LLSingleton<LLPostProcess>
|
||||
{
|
||||
private:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -177,6 +177,8 @@
|
||||
<key>enable_posterize</key>
|
||||
<boolean>0</boolean>
|
||||
<key>enable_motionblur</key>
|
||||
<boolean>0</boolean>
|
||||
<key>enable_vignette</key>
|
||||
<boolean>0</boolean>
|
||||
<key>gauss_blur_passes</key>
|
||||
<integer>2</integer>
|
||||
@@ -194,6 +196,16 @@
|
||||
<real>10</real>
|
||||
<key>blur_strength</key>
|
||||
<real>10</real>
|
||||
<key>vignette_strength</key>
|
||||
<real>0.85</real>
|
||||
<key>vignette_radius</key>
|
||||
<real>0.7</real>
|
||||
<key>vignette_darkness</key>
|
||||
<real>1.0</real>
|
||||
<key>vignette_desaturation</key>
|
||||
<real>1.0</real>
|
||||
<key>vignette_chromatic_aberration</key>
|
||||
<real>0.01</real>
|
||||
</map>
|
||||
</map>
|
||||
</llsd>
|
||||
@@ -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<string> 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;
|
||||
|
||||
@@ -184,6 +184,73 @@
|
||||
max_val="30" min_val="1" mouse_opaque="true"
|
||||
name="blur_strength" show_text="true" value="0.7" width="200" />
|
||||
</panel>
|
||||
<panel border="true" bottom="-180" follows="left|top|right|bottom" height="400"
|
||||
label="Vignette" left="1" mouse_opaque="false"
|
||||
name="VignettePanel" width="398">
|
||||
<check_box follows="left|top"
|
||||
font="SansSerifSmall" height="16" initial_value="false" label="Enable"
|
||||
left="4" mouse_opaque="true" name="enable_vignette" width="200" />
|
||||
<text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
|
||||
bottom_delta="-21" drop_shadow_visible="true" follows="left|top|right"
|
||||
font="SansSerif" h_pad="0" halign="left" height="16"
|
||||
left="10" mouse_opaque="true" name="VignetteStrengthText" v_pad="0"
|
||||
width="355">
|
||||
Strength
|
||||
</text>
|
||||
<slider bottom_delta="-35" can_edit_text="true"
|
||||
decimal_digits="3" follows="left"
|
||||
height="18" increment=".005" initial_val=".85" label="" left="14"
|
||||
max_val="1" min_val="0" mouse_opaque="true"
|
||||
name="vignette_strength" show_text="true" value="0" width="200" />
|
||||
<text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
|
||||
bottom_delta="-21" drop_shadow_visible="true" follows="left|top|right"
|
||||
font="SansSerif" h_pad="0" halign="left" height="16"
|
||||
left="10" mouse_opaque="true" name="VignetteRadiusText" v_pad="0"
|
||||
width="355">
|
||||
Radius
|
||||
</text>
|
||||
<slider bottom_delta="-35" can_edit_text="true"
|
||||
decimal_digits="3" follows="left"
|
||||
height="18" increment=".01" initial_val=".7" label="" left="14"
|
||||
max_val="8" min_val=".1" mouse_opaque="true"
|
||||
name="vignette_radius" show_text="true" value="0" width="200" />
|
||||
<text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
|
||||
bottom_delta="-21" drop_shadow_visible="true" follows="left|top|right"
|
||||
font="SansSerif" h_pad="0" halign="left" height="16"
|
||||
left="10" mouse_opaque="true" name="VignetteDarknessText" v_pad="0"
|
||||
width="355">
|
||||
Darkness
|
||||
</text>
|
||||
<slider bottom_delta="-35" can_edit_text="true"
|
||||
decimal_digits="3" follows="left"
|
||||
height="18" increment=".005" initial_val=".85" label="" left="14"
|
||||
max_val="1" min_val="0" mouse_opaque="true"
|
||||
name="vignette_darkness" show_text="true" value="0" width="200" />
|
||||
<text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
|
||||
bottom_delta="-21" drop_shadow_visible="true" follows="left|top|right"
|
||||
font="SansSerif" h_pad="0" halign="left" height="16"
|
||||
left="10" mouse_opaque="true" name="VignetteDesaturateText" v_pad="0"
|
||||
width="355">
|
||||
Desaturation Strength
|
||||
</text>
|
||||
<slider bottom_delta="-35" can_edit_text="true"
|
||||
decimal_digits="3" follows="left"
|
||||
height="18" increment=".05" initial_val="1" label="" left="14"
|
||||
max_val="10" min_val="0" mouse_opaque="true"
|
||||
name="vignette_desaturation" show_text="true" value="0" width="200" />
|
||||
<text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
|
||||
bottom_delta="-21" drop_shadow_visible="true" follows="left|top|right"
|
||||
font="SansSerif" h_pad="0" halign="left" height="16"
|
||||
left="10" mouse_opaque="true" name="VignetteChormaticAberrationText" v_pad="0"
|
||||
width="355">
|
||||
Chromatic Aberration
|
||||
</text>
|
||||
<slider bottom_delta="-35" can_edit_text="true"
|
||||
decimal_digits="3" follows="left"
|
||||
height="18" increment="0.0005" initial_val=".01" label="" left="14"
|
||||
max_val=".1" min_val="0" mouse_opaque="true"
|
||||
name="vignette_chromatic_aberration" show_text="true" value="0" width="200" />
|
||||
</panel>
|
||||
<!--<panel border="true" bottom="-180" follows="left|top|right|bottom" height="400"
|
||||
label="Bloom" left="1" mouse_opaque="true"
|
||||
name="BloomPanel" width="398">
|
||||
|
||||
Reference in New Issue
Block a user