SL-19203 et al -- Integrate SSR with reflection probes, tweak probe blending. (#63)

* SL-19203 WIP -- Integrate SSR with reflection probes.  Decruft LLRenderTarget.

* SL-19203 WIP -- Re-integrate SSR.  Incidental decruft.

* SL-19203 WIP -- SSR frame delta correction (still broken for Z)

* SL-19203 WIP -- SSR frame delta Z fix

* SL-19203 WIP -- Make SSR toggleable again and disable SSR in cube snapshots.

* SL-19203 WIP -- Soften sphere probe transitions and fix reflections on void water (make fallback probe a simple terrain+water+sky probe).  Remove parallax correction for automatic probes to reduce artifacts.

* SL-19203 Tune probe blending.

* SL-19203 Cleanup.
master
RunitaiLinden 2023-01-27 17:24:22 -06:00 committed by GitHub
parent 503e18fc64
commit 3ef31cb9b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 755 additions and 760 deletions

View File

@ -2270,7 +2270,7 @@ void do_assert_glerror()
GLenum error;
error = glGetError();
BOOL quit = FALSE;
while (LL_UNLIKELY(error))
if (LL_UNLIKELY(error))
{
quit = TRUE;
GLubyte const * gl_error_msg = gluErrorString(error);
@ -2295,7 +2295,6 @@ void do_assert_glerror()
gFailLog << "GL Error: UNKNOWN 0x" << std::hex << error << std::dec << std::endl;
}
}
error = glGetError();
}
if (quit)

View File

@ -55,8 +55,14 @@ F32 gGLModelView[16];
F32 gGLLastModelView[16];
F32 gGLLastProjection[16];
F32 gGLProjection[16];
// transform from last frame's camera space to this frame's camera space (and inverse)
F32 gGLDeltaModelView[16];
F32 gGLInverseDeltaModelView[16];
S32 gGLViewport[4];
U32 LLRender::sUICalls = 0;
U32 LLRender::sUIVerts = 0;
U32 LLTexUnit::sWhiteTexture = 0;
@ -373,7 +379,6 @@ bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth)
if (bindDepth)
{
llassert(renderTarget->getDepth()); // target MUST have a depth buffer attachment
llassert(renderTarget->canSampleDepth()); // depth buffer attachment MUST be sampleable
bindManual(renderTarget->getUsage(), renderTarget->getDepth());
}

View File

@ -507,6 +507,8 @@ extern F32 gGLLastModelView[16];
extern F32 gGLLastProjection[16];
extern F32 gGLProjection[16];
extern S32 gGLViewport[4];
extern F32 gGLDeltaModelView[16];
extern F32 gGLInverseDeltaModelView[16];
extern thread_local LLRender gGL;

View File

@ -35,19 +35,19 @@ U32 LLRenderTarget::sBytesAllocated = 0;
void check_framebuffer_status()
{
if (gDebugGL)
{
GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
switch (status)
{
case GL_FRAMEBUFFER_COMPLETE:
break;
default:
LL_WARNS() << "check_framebuffer_status failed -- " << std::hex << status << LL_ENDL;
ll_fail("check_framebuffer_status failed");
break;
}
}
if (gDebugGL)
{
GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
switch (status)
{
case GL_FRAMEBUFFER_COMPLETE:
break;
default:
LL_WARNS() << "check_framebuffer_status failed -- " << std::hex << status << LL_ENDL;
ll_fail("check_framebuffer_status failed");
break;
}
}
}
bool LLRenderTarget::sUseFBO = false;
@ -60,112 +60,86 @@ U32 LLRenderTarget::sCurResX = 0;
U32 LLRenderTarget::sCurResY = 0;
LLRenderTarget::LLRenderTarget() :
mResX(0),
mResY(0),
mFBO(0),
mPreviousFBO(0),
mPreviousResX(0),
mPreviousResY(0),
mDepth(0),
mUseDepth(false),
mSampleDepth(false),
mUsage(LLTexUnit::TT_TEXTURE)
mResX(0),
mResY(0),
mFBO(0),
mDepth(0),
mUseDepth(false),
mUsage(LLTexUnit::TT_TEXTURE)
{
}
LLRenderTarget::~LLRenderTarget()
{
release();
release();
}
void LLRenderTarget::resize(U32 resx, U32 resy)
{
//for accounting, get the number of pixels added/subtracted
S32 pix_diff = (resx*resy)-(mResX*mResY);
mResX = resx;
mResY = resy;
//for accounting, get the number of pixels added/subtracted
S32 pix_diff = (resx*resy)-(mResX*mResY);
mResX = resx;
mResY = resy;
llassert(mInternalFormat.size() == mTex.size());
llassert(mInternalFormat.size() == mTex.size());
for (U32 i = 0; i < mTex.size(); ++i)
{ //resize color attachments
gGL.getTexUnit(0)->bindManual(mUsage, mTex[i]);
LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, mInternalFormat[i], mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false);
sBytesAllocated += pix_diff*4;
}
for (U32 i = 0; i < mTex.size(); ++i)
{ //resize color attachments
gGL.getTexUnit(0)->bindManual(mUsage, mTex[i]);
LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, mInternalFormat[i], mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false);
sBytesAllocated += pix_diff*4;
}
if (mDepth)
{ //resize depth attachment
if (!mSampleDepth)
{
//use render buffers where stencil buffers are in play
glBindRenderbuffer(GL_RENDERBUFFER, mDepth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mResX, mResY);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
else
{
gGL.getTexUnit(0)->bindManual(mUsage, mDepth);
U32 internal_type = LLTexUnit::getInternalType(mUsage);
LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false);
}
if (mDepth)
{
gGL.getTexUnit(0)->bindManual(mUsage, mDepth);
U32 internal_type = LLTexUnit::getInternalType(mUsage);
LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false);
sBytesAllocated += pix_diff*4;
}
sBytesAllocated += pix_diff*4;
}
}
bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool sample_depth, LLTexUnit::eTextureType usage, bool use_fbo, S32 samples)
bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, LLTexUnit::eTextureType usage)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
resx = llmin(resx, (U32) gGLManager.mGLMaxTextureSize);
resy = llmin(resy, (U32) gGLManager.mGLMaxTextureSize);
llassert(usage == LLTexUnit::TT_TEXTURE);
llassert(!isBoundInStack());
stop_glerror();
release();
stop_glerror();
resx = llmin(resx, (U32) gGLManager.mGLMaxTextureSize);
resy = llmin(resy, (U32) gGLManager.mGLMaxTextureSize);
mResX = resx;
mResY = resy;
release();
mResX = resx;
mResY = resy;
mUsage = usage;
mUsage = usage;
mUseDepth = depth;
mSampleDepth = sample_depth;
if (depth)
{
if (!allocateDepth())
{
LL_WARNS() << "Failed to allocate depth buffer for render target." << LL_ENDL;
return false;
}
}
if ((sUseFBO || use_fbo))
{
if (depth)
{
if (!allocateDepth())
{
LL_WARNS() << "Failed to allocate depth buffer for render target." << LL_ENDL;
return false;
}
}
glGenFramebuffers(1, (GLuint *) &mFBO);
glGenFramebuffers(1, (GLuint *) &mFBO);
if (mDepth)
{
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
if (mDepth)
{
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
if (!canSampleDepth())
{
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepth);
}
else
{
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
stop_glerror();
}
glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
}
stop_glerror();
}
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
return addColorAttachment(color_fmt);
glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
}
return addColorAttachment(color_fmt);
}
void LLRenderTarget::setColorAttachment(LLImageGL* img, LLGLuint use_name)
@ -175,6 +149,7 @@ void LLRenderTarget::setColorAttachment(LLImageGL* img, LLGLuint use_name)
llassert(sUseFBO); // FBO support must be enabled
llassert(mDepth == 0); // depth buffers not supported with this mode
llassert(mTex.empty()); // mTex must be empty with this mode (binding target should be done via LLImageGL)
llassert(!isBoundInStack());
if (mFBO == 0)
{
@ -205,6 +180,7 @@ void LLRenderTarget::setColorAttachment(LLImageGL* img, LLGLuint use_name)
void LLRenderTarget::releaseColorAttachment()
{
LL_PROFILE_ZONE_SCOPED;
llassert(!isBoundInStack());
llassert(mTex.size() == 1); //cannot use releaseColorAttachment with LLRenderTarget managed color targets
llassert(mFBO != 0); // mFBO must be valid
@ -218,323 +194,291 @@ void LLRenderTarget::releaseColorAttachment()
bool LLRenderTarget::addColorAttachment(U32 color_fmt)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
if (color_fmt == 0)
{
return true;
}
llassert(!isBoundInStack());
U32 offset = mTex.size();
if (color_fmt == 0)
{
return true;
}
if( offset >= 4 )
{
LL_WARNS() << "Too many color attachments" << LL_ENDL;
llassert( offset < 4 );
return false;
}
if( offset > 0 && (mFBO == 0) )
{
llassert( mFBO != 0 );
return false;
}
U32 offset = mTex.size();
U32 tex;
LLImageGL::generateTextures(1, &tex);
gGL.getTexUnit(0)->bindManual(mUsage, tex);
if( offset >= 4 )
{
LL_WARNS() << "Too many color attachments" << LL_ENDL;
llassert( offset < 4 );
return false;
}
if( offset > 0 && (mFBO == 0) )
{
llassert( mFBO != 0 );
return false;
}
stop_glerror();
U32 tex;
LLImageGL::generateTextures(1, &tex);
gGL.getTexUnit(0)->bindManual(mUsage, tex);
stop_glerror();
{
clear_glerror();
LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false);
if (glGetError() != GL_NO_ERROR)
{
LL_WARNS() << "Could not allocate color buffer for render target." << LL_ENDL;
return false;
}
}
sBytesAllocated += mResX*mResY*4;
{
clear_glerror();
LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false);
if (glGetError() != GL_NO_ERROR)
{
LL_WARNS() << "Could not allocate color buffer for render target." << LL_ENDL;
return false;
}
}
sBytesAllocated += mResX*mResY*4;
stop_glerror();
stop_glerror();
if (offset == 0)
{ //use bilinear filtering on single texture render targets that aren't multisampled
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
stop_glerror();
}
else
{ //don't filter data attachments
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
stop_glerror();
}
if (offset == 0)
{ //use bilinear filtering on single texture render targets that aren't multisampled
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
stop_glerror();
}
else
{ //don't filter data attachments
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
stop_glerror();
}
if (mUsage != LLTexUnit::TT_RECT_TEXTURE)
{
gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_MIRROR);
stop_glerror();
}
else
{
// ATI doesn't support mirrored repeat for rectangular textures.
gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
stop_glerror();
}
if (mFBO)
{
stop_glerror();
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+offset,
LLTexUnit::getInternalType(mUsage), tex, 0);
stop_glerror();
if (mUsage != LLTexUnit::TT_RECT_TEXTURE)
{
gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_MIRROR);
stop_glerror();
}
else
{
// ATI doesn't support mirrored repeat for rectangular textures.
gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
stop_glerror();
}
if (mFBO)
{
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+offset,
LLTexUnit::getInternalType(mUsage), tex, 0);
check_framebuffer_status();
glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
}
check_framebuffer_status();
glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
}
mTex.push_back(tex);
mInternalFormat.push_back(color_fmt);
mTex.push_back(tex);
mInternalFormat.push_back(color_fmt);
if (gDebugGL)
{ //bind and unbind to validate target
bindTarget();
flush();
}
if (gDebugGL)
{ //bind and unbind to validate target
bindTarget();
flush();
}
return true;
return true;
}
bool LLRenderTarget::allocateDepth()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
if (!mSampleDepth)
{
//use render buffers if depth buffer won't be sampled
glGenRenderbuffers(1, (GLuint *) &mDepth);
glBindRenderbuffer(GL_RENDERBUFFER, mDepth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mResX, mResY);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
else
{
LLImageGL::generateTextures(1, &mDepth);
gGL.getTexUnit(0)->bindManual(mUsage, mDepth);
U32 internal_type = LLTexUnit::getInternalType(mUsage);
stop_glerror();
clear_glerror();
LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false);
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
}
LLImageGL::generateTextures(1, &mDepth);
gGL.getTexUnit(0)->bindManual(mUsage, mDepth);
U32 internal_type = LLTexUnit::getInternalType(mUsage);
stop_glerror();
clear_glerror();
LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false);
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
sBytesAllocated += mResX*mResY*4;
sBytesAllocated += mResX*mResY*4;
if (glGetError() != GL_NO_ERROR)
{
LL_WARNS() << "Unable to allocate depth buffer for render target." << LL_ENDL;
return false;
}
if (glGetError() != GL_NO_ERROR)
{
LL_WARNS() << "Unable to allocate depth buffer for render target." << LL_ENDL;
return false;
}
return true;
return true;
}
void LLRenderTarget::shareDepthBuffer(LLRenderTarget& target)
{
if (!mFBO || !target.mFBO)
{
LL_ERRS() << "Cannot share depth buffer between non FBO render targets." << LL_ENDL;
}
llassert(!isBoundInStack());
if (target.mDepth)
{
LL_ERRS() << "Attempting to override existing depth buffer. Detach existing buffer first." << LL_ENDL;
}
if (!mFBO || !target.mFBO)
{
LL_ERRS() << "Cannot share depth buffer between non FBO render targets." << LL_ENDL;
}
if (target.mUseDepth)
{
LL_ERRS() << "Attempting to override existing shared depth buffer. Detach existing buffer first." << LL_ENDL;
}
if (target.mDepth)
{
LL_ERRS() << "Attempting to override existing depth buffer. Detach existing buffer first." << LL_ENDL;
}
if (mDepth)
{
glBindFramebuffer(GL_FRAMEBUFFER, target.mFBO);
if (!mSampleDepth)
{
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepth);
}
else
{
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
}
if (target.mUseDepth)
{
LL_ERRS() << "Attempting to override existing shared depth buffer. Detach existing buffer first." << LL_ENDL;
}
check_framebuffer_status();
if (mDepth)
{
glBindFramebuffer(GL_FRAMEBUFFER, target.mFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
check_framebuffer_status();
target.mUseDepth = true;
}
glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
target.mUseDepth = true;
}
}
void LLRenderTarget::release()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
if (mDepth)
{
if (!mSampleDepth)
{
glDeleteRenderbuffers(1, (GLuint*) &mDepth);
}
else
{
LLImageGL::deleteTextures(1, &mDepth);
}
mDepth = 0;
llassert(!isBoundInStack());
sBytesAllocated -= mResX*mResY*4;
}
else if (mFBO)
{
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
if (mDepth)
{
LLImageGL::deleteTextures(1, &mDepth);
mDepth = 0;
if (mUseDepth)
{ //detach shared depth buffer
if (!mSampleDepth)
{ //attached as a renderbuffer
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
mSampleDepth = false;
}
else
{ //attached as a texture
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0);
}
mUseDepth = false;
}
}
sBytesAllocated -= mResX*mResY*4;
}
else if (mFBO)
{
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
// Detach any extra color buffers (e.g. SRGB spec buffers)
//
if (mFBO && (mTex.size() > 1))
{
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
S32 z;
for (z = mTex.size() - 1; z >= 1; z--)
{
sBytesAllocated -= mResX*mResY*4;
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+z, LLTexUnit::getInternalType(mUsage), 0, 0);
stop_glerror();
LLImageGL::deleteTextures(1, &mTex[z]);
}
}
if (mUseDepth)
{ //detach shared depth buffer
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0);
mUseDepth = false;
}
if (mFBO)
{
glDeleteFramebuffers(1, (GLuint *) &mFBO);
stop_glerror();
mFBO = 0;
}
glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
}
if (mTex.size() > 0)
{
sBytesAllocated -= mResX*mResY*4;
LLImageGL::deleteTextures(1, &mTex[0]);
}
// Detach any extra color buffers (e.g. SRGB spec buffers)
//
if (mFBO && (mTex.size() > 1))
{
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
S32 z;
for (z = mTex.size() - 1; z >= 1; z--)
{
sBytesAllocated -= mResX*mResY*4;
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+z, LLTexUnit::getInternalType(mUsage), 0, 0);
LLImageGL::deleteTextures(1, &mTex[z]);
}
glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
}
mTex.clear();
mInternalFormat.clear();
mResX = mResY = 0;
if (mFBO == sCurFBO)
{
sCurFBO = 0;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
sBoundTarget = NULL;
if (mFBO)
{
glDeleteFramebuffers(1, (GLuint *) &mFBO);
mFBO = 0;
}
if (mTex.size() > 0)
{
sBytesAllocated -= mResX*mResY*4;
LLImageGL::deleteTextures(1, &mTex[0]);
}
mTex.clear();
mInternalFormat.clear();
mResX = mResY = 0;
}
void LLRenderTarget::bindTarget()
{
LL_PROFILE_GPU_ZONE("bindTarget");
llassert(mFBO);
llassert(!isBoundInStack());
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
sCurFBO = mFBO;
if (mFBO)
{
stop_glerror();
mPreviousFBO = sCurFBO;
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
sCurFBO = mFBO;
stop_glerror();
//setup multiple render targets
GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0,
GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2,
GL_COLOR_ATTACHMENT3};
glDrawBuffers(mTex.size(), drawbuffers);
if (mTex.empty())
{ //no color buffer to draw to
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
}
//setup multiple render targets
GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0,
GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2,
GL_COLOR_ATTACHMENT3};
glDrawBuffers(mTex.size(), drawbuffers);
if (mTex.empty())
{ //no color buffer to draw to
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
}
check_framebuffer_status();
check_framebuffer_status();
stop_glerror();
}
glViewport(0, 0, mResX, mResY);
sCurResX = mResX;
sCurResY = mResY;
mPreviousResX = sCurResX;
mPreviousResY = sCurResY;
glViewport(0, 0, mResX, mResY);
sCurResX = mResX;
sCurResY = mResY;
sBoundTarget = this;
mPreviousRT = sBoundTarget;
sBoundTarget = this;
}
void LLRenderTarget::clear(U32 mask_in)
{
LL_PROFILE_GPU_ZONE("clear");
llassert(mFBO);
U32 mask = GL_COLOR_BUFFER_BIT;
if (mUseDepth)
{
mask |= GL_DEPTH_BUFFER_BIT; // stencil buffer is deprecated, performance pnealty | GL_STENCIL_BUFFER_BIT;
U32 mask = GL_COLOR_BUFFER_BIT;
if (mUseDepth)
{
mask |= GL_DEPTH_BUFFER_BIT;
}
if (mFBO)
{
check_framebuffer_status();
stop_glerror();
glClear(mask & mask_in);
stop_glerror();
}
else
{
LLGLEnable scissor(GL_SCISSOR_TEST);
glScissor(0, 0, mResX, mResY);
stop_glerror();
glClear(mask & mask_in);
}
}
if (mFBO)
{
check_framebuffer_status();
stop_glerror();
glClear(mask & mask_in);
stop_glerror();
}
else
{
LLGLEnable scissor(GL_SCISSOR_TEST);
glScissor(0, 0, mResX, mResY);
stop_glerror();
glClear(mask & mask_in);
}
}
U32 LLRenderTarget::getTexture(U32 attachment) const
{
if (attachment > mTex.size()-1)
{
LL_ERRS() << "Invalid attachment index." << LL_ENDL;
}
if (mTex.empty())
{
return 0;
}
return mTex[attachment];
if (attachment > mTex.size()-1)
{
LL_ERRS() << "Invalid attachment index." << LL_ENDL;
}
if (mTex.empty())
{
return 0;
}
return mTex[attachment];
}
U32 LLRenderTarget::getNumTextures() const
{
return mTex.size();
return mTex.size();
}
void LLRenderTarget::bindTexture(U32 index, S32 channel, LLTexUnit::eTextureFilterOptions filter_options)
@ -560,64 +504,54 @@ void LLRenderTarget::bindTexture(U32 index, S32 channel, LLTexUnit::eTextureFilt
gGL.getTexUnit(channel)->setTextureColorSpace(isSRGB ? LLTexUnit::TCS_SRGB : LLTexUnit::TCS_LINEAR);
}
void LLRenderTarget::flush(bool fetch_depth)
void LLRenderTarget::flush()
{
LL_PROFILE_GPU_ZONE("rt flush");
gGL.flush();
gGL.flush();
llassert(mFBO);
if (!mFBO)
{
gGL.getTexUnit(0)->bind(this);
glCopyTexSubImage2D(LLTexUnit::getInternalType(mUsage), 0, 0, 0, 0, 0, mResX, mResY);
llassert(sCurFBO == mFBO);
llassert(sBoundTarget == this);
if (fetch_depth)
{
if (!mDepth)
{
allocateDepth();
}
gGL.getTexUnit(0)->bind(this);
glCopyTexImage2D(LLTexUnit::getInternalType(mUsage), 0, GL_DEPTH24_STENCIL8, 0, 0, mResX, mResY, 0);
}
gGL.getTexUnit(0)->disable();
}
else
{
stop_glerror();
glBindFramebuffer(GL_FRAMEBUFFER, mPreviousFBO);
sCurFBO = mPreviousFBO;
if (mPreviousFBO)
{
glViewport(0, 0, mPreviousResX, mPreviousResY);
sCurResX = mPreviousResX;
sCurResY = mPreviousResY;
}
else
{
glViewport(gGLViewport[0],gGLViewport[1],gGLViewport[2],gGLViewport[3]);
sCurResX = gGLViewport[2];
sCurResY = gGLViewport[3];
}
stop_glerror();
}
if (mPreviousRT)
{
// a bit hacky -- pop the RT stack back two frames and push
// the previous frame back on to play nice with the GL state machine
sBoundTarget = mPreviousRT->mPreviousRT;
mPreviousRT->bindTarget();
}
else
{
sBoundTarget = nullptr;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
sCurFBO = 0;
glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
sCurResX = gGLViewport[2];
sCurResY = gGLViewport[3];
}
}
bool LLRenderTarget::isComplete() const
{
return (!mTex.empty() || mDepth) ? true : false;
return (!mTex.empty() || mDepth) ? true : false;
}
void LLRenderTarget::getViewport(S32* viewport)
{
viewport[0] = 0;
viewport[1] = 0;
viewport[2] = mResX;
viewport[3] = mResY;
viewport[0] = 0;
viewport[1] = 0;
viewport[2] = mResX;
viewport[3] = mResY;
}
bool LLRenderTarget::isBoundInStack() const
{
LLRenderTarget* cur = sBoundTarget;
while (cur && cur != this)
{
cur = cur->mPreviousRT;
}
return cur == this;
}

View File

@ -33,6 +33,8 @@
#include "llrender.h"
/*
Wrapper around OpenGL framebuffer objects for use in render-to-texture
SAMPLE USAGE:
LLRenderTarget target;
@ -73,7 +75,12 @@ public:
//allocate resources for rendering
//must be called before use
//multiple calls will release previously allocated resources
bool allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool sample_depth, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE, bool use_fbo = false, S32 samples = 0);
// resX - width
// resY - height
// color_fmt - GL color format (e.g. GL_RGB)
// depth - if true, allocate a depth buffer
// usage - deprecated, should always be TT_TEXTURE
bool allocate(U32 resx, U32 resy, U32 color_fmt, bool depth = false, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE);
//resize existing attachments to use new resolution and color format
// CAUTION: if the GL runs out of memory attempting to resize, this render target will be undefined
@ -93,7 +100,7 @@ public:
// attachment -- LLImageGL to render into
// use_name -- optional texture name to target instead of attachment->getTexName()
// NOTE: setColorAttachment and releaseColorAttachment cannot be used in conjuction with
// addColorAttachment, allocateDepth, resize, etc.
// addColorAttachment, allocateDepth, resize, etc.
void setColorAttachment(LLImageGL* attachment, LLGLuint use_name = 0);
// detach from current color attachment
@ -111,14 +118,19 @@ public:
//free any allocated resources
//safe to call redundantly
// asserts that this target is not currently bound or present in the RT stack
void release();
//bind target for rendering
//applies appropriate viewport
// If an LLRenderTarget is currently bound, stores a reference to that LLRenderTarget
// and restores previous binding on flush() (maintains a stack of Render Targets)
// Asserts that this target is not currently bound in the stack
void bindTarget();
//clear render targer, clears depth buffer if present,
//uses scissor rect if in copy-to-texture mode
// asserts that this target is currently bound
void clear(U32 mask = 0xFFFFFFFF);
//get applied viewport
@ -136,7 +148,6 @@ public:
U32 getNumTextures() const;
U32 getDepth(void) const { return mDepth; }
bool canSampleDepth() const { return mSampleDepth; }
void bindTexture(U32 index, S32 channel, LLTexUnit::eTextureFilterOptions filter_options = LLTexUnit::TFO_BILINEAR);
@ -144,15 +155,18 @@ public:
//must be called when rendering is complete
//should be used 1:1 with bindTarget
// call bindTarget once, do all your rendering, call flush once
// if fetch_depth is TRUE, every effort will be made to copy the depth buffer into
// the current depth texture. A depth texture will be allocated if needed.
void flush(bool fetch_depth = FALSE);
// If an LLRenderTarget was bound when bindTarget was called, binds that RenderTarget for rendering (maintains RT stack)
// asserts that this target is currently bound
void flush();
//Returns TRUE if target is ready to be rendered into.
//That is, if the target has been allocated with at least
//one renderable attachment (i.e. color buffer, depth buffer).
bool isComplete() const;
// Returns true if this RenderTarget is bound somewhere in the stack
bool isBoundInStack() const;
static LLRenderTarget* getCurrentBoundTarget() { return sBoundTarget; }
protected:
@ -161,13 +175,10 @@ protected:
std::vector<U32> mTex;
std::vector<U32> mInternalFormat;
U32 mFBO;
U32 mPreviousFBO;
U32 mPreviousResX;
U32 mPreviousResY;
LLRenderTarget* mPreviousRT = nullptr;
U32 mDepth;
U32 mDepth;
bool mUseDepth;
bool mSampleDepth;
LLTexUnit::eTextureType mUsage;

View File

@ -222,7 +222,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
}
}
if (features->hasScreenSpaceReflections)
if (features->hasScreenSpaceReflections || features->hasReflectionProbes)
{
if (!shader->attachFragmentObject("deferred/screenSpaceReflUtil.glsl"))
{
@ -1244,6 +1244,8 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("bumpMap");
mReservedUniforms.push_back("bumpMap2");
mReservedUniforms.push_back("environmentMap");
mReservedUniforms.push_back("sceneMap");
mReservedUniforms.push_back("sceneDepth");
mReservedUniforms.push_back("reflectionProbes");
mReservedUniforms.push_back("irradianceProbes");
mReservedUniforms.push_back("cloud_noise_texture");
@ -1323,6 +1325,10 @@ void LLShaderMgr::initAttribsAndUniforms()
llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH+1);
mReservedUniforms.push_back("modelview_delta");
mReservedUniforms.push_back("inv_modelview_delta");
mReservedUniforms.push_back("cube_snapshot");
mReservedUniforms.push_back("tc_scale");
mReservedUniforms.push_back("rcp_screen_res");
mReservedUniforms.push_back("rcp_frame_opt");

View File

@ -90,6 +90,8 @@ public:
BUMP_MAP, // "bumpMap"
BUMP_MAP2, // "bumpMap2"
ENVIRONMENT_MAP, // "environmentMap"
SCENE_MAP, // "sceneMap"
SCENE_DEPTH, // "sceneDepth"
REFLECTION_PROBES, // "reflectionProbes"
IRRADIANCE_PROBES, // "irradianceProbes"
CLOUD_NOISE_MAP, // "cloud_noise_texture"
@ -158,6 +160,10 @@ public:
DEFERRED_NORM_CUTOFF, // "norm_cutoff"
DEFERRED_SHADOW_TARGET_WIDTH, // "shadow_target_width"
MODELVIEW_DELTA_MATRIX, // "modelview_delta"
INVERSE_MODELVIEW_DELTA_MATRIX, // "inv_modelview_delta"
CUBE_SNAPSHOT, // "cube_snapshot"
FXAA_TC_SCALE, // "tc_scale"
FXAA_RCP_SCREEN_RES, // "rcp_screen_res"
FXAA_RCP_FRAME_OPT, // "rcp_frame_opt"

View File

@ -744,7 +744,7 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
{
drawRange(mode, 0, mNumVerts, count, indices_offset);
drawRange(mode, 0, mNumVerts-1, count, indices_offset);
}

View File

@ -25,14 +25,14 @@
// fallback stub -- will be used if actual reflection probe shader failed to load (output pink so it's obvious)
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
vec3 pos, vec3 norm, float glossiness, bool errorCorrect)
vec2 tc, vec3 pos, vec3 norm, float glossiness, bool errorCorrect)
{
ambenv = vec3(1,0,1);
glossenv = vec3(1,0,1);
}
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
vec3 pos, vec3 norm, float glossiness)
vec2 tc, vec3 pos, vec3 norm, float glossiness)
{
sampleReflectionProbes(ambenv, glossenv,
pos, norm, glossiness, false);

View File

@ -23,35 +23,11 @@
* $/LicenseInfo$
*/
#extension GL_ARB_texture_rectangle : enable
// debug stub
/*[EXTRA_CODE_HERE]*/
#ifdef DEFINE_GL_FRAGCOLOR
out vec4 frag_color;
#else
#define frag_color gl_FragColor
#endif
uniform vec2 screen_res;
uniform mat4 projection_matrix;
uniform mat4 inv_proj;
uniform float zNear;
uniform float zFar;
VARYING vec2 vary_fragcoord;
uniform sampler2D depthMap;
uniform sampler2D normalMap;
uniform sampler2D sceneMap;
uniform sampler2D diffuseRect;
vec3 getNorm(vec2 screenpos);
float getDepth(vec2 pos_screen);
float linearDepth(float d, float znear, float zfar);
void main() {
vec2 tc = vary_fragcoord.xy;
vec4 pos = getPositionWithDepth(tc, getDepth(tc));
frag_color = pos;
void main()
{
frag_color = vec4(0.5, 0.4, 0.1, 0);
}

View File

@ -23,98 +23,15 @@
* $/LicenseInfo$
*/
uniform sampler2D depthMap;
uniform sampler2D normalMap;
uniform sampler2D sceneMap;
uniform vec2 screen_res;
uniform mat4 projection_matrix;
// debug stub
// Shamelessly taken from http://casual-effects.blogspot.com/2014/08/screen-space-ray-tracing.html
// Original paper: https://jcgt.org/published/0003/04/04/
// By Morgan McGuire and Michael Mara at Williams College 2014
// Released as open source under the BSD 2-Clause License
// http://opensource.org/licenses/BSD-2-Clause
float distanceSquared(vec2 a, vec2 b) { a -= b; return dot(a, a); }
bool traceScreenSpaceRay1(vec3 csOrig, vec3 csDir, mat4 proj, float zThickness,
float nearPlaneZ, float stride, float jitter, const float maxSteps, float maxDistance,
out vec2 hitPixel, out vec3 hitPoint)
float random (vec2 uv)
{
// Clip to the near plane
float rayLength = ((csOrig.z + csDir.z * maxDistance) > nearPlaneZ) ?
(nearPlaneZ - csOrig.z) / csDir.z : maxDistance;
vec3 csEndPoint = csOrig + csDir * rayLength;
// Project into homogeneous clip space
vec4 H0 = proj * vec4(csOrig, 1.0);
vec4 H1 = proj * vec4(csEndPoint, 1.0);
float k0 = 1.0 / H0.w, k1 = 1.0 / H1.w;
// The interpolated homogeneous version of the camera-space points
vec3 Q0 = csOrig * k0, Q1 = csEndPoint * k1;
// Screen-space endpoints
vec2 P0 = H0.xy * k0, P1 = H1.xy * k1;
// If the line is degenerate, make it cover at least one pixel
// to avoid handling zero-pixel extent as a special case later
P1 += vec2((distanceSquared(P0, P1) < 0.0001) ? 0.01 : 0.0);
vec2 delta = P1 - P0;
// Permute so that the primary iteration is in x to collapse
// all quadrant-specific DDA cases later
bool permute = false;
if (abs(delta.x) < abs(delta.y)) {
// This is a more-vertical line
permute = true; delta = delta.yx; P0 = P0.yx; P1 = P1.yx;
}
float stepDir = sign(delta.x);
float invdx = stepDir / delta.x;
// Track the derivatives of Q and k
vec3 dQ = (Q1 - Q0) * invdx;
float dk = (k1 - k0) * invdx;
vec2 dP = vec2(stepDir, delta.y * invdx);
// Scale derivatives by the desired pixel stride and then
// offset the starting values by the jitter fraction
dP *= stride; dQ *= stride; dk *= stride;
P0 += dP * jitter; Q0 += dQ * jitter; k0 += dk * jitter;
// Slide P from P0 to P1, (now-homogeneous) Q from Q0 to Q1, k from k0 to k1
vec3 Q = Q0;
// Adjust end condition for iteration direction
float end = P1.x * stepDir;
float k = k0, stepCount = 0.0, prevZMaxEstimate = csOrig.z;
float rayZMin = prevZMaxEstimate, rayZMax = prevZMaxEstimate;
float sceneZMax = rayZMax + 100;
for (vec2 P = P0;
((P.x * stepDir) <= end) && (stepCount < maxSteps) &&
((rayZMax < sceneZMax - zThickness) || (rayZMin > sceneZMax)) &&
(sceneZMax != 0);
P += dP, Q.z += dQ.z, k += dk, ++stepCount) {
rayZMin = prevZMaxEstimate;
rayZMax = (dQ.z * 0.5 + Q.z) / (dk * 0.5 + k);
prevZMaxEstimate = rayZMax;
if (rayZMin > rayZMax) {
float t = rayZMin; rayZMin = rayZMax; rayZMax = t;
}
hitPixel = permute ? P.yx : P;
hitPixel.y = screen_res.y - hitPixel.y;
// You may need hitPixel.y = screen_res.y - hitPixel.y; here if your vertical axis
// is different than ours in screen space
sceneZMax = texelFetch(depthMap, ivec2(hitPixel)).r;
}
// Advance Q based on the number of steps
Q.xy += dQ.xy * stepCount;
hitPoint = Q * (1.0 / k);
return (rayZMax >= sceneZMax - zThickness) && (rayZMin < sceneZMax);
return 0;
}
float tapScreenSpaceReflection(int totalSamples, vec2 tc, vec3 viewPos, vec3 n, inout vec4 collectedColor, sampler2D source)
{
collectedColor = vec4(0);
return 0;
}

View File

@ -90,8 +90,8 @@ float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen);
float getAmbientClamp();
void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
vec3 pos, vec3 norm, float glossiness, float envIntensity);
void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity);
vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 diffuse, vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight, float ambiance)
{
@ -253,7 +253,7 @@ void main()
vec3 irradiance;
vec3 glossenv;
vec3 legacyenv;
sampleReflectionProbesLegacy(irradiance, glossenv, legacyenv, pos.xyz, norm.xyz, 0.0, 0.0);
sampleReflectionProbesLegacy(irradiance, glossenv, legacyenv, frag, pos.xyz, norm.xyz, 0.0, 0.0);
float da = dot(norm.xyz, light_dir.xyz);

View File

@ -84,7 +84,7 @@ void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float
float calcLegacyDistanceAttenuation(float distance, float falloff);
float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen);
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
vec3 pos, vec3 norm, float glossiness);
vec2 tc, vec3 pos, vec3 norm, float glossiness);
void waterClip(vec3 pos);
@ -207,7 +207,7 @@ void main()
float gloss = 1.0 - perceptualRoughness;
vec3 irradiance = vec3(0);
vec3 radiance = vec3(0);
sampleReflectionProbes(irradiance, radiance, pos.xyz, norm.xyz, gloss);
sampleReflectionProbes(irradiance, radiance, vec2(0), pos.xyz, norm.xyz, gloss);
// Take maximium of legacy ambient vs irradiance sample as irradiance
// NOTE: ao is applied in pbrIbl (see pbrBaseLight), do not apply here
irradiance = max(amblit,irradiance);

View File

@ -34,7 +34,7 @@ uniform mat3 env_mat;
vec3 srgb_to_linear(vec3 c);
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
vec3 pos, vec3 norm, float glossiness, bool errorCorrect)
vec2 tc, vec3 pos, vec3 norm, float glossiness, bool errorCorrect)
{
ambenv = vec3(reflection_probe_ambiance * 0.25);
@ -44,10 +44,10 @@ void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
}
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
vec3 pos, vec3 norm, float glossiness)
vec2 tc, vec3 pos, vec3 norm, float glossiness)
{
sampleReflectionProbes(ambenv, glossenv,
pos, norm, glossiness, false);
tc, pos, norm, glossiness, false);
}
vec4 sampleReflectionProbesDebug(vec3 pos)
@ -56,8 +56,8 @@ vec4 sampleReflectionProbesDebug(vec3 pos)
return vec4(0, 0, 0, 0);
}
void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
vec3 pos, vec3 norm, float glossiness, float envIntensity)
void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity)
{
ambenv = vec3(reflection_probe_ambiance * 0.25);

View File

@ -56,8 +56,9 @@ vec3 linear_to_srgb(vec3 c);
vec3 srgb_to_linear(vec3 c);
// reflection probe interface
void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyEnv,
vec3 pos, vec3 norm, float glossiness, float envIntensity);
void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity);
void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm);
void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity);
@ -91,7 +92,7 @@ void main()
vec3 legacyenv;
vec3 norm = normalize(vary_texcoord1.xyz);
vec4 spec = vec4(0,0,0,0);
sampleReflectionProbesLegacy(ambenv, glossenv, legacyenv, pos.xyz, norm.xyz, spec.a, env_intensity);
sampleReflectionProbesLegacy(ambenv, glossenv, legacyenv, vec2(0), pos.xyz, norm.xyz, spec.a, env_intensity);
applyLegacyEnv(color.rgb, legacyenv, spec, pos, norm, env_intensity);
color.rgb = fullbrightAtmosTransportFrag(color.rgb, additive, atten);

View File

@ -61,8 +61,8 @@ out vec4 frag_color;
float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen);
#endif
void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
vec3 pos, vec3 norm, float glossiness, float envIntensity);
void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity);
void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm);
void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity);
@ -310,7 +310,7 @@ void main()
vec3 ambenv;
vec3 glossenv;
vec3 legacyenv;
sampleReflectionProbesLegacy(ambenv, glossenv, legacyenv, pos.xyz, norm.xyz, final_specular.a, env_intensity);
sampleReflectionProbesLegacy(ambenv, glossenv, legacyenv, pos_screen, pos.xyz, norm.xyz, final_specular.a, env_intensity);
// use sky settings ambient or irradiance map sample, whichever is brighter
color = max(amblit, ambenv);

View File

@ -25,11 +25,17 @@
#define FLT_MAX 3.402823466e+38
#if defined(SSR)
float tapScreenSpaceReflection(int totalSamples, vec2 tc, vec3 viewPos, vec3 n, inout vec4 collectedColor, sampler2D source);
#endif
#define REFMAP_COUNT 256
#define REF_SAMPLE_COUNT 64 //maximum number of samples to consider
uniform samplerCubeArray reflectionProbes;
uniform samplerCubeArray irradianceProbes;
uniform sampler2D sceneMap;
uniform int cube_snapshot;
layout (std140) uniform ReflectionProbes
{
@ -92,14 +98,17 @@ bool shouldSampleProbe(int i, vec3 pos)
}
else
{
vec3 delta = pos.xyz - refSphere[i].xyz;
float d = dot(delta, delta);
float r2 = refSphere[i].w;
r2 *= r2;
if (refSphere[i].w > 0.0) // zero is special indicator to always sample this probe
{
vec3 delta = pos.xyz - refSphere[i].xyz;
float d = dot(delta, delta);
float r2 = refSphere[i].w;
r2 *= r2;
if (d > r2)
{ //outside bounding sphere
return false;
if (d > r2)
{ //outside bounding sphere
return false;
}
}
max_priority = max(max_priority, refIndex[i].w);
@ -138,13 +147,13 @@ void preProbeSample(vec3 pos)
probeIndex[probeInfluences++] = idx;
if (probeInfluences == REF_SAMPLE_COUNT)
{
return;
break;
}
}
count++;
if (count == neighborCount)
{
return;
break;
}
idx = refNeighbor[neighborIdx].y;
@ -153,13 +162,13 @@ void preProbeSample(vec3 pos)
probeIndex[probeInfluences++] = idx;
if (probeInfluences == REF_SAMPLE_COUNT)
{
return;
break;
}
}
count++;
if (count == neighborCount)
{
return;
break;
}
idx = refNeighbor[neighborIdx].z;
@ -168,13 +177,13 @@ void preProbeSample(vec3 pos)
probeIndex[probeInfluences++] = idx;
if (probeInfluences == REF_SAMPLE_COUNT)
{
return;
break;
}
}
count++;
if (count == neighborCount)
{
return;
break;
}
idx = refNeighbor[neighborIdx].w;
@ -183,27 +192,26 @@ void preProbeSample(vec3 pos)
probeIndex[probeInfluences++] = idx;
if (probeInfluences == REF_SAMPLE_COUNT)
{
return;
break;
}
}
count++;
if (count == neighborCount)
{
return;
break;
}
++neighborIdx;
}
return;
break;
}
}
}
if (probeInfluences == 0)
{ // probe at index 0 is a special fallback probe
probeIndex[0] = 0;
probeInfluences = 1;
if (max_priority <= 1)
{ // probe at index 0 is a special probe for smoothing out automatic probes
probeIndex[probeInfluences++] = 0;
}
}
@ -330,7 +338,8 @@ return texCUBE(envMap, ReflDirectionWS);
// origin - ray origin in clip space
// dir - ray direction in clip space
// i - probe index in refBox/refSphere
vec3 boxIntersect(vec3 origin, vec3 dir, int i)
// d - distance to nearest wall in clip space
vec3 boxIntersect(vec3 origin, vec3 dir, int i, out float d)
{
// Intersection with OBB convertto unit box space
// Transform in local unit parallax cube space (scaled and rotated)
@ -339,6 +348,8 @@ vec3 boxIntersect(vec3 origin, vec3 dir, int i)
vec3 RayLS = mat3(clipToLocal) * dir;
vec3 PositionLS = (clipToLocal * vec4(origin, 1.0)).xyz;
d = 1.0-max(max(abs(PositionLS.x), abs(PositionLS.y)), abs(PositionLS.z));
vec3 Unitary = vec3(1.0f, 1.0f, 1.0f);
vec3 FirstPlaneIntersect = (Unitary - PositionLS) / RayLS;
vec3 SecondPlaneIntersect = (-Unitary - PositionLS) / RayLS;
@ -413,6 +424,29 @@ void boxIntersectDebug(vec3 origin, vec3 pos, int i, inout vec4 col)
}
// get the weight of a sphere probe
// pos - position to be weighted
// dir - normal to be weighted
// origin - center of sphere probe
// r - radius of probe influence volume
// min_da - minimum angular attenuation coefficient
float sphereWeight(vec3 pos, vec3 dir, vec3 origin, float r, float min_da)
{
float r1 = r * 0.5; // 50% of radius (outer sphere to start interpolating down)
vec3 delta = pos.xyz - origin;
float d2 = max(length(delta), 0.001);
float r2 = r1; //r1 * r1;
//float atten = 1.0 - max(d2 - r2, 0.0) / max((rr - r2), 0.001);
float atten = 1.0 - max(d2 - r2, 0.0) / max((r - r2), 0.001);
atten *= max(dot(normalize(-delta), dir), min_da);
float w = 1.0 / d2;
w *= atten;
return w;
}
// Tap a reflection probe
// pos - position of pixel
// dir - pixel normal
@ -431,27 +465,21 @@ vec3 tapRefMap(vec3 pos, vec3 dir, out float w, out vec3 vi, out vec3 wi, float
if (refIndex[i].w < 0)
{
v = boxIntersect(pos, dir, i);
w = 1.0;
float d = 0;
v = boxIntersect(pos, dir, i, d);
w = max(d, 0.001);
}
else
{
float r = refSphere[i].w; // radius of sphere volume
float rr = r * r; // radius squared
v = sphereIntersect(pos, dir, c, rr);
v = sphereIntersect(pos, dir, c,
refIndex[i].w <= 1 ? 4096.0*4096.0 : // <== effectively disable parallax correction for automatically placed probes to keep from bombing the world with obvious spheres
rr);
float p = float(abs(refIndex[i].w)); // priority
float r1 = r * 0.1; // 90% of radius (outer sphere to start interpolating down)
vec3 delta = pos.xyz - refSphere[i].xyz;
float d2 = max(dot(delta, delta), 0.001);
float r2 = r1 * r1;
float atten = 1.0 - max(d2 - r2, 0.0) / max((rr - r2), 0.001);
w = 1.0 / d2;
w *= atten;
w = sphereWeight(pos, dir, refSphere[i].xyz, r, 0.25);
}
vi = v;
@ -480,8 +508,9 @@ vec3 tapIrradianceMap(vec3 pos, vec3 dir, out float w, vec3 c, int i)
vec3 v;
if (refIndex[i].w < 0)
{
v = boxIntersect(pos, dir, i);
w = 1.0;
float d = 0.0;
v = boxIntersect(pos, dir, i, d);
w = max(d, 0.001);
}
else
{
@ -489,17 +518,11 @@ vec3 tapIrradianceMap(vec3 pos, vec3 dir, out float w, vec3 c, int i)
float p = float(abs(refIndex[i].w)); // priority
float rr = r * r; // radius squred
v = sphereIntersect(pos, dir, c, rr);
v = sphereIntersect(pos, dir, c,
refIndex[i].w <= 1 ? 4096.0*4096.0 : // <== effectively disable parallax correction for automatically placed probes to keep from bombing the world with obvious spheres
rr);
float r1 = r * 0.1; // 75% of radius (outer sphere to start interpolating down)
vec3 delta = pos.xyz - refSphere[i].xyz;
float d2 = dot(delta, delta);
float r2 = r1 * r1;
w = 1.0 / d2;
float atten = 1.0 - max(d2 - r2, 0.0) / (rr - r2);
w *= atten;
w = sphereWeight(pos, dir, refSphere[i].xyz, r, 0.001);
}
v -= c;
@ -605,7 +628,7 @@ vec3 sampleProbeAmbient(vec3 pos, vec3 dir)
}
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
vec3 pos, vec3 norm, float glossiness, bool errorCorrect)
vec2 tc, vec3 pos, vec3 norm, float glossiness, bool errorCorrect)
{
// TODO - don't hard code lods
float reflection_lods = 6;
@ -617,6 +640,17 @@ void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
float lod = (1.0-glossiness)*reflection_lods;
glossenv = sampleProbes(pos, normalize(refnormpersp), lod, errorCorrect);
#if defined(SSR)
if (cube_snapshot != 1)
{
vec4 ssr = vec4(0);
//float w = tapScreenSpaceReflection(errorCorrect ? 1 : 4, tc, pos, norm, ssr, sceneMap);
float w = tapScreenSpaceReflection(1, tc, pos, norm, ssr, sceneMap);
glossenv = mix(glossenv, ssr.rgb, w);
}
#endif
}
void debugTapRefMap(vec3 pos, vec3 dir, float depth, int i, inout vec4 col)
@ -660,15 +694,15 @@ vec4 sampleReflectionProbesDebug(vec3 pos)
}
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
vec3 pos, vec3 norm, float glossiness)
vec2 tc, vec3 pos, vec3 norm, float glossiness)
{
sampleReflectionProbes(ambenv, glossenv,
pos, norm, glossiness, false);
tc, pos, norm, glossiness, false);
}
void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
vec3 pos, vec3 norm, float glossiness, float envIntensity)
vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity)
{
// TODO - don't hard code lods
float reflection_lods = 7;
@ -676,7 +710,6 @@ void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout
vec3 refnormpersp = reflect(pos.xyz, norm.xyz);
ambenv = sampleProbeAmbient(pos, norm);
if (glossiness > 0.0)
@ -689,6 +722,17 @@ void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout
{
legacyenv = sampleProbes(pos, normalize(refnormpersp), 0.0, false);
}
#if defined(SSR)
if (cube_snapshot != 1)
{
vec4 ssr = vec4(0);
float w = tapScreenSpaceReflection(1, tc, pos, norm, ssr, sceneMap);
glossenv = mix(glossenv, ssr.rgb, w);
legacyenv = mix(legacyenv, ssr.rgb, w);
}
#endif
}
void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm)

View File

@ -42,10 +42,7 @@ uniform float zFar;
VARYING vec2 vary_fragcoord;
VARYING vec3 camera_ray;
uniform sampler2D depthMap;
uniform sampler2D normalMap;
uniform sampler2D specularRect;
uniform sampler2D sceneMap;
uniform sampler2D diffuseRect;
uniform sampler2D diffuseMap;
@ -57,27 +54,27 @@ float linearDepth01(float d, float znear, float zfar);
vec4 getPositionWithDepth(vec2 pos_screen, float depth);
vec4 getPosition(vec2 pos_screen);
vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity);
bool traceScreenRay(vec3 position, vec3 reflection, out vec4 hitColor, out float hitDepth, float depth, sampler2D textureFrame);
float random (vec2 uv);
float tapScreenSpaceReflection(int totalSamples, vec2 tc, vec3 viewPos, vec3 n, inout vec4 collectedColor, sampler2D source);
void main()
{
vec2 tc = vary_fragcoord.xy;
float depth = linearDepth01(getDepth(tc), zNear, zFar);
vec3 n = vec3(0, 0, 1);
float envIntensity;
vec3 n;
vec4 norm = getNormalEnvIntensityFlags(tc, n, envIntensity); // need `norm.w` for GET_GBUFFER_FLAG()
vec3 pos = getPositionWithDepth(tc, getDepth(tc)).xyz;
vec4 spec = texture2D(specularRect, tc);
vec3 viewPos = camera_ray * depth;
vec3 rayDirection = normalize(reflect(normalize(viewPos), n)) * -viewPos.z;
vec2 hitpixel;
vec4 hitpoint;
vec4 diffuse = texture2D(diffuseRect, tc);
vec3 specCol = spec.rgb;
frag_color = texture(diffuseMap, tc);
if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR))
{
vec3 orm = specCol.rgb;
@ -85,44 +82,17 @@ void main()
float metallic = orm.b;
vec3 f0 = vec3(0.04);
vec3 baseColor = diffuse.rgb;
vec3 diffuseColor = baseColor.rgb*(vec3(1.0)-f0);
specCol = mix(f0, baseColor.rgb, metallic);
}
vec2 uv2 = tc * screen_res;
float c = (uv2.x + uv2.y) * 0.125;
float jitter = mod( c, 1.0);
vec4 collectedColor = vec4(0);
vec3 firstBasis = normalize(cross(vec3(1.f, 1.f, 1.f), rayDirection));
vec3 secondBasis = normalize(cross(rayDirection, firstBasis));
frag_color = texture(diffuseMap, tc);
vec4 collectedColor;
vec2 screenpos = 1 - abs(tc * 2 - 1);
float vignette = clamp((screenpos.x * screenpos.y) * 16,0, 1);
vignette *= clamp((dot(normalize(viewPos), n) * 0.5 + 0.5 - 0.2) * 8, 0, 1);
vignette *= min(linearDepth(getDepth(tc), zNear, zFar) / zFar, 1);
float w = tapScreenSpaceReflection(4, tc, pos, n, collectedColor, diffuseMap);
int totalSamples = 4;
collectedColor.rgb *= specCol.rgb;
for (int i = 0; i < totalSamples; i++)
{
vec2 coeffs = vec2(random(tc + vec2(0, i)) + random(tc + vec2(i, 0)));
vec3 reflectionDirectionRandomized = rayDirection + firstBasis * coeffs.x + secondBasis * coeffs.y;
bool hit = traceScreenRay(pos, reflectionDirectionRandomized, hitpoint, depth, depth, diffuseMap);
if (hit)
{
collectedColor += hitpoint;
collectedColor.rgb *= specCol.rgb;
}
}
collectedColor *= vignette;
frag_color += collectedColor;
frag_color += collectedColor * w;
}

View File

@ -23,19 +23,18 @@
* $/LicenseInfo$
*/
uniform sampler2D depthMap;
uniform sampler2D normalMap;
uniform sampler2D sceneMap;
uniform sampler2D sceneDepth;
uniform vec2 screen_res;
uniform mat4 projection_matrix;
uniform float zNear;
uniform float zFar;
//uniform float zNear;
//uniform float zFar;
uniform mat4 inv_proj;
uniform mat4 modelview_delta; // should be transform from last camera space to current camera space
uniform mat4 inv_modelview_delta;
vec4 getPositionWithDepth(vec2 pos_screen, float depth);
float linearDepth(float depth, float near, float far);
float getDepth(vec2 pos_screen);
float linearDepth01(float d, float znear, float zfar);
float random (vec2 uv)
{
@ -62,8 +61,25 @@ float distanceBias = 0.02;
float depthRejectBias = 0.001;
float epsilon = 0.1;
float getLinearDepth(vec2 tc)
{
float depth = texture(sceneDepth, tc).r;
vec4 pos = getPositionWithDepth(tc, depth);
return -pos.z;
}
bool traceScreenRay(vec3 position, vec3 reflection, out vec4 hitColor, out float hitDepth, float depth, sampler2D textureFrame)
{
// transform position and reflection into same coordinate frame as the sceneMap and sceneDepth
reflection += position;
position = (inv_modelview_delta * vec4(position, 1)).xyz;
reflection = (inv_modelview_delta * vec4(reflection, 1)).xyz;
reflection -= position;
depth = -position.z;
vec3 step = rayStep * reflection;
vec3 marchingPosition = position + step;
float delta;
@ -72,13 +88,14 @@ bool traceScreenRay(vec3 position, vec3 reflection, out vec4 hitColor, out float
bool hit = false;
hitColor = vec4(0);
int i = 0;
if (depth > depthRejectBias)
{
for (; i < iterationCount && !hit; i++)
{
screenPosition = generateProjectedPosition(marchingPosition);
depthFromScreen = linearDepth(getDepth(screenPosition), zNear, zFar);
depthFromScreen = getLinearDepth(screenPosition);
delta = abs(marchingPosition.z) - depthFromScreen;
if (depth < depthFromScreen + epsilon && depth > depthFromScreen - epsilon)
@ -91,7 +108,7 @@ bool traceScreenRay(vec3 position, vec3 reflection, out vec4 hitColor, out float
vec4 color = vec4(1);
if(debugDraw)
color = vec4( 0.5+ sign(delta)/2,0.3,0.5- sign(delta)/2, 0);
hitColor = texture(textureFrame, screenPosition) * color;
hitColor = texture(sceneMap, screenPosition) * color;
hitDepth = depthFromScreen;
hit = true;
break;
@ -126,7 +143,7 @@ bool traceScreenRay(vec3 position, vec3 reflection, out vec4 hitColor, out float
marchingPosition = marchingPosition - step * sign(delta);
screenPosition = generateProjectedPosition(marchingPosition);
depthFromScreen = linearDepth(getDepth(screenPosition), zNear, zFar);
depthFromScreen = getLinearDepth(screenPosition);
delta = abs(marchingPosition.z) - depthFromScreen;
if (depth < depthFromScreen + epsilon && depth > depthFromScreen - epsilon)
@ -139,7 +156,7 @@ bool traceScreenRay(vec3 position, vec3 reflection, out vec4 hitColor, out float
vec4 color = vec4(1);
if(debugDraw)
color = vec4( 0.5+ sign(delta)/2,0.3,0.5- sign(delta)/2, 0);
hitColor = texture(textureFrame, screenPosition) * color;
hitColor = texture(sceneMap, screenPosition) * color;
hitDepth = depthFromScreen;
hit = true;
break;
@ -150,3 +167,68 @@ bool traceScreenRay(vec3 position, vec3 reflection, out vec4 hitColor, out float
return hit;
}
float tapScreenSpaceReflection(int totalSamples, vec2 tc, vec3 viewPos, vec3 n, inout vec4 collectedColor, sampler2D source)
{
collectedColor = vec4(0);
int hits = 0;
float depth = -viewPos.z;
vec3 rayDirection = normalize(reflect(viewPos, normalize(n)));
vec2 uv2 = tc * screen_res;
float c = (uv2.x + uv2.y) * 0.125;
float jitter = mod( c, 1.0);
vec3 firstBasis = normalize(cross(vec3(1,1,1), rayDirection));
vec3 secondBasis = normalize(cross(rayDirection, firstBasis));
vec2 screenpos = 1 - abs(tc * 2 - 1);
float vignette = clamp((screenpos.x * screenpos.y) * 16,0, 1);
vignette *= clamp((dot(normalize(viewPos), n) * 0.5 + 0.5 - 0.2) * 8, 0, 1);
float zFar = 64.0;
vignette *= clamp(1.0+(viewPos.z/zFar), 0.0, 1.0);
//vignette *= min(linearDepth(getDepth(tc), zNear, zFar) / zFar, 1);
vec4 hitpoint;
if (totalSamples > 1)
{
for (int i = 0; i < totalSamples; i++)
{
vec2 coeffs = vec2(random(tc + vec2(0, i)) + random(tc + vec2(i, 0)));
vec3 reflectionDirectionRandomized = rayDirection + firstBasis * coeffs.x + secondBasis * coeffs.y;
//float hitDepth;
bool hit = traceScreenRay(viewPos, normalize(reflectionDirectionRandomized), hitpoint, depth, depth, source);
if (hit)
{
++hits;
collectedColor += hitpoint;
}
}
}
else
{
bool hit = traceScreenRay(viewPos, normalize(rayDirection), hitpoint, depth, depth, source);
if (hit)
{
++hits;
collectedColor += hitpoint;
}
}
if (hits > 0)
{
collectedColor /= hits;
}
else
{
collectedColor = vec4(0);
}
return min(float(hits), 1.0) * vignette;
}

View File

@ -75,9 +75,9 @@ vec3 fullbrightAtmosTransportFragLinear(vec3 light, vec3 additive, vec3 atten);
// reflection probe interface
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
vec3 pos, vec3 norm, float glossiness);
void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyEnv,
vec3 pos, vec3 norm, float glossiness, float envIntensity);
vec2 tc, vec3 pos, vec3 norm, float glossiness);
void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity);
void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm);
void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity);
float getDepth(vec2 pos_screen);
@ -166,7 +166,7 @@ void main()
float gloss = 1.0 - perceptualRoughness;
vec3 irradiance = vec3(0);
vec3 radiance = vec3(0);
sampleReflectionProbes(irradiance, radiance, pos.xyz, norm.xyz, gloss);
sampleReflectionProbes(irradiance, radiance, tc, pos.xyz, norm.xyz, gloss);
// Take maximium of legacy ambient vs irradiance sample as irradiance
// NOTE: ao is applied in pbrIbl (see pbrBaseLight), do not apply here
@ -196,7 +196,7 @@ void main()
vec3 glossenv = vec3(0);
vec3 legacyenv = vec3(0);
sampleReflectionProbesLegacy(irradiance, glossenv, legacyenv, pos.xyz, norm.xyz, spec.a, envIntensity);
sampleReflectionProbesLegacy(irradiance, glossenv, legacyenv, tc, pos.xyz, norm.xyz, spec.a, envIntensity);
// use sky settings ambient or irradiance map sample, whichever is brighter
irradiance = max(amblit, irradiance);

View File

@ -95,9 +95,6 @@ vec3 BlendNormal(vec3 bump1, vec3 bump2)
vec3 srgb_to_linear(vec3 col);
void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
vec3 pos, vec3 norm, float glossiness, float envIntensity);
vec3 vN, vT, vB;
vec3 transform_normal(vec3 vNt)
@ -106,7 +103,10 @@ vec3 transform_normal(vec3 vNt)
}
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
vec3 pos, vec3 norm, float glossiness, bool errorCorrect);
vec2 tc, vec3 pos, vec3 norm, float glossiness);
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, bool errorCorrect);
vec3 getPositionWithNDC(vec3 ndc);
@ -225,7 +225,7 @@ void main()
vec3 irradiance = vec3(0);
vec3 radiance = vec3(0);
sampleReflectionProbes(irradiance, radiance, pos, refnorm, gloss, true);
sampleReflectionProbes(irradiance, radiance, distort, pos, refnorm, gloss, true);
radiance *= 0.5;
irradiance = fb.rgb;

View File

@ -468,7 +468,7 @@ void LLFastTimerView::exportCharts(const std::string& base, const std::string& t
{
//allocate render target for drawing charts
LLRenderTarget buffer;
buffer.allocate(1024,512, GL_RGB, FALSE, FALSE);
buffer.allocate(1024,512, GL_RGB);
LLSD cur;

View File

@ -1050,7 +1050,7 @@ F32 gpu_benchmark()
for (U32 i = 0; i < count; ++i)
{
//allocate render targets and textures
if (!dest[i].allocate(res, res, GL_RGBA, false, false, LLTexUnit::TT_TEXTURE, true))
if (!dest[i].allocate(res, res, GL_RGBA))
{
LL_WARNS("Benchmark") << "Failed to allocate render target." << LL_ENDL;
// abandon the benchmark test

View File

@ -39,6 +39,14 @@
extern BOOL gCubeSnapshot;
extern BOOL gTeleportDisplay;
static void touch_default_probe(LLReflectionMap* probe)
{
LLVector3 origin = LLViewerCamera::getInstance()->getOrigin();
origin.mV[2] += 64.f;
probe->mOrigin.load3(origin.mV);
}
LLReflectionMapManager::LLReflectionMapManager()
{
initCubeFree();
@ -83,10 +91,8 @@ void LLReflectionMapManager::update()
if (!mRenderTarget.isComplete())
{
U32 color_fmt = GL_RGB16F;
const bool use_depth_buffer = true;
const bool use_stencil_buffer = false;
U32 targetRes = LL_REFLECTION_PROBE_RESOLUTION * 2; // super sample
mRenderTarget.allocate(targetRes, targetRes, color_fmt, use_depth_buffer, use_stencil_buffer, LLTexUnit::TT_TEXTURE);
mRenderTarget.allocate(targetRes, targetRes, color_fmt, true);
}
if (mMipChain.empty())
@ -97,7 +103,7 @@ void LLReflectionMapManager::update()
mMipChain.resize(count);
for (int i = 0; i < count; ++i)
{
mMipChain[i].allocate(res, res, GL_RGBA16F, false, false, LLTexUnit::TT_TEXTURE);
mMipChain[i].allocate(res, res, GL_RGBA16F);
res /= 2;
}
}
@ -108,9 +114,8 @@ void LLReflectionMapManager::update()
mDefaultProbe = addProbe();
mDefaultProbe->mDistance = -4096.f; // hack to make sure the default probe is always first in sort order
mDefaultProbe->mRadius = 4096.f;
touch_default_probe(mDefaultProbe);
}
mDefaultProbe->mOrigin.load3(LLViewerCamera::getInstance()->getOrigin().mV);
LLVector4a camera_pos;
camera_pos.load3(LLViewerCamera::instance().getOrigin().mV);
@ -155,6 +160,8 @@ void LLReflectionMapManager::update()
doProbeUpdate();
}
//LL_INFOS() << mProbes.size() << LL_ENDL;
for (int i = 0; i < mProbes.size(); ++i)
{
LLReflectionMap* probe = mProbes[i];
@ -403,7 +410,26 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face)
{
// hacky hot-swap of camera specific render targets
gPipeline.mRT = &gPipeline.mAuxillaryRT;
probe->update(mRenderTarget.getWidth(), face);
if (probe == mDefaultProbe)
{
touch_default_probe(probe);
gPipeline.pushRenderTypeMask();
//only render sky, water, terrain, and clouds
gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, LLPipeline::RENDER_TYPE_WL_SKY,
LLPipeline::RENDER_TYPE_WATER, LLPipeline::RENDER_TYPE_CLOUDS, LLPipeline::RENDER_TYPE_TERRAIN, LLPipeline::END_RENDER_TYPES);
probe->update(mRenderTarget.getWidth(), face);
gPipeline.popRenderTypeMask();
}
else
{
probe->update(mRenderTarget.getWidth(), face);
}
gPipeline.mRT = &gPipeline.mMainRT;
S32 targetIdx = mReflectionProbeCount;

View File

@ -177,7 +177,7 @@ LLRenderTarget& LLSceneMonitor::getCaptureTarget()
if(!mFrames[0])
{
mFrames[0] = new LLRenderTarget();
mFrames[0]->allocate(width, height, GL_RGB, false, false, LLTexUnit::TT_TEXTURE, true);
mFrames[0]->allocate(width, height, GL_RGB);
gGL.getTexUnit(0)->bind(mFrames[0]);
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
@ -187,7 +187,7 @@ LLRenderTarget& LLSceneMonitor::getCaptureTarget()
else if(!mFrames[1])
{
mFrames[1] = new LLRenderTarget();
mFrames[1]->allocate(width, height, GL_RGB, false, false, LLTexUnit::TT_TEXTURE, true);
mFrames[1]->allocate(width, height, GL_RGB);
gGL.getTexUnit(0)->bind(mFrames[1]);
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
@ -360,7 +360,7 @@ void LLSceneMonitor::compare()
if(!mDiff)
{
mDiff = new LLRenderTarget();
mDiff->allocate(width, height, GL_RGBA, false, false, LLTexUnit::TT_TEXTURE, true);
mDiff->allocate(width, height, GL_RGBA);
generateDitheringTexture(width, height);
}

View File

@ -682,6 +682,7 @@ void settings_setup_listeners()
// DEPRECATED - setting_setup_signal_listener(gSavedSettings, "RenderDeferred", handleRenderDeferredChanged);
setting_setup_signal_listener(gSavedSettings, "RenderReflectionProbeDetail", handleReflectionProbeDetailChanged);
setting_setup_signal_listener(gSavedSettings, "RenderReflectionsEnabled", handleReflectionProbeDetailChanged);
setting_setup_signal_listener(gSavedSettings, "RenderScreenSpaceReflections", handleReflectionProbeDetailChanged);
setting_setup_signal_listener(gSavedSettings, "RenderShadowDetail", handleSetShaderChanged);
setting_setup_signal_listener(gSavedSettings, "RenderDeferredSSAO", handleSetShaderChanged);
setting_setup_signal_listener(gSavedSettings, "RenderPerformanceTest", handleRenderPerfTestChanged);

View File

@ -918,15 +918,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
gGL.setColorMask(true, true);
gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance(), true);
//store this frame's modelview matrix for use
//when rendering next frame's occlusion queries
for (U32 i = 0; i < 16; i++)
{
gGLLastModelView[i] = gGLModelView[i];
gGLLastProjection[i] = gGLProjection[i];
}
stop_glerror();
}
{

View File

@ -843,6 +843,7 @@ std::string LLViewerShaderMgr::loadBasicShaders()
BOOL ambient_kill = gSavedSettings.getBOOL("AmbientDisable");
BOOL sunlight_kill = gSavedSettings.getBOOL("SunlightDisable");
BOOL local_light_kill = gSavedSettings.getBOOL("LocalLightDisable");
BOOL ssr = gSavedSettings.getBOOL("RenderScreenSpaceReflections");
if (ambient_kill)
{
@ -871,6 +872,11 @@ std::string LLViewerShaderMgr::loadBasicShaders()
}
}
if (ssr)
{
attribs["SSR"] = "1";
}
// We no longer have to bind the shaders to global glhandles, they are automatically added to a map now.
for (U32 i = 0; i < shaders.size(); i++)
{
@ -910,7 +916,7 @@ std::string LLViewerShaderMgr::loadBasicShaders()
index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/shadowUtil.glsl", 1) );
index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/aoUtil.glsl", 1) );
index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/reflectionProbeF.glsl", has_reflection_probes ? 3 : 2) );
index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/screenSpaceReflUtil.glsl", 3) );
index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/screenSpaceReflUtil.glsl", ssr ? 3 : 1) );
index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) );
index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightAlphaMaskNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) );
index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightFullbrightNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) );

View File

@ -4898,7 +4898,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
(image_width > window_width || image_height > window_height) && LLPipeline::sRenderDeferred && !show_ui)
{
U32 color_fmt = type == LLSnapshotModel::SNAPSHOT_TYPE_DEPTH ? GL_DEPTH_COMPONENT : GL_RGBA;
if (scratch_space.allocate(image_width, image_height, color_fmt, true, true))
if (scratch_space.allocate(image_width, image_height, color_fmt, true))
{
original_width = gPipeline.mRT->deferredScreen.getWidth();
original_height = gPipeline.mRT->deferredScreen.getHeight();
@ -5162,9 +5162,7 @@ BOOL LLViewerWindow::simpleSnapshot(LLImageRaw* raw, S32 image_width, S32 image_
LLRenderTarget scratch_space;
U32 color_fmt = GL_RGBA;
const bool use_depth_buffer = true;
const bool use_stencil_buffer = false;
if (scratch_space.allocate(image_width, image_height, color_fmt, use_depth_buffer, use_stencil_buffer))
if (scratch_space.allocate(image_width, image_height, color_fmt, true))
{
if (gPipeline.allocateScreenBuffer(image_width, image_height))
{

View File

@ -479,14 +479,9 @@ void LLPipeline::init()
mBackfaceCull = true;
stop_glerror();
// Enable features
LLViewerShaderMgr::instance()->setShaders();
stop_glerror();
for (U32 i = 0; i < 2; ++i)
{
mSpotLightFade[i] = 1.f;
@ -835,7 +830,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
if (RenderUIBuffer)
{
if (!mRT->uiScreen.allocate(resX,resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE))
if (!mRT->uiScreen.allocate(resX,resY, GL_RGBA))
{
return false;
}
@ -845,18 +840,18 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
bool ssao = RenderDeferredSSAO;
//allocate deferred rendering color buffers
if (!mRT->deferredScreen.allocate(resX, resY, GL_RGBA, true, true, LLTexUnit::TT_TEXTURE, false, samples)) return false;
if (!mRT->deferredScreen.allocate(resX, resY, GL_RGBA, true)) return false;
if (!addDeferredAttachments(mRT->deferredScreen)) return false;
GLuint screenFormat = GL_RGBA16;
if (!mRT->screen.allocate(resX, resY, screenFormat, FALSE, true, LLTexUnit::TT_TEXTURE, FALSE, samples)) return false;
if (!mRT->screen.allocate(resX, resY, screenFormat)) return false;
mRT->deferredScreen.shareDepthBuffer(mRT->screen);
if (samples > 0)
{
if (!mRT->fxaaBuffer.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE, samples)) return false;
if (!mRT->fxaaBuffer.allocate(resX, resY, GL_RGBA)) return false;
}
else
{
@ -865,7 +860,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
if (shadow_detail > 0 || ssao || RenderDepthOfField || samples > 0)
{ //only need mRT->deferredLight for shadows OR ssao OR dof OR fxaa
if (!mRT->deferredLight.allocate(resX, resY, GL_RGBA16, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE)) return false;
if (!mRT->deferredLight.allocate(resX, resY, GL_RGBA16)) return false;
}
else
{
@ -874,6 +869,11 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
allocateShadowBuffer(resX, resY);
if (!gCubeSnapshot && RenderScreenSpaceReflections) // hack to not allocate mSceneMap for cube snapshots
{
mSceneMap.allocate(resX, resY, GL_RGB, true);
}
//HACK make screenbuffer allocations start failing after 30 seconds
if (gSavedSettings.getBOOL("SimulateFBOFailure"))
{
@ -903,7 +903,7 @@ bool LLPipeline::allocateShadowBuffer(U32 resX, U32 resY)
{ //allocate 4 sun shadow maps
for (U32 i = 0; i < 4; i++)
{
if (!mRT->shadow[i].allocate(sun_shadow_map_width, sun_shadow_map_height, 0, true, true, LLTexUnit::TT_TEXTURE))
if (!mRT->shadow[i].allocate(sun_shadow_map_width, sun_shadow_map_height, 0, true))
{
return false;
}
@ -928,7 +928,7 @@ bool LLPipeline::allocateShadowBuffer(U32 resX, U32 resY)
U32 spot_shadow_map_height = height;
for (U32 i = 0; i < 2; i++)
{
if (!mSpotShadow[i].allocate(spot_shadow_map_width, spot_shadow_map_height, 0, true, true))
if (!mSpotShadow[i].allocate(spot_shadow_map_width, spot_shadow_map_height, 0, true))
{
return false;
}
@ -1112,6 +1112,8 @@ void LLPipeline::releaseGLBuffers()
mWaterDis.release();
mBake.release();
mSceneMap.release();
for (U32 i = 0; i < 3; i++)
{
mGlow[i].release();
@ -1185,11 +1187,11 @@ void LLPipeline::createGLBuffers()
if (LLPipeline::sRenderTransparentWater)
{ //water reflection texture
U32 res = (U32) llmax(gSavedSettings.getS32("RenderWaterRefResolution"), 512);
mWaterDis.allocate(res,res,GL_RGBA,true,true,LLTexUnit::TT_TEXTURE);
mWaterDis.allocate(res,res,GL_RGBA,true);
}
// Use FBO for bake tex
mBake.allocate(512, 512, GL_RGBA, TRUE, FALSE, LLTexUnit::TT_TEXTURE, true); // SL-12781 Build > Upload > Model; 3D Preview
mBake.allocate(512, 512, GL_RGBA, true); // SL-12781 Build > Upload > Model; 3D Preview
stop_glerror();
@ -1200,7 +1202,7 @@ void LLPipeline::createGLBuffers()
const U32 glow_res = llmax(1, llmin(512, 1 << gSavedSettings.getS32("RenderGlowResolutionPow")));
for (U32 i = 0; i < 3; i++)
{
mGlow[i].allocate(512, glow_res, GL_RGBA, FALSE, FALSE);
mGlow[i].allocate(512, glow_res, GL_RGBA);
}
allocateScreenBuffer(resX, resY);
@ -1306,7 +1308,7 @@ void LLPipeline::createLUTBuffers()
delete [] ls;
}
mPbrBrdfLut.allocate(512, 512, GL_RG16F, false, false);
mPbrBrdfLut.allocate(512, 512, GL_RG16F);
mPbrBrdfLut.bindTarget();
gDeferredGenBrdfLutProgram.bind();
@ -4019,6 +4021,26 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera, bool do_occlusion)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
if (&camera == LLViewerCamera::getInstance())
{ // a bit hacky, this is the start of the main render frame, figure out delta between last modelview matrix and
// current modelview matrix
glh::matrix4f last_modelview(gGLLastModelView);
glh::matrix4f cur_modelview(gGLModelView);
// goal is to have a matrix here that goes from the last frame's camera space to the current frame's camera space
glh::matrix4f m = last_modelview.inverse(); // last camera space to world space
m.mult_left(cur_modelview); // world space to camera space
glh::matrix4f n = m.inverse();
for (U32 i = 0; i < 16; ++i)
{
gGLDeltaModelView[i] = m.m[i];
gGLInverseDeltaModelView[i] = n.m[i];
}
}
bool occlude = LLPipeline::sUseOcclusion > 1 && do_occlusion;
setupHWLights(nullptr);
@ -7529,10 +7551,11 @@ void LLPipeline::renderFinalize()
if (!gCubeSnapshot)
{
screenTarget()->bindTarget();
LLRenderTarget* screen_target = screenTarget();
if (RenderScreenSpaceReflections)
if (RenderScreenSpaceReflections && !gCubeSnapshot)
{
#if 0
LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - screen space reflections");
LL_PROFILE_GPU_ZONE("screen space reflections");
@ -7565,8 +7588,33 @@ void LLPipeline::renderFinalize()
}
unbindDeferredShader(gPostScreenSpaceReflectionProgram);
#else
LL_PROFILE_GPU_ZONE("ssr copy");
LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS);
LLRenderTarget& src = *screen_target;
LLRenderTarget& depth_src = mRT->deferredScreen;
LLRenderTarget& dst = mSceneMap;
dst.bindTarget();
dst.clear();
gCopyDepthProgram.bind();
S32 diff_map = gCopyDepthProgram.getTextureChannel(LLShaderMgr::DIFFUSE_MAP);
S32 depth_map = gCopyDepthProgram.getTextureChannel(LLShaderMgr::DEFERRED_DEPTH);
gGL.getTexUnit(diff_map)->bind(&src);
gGL.getTexUnit(depth_map)->bind(&depth_src, true);
mScreenTriangleVB->setBuffer();
mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
dst.flush();
#endif
}
screenTarget()->bindTarget();
// gamma correct lighting
{
LL_PROFILE_GPU_ZONE("gamma correct");
@ -7821,56 +7869,6 @@ void LLPipeline::bindDeferredShaderFast(LLGLSLShader& shader)
bindLightFunc(shader);
bindShadowMaps(shader);
bindReflectionProbes(shader);
#if 0
shader.uniform1f(LLShaderMgr::DEFERRED_SUN_WASH, RenderDeferredSunWash);
shader.uniform1f(LLShaderMgr::DEFERRED_SHADOW_NOISE, RenderShadowNoise);
shader.uniform1f(LLShaderMgr::DEFERRED_BLUR_SIZE, RenderShadowBlurSize);
shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_RADIUS, RenderSSAOScale);
shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_MAX_RADIUS, RenderSSAOMaxScale);
F32 ssao_factor = RenderSSAOFactor;
shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_FACTOR, ssao_factor);
shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_FACTOR_INV, 1.0 / ssao_factor);
LLVector3 ssao_effect = RenderSSAOEffect;
F32 matrix_diag = (ssao_effect[0] + 2.0 * ssao_effect[1]) / 3.0;
F32 matrix_nondiag = (ssao_effect[0] - ssao_effect[1]) / 3.0;
// This matrix scales (proj of color onto <1/rt(3),1/rt(3),1/rt(3)>) by
// value factor, and scales remainder by saturation factor
F32 ssao_effect_mat[] = { matrix_diag, matrix_nondiag, matrix_nondiag,
matrix_nondiag, matrix_diag, matrix_nondiag,
matrix_nondiag, matrix_nondiag, matrix_diag };
shader.uniformMatrix3fv(LLShaderMgr::DEFERRED_SSAO_EFFECT_MAT, 1, GL_FALSE, ssao_effect_mat);
//F32 shadow_offset_error = 1.f + RenderShadowOffsetError * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]);
F32 shadow_bias_error = RenderShadowBiasError * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]) / 3000.f;
F32 shadow_bias = RenderShadowBias + shadow_bias_error;
//shader.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, deferred_target->getWidth(), deferred_target->getHeight());
shader.uniform1f(LLShaderMgr::DEFERRED_NEAR_CLIP, LLViewerCamera::getInstance()->getNear() * 2.f);
shader.uniform1f(LLShaderMgr::DEFERRED_SHADOW_OFFSET, RenderShadowOffset); //*shadow_offset_error);
shader.uniform1f(LLShaderMgr::DEFERRED_SHADOW_BIAS, shadow_bias);
shader.uniform1f(LLShaderMgr::DEFERRED_SPOT_SHADOW_OFFSET, RenderSpotShadowOffset);
shader.uniform1f(LLShaderMgr::DEFERRED_SPOT_SHADOW_BIAS, RenderSpotShadowBias);
shader.uniform3fv(LLShaderMgr::DEFERRED_SUN_DIR, 1, mTransformedSunDir.mV);
shader.uniform3fv(LLShaderMgr::DEFERRED_MOON_DIR, 1, mTransformedMoonDir.mV);
shader.uniform2f(LLShaderMgr::DEFERRED_SHADOW_RES, mRT->shadow[0].getWidth(), mRT->shadow[0].getHeight());
shader.uniform2f(LLShaderMgr::DEFERRED_PROJ_SHADOW_RES, mSpotShadow[0].getWidth(), mSpotShadow[0].getHeight());
shader.uniform1f(LLShaderMgr::DEFERRED_DEPTH_CUTOFF, RenderEdgeDepthCutoff);
shader.uniform1f(LLShaderMgr::DEFERRED_NORM_CUTOFF, RenderEdgeNormCutoff);
if (shader.getUniformLocation(LLShaderMgr::DEFERRED_NORM_MATRIX) >= 0)
{
glh::matrix4f norm_mat = get_current_modelview().inverse().transpose();
shader.uniformMatrix4fv(LLShaderMgr::DEFERRED_NORM_MATRIX, 1, FALSE, norm_mat.m);
}
shader.uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, 1, mSunDiffuse.mV);
shader.uniform3fv(LLShaderMgr::MOONLIGHT_COLOR, 1, mMoonDiffuse.mV);
#endif
}
void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_target)
@ -7910,21 +7908,24 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_
gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
}
#if 0
channel = shader.enableTexture(LLShaderMgr::DEFERRED_DEPTH, deferred_depth_target->getUsage());
if (channel > -1)
{
gGL.getTexUnit(channel)->bind(deferred_depth_target, TRUE);
stop_glerror();
}
#else
channel = shader.enableTexture(LLShaderMgr::DEFERRED_DEPTH, deferred_target->getUsage());
if (channel > -1)
{
gGL.getTexUnit(channel)->bind(deferred_target, TRUE);
stop_glerror();
}
#endif
channel = shader.enableTexture(LLShaderMgr::SCENE_MAP);
if (channel > -1)
{
gGL.getTexUnit(channel)->bind(&mSceneMap);
}
channel = shader.enableTexture(LLShaderMgr::SCENE_DEPTH);
if (channel > -1)
{
gGL.getTexUnit(channel)->bind(&mSceneMap, true);
}
if (shader.getUniformLocation(LLShaderMgr::VIEWPORT) != -1)
{
@ -8090,6 +8091,11 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_
shader.uniform1f(LLShaderMgr::DEFERRED_DEPTH_CUTOFF, RenderEdgeDepthCutoff);
shader.uniform1f(LLShaderMgr::DEFERRED_NORM_CUTOFF, RenderEdgeNormCutoff);
shader.uniformMatrix4fv(LLShaderMgr::MODELVIEW_DELTA_MATRIX, 1, GL_FALSE, gGLDeltaModelView);
shader.uniformMatrix4fv(LLShaderMgr::INVERSE_MODELVIEW_DELTA_MATRIX, 1, GL_FALSE, gGLInverseDeltaModelView);
shader.uniform1i(LLShaderMgr::CUBE_SNAPSHOT, gCubeSnapshot ? 1 : 0);
if (shader.getUniformLocation(LLShaderMgr::DEFERRED_NORM_MATRIX) >= 0)
{
glh::matrix4f norm_mat = get_current_modelview().inverse().transpose();
@ -8584,6 +8590,16 @@ void LLPipeline::renderDeferredLighting()
screen_target->flush();
if (!gCubeSnapshot)
{
// this is the end of the 3D scene render, grab a copy of the modelview and projection
// matrix for use in off-by-one-frame effects in the next frame
for (U32 i = 0; i < 16; i++)
{
gGLLastModelView[i] = gGLModelView[i];
gGLLastProjection[i] = gGLProjection[i];
}
}
gGL.setColorMask(true, true);
}
@ -10398,7 +10414,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar)
if (!avatar->mImpostor.isComplete())
{
avatar->mImpostor.allocate(resX, resY, GL_RGBA, TRUE, FALSE);
avatar->mImpostor.allocate(resX, resY, GL_RGBA, true);
if (LLPipeline::sRenderDeferred)
{

View File

@ -685,6 +685,10 @@ public:
LLRenderTarget mPbrBrdfLut;
// copy of the color/depth buffer just before gamma correction
// for use by SSR
LLRenderTarget mSceneMap;
LLCullResult mSky;
LLCullResult mReflectedObjects;
LLCullResult mRefractedObjects;