Merge branch 'DRTVWR-559' of https://github.com/secondlife/viewer
# Conflicts: # indra/llcommon/llprofiler.h # indra/llcommon/lluuid.cpp # indra/llprimitive/llmodel.cpp # indra/llrender/llrendertarget.cpp # indra/newview/app_settings/settings.xml # indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl # indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl # indra/newview/llviewerwindow.cpp # indra/newview/pipeline.cpp # indra/newview/skins/default/xui/da/floater_about.xml # indra/newview/skins/default/xui/de/floater_about.xml # indra/newview/skins/default/xui/en/floater_about.xml # indra/newview/skins/default/xui/es/floater_about.xml # indra/newview/skins/default/xui/fr/floater_about.xml # indra/newview/skins/default/xui/it/floater_about.xml # indra/newview/skins/default/xui/pt/floater_about.xml # indra/newview/skins/default/xui/ru/floater_about.xml # indra/newview/skins/default/xui/tr/floater_about.xml # indra/newview/skins/default/xui/zh/floater_about.xmlmaster
commit
6cbca4da71
|
|
@ -3465,6 +3465,36 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>version</key>
|
||||
<string>0.54.1.555529</string>
|
||||
</map>
|
||||
<key>xxhash</key>
|
||||
<map>
|
||||
<key>copyright</key>
|
||||
<string>Copyright 2012-2020 Yann Collet</string>
|
||||
<key>description</key>
|
||||
<string>xxHash Extremely fast hash algorithm</string>
|
||||
<key>license</key>
|
||||
<string>bsd</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/xxhash.txt</string>
|
||||
<key>name</key>
|
||||
<string>xxhash</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>common</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>e4f77ba0a9b8ec3cc3fabc51c4da81d2</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/110070/956941/xxhash-0.8.1.578006-windows-578006.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>common</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>0.8.1</string>
|
||||
</map>
|
||||
<key>zlib-ng</key>
|
||||
<map>
|
||||
<key>canonical_repo</key>
|
||||
|
|
|
|||
|
|
@ -588,6 +588,8 @@ Henri Beauchamp
|
|||
VWR-1320
|
||||
VWR-1406
|
||||
VWR-4157
|
||||
SL-15175
|
||||
SL-19110
|
||||
herina Bode
|
||||
Hikkoshi Sakai
|
||||
VWR-429
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ set(cmake_SOURCE_FILES
|
|||
VisualLeakDetector.cmake
|
||||
LibVLCPlugin.cmake
|
||||
XmlRpcEpi.cmake
|
||||
xxHash.cmake
|
||||
ZLIBNG.cmake
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ include(APR)
|
|||
include(Boost)
|
||||
include(EXPAT)
|
||||
include(Tracy)
|
||||
include(xxHash)
|
||||
include(ZLIBNG)
|
||||
|
||||
set(LLCOMMON_INCLUDE_DIRS
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
# -*- cmake -*-
|
||||
if (XXHASH_CMAKE_INCLUDED)
|
||||
return()
|
||||
endif (XXHASH_CMAKE_INCLUDED)
|
||||
set (XXHASH_CMAKE_INCLUDED TRUE)
|
||||
|
||||
include(Prebuilt)
|
||||
use_prebuilt_binary(xxhash)
|
||||
|
|
@ -119,6 +119,7 @@ set(llcommon_SOURCE_FILES
|
|||
lluriparser.cpp
|
||||
lluuid.cpp
|
||||
llworkerthread.cpp
|
||||
hbxxh.cpp
|
||||
u64.cpp
|
||||
threadpool.cpp
|
||||
workqueue.cpp
|
||||
|
|
@ -257,6 +258,7 @@ set(llcommon_HEADER_FILES
|
|||
llwin32headers.h
|
||||
llwin32headerslean.h
|
||||
llworkerthread.h
|
||||
hbxxh.h
|
||||
lockstatic.h
|
||||
stdtypes.h
|
||||
stringize.h
|
||||
|
|
|
|||
|
|
@ -0,0 +1,377 @@
|
|||
/**
|
||||
* @file hbxxh.cpp
|
||||
* @brief High performances vectorized hashing based on xxHash.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (c) 2023, Henri Beauchamp.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
// This define ensures that xxHash will be compiled within this module, with
|
||||
// vectorized (*) and inlined functions (with no exported API symbol); our
|
||||
// xxhash "pre-built library" package actually only contains the xxhash.h
|
||||
// header (no library needed at link time).
|
||||
// (*) SSE2 is normally used for x86(_64) builds, unless you enabled AVX2
|
||||
// in your build, in which case the latter would be used instead. For ARM64
|
||||
// builds, this would also automatically enable NEON vectorization.
|
||||
#define XXH_INLINE_ALL
|
||||
#include "xxhash/xxhash.h"
|
||||
|
||||
#include "hbxxh.h"
|
||||
|
||||
// How many bytes to grab at a time when hashing files or streams
|
||||
constexpr size_t BLOCK_LEN = 4096;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// HBXXH64 class
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//static
|
||||
U64 HBXXH64::digest(const void* buffer, size_t len)
|
||||
{
|
||||
return XXH3_64bits(buffer, len);
|
||||
}
|
||||
|
||||
//static
|
||||
U64 HBXXH64::digest(const char* str)
|
||||
{
|
||||
return XXH3_64bits((const void*)str, strlen(str));
|
||||
}
|
||||
|
||||
//static
|
||||
U64 HBXXH64::digest(const std::string& str)
|
||||
{
|
||||
return XXH3_64bits((const void*)str.c_str(), str.size());
|
||||
}
|
||||
|
||||
// Must be called by all constructors.
|
||||
void HBXXH64::init()
|
||||
{
|
||||
mDigest = 0;
|
||||
mState = (void*)XXH3_createState();
|
||||
if (!mState || XXH3_64bits_reset((XXH3_state_t*)mState) != XXH_OK)
|
||||
{
|
||||
LL_WARNS() << "Failed to initialize state !" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
HBXXH64::~HBXXH64()
|
||||
{
|
||||
if (mState)
|
||||
{
|
||||
XXH3_freeState((XXH3_state_t*)mState);
|
||||
}
|
||||
}
|
||||
|
||||
void HBXXH64::update(const void* buffer, size_t len)
|
||||
{
|
||||
if (mState)
|
||||
{
|
||||
XXH3_64bits_update((XXH3_state_t*)mState, buffer, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS() << "Cannot update a finalized digest !" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
void HBXXH64::update(const std::string& str)
|
||||
{
|
||||
if (mState)
|
||||
{
|
||||
XXH3_64bits_update((XXH3_state_t*)mState, (const void*)str.c_str(),
|
||||
str.length());
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS() << "Cannot update a finalized digest !" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
void HBXXH64::update(std::istream& stream)
|
||||
{
|
||||
if (!mState)
|
||||
{
|
||||
LL_WARNS() << "Cannot update a finalized digest !" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[BLOCK_LEN];
|
||||
size_t len;
|
||||
while (stream.good())
|
||||
{
|
||||
stream.read(buffer, BLOCK_LEN);
|
||||
len = stream.gcount();
|
||||
XXH3_64bits_update((XXH3_state_t*)mState, (const void*)buffer, len);
|
||||
}
|
||||
}
|
||||
|
||||
void HBXXH64::update(FILE* file)
|
||||
{
|
||||
if (!mState)
|
||||
{
|
||||
LL_WARNS() << "Cannot update a finalized digest !" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[BLOCK_LEN];
|
||||
size_t len;
|
||||
while ((len = fread((void*)buffer, 1, BLOCK_LEN, file)))
|
||||
{
|
||||
XXH3_64bits_update((XXH3_state_t*)mState, (const void*)buffer, len);
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
void HBXXH64::finalize()
|
||||
{
|
||||
if (!mState)
|
||||
{
|
||||
LL_WARNS() << "Already finalized !" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
mDigest = XXH3_64bits_digest((XXH3_state_t*)mState);
|
||||
XXH3_freeState((XXH3_state_t*)mState);
|
||||
mState = NULL;
|
||||
}
|
||||
|
||||
U64 HBXXH64::digest() const
|
||||
{
|
||||
return mState ? XXH3_64bits_digest((XXH3_state_t*)mState) : mDigest;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, HBXXH64 context)
|
||||
{
|
||||
stream << context.digest();
|
||||
return stream;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// HBXXH128 class
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//static
|
||||
LLUUID HBXXH128::digest(const void* buffer, size_t len)
|
||||
{
|
||||
XXH128_hash_t hash = XXH3_128bits(buffer, len);
|
||||
LLUUID id;
|
||||
U64* data = (U64*)id.mData;
|
||||
// Note: we do not check endianness here and we just store in the same
|
||||
// order as XXH128_hash_t, that is low word "first".
|
||||
data[0] = hash.low64;
|
||||
data[1] = hash.high64;
|
||||
return id;
|
||||
}
|
||||
|
||||
//static
|
||||
LLUUID HBXXH128::digest(const char* str)
|
||||
{
|
||||
XXH128_hash_t hash = XXH3_128bits((const void*)str, strlen(str));
|
||||
LLUUID id;
|
||||
U64* data = (U64*)id.mData;
|
||||
// Note: we do not check endianness here and we just store in the same
|
||||
// order as XXH128_hash_t, that is low word "first".
|
||||
data[0] = hash.low64;
|
||||
data[1] = hash.high64;
|
||||
return id;
|
||||
}
|
||||
|
||||
//static
|
||||
LLUUID HBXXH128::digest(const std::string& str)
|
||||
{
|
||||
XXH128_hash_t hash = XXH3_128bits((const void*)str.c_str(), str.size());
|
||||
LLUUID id;
|
||||
U64* data = (U64*)id.mData;
|
||||
// Note: we do not check endianness here and we just store in the same
|
||||
// order as XXH128_hash_t, that is low word "first".
|
||||
data[0] = hash.low64;
|
||||
data[1] = hash.high64;
|
||||
return id;
|
||||
}
|
||||
|
||||
//static
|
||||
void HBXXH128::digest(LLUUID& result, const void* buffer, size_t len)
|
||||
{
|
||||
XXH128_hash_t hash = XXH3_128bits(buffer, len);
|
||||
U64* data = (U64*)result.mData;
|
||||
// Note: we do not check endianness here and we just store in the same
|
||||
// order as XXH128_hash_t, that is low word "first".
|
||||
data[0] = hash.low64;
|
||||
data[1] = hash.high64;
|
||||
}
|
||||
|
||||
//static
|
||||
void HBXXH128::digest(LLUUID& result, const char* str)
|
||||
{
|
||||
XXH128_hash_t hash = XXH3_128bits((const void*)str, strlen(str));
|
||||
U64* data = (U64*)result.mData;
|
||||
// Note: we do not check endianness here and we just store in the same
|
||||
// order as XXH128_hash_t, that is low word "first".
|
||||
data[0] = hash.low64;
|
||||
data[1] = hash.high64;
|
||||
}
|
||||
|
||||
//static
|
||||
void HBXXH128::digest(LLUUID& result, const std::string& str)
|
||||
{
|
||||
XXH128_hash_t hash = XXH3_128bits((const void*)str.c_str(), str.size());
|
||||
U64* data = (U64*)result.mData;
|
||||
// Note: we do not check endianness here and we just store in the same
|
||||
// order as XXH128_hash_t, that is low word "first".
|
||||
data[0] = hash.low64;
|
||||
data[1] = hash.high64;
|
||||
}
|
||||
|
||||
// Must be called by all constructors.
|
||||
void HBXXH128::init()
|
||||
{
|
||||
mState = (void*)XXH3_createState();
|
||||
if (!mState || XXH3_128bits_reset((XXH3_state_t*)mState) != XXH_OK)
|
||||
{
|
||||
LL_WARNS() << "Failed to initialize state !" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
HBXXH128::~HBXXH128()
|
||||
{
|
||||
if (mState)
|
||||
{
|
||||
XXH3_freeState((XXH3_state_t*)mState);
|
||||
}
|
||||
}
|
||||
|
||||
void HBXXH128::update(const void* buffer, size_t len)
|
||||
{
|
||||
if (mState)
|
||||
{
|
||||
XXH3_128bits_update((XXH3_state_t*)mState, buffer, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS() << "Cannot update a finalized digest !" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
void HBXXH128::update(const std::string& str)
|
||||
{
|
||||
if (mState)
|
||||
{
|
||||
XXH3_128bits_update((XXH3_state_t*)mState, (const void*)str.c_str(),
|
||||
str.length());
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS() << "Cannot update a finalized digest !" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
void HBXXH128::update(std::istream& stream)
|
||||
{
|
||||
if (!mState)
|
||||
{
|
||||
LL_WARNS() << "Cannot update a finalized digest !" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[BLOCK_LEN];
|
||||
size_t len;
|
||||
while (stream.good())
|
||||
{
|
||||
stream.read(buffer, BLOCK_LEN);
|
||||
len = stream.gcount();
|
||||
XXH3_128bits_update((XXH3_state_t*)mState, (const void*)buffer, len);
|
||||
}
|
||||
}
|
||||
|
||||
void HBXXH128::update(FILE* file)
|
||||
{
|
||||
if (!mState)
|
||||
{
|
||||
LL_WARNS() << "Cannot update a finalized digest !" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[BLOCK_LEN];
|
||||
size_t len;
|
||||
while ((len = fread((void*)buffer, 1, BLOCK_LEN, file)))
|
||||
{
|
||||
XXH3_128bits_update((XXH3_state_t*)mState, (const void*)buffer, len);
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
void HBXXH128::finalize()
|
||||
{
|
||||
if (!mState)
|
||||
{
|
||||
LL_WARNS() << "Already finalized !" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
XXH128_hash_t hash = XXH3_128bits_digest((XXH3_state_t*)mState);
|
||||
U64* data = (U64*)mDigest.mData;
|
||||
// Note: we do not check endianness here and we just store in the same
|
||||
// order as XXH128_hash_t, that is low word "first".
|
||||
data[0] = hash.low64;
|
||||
data[1] = hash.high64;
|
||||
XXH3_freeState((XXH3_state_t*)mState);
|
||||
mState = NULL;
|
||||
}
|
||||
|
||||
const LLUUID& HBXXH128::digest() const
|
||||
{
|
||||
if (mState)
|
||||
{
|
||||
XXH128_hash_t hash = XXH3_128bits_digest((XXH3_state_t*)mState);
|
||||
// We cheat the const-ness of the method here, but this is OK, since
|
||||
// mDigest is private and cannot be accessed indirectly by other
|
||||
// methods than digest() ones, that do check for mState to decide
|
||||
// wether mDigest's current value may be provided as is or not. This
|
||||
// cheat saves us a temporary LLLUID copy.
|
||||
U64* data = (U64*)mDigest.mData;
|
||||
// Note: we do not check endianness here and we just store in the same
|
||||
// order as XXH128_hash_t, that is low word "first".
|
||||
data[0] = hash.low64;
|
||||
data[1] = hash.high64;
|
||||
}
|
||||
return mDigest;
|
||||
}
|
||||
|
||||
void HBXXH128::digest(LLUUID& result) const
|
||||
{
|
||||
if (!mState)
|
||||
{
|
||||
result = mDigest;
|
||||
return;
|
||||
}
|
||||
XXH128_hash_t hash = XXH3_128bits_digest((XXH3_state_t*)mState);
|
||||
U64* data = (U64*)result.mData;
|
||||
// Note: we do not check endianness here and we just store in the same
|
||||
// order as XXH128_hash_t, that is low word "first".
|
||||
data[0] = hash.low64;
|
||||
data[1] = hash.high64;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, HBXXH128 context)
|
||||
{
|
||||
stream << context.digest();
|
||||
return stream;
|
||||
}
|
||||
|
|
@ -0,0 +1,259 @@
|
|||
/**
|
||||
* @file hbxxh.h
|
||||
* @brief High performances vectorized hashing based on xxHash.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (c) 2023, Henri Beauchamp.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_HBXXH_H
|
||||
#define LL_HBXXH_H
|
||||
|
||||
#include "lluuid.h"
|
||||
|
||||
// HBXXH* classes are to be used where speed matters and cryptographic quality
|
||||
// is not required (no "one-way" guarantee, though they are likely not worst in
|
||||
// this respect than MD5 which got busted and is now considered too weak). The
|
||||
// xxHash code they are built upon is vectorized and about 50 times faster than
|
||||
// MD5. A 64 bits hash class is also provided for when 128 bits of entropy are
|
||||
// not needed. The hashes collision rate is similar to MD5's.
|
||||
// See https://github.com/Cyan4973/xxHash#readme for details.
|
||||
|
||||
// 64 bits hashing class
|
||||
|
||||
class HBXXH64
|
||||
{
|
||||
friend std::ostream& operator<<(std::ostream&, HBXXH64);
|
||||
|
||||
protected:
|
||||
LOG_CLASS(HBXXH64);
|
||||
|
||||
public:
|
||||
inline HBXXH64() { init(); }
|
||||
|
||||
// Constructors for special circumstances; they all digest the first passed
|
||||
// parameter. Set 'do_finalize' to false if you do not want to finalize the
|
||||
// context, which is useful/needed when you want to update() it afterwards.
|
||||
// Ideally, the compiler should be smart enough to get our clue and
|
||||
// optimize out the const bool test during inlining...
|
||||
|
||||
inline HBXXH64(const void* buffer, size_t len,
|
||||
const bool do_finalize = true)
|
||||
{
|
||||
init();
|
||||
update(buffer, len);
|
||||
if (do_finalize)
|
||||
{
|
||||
finalize();
|
||||
}
|
||||
}
|
||||
|
||||
inline HBXXH64(const std::string& str, const bool do_finalize = true)
|
||||
{
|
||||
init();
|
||||
update(str);
|
||||
if (do_finalize)
|
||||
{
|
||||
finalize();
|
||||
}
|
||||
}
|
||||
|
||||
inline HBXXH64(std::istream& s, const bool do_finalize = true)
|
||||
{
|
||||
init();
|
||||
update(s);
|
||||
if (do_finalize)
|
||||
{
|
||||
finalize();
|
||||
}
|
||||
}
|
||||
|
||||
inline HBXXH64(FILE* file, const bool do_finalize = true)
|
||||
{
|
||||
init();
|
||||
update(file);
|
||||
if (do_finalize)
|
||||
{
|
||||
finalize();
|
||||
}
|
||||
}
|
||||
|
||||
~HBXXH64();
|
||||
|
||||
void update(const void* buffer, size_t len);
|
||||
void update(const std::string& str);
|
||||
void update(std::istream& s);
|
||||
void update(FILE* file);
|
||||
|
||||
// Note that unlike what happens with LLMD5, you do not need to finalize()
|
||||
// HBXXH64 before using digest(), and you may keep updating() it even after
|
||||
// you got a first digest() (the next digest would of course change after
|
||||
// any update). It is still useful to use finalize() when you do not want
|
||||
// to store a final digest() result in a separate U64; after this method
|
||||
// has been called, digest() simply returns mDigest value.
|
||||
void finalize();
|
||||
|
||||
U64 digest() const;
|
||||
|
||||
// Fast static methods. Use them when hashing just one contiguous block of
|
||||
// data.
|
||||
static U64 digest(const void* buffer, size_t len);
|
||||
static U64 digest(const char* str); // str must be NUL-terminated
|
||||
static U64 digest(const std::string& str);
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
||||
private:
|
||||
// We use a void pointer to avoid including xxhash.h here for XXH3_state_t
|
||||
// (which cannot either be trivially forward-declared, due to complex API
|
||||
// related pre-processor macros in xxhash.h).
|
||||
void* mState;
|
||||
U64 mDigest;
|
||||
};
|
||||
|
||||
inline bool operator==(const HBXXH64& a, const HBXXH64& b)
|
||||
{
|
||||
return a.digest() == b.digest();
|
||||
}
|
||||
|
||||
inline bool operator!=(const HBXXH64& a, const HBXXH64& b)
|
||||
{
|
||||
return a.digest() != b.digest();
|
||||
}
|
||||
|
||||
// 128 bits hashing class
|
||||
|
||||
class HBXXH128
|
||||
{
|
||||
friend std::ostream& operator<<(std::ostream&, HBXXH128);
|
||||
|
||||
protected:
|
||||
LOG_CLASS(HBXXH128);
|
||||
|
||||
public:
|
||||
inline HBXXH128() { init(); }
|
||||
|
||||
// Constructors for special circumstances; they all digest the first passed
|
||||
// parameter. Set 'do_finalize' to false if you do not want to finalize the
|
||||
// context, which is useful/needed when you want to update() it afterwards.
|
||||
// Ideally, the compiler should be smart enough to get our clue and
|
||||
// optimize out the const bool test during inlining...
|
||||
|
||||
inline HBXXH128(const void* buffer, size_t len,
|
||||
const bool do_finalize = true)
|
||||
{
|
||||
init();
|
||||
update(buffer, len);
|
||||
if (do_finalize)
|
||||
{
|
||||
finalize();
|
||||
}
|
||||
}
|
||||
|
||||
inline HBXXH128(const std::string& str, const bool do_finalize = true)
|
||||
{
|
||||
init();
|
||||
update(str);
|
||||
if (do_finalize)
|
||||
{
|
||||
finalize();
|
||||
}
|
||||
}
|
||||
|
||||
inline HBXXH128(std::istream& s, const bool do_finalize = true)
|
||||
{
|
||||
init();
|
||||
update(s);
|
||||
if (do_finalize)
|
||||
{
|
||||
finalize();
|
||||
}
|
||||
}
|
||||
|
||||
inline HBXXH128(FILE* file, const bool do_finalize = true)
|
||||
{
|
||||
init();
|
||||
update(file);
|
||||
if (do_finalize)
|
||||
{
|
||||
finalize();
|
||||
}
|
||||
}
|
||||
|
||||
~HBXXH128();
|
||||
|
||||
void update(const void* buffer, size_t len);
|
||||
void update(const std::string& str);
|
||||
void update(std::istream& s);
|
||||
void update(FILE* file);
|
||||
|
||||
// Note that unlike what happens with LLMD5, you do not need to finalize()
|
||||
// HBXXH128 before using digest(), and you may keep updating() it even
|
||||
// after you got a first digest() (the next digest would of course change
|
||||
// after any update). It is still useful to use finalize() when you do not
|
||||
// want to store a final digest() result in a separate LLUUID; after this
|
||||
// method has been called, digest() simply returns a reference on mDigest.
|
||||
void finalize();
|
||||
|
||||
// We use an LLUUID for the digest, since this is a 128 bits wide native
|
||||
// type available in the viewer code, making it easy to manipulate. It also
|
||||
// allows to use HBXXH128 efficiently in LLUUID generate() and combine()
|
||||
// methods.
|
||||
const LLUUID& digest() const;
|
||||
|
||||
// Here, we avoid an LLUUID copy whenever we already got one to store the
|
||||
// result *and* we did not yet call finalize().
|
||||
void digest(LLUUID& result) const;
|
||||
|
||||
// Fast static methods. Use them when hashing just one contiguous block of
|
||||
// data.
|
||||
static LLUUID digest(const void* buffer, size_t len);
|
||||
static LLUUID digest(const char* str); // str must be NUL-terminated
|
||||
static LLUUID digest(const std::string& str);
|
||||
// Same as above, but saves you from an LLUUID copy when you already got
|
||||
// one for storage use.
|
||||
static void digest(LLUUID& result, const void* buffer, size_t len);
|
||||
static void digest(LLUUID& result, const char* str); // str NUL-terminated
|
||||
static void digest(LLUUID& result, const std::string& str);
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
||||
private:
|
||||
// We use a void pointer to avoid including xxhash.h here for XXH3_state_t
|
||||
// (which cannot either be trivially forward-declared, due to complex API
|
||||
// related pre-processor macros in xxhash.h).
|
||||
void* mState;
|
||||
LLUUID mDigest;
|
||||
};
|
||||
|
||||
inline bool operator==(const HBXXH128& a, const HBXXH128& b)
|
||||
{
|
||||
return a.digest() == b.digest();
|
||||
}
|
||||
|
||||
inline bool operator!=(const HBXXH128& a, const HBXXH128& b)
|
||||
{
|
||||
return a.digest() != b.digest();
|
||||
}
|
||||
|
||||
#endif // LL_HBXXH_H
|
||||
|
|
@ -96,7 +96,7 @@ namespace LLProfiler
|
|||
//// GPU Mutually exclusive with detailed memory tracing
|
||||
// #define LL_PROFILER_ENABLE_TRACY_OPENGL 0
|
||||
#define LL_PROFILER_ENABLE_TRACY_MEMORY 1
|
||||
#define LL_PROFILER_ENABLE_TRACY_OPENGL 1
|
||||
#define LL_PROFILER_ENABLE_TRACY_OPENGL 0
|
||||
|
||||
// Enable RenderDoc labeling
|
||||
#define LL_PROFILER_ENABLE_RENDER_DOC 0
|
||||
|
|
|
|||
|
|
@ -40,11 +40,12 @@
|
|||
#include "lluuid.h"
|
||||
#include "llerror.h"
|
||||
#include "llrand.h"
|
||||
#include "llmd5.h"
|
||||
#include "llstring.h"
|
||||
#include "lltimer.h"
|
||||
#include "llthread.h"
|
||||
#include "llmutex.h"
|
||||
#include "hbxxh.h"
|
||||
|
||||
#include "llprofiler.h"
|
||||
const LLUUID LLUUID::null;
|
||||
const LLTransactionID LLTransactionID::tnull;
|
||||
|
|
@ -405,11 +406,9 @@ LLUUID LLUUID::operator^(const LLUUID& rhs) const
|
|||
|
||||
void LLUUID::combine(const LLUUID& other, LLUUID& result) const
|
||||
{
|
||||
LLMD5 md5_uuid;
|
||||
md5_uuid.update((unsigned char*)mData, 16);
|
||||
md5_uuid.update((unsigned char*)other.mData, 16);
|
||||
md5_uuid.finalize();
|
||||
md5_uuid.raw_digest(result.mData);
|
||||
HBXXH128 hash((const void*)mData, 16, false); // false = do not finalize
|
||||
hash.update((const void*)other.mData, 16);
|
||||
hash.digest(result);
|
||||
}
|
||||
|
||||
LLUUID LLUUID::combine(const LLUUID &other) const
|
||||
|
|
@ -860,17 +859,12 @@ void LLUUID::generate()
|
|||
tmp >>= 8;
|
||||
mData[8] = (unsigned char) tmp;
|
||||
|
||||
LLMD5 md5_uuid;
|
||||
|
||||
md5_uuid.update(mData,16);
|
||||
md5_uuid.finalize();
|
||||
md5_uuid.raw_digest(mData);
|
||||
HBXXH128::digest(*this, (const void*)mData, 16);
|
||||
}
|
||||
|
||||
void LLUUID::generate(const std::string& hash_string)
|
||||
{
|
||||
LLMD5 md5_uuid((U8*)hash_string.c_str());
|
||||
md5_uuid.raw_digest(mData);
|
||||
HBXXH128::digest(*this, hash_string);
|
||||
}
|
||||
|
||||
U32 LLUUID::getRandomSeed()
|
||||
|
|
@ -888,13 +882,8 @@ U32 LLUUID::getRandomSeed()
|
|||
seed[7]=(unsigned char)(pid);
|
||||
getSystemTime((uuid_time_t *)(&seed[8]));
|
||||
|
||||
LLMD5 md5_seed;
|
||||
|
||||
md5_seed.update(seed,16);
|
||||
md5_seed.finalize();
|
||||
md5_seed.raw_digest(seed);
|
||||
|
||||
return(*(U32 *)seed);
|
||||
U64 seed64 = HBXXH64((const void*)seed, 16).digest();
|
||||
return U32(seed64) ^ U32(seed64 >> 32);
|
||||
}
|
||||
|
||||
BOOL LLUUID::parseUUID(const std::string& buf, LLUUID* value)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
#include "llconvexdecomposition.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llvector4a.h"
|
||||
#include "llmd5.h"
|
||||
#include "hbxxh.h"
|
||||
#include "llcontrol.h"
|
||||
|
||||
#ifdef LL_USESYSTEMLIBS
|
||||
|
|
@ -1597,7 +1597,7 @@ LLSD LLMeshSkinInfo::asLLSD(bool include_joints, bool lock_scale_if_joint_positi
|
|||
void LLMeshSkinInfo::updateHash()
|
||||
{
|
||||
// get hash of data relevant to render batches
|
||||
LLMD5 hash;
|
||||
HBXXH64 hash;
|
||||
|
||||
//mJointNames
|
||||
for (auto& name : mJointNames)
|
||||
|
|
@ -1608,24 +1608,19 @@ void LLMeshSkinInfo::updateHash()
|
|||
}
|
||||
|
||||
//mJointNums
|
||||
hash.update((U8*)&(mJointNums[0]), sizeof(S32) * mJointNums.size());
|
||||
hash.update((const void*)mJointNums.data(), sizeof(S32) * mJointNums.size());
|
||||
|
||||
//mInvBindMatrix
|
||||
F32* src = mInvBindMatrix[0].getF32ptr();
|
||||
|
||||
for (int i = 0; i < mInvBindMatrix.size() * 16; ++i)
|
||||
for (size_t i = 0, count = mInvBindMatrix.size() * 16; i < count; ++i)
|
||||
{
|
||||
S32 t = llround(src[i] * 10000.f);
|
||||
hash.update((U8*)&t, sizeof(S32));
|
||||
hash.update((const void*)&t, sizeof(S32));
|
||||
}
|
||||
//hash.update((U8*)&(mInvBindMatrix[0]), sizeof(LLMatrix4a) * mInvBindMatrix.size());
|
||||
//hash.update((const void*)mInvBindMatrix.data(), sizeof(LLMatrix4a) * mInvBindMatrix.size());
|
||||
|
||||
hash.finalize();
|
||||
|
||||
U64 digest[2];
|
||||
hash.raw_digest((U8*) digest);
|
||||
|
||||
mHash = digest[0];
|
||||
mHash = hash.digest();
|
||||
}
|
||||
|
||||
U32 LLMeshSkinInfo::sizeBytes() const
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ void APIENTRY gl_debug_callback(GLenum source,
|
|||
const GLchar* message,
|
||||
GLvoid* userParam)
|
||||
{
|
||||
if (severity != GL_DEBUG_SEVERITY_HIGH // &&
|
||||
if (severity != GL_DEBUG_SEVERITY_HIGH //&&
|
||||
//severity != GL_DEBUG_SEVERITY_MEDIUM &&
|
||||
//severity != GL_DEBUG_SEVERITY_LOW
|
||||
)
|
||||
|
|
@ -112,10 +112,28 @@ void APIENTRY gl_debug_callback(GLenum source,
|
|||
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &vao);
|
||||
GLint vbo = 0;
|
||||
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &vbo);
|
||||
GLint vbo_size = 0;
|
||||
if (vbo != 0)
|
||||
{
|
||||
glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, &vbo_size);
|
||||
}
|
||||
GLint ibo = 0;
|
||||
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &ibo);
|
||||
|
||||
if (severity == GL_DEBUG_SEVERITY_HIGH)
|
||||
GLint ibo_size = 0;
|
||||
if (ibo != 0)
|
||||
{
|
||||
glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &ibo_size);
|
||||
}
|
||||
GLint ubo = 0;
|
||||
glGetIntegerv(GL_UNIFORM_BUFFER_BINDING, &ubo);
|
||||
GLint ubo_size = 0;
|
||||
GLint ubo_immutable = 0;
|
||||
if (ubo != 0)
|
||||
{
|
||||
glGetBufferParameteriv(GL_UNIFORM_BUFFER, GL_BUFFER_SIZE, &ubo_size);
|
||||
glGetBufferParameteriv(GL_UNIFORM_BUFFER, GL_BUFFER_IMMUTABLE_STORAGE, &ubo_immutable);
|
||||
}
|
||||
//if (severity == GL_DEBUG_SEVERITY_HIGH)
|
||||
{
|
||||
LL_ERRS() << "Halting on GL Error" << LL_ENDL;
|
||||
}
|
||||
|
|
@ -1018,8 +1036,6 @@ bool LLGLManager::initGL()
|
|||
LL_ERRS("RenderInit") << "Calling init on LLGLManager after already initialized!" << LL_ENDL;
|
||||
}
|
||||
|
||||
stop_glerror();
|
||||
|
||||
#if 0 && LL_WINDOWS
|
||||
if (!glGetStringi)
|
||||
{
|
||||
|
|
@ -1055,8 +1071,6 @@ bool LLGLManager::initGL()
|
|||
}
|
||||
#endif
|
||||
|
||||
stop_glerror();
|
||||
|
||||
// Extract video card strings and convert to upper case to
|
||||
// work around driver-to-driver variation in capitalization.
|
||||
mGLVendor = ll_safe_string((const char *)glGetString(GL_VENDOR));
|
||||
|
|
@ -1128,10 +1142,8 @@ bool LLGLManager::initGL()
|
|||
mGLVendorShort = "MISC";
|
||||
}
|
||||
|
||||
stop_glerror();
|
||||
// This is called here because it depends on the setting of mIsGF2or4MX, and sets up mHasMultitexture.
|
||||
initExtensions();
|
||||
stop_glerror();
|
||||
|
||||
S32 old_vram = mVRAM;
|
||||
mVRAM = 0;
|
||||
|
|
@ -1195,29 +1207,19 @@ bool LLGLManager::initGL()
|
|||
LL_WARNS("RenderInit") << "VRAM detected via MemInfo OpenGL extension most likely broken. Reverting to " << mVRAM << " MB" << LL_ENDL;
|
||||
}
|
||||
|
||||
stop_glerror();
|
||||
|
||||
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &mNumTextureImageUnits);
|
||||
stop_glerror();
|
||||
glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &mMaxColorTextureSamples);
|
||||
stop_glerror();
|
||||
glGetIntegerv(GL_MAX_DEPTH_TEXTURE_SAMPLES, &mMaxDepthTextureSamples);
|
||||
stop_glerror();
|
||||
glGetIntegerv(GL_MAX_INTEGER_SAMPLES, &mMaxIntegerSamples);
|
||||
stop_glerror();
|
||||
glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &mMaxSampleMaskWords);
|
||||
stop_glerror();
|
||||
glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples);
|
||||
stop_glerror();
|
||||
|
||||
if (mGLVersion >= 4.59f)
|
||||
{
|
||||
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &mMaxAnisotropy);
|
||||
stop_glerror();
|
||||
}
|
||||
|
||||
initGLStates();
|
||||
stop_glerror();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -2271,7 +2273,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);
|
||||
|
|
@ -2296,7 +2298,6 @@ void do_assert_glerror()
|
|||
gFailLog << "GL Error: UNKNOWN 0x" << std::hex << error << std::dec << std::endl;
|
||||
}
|
||||
}
|
||||
error = glGetError();
|
||||
}
|
||||
|
||||
if (quit)
|
||||
|
|
@ -2412,12 +2413,13 @@ void LLGLState::checkStates(GLboolean writeAlpha)
|
|||
llassert_always(src == GL_SRC_ALPHA);
|
||||
llassert_always(dst == GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
GLboolean colorMask[4];
|
||||
glGetBooleanv(GL_COLOR_WRITEMASK, colorMask);
|
||||
llassert_always(colorMask[0]);
|
||||
llassert_always(colorMask[1]);
|
||||
llassert_always(colorMask[2]);
|
||||
llassert_always(colorMask[3] == writeAlpha);
|
||||
// disable for now until usage is consistent
|
||||
//GLboolean colorMask[4];
|
||||
//glGetBooleanv(GL_COLOR_WRITEMASK, colorMask);
|
||||
//llassert_always(colorMask[0]);
|
||||
//llassert_always(colorMask[1]);
|
||||
//llassert_always(colorMask[2]);
|
||||
// llassert_always(colorMask[3] == writeAlpha);
|
||||
|
||||
for (boost::unordered_map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin();
|
||||
iter != sStateMap.end(); ++iter)
|
||||
|
|
|
|||
|
|
@ -1043,26 +1043,10 @@ void LLGLSLShader::bind(bool rigged)
|
|||
}
|
||||
}
|
||||
|
||||
void LLGLSLShader::unbind()
|
||||
void LLGLSLShader::unbind(void)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
|
||||
gGL.flush();
|
||||
if (sCurBoundShaderPtr)
|
||||
{
|
||||
sCurBoundShaderPtr->readProfileQuery();
|
||||
}
|
||||
stop_glerror();
|
||||
LLVertexBuffer::unbind();
|
||||
glUseProgram(0);
|
||||
sCurBoundShader = 0;
|
||||
sCurBoundShaderPtr = NULL;
|
||||
stop_glerror();
|
||||
}
|
||||
|
||||
void LLGLSLShader::bindNoShader(void)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
|
||||
|
||||
LLVertexBuffer::unbind();
|
||||
|
||||
if (sCurBoundShaderPtr)
|
||||
|
|
@ -1136,6 +1120,11 @@ S32 LLGLSLShader::unbindTexture(S32 uniform, LLTexUnit::eTextureType mode)
|
|||
return uniform;
|
||||
}
|
||||
|
||||
S32 LLGLSLShader::getTextureChannel(S32 uniform) const
|
||||
{
|
||||
return mTexture[uniform];
|
||||
}
|
||||
|
||||
S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
|
||||
|
|
|
|||
|
|
@ -240,6 +240,9 @@ public:
|
|||
S32 enableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR);
|
||||
S32 disableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR);
|
||||
|
||||
// get the texture channel of the given uniform, or -1 if uniform is not used as a texture
|
||||
S32 getTextureChannel(S32 uniform) const;
|
||||
|
||||
// bindTexture returns the texture unit we've bound the texture to.
|
||||
// You can reuse the return value to unbind a texture when required.
|
||||
S32 bindTexture(const std::string& uniform, LLTexture* texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR);
|
||||
|
|
@ -251,10 +254,9 @@ public:
|
|||
void bind();
|
||||
//helper to conditionally bind mRiggedVariant instead of this
|
||||
void bind(bool rigged);
|
||||
void unbind();
|
||||
|
||||
|
||||
// Unbinds any previously bound shader by explicitly binding no shader.
|
||||
static void bindNoShader(void);
|
||||
static void unbind();
|
||||
|
||||
U32 mMatHash[LLRender::NUM_MATRIX_MODES];
|
||||
U32 mLightHash;
|
||||
|
|
|
|||
|
|
@ -1428,6 +1428,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
|
|||
{
|
||||
case GL_UNSIGNED_BYTE:
|
||||
case GL_BYTE:
|
||||
case GL_UNSIGNED_INT_8_8_8_8_REV:
|
||||
type_width = 1;
|
||||
break;
|
||||
case GL_UNSIGNED_SHORT:
|
||||
|
|
|
|||
|
|
@ -376,7 +376,7 @@ void LLPostProcess::doEffects(void)
|
|||
checkError();
|
||||
applyShaders();
|
||||
|
||||
LLGLSLShader::bindNoShader();
|
||||
LLGLSLShader::unbind();
|
||||
checkError();
|
||||
|
||||
/// Change to a perspective view
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
#include "llrendertarget.h"
|
||||
#include "lltexture.h"
|
||||
#include "llshadermgr.h"
|
||||
#include "llmd5.h"
|
||||
#include "hbxxh.h"
|
||||
|
||||
#if LL_WINDOWS
|
||||
extern void APIENTRY gl_debug_callback(GLenum source,
|
||||
|
|
@ -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;
|
||||
|
|
@ -73,7 +79,7 @@ struct LLVBCache
|
|||
std::chrono::steady_clock::time_point touched;
|
||||
};
|
||||
|
||||
static std::unordered_map<std::size_t, LLVBCache> sVBCache;
|
||||
static std::unordered_map<U64, LLVBCache> sVBCache;
|
||||
|
||||
static const GLenum sGLTextureType[] =
|
||||
{
|
||||
|
|
@ -372,11 +378,7 @@ bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth)
|
|||
|
||||
if (bindDepth)
|
||||
{
|
||||
|
||||
if (renderTarget->getDepth() && !renderTarget->canSampleDepth())
|
||||
{
|
||||
LL_ERRS() << "Cannot bind a render buffer for sampling. Allocate render target with depth buffer sampling enabled." << LL_ENDL;
|
||||
}
|
||||
llassert(renderTarget->getDepth()); // target MUST have a depth buffer attachment
|
||||
|
||||
bindManual(renderTarget->getUsage(), renderTarget->getDepth());
|
||||
}
|
||||
|
|
@ -1682,7 +1684,7 @@ void LLRender::flush()
|
|||
if (mBuffer)
|
||||
{
|
||||
|
||||
LLMD5 hash;
|
||||
HBXXH64 hash;
|
||||
U32 attribute_mask = LLGLSLShader::sCurBoundShaderPtr->mAttributeMask;
|
||||
|
||||
{
|
||||
|
|
@ -1702,8 +1704,8 @@ void LLRender::flush()
|
|||
hash.finalize();
|
||||
}
|
||||
|
||||
size_t vhash[2];
|
||||
hash.raw_digest((unsigned char*) vhash);
|
||||
|
||||
U64 vhash = hash.digest();
|
||||
|
||||
// check the VB cache before making a new vertex buffer
|
||||
// This is a giant hack to deal with (mostly) our terrible UI rendering code
|
||||
|
|
@ -1714,7 +1716,7 @@ void LLRender::flush()
|
|||
// To leverage this, we maintain a running hash of the vertex stream being
|
||||
// built up before a flush, and then check that hash against a VB
|
||||
// cache just before creating a vertex buffer in VRAM
|
||||
std::unordered_map<std::size_t, LLVBCache>::iterator cache = sVBCache.find(vhash[0]);
|
||||
std::unordered_map<U64, LLVBCache>::iterator cache = sVBCache.find(vhash);
|
||||
|
||||
LLPointer<LLVertexBuffer> vb;
|
||||
|
||||
|
|
@ -1747,7 +1749,7 @@ void LLRender::flush()
|
|||
|
||||
vb->unbind();
|
||||
|
||||
sVBCache[vhash[0]] = { vb , std::chrono::steady_clock::now() };
|
||||
sVBCache[vhash] = { vb , std::chrono::steady_clock::now() };
|
||||
|
||||
static U32 miss_count = 0;
|
||||
miss_count++;
|
||||
|
|
@ -1759,7 +1761,7 @@ void LLRender::flush()
|
|||
|
||||
using namespace std::chrono_literals;
|
||||
// every 1024 misses, clean the cache of any VBs that haven't been touched in the last second
|
||||
for (std::unordered_map<std::size_t, LLVBCache>::iterator iter = sVBCache.begin(); iter != sVBCache.end(); )
|
||||
for (std::unordered_map<U64, LLVBCache>::iterator iter = sVBCache.begin(); iter != sVBCache.end(); )
|
||||
{
|
||||
if (now - iter->second.touched > 1s)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -526,6 +526,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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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_CATEGORY_PIPELINE;
|
||||
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,61 +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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
|
|||
}
|
||||
}
|
||||
|
||||
if (features->hasScreenSpaceReflections)
|
||||
if (features->hasScreenSpaceReflections || features->hasReflectionProbes)
|
||||
{
|
||||
if (!shader->attachFragmentObject("deferred/screenSpaceReflUtil.glsl"))
|
||||
{
|
||||
|
|
@ -262,7 +262,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
|
|||
}
|
||||
}
|
||||
|
||||
if (features->hasGamma)
|
||||
if (features->hasGamma || features->isDeferred)
|
||||
{
|
||||
if (!shader->attachFragmentObject("windlight/gammaF.glsl"))
|
||||
{
|
||||
|
|
@ -278,7 +278,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
|
|||
}
|
||||
}
|
||||
|
||||
if (features->hasAtmospherics)
|
||||
if (features->hasAtmospherics || features->isDeferred)
|
||||
{
|
||||
if (!shader->attachFragmentObject("windlight/atmosphericsFuncs.glsl")) {
|
||||
return FALSE;
|
||||
|
|
@ -1250,6 +1250,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");
|
||||
|
|
@ -1326,9 +1328,12 @@ void LLShaderMgr::initAttribsAndUniforms()
|
|||
mReservedUniforms.push_back("depth_cutoff");
|
||||
mReservedUniforms.push_back("norm_cutoff");
|
||||
mReservedUniforms.push_back("shadow_target_width");
|
||||
mReservedUniforms.push_back("view_dir"); // DEFERRED_VIEW_DIR
|
||||
|
||||
llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_VIEW_DIR+1);
|
||||
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");
|
||||
|
|
@ -1445,6 +1450,7 @@ void LLShaderMgr::initAttribsAndUniforms()
|
|||
mReservedUniforms.push_back("moon_brightness");
|
||||
mReservedUniforms.push_back("cloud_variance");
|
||||
mReservedUniforms.push_back("reflection_probe_ambiance");
|
||||
mReservedUniforms.push_back("max_probe_lod");
|
||||
|
||||
mReservedUniforms.push_back("sh_input_r");
|
||||
mReservedUniforms.push_back("sh_input_g");
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -157,7 +159,10 @@ public:
|
|||
DEFERRED_DEPTH_CUTOFF, // "depth_cutoff"
|
||||
DEFERRED_NORM_CUTOFF, // "norm_cutoff"
|
||||
DEFERRED_SHADOW_TARGET_WIDTH, // "shadow_target_width"
|
||||
DEFERRED_VIEW_DIR, // "view_dir"
|
||||
|
||||
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"
|
||||
|
|
@ -276,6 +281,7 @@ public:
|
|||
CLOUD_VARIANCE, // "cloud_variance"
|
||||
|
||||
REFLECTION_PROBE_AMBIANCE, // "reflection_probe_ambiance"
|
||||
REFLECTION_PROBE_MAX_LOD, // "max_probe_lod"
|
||||
SH_INPUT_L1R, // "sh_input_r"
|
||||
SH_INPUT_L1G, // "sh_input_g"
|
||||
SH_INPUT_L1B, // "sh_input_b"
|
||||
|
|
|
|||
|
|
@ -260,6 +260,8 @@ static GLWorkQueue* sQueue = nullptr;
|
|||
static GLuint gen_buffer()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
|
||||
|
||||
GLuint ret = 0;
|
||||
constexpr U32 pool_size = 4096;
|
||||
|
||||
thread_local static GLuint sNamePool[pool_size];
|
||||
|
|
@ -269,10 +271,21 @@ static GLuint gen_buffer()
|
|||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("gen buffer");
|
||||
sIndex = pool_size;
|
||||
glGenBuffers(pool_size, sNamePool);
|
||||
if (!gGLManager.mIsAMD)
|
||||
{
|
||||
glGenBuffers(pool_size, sNamePool);
|
||||
}
|
||||
else
|
||||
{ // work around for AMD driver bug
|
||||
for (U32 i = 0; i < pool_size; ++i)
|
||||
{
|
||||
glGenBuffers(1, sNamePool + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sNamePool[--sIndex];
|
||||
ret = sNamePool[--sIndex];
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define ANALYZE_VBO_POOL 0
|
||||
|
|
@ -741,14 +754,13 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
|
|||
llassert(mGLBuffer == sGLRenderBuffer);
|
||||
llassert(mGLIndices == sGLRenderIndices);
|
||||
gGL.syncMatrices();
|
||||
|
||||
glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT,
|
||||
(GLvoid*) (indices_offset * sizeof(U16)));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1160,7 +1172,8 @@ static void flush_vbo(GLenum target, U32 start, U32 end, void* data)
|
|||
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData block");
|
||||
//LL_PROFILE_GPU_ZONE("glBufferSubData");
|
||||
U32 tend = llmin(i + block_size, end);
|
||||
glBufferSubData(target, i, tend - i+1, (U8*) data + (i-start));
|
||||
U32 size = tend - i + 1;
|
||||
glBufferSubData(target, i, size, (U8*) data + (i-start));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12716,18 +12716,6 @@ Change of this parameter will affect the layout of buttons in notification toast
|
|||
<integer>0</integer>
|
||||
</map>
|
||||
|
||||
<key>RenderPBR</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>DEPRECATED - only true supported - Use PBR rendering pipeline (Physically Based Rendering).</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
|
||||
<key>RenderDeferred</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
@ -13480,6 +13468,28 @@ Change of this parameter will affect the layout of buttons in notification toast
|
|||
<key>Value</key>
|
||||
<integer>256</integer>
|
||||
</map>
|
||||
<key>RenderReflectionProbeResolution</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Resolution of reflection probe radiance maps (requires restart). Will be set to the next highest power of two clamped to [64, 512]. Note that changing this value may consume a massive amount of video memory.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>256</integer>
|
||||
</map>
|
||||
<key>RenderReflectionProbeAmbianceScale</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Scaler to apply to reflection probes to over-brighten sky contributions to indirect light</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>F32</string>
|
||||
<key>Value</key>
|
||||
<integer>8</integer>
|
||||
</map>
|
||||
|
||||
<key>RenderReflectionProbeDrawDistance</key>
|
||||
<map>
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ uniform sampler2D lightMap;
|
|||
uniform float dist_factor;
|
||||
uniform float blur_size;
|
||||
uniform vec2 delta;
|
||||
uniform vec2 screen_res;
|
||||
uniform vec3 kern[4];
|
||||
uniform float kern_scale;
|
||||
|
||||
|
|
@ -52,8 +53,8 @@ void main()
|
|||
vec2 tc = vary_fragcoord.xy;
|
||||
vec3 norm = getNorm(tc);
|
||||
vec3 pos = getPosition(tc).xyz;
|
||||
vec4 ccol = texture2D(lightMap, tc).rgba;
|
||||
|
||||
vec4 ccol = texture(lightMap, tc).rgba;
|
||||
|
||||
vec2 dlt = kern_scale * delta / (1.0+norm.xy*norm.xy);
|
||||
dlt /= max(-pos.z*dist_factor, 1.0);
|
||||
|
||||
|
|
@ -64,7 +65,8 @@ void main()
|
|||
float pointplanedist_tolerance_pow2 = pos.z*pos.z*0.00005;
|
||||
|
||||
// perturb sampling origin slightly in screen-space to hide edge-ghosting artifacts where smoothing radius is quite large
|
||||
float tc_mod = 0.5*(tc.x + tc.y); // mod(tc.x+tc.y,2)
|
||||
tc *= screen_res;
|
||||
float tc_mod = 0.5*(tc.x + tc.y);
|
||||
tc_mod -= floor(tc_mod);
|
||||
tc_mod *= 2.0;
|
||||
tc += ( (tc_mod - 0.5) * kern[1].z * dlt * 0.5 );
|
||||
|
|
@ -83,13 +85,14 @@ void main()
|
|||
for (int i = 1; i < 7; i++)
|
||||
{
|
||||
vec2 samptc = tc + k[i].z*dlt*2.0;
|
||||
samptc /= screen_res;
|
||||
vec3 samppos = getPosition(samptc).xyz;
|
||||
|
||||
float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane
|
||||
|
||||
if (d*d <= pointplanedist_tolerance_pow2)
|
||||
{
|
||||
col += texture2D(lightMap, samptc)*k[i].xyxx;
|
||||
col += texture(lightMap, samptc)*k[i].xyxx;
|
||||
defined_weight += k[i].xy;
|
||||
}
|
||||
}
|
||||
|
|
@ -97,19 +100,20 @@ void main()
|
|||
for (int i = 1; i < 7; i++)
|
||||
{
|
||||
vec2 samptc = tc - k[i].z*dlt*2.0;
|
||||
samptc /= screen_res;
|
||||
vec3 samppos = getPosition(samptc).xyz;
|
||||
|
||||
float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane
|
||||
|
||||
if (d*d <= pointplanedist_tolerance_pow2)
|
||||
{
|
||||
col += texture2D(lightMap, samptc)*k[i].xyxx;
|
||||
col += texture(lightMap, samptc)*k[i].xyxx;
|
||||
defined_weight += k[i].xy;
|
||||
}
|
||||
}
|
||||
|
||||
col /= defined_weight.xyxx;
|
||||
//col.y *= max(col.y, 0.75);
|
||||
//col.y *= col.y;
|
||||
|
||||
frag_color = col;
|
||||
|
||||
|
|
|
|||
|
|
@ -23,124 +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 sampler2D depthMap; // <FS:Beq/> Colour space and shader fixes for BUG-228586 (Rye)
|
||||
uniform sampler2D diffuseRect;
|
||||
uniform sampler2D specularRect;
|
||||
uniform sampler2D noiseMap;
|
||||
uniform sampler2D lightFunc;
|
||||
|
||||
uniform vec3 env_mat[3];
|
||||
uniform float sun_wash;
|
||||
uniform int light_count;
|
||||
uniform vec4 light[LIGHT_COUNT];
|
||||
uniform vec4 light_col[LIGHT_COUNT];
|
||||
|
||||
uniform vec2 screen_res;
|
||||
uniform float far_z;
|
||||
uniform mat4 inv_proj;
|
||||
|
||||
VARYING vec4 vary_fragcoord;
|
||||
|
||||
vec4 getPosition(vec2 pos_screen);
|
||||
vec3 getNorm(vec2 pos_screen);
|
||||
vec3 srgb_to_linear(vec3 c);
|
||||
float getDepth(vec2 tc);
|
||||
vec2 getScreenCoord(vec4 clip);
|
||||
|
||||
void main()
|
||||
{
|
||||
#if defined(LOCAL_LIGHT_KILL)
|
||||
discard; // Bail immediately
|
||||
#endif
|
||||
|
||||
vec3 out_col = vec3(0, 0, 0);
|
||||
vec2 frag = getScreenCoord(vary_fragcoord);
|
||||
vec3 pos = getPosition(frag.xy).xyz;
|
||||
if (pos.z < far_z)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
vec3 norm = getNorm(frag.xy);
|
||||
|
||||
vec4 spec = texture2D(specularRect, frag.xy);
|
||||
vec3 diff = texture2D(diffuseRect, frag.xy).rgb;
|
||||
|
||||
float noise = texture2D(noiseMap, frag.xy).b;
|
||||
vec3 npos = normalize(-pos);
|
||||
|
||||
// As of OSX 10.6.7 ATI Apple's crash when using a variable size loop
|
||||
for (int i = 0; i < LIGHT_COUNT; ++i)
|
||||
{
|
||||
vec3 lv = light[i].xyz - pos;
|
||||
float dist = length(lv);
|
||||
dist /= light[i].w;
|
||||
if (dist <= 1.0)
|
||||
{
|
||||
float da = dot(norm, lv);
|
||||
if (da > 0.0)
|
||||
{
|
||||
lv = normalize(lv);
|
||||
da = dot(norm, lv);
|
||||
|
||||
float fa = light_col[i].a + 1.0;
|
||||
float dist_atten = clamp(1.0 - (dist - 1.0 * (1.0 - fa)) / fa, 0.0, 1.0);
|
||||
dist_atten *= dist_atten;
|
||||
|
||||
// Tweak falloff slightly to match pre-EEP attenuation
|
||||
// NOTE: this magic number also shows up in a great many other places, search for dist_atten *= to audit
|
||||
dist_atten *= 2.0;
|
||||
|
||||
dist_atten *= noise;
|
||||
|
||||
float lit = da * dist_atten;
|
||||
|
||||
vec3 col = light_col[i].rgb * lit * diff;
|
||||
|
||||
if (spec.a > 0.0)
|
||||
{
|
||||
lit = min(da * 6.0, 1.0) * dist_atten;
|
||||
vec3 h = normalize(lv + npos);
|
||||
float nh = dot(norm, h);
|
||||
float nv = dot(norm, npos);
|
||||
float vh = dot(npos, h);
|
||||
float sa = nh;
|
||||
float fres = pow(1 - dot(h, npos), 5) * 0.4 + 0.5;
|
||||
|
||||
float gtdenom = 2 * nh;
|
||||
float gt = max(0, min(gtdenom * nv / vh, gtdenom * da / vh));
|
||||
|
||||
if (nh > 0.0)
|
||||
{
|
||||
float scol = fres * texture2D(lightFunc, vec2(nh, spec.a)).r * gt / (nh * da);
|
||||
col += lit * scol * light_col[i].rgb * spec.rgb;
|
||||
}
|
||||
}
|
||||
|
||||
out_col += col;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
frag_color.rgb = out_col;
|
||||
frag_color.a = 0.0;
|
||||
|
||||
#ifdef IS_AMD_CARD
|
||||
// If it's AMD make sure the GLSL compiler sees the arrays referenced once by static index. Otherwise it seems to optimise the storage
|
||||
// awawy which leads to unfun crashes and artifacts.
|
||||
vec4 dummy1 = light[0];
|
||||
vec4 dummy2 = light_col[0];
|
||||
vec4 dummy3 = light[LIGHT_COUNT - 1];
|
||||
vec4 dummy4 = light_col[LIGHT_COUNT - 1];
|
||||
#endif
|
||||
frag_color = vec4(0.5, 0.5, 0.0, 0.0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,113 +22,11 @@
|
|||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#extension GL_ARB_texture_rectangle : enable
|
||||
|
||||
/*[EXTRA_CODE_HERE]*/
|
||||
|
||||
#ifdef DEFINE_GL_FRAGCOLOR
|
||||
// debug stub
|
||||
out vec4 frag_color;
|
||||
#else
|
||||
#define frag_color gl_FragColor
|
||||
#endif
|
||||
|
||||
uniform sampler2D diffuseRect;
|
||||
uniform sampler2D specularRect;
|
||||
// <FS:Beq> Colour space and shader fixes for BUG-228586 (Rye)
|
||||
//uniform sampler2D normalMap;
|
||||
// </FS:Beq>
|
||||
uniform sampler2D noiseMap;
|
||||
uniform sampler2D lightFunc;
|
||||
//uniform sampler2D depthMap;// <FS:Beq/> Colour space and shader fixes for BUG-228586 (Rye)
|
||||
|
||||
uniform vec3 env_mat[3];
|
||||
uniform float sun_wash;
|
||||
|
||||
uniform vec3 color;
|
||||
uniform float falloff;
|
||||
uniform float size;
|
||||
|
||||
VARYING vec4 vary_fragcoord;
|
||||
VARYING vec3 trans_center;
|
||||
|
||||
uniform vec2 screen_res;
|
||||
|
||||
uniform mat4 inv_proj;
|
||||
uniform vec4 viewport;
|
||||
|
||||
vec3 getNorm(vec2 pos_screen);
|
||||
vec4 getPosition(vec2 pos_screen);
|
||||
float getDepth(vec2 pos);
|
||||
vec3 srgb_to_linear(vec3 c);
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 frag = vary_fragcoord;
|
||||
frag.xyz /= frag.w;
|
||||
frag.xyz = frag.xyz*0.5+0.5;
|
||||
|
||||
vec3 pos = getPosition(frag.xy).xyz;
|
||||
vec3 lv = trans_center.xyz-pos;
|
||||
float dist = length(lv);
|
||||
dist /= size;
|
||||
if (dist > 1.0)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
vec3 norm = getNorm(frag.xy);
|
||||
|
||||
float da = dot(norm, lv);
|
||||
if (da < 0.0)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
lv = normalize(lv);
|
||||
da = dot(norm, lv);
|
||||
|
||||
float noise = texture2D(noiseMap, frag.xy).b;
|
||||
|
||||
vec3 col = texture2D(diffuseRect, frag.xy).rgb;
|
||||
|
||||
float fa = falloff+1.0;
|
||||
float dist_atten = clamp(1.0-(dist-1.0*(1.0-fa))/fa, 0.0, 1.0);
|
||||
dist_atten *= dist_atten;
|
||||
dist_atten *= 2.0;
|
||||
|
||||
float lit = da * dist_atten * noise;
|
||||
|
||||
col = color.rgb*lit*col;
|
||||
|
||||
vec4 spec = texture2D(specularRect, frag.xy);
|
||||
if (spec.a > 0.0)
|
||||
{
|
||||
lit = min(da*6.0, 1.0) * dist_atten;
|
||||
|
||||
vec3 npos = -normalize(pos);
|
||||
vec3 h = normalize(lv+npos);
|
||||
float nh = dot(norm, h);
|
||||
float nv = dot(norm, npos);
|
||||
float vh = dot(npos, h);
|
||||
float sa = nh;
|
||||
float fres = pow(1 - dot(h, npos), 5) * 0.4+0.5;
|
||||
float gtdenom = 2 * nh;
|
||||
float gt = max(0,(min(gtdenom * nv / vh, gtdenom * da / vh)));
|
||||
|
||||
if (nh > 0.0)
|
||||
{
|
||||
float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt/(nh*da);
|
||||
col += lit*scol*color.rgb*spec.rgb;
|
||||
}
|
||||
}
|
||||
|
||||
if (dot(col, col) <= 0.0)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
final_color.rgb = vec3(getDepth(frag.xy));
|
||||
|
||||
frag_color.rgb = col;
|
||||
frag_color.a = 0.0;
|
||||
frag_color = vec4(0.0, 0.5, 0.5, 0.0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,7 +84,9 @@ void main()
|
|||
//this is the one of the rare spots where diffuseRect contains linear color values (not sRGB)
|
||||
vec4 diff = texture2D(diffuseRect, vary_fragcoord);
|
||||
diff.rgb = linear_to_srgb(diff.rgb);
|
||||
vec3 seed = (diff.rgb+vec3(1.0))*vec3(vary_fragcoord.xy, vary_fragcoord.x+vary_fragcoord.y);
|
||||
vec2 tc = vary_fragcoord.xy*screen_res;
|
||||
|
||||
vec3 seed = (diff.rgb+vec3(1.0))*vec3(tc.xy, tc.x+tc.y);
|
||||
vec3 nz = vec3(noise(seed.rg), noise(seed.gb), noise(seed.rb));
|
||||
diff.rgb += nz*0.008;
|
||||
//diff.rgb = nz;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,12 +25,18 @@
|
|||
|
||||
uniform sampler2D normalMap;
|
||||
uniform sampler2D depthMap;
|
||||
|
||||
#if defined(SUN_SHADOW)
|
||||
uniform sampler2DShadow shadowMap0;
|
||||
uniform sampler2DShadow shadowMap1;
|
||||
uniform sampler2DShadow shadowMap2;
|
||||
uniform sampler2DShadow shadowMap3;
|
||||
#endif
|
||||
|
||||
#if defined(SPOT_SHADOW)
|
||||
uniform sampler2DShadow shadowMap4;
|
||||
uniform sampler2DShadow shadowMap5;
|
||||
#endif
|
||||
|
||||
uniform vec3 sun_dir;
|
||||
uniform vec3 moon_dir;
|
||||
|
|
@ -48,6 +54,7 @@ uniform int sun_up_factor;
|
|||
|
||||
float pcfShadow(sampler2DShadow shadowMap, vec3 norm, vec4 stc, float bias_mul, vec2 pos_screen, vec3 light_dir)
|
||||
{
|
||||
#if defined(SUN_SHADOW)
|
||||
float offset = shadow_bias * bias_mul;
|
||||
stc.xyz /= stc.w;
|
||||
stc.z += offset * 2.0;
|
||||
|
|
@ -59,10 +66,14 @@ float pcfShadow(sampler2DShadow shadowMap, vec3 norm, vec4 stc, float bias_mul,
|
|||
shadow += shadow2D(shadowMap, stc.xyz+vec3(-1.5/shadow_res.x, -0.5/shadow_res.y, 0.0)).x;
|
||||
shadow += shadow2D(shadowMap, stc.xyz+vec3(-0.5/shadow_res.x, 1.5/shadow_res.y, 0.0)).x;
|
||||
return clamp(shadow * 0.125, 0.0, 1.0);
|
||||
#else
|
||||
return 1.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
float pcfSpotShadow(sampler2DShadow shadowMap, vec4 stc, float bias_scale, vec2 pos_screen)
|
||||
{
|
||||
#if defined(SPOT_SHADOW)
|
||||
stc.xyz /= stc.w;
|
||||
stc.z += spot_shadow_bias * bias_scale;
|
||||
stc.x = floor(proj_shadow_res.x * stc.x + fract(pos_screen.y*0.666666666)) / proj_shadow_res.x; // snap
|
||||
|
|
@ -78,10 +89,14 @@ float pcfSpotShadow(sampler2DShadow shadowMap, vec4 stc, float bias_scale, vec2
|
|||
shadow += shadow2D(shadowMap, stc.xyz+vec3(-off.x, off.y, 0.0)).x;
|
||||
shadow += shadow2D(shadowMap, stc.xyz+vec3(-off.x*2.0, -off.y, 0.0)).x;
|
||||
return shadow*0.2;
|
||||
#else
|
||||
return 1.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen)
|
||||
{
|
||||
#if defined(SUN_SHADOW)
|
||||
float shadow = 0.0f;
|
||||
vec3 light_dir = normalize((sun_up_factor == 1) ? sun_dir : moon_dir);
|
||||
|
||||
|
|
@ -175,10 +190,14 @@ float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen)
|
|||
}
|
||||
//shadow = min(dp_directional_light,shadow);
|
||||
return shadow;
|
||||
#else
|
||||
return 1.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
float sampleSpotShadow(vec3 pos, vec3 norm, int index, vec2 pos_screen)
|
||||
{
|
||||
#if defined(SPOT_SHADOW)
|
||||
float shadow = 0.0f;
|
||||
pos += norm * spot_shadow_offset;
|
||||
|
||||
|
|
@ -217,5 +236,8 @@ float sampleSpotShadow(vec3 pos, vec3 norm, int index, vec2 pos_screen)
|
|||
shadow = 1.0f;
|
||||
}
|
||||
return shadow;
|
||||
#else
|
||||
return 1.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ VARYING vec2 vary_texcoord0;
|
|||
VARYING vec2 screenpos;
|
||||
|
||||
uniform sampler2D diffuseMap;
|
||||
uniform sampler2D altDiffuseMap;
|
||||
uniform float blend_factor;
|
||||
uniform float custom_alpha;
|
||||
uniform float time;
|
||||
|
|
|
|||
|
|
@ -23,205 +23,11 @@
|
|||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
// debug stub
|
||||
|
||||
/*[EXTRA_CODE_HERE]*/
|
||||
|
||||
|
||||
#ifdef DEFINE_GL_FRAGCOLOR
|
||||
out vec4 frag_color;
|
||||
#else
|
||||
#define frag_color gl_FragColor
|
||||
#endif
|
||||
|
||||
uniform samplerCubeArray reflectionProbes;
|
||||
uniform int sourceIdx;
|
||||
|
||||
VARYING vec3 vary_dir;
|
||||
|
||||
|
||||
// Code below is derived from the Khronos GLTF Sample viewer:
|
||||
// https://github.com/KhronosGroup/glTF-Sample-Viewer/blob/master/source/shaders/ibl_filtering.frag
|
||||
|
||||
|
||||
#define MATH_PI 3.1415926535897932384626433832795
|
||||
|
||||
float u_roughness = 1.0;
|
||||
int u_sampleCount = 16;
|
||||
float u_lodBias = 2.0;
|
||||
int u_width = 64;
|
||||
|
||||
// Hammersley Points on the Hemisphere
|
||||
// CC BY 3.0 (Holger Dammertz)
|
||||
// http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
|
||||
// with adapted interface
|
||||
float radicalInverse_VdC(uint bits)
|
||||
{
|
||||
bits = (bits << 16u) | (bits >> 16u);
|
||||
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
|
||||
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
|
||||
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
|
||||
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
|
||||
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
|
||||
}
|
||||
|
||||
// hammersley2d describes a sequence of points in the 2d unit square [0,1)^2
|
||||
// that can be used for quasi Monte Carlo integration
|
||||
vec2 hammersley2d(int i, int N) {
|
||||
return vec2(float(i)/float(N), radicalInverse_VdC(uint(i)));
|
||||
}
|
||||
|
||||
// Hemisphere Sample
|
||||
|
||||
// TBN generates a tangent bitangent normal coordinate frame from the normal
|
||||
// (the normal must be normalized)
|
||||
mat3 generateTBN(vec3 normal)
|
||||
{
|
||||
vec3 bitangent = vec3(0.0, 1.0, 0.0);
|
||||
|
||||
float NdotUp = dot(normal, vec3(0.0, 1.0, 0.0));
|
||||
float epsilon = 0.0000001;
|
||||
/*if (1.0 - abs(NdotUp) <= epsilon)
|
||||
{
|
||||
// Sampling +Y or -Y, so we need a more robust bitangent.
|
||||
if (NdotUp > 0.0)
|
||||
{
|
||||
bitangent = vec3(0.0, 0.0, 1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
bitangent = vec3(0.0, 0.0, -1.0);
|
||||
}
|
||||
}*/
|
||||
|
||||
vec3 tangent = normalize(cross(bitangent, normal));
|
||||
bitangent = cross(normal, tangent);
|
||||
|
||||
return mat3(tangent, bitangent, normal);
|
||||
}
|
||||
|
||||
struct MicrofacetDistributionSample
|
||||
{
|
||||
float pdf;
|
||||
float cosTheta;
|
||||
float sinTheta;
|
||||
float phi;
|
||||
};
|
||||
|
||||
MicrofacetDistributionSample Lambertian(vec2 xi, float roughness)
|
||||
{
|
||||
MicrofacetDistributionSample lambertian;
|
||||
|
||||
// Cosine weighted hemisphere sampling
|
||||
// http://www.pbr-book.org/3ed-2018/Monte_Carlo_Integration/2D_Sampling_with_Multidimensional_Transformations.html#Cosine-WeightedHemisphereSampling
|
||||
lambertian.cosTheta = sqrt(1.0 - xi.y);
|
||||
lambertian.sinTheta = sqrt(xi.y); // equivalent to `sqrt(1.0 - cosTheta*cosTheta)`;
|
||||
lambertian.phi = 2.0 * MATH_PI * xi.x;
|
||||
|
||||
lambertian.pdf = lambertian.cosTheta / MATH_PI; // evaluation for solid angle, therefore drop the sinTheta
|
||||
|
||||
return lambertian;
|
||||
}
|
||||
|
||||
|
||||
// getImportanceSample returns an importance sample direction with pdf in the .w component
|
||||
vec4 getImportanceSample(int sampleIndex, vec3 N, float roughness)
|
||||
{
|
||||
// generate a quasi monte carlo point in the unit square [0.1)^2
|
||||
vec2 xi = hammersley2d(sampleIndex, u_sampleCount);
|
||||
|
||||
MicrofacetDistributionSample importanceSample;
|
||||
|
||||
// generate the points on the hemisphere with a fitting mapping for
|
||||
// the distribution (e.g. lambertian uses a cosine importance)
|
||||
importanceSample = Lambertian(xi, roughness);
|
||||
|
||||
// transform the hemisphere sample to the normal coordinate frame
|
||||
// i.e. rotate the hemisphere to the normal direction
|
||||
vec3 localSpaceDirection = normalize(vec3(
|
||||
importanceSample.sinTheta * cos(importanceSample.phi),
|
||||
importanceSample.sinTheta * sin(importanceSample.phi),
|
||||
importanceSample.cosTheta
|
||||
));
|
||||
mat3 TBN = generateTBN(N);
|
||||
vec3 direction = TBN * localSpaceDirection;
|
||||
|
||||
return vec4(direction, importanceSample.pdf);
|
||||
}
|
||||
|
||||
// Mipmap Filtered Samples (GPU Gems 3, 20.4)
|
||||
// https://developer.nvidia.com/gpugems/gpugems3/part-iii-rendering/chapter-20-gpu-based-importance-sampling
|
||||
// https://cgg.mff.cuni.cz/~jaroslav/papers/2007-sketch-fis/Final_sap_0073.pdf
|
||||
float computeLod(float pdf)
|
||||
{
|
||||
// // Solid angle of current sample -- bigger for less likely samples
|
||||
// float omegaS = 1.0 / (float(u_sampleCount) * pdf);
|
||||
// // Solid angle of texel
|
||||
// // note: the factor of 4.0 * MATH_PI
|
||||
// float omegaP = 4.0 * MATH_PI / (6.0 * float(u_width) * float(u_width));
|
||||
// // Mip level is determined by the ratio of our sample's solid angle to a texel's solid angle
|
||||
// // note that 0.5 * log2 is equivalent to log4
|
||||
// float lod = 0.5 * log2(omegaS / omegaP);
|
||||
|
||||
// babylon introduces a factor of K (=4) to the solid angle ratio
|
||||
// this helps to avoid undersampling the environment map
|
||||
// this does not appear in the original formulation by Jaroslav Krivanek and Mark Colbert
|
||||
// log4(4) == 1
|
||||
// lod += 1.0;
|
||||
|
||||
// We achieved good results by using the original formulation from Krivanek & Colbert adapted to cubemaps
|
||||
|
||||
// https://cgg.mff.cuni.cz/~jaroslav/papers/2007-sketch-fis/Final_sap_0073.pdf
|
||||
float lod = 0.5 * log2( 6.0 * float(u_width) * float(u_width) / (float(u_sampleCount) * pdf));
|
||||
|
||||
|
||||
return lod;
|
||||
}
|
||||
|
||||
vec4 filterColor(vec3 N)
|
||||
{
|
||||
//return textureLod(uCubeMap, N, 3.0).rgb;
|
||||
vec4 color = vec4(0.f);
|
||||
float weight = 0.0f;
|
||||
|
||||
for(int i = 0; i < u_sampleCount; ++i)
|
||||
{
|
||||
vec4 importanceSample = getImportanceSample(i, N, 1.0);
|
||||
|
||||
vec3 H = vec3(importanceSample.xyz);
|
||||
float pdf = importanceSample.w;
|
||||
|
||||
// mipmap filtered samples (GPU Gems 3, 20.4)
|
||||
float lod = computeLod(pdf);
|
||||
|
||||
// apply the bias to the lod
|
||||
lod += u_lodBias;
|
||||
|
||||
lod = clamp(lod, 0, 6);
|
||||
// sample lambertian at a lower resolution to avoid fireflies
|
||||
vec4 lambertian = textureLod(reflectionProbes, vec4(H, sourceIdx), lod);
|
||||
|
||||
color += lambertian;
|
||||
}
|
||||
|
||||
if(weight != 0.0f)
|
||||
{
|
||||
color /= weight;
|
||||
}
|
||||
else
|
||||
{
|
||||
color /= float(u_sampleCount);
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
// entry point
|
||||
void main()
|
||||
{
|
||||
vec4 color = vec4(0);
|
||||
|
||||
color = filterColor(vary_dir);
|
||||
|
||||
frag_color = color;
|
||||
frag_color = vec4(0.5, 0, 0.5, 0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ VARYING vec3 vary_dir;
|
|||
|
||||
uniform float mipLevel;
|
||||
uniform int u_width;
|
||||
uniform float max_probe_lod;
|
||||
|
||||
|
||||
// =============================================================================================================
|
||||
// Parts of this file are (c) 2018 Sascha Willems
|
||||
|
|
@ -128,7 +130,7 @@ vec4 prefilterEnvMap(vec3 R)
|
|||
float envMapDim = u_width;
|
||||
int numSamples = 4;
|
||||
|
||||
float numMips = 6.0;
|
||||
float numMips = max_probe_lod;
|
||||
|
||||
float roughness = mipLevel/numMips;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,218 @@
|
|||
/**
|
||||
* @file irradianceGenF.glsl
|
||||
*
|
||||
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2022, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
|
||||
/*[EXTRA_CODE_HERE]*/
|
||||
|
||||
out vec4 frag_color;
|
||||
|
||||
uniform samplerCubeArray reflectionProbes;
|
||||
uniform int sourceIdx;
|
||||
|
||||
uniform float max_probe_lod;
|
||||
uniform float ambiance_scale;
|
||||
|
||||
in vec3 vary_dir;
|
||||
|
||||
// Code below is derived from the Khronos GLTF Sample viewer:
|
||||
// https://github.com/KhronosGroup/glTF-Sample-Viewer/blob/master/source/shaders/ibl_filtering.frag
|
||||
|
||||
|
||||
#define MATH_PI 3.1415926535897932384626433832795
|
||||
|
||||
float u_roughness = 1.0;
|
||||
int u_sampleCount = 32;
|
||||
float u_lodBias = 2.0;
|
||||
int u_width = 64;
|
||||
|
||||
// Hammersley Points on the Hemisphere
|
||||
// CC BY 3.0 (Holger Dammertz)
|
||||
// http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
|
||||
// with adapted interface
|
||||
float radicalInverse_VdC(uint bits)
|
||||
{
|
||||
bits = (bits << 16u) | (bits >> 16u);
|
||||
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
|
||||
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
|
||||
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
|
||||
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
|
||||
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
|
||||
}
|
||||
|
||||
// hammersley2d describes a sequence of points in the 2d unit square [0,1)^2
|
||||
// that can be used for quasi Monte Carlo integration
|
||||
vec2 hammersley2d(int i, int N) {
|
||||
return vec2(float(i)/float(N), radicalInverse_VdC(uint(i)));
|
||||
}
|
||||
|
||||
// Hemisphere Sample
|
||||
|
||||
// TBN generates a tangent bitangent normal coordinate frame from the normal
|
||||
// (the normal must be normalized)
|
||||
mat3 generateTBN(vec3 normal)
|
||||
{
|
||||
vec3 bitangent = vec3(0.0, 1.0, 0.0);
|
||||
|
||||
float NdotUp = dot(normal, vec3(0.0, 1.0, 0.0));
|
||||
float epsilon = 0.0000001;
|
||||
/*if (1.0 - abs(NdotUp) <= epsilon)
|
||||
{
|
||||
// Sampling +Y or -Y, so we need a more robust bitangent.
|
||||
if (NdotUp > 0.0)
|
||||
{
|
||||
bitangent = vec3(0.0, 0.0, 1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
bitangent = vec3(0.0, 0.0, -1.0);
|
||||
}
|
||||
}*/
|
||||
|
||||
vec3 tangent = normalize(cross(bitangent, normal));
|
||||
bitangent = cross(normal, tangent);
|
||||
|
||||
return mat3(tangent, bitangent, normal);
|
||||
}
|
||||
|
||||
struct MicrofacetDistributionSample
|
||||
{
|
||||
float pdf;
|
||||
float cosTheta;
|
||||
float sinTheta;
|
||||
float phi;
|
||||
};
|
||||
|
||||
MicrofacetDistributionSample Lambertian(vec2 xi, float roughness)
|
||||
{
|
||||
MicrofacetDistributionSample lambertian;
|
||||
|
||||
// Cosine weighted hemisphere sampling
|
||||
// http://www.pbr-book.org/3ed-2018/Monte_Carlo_Integration/2D_Sampling_with_Multidimensional_Transformations.html#Cosine-WeightedHemisphereSampling
|
||||
lambertian.cosTheta = sqrt(1.0 - xi.y);
|
||||
lambertian.sinTheta = sqrt(xi.y); // equivalent to `sqrt(1.0 - cosTheta*cosTheta)`;
|
||||
lambertian.phi = 2.0 * MATH_PI * xi.x;
|
||||
|
||||
lambertian.pdf = lambertian.cosTheta / MATH_PI; // evaluation for solid angle, therefore drop the sinTheta
|
||||
|
||||
return lambertian;
|
||||
}
|
||||
|
||||
|
||||
// getImportanceSample returns an importance sample direction with pdf in the .w component
|
||||
vec4 getImportanceSample(int sampleIndex, vec3 N, float roughness)
|
||||
{
|
||||
// generate a quasi monte carlo point in the unit square [0.1)^2
|
||||
vec2 xi = hammersley2d(sampleIndex, u_sampleCount);
|
||||
|
||||
MicrofacetDistributionSample importanceSample;
|
||||
|
||||
// generate the points on the hemisphere with a fitting mapping for
|
||||
// the distribution (e.g. lambertian uses a cosine importance)
|
||||
importanceSample = Lambertian(xi, roughness);
|
||||
|
||||
// transform the hemisphere sample to the normal coordinate frame
|
||||
// i.e. rotate the hemisphere to the normal direction
|
||||
vec3 localSpaceDirection = normalize(vec3(
|
||||
importanceSample.sinTheta * cos(importanceSample.phi),
|
||||
importanceSample.sinTheta * sin(importanceSample.phi),
|
||||
importanceSample.cosTheta
|
||||
));
|
||||
mat3 TBN = generateTBN(N);
|
||||
vec3 direction = TBN * localSpaceDirection;
|
||||
|
||||
return vec4(direction, importanceSample.pdf);
|
||||
}
|
||||
|
||||
// Mipmap Filtered Samples (GPU Gems 3, 20.4)
|
||||
// https://developer.nvidia.com/gpugems/gpugems3/part-iii-rendering/chapter-20-gpu-based-importance-sampling
|
||||
// https://cgg.mff.cuni.cz/~jaroslav/papers/2007-sketch-fis/Final_sap_0073.pdf
|
||||
float computeLod(float pdf)
|
||||
{
|
||||
// // Solid angle of current sample -- bigger for less likely samples
|
||||
// float omegaS = 1.0 / (float(u_sampleCount) * pdf);
|
||||
// // Solid angle of texel
|
||||
// // note: the factor of 4.0 * MATH_PI
|
||||
// float omegaP = 4.0 * MATH_PI / (6.0 * float(u_width) * float(u_width));
|
||||
// // Mip level is determined by the ratio of our sample's solid angle to a texel's solid angle
|
||||
// // note that 0.5 * log2 is equivalent to log4
|
||||
// float lod = 0.5 * log2(omegaS / omegaP);
|
||||
|
||||
// babylon introduces a factor of K (=4) to the solid angle ratio
|
||||
// this helps to avoid undersampling the environment map
|
||||
// this does not appear in the original formulation by Jaroslav Krivanek and Mark Colbert
|
||||
// log4(4) == 1
|
||||
// lod += 1.0;
|
||||
|
||||
// We achieved good results by using the original formulation from Krivanek & Colbert adapted to cubemaps
|
||||
|
||||
// https://cgg.mff.cuni.cz/~jaroslav/papers/2007-sketch-fis/Final_sap_0073.pdf
|
||||
float lod = 0.5 * log2( 6.0 * float(u_width) * float(u_width) / (float(u_sampleCount) * pdf));
|
||||
|
||||
|
||||
return lod;
|
||||
}
|
||||
|
||||
vec4 filterColor(vec3 N)
|
||||
{
|
||||
//return textureLod(uCubeMap, N, 3.0).rgb;
|
||||
vec4 color = vec4(0.f);
|
||||
|
||||
for(int i = 0; i < u_sampleCount; ++i)
|
||||
{
|
||||
vec4 importanceSample = getImportanceSample(i, N, 1.0);
|
||||
|
||||
vec3 H = vec3(importanceSample.xyz);
|
||||
float pdf = importanceSample.w;
|
||||
|
||||
// mipmap filtered samples (GPU Gems 3, 20.4)
|
||||
float lod = computeLod(pdf);
|
||||
|
||||
// apply the bias to the lod
|
||||
lod += u_lodBias;
|
||||
|
||||
lod = clamp(lod, 0, 7);
|
||||
// sample lambertian at a lower resolution to avoid fireflies
|
||||
vec4 lambertian = textureLod(reflectionProbes, vec4(H, sourceIdx), lod);
|
||||
|
||||
color += lambertian;
|
||||
}
|
||||
|
||||
color /= float(u_sampleCount);
|
||||
|
||||
color.rgb *= ambiance_scale;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
// entry point
|
||||
void main()
|
||||
{
|
||||
vec4 color = vec4(0);
|
||||
|
||||
color = filterColor(vary_dir);
|
||||
|
||||
frag_color = color;
|
||||
}
|
||||
|
||||
|
|
@ -162,90 +162,10 @@ float ambientLighting(vec3 norm, vec3 light_dir)
|
|||
void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 additive,
|
||||
out vec3 atten)
|
||||
{
|
||||
#if 1
|
||||
calcAtmosphericVars(inPositionEye, light_dir, 1.0, sunlit, amblit, additive, atten, false);
|
||||
sunlit = srgb_to_linear(sunlit);
|
||||
additive = srgb_to_linear(additive);
|
||||
amblit = ambient_linear;
|
||||
|
||||
amblit *= ambientLighting(norm, light_dir);
|
||||
#else
|
||||
|
||||
//EXPERIMENTAL -- attempt to factor out srgb_to_linear conversions above
|
||||
vec3 rel_pos = inPositionEye;
|
||||
|
||||
//(TERRAIN) limit altitude
|
||||
if (abs(rel_pos.y) > max_y) rel_pos *= (max_y / rel_pos.y);
|
||||
|
||||
vec3 rel_pos_norm = normalize(rel_pos);
|
||||
float rel_pos_len = length(rel_pos);
|
||||
vec3 sunlight = (sun_up_factor == 1) ? vec3(sunlight_linear, 0.0) : vec3(moonlight_linear, 0.0);
|
||||
|
||||
// sunlight attenuation effect (hue and brightness) due to atmosphere
|
||||
// this is used later for sunlight modulation at various altitudes
|
||||
vec3 light_atten = (blue_density + vec3(haze_density * 0.25)) * (density_multiplier * max_y);
|
||||
// I had thought blue_density and haze_density should have equal weighting,
|
||||
// but attenuation due to haze_density tends to seem too strong
|
||||
|
||||
vec3 combined_haze = blue_density + vec3(haze_density);
|
||||
vec3 blue_weight = blue_density / combined_haze;
|
||||
vec3 haze_weight = vec3(haze_density) / combined_haze;
|
||||
|
||||
//(TERRAIN) compute sunlight from lightnorm y component. Factor is roughly cosecant(sun elevation) (for short rays like terrain)
|
||||
float above_horizon_factor = 1.0 / max(1e-6, lightnorm.y);
|
||||
sunlight *= exp(-light_atten * above_horizon_factor); // for sun [horizon..overhead] this maps to an exp curve [0..1]
|
||||
|
||||
// main atmospheric scattering line integral
|
||||
float density_dist = rel_pos_len * density_multiplier;
|
||||
|
||||
// Transparency (-> combined_haze)
|
||||
// ATI Bugfix -- can't store combined_haze*density_dist*distance_multiplier in a variable because the ati
|
||||
// compiler gets confused.
|
||||
combined_haze = exp(-combined_haze * density_dist * distance_multiplier);
|
||||
|
||||
// final atmosphere attenuation factor
|
||||
atten = combined_haze.rgb;
|
||||
|
||||
// compute haze glow
|
||||
float haze_glow = dot(rel_pos_norm, lightnorm.xyz);
|
||||
|
||||
// dampen sun additive contrib when not facing it...
|
||||
// SL-13539: This "if" clause causes an "additive" white artifact at roughly 77 degreees.
|
||||
// if (length(light_dir) > 0.01)
|
||||
haze_glow *= max(0.0f, dot(light_dir, rel_pos_norm));
|
||||
|
||||
haze_glow = 1. - haze_glow;
|
||||
// haze_glow is 0 at the sun and increases away from sun
|
||||
haze_glow = max(haze_glow, .001); // set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot)
|
||||
haze_glow *= glow.x;
|
||||
// higher glow.x gives dimmer glow (because next step is 1 / "angle")
|
||||
haze_glow = pow(haze_glow, glow.z);
|
||||
// glow.z should be negative, so we're doing a sort of (1 / "angle") function
|
||||
|
||||
// add "minimum anti-solar illumination"
|
||||
haze_glow += .25;
|
||||
|
||||
haze_glow *= sun_moon_glow_factor;
|
||||
|
||||
//vec3 amb_color = vec4(ambient_linear, 0.0);
|
||||
vec3 amb_color = ambient_color;
|
||||
|
||||
// increase ambient when there are more clouds
|
||||
vec3 tmpAmbient = amb_color + (vec3(1.) - amb_color) * cloud_shadow * 0.5;
|
||||
|
||||
// Similar/Shared Algorithms:
|
||||
// indra\llinventory\llsettingssky.cpp -- LLSettingsSky::calculateLightSettings()
|
||||
// indra\newview\app_settings\shaders\class1\windlight\atmosphericsFuncs.glsl -- calcAtmosphericVars()
|
||||
// haze color
|
||||
vec3 cs = sunlight.rgb * (1. - cloud_shadow);
|
||||
additive = (blue_horizon.rgb * blue_weight.rgb) * (cs + tmpAmbient.rgb) + (haze_horizon * haze_weight.rgb) * (cs * haze_glow + tmpAmbient.rgb);
|
||||
|
||||
// brightness of surface both sunlight and ambient
|
||||
sunlit = min(sunlight.rgb, vec3(1));
|
||||
amblit = tmpAmbient.rgb;
|
||||
additive *= vec3(1.0 - combined_haze);
|
||||
|
||||
//sunlit = sunlight_linear;
|
||||
amblit = ambient_linear*0.8;
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -25,11 +25,18 @@
|
|||
|
||||
#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;
|
||||
uniform float max_probe_lod;
|
||||
|
||||
layout (std140) uniform ReflectionProbes
|
||||
{
|
||||
|
|
@ -92,14 +99,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 +148,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 +163,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 +178,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 +193,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 +339,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 +349,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 +425,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 +466,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 +509,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 +519,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;
|
||||
|
|
@ -600,15 +624,15 @@ vec3 sampleProbeAmbient(vec3 pos, vec3 dir)
|
|||
{
|
||||
col *= 1.0/wsum;
|
||||
}
|
||||
|
||||
|
||||
return col;
|
||||
}
|
||||
|
||||
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;
|
||||
float reflection_lods = max_probe_lod;
|
||||
preProbeSample(pos);
|
||||
|
||||
vec3 refnormpersp = reflect(pos.xyz, norm.xyz);
|
||||
|
|
@ -617,6 +641,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,23 +695,22 @@ 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;
|
||||
float reflection_lods = max_probe_lod;
|
||||
preProbeSample(pos);
|
||||
|
||||
vec3 refnormpersp = reflect(pos.xyz, norm.xyz);
|
||||
|
||||
|
||||
ambenv = sampleProbeAmbient(pos, norm);
|
||||
|
||||
if (glossiness > 0.0)
|
||||
|
|
@ -689,6 +723,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)
|
||||
|
|
|
|||
|
|
@ -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,62 +54,45 @@ 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);
|
||||
void main() {
|
||||
|
||||
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;
|
||||
|
||||
if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR)) {
|
||||
frag_color = texture(diffuseMap, tc);
|
||||
|
||||
if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR))
|
||||
{
|
||||
vec3 orm = specCol.rgb;
|
||||
float perceptualRoughness = orm.g;
|
||||
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);
|
||||
int totalSamples = 4;
|
||||
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 w = tapScreenSpaceReflection(4, tc, pos, n, collectedColor, diffuseMap);
|
||||
|
||||
bool hit = traceScreenRay(pos, reflectionDirectionRandomized, hitpoint, depth, depth, diffuseMap);
|
||||
if (hit) {
|
||||
collectedColor += hitpoint;
|
||||
collectedColor.rgb *= specCol.rgb;
|
||||
}
|
||||
}
|
||||
collectedColor.rgb *= specCol.rgb;
|
||||
|
||||
collectedColor *= vignette;
|
||||
|
||||
frag_color += collectedColor;
|
||||
frag_color += collectedColor * w;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,31 +23,32 @@
|
|||
* $/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) {
|
||||
return fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453123); //simple random function
|
||||
float random (vec2 uv)
|
||||
{
|
||||
return fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453123); //simple random function
|
||||
}
|
||||
|
||||
// Based off of https://github.com/RoundedGlint585/ScreenSpaceReflection/
|
||||
// A few tweaks here and there to suit our needs.
|
||||
|
||||
vec2 generateProjectedPosition(vec3 pos){
|
||||
vec4 samplePosition = projection_matrix * vec4(pos, 1.f);
|
||||
samplePosition.xy = (samplePosition.xy / samplePosition.w) * 0.5 + 0.5;
|
||||
return samplePosition.xy;
|
||||
vec2 generateProjectedPosition(vec3 pos)
|
||||
{
|
||||
vec4 samplePosition = projection_matrix * vec4(pos, 1.f);
|
||||
samplePosition.xy = (samplePosition.xy / samplePosition.w) * 0.5 + 0.5;
|
||||
return samplePosition.xy;
|
||||
}
|
||||
|
||||
bool isBinarySearchEnabled = true;
|
||||
|
|
@ -60,79 +61,174 @@ float distanceBias = 0.02;
|
|||
float depthRejectBias = 0.001;
|
||||
float epsilon = 0.1;
|
||||
|
||||
bool traceScreenRay(vec3 position, vec3 reflection, out vec4 hitColor, out float hitDepth, float depth, sampler2D textureFrame) {
|
||||
vec3 step = rayStep * reflection;
|
||||
vec3 marchingPosition = position + step;
|
||||
float delta;
|
||||
float depthFromScreen;
|
||||
vec2 screenPosition;
|
||||
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;
|
||||
float depthFromScreen;
|
||||
vec2 screenPosition;
|
||||
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);
|
||||
delta = abs(marchingPosition.z) - depthFromScreen;
|
||||
|
||||
if (depth < depthFromScreen + epsilon && depth > depthFromScreen - epsilon) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
int i = 0;
|
||||
if (depth > depthRejectBias)
|
||||
{
|
||||
for (; i < iterationCount && !hit; i++)
|
||||
{
|
||||
screenPosition = generateProjectedPosition(marchingPosition);
|
||||
depthFromScreen = getLinearDepth(screenPosition);
|
||||
delta = abs(marchingPosition.z) - depthFromScreen;
|
||||
|
||||
if (depth < depthFromScreen + epsilon && depth > depthFromScreen - epsilon)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (abs(delta) < distanceBias) {
|
||||
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;
|
||||
hitDepth = depthFromScreen;
|
||||
hit = true;
|
||||
break;
|
||||
}
|
||||
if (isBinarySearchEnabled && delta > 0) {
|
||||
break;
|
||||
}
|
||||
if (isAdaptiveStepEnabled){
|
||||
float directionSign = sign(abs(marchingPosition.z) - depthFromScreen);
|
||||
//this is sort of adapting step, should prevent lining reflection by doing sort of iterative converging
|
||||
//some implementation doing it by binary search, but I found this idea more cheaty and way easier to implement
|
||||
step = step * (1.0 - rayStep * max(directionSign, 0.0));
|
||||
marchingPosition += step * (-directionSign);
|
||||
}
|
||||
else {
|
||||
marchingPosition += step;
|
||||
}
|
||||
if (abs(delta) < distanceBias)
|
||||
{
|
||||
vec4 color = vec4(1);
|
||||
if(debugDraw)
|
||||
color = vec4( 0.5+ sign(delta)/2,0.3,0.5- sign(delta)/2, 0);
|
||||
hitColor = texture(sceneMap, screenPosition) * color;
|
||||
hitDepth = depthFromScreen;
|
||||
hit = true;
|
||||
break;
|
||||
}
|
||||
if (isBinarySearchEnabled && delta > 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (isAdaptiveStepEnabled)
|
||||
{
|
||||
float directionSign = sign(abs(marchingPosition.z) - depthFromScreen);
|
||||
//this is sort of adapting step, should prevent lining reflection by doing sort of iterative converging
|
||||
//some implementation doing it by binary search, but I found this idea more cheaty and way easier to implement
|
||||
step = step * (1.0 - rayStep * max(directionSign, 0.0));
|
||||
marchingPosition += step * (-directionSign);
|
||||
}
|
||||
else
|
||||
{
|
||||
marchingPosition += step;
|
||||
}
|
||||
|
||||
if (isExponentialStepEnabled){
|
||||
step *= 1.05;
|
||||
}
|
||||
}
|
||||
if(isBinarySearchEnabled){
|
||||
for(; i < iterationCount && !hit; i++){
|
||||
|
||||
step *= 0.5;
|
||||
marchingPosition = marchingPosition - step * sign(delta);
|
||||
|
||||
screenPosition = generateProjectedPosition(marchingPosition);
|
||||
depthFromScreen = linearDepth(getDepth(screenPosition), zNear, zFar);
|
||||
delta = abs(marchingPosition.z) - depthFromScreen;
|
||||
if (isExponentialStepEnabled)
|
||||
{
|
||||
step *= 1.05;
|
||||
}
|
||||
}
|
||||
if(isBinarySearchEnabled)
|
||||
{
|
||||
for(; i < iterationCount && !hit; i++)
|
||||
{
|
||||
step *= 0.5;
|
||||
marchingPosition = marchingPosition - step * sign(delta);
|
||||
|
||||
screenPosition = generateProjectedPosition(marchingPosition);
|
||||
depthFromScreen = getLinearDepth(screenPosition);
|
||||
delta = abs(marchingPosition.z) - depthFromScreen;
|
||||
|
||||
if (depth < depthFromScreen + epsilon && depth > depthFromScreen - epsilon) {
|
||||
break;
|
||||
}
|
||||
if (depth < depthFromScreen + epsilon && depth > depthFromScreen - epsilon)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (abs(delta) < distanceBias && depthFromScreen != (depth - distanceBias)) {
|
||||
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;
|
||||
hitDepth = depthFromScreen;
|
||||
hit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (abs(delta) < distanceBias && depthFromScreen != (depth - distanceBias))
|
||||
{
|
||||
vec4 color = vec4(1);
|
||||
if(debugDraw)
|
||||
color = vec4( 0.5+ sign(delta)/2,0.3,0.5- sign(delta)/2, 0);
|
||||
hitColor = texture(sceneMap, screenPosition) * color;
|
||||
hitDepth = depthFromScreen;
|
||||
hit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ uniform sampler2D diffuseRect;
|
|||
uniform sampler2D specularRect;
|
||||
uniform sampler2D normalMap;
|
||||
uniform sampler2D emissiveRect; // PBR linear packed Occlusion, Roughness, Metal. See: pbropaqueF.glsl
|
||||
uniform sampler2D altDiffuseMap; // PBR: irradiance, skins/default/textures/default_irradiance.png
|
||||
|
||||
const float M_PI = 3.14159265;
|
||||
|
||||
|
|
@ -76,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);
|
||||
|
|
@ -167,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
|
||||
|
|
@ -197,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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
version 45
|
||||
version 47
|
||||
// The version number above should be incremented IF AND ONLY IF some
|
||||
// change has been made that is sufficiently important to justify
|
||||
// resetting the graphics preferences of all users to the recommended
|
||||
|
|
@ -62,7 +62,6 @@ Disregard128DefaultDrawDistance 1 1
|
|||
Disregard96DefaultDrawDistance 1 1
|
||||
RenderCompressTextures 1 1
|
||||
RenderShaderLightingMaxLevel 1 3
|
||||
RenderPBR 1 1
|
||||
RenderReflectionProbeCount 1 256
|
||||
RenderDeferred 1 1
|
||||
RenderDeferredSSAO 1 1
|
||||
|
|
@ -73,6 +72,7 @@ RenderFSAASamples 1 16
|
|||
RenderMaxTextureIndex 1 16
|
||||
RenderGLContextCoreProfile 1 1
|
||||
RenderGLMultiThreaded 1 0
|
||||
RenderReflectionProbeResolution 1 256
|
||||
|
||||
|
||||
//
|
||||
|
|
@ -272,6 +272,12 @@ RenderUseAdvancedAtmospherics 1 0
|
|||
list VRAMGT512
|
||||
RenderCompressTextures 1 0
|
||||
|
||||
//
|
||||
// VRAM < 2GB
|
||||
//
|
||||
list VRAMLT2GB
|
||||
RenderReflectionProbeResolution 1 128
|
||||
|
||||
//
|
||||
// "Default" setups for safe, low, medium, high
|
||||
//
|
||||
|
|
@ -292,6 +298,9 @@ RenderAnisotropic 1 0
|
|||
RenderFSAASamples 1 0
|
||||
RenderGLContextCoreProfile 1 0
|
||||
|
||||
list AMD
|
||||
RenderGLMultiThreaded 1 1
|
||||
|
||||
list GL3
|
||||
RenderFSAASamples 0 0
|
||||
RenderReflectionsEnabled 0 0
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
version 35
|
||||
version 36
|
||||
// The version number above should be incremented IF AND ONLY IF some
|
||||
// change has been made that is sufficiently important to justify
|
||||
// resetting the graphics preferences of all users to the recommended
|
||||
|
|
@ -62,7 +62,6 @@ Disregard128DefaultDrawDistance 1 1
|
|||
Disregard96DefaultDrawDistance 1 1
|
||||
RenderCompressTextures 1 1
|
||||
RenderShaderLightingMaxLevel 1 3
|
||||
RenderPBR 1 1
|
||||
RenderReflectionProbeCount 1 256
|
||||
RenderDeferred 1 1
|
||||
RenderDeferredSSAO 1 1
|
||||
|
|
@ -73,6 +72,7 @@ RenderFSAASamples 1 16
|
|||
RenderMaxTextureIndex 1 16
|
||||
RenderGLContextCoreProfile 1 1
|
||||
RenderGLMultiThreaded 1 0
|
||||
RenderReflectionProbeResolution 1 256
|
||||
|
||||
|
||||
//
|
||||
|
|
@ -272,6 +272,12 @@ RenderUseAdvancedAtmospherics 1 0
|
|||
list VRAMGT512
|
||||
RenderCompressTextures 1 0
|
||||
|
||||
//
|
||||
// VRAM < 2GB
|
||||
//
|
||||
list VRAMLT2GB
|
||||
RenderReflectionProbeResolution 1 128
|
||||
|
||||
//
|
||||
// "Default" setups for safe, low, medium, high
|
||||
//
|
||||
|
|
|
|||
|
|
@ -61,7 +61,6 @@ Disregard96DefaultDrawDistance 1 1
|
|||
RenderCompressTextures 1 1
|
||||
RenderShaderLightingMaxLevel 1 3
|
||||
RenderDeferred 1 1
|
||||
RenderPBR 1 1
|
||||
RenderDeferredSSAO 1 1
|
||||
RenderUseAdvancedAtmospherics 1 0
|
||||
RenderShadowDetail 1 2
|
||||
|
|
|
|||
|
|
@ -88,11 +88,6 @@ void LLDrawPoolAlpha::prerender()
|
|||
// TODO: is this even necessay? These are probably set to never discard
|
||||
LLViewerFetchedTexture::sFlatNormalImagep->addTextureStats(1024.f*1024.f);
|
||||
LLViewerFetchedTexture::sWhiteImagep->addTextureStats(1024.f * 1024.f);
|
||||
|
||||
if (LLPipeline::sRenderPBR)
|
||||
{
|
||||
gPipeline.setupHWLights(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
S32 LLDrawPoolAlpha::getNumPostDeferredPasses()
|
||||
|
|
@ -200,10 +195,6 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass)
|
|||
if (!LLPipeline::sImpostorRender && gSavedSettings.getBOOL("RenderDepthOfField") && !gCubeSnapshot)
|
||||
{
|
||||
//update depth buffer sampler
|
||||
/*gPipeline.mRT->screen.flush();
|
||||
gPipeline.mRT->deferredDepth.copyContents(gPipeline.mRT->deferredScreen, 0, 0, gPipeline.mRT->deferredScreen.getWidth(), gPipeline.mRT->deferredScreen.getHeight(),
|
||||
0, 0, gPipeline.mRT->deferredDepth.getWidth(), gPipeline.mRT->deferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
|
||||
gPipeline.mRT->deferredDepth.bindTarget();*/
|
||||
simple_shader = fullbright_shader = &gObjectFullbrightAlphaMaskProgram;
|
||||
|
||||
simple_shader->bind();
|
||||
|
|
@ -217,8 +208,6 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass)
|
|||
renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2,
|
||||
true); // <--- discard mostly transparent faces
|
||||
|
||||
//gPipeline.mRT->deferredDepth.flush();
|
||||
//gPipeline.mRT->screen.bindTarget();
|
||||
gGL.setColorMask(true, false);
|
||||
}
|
||||
|
||||
|
|
@ -723,12 +712,11 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged)
|
|||
LLRenderPass::applyModelMatrix(params);
|
||||
|
||||
LLMaterial* mat = NULL;
|
||||
LLGLTFMaterial *gltf_mat = params.mGLTFMaterial; // Also see: LLPipeline::getPoolTypeFromTE()
|
||||
bool is_pbr = LLPipeline::sRenderPBR && gltf_mat;
|
||||
LLGLTFMaterial *gltf_mat = params.mGLTFMaterial;
|
||||
|
||||
LLGLDisable cull_face(is_pbr && gltf_mat->mDoubleSided ? GL_CULL_FACE : 0);
|
||||
LLGLDisable cull_face(gltf_mat && gltf_mat->mDoubleSided ? GL_CULL_FACE : 0);
|
||||
|
||||
if (is_pbr && gltf_mat->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_BLEND)
|
||||
if (gltf_mat && gltf_mat->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_BLEND)
|
||||
{
|
||||
target_shader = &gDeferredPBRAlphaProgram;
|
||||
if (params.mAvatar != nullptr)
|
||||
|
|
|
|||
|
|
@ -689,7 +689,7 @@ void LLDrawPoolBump::renderBump(U32 pass)
|
|||
//static
|
||||
void LLDrawPoolBump::endBump(U32 pass)
|
||||
{
|
||||
gObjectBumpProgram.unbind();
|
||||
LLGLSLShader::unbind();
|
||||
|
||||
gGL.setSceneBlendType(LLRender::BT_ALPHA);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -358,7 +358,7 @@ void LLDrawPoolGrass::beginRenderPass(S32 pass)
|
|||
else
|
||||
{
|
||||
gGL.flush();
|
||||
LLGLSLShader::bindNoShader();
|
||||
LLGLSLShader::unbind();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,8 +50,6 @@
|
|||
#include "llsettingssky.h"
|
||||
#include "llsettingswater.h"
|
||||
|
||||
BOOL deferred_render = FALSE;
|
||||
|
||||
BOOL LLDrawPoolWater::sSkipScreenCopy = FALSE;
|
||||
BOOL LLDrawPoolWater::sNeedsReflectionUpdate = TRUE;
|
||||
BOOL LLDrawPoolWater::sNeedsDistortionUpdate = TRUE;
|
||||
|
|
@ -114,21 +112,26 @@ S32 LLDrawPoolWater::getNumPostDeferredPasses()
|
|||
void LLDrawPoolWater::beginPostDeferredPass(S32 pass)
|
||||
{
|
||||
LL_PROFILE_GPU_ZONE("water beginPostDeferredPass")
|
||||
gGL.setColorMask(true, true);
|
||||
|
||||
if (LLPipeline::sRenderTransparentWater && !gCubeSnapshot)
|
||||
{
|
||||
// copy framebuffer contents so far to a texture to be used for
|
||||
// reflections and refractions
|
||||
LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS);
|
||||
|
||||
LLRenderTarget& src = gPipeline.mRT->screen;
|
||||
LLRenderTarget& depth_src = gPipeline.mRT->deferredScreen;
|
||||
LLRenderTarget& dst = gPipeline.mWaterDis;
|
||||
|
||||
dst.bindTarget();
|
||||
gCopyDepthProgram.bind();
|
||||
|
||||
S32 diff_map = gCopyDepthProgram.enableTexture(LLShaderMgr::DIFFUSE_MAP);
|
||||
S32 depth_map = gCopyDepthProgram.enableTexture(LLShaderMgr::DEFERRED_DEPTH);
|
||||
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(&src, true);
|
||||
gGL.getTexUnit(depth_map)->bind(&depth_src, true);
|
||||
|
||||
gPipeline.mScreenTriangleVB->setBuffer();
|
||||
gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
|
||||
|
|
@ -140,12 +143,9 @@ void LLDrawPoolWater::beginPostDeferredPass(S32 pass)
|
|||
void LLDrawPoolWater::renderPostDeferred(S32 pass)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
|
||||
if (!deferred_render)
|
||||
{
|
||||
gGL.setColorMask(true, true);
|
||||
}
|
||||
|
||||
LLGLDisable blend(GL_BLEND);
|
||||
|
||||
gGL.setColorMask(true, true);
|
||||
|
||||
LLColor3 light_diffuse(0, 0, 0);
|
||||
F32 light_exp = 0.0f;
|
||||
|
|
@ -194,195 +194,174 @@ void LLDrawPoolWater::renderPostDeferred(S32 pass)
|
|||
LLGLSLShader *shader = nullptr;
|
||||
|
||||
// two passes, first with standard water shader bound, second with edge water shader bound
|
||||
for( int edge = 0 ; edge < 2; edge++ )
|
||||
for (int edge = 0; edge < 2; edge++)
|
||||
{
|
||||
// select shader
|
||||
if (underwater)
|
||||
{
|
||||
shader = deferred_render ? &gDeferredUnderWaterProgram : &gUnderWaterProgram;
|
||||
shader = &gUnderWaterProgram;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (edge && !deferred_render)
|
||||
if (edge)
|
||||
{
|
||||
shader = &gWaterEdgeProgram;
|
||||
}
|
||||
else
|
||||
{
|
||||
shader = deferred_render ? &gDeferredWaterProgram : &gWaterProgram;
|
||||
shader = &gWaterProgram;
|
||||
}
|
||||
}
|
||||
|
||||
gPipeline.bindDeferredShader(*shader);
|
||||
|
||||
// bind textures for water rendering
|
||||
S32 reftex = shader->enableTexture(LLShaderMgr::WATER_REFTEX);
|
||||
if (reftex > -1)
|
||||
{
|
||||
gGL.getTexUnit(reftex)->activate();
|
||||
gGL.getTexUnit(reftex)->bind(&gPipeline.mWaterRef);
|
||||
gGL.getTexUnit(0)->activate();
|
||||
}
|
||||
|
||||
//bind normal map
|
||||
S32 bumpTex = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP);
|
||||
S32 bumpTex2 = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP2);
|
||||
//bind normal map
|
||||
S32 bumpTex = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP);
|
||||
S32 bumpTex2 = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP2);
|
||||
|
||||
LLViewerTexture* tex_a = mWaterNormp[0];
|
||||
LLViewerTexture* tex_b = mWaterNormp[1];
|
||||
LLViewerTexture* tex_a = mWaterNormp[0];
|
||||
LLViewerTexture* tex_b = mWaterNormp[1];
|
||||
|
||||
F32 blend_factor = pwater->getBlendFactor();
|
||||
|
||||
gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
|
||||
if (tex_a && (!tex_b || (tex_a == tex_b)))
|
||||
{
|
||||
gGL.getTexUnit(bumpTex)->bind(tex_a);
|
||||
blend_factor = 0; // only one tex provided, no blending
|
||||
}
|
||||
else if (tex_b && !tex_a)
|
||||
{
|
||||
gGL.getTexUnit(bumpTex)->bind(tex_b);
|
||||
blend_factor = 0; // only one tex provided, no blending
|
||||
}
|
||||
else if (tex_b != tex_a)
|
||||
{
|
||||
gGL.getTexUnit(bumpTex)->bind(tex_a);
|
||||
gGL.getTexUnit(bumpTex2)->bind(tex_b);
|
||||
}
|
||||
|
||||
// bind reflection texture from RenderTarget
|
||||
S32 screentex = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX);
|
||||
S32 screenDepth = shader->enableTexture(LLShaderMgr::WATER_SCREENDEPTH);
|
||||
gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
|
||||
F32 screenRes[] = {1.f / gGLViewport[2], 1.f / gGLViewport[3]};
|
||||
|
||||
S32 diffTex = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP);
|
||||
|
||||
// set uniforms for shader
|
||||
if (deferred_render)
|
||||
if (tex_a && (!tex_b || (tex_a == tex_b)))
|
||||
{
|
||||
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);
|
||||
}
|
||||
gGL.getTexUnit(bumpTex)->bind(tex_a);
|
||||
blend_factor = 0; // only one tex provided, no blending
|
||||
}
|
||||
else if (tex_b && !tex_a)
|
||||
{
|
||||
gGL.getTexUnit(bumpTex)->bind(tex_b);
|
||||
blend_factor = 0; // only one tex provided, no blending
|
||||
}
|
||||
else if (tex_b != tex_a)
|
||||
{
|
||||
gGL.getTexUnit(bumpTex)->bind(tex_a);
|
||||
gGL.getTexUnit(bumpTex2)->bind(tex_b);
|
||||
}
|
||||
|
||||
shader->uniform2fv(LLShaderMgr::DEFERRED_SCREEN_RES, 1, screenRes);
|
||||
shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor);
|
||||
// bind reflection texture from RenderTarget
|
||||
S32 screentex = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX);
|
||||
S32 screenDepth = shader->enableTexture(LLShaderMgr::WATER_SCREENDEPTH);
|
||||
|
||||
F32 fog_density = pwater->getModifiedWaterFogDensity(underwater);
|
||||
F32 screenRes[] = { 1.f / gGLViewport[2], 1.f / gGLViewport[3] };
|
||||
|
||||
S32 diffTex = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP);
|
||||
|
||||
shader->uniform2fv(LLShaderMgr::DEFERRED_SCREEN_RES, 1, screenRes);
|
||||
shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor);
|
||||
|
||||
F32 fog_density = pwater->getModifiedWaterFogDensity(underwater);
|
||||
|
||||
if (screentex > -1)
|
||||
{
|
||||
shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, fog_density);
|
||||
gGL.getTexUnit(screentex)->bind(&gPipeline.mWaterDis);
|
||||
}
|
||||
|
||||
if (screentex > -1)
|
||||
{
|
||||
shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, fog_density);
|
||||
gGL.getTexUnit(screentex)->bind(&gPipeline.mWaterDis);
|
||||
}
|
||||
|
||||
if (screenDepth > -1)
|
||||
{
|
||||
gGL.getTexUnit(screenDepth)->bind(&gPipeline.mWaterDis, true);
|
||||
}
|
||||
|
||||
if (mShaderLevel == 1)
|
||||
{
|
||||
fog_color.mV[VW] = log(fog_density) / log(2);
|
||||
}
|
||||
if (mShaderLevel == 1)
|
||||
{
|
||||
fog_color.mV[VW] = log(fog_density) / log(2);
|
||||
}
|
||||
|
||||
F32 water_height = environment.getWaterHeight();
|
||||
F32 water_height = environment.getWaterHeight();
|
||||
F32 camera_height = LLViewerCamera::getInstance()->getOrigin().mV[2];
|
||||
shader->uniform1f(LLShaderMgr::WATER_WATERHEIGHT, camera_height - water_height);
|
||||
shader->uniform1f(LLShaderMgr::WATER_TIME, phase_time);
|
||||
shader->uniform3fv(LLShaderMgr::WATER_EYEVEC, 1, LLViewerCamera::getInstance()->getOrigin().mV);
|
||||
|
||||
shader->uniform4fv(LLShaderMgr::SPECULAR_COLOR, 1, specular.mV);
|
||||
shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, fog_color.mV);
|
||||
shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, fog_color.mV);
|
||||
shader->uniform3fv(LLShaderMgr::WATER_FOGCOLOR_LINEAR, 1, fog_color_linear.mV);
|
||||
|
||||
shader->uniform3fv(LLShaderMgr::WATER_SPECULAR, 1, light_diffuse.mV);
|
||||
shader->uniform1f(LLShaderMgr::WATER_SPECULAR_EXP, light_exp);
|
||||
shader->uniform3fv(LLShaderMgr::WATER_SPECULAR, 1, light_diffuse.mV);
|
||||
shader->uniform1f(LLShaderMgr::WATER_SPECULAR_EXP, light_exp);
|
||||
|
||||
shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, pwater->getWave1Dir().mV);
|
||||
shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, pwater->getWave2Dir().mV);
|
||||
shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, pwater->getWave1Dir().mV);
|
||||
shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, pwater->getWave2Dir().mV);
|
||||
|
||||
shader->uniform3fv(LLShaderMgr::WATER_LIGHT_DIR, 1, light_dir.mV);
|
||||
shader->uniform3fv(LLShaderMgr::WATER_LIGHT_DIR, 1, light_dir.mV);
|
||||
|
||||
shader->uniform3fv(LLShaderMgr::WATER_NORM_SCALE, 1, pwater->getNormalScale().mV);
|
||||
shader->uniform1f(LLShaderMgr::WATER_FRESNEL_SCALE, pwater->getFresnelScale());
|
||||
shader->uniform1f(LLShaderMgr::WATER_FRESNEL_OFFSET, pwater->getFresnelOffset());
|
||||
shader->uniform1f(LLShaderMgr::WATER_BLUR_MULTIPLIER, pwater->getBlurMultiplier());
|
||||
shader->uniform3fv(LLShaderMgr::WATER_NORM_SCALE, 1, pwater->getNormalScale().mV);
|
||||
shader->uniform1f(LLShaderMgr::WATER_FRESNEL_SCALE, pwater->getFresnelScale());
|
||||
shader->uniform1f(LLShaderMgr::WATER_FRESNEL_OFFSET, pwater->getFresnelOffset());
|
||||
shader->uniform1f(LLShaderMgr::WATER_BLUR_MULTIPLIER, pwater->getBlurMultiplier());
|
||||
|
||||
F32 sunAngle = llmax(0.f, light_dir.mV[1]);
|
||||
F32 scaledAngle = 1.f - sunAngle;
|
||||
F32 sunAngle = llmax(0.f, light_dir.mV[1]);
|
||||
F32 scaledAngle = 1.f - sunAngle;
|
||||
|
||||
shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up ? 1 : 0);
|
||||
shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE, sunAngle);
|
||||
shader->uniform1f(LLShaderMgr::WATER_SCALED_ANGLE, scaledAngle);
|
||||
shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE2, 0.1f + 0.2f*sunAngle);
|
||||
shader->uniform1i(LLShaderMgr::WATER_EDGE_FACTOR, edge ? 1 : 0);
|
||||
shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE, sunAngle);
|
||||
shader->uniform1f(LLShaderMgr::WATER_SCALED_ANGLE, scaledAngle);
|
||||
shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE2, 0.1f + 0.2f * sunAngle);
|
||||
shader->uniform1i(LLShaderMgr::WATER_EDGE_FACTOR, edge ? 1 : 0);
|
||||
|
||||
// SL-15861 This was changed from getRotatedLightNorm() as it was causing
|
||||
// lightnorm in shaders\class1\windlight\atmosphericsFuncs.glsl in have inconsistent additive lighting for 180 degrees of the FOV.
|
||||
LLVector4 rotated_light_direction = LLEnvironment::instance().getClampedLightNorm();
|
||||
shader->uniform3fv(LLViewerShaderMgr::LIGHTNORM, 1, rotated_light_direction.mV);
|
||||
// SL-15861 This was changed from getRotatedLightNorm() as it was causing
|
||||
// lightnorm in shaders\class1\windlight\atmosphericsFuncs.glsl in have inconsistent additive lighting for 180 degrees of the FOV.
|
||||
LLVector4 rotated_light_direction = LLEnvironment::instance().getClampedLightNorm();
|
||||
shader->uniform3fv(LLViewerShaderMgr::LIGHTNORM, 1, rotated_light_direction.mV);
|
||||
|
||||
shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV);
|
||||
shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV);
|
||||
|
||||
if (LLViewerCamera::getInstance()->cameraUnderWater())
|
||||
{
|
||||
shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleBelow());
|
||||
}
|
||||
else
|
||||
{
|
||||
shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleAbove());
|
||||
}
|
||||
if (LLViewerCamera::getInstance()->cameraUnderWater())
|
||||
{
|
||||
shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleBelow());
|
||||
}
|
||||
else
|
||||
{
|
||||
shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleAbove());
|
||||
}
|
||||
|
||||
LLGLDisable cullface(GL_CULL_FACE);
|
||||
LLGLDisable cullface(GL_CULL_FACE);
|
||||
|
||||
LLVOWater *water = nullptr;
|
||||
for (LLFace *const &face : mDrawFace)
|
||||
LLVOWater* water = nullptr;
|
||||
for (LLFace* const& face : mDrawFace)
|
||||
{
|
||||
if (!face) continue;
|
||||
water = static_cast<LLVOWater *>(face->getViewerObject());
|
||||
water = static_cast<LLVOWater*>(face->getViewerObject());
|
||||
if (!water) continue;
|
||||
|
||||
gGL.getTexUnit(diffTex)->bind(face->getTexture());
|
||||
gGL.getTexUnit(diffTex)->bind(face->getTexture());
|
||||
|
||||
if ((bool)edge == (bool) water->getIsEdgePatch())
|
||||
{
|
||||
face->renderIndexed();
|
||||
if ((bool)edge == (bool)water->getIsEdgePatch())
|
||||
{
|
||||
face->renderIndexed();
|
||||
|
||||
// Note non-void water being drawn, updates required
|
||||
if (!edge) // SL-16461 remove !LLPipeline::sUseOcclusion check
|
||||
{
|
||||
sNeedsReflectionUpdate = TRUE;
|
||||
sNeedsDistortionUpdate = TRUE;
|
||||
{
|
||||
sNeedsReflectionUpdate = TRUE;
|
||||
sNeedsDistortionUpdate = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shader->disableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
|
||||
shader->disableTexture(LLShaderMgr::WATER_SCREENTEX);
|
||||
shader->disableTexture(LLShaderMgr::BUMP_MAP);
|
||||
shader->disableTexture(LLShaderMgr::DIFFUSE_MAP);
|
||||
shader->disableTexture(LLShaderMgr::WATER_REFTEX);
|
||||
shader->disableTexture(LLShaderMgr::WATER_SCREENDEPTH);
|
||||
shader->disableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
|
||||
shader->disableTexture(LLShaderMgr::WATER_SCREENTEX);
|
||||
shader->disableTexture(LLShaderMgr::BUMP_MAP);
|
||||
shader->disableTexture(LLShaderMgr::DIFFUSE_MAP);
|
||||
shader->disableTexture(LLShaderMgr::WATER_REFTEX);
|
||||
shader->disableTexture(LLShaderMgr::WATER_SCREENDEPTH);
|
||||
|
||||
// clean up
|
||||
gPipeline.unbindDeferredShader(*shader);
|
||||
|
||||
gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
}
|
||||
}
|
||||
|
||||
gGL.getTexUnit(0)->activate();
|
||||
gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
|
||||
if (!deferred_render)
|
||||
{
|
||||
gGL.setColorMask(true, false);
|
||||
}
|
||||
|
||||
gGL.setColorMask(true, false);
|
||||
}
|
||||
|
||||
LLViewerTexture *LLDrawPoolWater::getDebugTexture()
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ BOOL LLViewerDynamicTexture::updateAllInstances()
|
|||
gPipeline.mBake.clear();
|
||||
}
|
||||
|
||||
LLGLSLShader::bindNoShader();
|
||||
LLGLSLShader::unbind();
|
||||
LLVertexBuffer::unbind();
|
||||
|
||||
BOOL result = FALSE;
|
||||
|
|
|
|||
|
|
@ -1754,28 +1754,31 @@ LLVector4 LLEnvironment::getRotatedLightNorm() const
|
|||
return toLightNorm(light_direction);
|
||||
}
|
||||
|
||||
extern BOOL gCubeSnapshot;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void LLEnvironment::update(const LLViewerCamera * cam)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; //LL_RECORD_BLOCK_TIME(FTM_ENVIRONMENT_UPDATE);
|
||||
//F32Seconds now(LLDate::now().secondsSinceEpoch());
|
||||
static LLFrameTimer timer;
|
||||
|
||||
F32Seconds delta(timer.getElapsedTimeAndResetF32());
|
||||
|
||||
if (!gCubeSnapshot)
|
||||
{
|
||||
DayInstance::ptr_t keeper = mCurrentEnvironment;
|
||||
// make sure the current environment does not go away until applyTimeDelta is done.
|
||||
mCurrentEnvironment->applyTimeDelta(delta);
|
||||
static LLFrameTimer timer;
|
||||
|
||||
F32Seconds delta(timer.getElapsedTimeAndResetF32());
|
||||
|
||||
{
|
||||
DayInstance::ptr_t keeper = mCurrentEnvironment;
|
||||
// make sure the current environment does not go away until applyTimeDelta is done.
|
||||
mCurrentEnvironment->applyTimeDelta(delta);
|
||||
|
||||
}
|
||||
// update clouds, sun, and general
|
||||
updateCloudScroll();
|
||||
|
||||
// cache this for use in rotating the rotated light vec for shader param updates later...
|
||||
mLastCamYaw = cam->getYaw() + SUN_DELTA_YAW;
|
||||
}
|
||||
// update clouds, sun, and general
|
||||
updateCloudScroll();
|
||||
|
||||
// cache this for use in rotating the rotated light vec for shader param updates later...
|
||||
mLastCamYaw = cam->getYaw() + SUN_DELTA_YAW;
|
||||
|
||||
stop_glerror();
|
||||
|
||||
updateSettingsUniforms();
|
||||
|
||||
|
|
@ -1876,13 +1879,23 @@ void LLEnvironment::updateGLVariablesForSettings(LLShaderUniforms* uniforms, con
|
|||
{
|
||||
LLVector4 vect4(value);
|
||||
|
||||
switch (it.second.getShaderKey())
|
||||
{ // convert to linear color space if this is a color parameter
|
||||
case LLShaderMgr::BLUE_HORIZON:
|
||||
case LLShaderMgr::BLUE_DENSITY:
|
||||
//vect4 = LLVector4(linearColor4(LLColor4(vect4.mV)).mV);
|
||||
break;
|
||||
if (gCubeSnapshot && !gPipeline.mReflectionMapManager.isRadiancePass())
|
||||
{ // maximize and remove tinting if this is an irradiance map render pass and the parameter feeds into the sky background color
|
||||
auto max_vec = [](LLVector4 col)
|
||||
{
|
||||
col.mV[0] = col.mV[1] = col.mV[2] = llmax(llmax(col.mV[0], col.mV[1]), col.mV[2]);
|
||||
return col;
|
||||
};
|
||||
|
||||
switch (it.second.getShaderKey())
|
||||
{
|
||||
case LLShaderMgr::BLUE_HORIZON:
|
||||
case LLShaderMgr::BLUE_DENSITY:
|
||||
vect4 = max_vec(vect4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//_WARNS("RIDER") << "pushing '" << (*it).first << "' as " << vect4 << LL_ENDL;
|
||||
shader->uniform3fv(it.second.getShaderKey(), LLVector3(vect4.mV) );
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -492,7 +492,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;
|
||||
|
|
|
|||
|
|
@ -661,6 +661,10 @@ void LLFeatureManager::applyBaseMasks()
|
|||
{
|
||||
maskFeatures("VRAMGT512");
|
||||
}
|
||||
if (gGLManager.mVRAM < 2048)
|
||||
{
|
||||
maskFeatures("VRAMLT2GB");
|
||||
}
|
||||
if (gGLManager.mGLVersion < 3.99f)
|
||||
{
|
||||
maskFeatures("GL3");
|
||||
|
|
|
|||
|
|
@ -115,3 +115,35 @@ void LLFetchedGLTFMaterial::bind()
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
void LLFetchedGLTFMaterial::materialBegin()
|
||||
{
|
||||
llassert(!mFetching);
|
||||
mFetching = true;
|
||||
}
|
||||
|
||||
void LLFetchedGLTFMaterial::onMaterialComplete(std::function<void()> material_complete)
|
||||
{
|
||||
if (!material_complete) { return; }
|
||||
|
||||
if (!mFetching)
|
||||
{
|
||||
material_complete();
|
||||
return;
|
||||
}
|
||||
|
||||
materialCompleteCallbacks.push_back(material_complete);
|
||||
}
|
||||
|
||||
void LLFetchedGLTFMaterial::materialComplete()
|
||||
{
|
||||
llassert(mFetching);
|
||||
mFetching = false;
|
||||
|
||||
for (std::function<void()> material_complete : materialCompleteCallbacks)
|
||||
{
|
||||
material_complete();
|
||||
}
|
||||
materialCompleteCallbacks.clear();
|
||||
materialCompleteCallbacks.shrink_to_fit();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,9 @@ public:
|
|||
LLFetchedGLTFMaterial();
|
||||
virtual ~LLFetchedGLTFMaterial();
|
||||
|
||||
// If this material is loaded, fire the given function
|
||||
void onMaterialComplete(std::function<void()> material_complete);
|
||||
|
||||
// bind this material for rendering
|
||||
void bind();
|
||||
|
||||
|
|
@ -49,9 +52,14 @@ public:
|
|||
LLPointer<LLViewerFetchedTexture> mEmissiveTexture;
|
||||
|
||||
protected:
|
||||
//Lifetime management
|
||||
// Lifetime management
|
||||
|
||||
void materialBegin();
|
||||
void materialComplete();
|
||||
|
||||
F64 mExpectedFlusTime; // since epoch in seconds
|
||||
bool mActive;
|
||||
bool mFetching;
|
||||
std::vector<std::function<void()>> materialCompleteCallbacks;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -905,6 +905,8 @@ void LLImagePreviewSculpted::setPreviewTarget(LLImageRaw* imagep, F32 distance)
|
|||
{
|
||||
*(index_strider++) = vf.mIndices[i];
|
||||
}
|
||||
|
||||
mVertexBuffer->unmapBuffer();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2130,7 +2130,7 @@ void LLFloaterPreference::refreshEnabledState()
|
|||
sky->setEnabled(TRUE);
|
||||
|
||||
//PBR
|
||||
ctrl_pbr->setEnabled(LLFeatureManager::getInstance()->isFeatureAvailable("RenderPBR"));
|
||||
ctrl_pbr->setEnabled(TRUE);
|
||||
|
||||
LLCheckBoxCtrl* ctrl_ssao = getChild<LLCheckBoxCtrl>("UseSSAO");
|
||||
LLCheckBoxCtrl* ctrl_dof = getChild<LLCheckBoxCtrl>("UseDoF");
|
||||
|
|
|
|||
|
|
@ -1200,7 +1200,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
|
||||
|
|
|
|||
|
|
@ -392,15 +392,18 @@ void LLGLTFMaterialList::applyQueuedOverrides(LLViewerObject* obj)
|
|||
}
|
||||
}
|
||||
|
||||
void LLGLTFMaterialList::queueModify(const LLUUID& id, S32 side, const LLGLTFMaterial* mat)
|
||||
void LLGLTFMaterialList::queueModify(const LLViewerObject* obj, S32 side, const LLGLTFMaterial* mat)
|
||||
{
|
||||
if (mat == nullptr)
|
||||
if (obj && obj->getRenderMaterialID(side).notNull())
|
||||
{
|
||||
sModifyQueue.push_back({ id, side, LLGLTFMaterial(), false });
|
||||
}
|
||||
else
|
||||
{
|
||||
sModifyQueue.push_back({ id, side, *mat, true});
|
||||
if (mat == nullptr)
|
||||
{
|
||||
sModifyQueue.push_back({ obj->getID(), side, LLGLTFMaterial(), false });
|
||||
}
|
||||
else
|
||||
{
|
||||
sModifyQueue.push_back({ obj->getID(), side, *mat, true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -437,8 +440,14 @@ void LLGLTFMaterialList::flushUpdates(void(*done_callback)(bool))
|
|||
|
||||
S32 i = data.size();
|
||||
|
||||
for (auto& e : sModifyQueue)
|
||||
for (ModifyMaterialData& e : sModifyQueue)
|
||||
{
|
||||
#ifdef SHOW_ASSERT
|
||||
// validate object has a material id
|
||||
LLViewerObject* obj = gObjectList.findObject(e.object_id);
|
||||
llassert(obj && obj->getRenderMaterialID(e.side).notNull());
|
||||
#endif
|
||||
|
||||
data[i]["object_id"] = e.object_id;
|
||||
data[i]["side"] = e.side;
|
||||
|
||||
|
|
@ -516,7 +525,7 @@ void LLGLTFMaterialList::onAssetLoadComplete(const LLUUID& id, LLAssetType::ETyp
|
|||
if (status != LL_ERR_NOERR)
|
||||
{
|
||||
LL_WARNS("GLTF") << "Error getting material asset data: " << LLAssetStorage::getErrorString(status) << " (" << status << ")" << LL_ENDL;
|
||||
asset_data->mMaterial->mFetching = false;
|
||||
asset_data->mMaterial->materialComplete();
|
||||
delete asset_data;
|
||||
}
|
||||
else
|
||||
|
|
@ -602,13 +611,15 @@ void LLGLTFMaterialList::onAssetLoadComplete(const LLUUID& id, LLAssetType::ETyp
|
|||
{
|
||||
LL_DEBUGS("GLTF") << "Failed to get material " << id << LL_ENDL;
|
||||
}
|
||||
asset_data->mMaterial->mFetching = false;
|
||||
|
||||
asset_data->mMaterial->materialComplete();
|
||||
|
||||
delete asset_data;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
LLGLTFMaterial* LLGLTFMaterialList::getMaterial(const LLUUID& id)
|
||||
LLFetchedGLTFMaterial* LLGLTFMaterialList::getMaterial(const LLUUID& id)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
uuid_mat_map_t::iterator iter = mList.find(id);
|
||||
|
|
@ -620,7 +631,7 @@ LLGLTFMaterial* LLGLTFMaterialList::getMaterial(const LLUUID& id)
|
|||
|
||||
if (!mat->mFetching)
|
||||
{
|
||||
mat->mFetching = true;
|
||||
mat->materialBegin();
|
||||
|
||||
AssetLoadUserData *user_data = new AssetLoadUserData();
|
||||
user_data->mMaterial = mat;
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ public:
|
|||
LLGLTFMaterialList() {}
|
||||
|
||||
|
||||
LLGLTFMaterial* getMaterial(const LLUUID& id);
|
||||
LLFetchedGLTFMaterial* getMaterial(const LLUUID& id);
|
||||
|
||||
void addMaterial(const LLUUID& id, LLFetchedGLTFMaterial* material);
|
||||
void removeMaterial(const LLUUID& id);
|
||||
|
|
@ -60,7 +60,7 @@ public:
|
|||
// mat - material to apply as override, or nullptr to remove existing overrides and revert to asset
|
||||
//
|
||||
// NOTE: do not use to revert to asset when applying a new asset id, use queueApply below
|
||||
static void queueModify(const LLUUID& id, S32 side, const LLGLTFMaterial* mat);
|
||||
static void queueModify(const LLViewerObject* obj, S32 side, const LLGLTFMaterial* mat);
|
||||
|
||||
// Queue an application of a material asset we want to send to the simulator. Call "flushUpdates" to flush pending updates.
|
||||
// object_id - ID of object to apply material asset to
|
||||
|
|
|
|||
|
|
@ -271,11 +271,7 @@ void LLManipTranslate::restoreGL()
|
|||
}
|
||||
}
|
||||
}
|
||||
#ifdef LL_WINDOWS
|
||||
LLImageGL::setManualImage(GL_TEXTURE_2D, mip, GL_RGBA, rez, rez, GL_RGBA, GL_UNSIGNED_BYTE, d);
|
||||
#else
|
||||
LLImageGL::setManualImage(GL_TEXTURE_2D, mip, GL_RGBA, rez, rez, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, d);
|
||||
#endif
|
||||
rez = rez >> 1;
|
||||
mip++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2156,6 +2156,8 @@ void LLMaterialEditor::loadMaterial(const tinygltf::Model &model_in, const std::
|
|||
{
|
||||
openFloater(getKey());
|
||||
setFocus(TRUE);
|
||||
setCanSave(true);
|
||||
setCanSaveAs(true);
|
||||
|
||||
applyToSelection();
|
||||
}
|
||||
|
|
@ -2673,7 +2675,7 @@ public:
|
|||
{
|
||||
mSuccess = true;
|
||||
}
|
||||
LLGLTFMaterialList::queueModify(objectp->getID(), te, material);
|
||||
LLGLTFMaterialList::queueModify(objectp, te, material);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ void LLPanelFace::updateSelectedGLTFMaterials(std::function<void(LLGLTFMaterial*
|
|||
new_override = *tep->getGLTFMaterialOverride();
|
||||
}
|
||||
mFunc(&new_override);
|
||||
LLGLTFMaterialList::queueModify(object->getID(), face, &new_override);
|
||||
LLGLTFMaterialList::queueModify(object, face, &new_override);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,18 @@
|
|||
extern BOOL gCubeSnapshot;
|
||||
extern BOOL gTeleportDisplay;
|
||||
|
||||
// get the next highest power of two of v (or v if v is already a power of two)
|
||||
//defined in llvertexbuffer.cpp
|
||||
extern U32 nhpo2(U32 v);
|
||||
|
||||
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,21 +95,19 @@ 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);
|
||||
U32 targetRes = mProbeResolution * 2; // super sample
|
||||
mRenderTarget.allocate(targetRes, targetRes, color_fmt, true);
|
||||
}
|
||||
|
||||
if (mMipChain.empty())
|
||||
{
|
||||
U32 res = LL_REFLECTION_PROBE_RESOLUTION;
|
||||
U32 res = mProbeResolution;
|
||||
U32 count = log2((F32)res) + 0.5f;
|
||||
|
||||
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 +118,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 +164,8 @@ void LLReflectionMapManager::update()
|
|||
doProbeUpdate();
|
||||
}
|
||||
|
||||
//LL_INFOS() << mProbes.size() << LL_ENDL;
|
||||
|
||||
for (int i = 0; i < mProbes.size(); ++i)
|
||||
{
|
||||
LLReflectionMap* probe = mProbes[i];
|
||||
|
|
@ -394,32 +405,67 @@ void LLReflectionMapManager::doProbeUpdate()
|
|||
if (++mUpdatingFace == 6)
|
||||
{
|
||||
updateNeighbors(mUpdatingProbe);
|
||||
mUpdatingProbe = nullptr;
|
||||
mUpdatingFace = 0;
|
||||
if (isRadiancePass())
|
||||
{
|
||||
mUpdatingProbe = nullptr;
|
||||
mRadiancePass = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
mRadiancePass = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do the reflection map update render passes.
|
||||
// For every 12 calls of this function, one complete reflection probe radiance map and irradiance map is generated
|
||||
// First six passes render the scene with direct lighting only into a scratch space cube map at the end of the cube map array and generate
|
||||
// a simple mip chain (not convolution filter).
|
||||
// At the end of these passes, an irradiance map is generated for this probe and placed into the irradiance cube map array at the index for this probe
|
||||
// The next six passes render the scene with both radiance and irradiance into the same scratch space cube map and generate a simple mip chain.
|
||||
// At the end of these passes, a radiance map is generated for this probe and placed into the radiance cube map array at the index for this probe.
|
||||
// In effect this simulates single-bounce lighting.
|
||||
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;
|
||||
S32 sourceIdx = mReflectionProbeCount;
|
||||
|
||||
if (probe != mUpdatingProbe)
|
||||
{ // this is the "realtime" probe that's updating every frame, use the secondary scratch space channel
|
||||
targetIdx += 1;
|
||||
sourceIdx += 1;
|
||||
}
|
||||
|
||||
gGL.setColorMask(true, true);
|
||||
LLGLDepthTest depth(GL_FALSE, GL_FALSE);
|
||||
LLGLDisable cull(GL_CULL_FACE);
|
||||
LLGLDisable blend(GL_BLEND);
|
||||
|
||||
// downsample to placeholder map
|
||||
{
|
||||
LLGLDepthTest depth(GL_FALSE, GL_FALSE);
|
||||
LLGLDisable cull(GL_CULL_FACE);
|
||||
|
||||
gReflectionMipProgram.bind();
|
||||
|
||||
gGL.matrixMode(gGL.MM_MODELVIEW);
|
||||
|
|
@ -431,9 +477,9 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face)
|
|||
gGL.loadIdentity();
|
||||
|
||||
gGL.flush();
|
||||
U32 res = LL_REFLECTION_PROBE_RESOLUTION * 2;
|
||||
U32 res = mProbeResolution * 2;
|
||||
|
||||
S32 mips = log2((F32)LL_REFLECTION_PROBE_RESOLUTION) + 0.5f;
|
||||
S32 mips = log2((F32)mProbeResolution) + 0.5f;
|
||||
|
||||
S32 diffuseChannel = gReflectionMipProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_TEXTURE);
|
||||
S32 depthChannel = gReflectionMipProgram.enableTexture(LLShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_TEXTURE);
|
||||
|
|
@ -508,7 +554,7 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face)
|
|||
LL_PROFILE_GPU_ZONE("probe mip copy");
|
||||
mTexture->bind(0);
|
||||
//glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, 0, 0, probe->mCubeIndex * 6 + face, 0, 0, res, res);
|
||||
glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, 0, 0, targetIdx * 6 + face, 0, 0, res, res);
|
||||
glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, 0, 0, sourceIdx * 6 + face, 0, 0, res, res);
|
||||
//if (i == 0)
|
||||
//{
|
||||
//glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, 0, 0, probe->mCubeIndex * 6 + face, 0, 0, res, res);
|
||||
|
|
@ -529,89 +575,102 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face)
|
|||
|
||||
if (face == 5)
|
||||
{
|
||||
//generate radiance map
|
||||
gRadianceGenProgram.bind();
|
||||
mVertexBuffer->setBuffer();
|
||||
|
||||
S32 channel = gRadianceGenProgram.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY);
|
||||
mTexture->bind(channel);
|
||||
static LLStaticHashedString sSourceIdx("sourceIdx");
|
||||
gRadianceGenProgram.uniform1i(sSourceIdx, targetIdx);
|
||||
|
||||
mMipChain[0].bindTarget();
|
||||
U32 res = mMipChain[0].getWidth();
|
||||
static LLStaticHashedString sSourceIdx("sourceIdx");
|
||||
|
||||
for (int i = 0; i < mMipChain.size(); ++i)
|
||||
if (isRadiancePass())
|
||||
{
|
||||
LL_PROFILE_GPU_ZONE("probe radiance gen");
|
||||
static LLStaticHashedString sMipLevel("mipLevel");
|
||||
static LLStaticHashedString sRoughness("roughness");
|
||||
static LLStaticHashedString sWidth("u_width");
|
||||
//generate radiance map (even if this is not the irradiance map, we need the mip chain for the irradiance map)
|
||||
gRadianceGenProgram.bind();
|
||||
mVertexBuffer->setBuffer();
|
||||
|
||||
gRadianceGenProgram.uniform1f(sRoughness, (F32)i / (F32)(mMipChain.size() - 1));
|
||||
gRadianceGenProgram.uniform1f(sMipLevel, i);
|
||||
gRadianceGenProgram.uniform1i(sWidth, mMipChain[i].getWidth());
|
||||
S32 channel = gRadianceGenProgram.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY);
|
||||
mTexture->bind(channel);
|
||||
gRadianceGenProgram.uniform1i(sSourceIdx, sourceIdx);
|
||||
gRadianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_MAX_LOD, mMaxProbeLOD);
|
||||
|
||||
for (int cf = 0; cf < 6; ++cf)
|
||||
{ // for each cube face
|
||||
LLCoordFrame frame;
|
||||
frame.lookAt(LLVector3(0, 0, 0), LLCubeMapArray::sClipToCubeLookVecs[cf], LLCubeMapArray::sClipToCubeUpVecs[cf]);
|
||||
U32 res = mMipChain[0].getWidth();
|
||||
|
||||
F32 mat[16];
|
||||
frame.getOpenGLRotation(mat);
|
||||
gGL.loadMatrix(mat);
|
||||
|
||||
mVertexBuffer->drawArrays(gGL.TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, i, 0, 0, probe->mCubeIndex * 6 + cf, 0, 0, res, res);
|
||||
}
|
||||
|
||||
if (i != mMipChain.size() - 1)
|
||||
for (int i = 0; i < mMipChain.size(); ++i)
|
||||
{
|
||||
res /= 2;
|
||||
glViewport(0, 0, res, res);
|
||||
LL_PROFILE_GPU_ZONE("probe radiance gen");
|
||||
static LLStaticHashedString sMipLevel("mipLevel");
|
||||
static LLStaticHashedString sRoughness("roughness");
|
||||
static LLStaticHashedString sWidth("u_width");
|
||||
|
||||
gRadianceGenProgram.uniform1f(sRoughness, (F32)i / (F32)(mMipChain.size() - 1));
|
||||
gRadianceGenProgram.uniform1f(sMipLevel, i);
|
||||
gRadianceGenProgram.uniform1i(sWidth, mMipChain[i].getWidth());
|
||||
|
||||
for (int cf = 0; cf < 6; ++cf)
|
||||
{ // for each cube face
|
||||
LLCoordFrame frame;
|
||||
frame.lookAt(LLVector3(0, 0, 0), LLCubeMapArray::sClipToCubeLookVecs[cf], LLCubeMapArray::sClipToCubeUpVecs[cf]);
|
||||
|
||||
F32 mat[16];
|
||||
frame.getOpenGLRotation(mat);
|
||||
gGL.loadMatrix(mat);
|
||||
|
||||
mVertexBuffer->drawArrays(gGL.TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, i, 0, 0, probe->mCubeIndex * 6 + cf, 0, 0, res, res);
|
||||
}
|
||||
|
||||
if (i != mMipChain.size() - 1)
|
||||
{
|
||||
res /= 2;
|
||||
glViewport(0, 0, res, res);
|
||||
}
|
||||
}
|
||||
|
||||
gRadianceGenProgram.unbind();
|
||||
}
|
||||
|
||||
gRadianceGenProgram.unbind();
|
||||
|
||||
//generate irradiance map
|
||||
gIrradianceGenProgram.bind();
|
||||
channel = gIrradianceGenProgram.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY);
|
||||
mTexture->bind(channel);
|
||||
|
||||
gIrradianceGenProgram.uniform1i(sSourceIdx, targetIdx);
|
||||
mVertexBuffer->setBuffer();
|
||||
int start_mip = 0;
|
||||
// find the mip target to start with based on irradiance map resolution
|
||||
for (start_mip = 0; start_mip < mMipChain.size(); ++start_mip)
|
||||
else
|
||||
{
|
||||
if (mMipChain[start_mip].getWidth() == LL_IRRADIANCE_MAP_RESOLUTION)
|
||||
//generate irradiance map
|
||||
gIrradianceGenProgram.bind();
|
||||
S32 channel = gIrradianceGenProgram.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY);
|
||||
mTexture->bind(channel);
|
||||
|
||||
static LLCachedControl<F32> ambiance_scale(gSavedSettings, "RenderReflectionProbeAmbianceScale", 8.f);
|
||||
static LLStaticHashedString ambiance_scale_str("ambiance_scale");
|
||||
|
||||
gIrradianceGenProgram.uniform1f(ambiance_scale_str, ambiance_scale);
|
||||
gIrradianceGenProgram.uniform1i(sSourceIdx, sourceIdx);
|
||||
gIrradianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_MAX_LOD, mMaxProbeLOD);
|
||||
|
||||
mVertexBuffer->setBuffer();
|
||||
int start_mip = 0;
|
||||
// find the mip target to start with based on irradiance map resolution
|
||||
for (start_mip = 0; start_mip < mMipChain.size(); ++start_mip)
|
||||
{
|
||||
break;
|
||||
if (mMipChain[start_mip].getWidth() == LL_IRRADIANCE_MAP_RESOLUTION)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//for (int i = start_mip; i < mMipChain.size(); ++i)
|
||||
{
|
||||
int i = start_mip;
|
||||
LL_PROFILE_GPU_ZONE("probe irradiance gen");
|
||||
glViewport(0, 0, mMipChain[i].getWidth(), mMipChain[i].getHeight());
|
||||
for (int cf = 0; cf < 6; ++cf)
|
||||
{ // for each cube face
|
||||
LLCoordFrame frame;
|
||||
frame.lookAt(LLVector3(0, 0, 0), LLCubeMapArray::sClipToCubeLookVecs[cf], LLCubeMapArray::sClipToCubeUpVecs[cf]);
|
||||
//for (int i = start_mip; i < mMipChain.size(); ++i)
|
||||
{
|
||||
int i = start_mip;
|
||||
LL_PROFILE_GPU_ZONE("probe irradiance gen");
|
||||
glViewport(0, 0, mMipChain[i].getWidth(), mMipChain[i].getHeight());
|
||||
for (int cf = 0; cf < 6; ++cf)
|
||||
{ // for each cube face
|
||||
LLCoordFrame frame;
|
||||
frame.lookAt(LLVector3(0, 0, 0), LLCubeMapArray::sClipToCubeLookVecs[cf], LLCubeMapArray::sClipToCubeUpVecs[cf]);
|
||||
|
||||
F32 mat[16];
|
||||
frame.getOpenGLRotation(mat);
|
||||
gGL.loadMatrix(mat);
|
||||
F32 mat[16];
|
||||
frame.getOpenGLRotation(mat);
|
||||
gGL.loadMatrix(mat);
|
||||
|
||||
mVertexBuffer->drawArrays(gGL.TRIANGLE_STRIP, 0, 4);
|
||||
mVertexBuffer->drawArrays(gGL.TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
S32 res = mMipChain[i].getWidth();
|
||||
mIrradianceMaps->bind(channel);
|
||||
glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, i - start_mip, 0, 0, probe->mCubeIndex * 6 + cf, 0, 0, res, res);
|
||||
mTexture->bind(channel);
|
||||
S32 res = mMipChain[i].getWidth();
|
||||
mIrradianceMaps->bind(channel);
|
||||
glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, i - start_mip, 0, 0, probe->mCubeIndex * 6 + cf, 0, 0, res, res);
|
||||
mTexture->bind(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -689,12 +748,28 @@ void LLReflectionMapManager::updateUniforms()
|
|||
// see class3/deferred/reflectionProbeF.glsl
|
||||
struct ReflectionProbeData
|
||||
{
|
||||
LLMatrix4 refBox[LL_MAX_REFLECTION_PROBE_COUNT]; // object bounding box as needed
|
||||
LLVector4 refSphere[LL_MAX_REFLECTION_PROBE_COUNT]; //origin and radius of refmaps in clip space
|
||||
LLVector4 refParams[LL_MAX_REFLECTION_PROBE_COUNT]; //extra parameters (currently only ambiance)
|
||||
GLint refIndex[LL_MAX_REFLECTION_PROBE_COUNT][4];
|
||||
GLint refNeighbor[4096];
|
||||
GLint refmapCount;
|
||||
// for box probes, matrix that transforms from camera space to a [-1, 1] cube representing the bounding box of
|
||||
// the box probe
|
||||
LLMatrix4 refBox[LL_MAX_REFLECTION_PROBE_COUNT];
|
||||
|
||||
// for sphere probes, origin (xyz) and radius (w) of refmaps in clip space
|
||||
LLVector4 refSphere[LL_MAX_REFLECTION_PROBE_COUNT];
|
||||
|
||||
// extra parameters (currently only ambiance in .x)
|
||||
LLVector4 refParams[LL_MAX_REFLECTION_PROBE_COUNT];
|
||||
|
||||
// indices used by probe:
|
||||
// [i][0] - cubemap array index for this probe
|
||||
// [i][1] - index into "refNeighbor" for probes that intersect this probe
|
||||
// [i][2] - number of probes that intersect this probe, or -1 for no neighbors
|
||||
// [i][3] - priority (probe type stored in sign bit - positive for spheres, negative for boxes)
|
||||
GLint refIndex[LL_MAX_REFLECTION_PROBE_COUNT][4];
|
||||
|
||||
// list of neighbor indices
|
||||
GLint refNeighbor[4096];
|
||||
|
||||
// numbrer of active refmaps
|
||||
GLint refmapCount;
|
||||
};
|
||||
|
||||
mReflectionMaps.resize(mReflectionProbeCount);
|
||||
|
|
@ -714,7 +789,8 @@ void LLReflectionMapManager::updateUniforms()
|
|||
LLSettingsSky::ptr_t psky = environment.getCurrentSky();
|
||||
|
||||
F32 minimum_ambiance = psky->getTotalReflectionProbeAmbiance();
|
||||
F32 ambscale = gCubeSnapshot ? 0.5f : 1.f;
|
||||
F32 ambscale = gCubeSnapshot && !isRadiancePass() ? 0.f : 1.f;
|
||||
|
||||
|
||||
for (auto* refmap : mReflectionMaps)
|
||||
{
|
||||
|
|
@ -904,12 +980,14 @@ void LLReflectionMapManager::initReflectionMaps()
|
|||
{
|
||||
if (mTexture.isNull())
|
||||
{
|
||||
mProbeResolution = nhpo2(llclamp(gSavedSettings.getU32("RenderReflectionProbeResolution"), (U32)64, (U32)512));
|
||||
mMaxProbeLOD = log2f(mProbeResolution) - 1.f; // number of mips - 1
|
||||
mReflectionProbeCount = llclamp(gSavedSettings.getS32("RenderReflectionProbeCount"), 1, LL_MAX_REFLECTION_PROBE_COUNT);
|
||||
|
||||
mTexture = new LLCubeMapArray();
|
||||
|
||||
// store mReflectionProbeCount+2 cube maps, final two cube maps are used for render target and radiance map generation source)
|
||||
mTexture->allocate(LL_REFLECTION_PROBE_RESOLUTION, 4, mReflectionProbeCount + 2);
|
||||
mTexture->allocate(mProbeResolution, 4, mReflectionProbeCount + 2);
|
||||
|
||||
mIrradianceMaps = new LLCubeMapArray();
|
||||
mIrradianceMaps->allocate(LL_IRRADIANCE_MAP_RESOLUTION, 4, mReflectionProbeCount, FALSE);
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ class LLViewerObject;
|
|||
#define LL_MAX_REFLECTION_PROBE_COUNT 256
|
||||
|
||||
// reflection probe resolution
|
||||
#define LL_REFLECTION_PROBE_RESOLUTION 128
|
||||
#define LL_IRRADIANCE_MAP_RESOLUTION 64
|
||||
|
||||
// reflection probe mininum scale
|
||||
|
|
@ -94,6 +93,9 @@ public:
|
|||
// call once at startup to allocate cubemap arrays
|
||||
void initReflectionMaps();
|
||||
|
||||
// True if currently updating a radiance map, false if currently updating an irradiance map
|
||||
bool isRadiancePass() { return mRadiancePass; }
|
||||
|
||||
private:
|
||||
friend class LLPipeline;
|
||||
|
||||
|
|
@ -161,9 +163,21 @@ private:
|
|||
LLReflectionMap* mUpdatingProbe = nullptr;
|
||||
U32 mUpdatingFace = 0;
|
||||
|
||||
// if true, we're generating the radiance map for the current probe, otherwise we're generating the irradiance map.
|
||||
// Update sequence should be to generate the irradiance map from render of the world that has no irradiance,
|
||||
// then generate the radiance map from a render of the world that includes irradiance.
|
||||
// This should avoid feedback loops and ensure that the colors in the radiance maps match the colors in the environment.
|
||||
bool mRadiancePass = false;
|
||||
|
||||
LLPointer<LLReflectionMap> mDefaultProbe; // default reflection probe to fall back to for pixels with no probe influences (should always be at cube index 0)
|
||||
|
||||
// number of reflection probes to use for rendering (based on saved setting RenderReflectionProbeCount)
|
||||
U32 mReflectionProbeCount;
|
||||
|
||||
// resolution of reflection probes
|
||||
U32 mProbeResolution = 128;
|
||||
|
||||
// maximum LoD of reflection probes (mip levels - 1)
|
||||
F32 mMaxProbeLOD = 6.f;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2305,7 +2305,7 @@ void LLSelectMgr::selectionRevertGLTFMaterials()
|
|||
&& asset_id.notNull())
|
||||
{
|
||||
// Restore overrides
|
||||
LLGLTFMaterialList::queueModify(objectp->getID(), te, nodep->mSavedGLTFOverrideMaterials[te]);
|
||||
LLGLTFMaterialList::queueModify(objectp, te, nodep->mSavedGLTFOverrideMaterials[te]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -68,6 +68,8 @@
|
|||
|
||||
#undef VERIFY_LEGACY_CONVERSION
|
||||
|
||||
extern BOOL gCubeSnapshot;
|
||||
|
||||
//=========================================================================
|
||||
namespace
|
||||
{
|
||||
|
|
@ -673,6 +675,8 @@ void LLSettingsVOSky::applySpecial(void *ptarget, bool force)
|
|||
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
|
||||
LLVector3 light_direction = LLVector3(LLEnvironment::instance().getClampedLightNorm().mV);
|
||||
|
||||
bool radiance_pass = gCubeSnapshot && !gPipeline.mReflectionMapManager.isRadiancePass();
|
||||
|
||||
LLShaderUniforms* shader = &((LLShaderUniforms*)ptarget)[LLGLSLShader::SG_DEFAULT];
|
||||
{
|
||||
shader->uniform3fv(LLViewerShaderMgr::LIGHTNORM, light_direction);
|
||||
|
|
@ -680,43 +684,54 @@ void LLSettingsVOSky::applySpecial(void *ptarget, bool force)
|
|||
}
|
||||
|
||||
shader = &((LLShaderUniforms*)ptarget)[LLGLSLShader::SG_SKY];
|
||||
{
|
||||
shader->uniform3fv(LLViewerShaderMgr::LIGHTNORM, light_direction);
|
||||
|
||||
// Legacy? SETTING_CLOUD_SCROLL_RATE("cloud_scroll_rate")
|
||||
LLVector4 vect_c_p_d1(mSettings[SETTING_CLOUD_POS_DENSITY1]);
|
||||
LLVector4 cloud_scroll( LLEnvironment::instance().getCloudScrollDelta() );
|
||||
shader->uniform3fv(LLViewerShaderMgr::LIGHTNORM, light_direction);
|
||||
|
||||
// SL-13084 EEP added support for custom cloud textures -- flip them horizontally to match the preview of Clouds > Cloud Scroll
|
||||
// Keep in Sync!
|
||||
// * indra\newview\llsettingsvo.cpp
|
||||
// * indra\newview\app_settings\shaders\class2\windlight\cloudsV.glsl
|
||||
// * indra\newview\app_settings\shaders\class1\deferred\cloudsV.glsl
|
||||
cloud_scroll[0] = -cloud_scroll[0];
|
||||
vect_c_p_d1 += cloud_scroll;
|
||||
shader->uniform3fv(LLShaderMgr::CLOUD_POS_DENSITY1, LLVector3(vect_c_p_d1.mV));
|
||||
// Legacy? SETTING_CLOUD_SCROLL_RATE("cloud_scroll_rate")
|
||||
LLVector4 vect_c_p_d1(mSettings[SETTING_CLOUD_POS_DENSITY1]);
|
||||
LLVector4 cloud_scroll( LLEnvironment::instance().getCloudScrollDelta() );
|
||||
|
||||
LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
|
||||
// SL-13084 EEP added support for custom cloud textures -- flip them horizontally to match the preview of Clouds > Cloud Scroll
|
||||
// Keep in Sync!
|
||||
// * indra\newview\llsettingsvo.cpp
|
||||
// * indra\newview\app_settings\shaders\class2\windlight\cloudsV.glsl
|
||||
// * indra\newview\app_settings\shaders\class1\deferred\cloudsV.glsl
|
||||
cloud_scroll[0] = -cloud_scroll[0];
|
||||
vect_c_p_d1 += cloud_scroll;
|
||||
shader->uniform3fv(LLShaderMgr::CLOUD_POS_DENSITY1, LLVector3(vect_c_p_d1.mV));
|
||||
|
||||
// TODO -- make these getters return vec3s
|
||||
LLVector3 sunDiffuse = LLVector3(psky->getSunlightColor().mV);
|
||||
LLVector3 moonDiffuse = LLVector3(psky->getMoonlightColor().mV);
|
||||
LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
|
||||
|
||||
shader->uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, sunDiffuse);
|
||||
shader->uniform3fv(LLShaderMgr::MOONLIGHT_COLOR, moonDiffuse);
|
||||
// TODO -- make these getters return vec3s
|
||||
LLVector3 sunDiffuse = LLVector3(psky->getSunlightColor().mV);
|
||||
LLVector3 moonDiffuse = LLVector3(psky->getMoonlightColor().mV);
|
||||
|
||||
shader->uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, sunDiffuse);
|
||||
shader->uniform3fv(LLShaderMgr::MOONLIGHT_COLOR, moonDiffuse);
|
||||
|
||||
shader->uniform3fv(LLShaderMgr::CLOUD_COLOR, LLVector3(psky->getCloudColor().mV));
|
||||
|
||||
shader->uniform3fv(LLShaderMgr::CLOUD_COLOR, LLVector3(psky->getCloudColor().mV));
|
||||
}
|
||||
|
||||
shader = &((LLShaderUniforms*)ptarget)[LLGLSLShader::SG_ANY];
|
||||
shader->uniform1f(LLShaderMgr::SCENE_LIGHT_STRENGTH, mSceneLightStrength);
|
||||
|
||||
LLColor3 ambient(getTotalAmbient());
|
||||
|
||||
shader->uniform3fv(LLShaderMgr::AMBIENT, LLVector3(ambient.mV));
|
||||
shader->uniform3fv(LLShaderMgr::AMBIENT_LINEAR, linearColor3v(getAmbientColor()/3.f)); // note magic number 3.f comes from SLIDER_SCALE_SUN_AMBIENT
|
||||
shader->uniform3fv(LLShaderMgr::SUNLIGHT_LINEAR, linearColor3v(getSunlightColor()));
|
||||
shader->uniform3fv(LLShaderMgr::MOONLIGHT_LINEAR,linearColor3v(getMoonlightColor()));
|
||||
|
||||
if (radiance_pass)
|
||||
{ // during an irradiance map update, disable ambient lighting (direct lighting only) and desaturate sky color (avoid tinting the world blue)
|
||||
shader->uniform3fv(LLShaderMgr::AMBIENT_LINEAR, LLVector3::zero.mV);
|
||||
}
|
||||
else
|
||||
{
|
||||
shader->uniform3fv(LLShaderMgr::AMBIENT_LINEAR, linearColor3v(getAmbientColor() / 3.f)); // note magic number 3.f comes from SLIDER_SCALE_SUN_AMBIENT
|
||||
}
|
||||
|
||||
shader->uniform3fv(LLShaderMgr::BLUE_HORIZON_LINEAR, linearColor3v(getBlueHorizon() / 2.f)); // note magic number of 2.f comes from SLIDER_SCALE_BLUE_HORIZON_DENSITY
|
||||
shader->uniform3fv(LLShaderMgr::BLUE_DENSITY_LINEAR, linearColor3v(getBlueDensity() / 2.f));
|
||||
|
||||
shader->uniform3fv(LLShaderMgr::SUNLIGHT_LINEAR, linearColor3v(sunDiffuse));
|
||||
shader->uniform3fv(LLShaderMgr::MOONLIGHT_LINEAR,linearColor3v(moonDiffuse));
|
||||
|
||||
shader->uniform1f(LLShaderMgr::REFLECTION_PROBE_AMBIANCE, getTotalReflectionProbeAmbiance());
|
||||
|
||||
|
|
@ -724,16 +739,14 @@ void LLSettingsVOSky::applySpecial(void *ptarget, bool force)
|
|||
shader->uniform1f(LLShaderMgr::SUN_MOON_GLOW_FACTOR, getSunMoonGlowFactor());
|
||||
shader->uniform1f(LLShaderMgr::DENSITY_MULTIPLIER, getDensityMultiplier());
|
||||
shader->uniform1f(LLShaderMgr::DISTANCE_MULTIPLIER, getDistanceMultiplier());
|
||||
|
||||
|
||||
shader->uniform1f(LLShaderMgr::HAZE_DENSITY_LINEAR, sRGBtoLinear(getHazeDensity()));
|
||||
|
||||
F32 g = getGamma();
|
||||
F32 display_gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma");
|
||||
|
||||
shader->uniform1f(LLShaderMgr::GAMMA, g);
|
||||
shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, display_gamma);
|
||||
|
||||
shader->uniform3fv(LLShaderMgr::BLUE_HORIZON_LINEAR, linearColor3v(getBlueHorizon()/2.f)); // note magic number of 2.f comes from SLIDER_SCALE_BLUE_HORIZON_DENSITY
|
||||
shader->uniform3fv(LLShaderMgr::BLUE_DENSITY_LINEAR, linearColor3v(getBlueDensity()/2.f));
|
||||
shader->uniform1f(LLShaderMgr::HAZE_DENSITY_LINEAR, sRGBtoLinear(getHazeDensity()));
|
||||
}
|
||||
|
||||
LLSettingsSky::parammapping_t LLSettingsVOSky::getParameterMap() const
|
||||
|
|
|
|||
|
|
@ -245,7 +245,6 @@ bool handleSetShaderChanged(const LLSD& newvalue)
|
|||
// ALM depends onto atmospheric shaders, state might have changed
|
||||
bool old_state = LLPipeline::sRenderDeferred;
|
||||
LLPipeline::refreshCachedSettings();
|
||||
gPipeline.updateRenderDeferred();
|
||||
if (old_state != LLPipeline::sRenderDeferred)
|
||||
{
|
||||
gPipeline.releaseGLBuffers();
|
||||
|
|
@ -301,7 +300,6 @@ bool handleRenderTransparentWaterChanged(const LLSD& newvalue)
|
|||
if (gPipeline.isInit())
|
||||
{
|
||||
gPipeline.updateRenderTransparentWater();
|
||||
gPipeline.updateRenderDeferred();
|
||||
gPipeline.releaseGLBuffers();
|
||||
gPipeline.createGLBuffers();
|
||||
gPipeline.resetVertexBuffers();
|
||||
|
|
@ -540,7 +538,6 @@ static bool handleReflectionProbeDetailChanged(const LLSD& newvalue)
|
|||
if (gPipeline.isInit())
|
||||
{
|
||||
LLPipeline::refreshCachedSettings();
|
||||
gPipeline.updateRenderDeferred();
|
||||
gPipeline.releaseGLBuffers();
|
||||
gPipeline.createGLBuffers();
|
||||
gPipeline.resetVertexBuffers();
|
||||
|
|
@ -549,46 +546,6 @@ static bool handleReflectionProbeDetailChanged(const LLSD& newvalue)
|
|||
return true;
|
||||
}
|
||||
|
||||
#if 0 // DEPRECATED
|
||||
// NOTE: may be triggered by RenderDeferred OR RenderPBR changing, don't trust "newvalue"
|
||||
static bool handleRenderDeferredChanged(const LLSD& newvalue)
|
||||
{
|
||||
LLRenderTarget::sUseFBO = gSavedSettings.getBOOL("RenderDeferred");
|
||||
if (gPipeline.isInit())
|
||||
{
|
||||
LLPipeline::refreshCachedSettings();
|
||||
gPipeline.updateRenderDeferred();
|
||||
gPipeline.releaseGLBuffers();
|
||||
gPipeline.createGLBuffers();
|
||||
gPipeline.resetVertexBuffers();
|
||||
if (LLPipeline::sRenderDeferred == (BOOL)LLRenderTarget::sUseFBO)
|
||||
{
|
||||
LLViewerShaderMgr::instance()->setShaders();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// This looks a great deal like handleRenderDeferredChanged because
|
||||
// Advanced Lighting (Materials) implies bumps and shiny so disabling
|
||||
// bumps should further disable that feature.
|
||||
//
|
||||
static bool handleRenderBumpChanged(const LLSD& newval)
|
||||
{
|
||||
LLRenderTarget::sUseFBO = newval.asBoolean() && gSavedSettings.getBOOL("RenderDeferred");
|
||||
if (gPipeline.isInit())
|
||||
{
|
||||
gPipeline.updateRenderBump();
|
||||
gPipeline.updateRenderDeferred();
|
||||
gPipeline.releaseGLBuffers();
|
||||
gPipeline.createGLBuffers();
|
||||
gPipeline.resetVertexBuffers();
|
||||
LLViewerShaderMgr::instance()->setShaders();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool handleRenderDebugPipelineChanged(const LLSD& newvalue)
|
||||
{
|
||||
gDebugPipeline = newvalue.asBoolean();
|
||||
|
|
@ -1229,6 +1186,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);
|
||||
|
|
|
|||
|
|
@ -1062,15 +1062,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();
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -1171,6 +1162,12 @@ void display_cube_face()
|
|||
|
||||
display_update_camera();
|
||||
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Env Update");
|
||||
// update all the sky/atmospheric/water settings
|
||||
LLEnvironment::instance().update(LLViewerCamera::getInstance());
|
||||
}
|
||||
|
||||
LLSpatialGroup::sNoDelete = TRUE;
|
||||
|
||||
S32 occlusion = LLPipeline::sUseOcclusion;
|
||||
|
|
|
|||
|
|
@ -7347,6 +7347,14 @@ const LLUUID& LLViewerObject::getRenderMaterialID(U8 te) const
|
|||
return LLUUID::null;
|
||||
}
|
||||
|
||||
void LLViewerObject::rebuildMaterial()
|
||||
{
|
||||
llassert(!isDead());
|
||||
|
||||
faceMappingChanged();
|
||||
gPipeline.markTextured(mDrawable);
|
||||
}
|
||||
|
||||
void LLViewerObject::setRenderMaterialID(S32 te_in, const LLUUID& id, bool update_server)
|
||||
{
|
||||
// implementation is delicate
|
||||
|
|
@ -7375,17 +7383,16 @@ void LLViewerObject::setRenderMaterialID(S32 te_in, const LLUUID& id, bool updat
|
|||
}
|
||||
|
||||
|
||||
LLFetchedGLTFMaterial* new_material = nullptr;
|
||||
if (id.notNull())
|
||||
{
|
||||
new_material = gGLTFMaterialList.getMaterial(id);
|
||||
}
|
||||
|
||||
// update local state
|
||||
for (S32 te = start_idx; te < end_idx; ++te)
|
||||
{
|
||||
|
||||
LLGLTFMaterial* new_material = nullptr;
|
||||
LLTextureEntry* tep = getTE(te);
|
||||
|
||||
if (id.notNull())
|
||||
{
|
||||
new_material = gGLTFMaterialList.getMaterial(id);
|
||||
}
|
||||
|
||||
bool material_changed = !param_block || id != param_block->getMaterial(te);
|
||||
|
||||
|
|
@ -7412,8 +7419,19 @@ void LLViewerObject::setRenderMaterialID(S32 te_in, const LLUUID& id, bool updat
|
|||
}
|
||||
|
||||
// signal to render pipe that render batches must be rebuilt for this object
|
||||
faceMappingChanged();
|
||||
gPipeline.markTextured(mDrawable);
|
||||
if (!new_material)
|
||||
{
|
||||
rebuildMaterial();
|
||||
}
|
||||
else
|
||||
{
|
||||
LLPointer<LLViewerObject> this_ptr = this;
|
||||
new_material->onMaterialComplete([this_ptr]() mutable {
|
||||
if (this_ptr->isDead()) { return; }
|
||||
|
||||
this_ptr->rebuildMaterial();
|
||||
});
|
||||
}
|
||||
|
||||
if (update_server)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -229,6 +229,7 @@ public:
|
|||
private:
|
||||
void resetRotTime();
|
||||
void setRenderMaterialIDs(const LLRenderMaterialParams* material_params, bool local_origin);
|
||||
void rebuildMaterial();
|
||||
public:
|
||||
void resetRot();
|
||||
void applyAngularVelocity(F32 dt);
|
||||
|
|
|
|||
|
|
@ -475,7 +475,6 @@ void LLViewerShaderMgr::setShaders()
|
|||
gPipeline.releaseGLBuffers();
|
||||
|
||||
LLPipeline::sRenderGlow = gSavedSettings.getBOOL("RenderGlow");
|
||||
LLPipeline::updateRenderDeferred();
|
||||
|
||||
//hack to reset buffers that change behavior with shaders
|
||||
gPipeline.resetVertexBuffers();
|
||||
|
|
@ -504,10 +503,7 @@ void LLViewerShaderMgr::setShaders()
|
|||
|
||||
//bool canRenderDeferred = true; // DEPRECATED -- LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred");
|
||||
//bool hasWindLightShaders = true; // DEPRECATED -- LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders");
|
||||
S32 shadow_detail = gSavedSettings.getS32("RenderShadowDetail");
|
||||
bool pbr = gSavedSettings.getBOOL("RenderPBR");
|
||||
bool doingWindLight = true; //DEPRECATED -- hasWindLightShaders&& gSavedSettings.getBOOL("WindLightUseAtmosShaders");
|
||||
bool useRenderDeferred = true; //DEPRECATED -- doingWindLight&& canRenderDeferred&& gSavedSettings.getBOOL("RenderDeferred");
|
||||
|
||||
S32 light_class = 3;
|
||||
S32 interface_class = 2;
|
||||
|
|
@ -516,32 +512,7 @@ void LLViewerShaderMgr::setShaders()
|
|||
S32 effect_class = 2;
|
||||
S32 wl_class = 1;
|
||||
S32 water_class = 3;
|
||||
S32 deferred_class = 0;
|
||||
|
||||
if (useRenderDeferred)
|
||||
{
|
||||
//shadows
|
||||
switch (shadow_detail)
|
||||
{
|
||||
case 1:
|
||||
deferred_class = 2; // PCF shadows
|
||||
break;
|
||||
|
||||
case 2:
|
||||
deferred_class = 2; // PCF shadows
|
||||
break;
|
||||
|
||||
case 0:
|
||||
default:
|
||||
deferred_class = 1; // no shadows
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (deferred_class > 0 && pbr)
|
||||
{
|
||||
deferred_class = 3;
|
||||
}
|
||||
S32 deferred_class = 3;
|
||||
|
||||
if (doingWindLight)
|
||||
{
|
||||
|
|
@ -880,6 +851,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)
|
||||
{
|
||||
|
|
@ -896,6 +868,23 @@ std::string LLViewerShaderMgr::loadBasicShaders()
|
|||
attribs["LOCAL_LIGHT_KILL"] = "1";
|
||||
}
|
||||
|
||||
S32 shadow_detail = gSavedSettings.getS32("RenderShadowDetail");
|
||||
|
||||
if (shadow_detail >= 1)
|
||||
{
|
||||
attribs["SUN_SHADOW"] = "1";
|
||||
|
||||
if (shadow_detail >= 2)
|
||||
{
|
||||
attribs["SPOT_SHADOW"] = "1";
|
||||
}
|
||||
}
|
||||
|
||||
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++)
|
||||
{
|
||||
|
|
@ -935,7 +924,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] ) );
|
||||
|
|
@ -1759,8 +1748,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
|
|||
{
|
||||
gDeferredTreeShadowProgram.mName = "Deferred Tree Shadow Shader";
|
||||
gDeferredTreeShadowProgram.mShaderFiles.clear();
|
||||
gDeferredTreeShadowProgram.mFeatures.isDeferred = true;
|
||||
gDeferredTreeShadowProgram.mFeatures.hasShadows = true;
|
||||
gDeferredTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowV.glsl", GL_VERTEX_SHADER));
|
||||
gDeferredTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowF.glsl", GL_FRAGMENT_SHADER));
|
||||
gDeferredTreeShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
|
||||
|
|
@ -1773,8 +1760,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
|
|||
{
|
||||
gDeferredSkinnedTreeShadowProgram.mName = "Deferred Skinned Tree Shadow Shader";
|
||||
gDeferredSkinnedTreeShadowProgram.mShaderFiles.clear();
|
||||
gDeferredSkinnedTreeShadowProgram.mFeatures.isDeferred = true;
|
||||
gDeferredSkinnedTreeShadowProgram.mFeatures.hasShadows = true;
|
||||
gDeferredSkinnedTreeShadowProgram.mFeatures.hasObjectSkinning = true;
|
||||
gDeferredSkinnedTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowSkinnedV.glsl", GL_VERTEX_SHADER));
|
||||
gDeferredSkinnedTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowF.glsl", GL_FRAGMENT_SHADER));
|
||||
|
|
@ -3881,6 +3866,12 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
|
|||
{
|
||||
gReflectionProbeDisplayProgram.mName = "Reflection Probe Display Shader";
|
||||
gReflectionProbeDisplayProgram.mFeatures.hasReflectionProbes = true;
|
||||
gReflectionProbeDisplayProgram.mFeatures.hasSrgb = true;
|
||||
gReflectionProbeDisplayProgram.mFeatures.calculatesAtmospherics = true;
|
||||
gReflectionProbeDisplayProgram.mFeatures.hasAtmospherics = true;
|
||||
gReflectionProbeDisplayProgram.mFeatures.hasTransport = true;
|
||||
gReflectionProbeDisplayProgram.mFeatures.hasGamma = true;
|
||||
gReflectionProbeDisplayProgram.mFeatures.isDeferred = true;
|
||||
gReflectionProbeDisplayProgram.mShaderFiles.clear();
|
||||
gReflectionProbeDisplayProgram.mShaderFiles.push_back(make_pair("interface/reflectionprobeV.glsl", GL_VERTEX_SHADER));
|
||||
gReflectionProbeDisplayProgram.mShaderFiles.push_back(make_pair("interface/reflectionprobeF.glsl", GL_FRAGMENT_SHADER));
|
||||
|
|
@ -3934,6 +3925,9 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
|
|||
{
|
||||
gReflectionMipProgram.mName = "Reflection Mip Shader";
|
||||
gReflectionMipProgram.mFeatures.isDeferred = true;
|
||||
gReflectionMipProgram.mFeatures.hasGamma = true;
|
||||
gReflectionMipProgram.mFeatures.hasAtmospherics = true;
|
||||
gReflectionMipProgram.mFeatures.calculatesAtmospherics = true;
|
||||
gReflectionMipProgram.mShaderFiles.clear();
|
||||
gReflectionMipProgram.mShaderFiles.push_back(make_pair("interface/splattexturerectV.glsl", GL_VERTEX_SHADER));
|
||||
gReflectionMipProgram.mShaderFiles.push_back(make_pair("interface/reflectionmipF.glsl", GL_FRAGMENT_SHADER));
|
||||
|
|
|
|||
|
|
@ -6072,7 +6072,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
|
|||
//U32 color_fmt = type == LLSnapshotModel::SNAPSHOT_TYPE_DEPTH ? GL_DEPTH_COMPONENT : GL_RGBA;
|
||||
U32 color_fmt = (type == LLSnapshotModel::SNAPSHOT_TYPE_DEPTH || type == LLSnapshotModel::SNAPSHOT_TYPE_DEPTH24) ? GL_DEPTH_COMPONENT : GL_RGBA;
|
||||
// </FS:Ansariel>
|
||||
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();
|
||||
|
|
@ -6379,9 +6379,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))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -345,7 +345,6 @@ bool LLPipeline::sRenderAttachedLights = true;
|
|||
bool LLPipeline::sRenderAttachedParticles = true;
|
||||
bool LLPipeline::sRenderDeferred = false;
|
||||
bool LLPipeline::sReflectionProbesEnabled = false;
|
||||
bool LLPipeline::sRenderPBR = false;
|
||||
S32 LLPipeline::sVisibleLightCount = 0;
|
||||
bool LLPipeline::sRenderingHUDs;
|
||||
F32 LLPipeline::sDistortionWaterClipPlaneMargin = 1.0125f;
|
||||
|
|
@ -519,14 +518,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;
|
||||
|
|
@ -887,11 +881,12 @@ LLPipeline::eFBOStatus LLPipeline::doAllocateScreenBuffer(U32 resX, U32 resY)
|
|||
bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
|
||||
if (mRT == &mMainRT)
|
||||
if (mRT == &mMainRT && sReflectionProbesEnabled)
|
||||
{ // hacky -- allocate auxillary buffer
|
||||
gCubeSnapshot = TRUE;
|
||||
mReflectionMapManager.initReflectionMaps();
|
||||
mRT = &mAuxillaryRT;
|
||||
U32 res = LL_REFLECTION_PROBE_RESOLUTION * 2;
|
||||
U32 res = mReflectionMapManager.mProbeResolution * 2; //multiply by 2 because probes will be super sampled
|
||||
allocateScreenBuffer(res, res, samples);
|
||||
mRT = &mMainRT;
|
||||
gCubeSnapshot = FALSE;
|
||||
|
|
@ -930,71 +925,60 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (LLPipeline::sRenderDeferred)
|
||||
{
|
||||
S32 shadow_detail = RenderShadowDetail;
|
||||
bool ssao = RenderDeferredSSAO;
|
||||
S32 shadow_detail = RenderShadowDetail;
|
||||
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 (!addDeferredAttachments(mRT->deferredScreen)) return false;
|
||||
//allocate deferred rendering color buffers
|
||||
if (!mRT->deferredScreen.allocate(resX, resY, GL_RGBA, true)) return false;
|
||||
if (!addDeferredAttachments(mRT->deferredScreen)) return false;
|
||||
|
||||
GLuint screenFormat = GL_RGBA16;
|
||||
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);
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
mRT->fxaaBuffer.release();
|
||||
}
|
||||
if (samples > 0)
|
||||
{
|
||||
if (!mRT->fxaaBuffer.allocate(resX, resY, GL_RGBA)) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
mRT->fxaaBuffer.release();
|
||||
}
|
||||
|
||||
// if (shadow_detail > 0 || ssao || RenderDepthOfField || samples > 0)
|
||||
// [RLVa:KB] - @setsphere
|
||||
if (shadow_detail > 0 || ssao || RenderDepthOfField || samples > 0 || RlvActions::hasPostProcess())
|
||||
// [/RLVa:KB]
|
||||
{ //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
|
||||
{
|
||||
mRT->deferredLight.release();
|
||||
}
|
||||
|
||||
allocateShadowBuffer(resX, resY);
|
||||
allocateShadowBuffer(resX, resY);
|
||||
|
||||
//HACK make screenbuffer allocations start failing after 30 seconds
|
||||
if (gSavedSettings.getBOOL("SimulateFBOFailure"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!gCubeSnapshot && RenderScreenSpaceReflections) // hack to not allocate mSceneMap for cube snapshots
|
||||
{
|
||||
mRT->deferredLight.release();
|
||||
mSceneMap.allocate(resX, resY, GL_RGB, true);
|
||||
}
|
||||
|
||||
releaseSunShadowTargets();
|
||||
releaseSpotShadowTargets();
|
||||
//HACK make screenbuffer allocations start failing after 30 seconds
|
||||
if (gSavedSettings.getBOOL("SimulateFBOFailure"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
mRT->fxaaBuffer.release();
|
||||
mRT->screen.release();
|
||||
mRT->deferredScreen.release(); //make sure to release any render targets that share a depth buffer with mRT->deferredScreen first
|
||||
|
||||
if (!mRT->screen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_TEXTURE, FALSE)) return false;
|
||||
}
|
||||
|
||||
gGL.getTexUnit(0)->disable();
|
||||
gGL.getTexUnit(0)->disable();
|
||||
|
||||
stop_glerror();
|
||||
|
||||
|
|
@ -1017,7 +1001,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;
|
||||
}
|
||||
|
|
@ -1042,7 +1026,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;
|
||||
}
|
||||
|
|
@ -1105,22 +1089,6 @@ void LLPipeline::updateRenderBump()
|
|||
sRenderBump = TRUE; // DEPRECATED -- gSavedSettings.getBOOL("RenderObjectBump");
|
||||
}
|
||||
|
||||
// static
|
||||
void LLPipeline::updateRenderDeferred()
|
||||
{
|
||||
sRenderPBR = sRenderDeferred;
|
||||
|
||||
exoPostProcess::instance().ExodusRenderPostUpdate(); // <FS:CR> Import Vignette from Exodus
|
||||
|
||||
// [RLVa:KB] - @setsphere
|
||||
if (!sRenderDeferred && RlvActions::hasBehaviour(RLV_BHVR_SETSPHERE) && WindLightUseAtmosShaders)
|
||||
{
|
||||
LLRenderTarget::sUseFBO = true;
|
||||
LLPipeline::sUseDepthTexture = true;
|
||||
}
|
||||
// [/RLVa:KB]
|
||||
}
|
||||
|
||||
// static
|
||||
void LLPipeline::refreshCachedSettings()
|
||||
{
|
||||
|
|
@ -1227,10 +1195,10 @@ void LLPipeline::refreshCachedSettings()
|
|||
|
||||
RenderAutoHideSurfaceAreaLimit = gSavedSettings.getF32("RenderAutoHideSurfaceAreaLimit");
|
||||
RenderScreenSpaceReflections = gSavedSettings.getBOOL("RenderScreenSpaceReflections");
|
||||
sReflectionProbesEnabled = gSavedSettings.getBOOL("RenderReflectionsEnabled");
|
||||
sReflectionProbesEnabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderReflectionsEnabled") && gSavedSettings.getBOOL("RenderReflectionsEnabled");
|
||||
RenderSpotLight = nullptr;
|
||||
|
||||
updateRenderDeferred();
|
||||
exoPostProcess::instance().ExodusRenderPostUpdate(); // <FS:CR> Import Vignette from Exodus
|
||||
|
||||
if (gNonInteractive)
|
||||
{
|
||||
|
|
@ -1261,6 +1229,8 @@ void LLPipeline::releaseGLBuffers()
|
|||
mWaterDis.release();
|
||||
mBake.release();
|
||||
|
||||
mSceneMap.release();
|
||||
|
||||
for (U32 i = 0; i < 3; i++)
|
||||
{
|
||||
mGlow[i].release();
|
||||
|
|
@ -1331,17 +1301,17 @@ void LLPipeline::createGLBuffers()
|
|||
stop_glerror();
|
||||
assertInitialized();
|
||||
|
||||
updateRenderDeferred();
|
||||
exoPostProcess::instance().ExodusRenderPostUpdate(); // <FS:CR> Import Vignette from Exodus
|
||||
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
|
||||
// <FS:Ansariel> Allow higher resolution rendering in mesh render preview
|
||||
//mBake.allocate(512, 512, GL_RGBA, TRUE, FALSE, LLTexUnit::TT_TEXTURE, true); // SL-12781 Build > Upload > Model; 3D Preview
|
||||
mBake.allocate(1024, 1024, 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
|
||||
mBake.allocate(1024, 1024, GL_RGBA, true); // SL-12781 Build > Upload > Model; 3D Preview
|
||||
// <FS:Ansariel>
|
||||
|
||||
stop_glerror();
|
||||
|
|
@ -1353,7 +1323,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);
|
||||
|
|
@ -1459,7 +1429,7 @@ void LLPipeline::createLUTBuffers()
|
|||
delete [] ls;
|
||||
}
|
||||
|
||||
mPbrBrdfLut.allocate(512, 512, GL_RG16F, false, false);
|
||||
mPbrBrdfLut.allocate(512, 512, GL_RG16F);
|
||||
mPbrBrdfLut.bindTarget();
|
||||
gDeferredGenBrdfLutProgram.bind();
|
||||
|
||||
|
|
@ -4220,10 +4190,31 @@ 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);
|
||||
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred pools"); //LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLS);
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred pools");
|
||||
|
||||
LLGLEnable cull(GL_CULL_FACE);
|
||||
|
||||
|
|
@ -4272,7 +4263,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera, bool do_occlusion)
|
|||
pool_set_t::iterator iter2 = iter1;
|
||||
if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0)
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred pool render"); //LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLRENDER);
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred pool render");
|
||||
|
||||
gGLLastMatrix = NULL;
|
||||
gGL.loadMatrix(gGLModelView);
|
||||
|
|
@ -4332,7 +4323,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera, bool do_occlusion)
|
|||
|
||||
void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_POST_DEFERRED_POOLS);
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
|
||||
LL_PROFILE_GPU_ZONE("renderGeomPostDeferred");
|
||||
|
||||
if (gUseWireframe)
|
||||
|
|
@ -4349,10 +4340,16 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
|
|||
calcNearbyLights(camera);
|
||||
setupHWLights(NULL);
|
||||
|
||||
gGL.setSceneBlendType(LLRender::BT_ALPHA);
|
||||
gGL.setColorMask(true, false);
|
||||
|
||||
pool_set_t::iterator iter1 = mPools.begin();
|
||||
|
||||
if (gDebugGL || gDebugPipeline)
|
||||
{
|
||||
LLGLState::checkStates(GL_FALSE);
|
||||
}
|
||||
|
||||
while ( iter1 != mPools.end() )
|
||||
{
|
||||
LLDrawPool *poolp = *iter1;
|
||||
|
|
@ -4362,7 +4359,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
|
|||
pool_set_t::iterator iter2 = iter1;
|
||||
if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0)
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred poolrender"); //LL_RECORD_BLOCK_TIME(FTM_POST_DEFERRED_POOLRENDER);
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred poolrender");
|
||||
|
||||
gGLLastMatrix = NULL;
|
||||
gGL.loadMatrix(gGLModelView);
|
||||
|
|
@ -5936,6 +5933,15 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
|
|||
// Ambient
|
||||
LLColor4 ambient = psky->getTotalAmbient();
|
||||
|
||||
static LLCachedControl<F32> ambiance_scale(gSavedSettings, "RenderReflectionProbeAmbianceScale", 8.f);
|
||||
|
||||
F32 light_scale = 1.f;
|
||||
|
||||
if (gCubeSnapshot && !mReflectionMapManager.isRadiancePass())
|
||||
{ //darken local lights based on brightening of sky lighting
|
||||
light_scale = 1.f / ambiance_scale;
|
||||
}
|
||||
|
||||
gGL.setAmbientLightColor(ambient);
|
||||
|
||||
bool sun_up = environment.getIsSunUp();
|
||||
|
|
@ -6029,7 +6035,7 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
|
|||
}
|
||||
|
||||
//send linear light color to shader
|
||||
LLColor4 light_color = light->getLightLinearColor();
|
||||
LLColor4 light_color = light->getLightLinearColor()*light_scale;
|
||||
light_color.mV[3] = 0.0f;
|
||||
|
||||
F32 fade = iter->fade;
|
||||
|
|
@ -7057,10 +7063,9 @@ void LLPipeline::doResetVertexBuffers(bool forced)
|
|||
LLVOPartGroup::destroyGL();
|
||||
gGL.resetVertexBuffer();
|
||||
|
||||
LLVertexBuffer::unbind();
|
||||
LLVertexBuffer::unbind();
|
||||
|
||||
updateRenderBump();
|
||||
//updateRenderDeferred(); // <FS:Ansariel> Moved further down because of exoPostProcess creating a new VB
|
||||
|
||||
sBakeSunlight = gSavedSettings.getBOOL("RenderBakeSunlight");
|
||||
sNoAlpha = gSavedSettings.getBOOL("RenderNoAlpha");
|
||||
|
|
@ -7076,9 +7081,7 @@ void LLPipeline::doResetVertexBuffers(bool forced)
|
|||
|
||||
LLVOPartGroup::restoreGL();
|
||||
|
||||
// <FS:Ansariel> Reset VB during TP
|
||||
updateRenderDeferred(); // Moved further down because of exoPostProcess creating a new VB
|
||||
// </FS:Ansariel>
|
||||
exoPostProcess::instance().ExodusRenderPostUpdate(); // <FS:CR> Import Vignette from Exodus
|
||||
}
|
||||
|
||||
void LLPipeline::renderObjects(U32 type, bool texture, bool batch_texture, bool rigged)
|
||||
|
|
@ -7792,10 +7795,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");
|
||||
|
||||
|
|
@ -7828,8 +7832,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");
|
||||
|
|
@ -7855,17 +7884,8 @@ void LLPipeline::renderFinalize()
|
|||
|
||||
gDeferredPostGammaCorrectProgram.uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f / 2.2f));
|
||||
|
||||
gGL.begin(LLRender::TRIANGLE_STRIP);
|
||||
gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
|
||||
gGL.vertex2f(-1, -1);
|
||||
|
||||
gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
|
||||
gGL.vertex2f(-1, 3);
|
||||
|
||||
gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
|
||||
gGL.vertex2f(3, -1);
|
||||
|
||||
gGL.end();
|
||||
mScreenTriangleVB->setBuffer();
|
||||
mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
|
||||
|
||||
gGL.getTexUnit(channel)->unbind(screenTarget()->getUsage());
|
||||
gDeferredPostGammaCorrectProgram.unbind();
|
||||
|
|
@ -8133,56 +8153,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)
|
||||
|
|
@ -8222,21 +8192,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)
|
||||
{
|
||||
|
|
@ -8402,6 +8375,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();
|
||||
|
|
@ -8410,6 +8388,8 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_
|
|||
|
||||
shader.uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, 1, mSunDiffuse.mV);
|
||||
shader.uniform3fv(LLShaderMgr::MOONLIGHT_COLOR, 1, mMoonDiffuse.mV);
|
||||
|
||||
shader.uniform1f(LLShaderMgr::REFLECTION_PROBE_MAX_LOD, mReflectionMapManager.mMaxProbeLOD);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -8431,8 +8411,6 @@ LLVector4 pow4fsrgb(LLVector4 v, F32 f)
|
|||
|
||||
void LLPipeline::renderDeferredLighting()
|
||||
{
|
||||
|
||||
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
|
||||
LL_PROFILE_GPU_ZONE("renderDeferredLighting");
|
||||
if (!sCull)
|
||||
|
|
@ -8440,32 +8418,22 @@ void LLPipeline::renderDeferredLighting()
|
|||
return;
|
||||
}
|
||||
|
||||
static LLCachedControl<F32> ambiance_scale(gSavedSettings, "RenderReflectionProbeAmbianceScale", 8.f);
|
||||
|
||||
F32 light_scale = 1.f;
|
||||
|
||||
if (gCubeSnapshot && !mReflectionMapManager.isRadiancePass())
|
||||
{ //darken local lights based on brightening of sky lighting
|
||||
light_scale = 1.f / ambiance_scale;
|
||||
}
|
||||
|
||||
LLRenderTarget *screen_target = &mRT->screen;
|
||||
//LLRenderTarget *deferred_target = &mRT->deferredScreen;
|
||||
//LLRenderTarget *deferred_depth_target = &mRT->deferredDepth;
|
||||
LLRenderTarget* deferred_light_target = &mRT->deferredLight;
|
||||
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("deferred"); //LL_RECORD_BLOCK_TIME(FTM_RENDER_DEFERRED);
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("deferred");
|
||||
LLViewerCamera *camera = LLViewerCamera::getInstance();
|
||||
|
||||
#if 0
|
||||
{
|
||||
LLGLDepthTest depth(GL_TRUE);
|
||||
deferred_depth_target->copyContents(*deferred_target,
|
||||
0,
|
||||
0,
|
||||
deferred_target->getWidth(),
|
||||
deferred_target->getHeight(),
|
||||
0,
|
||||
0,
|
||||
deferred_depth_target->getWidth(),
|
||||
deferred_depth_target->getHeight(),
|
||||
GL_DEPTH_BUFFER_BIT,
|
||||
GL_NEAREST);
|
||||
}
|
||||
#endif
|
||||
|
||||
LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE : 0);
|
||||
|
||||
if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
|
||||
|
|
@ -8473,11 +8441,6 @@ void LLPipeline::renderDeferredLighting()
|
|||
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
|
||||
}
|
||||
|
||||
// ati doesn't seem to love actually using the stencil buffer on FBO's
|
||||
//LLGLDisable stencil(GL_STENCIL_TEST);
|
||||
// glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
|
||||
// glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||||
|
||||
gGL.setColorMask(true, true);
|
||||
|
||||
// draw a cube around every light
|
||||
|
|
@ -8547,76 +8510,64 @@ void LLPipeline::renderDeferredLighting()
|
|||
|
||||
if (RenderDeferredSSAO)
|
||||
{
|
||||
/*if (gCubeSnapshot)
|
||||
{ // SSAO and shadows disabled in reflection maps
|
||||
deferred_light_target->bindTarget();
|
||||
glClearColor(1, 1, 1, 1);
|
||||
deferred_light_target->clear();
|
||||
glClearColor(0, 0, 0, 0);
|
||||
deferred_light_target->flush();
|
||||
}
|
||||
else*/
|
||||
// soften direct lighting lightmap
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - soften shadow");
|
||||
LL_PROFILE_GPU_ZONE("soften shadow");
|
||||
// blur lightmap
|
||||
screen_target->bindTarget();
|
||||
glClearColor(1, 1, 1, 1);
|
||||
screen_target->clear(GL_COLOR_BUFFER_BIT);
|
||||
glClearColor(0, 0, 0, 0);
|
||||
|
||||
bindDeferredShader(gDeferredBlurLightProgram);
|
||||
|
||||
LLVector3 go = RenderShadowGaussian;
|
||||
const U32 kern_length = 4;
|
||||
F32 blur_size = RenderShadowBlurSize;
|
||||
F32 dist_factor = RenderShadowBlurDistFactor;
|
||||
|
||||
// sample symmetrically with the middle sample falling exactly on 0.0
|
||||
F32 x = 0.f;
|
||||
|
||||
LLVector3 gauss[32]; // xweight, yweight, offset
|
||||
|
||||
for (U32 i = 0; i < kern_length; i++)
|
||||
{
|
||||
// soften direct lighting lightmap
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - soften shadow");
|
||||
LL_PROFILE_GPU_ZONE("soften shadow");
|
||||
// blur lightmap
|
||||
screen_target->bindTarget();
|
||||
glClearColor(1, 1, 1, 1);
|
||||
screen_target->clear(GL_COLOR_BUFFER_BIT);
|
||||
glClearColor(0, 0, 0, 0);
|
||||
|
||||
bindDeferredShader(gDeferredBlurLightProgram);
|
||||
mScreenTriangleVB->setBuffer();
|
||||
LLVector3 go = RenderShadowGaussian;
|
||||
const U32 kern_length = 4;
|
||||
F32 blur_size = RenderShadowBlurSize;
|
||||
F32 dist_factor = RenderShadowBlurDistFactor;
|
||||
|
||||
// sample symmetrically with the middle sample falling exactly on 0.0
|
||||
F32 x = 0.f;
|
||||
|
||||
LLVector3 gauss[32]; // xweight, yweight, offset
|
||||
|
||||
F32 screenPixelSize = 1.f / screen_target->getWidth();
|
||||
|
||||
for (U32 i = 0; i < kern_length; i++)
|
||||
{
|
||||
gauss[i].mV[0] = llgaussian(x, go.mV[0]);
|
||||
gauss[i].mV[1] = llgaussian(x, go.mV[1]);
|
||||
gauss[i].mV[2] = x;
|
||||
x += screenPixelSize;
|
||||
}
|
||||
|
||||
gDeferredBlurLightProgram.uniform2f(sDelta, screenPixelSize, 0.f);
|
||||
gDeferredBlurLightProgram.uniform1f(sDistFactor, dist_factor);
|
||||
gDeferredBlurLightProgram.uniform3fv(sKern, kern_length, gauss[0].mV);
|
||||
gDeferredBlurLightProgram.uniform1f(sKernScale, blur_size * (kern_length / 2.f - 0.5f));
|
||||
|
||||
{
|
||||
LLGLDisable blend(GL_BLEND);
|
||||
LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
|
||||
mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
|
||||
}
|
||||
|
||||
screen_target->flush();
|
||||
unbindDeferredShader(gDeferredBlurLightProgram);
|
||||
|
||||
bindDeferredShader(gDeferredBlurLightProgram, screen_target);
|
||||
|
||||
mScreenTriangleVB->setBuffer();
|
||||
deferred_light_target->bindTarget();
|
||||
|
||||
gDeferredBlurLightProgram.uniform2f(sDelta, 0.f, 1.f);
|
||||
|
||||
{
|
||||
LLGLDisable blend(GL_BLEND);
|
||||
LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
|
||||
mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
|
||||
}
|
||||
deferred_light_target->flush();
|
||||
unbindDeferredShader(gDeferredBlurLightProgram);
|
||||
gauss[i].mV[0] = llgaussian(x, go.mV[0]);
|
||||
gauss[i].mV[1] = llgaussian(x, go.mV[1]);
|
||||
gauss[i].mV[2] = x;
|
||||
x += 1.f;
|
||||
}
|
||||
|
||||
gDeferredBlurLightProgram.uniform2f(sDelta, 1.f, 0.f);
|
||||
gDeferredBlurLightProgram.uniform1f(sDistFactor, dist_factor);
|
||||
gDeferredBlurLightProgram.uniform3fv(sKern, kern_length, gauss[0].mV);
|
||||
gDeferredBlurLightProgram.uniform1f(sKernScale, blur_size * (kern_length / 2.f - 0.5f));
|
||||
|
||||
{
|
||||
LLGLDisable blend(GL_BLEND);
|
||||
LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
|
||||
mScreenTriangleVB->setBuffer();
|
||||
mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
|
||||
}
|
||||
|
||||
screen_target->flush();
|
||||
unbindDeferredShader(gDeferredBlurLightProgram);
|
||||
|
||||
bindDeferredShader(gDeferredBlurLightProgram, screen_target);
|
||||
|
||||
deferred_light_target->bindTarget();
|
||||
|
||||
gDeferredBlurLightProgram.uniform2f(sDelta, 0.f, 1.f);
|
||||
|
||||
{
|
||||
LLGLDisable blend(GL_BLEND);
|
||||
LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
|
||||
mScreenTriangleVB->setBuffer();
|
||||
mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
|
||||
}
|
||||
deferred_light_target->flush();
|
||||
unbindDeferredShader(gDeferredBlurLightProgram);
|
||||
}
|
||||
|
||||
screen_target->bindTarget();
|
||||
|
|
@ -8636,50 +8587,19 @@ void LLPipeline::renderDeferredLighting()
|
|||
soften_shader.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
|
||||
soften_shader.uniform3fv(LLShaderMgr::LIGHTNORM, 1, environment.getClampedLightNorm().mV);
|
||||
|
||||
if (!LLPipeline::sUnderWaterRender && LLPipeline::sRenderPBR)
|
||||
{
|
||||
soften_shader.bindTexture(LLShaderMgr::ALTERNATE_DIFFUSE_MAP, LLViewerFetchedTexture::sDefaultIrradiancePBRp); // PBR: irradiance
|
||||
}
|
||||
|
||||
if(LLPipeline::sRenderPBR)
|
||||
{
|
||||
LLVector3 cameraAtAxis = LLViewerCamera::getInstance()->getAtAxis();
|
||||
soften_shader.uniform3fv(LLShaderMgr::DEFERRED_VIEW_DIR, 1, cameraAtAxis.mV);
|
||||
}
|
||||
|
||||
{
|
||||
LLGLDepthTest depth(GL_FALSE);
|
||||
LLGLDisable blend(GL_BLEND);
|
||||
LLGLDisable test(GL_ALPHA_TEST);
|
||||
|
||||
// full screen blit
|
||||
|
||||
mScreenTriangleVB->setBuffer();
|
||||
mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
|
||||
|
||||
}
|
||||
|
||||
unbindDeferredShader(LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram);
|
||||
}
|
||||
|
||||
#if 0
|
||||
{ // render non-deferred geometry (fullbright, alpha, etc)
|
||||
LLGLDisable blend(GL_BLEND);
|
||||
//LLGLDisable stencil(GL_STENCIL_TEST);
|
||||
gGL.setSceneBlendType(LLRender::BT_ALPHA);
|
||||
|
||||
gPipeline.pushRenderTypeMask();
|
||||
|
||||
gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
|
||||
LLPipeline::RENDER_TYPE_CLOUDS,
|
||||
LLPipeline::RENDER_TYPE_WL_SKY,
|
||||
LLPipeline::END_RENDER_TYPES);
|
||||
|
||||
renderGeomPostDeferred(*LLViewerCamera::getInstance(), false);
|
||||
gPipeline.popRenderTypeMask();
|
||||
}
|
||||
#endif
|
||||
|
||||
bool render_local = RenderLocalLights; // && !gCubeSnapshot;
|
||||
|
||||
if (render_local)
|
||||
|
|
@ -8740,7 +8660,7 @@ void LLPipeline::renderDeferredLighting()
|
|||
F32 s = volume->getLightRadius() * 1.5f;
|
||||
|
||||
// send light color to shader in linear space
|
||||
LLColor3 col = volume->getLightLinearColor();
|
||||
LLColor3 col = volume->getLightLinearColor()*light_scale;
|
||||
|
||||
if (col.magVecSquared() < 0.001f)
|
||||
{
|
||||
|
|
@ -8834,7 +8754,7 @@ void LLPipeline::renderDeferredLighting()
|
|||
setupSpotLight(gDeferredSpotLightProgram, drawablep);
|
||||
|
||||
// send light color to shader in linear space
|
||||
LLColor3 col = volume->getLightLinearColor();
|
||||
LLColor3 col = volume->getLightLinearColor() * light_scale;
|
||||
|
||||
gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, c);
|
||||
gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s);
|
||||
|
|
@ -8909,7 +8829,7 @@ void LLPipeline::renderDeferredLighting()
|
|||
setupSpotLight(gDeferredMultiSpotLightProgram, drawablep);
|
||||
|
||||
// send light color to shader in linear space
|
||||
LLColor3 col = volume->getLightLinearColor();
|
||||
LLColor3 col = volume->getLightLinearColor() * light_scale;
|
||||
|
||||
gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v);
|
||||
gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, light_size_final);
|
||||
|
|
@ -8965,6 +8885,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);
|
||||
}
|
||||
|
||||
|
|
@ -9304,24 +9234,23 @@ static LLTrace::BlockTimerStatHandle FTM_SHADOW_ALPHA_TREE("Alpha Tree");
|
|||
static LLTrace::BlockTimerStatHandle FTM_SHADOW_ALPHA_GRASS("Alpha Grass");
|
||||
static LLTrace::BlockTimerStatHandle FTM_SHADOW_FULLBRIGHT_ALPHA_MASKED("Fullbright Alpha Masked");
|
||||
|
||||
void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult& result, bool use_shader, bool use_occlusion, U32 target_width)
|
||||
void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult& result, bool depth_clamp)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_SHADOW_RENDER);
|
||||
LL_PROFILE_GPU_ZONE("renderShadow");
|
||||
//disable occlusion culling for shadow passes (save setting to restore later)
|
||||
S32 occlude = LLPipeline::sUseOcclusion;
|
||||
if (!use_occlusion)
|
||||
{
|
||||
LLPipeline::sUseOcclusion = 0;
|
||||
}
|
||||
|
||||
LLPipeline::sShadowRender = true;
|
||||
|
||||
// disable occlusion culling during shadow render
|
||||
U32 saved_occlusion = sUseOcclusion;
|
||||
sUseOcclusion = 0;
|
||||
|
||||
static const U32 types[] = {
|
||||
LLRenderPass::PASS_SIMPLE,
|
||||
LLRenderPass::PASS_FULLBRIGHT,
|
||||
LLRenderPass::PASS_SHINY,
|
||||
LLRenderPass::PASS_BUMP,
|
||||
LLRenderPass::PASS_FULLBRIGHT_SHINY ,
|
||||
LLRenderPass::PASS_FULLBRIGHT_SHINY,
|
||||
LLRenderPass::PASS_MATERIAL,
|
||||
LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE,
|
||||
LLRenderPass::PASS_SPECMAP,
|
||||
|
|
@ -9336,21 +9265,14 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
|
|||
LLGLEnable cull(GL_CULL_FACE);
|
||||
|
||||
//enable depth clamping if available
|
||||
LLGLEnable depth_clamp(GL_DEPTH_CLAMP);
|
||||
LLGLEnable clamp_depth(depth_clamp ? GL_DEPTH_CLAMP : 0);
|
||||
|
||||
LLGLDepthTest depth_test(GL_TRUE, GL_TRUE, GL_LESS);
|
||||
|
||||
if (use_shader)
|
||||
{
|
||||
gDeferredShadowCubeProgram.bind();
|
||||
}
|
||||
|
||||
|
||||
updateCull(shadow_cam, result);
|
||||
|
||||
stateSort(shadow_cam, result);
|
||||
|
||||
|
||||
//generate shadow map
|
||||
gGL.matrixMode(LLRender::MM_PROJECTION);
|
||||
gGL.pushMatrix();
|
||||
|
|
@ -9413,25 +9335,14 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
|
|||
gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
|
||||
}
|
||||
|
||||
if (occlude > 1)
|
||||
if (LLPipeline::sUseOcclusion > 1)
|
||||
{ // do occlusion culling against non-masked only to take advantage of hierarchical Z
|
||||
doOcclusion(shadow_cam);
|
||||
}
|
||||
|
||||
|
||||
if (use_shader)
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow geom");
|
||||
|
||||
gDeferredShadowProgram.unbind();
|
||||
renderGeomShadow(shadow_cam);
|
||||
gDeferredShadowProgram.bind();
|
||||
gDeferredShadowProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow geom");
|
||||
|
||||
renderGeomShadow(shadow_cam);
|
||||
}
|
||||
|
||||
|
|
@ -9439,6 +9350,8 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
|
|||
LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha");
|
||||
LL_PROFILE_GPU_ZONE("shadow alpha");
|
||||
|
||||
U32 target_width = LLRenderTarget::sCurResX;
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
bool rigged = i == 1;
|
||||
|
|
@ -9520,11 +9433,6 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
|
|||
gGLLastMatrix = NULL;
|
||||
gGL.loadMatrix(gGLModelView);
|
||||
|
||||
if (use_shader)
|
||||
{
|
||||
gDeferredShadowProgram.unbind();
|
||||
}
|
||||
|
||||
gGL.setColorMask(true, true);
|
||||
|
||||
gGL.matrixMode(LLRender::MM_PROJECTION);
|
||||
|
|
@ -9533,7 +9441,8 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
|
|||
gGL.popMatrix();
|
||||
gGLLastMatrix = NULL;
|
||||
|
||||
LLPipeline::sUseOcclusion = occlude;
|
||||
// reset occlusion culling flag
|
||||
sUseOcclusion = saved_occlusion;
|
||||
LLPipeline::sShadowRender = false;
|
||||
}
|
||||
|
||||
|
|
@ -10374,11 +10283,9 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
|
|||
mRT->shadow[j].getViewport(gGLViewport);
|
||||
mRT->shadow[j].clear();
|
||||
|
||||
U32 target_width = mRT->shadow[j].getWidth();
|
||||
|
||||
{
|
||||
static LLCullResult result[4];
|
||||
renderShadow(view[j], proj[j], shadow_cam, result[j], true, true, target_width);
|
||||
renderShadow(view[j], proj[j], shadow_cam, result[j], true);
|
||||
}
|
||||
|
||||
mRT->shadow[j].flush();
|
||||
|
|
@ -10525,15 +10432,13 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
|
|||
mSpotShadow[i].getViewport(gGLViewport);
|
||||
mSpotShadow[i].clear();
|
||||
|
||||
U32 target_width = mSpotShadow[i].getWidth();
|
||||
|
||||
static LLCullResult result[2];
|
||||
|
||||
LLViewerCamera::sCurCameraID = (LLViewerCamera::eCameraID)(LLViewerCamera::CAMERA_SPOT_SHADOW0 + i);
|
||||
|
||||
RenderSpotLight = drawable;
|
||||
|
||||
renderShadow(view[i + 4], proj[i + 4], shadow_cam, result[i], false, true, target_width);
|
||||
renderShadow(view[i + 4], proj[i + 4], shadow_cam, result[i], false);
|
||||
|
||||
RenderSpotLight = nullptr;
|
||||
|
||||
|
|
@ -10818,7 +10723,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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -318,7 +318,7 @@ public:
|
|||
|
||||
void renderHighlight(const LLViewerObject* obj, F32 fade);
|
||||
|
||||
void renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& camera, LLCullResult& result, bool use_shader, bool use_occlusion, U32 target_width);
|
||||
void renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& camera, LLCullResult& result, bool depth_clamp);
|
||||
void renderHighlights();
|
||||
void renderDebug();
|
||||
void renderPhysicsDisplay();
|
||||
|
|
@ -428,7 +428,6 @@ public:
|
|||
|
||||
static void updateRenderTransparentWater();
|
||||
static void updateRenderBump();
|
||||
static void updateRenderDeferred();
|
||||
static void refreshCachedSettings();
|
||||
|
||||
void addDebugBlip(const LLVector3& position, const LLColor4& color);
|
||||
|
|
@ -654,7 +653,6 @@ public:
|
|||
static bool sRenderAttachedParticles;
|
||||
static bool sRenderDeferred;
|
||||
static bool sReflectionProbesEnabled;
|
||||
static bool sRenderPBR;
|
||||
static S32 sVisibleLightCount;
|
||||
static bool sRenderingHUDs;
|
||||
static F32 sDistortionWaterClipPlaneMargin;
|
||||
|
|
@ -702,6 +700,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;
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ PCRE Copyright (c) 1997-2012 University of Cambridge.
|
|||
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga.
|
||||
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com).
|
||||
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
|
||||
xxHash Copyright (C) 2012-2020 Yann Collet.
|
||||
zlib Copyright (C) 1995-2012 Jean-loup Gailly und Mark Adler.
|
||||
|
||||
Second Life Viewer verwendet Havok (TM) Physics. (c)Copyright 1999-2010 Havok.com Inc. (und Lizenzgeber). Alle Rechte vorbehalten. Details siehe www.havok.com.
|
||||
|
|
|
|||
|
|
@ -260,6 +260,7 @@ PCRE Copyright (c) 1997-2012 University of Cambridge
|
|||
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
|
||||
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
|
||||
xxHash Copyright (C) 2012-2020 Yann Collet.
|
||||
zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler.
|
||||
Some icons by Joseph Wain / glyphish.com
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,8 @@
|
|||
layout="topleft"
|
||||
left="10"
|
||||
top="5"
|
||||
width="128">
|
||||
width="128"
|
||||
name="base_color_lbl">
|
||||
Base Color:
|
||||
</text>
|
||||
<texture_picker
|
||||
|
|
@ -73,7 +74,8 @@
|
|||
height="10"
|
||||
layout="topleft"
|
||||
left_pad="5"
|
||||
top="8">
|
||||
top="8"
|
||||
name="base_color_tint_lbl">
|
||||
Tint
|
||||
</text>
|
||||
<color_swatch
|
||||
|
|
@ -94,7 +96,8 @@
|
|||
layout="topleft"
|
||||
left_delta="0"
|
||||
top_pad="5"
|
||||
width="96">
|
||||
width="96"
|
||||
name="base_color_transparency_lbl">
|
||||
Transparency
|
||||
</text>
|
||||
<spinner
|
||||
|
|
@ -117,10 +120,10 @@
|
|||
height="10"
|
||||
layout="topleft"
|
||||
left_delta="0"
|
||||
name="label alphamode"
|
||||
text_readonly_color="LabelDisabledColor"
|
||||
top_pad="5"
|
||||
width="90">
|
||||
width="90"
|
||||
name="alpha_mode_lbl">
|
||||
Alpha mode
|
||||
</text>
|
||||
<combo_box
|
||||
|
|
@ -151,7 +154,8 @@
|
|||
layout="topleft"
|
||||
left_delta="0"
|
||||
top_pad="5"
|
||||
width="96">
|
||||
width="96"
|
||||
name="alpha_cutoff_lbl">
|
||||
Alpha Cutoff
|
||||
</text>
|
||||
<spinner
|
||||
|
|
@ -186,7 +190,8 @@
|
|||
height="10"
|
||||
layout="topleft"
|
||||
left="10"
|
||||
top="5">
|
||||
top="5"
|
||||
name="metallic_roughness_lbl">
|
||||
Metallic-Roughness:
|
||||
</text>
|
||||
<texture_picker
|
||||
|
|
@ -222,7 +227,8 @@
|
|||
height="10"
|
||||
layout="topleft"
|
||||
left_pad="5"
|
||||
top="8">
|
||||
top="8"
|
||||
name="metallic_factor_lbl">
|
||||
Metallic Factor
|
||||
</text>
|
||||
<spinner
|
||||
|
|
@ -246,7 +252,8 @@
|
|||
layout="topleft"
|
||||
left_delta="0"
|
||||
top_pad="5"
|
||||
width="96">
|
||||
width="96"
|
||||
name="roughness_factor_lbl">
|
||||
Roughness Factor
|
||||
</text>
|
||||
<spinner
|
||||
|
|
@ -282,7 +289,8 @@
|
|||
layout="topleft"
|
||||
left="10"
|
||||
top="5"
|
||||
width="64">
|
||||
width="64"
|
||||
name="emissive_lbl">
|
||||
Emissive:
|
||||
</text>
|
||||
<texture_picker
|
||||
|
|
@ -317,7 +325,8 @@
|
|||
height="10"
|
||||
layout="topleft"
|
||||
left_pad="5"
|
||||
top="8">
|
||||
top="8"
|
||||
name="emissive_tint_lbl">
|
||||
Tint
|
||||
</text>
|
||||
<color_swatch
|
||||
|
|
@ -350,7 +359,8 @@
|
|||
layout="topleft"
|
||||
left="10"
|
||||
top="5"
|
||||
width="64">
|
||||
width="64"
|
||||
name="normal_lbl">
|
||||
Normal:
|
||||
</text>
|
||||
<texture_picker
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ PCRE Copyright (c) 1997-2012 University of Cambridge
|
|||
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
|
||||
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
|
||||
xxHash Copyright (C) 2012-2020 Yann Collet.
|
||||
zlib Copyright (C) 1995-2012 Jean-loup Gailly y Mark Adler.
|
||||
Algunos iconos por Joseph Wain / glyphish.com
|
||||
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ PCRE Copyright (c) 1997-2012 University of Cambridge
|
|||
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
|
||||
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
|
||||
xxHash Copyright (C) 2012-2020 Yann Collet.
|
||||
zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler.
|
||||
|
||||
Il Viewer Second Life utilizza Havok (TM) Physics. (c)Copyright 1999-2010 Havok.com Inc. (e licenziatari). Tutti i diritti riservati. Per informazioni dettagliate, vedere www.havok.com.
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ PCRE Copyright (c) 1997-2012 University of Cambridge
|
|||
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
|
||||
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
|
||||
xxHash Copyright (C) 2012-2020 Yann Collet.
|
||||
zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler.
|
||||
|
||||
Second Life ビューワでは Havok (TM) Physics が使用されています。(c)Copyright 1999-2010 Havok.com Inc. (and its Licensors).無断複写・複製・転載を禁じます。詳細については www.havok.com をご参照ください。
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ PCRE Copyright (c) 1997-2012 University of Cambridge
|
|||
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
|
||||
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
|
||||
xxHash Copyright (C) 2012-2020 Yann Collet.
|
||||
zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler.
|
||||
|
||||
O Visualizador do Second Life usa Havok (TM) Physics. (c)Copyright 1999-2010 Havok.com Inc. (e seus Licenciantes). Todos os direitos reservados. Consulte www.havok.com para obter detalhes.
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ PCRE Telif Hakkı (c) 1997-2012 University of Cambridge
|
|||
SDL Telif Hakkı (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
|
||||
SSLeay Telif Hakkı (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
xmlrpc-epi Telif Hakkı (C) 2000 Epinions, Inc.
|
||||
xxHash Copyright (C) 2012-2020 Yann Collet.
|
||||
zlib Telif Hakkı (C) 1995-2012 Jean-loup Gailly ve Mark Adler.
|
||||
|
||||
Second Life Görüntüleyicisi Havok (TM) Fizik motorunu kullanmaktadır. (c)Telif Hakkı 1999-2010 Havok.com Inc. (ve Lisans Verenleri). Tüm Hakları Saklıdır. Ayrıntılı bilgi için bkz. www.havok.com
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ PCRE Copyright (c) 1997-2012 University of Cambridge
|
|||
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
|
||||
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
|
||||
xxHash Copyright (C) 2012-2020 Yann Collet.
|
||||
zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler.
|
||||
|
||||
第二人生 Viewer 採用 Havok (TM) 物理引擎。 (c)Copyright 1999-2010 Havok.com Inc.(及其放照人)。 保留一切權利。 詳情見 www.havok.com。
|
||||
|
|
|
|||
Loading…
Reference in New Issue