Merge branch 'release/materials_featurette' into release/gltf-maint2

master
Brad Linden 2024-02-09 09:47:19 -08:00 committed by GitHub
commit 846337483c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
120 changed files with 5482 additions and 694 deletions

View File

@ -0,0 +1,22 @@
# PBR Terrain Feature Gating
PBR terrain should have lower detail on lower graphics settings. PBR terrain will also not show emissive textures on some machines (like Macs) which do not support more than 16 textures.
## Triplanar Mapping
Triplanar mapping improves the texture repeats on the sides of terrain slopes.
Availability of Triplanar mapping:
- Medium-High and below: No triplanar mapping
- High and above: Triplanar mapping
## PBR Textures
At the highest graphics support level, PBR terrain supports all PBR textures.
Availability of PBR textures varies by machine and graphics setting:
- Low: Base color only (looks similar to texture terrain)
- Medium-Low, and machines that do not support greater than 16 textures such as Macs: All PBR textures enabled except emissive textures.
- Medium: All PBR textures enabled

View File

@ -0,0 +1,4 @@
- Texture terrain should load
- PBR terrain should load if enabled
- Related subsystem: A change to the PBR terrain loading system may affect the texture terrain loading system and vice-versa
- Related subsystem: Minimaps should load if terrain loads (may take longer)

View File

@ -31,6 +31,7 @@
#include "llmath.h"
#include "v4coloru.h"
#include "v3color.h"
#include "llimagebmp.h"
#include "llimagetga.h"
@ -1026,6 +1027,34 @@ bool LLImageRaw::optimizeAwayAlpha()
return false;
}
bool LLImageRaw::makeAlpha()
{
if (getComponents() == 3)
{
U8* data = getData();
U32 pixels = getWidth() * getHeight();
// alpha channel doesn't exist, make a new copy of data with alpha channel
U8* new_data = (U8*) ll_aligned_malloc_16(getWidth() * getHeight() * 4);
for (U32 i = 0; i < pixels; ++i)
{
U32 di = i * 4;
U32 si = i * 3;
for (U32 j = 0; j < 3; ++j)
{
new_data[di+j] = data[si+j];
}
}
setDataAndSize(new_data, getWidth(), getHeight(), 3);
return true;
}
return false;
}
void LLImageRaw::expandToPowerOfTwo(S32 max_dim, bool scale_image)
{
// Find new sizes
@ -1110,7 +1139,7 @@ void LLImageRaw::composite( LLImageRaw* src )
return;
}
llassert(3 == src->getComponents());
llassert((3 == src->getComponents()) || (4 == src->getComponents()));
llassert(3 == dst->getComponents());
if( 3 == dst->getComponents() )
@ -1268,6 +1297,30 @@ void LLImageRaw::fill( const LLColor4U& color )
}
}
void LLImageRaw::tint( const LLColor3& color )
{
llassert( (3 == getComponents()) || (4 == getComponents()) );
if (isBufferInvalid())
{
LL_WARNS() << "Invalid image buffer" << LL_ENDL;
return;
}
S32 pixels = getWidth() * getHeight();
const S32 components = getComponents();
U8* data = getData();
for( S32 i = 0; i < pixels; i++ )
{
const float c0 = data[0] * color.mV[0];
const float c1 = data[1] * color.mV[1];
const float c2 = data[2] * color.mV[2];
data[0] = llclamp((U8)c0, 0, 255);
data[1] = llclamp((U8)c1, 0, 255);
data[2] = llclamp((U8)c2, 0, 255);
data += components;
}
}
LLPointer<LLImageRaw> LLImageRaw::duplicate()
{
if(getNumRefs() < 2)

View File

@ -33,7 +33,7 @@
#include "lltrace.h"
const S32 MIN_IMAGE_MIP = 2; // 4x4, only used for expand/contract power of 2
const S32 MAX_IMAGE_MIP = 11; // 2048x2048
const S32 MAX_IMAGE_MIP = 12; // 4096x4096
// *TODO : Use MAX_IMAGE_MIP as max discard level and modify j2c management so that the number
// of levels is read from the header's file, not inferred from its size.
@ -44,7 +44,7 @@ const S32 MAX_DISCARD_LEVEL = 5;
// and declared right here. Some come from the JPEG2000 spec, some conventions specific to SL.
const S32 MAX_DECOMPOSITION_LEVELS = 32; // Number of decomposition levels cannot exceed 32 according to jpeg2000 spec
const S32 MIN_DECOMPOSITION_LEVELS = 5; // the SL viewer will *crash* trying to decode images with fewer than 5 decomposition levels (unless image is small that is)
const S32 MAX_PRECINCT_SIZE = 2048; // No reason to be bigger than MAX_IMAGE_SIZE
const S32 MAX_PRECINCT_SIZE = 4096; // No reason to be bigger than MAX_IMAGE_SIZE
const S32 MIN_PRECINCT_SIZE = 4; // Can't be smaller than MIN_BLOCK_SIZE
const S32 MAX_BLOCK_SIZE = 64; // Max total block size is 4096, hence 64x64 when using square blocks
const S32 MIN_BLOCK_SIZE = 4; // Min block dim is 4 according to jpeg2000 spec
@ -52,11 +52,11 @@ const S32 MIN_LAYER_SIZE = 2000; // Size of the first quality layer (after hea
const S32 MAX_NB_LAYERS = 64; // Max number of layers we'll entertain in SL (practical limit)
const S32 MIN_IMAGE_SIZE = (1<<MIN_IMAGE_MIP); // 4, only used for expand/contract power of 2
const S32 MAX_IMAGE_SIZE = (1<<MAX_IMAGE_MIP); // 2048
const S32 MAX_IMAGE_SIZE = (1<<MAX_IMAGE_MIP); // 4096
const S32 MIN_IMAGE_AREA = MIN_IMAGE_SIZE * MIN_IMAGE_SIZE;
const S32 MAX_IMAGE_AREA = MAX_IMAGE_SIZE * MAX_IMAGE_SIZE;
const S32 MAX_IMAGE_COMPONENTS = 8;
const S32 MAX_IMAGE_DATA_SIZE = MAX_IMAGE_AREA * MAX_IMAGE_COMPONENTS; //2048 * 2048 * 8 = 16 MB
const S32 MAX_IMAGE_DATA_SIZE = MAX_IMAGE_AREA * MAX_IMAGE_COMPONENTS; //4096 * 4096 * 8 = 128 MB
// Note! These CANNOT be changed without modifying simulator code
// *TODO: change both to 1024 when SIM texture fetching is deprecated
@ -71,6 +71,7 @@ const S32 HTTP_PACKET_SIZE = 1496;
class LLImageFormatted;
class LLImageRaw;
class LLColor4U;
class LLColor3;
typedef enum e_image_codec
{
@ -212,6 +213,8 @@ public:
// if the alpha channel is all 100% opaque, delete it
// returns true if alpha channel was deleted
bool optimizeAwayAlpha();
// Create an alpha channel if this image doesn't have one
bool makeAlpha();
static S32 biasedDimToPowerOfTwo(S32 curr_dim, S32 max_dim = MAX_IMAGE_SIZE);
static S32 expandDimToPowerOfTwo(S32 curr_dim, S32 max_dim = MAX_IMAGE_SIZE);
@ -225,6 +228,9 @@ public:
// Fill the buffer with a constant color
void fill( const LLColor4U& color );
// Multiply this raw image by the given color
void tint( const LLColor3& color );
// Copy operations
//duplicate this raw image if refCount > 1.

View File

@ -65,7 +65,6 @@ class LLCamera
: public LLCoordFrame
{
public:
LLCamera(const LLCamera& rhs)
{
*this = rhs;

View File

@ -6465,9 +6465,6 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
return TRUE;
}
void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVector4a *normal,
const LLVector2 *texcoord, U32 triangleCount, const U16* index_array, LLVector4a *tangent);
void LLVolumeFace::createTangents()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
@ -6485,7 +6482,7 @@ void LLVolumeFace::createTangents()
(*ptr++).clear();
}
CalculateTangentArray(mNumVertices, mPositions, mNormals, mTexCoords, mNumIndices / 3, mIndices, mTangents);
LLCalculateTangentArray(mNumVertices, mPositions, mNormals, mTexCoords, mNumIndices / 3, mIndices, mTangents);
//normalize normals
for (U32 i = 0; i < mNumVertices; i++)
@ -7195,7 +7192,7 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
}
//adapted from Lengyel, Eric. "Computing Tangent Space Basis Vectors for an Arbitrary Mesh". Terathon Software 3D Graphics Library, 2001. http://www.terathon.com/code/tangent.html
void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVector4a *normal,
void LLCalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVector4a *normal,
const LLVector2 *texcoord, U32 triangleCount, const U16* index_array, LLVector4a *tangent)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME

View File

@ -1142,6 +1142,8 @@ public:
std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params);
void LLCalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVector4a *normal, const LLVector2 *texcoord, U32 triangleCount, const U16* index_array, LLVector4a *tangent);
BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size);
BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size);
BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, const LLVector4a& center, const LLVector4a& size);

View File

@ -582,7 +582,7 @@ void LLPluginProcessParent::idle(void)
params.args.add("-e");
params.args.add("tell application \"Terminal\"");
params.args.add("-e");
params.args.add(STRINGIZE("set win to do script \"gdb -pid "
params.args.add(STRINGIZE("set win to do script \"lldb -pid "
<< mProcess->getProcessID() << "\""));
params.args.add("-e");
params.args.add("do script \"continue\" in win");

View File

@ -1934,6 +1934,19 @@ void LLReflectionProbeParams::setIsDynamic(bool is_dynamic)
}
}
void LLReflectionProbeParams::setIsMirror(bool is_mirror)
{
if (is_mirror)
{
mFlags |= FLAG_MIRROR;
}
else
{
mFlags &= ~FLAG_MIRROR;
}
}
//============================================================================
LLFlexibleObjectData::LLFlexibleObjectData()
{

View File

@ -186,6 +186,7 @@ public:
{
FLAG_BOX_VOLUME = 0x01, // use a box influence volume
FLAG_DYNAMIC = 0x02, // render dynamic objects (avatars) into this Reflection Probe
FLAG_MIRROR = 0x04, // This probe is used for reflections on realtime mirrors.
};
protected:
@ -209,11 +210,13 @@ public:
void setClipDistance(F32 distance) { mClipDistance = llclamp(distance, REFLECTION_PROBE_MIN_CLIP_DISTANCE, REFLECTION_PROBE_MAX_CLIP_DISTANCE); }
void setIsBox(bool is_box);
void setIsDynamic(bool is_dynamic);
void setIsMirror(bool is_mirror);
F32 getAmbiance() const { return mAmbiance; }
F32 getClipDistance() const { return mClipDistance; }
bool getIsBox() const { return (mFlags & FLAG_BOX_VOLUME) != 0; }
bool getIsDynamic() const { return (mFlags & FLAG_DYNAMIC) != 0; }
bool getIsMirror() const { return (mFlags & FLAG_MIRROR) != 0; }
};
//-------------------------------------------------

View File

@ -685,6 +685,7 @@ S32 LLTextureEntry::setMaterialParams(const LLMaterialPtr pMaterialParams)
mMaterialUpdatePending = true;
}
mMaterial = pMaterialParams;
return TEM_CHANGE_TEXTURE;
}

View File

@ -134,7 +134,7 @@ public:
S32 setGlow(F32 glow);
S32 setMaterialID(const LLMaterialID& pMaterialID);
S32 setMaterialParams(const LLMaterialPtr pMaterialParams);
virtual const LLUUID &getID() const { return mID; }
const LLColor4 &getColor() const { return mColor; }
const F32 getAlpha() const { return mColor.mV[VALPHA]; }

View File

@ -1184,12 +1184,14 @@ S32 LLGLSLShader::getTextureChannel(S32 uniform) const
S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
if (uniform < 0 || uniform >= (S32)mTexture.size())
{
LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL;
return -1;
}
S32 index = mTexture[uniform];
if (index != -1)
{

View File

@ -56,6 +56,8 @@ public:
bool hasAlphaMask = false;
bool hasReflectionProbes = false;
bool attachNothing = false;
bool hasHeroProbes = false;
bool isPBRTerrain = false;
};
// ============= Structure for caching shader uniforms ===============

View File

@ -42,7 +42,7 @@ class LLGLTexture : public LLTexture
public:
enum
{
MAX_IMAGE_SIZE_DEFAULT = 1024,
MAX_IMAGE_SIZE_DEFAULT = 2048,
INVALID_DISCARD_LEVEL = 0x7fff
};

View File

@ -44,6 +44,7 @@ using std::make_pair;
using std::string;
LLShaderMgr * LLShaderMgr::sInstance = NULL;
bool LLShaderMgr::sMirrorsEnabled = false;
LLShaderMgr::LLShaderMgr()
{
@ -183,7 +184,13 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
// Attach Fragment Shader Features Next
///////////////////////////////////////
// NOTE order of shader object attaching is VERY IMPORTANT!!!
// NOTE order of shader object attaching is VERY IMPORTANT!!!
if (!shader->attachFragmentObject("deferred/globalF.glsl"))
{
return FALSE;
}
if (features->hasSrgb || features->hasAtmospherics || features->calculatesAtmospherics || features->isDeferred)
{
if (!shader->attachFragmentObject("environment/srgbF.glsl"))
@ -277,6 +284,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
}
}
if (features->isPBRTerrain)
{
if (!shader->attachFragmentObject("deferred/pbrterrainUtilF.glsl"))
{
return FALSE;
}
}
// NOTE order of shader object attaching is VERY IMPORTANT!!!
if (features->hasAtmospherics)
{
@ -572,21 +587,38 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev
}
else
{
//set version to 1.40
shader_code_text[shader_code_count++] = strdup("#version 140\n");
//some implementations of GLSL 1.30 require integer precision be explicitly declared
extra_code_text[extra_code_count++] = strdup("precision mediump int;\n");
extra_code_text[extra_code_count++] = strdup("precision highp float;\n");
if (type == GL_GEOMETRY_SHADER)
{
//set version to 1.50
shader_code_text[shader_code_count++] = strdup("#version 150\n");
//some implementations of GLSL 1.30 require integer precision be explicitly declared
extra_code_text[extra_code_count++] = strdup("precision mediump int;\n");
extra_code_text[extra_code_count++] = strdup("precision highp float;\n");
}
else
{
//set version to 1.40
shader_code_text[shader_code_count++] = strdup("#version 140\n");
//some implementations of GLSL 1.30 require integer precision be explicitly declared
extra_code_text[extra_code_count++] = strdup("precision mediump int;\n");
extra_code_text[extra_code_count++] = strdup("precision highp float;\n");
}
}
extra_code_text[extra_code_count++] = strdup("#define FXAA_GLSL_130 1\n");
}
if (sMirrorsEnabled)
{
extra_code_text[extra_code_count++] = strdup("#define HERO_PROBES 1\n");
}
// Use alpha float to store bit flags
// See: C++: addDeferredAttachment(), shader: frag_data[2]
extra_code_text[extra_code_count++] = strdup("#define GBUFFER_FLAG_SKIP_ATMOS 0.0 \n"); // atmo kill
extra_code_text[extra_code_count++] = strdup("#define GBUFFER_FLAG_HAS_ATMOS 0.34\n"); // bit 0
extra_code_text[extra_code_count++] = strdup("#define GBUFFER_FLAG_HAS_PBR 0.67\n"); // bit 1
extra_code_text[extra_code_count++] = strdup("#define GBUFFER_FLAG_HAS_MIRROR 1.0\n"); // bit 2
extra_code_text[extra_code_count++] = strdup("#define GET_GBUFFER_FLAG(flag) (abs(norm.w-flag)< 0.1)\n");
if (defines)
@ -1192,6 +1224,9 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("emissiveColor");
mReservedUniforms.push_back("metallicFactor");
mReservedUniforms.push_back("roughnessFactor");
mReservedUniforms.push_back("mirror_flag");
mReservedUniforms.push_back("clipPlane");
mReservedUniforms.push_back("clipSign");
mReservedUniforms.push_back("diffuseMap");
mReservedUniforms.push_back("altDiffuseMap");
@ -1204,6 +1239,7 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("sceneDepth");
mReservedUniforms.push_back("reflectionProbes");
mReservedUniforms.push_back("irradianceProbes");
mReservedUniforms.push_back("heroProbes");
mReservedUniforms.push_back("cloud_noise_texture");
mReservedUniforms.push_back("cloud_noise_texture_next");
mReservedUniforms.push_back("fullbright");
@ -1374,8 +1410,32 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("detail_1");
mReservedUniforms.push_back("detail_2");
mReservedUniforms.push_back("detail_3");
mReservedUniforms.push_back("alpha_ramp");
mReservedUniforms.push_back("detail_0_base_color");
mReservedUniforms.push_back("detail_1_base_color");
mReservedUniforms.push_back("detail_2_base_color");
mReservedUniforms.push_back("detail_3_base_color");
mReservedUniforms.push_back("detail_0_normal");
mReservedUniforms.push_back("detail_1_normal");
mReservedUniforms.push_back("detail_2_normal");
mReservedUniforms.push_back("detail_3_normal");
mReservedUniforms.push_back("detail_0_metallic_roughness");
mReservedUniforms.push_back("detail_1_metallic_roughness");
mReservedUniforms.push_back("detail_2_metallic_roughness");
mReservedUniforms.push_back("detail_3_metallic_roughness");
mReservedUniforms.push_back("detail_0_emissive");
mReservedUniforms.push_back("detail_1_emissive");
mReservedUniforms.push_back("detail_2_emissive");
mReservedUniforms.push_back("detail_3_emissive");
mReservedUniforms.push_back("baseColorFactors");
mReservedUniforms.push_back("metallicFactors");
mReservedUniforms.push_back("roughnessFactors");
mReservedUniforms.push_back("emissiveColors");
mReservedUniforms.push_back("minimum_alphas");
mReservedUniforms.push_back("origin");
mReservedUniforms.push_back("display_gamma");
@ -1397,6 +1457,7 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("cloud_variance");
mReservedUniforms.push_back("reflection_probe_ambiance");
mReservedUniforms.push_back("max_probe_lod");
mReservedUniforms.push_back("probe_strength");
mReservedUniforms.push_back("sh_input_r");
mReservedUniforms.push_back("sh_input_g");
@ -1407,6 +1468,8 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("sun_up_factor");
mReservedUniforms.push_back("moonlight_color");
mReservedUniforms.push_back("debug_normal_draw_length");
llassert(mReservedUniforms.size() == END_RESERVED_UNIFORMS);
std::set<std::string> dupe_check;

View File

@ -85,6 +85,9 @@ public:
EMISSIVE_COLOR, // "emissiveColor"
METALLIC_FACTOR, // "metallicFactor"
ROUGHNESS_FACTOR, // "roughnessFactor"
MIRROR_FLAG, // "mirror_flag"
CLIP_PLANE, // "clipPlane"
CLIP_SIGN, // "clipSign"
DIFFUSE_MAP, // "diffuseMap"
ALTERNATE_DIFFUSE_MAP, // "altDiffuseMap"
SPECULAR_MAP, // "specularMap"
@ -96,6 +99,7 @@ public:
SCENE_DEPTH, // "sceneDepth"
REFLECTION_PROBES, // "reflectionProbes"
IRRADIANCE_PROBES, // "irradianceProbes"
HERO_PROBE, // "heroProbes"
CLOUD_NOISE_MAP, // "cloud_noise_texture"
CLOUD_NOISE_MAP_NEXT, // "cloud_noise_texture_next"
FULLBRIGHT, // "fullbright"
@ -251,8 +255,32 @@ public:
TERRAIN_DETAIL1, // "detail_1"
TERRAIN_DETAIL2, // "detail_2"
TERRAIN_DETAIL3, // "detail_3"
TERRAIN_ALPHARAMP, // "alpha_ramp"
TERRAIN_DETAIL0_BASE_COLOR, // "detail_0_base_color" (GLTF)
TERRAIN_DETAIL1_BASE_COLOR, // "detail_1_base_color" (GLTF)
TERRAIN_DETAIL2_BASE_COLOR, // "detail_2_base_color" (GLTF)
TERRAIN_DETAIL3_BASE_COLOR, // "detail_3_base_color" (GLTF)
TERRAIN_DETAIL0_NORMAL, // "detail_0_normal" (GLTF)
TERRAIN_DETAIL1_NORMAL, // "detail_1_normal" (GLTF)
TERRAIN_DETAIL2_NORMAL, // "detail_2_normal" (GLTF)
TERRAIN_DETAIL3_NORMAL, // "detail_3_normal" (GLTF)
TERRAIN_DETAIL0_METALLIC_ROUGHNESS, // "detail_0_metallic_roughness" (GLTF)
TERRAIN_DETAIL1_METALLIC_ROUGHNESS, // "detail_1_metallic_roughness" (GLTF)
TERRAIN_DETAIL2_METALLIC_ROUGHNESS, // "detail_2_metallic_roughness" (GLTF)
TERRAIN_DETAIL3_METALLIC_ROUGHNESS, // "detail_3_metallic_roughness" (GLTF)
TERRAIN_DETAIL0_EMISSIVE, // "detail_0_emissive" (GLTF)
TERRAIN_DETAIL1_EMISSIVE, // "detail_1_emissive" (GLTF)
TERRAIN_DETAIL2_EMISSIVE, // "detail_2_emissive" (GLTF)
TERRAIN_DETAIL3_EMISSIVE, // "detail_3_emissive" (GLTF)
TERRAIN_BASE_COLOR_FACTORS, // "baseColorFactors" (GLTF)
TERRAIN_METALLIC_FACTORS, // "metallicFactors" (GLTF)
TERRAIN_ROUGHNESS_FACTORS, // "roughnessFactors" (GLTF)
TERRAIN_EMISSIVE_COLORS, // "emissiveColors" (GLTF)
TERRAIN_MINIMUM_ALPHAS, // "minimum_alphas" (GLTF)
SHINY_ORIGIN, // "origin"
DISPLAY_GAMMA, // "display_gamma"
@ -279,6 +307,7 @@ public:
REFLECTION_PROBE_AMBIANCE, // "reflection_probe_ambiance"
REFLECTION_PROBE_MAX_LOD, // "max_probe_lod"
REFLECTION_PROBE_STRENGTH, // "probe_strength"
SH_INPUT_L1R, // "sh_input_r"
SH_INPUT_L1G, // "sh_input_g"
SH_INPUT_L1B, // "sh_input_b"
@ -287,6 +316,9 @@ public:
WATER_EDGE_FACTOR, // "water_edge"
SUN_UP_FACTOR, // "sun_up_factor"
MOONLIGHT_COLOR, // "moonlight_color"
DEBUG_NORMAL_DRAW_LENGTH, // "debug_normal_draw_length"
END_RESERVED_UNIFORMS
} eGLSLReservedUniforms;
// clang-format on
@ -336,6 +368,7 @@ public:
bool mShaderCacheInitialized = false;
bool mShaderCacheEnabled = false;
std::string mShaderCacheDir;
static bool sMirrorsEnabled;
protected:

View File

@ -1319,6 +1319,10 @@ bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector3>& strider, U32 index,
{
return VertexBufferStrider<LLVector3,TYPE_NORMAL>::get(*this, strider, index, count);
}
bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector4a>& strider, U32 index, S32 count)
{
return VertexBufferStrider<LLVector4a, TYPE_NORMAL>::get(*this, strider, index, count);
}
bool LLVertexBuffer::getTangentStrider(LLStrider<LLVector3>& strider, U32 index, S32 count)
{
return VertexBufferStrider<LLVector3,TYPE_TANGENT>::get(*this, strider, index, count);

View File

@ -180,6 +180,7 @@ public:
bool getTexCoord1Strider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1);
bool getTexCoord2Strider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1);
bool getNormalStrider(LLStrider<LLVector3>& strider, U32 index=0, S32 count = -1);
bool getNormalStrider(LLStrider<LLVector4a>& strider, U32 index = 0, S32 count = -1);
bool getTangentStrider(LLStrider<LLVector3>& strider, U32 index=0, S32 count = -1);
bool getTangentStrider(LLStrider<LLVector4a>& strider, U32 index=0, S32 count = -1);
bool getColorStrider(LLStrider<LLColor4U>& strider, U32 index=0, S32 count = -1);
@ -187,10 +188,6 @@ public:
bool getWeightStrider(LLStrider<F32>& strider, U32 index=0, S32 count = -1);
bool getWeight4Strider(LLStrider<LLVector4>& strider, U32 index=0, S32 count = -1);
bool getClothWeightStrider(LLStrider<LLVector4>& strider, U32 index=0, S32 count = -1);
bool getBasecolorTexcoordStrider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1);
bool getNormalTexcoordStrider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1);
bool getMetallicRoughnessTexcoordStrider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1);
bool getEmissiveTexcoordStrider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1);
void setPositionData(const LLVector4a* data);
void setTexCoordData(const LLVector2* data);

View File

@ -310,6 +310,7 @@ set(viewer_SOURCE_FILES
llgiveinventory.cpp
llglsandbox.cpp
llgltfmateriallist.cpp
llgltfmaterialpreviewmgr.cpp
llgroupactions.cpp
llgroupiconctrl.cpp
llgrouplist.cpp
@ -519,6 +520,7 @@ set(viewer_SOURCE_FILES
llrecentpeople.cpp
llreflectionmap.cpp
llreflectionmapmanager.cpp
llheroprobemanager.cpp
llregioninfomodel.cpp
llregionposition.cpp
llremoteparcelrequest.cpp
@ -963,6 +965,7 @@ set(viewer_HEADER_FILES
llgesturemgr.h
llgiveinventory.h
llgltfmateriallist.h
llgltfmaterialpreviewmgr.h
llgroupactions.h
llgroupiconctrl.h
llgrouplist.h
@ -1158,6 +1161,7 @@ set(viewer_HEADER_FILES
llrecentpeople.h
llreflectionmap.h
llreflectionmapmanager.h
llheroprobemanager.h
llregioninfomodel.h
llregionposition.h
llremoteparcelrequest.h

View File

@ -9153,6 +9153,17 @@
<real>0.00</real>
</array>
</map>
<key>RenderMirrors</key>
<map>
<key>Comment</key>
<string>Renders realtime mirrors.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>RenderScreenSpaceReflections</key>
<map>
<key>Comment</key>
@ -10357,6 +10368,28 @@
<key>Value</key>
<integer>0</integer>
</map>
<key>RenderHeroProbeResolution</key>
<map>
<key>Comment</key>
<string>Resolution to render hero probes used for mirrors, water, etc.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>1024</integer>
</map>
<key>RenderHeroProbeDistance</key>
<map>
<key>Comment</key>
<string>Distance in meters for hero probes to render out to.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>8</real>
</map>
<key>RenderReflectionProbeVolumes</key>
<map>
<key>Comment</key>
@ -10781,7 +10814,7 @@
<key>RenderTerrainScale</key>
<map>
<key>Comment</key>
<string>Terrain detail texture scale</string>
<string>Terrain detail texture scale (meters)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@ -10789,6 +10822,83 @@
<key>Value</key>
<real>12.0</real>
</map>
<key>RenderTerrainPBREnabled</key>
<map>
<key>Comment</key>
<string>EXPERIMENTAL: Enable PBR Terrain features. Requires restart.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>RenderTerrainPBRForce</key>
<map>
<key>Comment</key>
<string>Force-load PBR terrain if enabled</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>RenderTerrainPBRDetail</key>
<map>
<key>Comment</key>
<string>Detail level for PBR terrain. 0 is full detail. Negative values drop rendering features, in accordance with the GLTF specification when possible, which reduces the number of texture binds.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>RenderTerrainPBRScale</key>
<map>
<key>Comment</key>
<string>PBR terrain detail texture scale (meters)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>4.0</real>
</map>
<key>RenderTerrainPBRPlanarSampleCount</key>
<map>
<key>Comment</key>
<string>How many UV planes to sample PBR terrain textures from. 1 is "flat", 3 is triplanar mapping (aka box mapping)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>3</real>
</map>
<key>RenderTerrainPBRTriplanarBlendFactor</key>
<map>
<key>Comment</key>
<string>Higher values create sharper transitions, but are more likely to produce artifacts.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>8.0</real>
</map>
<key>RenderTerrainPBRNormalsEnabled</key>
<map>
<key>Comment</key>
<string>EXPERIMENTAL: Change normal gen for PBR Terrain.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>RenderTrackerBeacon</key>
<map>
<key>Comment</key>
@ -13719,6 +13829,17 @@
<key>Value</key>
<integer>2</integer>
</map>
<key>UIPreviewMaterial</key>
<map>
<key>Comment</key>
<string>Whether or not PBR material swatch is enabled</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<real>0</real>
</map>
<key>UIResizeBarHeight</key>
<map>
<key>Comment</key>
@ -15634,7 +15755,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>2048</integer>
<integer>1024</integer>
</map>
<key>max_texture_dimension_Y</key>
<map>
@ -15645,7 +15766,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>2048</integer>
<integer>1024</integer>
</map>
<!-- End of back compatibility settings -->
<key>teleport_offer_invitation_max_length</key>
@ -16520,6 +16641,50 @@
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>LocalTerrainAsset1</key>
<map>
<key>Comment</key>
<string>If set to a non-null UUID, overrides the terrain asset locally for all regions with material assets. Local terrain assets are not visible to others. Please keep in mind that this debug setting may be temporary. Do not rely on this setting existing in future viewer builds.</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>String</string>
<key>Value</key>
<string>00000000-0000-0000-0000-000000000000</string>
</map>
<key>LocalTerrainAsset2</key>
<map>
<key>Comment</key>
<string>If set to a non-null UUID, overrides the terrain asset locally for all regions with material assets. Local terrain assets are not visible to others. Please keep in mind that this debug setting may be temporary. Do not rely on this setting existing in future viewer builds.</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>String</string>
<key>Value</key>
<string>00000000-0000-0000-0000-000000000000</string>
</map>
<key>LocalTerrainAsset3</key>
<map>
<key>Comment</key>
<string>If set to a non-null UUID, overrides the terrain asset locally for all regions with material assets. Local terrain assets are not visible to others. Please keep in mind that this debug setting may be temporary. Do not rely on this setting existing in future viewer builds.</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>String</string>
<key>Value</key>
<string>00000000-0000-0000-0000-000000000000</string>
</map>
<key>LocalTerrainAsset4</key>
<map>
<key>Comment</key>
<string>If set to a non-null UUID, overrides the terrain asset locally for all regions with material assets. Local terrain assets are not visible to others. Please keep in mind that this debug setting may be temporary. Do not rely on this setting existing in future viewer builds.</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>String</string>
<key>Value</key>
<string>00000000-0000-0000-0000-000000000000</string>
</map>
<key>PathfindingRetrieveNeighboringRegion</key>
<map>

View File

@ -33,11 +33,15 @@ uniform float minimum_alpha;
in vec3 vary_normal;
in vec2 vary_texcoord0;
in vec3 vary_position;
vec2 encode_normal(vec3 n);
void mirrorClip(vec3 pos);
void main()
{
mirrorClip(vary_position);
vec4 diff = texture(diffuseMap, vary_texcoord0.xy);
if (diff.a < minimum_alpha)

View File

@ -35,6 +35,7 @@ in vec4 weight;
out vec3 vary_normal;
out vec2 vary_texcoord0;
out vec3 vary_position;
void main()
{
@ -57,6 +58,7 @@ void main()
vary_normal = norm;
vary_position = pos.xyz;
gl_Position = projection_matrix * pos;
}

View File

@ -37,11 +37,15 @@ in vec3 vary_mat2;
in vec4 vertex_color;
in vec2 vary_texcoord0;
in vec3 vary_position;
vec2 encode_normal(vec3 n);
void mirrorClip(vec3 pos);
void main()
{
mirrorClip(vary_position);
vec4 col = texture(diffuseMap, vary_texcoord0.xy);
if(col.a < minimum_alpha)

View File

@ -23,6 +23,7 @@
* $/LicenseInfo$
*/
uniform mat4 modelview_matrix;
uniform mat3 normal_matrix;
uniform mat4 texture_matrix0;
uniform mat4 modelview_projection_matrix;
@ -38,11 +39,11 @@ out vec3 vary_mat1;
out vec3 vary_mat2;
out vec4 vertex_color;
out vec2 vary_texcoord0;
out vec3 vary_position;
#ifdef HAS_SKIN
mat4 getObjectSkinnedTransform();
uniform mat4 projection_matrix;
uniform mat4 modelview_matrix;
#endif
void main()
@ -52,11 +53,13 @@ void main()
mat4 mat = getObjectSkinnedTransform();
mat = modelview_matrix * mat;
vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz;
vary_position = pos;
gl_Position = projection_matrix*vec4(pos, 1.0);
vec3 n = normalize((mat * vec4(normal.xyz+position.xyz, 1.0)).xyz-pos.xyz);
vec3 t = normalize((mat * vec4(tangent.xyz+position.xyz, 1.0)).xyz-pos.xyz);
#else
vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz;
gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
vec3 n = normalize(normal_matrix * normal);
vec3 t = normalize(normal_matrix * tangent.xyz);

View File

@ -31,14 +31,20 @@ uniform float minimum_alpha;
uniform sampler2D diffuseMap;
in vec3 vary_position;
in vec3 vary_normal;
in vec4 vertex_color;
in vec2 vary_texcoord0;
vec2 encode_normal(vec3 n);
void mirrorClip(vec3 pos);
void main()
{
mirrorClip(vary_position);
vec4 col = texture(diffuseMap, vary_texcoord0.xy) * vertex_color;
if (col.a < minimum_alpha)

View File

@ -28,6 +28,7 @@
out vec4 frag_data[4];
in vec3 vary_normal;
in vec3 vary_position;
uniform float minimum_alpha;
@ -36,8 +37,12 @@ in vec2 vary_texcoord0;
vec2 encode_normal(vec3 n);
void mirrorClip(vec3 pos);
void main()
{
mirrorClip(vary_position);
vec4 col = diffuseLookup(vary_texcoord0.xy) * vertex_color;
if (col.a < minimum_alpha)

View File

@ -32,11 +32,14 @@ uniform sampler2D diffuseMap;
in vec3 vary_normal;
in vec4 vertex_color;
in vec2 vary_texcoord0;
in vec3 vary_position;
vec2 encode_normal(vec3 n);
void mirrorClip(vec3 pos);
void main()
{
mirrorClip(vary_position);
vec3 col = vertex_color.rgb * texture(diffuseMap, vary_texcoord0.xy).rgb;
frag_data[0] = vec4(col, 0.0);
frag_data[1] = vertex_color.aaaa; // spec

View File

@ -30,12 +30,15 @@ out vec4 frag_data[4];
in vec3 vary_normal;
in vec4 vertex_color;
in vec2 vary_texcoord0;
in vec3 vary_position;
void mirrorClip(vec3 pos);
vec2 encode_normal(vec3 n);
vec3 linear_to_srgb(vec3 c);
void main()
{
mirrorClip(vary_position);
vec3 col = vertex_color.rgb * diffuseLookup(vary_texcoord0.xy).rgb;
vec3 spec;

View File

@ -36,13 +36,16 @@ out vec3 vary_normal;
out vec4 vertex_color;
out vec2 vary_texcoord0;
out vec3 vary_position;
void passTextureIndex();
uniform mat4 modelview_matrix;
#ifdef HAS_SKIN
mat4 getObjectSkinnedTransform();
uniform mat4 projection_matrix;
uniform mat4 modelview_matrix;
#endif
void main()
@ -51,9 +54,11 @@ void main()
mat4 mat = getObjectSkinnedTransform();
mat = modelview_matrix * mat;
vec4 pos = mat * vec4(position.xyz, 1.0);
vary_position = pos.xyz;
gl_Position = projection_matrix * pos;
vary_normal = normalize((mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz);
#else
vary_position = (modelview_matrix * vec4(position.xyz, 1.0)).xyz;
gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
vary_normal = normalize(normal_matrix * normal);
#endif

View File

@ -50,9 +50,11 @@ void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, ou
vec4 applySkyAndWaterFog(vec3 pos, vec3 additive, vec3 atten, vec4 color);
#endif
void mirrorClip(vec3 pos);
void main()
{
mirrorClip(vary_position);
#ifdef IS_ALPHA
waterClip(vary_position.xyz);
#endif

View File

@ -0,0 +1,45 @@
/**
* @file class1/deferred/globalF.glsl
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2024, 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$
*/
// Global helper functions included in every fragment shader
// DO NOT declare sampler uniforms here as OS X doesn't compile
// them out
uniform float mirror_flag;
uniform vec4 clipPlane;
uniform float clipSign;
void mirrorClip(vec3 pos)
{
if (mirror_flag > 0)
{
if ((dot(pos.xyz, clipPlane.xyz) + clipPlane.w) < 0.0)
{
discard;
}
}
}

View File

@ -28,25 +28,18 @@
#define DIFFUSE_ALPHA_MODE_MASK 2
#define DIFFUSE_ALPHA_MODE_EMISSIVE 3
#ifdef HAS_SKIN
uniform mat4 modelview_matrix;
uniform mat4 projection_matrix;
uniform mat4 modelview_projection_matrix;
#ifdef HAS_SKIN
mat4 getObjectSkinnedTransform();
#else
uniform mat3 normal_matrix;
uniform mat4 modelview_projection_matrix;
#endif
#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
#if !defined(HAS_SKIN)
uniform mat4 modelview_matrix;
#endif
out vec3 vary_position;
#endif
uniform mat4 texture_matrix0;
in vec3 position;
@ -85,9 +78,7 @@ void main()
vec3 pos = (mat*vec4(position.xyz,1.0)).xyz;
#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
vary_position = pos;
#endif
gl_Position = projection_matrix*vec4(pos,1.0);
@ -133,10 +124,8 @@ void main()
vertex_color = diffuse_color;
#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
#if !defined(HAS_SKIN)
vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz;
#endif
#endif
}

View File

@ -58,10 +58,17 @@ vec2 encode_normal(vec3 n);
vec3 linear_to_srgb(vec3 c);
vec3 srgb_to_linear(vec3 c);
uniform vec4 clipPlane;
uniform float clipSign;
void mirrorClip(vec3 pos);
uniform mat3 normal_matrix;
void main()
{
mirrorClip(vary_position);
vec4 basecolor = texture(diffuseMap, base_color_texcoord.xy).rgba;
if (basecolor.a < minimum_alpha)
{

View File

@ -28,8 +28,9 @@
//deferred opaque implementation
#ifdef HAS_SKIN
uniform mat4 modelview_matrix;
#ifdef HAS_SKIN
uniform mat4 projection_matrix;
mat4 getObjectSkinnedTransform();
#else
@ -59,6 +60,7 @@ out vec4 vertex_color;
out vec3 vary_tangent;
flat out float vary_sign;
out vec3 vary_normal;
out vec3 vary_position;
vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl_animation_transform);
vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform);
@ -71,10 +73,11 @@ void main()
mat = modelview_matrix * mat;
vec3 pos = (mat*vec4(position.xyz,1.0)).xyz;
vary_position = pos;
gl_Position = projection_matrix*vec4(pos,1.0);
#else
vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz;
//transform vertex
gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
#endif

View File

@ -0,0 +1,344 @@
/**
* @file class1\deferred\terrainF.glsl
*
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2023, 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]*/
#define TERRAIN_PBR_DETAIL_EMISSIVE 0
#define TERRAIN_PBR_DETAIL_OCCLUSION -1
#define TERRAIN_PBR_DETAIL_NORMAL -2
#define TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS -3
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
#define TerrainCoord vec4[2]
#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1
#define TerrainCoord vec2
#endif
#define MIX_X 1 << 3
#define MIX_Y 1 << 4
#define MIX_Z 1 << 5
#define MIX_W 1 << 6
struct TerrainMix
{
vec4 weight;
int type;
};
TerrainMix get_terrain_mix_weights(float alpha1, float alpha2, float alphaFinal);
struct PBRMix
{
vec4 col; // RGB color with alpha, linear space
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
vec3 orm; // Occlusion, roughness, metallic
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
vec2 rm; // Roughness, metallic
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
vec3 vNt; // Unpacked normal texture sample, vector
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
vec3 emissive; // RGB emissive color, linear space
#endif
};
PBRMix init_pbr_mix();
PBRMix terrain_sample_and_multiply_pbr(
TerrainCoord terrain_coord
, sampler2D tex_col
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
, sampler2D tex_orm
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
, sampler2D tex_vNt
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, sampler2D tex_emissive
#endif
, vec4 factor_col
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
, vec3 factor_orm
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
, vec2 factor_rm
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, vec3 factor_emissive
#endif
);
PBRMix mix_pbr(PBRMix mix1, PBRMix mix2, float mix2_weight);
out vec4 frag_data[4];
uniform sampler2D alpha_ramp;
// https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#additional-textures
uniform sampler2D detail_0_base_color;
uniform sampler2D detail_1_base_color;
uniform sampler2D detail_2_base_color;
uniform sampler2D detail_3_base_color;
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
uniform sampler2D detail_0_normal;
uniform sampler2D detail_1_normal;
uniform sampler2D detail_2_normal;
uniform sampler2D detail_3_normal;
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
uniform sampler2D detail_0_metallic_roughness;
uniform sampler2D detail_1_metallic_roughness;
uniform sampler2D detail_2_metallic_roughness;
uniform sampler2D detail_3_metallic_roughness;
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
uniform sampler2D detail_0_emissive;
uniform sampler2D detail_1_emissive;
uniform sampler2D detail_2_emissive;
uniform sampler2D detail_3_emissive;
#endif
uniform vec4[4] baseColorFactors; // See also vertex_color in pbropaqueV.glsl
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
uniform vec4 metallicFactors;
uniform vec4 roughnessFactors;
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
uniform vec3[4] emissiveColors;
#endif
uniform vec4 minimum_alphas; // PBR alphaMode: MASK, See: mAlphaCutoff, setAlphaCutoff()
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
in vec4[2] vary_coords;
#endif
in vec3 vary_normal;
in vec3 vary_tangent;
flat in float vary_sign;
in vec4 vary_texcoord0;
in vec4 vary_texcoord1;
vec2 encode_normal(vec3 n);
float terrain_mix(TerrainMix tm, vec4 tms4);
void main()
{
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
TerrainCoord terrain_texcoord = vary_coords;
#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1
TerrainCoord terrain_texcoord = vary_texcoord0.xy;
#endif
float alpha1 = texture(alpha_ramp, vary_texcoord0.zw).a;
float alpha2 = texture(alpha_ramp,vary_texcoord1.xy).a;
float alphaFinal = texture(alpha_ramp, vary_texcoord1.zw).a;
TerrainMix tm = get_terrain_mix_weights(alpha1, alpha2, alphaFinal);
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
// RGB = Occlusion, Roughness, Metal
// default values, see LLViewerTexture::sDefaultPBRORMImagep
// occlusion 1.0
// roughness 0.0
// metal 0.0
vec3[4] orm_factors;
orm_factors[0] = vec3(1.0, roughnessFactors.x, metallicFactors.x);
orm_factors[1] = vec3(1.0, roughnessFactors.y, metallicFactors.y);
orm_factors[2] = vec3(1.0, roughnessFactors.z, metallicFactors.z);
orm_factors[3] = vec3(1.0, roughnessFactors.w, metallicFactors.w);
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
vec2[4] rm_factors;
rm_factors[0] = vec2(roughnessFactors.x, metallicFactors.x);
rm_factors[1] = vec2(roughnessFactors.y, metallicFactors.y);
rm_factors[2] = vec2(roughnessFactors.z, metallicFactors.z);
rm_factors[3] = vec2(roughnessFactors.w, metallicFactors.w);
#endif
PBRMix mix = init_pbr_mix();
PBRMix mix2;
switch (tm.type & MIX_X)
{
case MIX_X:
mix2 = terrain_sample_and_multiply_pbr(
terrain_texcoord
, detail_0_base_color
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
, detail_0_metallic_roughness
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
, detail_0_normal
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, detail_0_emissive
#endif
, baseColorFactors[0]
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
, orm_factors[0]
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
, rm_factors[0]
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, emissiveColors[0]
#endif
);
mix = mix_pbr(mix, mix2, tm.weight.x);
break;
default:
break;
}
switch (tm.type & MIX_Y)
{
case MIX_Y:
mix2 = terrain_sample_and_multiply_pbr(
terrain_texcoord
, detail_1_base_color
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
, detail_1_metallic_roughness
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
, detail_1_normal
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, detail_1_emissive
#endif
, baseColorFactors[1]
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
, orm_factors[1]
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
, rm_factors[1]
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, emissiveColors[1]
#endif
);
mix = mix_pbr(mix, mix2, tm.weight.y);
break;
default:
break;
}
switch (tm.type & MIX_Z)
{
case MIX_Z:
mix2 = terrain_sample_and_multiply_pbr(
terrain_texcoord
, detail_2_base_color
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
, detail_2_metallic_roughness
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
, detail_2_normal
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, detail_2_emissive
#endif
, baseColorFactors[2]
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
, orm_factors[2]
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
, rm_factors[2]
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, emissiveColors[2]
#endif
);
mix = mix_pbr(mix, mix2, tm.weight.z);
break;
default:
break;
}
switch (tm.type & MIX_W)
{
case MIX_W:
mix2 = terrain_sample_and_multiply_pbr(
terrain_texcoord
, detail_3_base_color
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
, detail_3_metallic_roughness
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
, detail_3_normal
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, detail_3_emissive
#endif
, baseColorFactors[3]
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
, orm_factors[3]
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
, rm_factors[3]
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, emissiveColors[3]
#endif
);
mix = mix_pbr(mix, mix2, tm.weight.w);
break;
default:
break;
}
float minimum_alpha = terrain_mix(tm, minimum_alphas);
if (mix.col.a < minimum_alpha)
{
discard;
}
float base_color_factor_alpha = terrain_mix(tm, vec4(baseColorFactors[0].z, baseColorFactors[1].z, baseColorFactors[2].z, baseColorFactors[3].z));
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
// from mikktspace.com
vec3 vNt = mix.vNt;
vec3 vN = vary_normal;
vec3 vT = vary_tangent.xyz;
vec3 vB = vary_sign * cross(vN, vT);
vec3 tnorm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN );
tnorm *= gl_FrontFacing ? 1.0 : -1.0;
#else
vec3 tnorm = vary_normal;
tnorm *= gl_FrontFacing ? 1.0 : -1.0;
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
#define emissive mix.emissive
#else
#define emissive vec3(0)
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
#define orm mix.orm
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
#define orm vec3(1.0, mix.rm)
#else
// Matte plastic potato terrain
#define orm vec3(1.0, 1.0, 0.0)
#endif
frag_data[0] = max(vec4(mix.col.xyz, 0.0), vec4(0)); // Diffuse
frag_data[1] = max(vec4(orm.rgb, base_color_factor_alpha), vec4(0)); // PBR linear packed Occlusion, Roughness, Metal.
frag_data[2] = max(vec4(encode_normal(tnorm), base_color_factor_alpha, GBUFFER_FLAG_HAS_PBR), vec4(0)); // normal, environment intensity, flags
frag_data[3] = max(vec4(emissive,0), vec4(0)); // PBR sRGB Emissive
}

View File

@ -0,0 +1,473 @@
/**
* @file class1\deferred\pbrterrainUtilF.glsl
*
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2023, 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]*/
/**
* Triplanar mapping implementation adapted from Inigo Quilez' example shader,
* MIT license.
* https://www.shadertoy.com/view/MtsGWH
* Copyright © 2015 Inigo Quilez
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: The above copyright
* notice and this permission notice shall be included in all copies or
* substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS",
* WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#define TERRAIN_PBR_DETAIL_EMISSIVE 0
#define TERRAIN_PBR_DETAIL_OCCLUSION -1
#define TERRAIN_PBR_DETAIL_NORMAL -2
#define TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS -3
in vec3 vary_vertex_normal;
vec3 srgb_to_linear(vec3 c);
// A relatively agressive threshold for terrain material mixing sampling
// cutoff. This ensures that only one or two materials are used in most places,
// making PBR terrain blending more performant. Should be greater than 0 to work.
#define TERRAIN_RAMP_MIX_THRESHOLD 0.1
// A small threshold for triplanar mapping sampling cutoff. This and
// TERRAIN_TRIPLANAR_BLEND_FACTOR together ensures that only one or two samples
// per texture are used in most places, making triplanar mapping more
// performant. Should be greater than 0 to work.
// There's also an artistic design choice in the use of these factors, and the
// use of triplanar generally. Don't take these triplanar constants for granted.
#define TERRAIN_TRIPLANAR_MIX_THRESHOLD 0.01
#define SAMPLE_X 1 << 0
#define SAMPLE_Y 1 << 1
#define SAMPLE_Z 1 << 2
#define MIX_X 1 << 3
#define MIX_Y 1 << 4
#define MIX_Z 1 << 5
#define MIX_W 1 << 6
struct PBRMix
{
vec4 col; // RGB color with alpha, linear space
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
vec3 orm; // Occlusion, roughness, metallic
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
vec2 rm; // Roughness, metallic
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
vec3 vNt; // Unpacked normal texture sample, vector
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
vec3 emissive; // RGB emissive color, linear space
#endif
};
PBRMix init_pbr_mix()
{
PBRMix mix;
mix.col = vec4(0);
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
mix.orm = vec3(0);
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
mix.rm = vec2(0);
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
mix.vNt = vec3(0);
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
mix.emissive = vec3(0);
#endif
return mix;
}
// Usage example, for two weights:
// vec2 weights = ... // Weights must add up to 1
// PBRMix mix = init_pbr_mix();
// PBRMix mix1 = ...
// mix = mix_pbr(mix, mix1, weights.x);
// PBRMix mix2 = ...
// mix = mix_pbr(mix, mix2, weights.y);
PBRMix mix_pbr(PBRMix mix1, PBRMix mix2, float mix2_weight)
{
PBRMix mix;
mix.col = mix1.col + (mix2.col * mix2_weight);
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
mix.orm = mix1.orm + (mix2.orm * mix2_weight);
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
mix.rm = mix1.rm + (mix2.rm * mix2_weight);
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
mix.vNt = mix1.vNt + (mix2.vNt * mix2_weight);
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
mix.emissive = mix1.emissive + (mix2.emissive * mix2_weight);
#endif
return mix;
}
PBRMix sample_pbr(
vec2 uv
, sampler2D tex_col
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
, sampler2D tex_orm
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
, sampler2D tex_vNt
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, sampler2D tex_emissive
#endif
)
{
PBRMix mix;
mix.col = texture(tex_col, uv);
mix.col.rgb = srgb_to_linear(mix.col.rgb);
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
mix.orm = texture(tex_orm, uv).xyz;
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
mix.rm = texture(tex_orm, uv).yz;
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
mix.vNt = texture(tex_vNt, uv).xyz*2.0-1.0;
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
mix.emissive = srgb_to_linear(texture(tex_emissive, uv).xyz);
#endif
return mix;
}
struct TerrainTriplanar
{
vec3 weight;
int type;
};
struct TerrainMix
{
vec4 weight;
int type;
};
#define TerrainMixSample vec4[4]
#define TerrainMixSample3 vec3[4]
TerrainMix get_terrain_mix_weights(float alpha1, float alpha2, float alphaFinal)
{
TerrainMix tm;
vec4 sample_x = vec4(1,0,0,0);
vec4 sample_y = vec4(0,1,0,0);
vec4 sample_z = vec4(0,0,1,0);
vec4 sample_w = vec4(0,0,0,1);
tm.weight = mix( mix(sample_w, sample_z, alpha2), mix(sample_y, sample_x, alpha1), alphaFinal );
tm.weight -= TERRAIN_RAMP_MIX_THRESHOLD;
ivec4 usage = max(ivec4(0), ivec4(ceil(tm.weight)));
// Prevent negative weights and keep weights balanced
tm.weight = tm.weight*vec4(usage);
tm.weight /= (tm.weight.x + tm.weight.y + tm.weight.z + tm.weight.w);
tm.type = (usage.x * MIX_X) |
(usage.y * MIX_Y) |
(usage.z * MIX_Z) |
(usage.w * MIX_W);
return tm;
}
TerrainTriplanar _t_triplanar()
{
float sharpness = TERRAIN_TRIPLANAR_BLEND_FACTOR;
float threshold = TERRAIN_TRIPLANAR_MIX_THRESHOLD;
vec3 weight_signed = pow(abs(vary_vertex_normal), vec3(sharpness));
weight_signed /= (weight_signed.x + weight_signed.y + weight_signed.z);
weight_signed -= vec3(threshold);
TerrainTriplanar tw;
// *NOTE: Make sure the threshold doesn't affect the materials
tw.weight = max(vec3(0), weight_signed);
tw.weight /= (tw.weight.x + tw.weight.y + tw.weight.z);
ivec3 usage = ivec3(round(max(vec3(0), sign(weight_signed))));
tw.type = ((usage.x) * SAMPLE_X) |
((usage.y) * SAMPLE_Y) |
((usage.z) * SAMPLE_Z);
return tw;
}
// Assume weights add to 1
float terrain_mix(TerrainMix tm, vec4 tms4)
{
return (tm.weight.x * tms4[0]) +
(tm.weight.y * tms4[1]) +
(tm.weight.z * tms4[2]) +
(tm.weight.w * tms4[3]);
}
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
// Triplanar mapping
// Pre-transformed texture coordinates for each axial uv slice (Packing: xy, yz, (-x)z, unused)
#define TerrainCoord vec4[2]
vec2 _t_uv(vec2 uv_unflipped, float sign_or_zero)
{
// Handle case where sign is 0
float sign = (2.0*sign_or_zero) + 1.0;
sign /= abs(sign);
// If the vertex normal is negative, flip the texture back
// right-side up.
vec2 uv = uv_unflipped * vec2(sign, 1);
return uv;
}
vec3 _t_normal_post_1(vec3 vNt0, float sign_or_zero)
{
// Assume normal is unpacked
vec3 vNt1 = vNt0;
// Get sign
float sign = sign_or_zero;
// Handle case where sign is 0
sign = (2.0*sign) + 1.0;
sign /= abs(sign);
// If the sign is negative, rotate normal by 180 degrees
vNt1.xy = (min(0, sign) * vNt1.xy) + (min(0, -sign) * -vNt1.xy);
return vNt1;
}
// Triplanar-specific normal texture fixes
vec3 _t_normal_post_x(vec3 vNt0)
{
vec3 vNt_x = _t_normal_post_1(vNt0, sign(vary_vertex_normal.x));
// *HACK: Transform normals according to orientation of the UVs
vNt_x.xy = vec2(-vNt_x.y, vNt_x.x);
return vNt_x;
}
vec3 _t_normal_post_y(vec3 vNt0)
{
vec3 vNt_y = _t_normal_post_1(vNt0, sign(vary_vertex_normal.y));
// *HACK: Transform normals according to orientation of the UVs
vNt_y.xy = -vNt_y.xy;
return vNt_y;
}
vec3 _t_normal_post_z(vec3 vNt0)
{
vec3 vNt_z = _t_normal_post_1(vNt0, sign(vary_vertex_normal.z));
return vNt_z;
}
PBRMix terrain_sample_pbr(
TerrainCoord terrain_coord
, TerrainTriplanar tw
, sampler2D tex_col
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
, sampler2D tex_orm
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
, sampler2D tex_vNt
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, sampler2D tex_emissive
#endif
)
{
PBRMix mix = init_pbr_mix();
#define get_uv_x() _t_uv(terrain_coord[0].zw, sign(vary_vertex_normal.x))
#define get_uv_y() _t_uv(terrain_coord[1].xy, sign(vary_vertex_normal.y))
#define get_uv_z() _t_uv(terrain_coord[0].xy, sign(vary_vertex_normal.z))
switch (tw.type & SAMPLE_X)
{
case SAMPLE_X:
PBRMix mix_x = sample_pbr(
get_uv_x()
, tex_col
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
, tex_orm
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
, tex_vNt
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, tex_emissive
#endif
);
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
// Triplanar-specific normal texture fix
mix_x.vNt = _t_normal_post_x(mix_x.vNt);
#endif
mix = mix_pbr(mix, mix_x, tw.weight.x);
break;
default:
break;
}
switch (tw.type & SAMPLE_Y)
{
case SAMPLE_Y:
PBRMix mix_y = sample_pbr(
get_uv_y()
, tex_col
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
, tex_orm
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
, tex_vNt
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, tex_emissive
#endif
);
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
// Triplanar-specific normal texture fix
mix_y.vNt = _t_normal_post_y(mix_y.vNt);
#endif
mix = mix_pbr(mix, mix_y, tw.weight.y);
break;
default:
break;
}
switch (tw.type & SAMPLE_Z)
{
case SAMPLE_Z:
PBRMix mix_z = sample_pbr(
get_uv_z()
, tex_col
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
, tex_orm
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
, tex_vNt
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, tex_emissive
#endif
);
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
// Triplanar-specific normal texture fix
// *NOTE: Bottom face has not been tested
mix_z.vNt = _t_normal_post_z(mix_z.vNt);
#endif
mix = mix_pbr(mix, mix_z, tw.weight.z);
break;
default:
break;
}
return mix;
}
#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1
#define TerrainCoord vec2
#define terrain_sample_pbr sample_pbr
#endif
PBRMix multiply_factors_pbr(
PBRMix mix_in
, vec4 factor_col
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
, vec3 factor_orm
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
, vec2 factor_rm
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, vec3 factor_emissive
#endif
)
{
PBRMix mix = mix_in;
mix.col *= factor_col;
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
mix.orm *= factor_orm;
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
mix.rm *= factor_rm;
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
mix.emissive *= factor_emissive;
#endif
return mix;
}
PBRMix terrain_sample_and_multiply_pbr(
TerrainCoord terrain_coord
, sampler2D tex_col
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
, sampler2D tex_orm
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
, sampler2D tex_vNt
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, sampler2D tex_emissive
#endif
, vec4 factor_col
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
, vec3 factor_orm
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
, vec2 factor_rm
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, vec3 factor_emissive
#endif
)
{
PBRMix mix = terrain_sample_pbr(
terrain_coord
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
, _t_triplanar()
#endif
, tex_col
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
, tex_orm
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
, tex_vNt
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, tex_emissive
#endif
);
mix = multiply_factors_pbr(mix
, factor_col
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
, factor_orm
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
, factor_rm
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
, factor_emissive
#endif
);
return mix;
}

View File

@ -0,0 +1,93 @@
/**
* @file class1\environment\pbrterrainV.glsl
*
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2023, 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$
*/
uniform mat3 normal_matrix;
uniform mat4 texture_matrix0;
uniform mat4 modelview_projection_matrix;
in vec3 position;
in vec3 normal;
in vec4 tangent;
in vec4 diffuse_color;
in vec2 texcoord1;
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
out vec4[2] vary_coords;
#endif
out vec3 vary_vertex_normal; // Used by pbrterrainUtilF.glsl
out vec3 vary_normal;
out vec3 vary_tangent;
flat out float vary_sign;
out vec4 vary_texcoord0;
out vec4 vary_texcoord1;
// *HACK: tangent_space_transform should use texture_normal_transform, or maybe
// we shouldn't use tangent_space_transform at all. See the call to
// tangent_space_transform below.
uniform vec4[2] texture_base_color_transform;
vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl_animation_transform);
vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform);
void main()
{
//transform vertex
gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
vec3 n = normal_matrix * normal;
vary_vertex_normal = normal;
vec3 t = normal_matrix * tangent.xyz;
vary_tangent = normalize(t);
// *TODO: Decide if we want this. It may be better to just calculate the
// tangents on-the-fly in the fragment shader, due to the subtleties of the
// effect of triplanar mapping on UVs.
// *HACK: Should be using texture_normal_transform here. The KHR texture
// transform spec requires handling texture transforms separately for each
// individual texture.
vary_tangent = normalize(tangent_space_transform(vec4(t, tangent.w), n, texture_base_color_transform, texture_matrix0));
vary_sign = tangent.w;
vary_normal = normalize(n);
// Transform and pass tex coords
// *HACK: texture_base_color_transform is used for all of these here, but
// the KHR texture transform spec requires handling texture transforms
// separately for each individual texture.
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
// xy
vary_coords[0].xy = texture_transform(position.xy, texture_base_color_transform, texture_matrix0);
// yz
vary_coords[0].zw = texture_transform(position.yz, texture_base_color_transform, texture_matrix0);
// (-x)z
vary_coords[1].xy = texture_transform(position.xz * vec2(-1, 1), texture_base_color_transform, texture_matrix0);
#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1
vary_texcoord0.xy = texture_transform(position.xy, texture_base_color_transform, texture_matrix0);
#endif
vec4 tc = vec4(texcoord1,0,1);
vary_texcoord0.zw = tc.xy;
vary_texcoord1.xy = tc.xy-vec2(2.0, 0.0);
vary_texcoord1.zw = tc.xy-vec2(1.0, 0.0);
}

View File

@ -39,9 +39,11 @@ in vec4 vary_texcoord0;
in vec4 vary_texcoord1;
vec2 encode_normal(vec3 n);
void mirrorClip(vec3 position);
void main()
{
mirrorClip(pos);
/// Note: This should duplicate the blending functionality currently used for the terrain rendering.
vec4 color0 = texture(detail_0, vary_texcoord0.xy);

View File

@ -25,12 +25,12 @@
uniform mat3 normal_matrix;
uniform mat4 texture_matrix0;
uniform mat4 modelview_matrix;
uniform mat4 modelview_projection_matrix;
in vec3 position;
in vec3 normal;
in vec4 diffuse_color;
in vec2 texcoord0;
in vec2 texcoord1;
out vec3 pos;
@ -41,18 +41,16 @@ out vec4 vary_texcoord1;
uniform vec4 object_plane_s;
uniform vec4 object_plane_t;
vec4 texgen_object(vec4 vpos, vec4 tc, mat4 mat, vec4 tp0, vec4 tp1)
vec2 texgen_object(vec4 vpos, mat4 mat, vec4 tp0, vec4 tp1)
{
vec4 tcoord;
tcoord.x = dot(vpos, tp0);
tcoord.y = dot(vpos, tp1);
tcoord.z = tc.z;
tcoord.w = tc.w;
tcoord = mat * tcoord;
return tcoord;
return tcoord.xy;
}
void main()
@ -62,12 +60,12 @@ void main()
vec4 t_pos = modelview_projection_matrix * pre_pos;
gl_Position = t_pos;
pos = t_pos.xyz;
pos = (modelview_matrix*pre_pos).xyz;
vary_normal = normalize(normal_matrix * normal);
// Transform and pass tex coords
vary_texcoord0.xy = texgen_object(vec4(position, 1.0), vec4(texcoord0,0,1), texture_matrix0, object_plane_s, object_plane_t).xy;
vary_texcoord0.xy = texgen_object(vec4(position, 1.0), texture_matrix0, object_plane_s, object_plane_t);
vec4 t = vec4(texcoord1,0,1);

View File

@ -65,7 +65,7 @@ vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl
// Apply texture animation first to avoid shearing and other artifacts
texcoord = (sl_animation_transform * vec4(texcoord, 0, 1)).xy;
// Convert to left-handed coordinate system. The offset of 1 is necessary
// for rotations to be applied correctly.
// for rotation and scale to be applied correctly.
texcoord.y = 1.0 - texcoord.y;
texcoord = khr_texture_transform(texcoord, khr_gltf_transform[0].xy, khr_gltf_transform[0].z, khr_gltf_transform[1].xy);
// Convert back to right-handed coordinate system

View File

@ -32,13 +32,16 @@ uniform sampler2D diffuseMap;
in vec4 vertex_color;
in vec3 vary_normal;
in vec2 vary_texcoord0;
in vec3 vary_position;
uniform float minimum_alpha;
vec2 encode_normal(vec3 n);
void mirrorClip(vec3 pos);
void main()
{
mirrorClip(vary_position);
vec4 col = texture(diffuseMap, vary_texcoord0.xy);
if (col.a < minimum_alpha)
{

View File

@ -24,6 +24,7 @@
*/
uniform mat4 texture_matrix0;
uniform mat4 modelview_matrix;
uniform mat4 modelview_projection_matrix;
uniform mat3 normal_matrix;
@ -34,11 +35,14 @@ in vec2 texcoord0;
out vec3 vary_normal;
out vec4 vertex_color;
out vec2 vary_texcoord0;
out vec3 vary_position;
void main()
{
//transform vertex
gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz;
vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
vary_normal = normalize(normal_matrix * normal);

View File

@ -0,0 +1,33 @@
/**
* @file normaldebugF.glsl
*
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2023, 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$
*/
out vec4 frag_color;
in vec4 vertex_color;
void main()
{
frag_color = max(vertex_color, vec4(0));
}

View File

@ -0,0 +1,76 @@
/**
* @file normaldebugG.glsl
*
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2023, 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$
*/
// *NOTE: Geometry shaders have a reputation for being slow. Consider using
// compute shaders instead, which have a reputation for being fast. This
// geometry shader in particular seems to run fine on my machine, but I won't
// vouch for this in performance-critical areas.
// -Cosmic,2023-09-28
out vec4 vertex_color;
in vec4 normal_g[];
#if HAS_ATTRIBUTE_TANGENT == 1
in vec4 tangent_g[];
#endif
layout(TRIANGLES) in;
#if HAS_ATTRIBUTE_TANGENT == 1
layout(LINE_STRIP, max_vertices = 12) out;
#else
layout(LINE_STRIP, max_vertices = 6) out;
#endif
void triangle_normal_debug(int i)
{
// Normal
vec4 normal_color = vec4(1.0, 1.0, 0.0, 1.0);
gl_Position = gl_in[i].gl_Position;
vertex_color = normal_color;
EmitVertex();
gl_Position = normal_g[i];
vertex_color = normal_color;
EmitVertex();
EndPrimitive();
#if HAS_ATTRIBUTE_TANGENT == 1
// Tangent
vec4 tangent_color = vec4(0.0, 1.0, 1.0, 1.0);
gl_Position = gl_in[i].gl_Position;
vertex_color = tangent_color;
EmitVertex();
gl_Position = tangent_g[i];
vertex_color = tangent_color;
EmitVertex();
EndPrimitive();
#endif
}
void main()
{
triangle_normal_debug(0);
triangle_normal_debug(1);
triangle_normal_debug(2);
}

View File

@ -0,0 +1,74 @@
/**
* @file normaldebugV.glsl
*
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2023, 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$
*/
in vec3 position;
in vec3 normal;
out vec4 normal_g;
#if HAS_ATTRIBUTE_TANGENT == 1
in vec4 tangent;
out vec4 tangent_g;
#endif
uniform float debug_normal_draw_length;
#ifdef HAS_SKIN
mat4 getObjectSkinnedTransform();
#else
uniform mat3 normal_matrix;
#endif
uniform mat4 projection_matrix;
uniform mat4 modelview_matrix;
// *NOTE: Should use the modelview_projection_matrix here in the non-skinned
// case for efficiency, but opting for the simplier implementation for now as
// this is debug code. Also, the skinned version hasn't beeen tested yet.
// world_pos = mat * vec4(position.xyz, 1.0)
vec4 get_screen_normal(vec3 position, vec4 world_pos, vec3 normal, mat4 mat)
{
vec4 world_norm = mat * vec4((position + normal), 1.0);
world_norm.xyz -= world_pos.xyz;
world_norm.xyz = debug_normal_draw_length * normalize(world_norm.xyz);
world_norm.xyz += world_pos.xyz;
return projection_matrix * world_norm;
}
void main()
{
#ifdef HAS_SKIN
mat4 mat = getObjectSkinnedTransform();
mat = modelview_matrix * mat;
#else
#define mat modelview_matrix
#endif
vec4 world_pos = mat * vec4(position.xyz,1.0);
gl_Position = projection_matrix * world_pos;
normal_g = get_screen_normal(position.xyz, world_pos, normal.xyz, mat);
#if HAS_ATTRIBUTE_TANGENT == 1
tangent_g = get_screen_normal(position.xyz, world_pos, tangent.xyz, mat);
#endif
}

View File

@ -38,6 +38,7 @@ in vec3 vary_dir;
uniform float mipLevel;
uniform int u_width;
uniform float max_probe_lod;
uniform float probe_strength;
// =============================================================================================================
@ -129,7 +130,7 @@ vec4 prefilterEnvMap(vec3 R)
float totalWeight = 0.0;
float envMapDim = float(textureSize(reflectionProbes, 0).s);
float roughness = mipLevel/max_probe_lod;
int numSamples = max(int(32*roughness), 1);
int numSamples = max(int(PROBE_FILTER_SAMPLES*roughness), 1);
float numMips = max_probe_lod+1;
@ -163,5 +164,6 @@ void main()
{
vec3 N = normalize(vary_dir);
frag_color = max(prefilterEnvMap(N), vec4(0));
frag_color.a *= probe_strength;
}
// =============================================================================================================

View File

@ -30,9 +30,13 @@ uniform sampler2D texture1;
in vec2 vary_texcoord0;
in vec2 vary_texcoord1;
in vec3 vary_position;
void mirrorClip(vec3 pos);
void main()
{
mirrorClip(vary_position);
float tex0 = texture(texture0, vary_texcoord0.xy).a;
float tex1 = texture(texture1, vary_texcoord1.xy).a;

View File

@ -23,6 +23,7 @@
* $/LicenseInfo$
*/
uniform mat4 modelview_matrix;
uniform mat4 texture_matrix0;
uniform mat4 modelview_projection_matrix;
@ -32,11 +33,11 @@ in vec2 texcoord1;
out vec2 vary_texcoord0;
out vec2 vary_texcoord1;
out vec3 vary_position;
#ifdef HAS_SKIN
mat4 getObjectSkinnedTransform();
uniform mat4 projection_matrix;
uniform mat4 modelview_matrix;
#endif
void main()
@ -46,8 +47,10 @@ void main()
mat4 mat = getObjectSkinnedTransform();
mat = modelview_matrix * mat;
vec4 pos = mat * vec4(position.xyz, 1.0);
vary_position = pos.xyz;
gl_Position = projection_matrix * pos;
#else
vary_position = (modelview_matrix * vec4(position.xyz, 1.0)).xyz;
gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
#endif
vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;

View File

@ -78,6 +78,8 @@ float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen);
float getAmbientClamp();
void mirrorClip(vec3 pos);
void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit_linear);
@ -167,6 +169,8 @@ vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 diffuse, vec3 v, vec3 n, vec
void main()
{
mirrorClip(vary_position);
vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5;
vec4 pos = vec4(vary_position, 1.0);

View File

@ -90,6 +90,7 @@ float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen);
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, bool transparent, vec3 amblit_linear);
void mirrorClip(vec3 pos);
void waterClip(vec3 pos);
void calcDiffuseSpecular(vec3 baseColor, float metallic, inout vec3 diffuseColor, inout vec3 specularColor);
@ -156,6 +157,8 @@ vec3 calcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor,
void main()
{
mirrorClip(vary_position);
vec3 color = vec3(0,0,0);
vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir;

View File

@ -53,8 +53,11 @@ void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout
void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity);
void mirrorClip(vec3 pos);
void main()
{
mirrorClip(vary_position);
#ifdef HAS_DIFFUSE_LOOKUP
vec4 color = diffuseLookup(vary_texcoord0.xy);
#else

View File

@ -45,6 +45,13 @@ void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float
vec3 srgb_to_linear(vec3 cs);
vec3 linear_to_srgb(vec3 cs);
uniform mat4 modelview_matrix;
uniform mat3 normal_matrix;
in vec3 vary_position;
void mirrorClip(vec3 pos);
#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
out vec4 frag_color;
@ -66,12 +73,12 @@ uniform vec4 morphFactor;
uniform vec3 camPosLocal;
uniform mat3 env_mat;
uniform float is_mirror;
uniform vec3 sun_dir;
uniform vec3 moon_dir;
in vec2 vary_fragcoord;
in vec3 vary_position;
uniform mat4 proj_mat;
uniform mat4 inv_proj;
uniform vec2 screen_res;
@ -285,12 +292,12 @@ float getShadow(vec3 pos, vec3 norm)
void main()
{
mirrorClip(vary_position);
waterClip();
// diffcol == diffuse map combined with vertex color
vec4 diffcol = texture(diffuseMap, vary_texcoord0.xy);
diffcol.rgb *= vertex_color.rgb;
alphaMask(diffcol.a);
// spec == specular map combined with specular color
@ -407,9 +414,12 @@ void main()
#else // mode is not DIFFUSE_ALPHA_MODE_BLEND, encode to gbuffer
// deferred path // See: C++: addDeferredAttachment(), shader: softenLightF.glsl
float flag = GBUFFER_FLAG_HAS_ATMOS;
frag_data[0] = vec4(diffcol.rgb, emissive); // gbuffer is sRGB for legacy materials
frag_data[1] = vec4(spec.rgb, glossiness); // XYZ = Specular color. W = Specular exponent.
frag_data[2] = vec4(encode_normal(norm), env, GBUFFER_FLAG_HAS_ATMOS);; // XY = Normal. Z = Env. intensity. W = 1 skip atmos (mask off fog)
frag_data[2] = vec4(encode_normal(norm), env, flag);; // XY = Normal. Z = Env. intensity. W = 1 skip atmos (mask off fog)
frag_data[3] = vec4(0);
#endif
}

View File

@ -31,6 +31,7 @@ float tapScreenSpaceReflection(int totalSamples, vec2 tc, vec3 viewPos, vec3 n,
uniform samplerCubeArray reflectionProbes;
uniform samplerCubeArray irradianceProbes;
uniform sampler2D sceneMap;
uniform int cube_snapshot;
uniform float max_probe_lod;
@ -681,6 +682,35 @@ vec3 sampleProbeAmbient(vec3 pos, vec3 dir, vec3 amblit)
return col[1]+col[0];
}
#if defined(HERO_PROBES)
uniform vec4 clipPlane;
uniform samplerCubeArray heroProbes;
void tapHeroProbe(inout vec3 glossenv, vec3 pos, vec3 norm, float glossiness)
{
float clipDist = dot(pos.xyz, clipPlane.xyz) + clipPlane.w;
if (clipDist > 0.0 && clipDist < 0.1 && glossiness > 0.8)
{
vec3 refnormpersp = reflect(pos.xyz, norm.xyz);
if (dot(refnormpersp.xyz, clipPlane.xyz) > 0.0)
{
glossenv = textureLod(heroProbes, vec4(env_mat * refnormpersp, 0), (1.0-glossiness)*10).xyz;
}
}
}
#else
void tapHeroProbe(inout vec3 glossenv, vec3 pos, vec3 norm, float glossiness)
{
}
#endif
void doProbeSample(inout vec3 ambenv, inout vec3 glossenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, bool transparent, vec3 amblit)
{
@ -712,6 +742,8 @@ void doProbeSample(inout vec3 ambenv, inout vec3 glossenv,
glossenv = mix(glossenv, ssr.rgb, ssr.a);
}
#endif
tapHeroProbe(glossenv, pos, norm, glossiness);
}
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
@ -799,6 +831,7 @@ void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout
{
float lod = (1.0-glossiness)*reflection_lods;
glossenv = sampleProbes(pos, normalize(refnormpersp), lod);
}
if (envIntensity > 0.0)
@ -826,6 +859,9 @@ void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout
}
#endif
tapHeroProbe(glossenv, pos, norm, glossiness);
tapHeroProbe(legacyenv, pos, norm, 1.0);
glossenv = clamp(glossenv, vec3(0), vec3(10));
}

View File

@ -32,6 +32,16 @@ uniform sampler2D specularRect;
uniform sampler2D normalMap;
uniform sampler2D emissiveRect; // PBR linear packed Occlusion, Roughness, Metal. See: pbropaqueF.glsl
uniform samplerCubeArray heroProbes;
#if defined(HERO_PROBES)
layout (std140) uniform HeroProbeData
{
vec4 heroPosition[1];
int heroProbeCount;
};
#endif
const float M_PI = 3.14159265;
#if defined(HAS_SUN_SHADOW) || defined(HAS_SSAO)
@ -50,6 +60,7 @@ uniform float ssao_irradiance_max;
#endif
// Inputs
uniform vec4 clipPlane;
uniform mat3 env_mat;
uniform mat3 ssao_effect_mat;
uniform vec3 sun_dir;
@ -178,7 +189,7 @@ void main()
float gloss = 1.0 - perceptualRoughness;
sampleReflectionProbes(irradiance, radiance, tc, pos.xyz, norm.xyz, gloss, false, amblit_linear);
adjustIrradiance(irradiance, ambocc);
vec3 diffuseColor;
@ -209,7 +220,7 @@ void main()
vec3 legacyenv = vec3(0);
sampleReflectionProbesLegacy(irradiance, glossenv, legacyenv, tc, pos.xyz, norm.xyz, spec.a, envIntensity, false, amblit_linear);
adjustIrradiance(irradiance, ambocc);
// apply lambertian IBL only (see pbrIbl)
@ -244,6 +255,7 @@ void main()
// add radiance map
applyGlossEnv(color, glossenv, spec, pos.xyz, norm.xyz);
}
color.rgb = mix(color.rgb, baseColor.rgb, baseColor.a);

View File

@ -55,9 +55,11 @@ in vec4 view;
in vec3 vary_position;
vec4 applyWaterFogViewLinearNoClip(vec3 pos, vec4 color);
void mirrorClip(vec3 position);
void main()
{
mirrorClip(vary_position);
vec4 color;
//get detail normals

View File

@ -35,6 +35,8 @@ vec3 scaleSoftClipFragLinear(vec3 l);
void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive);
vec4 applyWaterFogViewLinear(vec3 pos, vec4 color);
void mirrorClip(vec3 pos);
// PBR interface
vec2 BRDF(float NoV, float roughness);
@ -129,6 +131,7 @@ vec3 getPositionWithNDC(vec3 ndc);
void main()
{
mirrorClip(vary_position);
vN = vary_normal;
vT = vary_tangent;
vB = cross(vN, vT);

View File

@ -1,4 +1,4 @@
version 59
version 60
// 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
@ -48,6 +48,8 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 2
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
RenderTerrainPBRDetail 1 0
RenderTerrainPBRPlanarSampleCount 1 3
RenderTreeLODFactor 1 1.0
RenderVBOEnable 1 1
RenderVBOMappingDisable 1 1
@ -94,6 +96,8 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 0
RenderTerrainDetail 1 0
RenderTerrainLODFactor 1 1
RenderTerrainPBRDetail 1 -4
RenderTerrainPBRPlanarSampleCount 1 1
RenderTreeLODFactor 1 0
RenderVolumeLODFactor 1 1.125
RenderDeferredSSAO 1 0
@ -123,6 +127,8 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 0
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 1.0
RenderTerrainPBRDetail 1 -1
RenderTerrainPBRPlanarSampleCount 1 1
RenderTreeLODFactor 1 0.5
RenderVolumeLODFactor 1 1.125
RenderDeferredSSAO 1 0
@ -150,6 +156,8 @@ RenderLocalLightCount 1 512
RenderTransparentWater 1 0
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
RenderTerrainPBRDetail 1 0
RenderTerrainPBRPlanarSampleCount 1 1
RenderTreeLODFactor 1 0.5
RenderVolumeLODFactor 1 1.25
RenderDeferredSSAO 1 0
@ -179,6 +187,8 @@ RenderLocalLightCount 1 1024
RenderTransparentWater 1 1
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
RenderTerrainPBRDetail 1 0
RenderTerrainPBRPlanarSampleCount 1 1
RenderTreeLODFactor 1 0.5
RenderVolumeLODFactor 1 1.375
RenderDeferredSSAO 1 0
@ -208,6 +218,8 @@ RenderLocalLightCount 1 2048
RenderTransparentWater 1 1
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
RenderTerrainPBRDetail 1 0
RenderTerrainPBRPlanarSampleCount 1 3
RenderTreeLODFactor 1 0.5
RenderVolumeLODFactor 1 1.5
RenderDeferredSSAO 1 1
@ -236,6 +248,8 @@ RenderMaxPartCount 1 4096
RenderLocalLightCount 1 4096
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
RenderTerrainPBRDetail 1 0
RenderTerrainPBRPlanarSampleCount 1 3
RenderTransparentWater 1 1
RenderTreeLODFactor 1 0.5
RenderVolumeLODFactor 1 1.75
@ -264,6 +278,8 @@ RenderLocalLightCount 1 8192
RenderMaxPartCount 1 8192
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
RenderTerrainPBRDetail 1 0
RenderTerrainPBRPlanarSampleCount 1 3
RenderTransparentWater 1 1
RenderTreeLODFactor 1 1.0
RenderVolumeLODFactor 1 2.0
@ -321,3 +337,5 @@ RenderFSAASamples 0 0
RenderReflectionsEnabled 0 0
RenderReflectionProbeDetail 0 0
list TexUnit16orLess
RenderTerrainPBRDetail 1 -1

View File

@ -1,4 +1,4 @@
version 56
version 57
// 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
@ -45,6 +45,8 @@ RenderObjectBump 1 1
RenderLocalLightCount 1 4096
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
RenderTerrainPBRDetail 1 0
RenderTerrainPBRPlanarSampleCount 1 3
RenderTransparentWater 1 1
RenderTreeLODFactor 1 1.0
RenderVBOEnable 1 1
@ -89,6 +91,8 @@ RenderLocalLightCount 1 8
RenderMaxPartCount 1 0
RenderTerrainDetail 1 0
RenderTerrainLODFactor 1 1
RenderTerrainPBRDetail 1 -4
RenderTerrainPBRPlanarSampleCount 1 1
RenderTransparentWater 1 0
RenderTreeLODFactor 1 0
RenderVolumeLODFactor 1 1.125
@ -118,6 +122,8 @@ RenderMaxPartCount 1 2048
RenderLocalLightCount 1 256
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 1.0
RenderTerrainPBRDetail 1 -1
RenderTerrainPBRPlanarSampleCount 1 1
RenderTransparentWater 1 1
RenderTreeLODFactor 1 0.5
RenderVolumeLODFactor 1 1.125
@ -147,6 +153,8 @@ RenderMaxPartCount 1 4096
RenderLocalLightCount 1 512
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
RenderTerrainPBRDetail 1 0
RenderTerrainPBRPlanarSampleCount 1 1
RenderTransparentWater 1 1
RenderTreeLODFactor 1 0.5
RenderVolumeLODFactor 1 1.25
@ -176,6 +184,8 @@ RenderMaxPartCount 1 4096
RenderLocalLightCount 1 1024
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
RenderTerrainPBRDetail 1 0
RenderTerrainPBRPlanarSampleCount 1 1
RenderTransparentWater 1 1
RenderTreeLODFactor 1 0.5
RenderVolumeLODFactor 1 1.375
@ -205,6 +215,8 @@ RenderMaxPartCount 1 4096
RenderLocalLightCount 1 2048
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
RenderTerrainPBRDetail 1 0
RenderTerrainPBRPlanarSampleCount 1 3
RenderTransparentWater 1 1
RenderTreeLODFactor 1 0.5
RenderVolumeLODFactor 1 1.5
@ -234,6 +246,8 @@ RenderMaxPartCount 1 4096
RenderLocalLightCount 1 4096
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
RenderTerrainPBRDetail 1 0
RenderTerrainPBRPlanarSampleCount 1 3
RenderTransparentWater 1 1
RenderTreeLODFactor 1 0.5
RenderVolumeLODFactor 1 1.75
@ -262,6 +276,8 @@ RenderLocalLightCount 1 8192
RenderMaxPartCount 1 8192
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
RenderTerrainPBRDetail 1 0
RenderTerrainPBRPlanarSampleCount 1 3
RenderTransparentWater 1 1
RenderTreeLODFactor 1 1.0
RenderVolumeLODFactor 1 2.0
@ -308,6 +324,9 @@ RenderShadowDetail 0 0
list TexUnit8orLess
RenderDeferredSSAO 0 0
list TexUnit16orLess
RenderTerrainPBRDetail 1 -1
list AMD
RenderDeferredSSAO 1 0

View File

@ -229,6 +229,7 @@
#include "pipeline.h"
#include "llgesturemgr.h"
#include "llsky.h"
#include "llvlcomposition.h"
#include "llvlmanager.h"
#include "llviewercamera.h"
#include "lldrawpoolbump.h"

View File

@ -286,6 +286,7 @@ public:
ANIMATED_CHILD = 0x01000000,
ACTIVE_CHILD = 0x02000000,
FOR_UNLOAD = 0x04000000, //should be unload from memory
MIRROR = 0x08000000, // Used as a mirror, needs a hero probe position to be calculated.
} EDrawableFlags;
public:

View File

@ -567,14 +567,19 @@ void LLRenderPass::pushRiggedMaskBatches(U32 type, bool texture, bool batch_text
void LLRenderPass::applyModelMatrix(const LLDrawInfo& params)
{
if (params.mModelMatrix != gGLLastMatrix)
applyModelMatrix(params.mModelMatrix);
}
void LLRenderPass::applyModelMatrix(const LLMatrix4* model_matrix)
{
if (model_matrix != gGLLastMatrix)
{
gGLLastMatrix = params.mModelMatrix;
gGLLastMatrix = model_matrix;
gGL.matrixMode(LLRender::MM_MODELVIEW);
gGL.loadMatrix(gGLModelView);
if (params.mModelMatrix)
if (model_matrix)
{
gGL.multMatrix((GLfloat*) params.mModelMatrix->mMatrix);
gGL.multMatrix((GLfloat*) model_matrix->mMatrix);
}
gPipeline.mMatrixOpCount++;
}
@ -746,6 +751,7 @@ void LLRenderPass::pushUntexturedGLTFBatches(U32 type)
}
}
// static
void LLRenderPass::pushGLTFBatch(LLDrawInfo& params)
{
auto& mat = params.mGLTFMaterial;
@ -764,6 +770,7 @@ void LLRenderPass::pushGLTFBatch(LLDrawInfo& params)
teardown_texture_matrix(params);
}
// static
void LLRenderPass::pushUntexturedGLTFBatch(LLDrawInfo& params)
{
auto& mat = params.mGLTFMaterial;
@ -825,6 +832,7 @@ void LLRenderPass::pushUntexturedRiggedGLTFBatches(U32 type)
}
// static
void LLRenderPass::pushRiggedGLTFBatch(LLDrawInfo& params, LLVOAvatar*& lastAvatar, U64& lastMeshId)
{
if (params.mAvatar.notNull() && (lastAvatar != params.mAvatar || lastMeshId != params.mSkinInfo->mHash))
@ -837,6 +845,7 @@ void LLRenderPass::pushRiggedGLTFBatch(LLDrawInfo& params, LLVOAvatar*& lastAvat
pushGLTFBatch(params);
}
// static
void LLRenderPass::pushUntexturedRiggedGLTFBatch(LLDrawInfo& params, LLVOAvatar*& lastAvatar, U64& lastMeshId)
{
if (params.mAvatar.notNull() && (lastAvatar != params.mAvatar || lastMeshId != params.mSkinInfo->mHash))

View File

@ -58,9 +58,9 @@ public:
POOL_SIMPLE,
POOL_FULLBRIGHT,
POOL_BUMP,
POOL_TERRAIN,
POOL_MATERIALS,
POOL_GLTF_PBR,
POOL_TERRAIN,
POOL_GRASS,
POOL_GLTF_PBR_ALPHA_MASK,
POOL_TREE,
@ -349,8 +349,8 @@ public:
void resetDrawOrders() { }
static void applyModelMatrix(const LLDrawInfo& params);
// Use before a non-GLTF batch if it is interleaved with GLTF batches that share the same shader
static void resetGLTFTextureTransform();
// For rendering that doesn't use LLDrawInfo for some reason
static void applyModelMatrix(const LLMatrix4* model_matrix);
void pushBatches(U32 type, bool texture = true, bool batch_textures = false);
void pushUntexturedBatches(U32 type);
@ -374,10 +374,10 @@ public:
void pushUntexturedRiggedGLTFBatches(U32 type);
// push a single GLTF draw call
void pushGLTFBatch(LLDrawInfo& params);
void pushRiggedGLTFBatch(LLDrawInfo& params, LLVOAvatar*& lastAvatar, U64& lastMeshId);
void pushUntexturedGLTFBatch(LLDrawInfo& params);
void pushUntexturedRiggedGLTFBatch(LLDrawInfo& params, LLVOAvatar*& lastAvatar, U64& lastMeshId);
static void pushGLTFBatch(LLDrawInfo& params);
static void pushRiggedGLTFBatch(LLDrawInfo& params, LLVOAvatar*& lastAvatar, U64& lastMeshId);
static void pushUntexturedGLTFBatch(LLDrawInfo& params);
static void pushUntexturedRiggedGLTFBatch(LLDrawInfo& params, LLVOAvatar*& lastAvatar, U64& lastMeshId);
void pushMaskBatches(U32 type, bool texture = true, bool batch_textures = false);
void pushRiggedMaskBatches(U32 type, bool texture = true, bool batch_textures = false);

View File

@ -54,8 +54,9 @@
const F32 DETAIL_SCALE = 1.f/16.f;
int DebugDetailMap = 0;
S32 LLDrawPoolTerrain::sDetailMode = 1;
S32 LLDrawPoolTerrain::sPBRDetailMode = 0;
F32 LLDrawPoolTerrain::sDetailScale = DETAIL_SCALE;
F32 LLDrawPoolTerrain::sPBRDetailScale = DETAIL_SCALE;
static LLGLSLShader* sShader = NULL;
static LLTrace::BlockTimerStatHandle FTM_SHADOW_TERRAIN("Terrain Shadow");
@ -66,7 +67,8 @@ LLDrawPoolTerrain::LLDrawPoolTerrain(LLViewerTexture *texturep) :
{
// Hack!
sDetailScale = 1.f/gSavedSettings.getF32("RenderTerrainScale");
sDetailMode = gSavedSettings.getS32("RenderTerrainDetail");
sPBRDetailScale = 1.f/gSavedSettings.getF32("RenderTerrainPBRScale");
sPBRDetailMode = gSavedSettings.getS32("RenderTerrainPBRDetail");
mAlphaRampImagep = LLViewerTextureManager::getFetchedTexture(IMG_ALPHA_GRAD);
//gGL.getTexUnit(0)->bind(mAlphaRampImagep.get());
@ -105,13 +107,7 @@ U32 LLDrawPoolTerrain::getVertexDataMask()
void LLDrawPoolTerrain::prerender()
{
sDetailMode = gSavedSettings.getS32("RenderTerrainDetail");
}
//static
S32 LLDrawPoolTerrain::getDetailMode()
{
return sDetailMode;
sPBRDetailMode = gSavedSettings.getS32("RenderTerrainPBRDetail");
}
void LLDrawPoolTerrain::boostTerrainDetailTextures()
@ -121,8 +117,38 @@ void LLDrawPoolTerrain::boostTerrainDetailTextures()
LLVLComposition *compp = regionp->getComposition();
for (S32 i = 0; i < 4; i++)
{
compp->mDetailTextures[i]->setBoostLevel(LLGLTexture::BOOST_TERRAIN);
compp->mDetailTextures[i]->addTextureStats(1024.f * 1024.f);
constexpr LLGLTexture::EBoostLevel level = LLGLTexture::BOOST_TERRAIN;
constexpr float stats = 1024.f * 1024.f;
LLPointer<LLViewerFetchedTexture>& tex = compp->mDetailTextures[i];
llassert(tex.notNull());
tex->setBoostLevel(level);
tex->addTextureStats(stats);
LLPointer<LLFetchedGLTFMaterial>& fetched_material = compp->mDetailMaterials[i];
if (fetched_material)
{
if (fetched_material->mBaseColorTexture)
{
fetched_material->mBaseColorTexture->setBoostLevel(level);
fetched_material->mBaseColorTexture->addTextureStats(stats);
}
if (fetched_material->mNormalTexture)
{
fetched_material->mNormalTexture->setBoostLevel(level);
fetched_material->mNormalTexture->addTextureStats(stats);
}
if (fetched_material->mMetallicRoughnessTexture)
{
fetched_material->mMetallicRoughnessTexture->setBoostLevel(level);
fetched_material->mMetallicRoughnessTexture->addTextureStats(stats);
}
if (fetched_material->mEmissiveTexture)
{
fetched_material->mEmissiveTexture->setBoostLevel(level);
fetched_material->mEmissiveTexture->addTextureStats(stats);
}
}
}
}
@ -130,10 +156,6 @@ void LLDrawPoolTerrain::beginDeferredPass(S32 pass)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN);
LLFacePool::beginRenderPass(pass);
sShader = &gDeferredTerrainProgram;
sShader->bind();
}
void LLDrawPoolTerrain::endDeferredPass(S32 pass)
@ -204,19 +226,8 @@ void LLDrawPoolTerrain::drawLoop()
{
LLFace *facep = *iter;
LLMatrix4* model_matrix = &(facep->getDrawable()->getRegion()->mRenderMatrix);
if (model_matrix != gGLLastMatrix)
{
llassert(gGL.getMatrixMode() == LLRender::MM_MODELVIEW);
gGLLastMatrix = model_matrix;
gGL.loadMatrix(gGLModelView);
if (model_matrix)
{
gGL.multMatrix((GLfloat*) model_matrix->mMatrix);
}
gPipeline.mMatrixOpCount++;
}
llassert(gGL.getMatrixMode() == LLRender::MM_MODELVIEW);
LLRenderPass::applyModelMatrix(&facep->getDrawable()->getRegion()->mRenderMatrix);
facep->renderIndexed();
}
@ -225,9 +236,34 @@ void LLDrawPoolTerrain::drawLoop()
void LLDrawPoolTerrain::renderFullShader()
{
const BOOL use_local_materials = gLocalTerrainMaterials.materialsReady(true, false);
// Hack! Get the region that this draw pool is rendering from!
LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion();
LLVLComposition *compp = regionp->getComposition();
const BOOL use_textures = !use_local_materials && (compp->getMaterialType() == LLTerrainMaterials::Type::TEXTURE);
if (use_textures)
{
// Use textures
sShader = &gDeferredTerrainProgram;
sShader->bind();
renderFullShaderTextures();
}
else
{
// Use materials
sShader = &gDeferredPBRTerrainProgram;
sShader->bind();
renderFullShaderPBR(use_local_materials);
}
}
void LLDrawPoolTerrain::renderFullShaderTextures()
{
// Hack! Get the region that this draw pool is rendering from!
LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion();
LLVLComposition *compp = regionp->getComposition();
LLViewerTexture *detail_texture0p = compp->mDetailTextures[0];
LLViewerTexture *detail_texture1p = compp->mDetailTextures[1];
LLViewerTexture *detail_texture2p = compp->mDetailTextures[2];
@ -322,6 +358,236 @@ void LLDrawPoolTerrain::renderFullShader()
gGL.getTexUnit(detail0)->activate();
}
// *TODO: Investigate use of bindFast for PBR terrain textures
void LLDrawPoolTerrain::renderFullShaderPBR(BOOL local_materials)
{
// Hack! Get the region that this draw pool is rendering from!
LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion();
LLVLComposition *compp = regionp->getComposition();
LLPointer<LLFetchedGLTFMaterial> (*fetched_materials)[LLVLComposition::ASSET_COUNT] = &compp->mDetailMaterials;
constexpr U32 terrain_material_count = LLVLComposition::ASSET_COUNT;
#ifdef SHOW_ASSERT
constexpr U32 shader_material_count = 1 + LLViewerShaderMgr::TERRAIN_DETAIL3_BASE_COLOR - LLViewerShaderMgr::TERRAIN_DETAIL0_BASE_COLOR;
llassert(shader_material_count == terrain_material_count);
#endif
if (local_materials)
{
// Override region terrain with the global local override terrain
fetched_materials = &gLocalTerrainMaterials.mDetailMaterials;
}
const LLGLTFMaterial* materials[terrain_material_count];
for (U32 i = 0; i < terrain_material_count; ++i)
{
materials[i] = (*fetched_materials)[i].get();
if (!materials[i]) { materials[i] = &LLGLTFMaterial::sDefault; }
}
S32 detail_basecolor[terrain_material_count];
S32 detail_normal[terrain_material_count];
S32 detail_metalrough[terrain_material_count];
S32 detail_emissive[terrain_material_count];
for (U32 i = 0; i < terrain_material_count; ++i)
{
LLViewerTexture* detail_basecolor_texturep = nullptr;
LLViewerTexture* detail_normal_texturep = nullptr;
LLViewerTexture* detail_metalrough_texturep = nullptr;
LLViewerTexture* detail_emissive_texturep = nullptr;
const LLFetchedGLTFMaterial* fetched_material = (*fetched_materials)[i].get();
if (fetched_material)
{
detail_basecolor_texturep = fetched_material->mBaseColorTexture;
detail_normal_texturep = fetched_material->mNormalTexture;
detail_metalrough_texturep = fetched_material->mMetallicRoughnessTexture;
detail_emissive_texturep = fetched_material->mEmissiveTexture;
}
detail_basecolor[i] = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_DETAIL0_BASE_COLOR + i);
if (detail_basecolor_texturep)
{
gGL.getTexUnit(detail_basecolor[i])->bind(detail_basecolor_texturep);
}
else
{
gGL.getTexUnit(detail_basecolor[i])->bind(LLViewerFetchedTexture::sWhiteImagep);
}
gGL.getTexUnit(detail_basecolor[i])->setTextureAddressMode(LLTexUnit::TAM_WRAP);
gGL.getTexUnit(detail_basecolor[i])->activate();
if (sPBRDetailMode >= TERRAIN_PBR_DETAIL_NORMAL)
{
detail_normal[i] = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_DETAIL0_NORMAL + i);
if (detail_normal_texturep)
{
gGL.getTexUnit(detail_normal[i])->bind(detail_normal_texturep);
}
else
{
gGL.getTexUnit(detail_normal[i])->bind(LLViewerFetchedTexture::sFlatNormalImagep);
}
gGL.getTexUnit(detail_normal[i])->setTextureAddressMode(LLTexUnit::TAM_WRAP);
gGL.getTexUnit(detail_normal[i])->activate();
}
if (sPBRDetailMode >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
{
detail_metalrough[i] = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_DETAIL0_METALLIC_ROUGHNESS + i);
if (detail_metalrough_texturep)
{
gGL.getTexUnit(detail_metalrough[i])->bind(detail_metalrough_texturep);
}
else
{
gGL.getTexUnit(detail_metalrough[i])->bind(LLViewerFetchedTexture::sWhiteImagep);
}
gGL.getTexUnit(detail_metalrough[i])->setTextureAddressMode(LLTexUnit::TAM_WRAP);
gGL.getTexUnit(detail_metalrough[i])->activate();
}
if (sPBRDetailMode >= TERRAIN_PBR_DETAIL_EMISSIVE)
{
detail_emissive[i] = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_DETAIL0_EMISSIVE + i);
if (detail_emissive_texturep)
{
gGL.getTexUnit(detail_emissive[i])->bind(detail_emissive_texturep);
}
else
{
gGL.getTexUnit(detail_emissive[i])->bind(LLViewerFetchedTexture::sWhiteImagep);
}
gGL.getTexUnit(detail_emissive[i])->setTextureAddressMode(LLTexUnit::TAM_WRAP);
gGL.getTexUnit(detail_emissive[i])->activate();
}
}
LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
llassert(shader);
// *TODO: Figure out why this offset is *sometimes* producing seams at the
// region edge, and repeat jumps when crossing regions, when
// RenderTerrainPBRScale is not a factor of the region scale.
LLVector3d region_origin_global = gAgent.getRegion()->getOriginGlobal();
F32 offset_x = (F32)fmod(region_origin_global.mdV[VX], 1.0/(F64)sPBRDetailScale)*sPBRDetailScale;
F32 offset_y = (F32)fmod(region_origin_global.mdV[VY], 1.0/(F64)sPBRDetailScale)*sPBRDetailScale;
LLGLTFMaterial::TextureTransform base_color_transform;
base_color_transform.mScale = LLVector2(sPBRDetailScale, sPBRDetailScale);
base_color_transform.mOffset = LLVector2(offset_x, offset_y);
F32 base_color_packed[8];
base_color_transform.getPacked(base_color_packed);
// *HACK: Use the same texture repeats for all PBR terrain textures for now
// (not compliant with KHR texture transform spec)
shader->uniform4fv(LLShaderMgr::TEXTURE_BASE_COLOR_TRANSFORM, 2, (F32*)base_color_packed);
LLSettingsWater::ptr_t pwater = LLEnvironment::instance().getCurrentWater();
//
// Alpha Ramp
//
S32 alpha_ramp = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP);
gGL.getTexUnit(alpha_ramp)->bind(m2DAlphaRampImagep);
gGL.getTexUnit(alpha_ramp)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
//
// GLTF uniforms
//
LLColor4 base_color_factors[terrain_material_count];
F32 metallic_factors[terrain_material_count];
F32 roughness_factors[terrain_material_count];
LLColor3 emissive_colors[terrain_material_count];
F32 minimum_alphas[terrain_material_count];
for (U32 i = 0; i < terrain_material_count; ++i)
{
const LLGLTFMaterial* material = materials[i];
base_color_factors[i] = material->mBaseColor;
metallic_factors[i] = material->mMetallicFactor;
roughness_factors[i] = material->mRoughnessFactor;
emissive_colors[i] = material->mEmissiveColor;
// glTF 2.0 Specification 3.9.4. Alpha Coverage
// mAlphaCutoff is only valid for LLGLTFMaterial::ALPHA_MODE_MASK
// Use 0 here due to GLTF terrain blending (LLGLTFMaterial::bind uses
// -1 for easier debugging)
F32 min_alpha = -0.0f;
if (material->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_MASK)
{
// dividing the alpha cutoff by transparency here allows the shader to compare against
// the alpha value of the texture without needing the transparency value
min_alpha = material->mAlphaCutoff/material->mBaseColor.mV[3];
}
minimum_alphas[i] = min_alpha;
}
shader->uniform4fv(LLShaderMgr::TERRAIN_BASE_COLOR_FACTORS, terrain_material_count, (F32*)base_color_factors);
if (sPBRDetailMode >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
{
shader->uniform4f(LLShaderMgr::TERRAIN_METALLIC_FACTORS, metallic_factors[0], metallic_factors[1], metallic_factors[2], metallic_factors[3]);
shader->uniform4f(LLShaderMgr::TERRAIN_ROUGHNESS_FACTORS, roughness_factors[0], roughness_factors[1], roughness_factors[2], roughness_factors[3]);
}
if (sPBRDetailMode >= TERRAIN_PBR_DETAIL_EMISSIVE)
{
shader->uniform3fv(LLShaderMgr::TERRAIN_EMISSIVE_COLORS, terrain_material_count, (F32*)emissive_colors);
}
shader->uniform4f(LLShaderMgr::TERRAIN_MINIMUM_ALPHAS, minimum_alphas[0], minimum_alphas[1], minimum_alphas[2], minimum_alphas[3]);
// GL_BLEND disabled by default
drawLoop();
// Disable multitexture
sShader->disableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP);
gGL.getTexUnit(alpha_ramp)->unbind(LLTexUnit::TT_TEXTURE);
gGL.getTexUnit(alpha_ramp)->disable();
gGL.getTexUnit(alpha_ramp)->activate();
for (U32 i = 0; i < terrain_material_count; ++i)
{
sShader->disableTexture(LLViewerShaderMgr::TERRAIN_DETAIL0_BASE_COLOR + i);
if (sPBRDetailMode >= TERRAIN_PBR_DETAIL_NORMAL)
{
sShader->disableTexture(LLViewerShaderMgr::TERRAIN_DETAIL0_NORMAL + i);
}
if (sPBRDetailMode >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
{
sShader->disableTexture(LLViewerShaderMgr::TERRAIN_DETAIL0_METALLIC_ROUGHNESS + i);
}
if (sPBRDetailMode >= TERRAIN_PBR_DETAIL_EMISSIVE)
{
sShader->disableTexture(LLViewerShaderMgr::TERRAIN_DETAIL0_EMISSIVE + i);
}
gGL.getTexUnit(detail_basecolor[i])->unbind(LLTexUnit::TT_TEXTURE);
gGL.getTexUnit(detail_basecolor[i])->disable();
gGL.getTexUnit(detail_basecolor[i])->activate();
if (sPBRDetailMode >= TERRAIN_PBR_DETAIL_NORMAL)
{
gGL.getTexUnit(detail_normal[i])->unbind(LLTexUnit::TT_TEXTURE);
gGL.getTexUnit(detail_normal[i])->disable();
gGL.getTexUnit(detail_normal[i])->activate();
}
if (sPBRDetailMode >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
{
gGL.getTexUnit(detail_metalrough[i])->unbind(LLTexUnit::TT_TEXTURE);
gGL.getTexUnit(detail_metalrough[i])->disable();
gGL.getTexUnit(detail_metalrough[i])->activate();
}
if (sPBRDetailMode >= TERRAIN_PBR_DETAIL_EMISSIVE)
{
gGL.getTexUnit(detail_emissive[i])->unbind(LLTexUnit::TT_TEXTURE);
gGL.getTexUnit(detail_emissive[i])->disable();
gGL.getTexUnit(detail_emissive[i])->activate();
}
}
}
void LLDrawPoolTerrain::hilightParcelOwners()
{
{ //use fullbright shader for highlighting

View File

@ -37,13 +37,12 @@ public:
{
VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX |
LLVertexBuffer::MAP_NORMAL |
LLVertexBuffer::MAP_TANGENT | // Only PBR terrain uses this currently
LLVertexBuffer::MAP_TEXCOORD0 |
LLVertexBuffer::MAP_TEXCOORD1
};
virtual U32 getVertexDataMask();
static S32 getDetailMode();
LLDrawPoolTerrain(LLViewerTexture *texturep);
virtual ~LLDrawPoolTerrain();
@ -67,8 +66,9 @@ public:
LLPointer<LLViewerTexture> m2DAlphaRampImagep;
LLPointer<LLViewerTexture> mAlphaNoiseImagep;
static S32 sDetailMode;
static F32 sDetailScale; // meters per texture
static S32 sPBRDetailMode;
static F32 sDetailScale; // textures per meter
static F32 sPBRDetailScale; // textures per meter
protected:
void boostTerrainDetailTextures();
@ -79,6 +79,8 @@ protected:
void renderFull2TU();
void renderFull4TU();
void renderFullShader();
void renderFullShaderTextures();
void renderFullShaderPBR(BOOL local_materials = false);
void drawLoop();
private:

View File

@ -85,17 +85,8 @@ void LLDrawPoolTree::renderDeferred(S32 pass)
{
LLMatrix4* model_matrix = &(face->getDrawable()->getRegion()->mRenderMatrix);
if (model_matrix != gGLLastMatrix)
{
gGLLastMatrix = model_matrix;
gGL.loadMatrix(gGLModelView);
if (model_matrix)
{
llassert(gGL.getMatrixMode() == LLRender::MM_MODELVIEW);
gGL.multMatrix((GLfloat*)model_matrix->mMatrix);
}
gPipeline.mMatrixOpCount++;
}
llassert(gGL.getMatrixMode() == LLRender::MM_MODELVIEW);
LLRenderPass::applyModelMatrix(model_matrix);
buff->setBuffer();
buff->drawRange(LLRender::TRIANGLES, 0, buff->getNumVerts() - 1, buff->getNumIndices(), 0);

View File

@ -181,19 +181,26 @@ void LLViewerDynamicTexture::postRender(BOOL success)
//-----------------------------------------------------------------------------
BOOL LLViewerDynamicTexture::updateAllInstances()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
sNumRenders = 0;
if (gGLManager.mIsDisabled)
{
return TRUE;
}
bool use_fbo = gPipeline.mBake.isComplete() && !gGLManager.mIsAMD;
LLRenderTarget& bake_target = gPipeline.mAuxillaryRT.deferredScreen;
if (use_fbo)
{
gPipeline.mBake.bindTarget();
gPipeline.mBake.clear();
}
if (!bake_target.isComplete())
{
llassert(false);
return FALSE;
}
llassert(bake_target.getWidth() >= LLPipeline::MAX_BAKE_WIDTH);
llassert(bake_target.getHeight() >= LLPipeline::MAX_BAKE_WIDTH);
bake_target.bindTarget();
bake_target.clear();
LLGLSLShader::unbind();
LLVertexBuffer::unbind();
@ -208,11 +215,14 @@ BOOL LLViewerDynamicTexture::updateAllInstances()
LLViewerDynamicTexture *dynamicTexture = *iter;
if (dynamicTexture->needsRender())
{
llassert(dynamicTexture->getFullWidth() <= LLPipeline::MAX_BAKE_WIDTH);
llassert(dynamicTexture->getFullHeight() <= LLPipeline::MAX_BAKE_WIDTH);
glClear(GL_DEPTH_BUFFER_BIT);
gDepthDirty = TRUE;
gGL.color4f(1,1,1,1);
dynamicTexture->setBoundTarget(use_fbo ? &gPipeline.mBake : nullptr);
dynamicTexture->setBoundTarget(&bake_target);
dynamicTexture->preRender(); // Must be called outside of startRender()
result = FALSE;
if (dynamicTexture->render())
@ -229,10 +239,7 @@ BOOL LLViewerDynamicTexture::updateAllInstances()
}
}
if (use_fbo)
{
gPipeline.mBake.flush();
}
bake_target.flush();
gGL.flush();

View File

@ -1675,8 +1675,6 @@ void LLEnvironment::update(const LLViewerCamera * cam)
updateSettingsUniforms();
// *TODO: potential optimization - this block may only need to be
// executed some of the time. For example for water shaders only.
{
LLViewerShaderMgr::shader_iter shaders_iter, end_shaders;
end_shaders = LLViewerShaderMgr::instance()->endShaders();
@ -1687,6 +1685,10 @@ void LLEnvironment::update(const LLViewerCamera * cam)
|| shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER))
{
shaders_iter->mUniformsDirty = TRUE;
if (shaders_iter->mRiggedVariant)
{
shaders_iter->mRiggedVariant->mUniformsDirty = TRUE;
}
}
}
}

View File

@ -1889,7 +1889,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
F32* normals = (F32*) norm.get();
LLVector4a* src = vf.mNormals;
LLVector4a* end = src+num_vertices;
while (src < end)
{
LLVector4a normal;

View File

@ -664,6 +664,10 @@ void LLFeatureManager::applyBaseMasks()
{
maskFeatures("TexUnit8orLess");
}
if (gGLManager.mNumTextureImageUnits <= 16)
{
maskFeatures("TexUnit16orLess");
}
if (gGLManager.mVRAM > 512)
{
maskFeatures("VRAMGT512");

View File

@ -37,8 +37,6 @@
LLFetchedGLTFMaterial::LLFetchedGLTFMaterial()
: LLGLTFMaterial()
, mExpectedFlusTime(0.f)
, mActive(true)
, mFetching(false)
{
}
@ -242,10 +240,11 @@ void LLFetchedGLTFMaterial::onMaterialComplete(std::function<void()> material_co
materialCompleteCallbacks.push_back(material_complete);
}
void LLFetchedGLTFMaterial::materialComplete()
void LLFetchedGLTFMaterial::materialComplete(bool success)
{
llassert(mFetching);
mFetching = false;
mFetchSuccess = success;
for (std::function<void()> material_complete : materialCompleteCallbacks)
{
@ -254,55 +253,3 @@ void LLFetchedGLTFMaterial::materialComplete()
materialCompleteCallbacks.clear();
materialCompleteCallbacks.shrink_to_fit();
}
LLPointer<LLViewerFetchedTexture> LLFetchedGLTFMaterial::getUITexture()
{
if (mFetching)
{
return nullptr;
}
auto fetch_texture_for_ui = [](LLPointer<LLViewerFetchedTexture>& img, const LLUUID& id)
{
if (id.notNull())
{
if (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(id))
{
LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
if (obj)
{
LLViewerTexture* viewerTexture = obj->getBakedTextureForMagicId(id);
img = viewerTexture ? dynamic_cast<LLViewerFetchedTexture*>(viewerTexture) : NULL;
}
}
else
{
img = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
}
}
if (img)
{
img->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
img->forceToSaveRawImage(0);
}
};
fetch_texture_for_ui(mBaseColorTexture, mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR]);
fetch_texture_for_ui(mNormalTexture, mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL]);
fetch_texture_for_ui(mMetallicRoughnessTexture, mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS]);
fetch_texture_for_ui(mEmissiveTexture, mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE]);
if ((mBaseColorTexture && (mBaseColorTexture->getRawImageLevel() != 0)) ||
(mNormalTexture && (mNormalTexture->getRawImageLevel() != 0)) ||
(mMetallicRoughnessTexture && (mMetallicRoughnessTexture->getRawImageLevel() != 0)) ||
(mEmissiveTexture && (mEmissiveTexture->getRawImageLevel() != 0)))
{
return nullptr;
}
// *HACK: Use one of the PBR texture components as the preview texture for now
mPreviewTexture = mBaseColorTexture;
return mPreviewTexture;
}

View File

@ -40,6 +40,8 @@ public:
virtual ~LLFetchedGLTFMaterial();
LLFetchedGLTFMaterial& operator=(const LLFetchedGLTFMaterial& rhs);
// LLGLTFMaterial::operator== is defined, but LLFetchedGLTFMaterial::operator== is not.
bool operator==(const LLGLTFMaterial& rhs) const = delete;
// If this material is loaded, fire the given function
void onMaterialComplete(std::function<void()> material_complete);
@ -49,8 +51,7 @@ public:
void bind(LLViewerTexture* media_tex = nullptr);
bool isFetching() const { return mFetching; }
LLPointer<LLViewerFetchedTexture> getUITexture();
bool isLoaded() const { return !mFetching && mFetchSuccess; }
void addTextureEntry(LLTextureEntry* te) override;
void removeTextureEntry(LLTextureEntry* te) override;
@ -65,18 +66,16 @@ public:
std::set<LLTextureEntry*> mTextureEntires;
// Texture used for previewing the material in the UI
LLPointer<LLViewerFetchedTexture> mPreviewTexture;
protected:
// Lifetime management
void materialBegin();
void materialComplete();
void materialComplete(bool success);
F64 mExpectedFlusTime; // since epoch in seconds
bool mActive;
bool mFetching;
bool mActive = true;
bool mFetching = false;
bool mFetchSuccess = false;
std::vector<std::function<void()>> materialCompleteCallbacks;
};

View File

@ -605,6 +605,26 @@ LLPanelRegionEnvironment* LLFloaterRegionInfo::getPanelEnvironment()
return panel;
}
enum class TerrainMaterialType
{
TEXTURE,
PBR_MATERIAL,
COUNT
};
TerrainMaterialType material_type_from_index(S32 index)
{
if (index == 0)
{
return TerrainMaterialType::TEXTURE;
}
if (index == 1)
{
return TerrainMaterialType::PBR_MATERIAL;
}
return TerrainMaterialType::COUNT;
}
// static
LLPanelRegionTerrainInfo* LLFloaterRegionInfo::getPanelRegionTerrain()
{
@ -1307,6 +1327,17 @@ void LLPanelRegionDebugInfo::onClickDebugConsole(void* data)
BOOL LLPanelRegionTerrainInfo::validateTextureSizes()
{
// *TODO: Don't early-exit in PBR material terrain editing mode, and
// instead do some reasonable checks that the PBR material is compatible
// with the terrain rendering pipeline. Err on the side of permissive.
LLComboBox* material_type_ctrl = getChild<LLComboBox>("terrain_material_type");
if (material_type_ctrl)
{
const TerrainMaterialType material_type = material_type_from_index(material_type_ctrl->getCurrentIndex());
const bool is_material_selected = material_type == TerrainMaterialType::PBR_MATERIAL;
if (is_material_selected) { return TRUE; }
}
static const S32 MAX_TERRAIN_TEXTURE_SIZE = 1024;
for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i)
{
@ -1324,7 +1355,7 @@ BOOL LLPanelRegionTerrainInfo::validateTextureSizes()
//LL_INFOS() << "texture detail " << i << " is " << width << "x" << height << "x" << components << LL_ENDL;
if (components != 3)
if (components != 3 && components != 4)
{
LLSD args;
args["TEXTURE_NUM"] = i+1;
@ -1380,12 +1411,20 @@ BOOL LLPanelRegionTerrainInfo::postBuild()
initCtrl("terrain_raise_spin");
initCtrl("terrain_lower_spin");
getChild<LLUICtrl>("terrain_material_type")->setCommitCallback(boost::bind(&LLPanelRegionTerrainInfo::onSelectMaterialType, this));
std::string buffer;
for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i)
{
buffer = llformat("texture_detail_%d", i);
initCtrl(buffer);
}
for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i)
{
buffer = llformat("material_detail_%d", i);
initCtrl(buffer);
}
for(S32 i = 0; i < CORNER_COUNT; ++i)
{
@ -1402,9 +1441,77 @@ BOOL LLPanelRegionTerrainInfo::postBuild()
mAskedTextureHeights = false;
mConfirmedTextureHeights = false;
refresh();
return LLPanelRegionInfo::postBuild();
}
// virtual
void LLPanelRegionTerrainInfo::refresh()
{
// For simplicity, require restart
static BOOL feature_pbr_terrain_enabled = gSavedSettings.getBOOL("RenderTerrainPBREnabled");
LLTextBox* texture_text = getChild<LLTextBox>("detail_texture_text");
if (texture_text) { texture_text->setVisible(!feature_pbr_terrain_enabled); }
LLComboBox* material_type_ctrl = getChild<LLComboBox>("terrain_material_type");
if (material_type_ctrl)
{
material_type_ctrl->setVisible(feature_pbr_terrain_enabled);
bool has_material_assets = false;
std::string buffer;
for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i)
{
buffer = llformat("material_detail_%d", i);
LLTextureCtrl* material_ctrl = getChild<LLTextureCtrl>(buffer);
if (material_ctrl && material_ctrl->getImageAssetID().notNull())
{
has_material_assets = true;
break;
}
}
TerrainMaterialType material_type = material_type_from_index(material_type_ctrl->getCurrentIndex());
if (!feature_pbr_terrain_enabled) { material_type = TerrainMaterialType::TEXTURE; }
const bool is_material_selected = material_type == TerrainMaterialType::PBR_MATERIAL;
material_type_ctrl->setEnabled(feature_pbr_terrain_enabled && !(is_material_selected && has_material_assets));
}
}
void LLPanelRegionTerrainInfo::onSelectMaterialType()
{
LLComboBox* material_type_ctrl = getChild<LLComboBox>("terrain_material_type");
if (!material_type_ctrl) { return; }
const TerrainMaterialType material_type = material_type_from_index(material_type_ctrl->getCurrentIndex());
const bool show_texture_controls = material_type == TerrainMaterialType::TEXTURE;
const bool show_material_controls = material_type == TerrainMaterialType::PBR_MATERIAL;
std::string buffer;
LLTextureCtrl* texture_ctrl;
for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i)
{
buffer = llformat("texture_detail_%d", i);
texture_ctrl = getChild<LLTextureCtrl>(buffer);
if (texture_ctrl)
{
texture_ctrl->setVisible(show_texture_controls);
}
}
for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i)
{
buffer = llformat("material_detail_%d", i);
texture_ctrl = getChild<LLTextureCtrl>(buffer);
if (texture_ctrl)
{
texture_ctrl->setVisible(show_material_controls);
}
}
}
// virtual
bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region)
{
@ -1421,18 +1528,30 @@ bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region)
getChild<LLUICtrl>("region_text")->setValue(LLSD(region->getName()));
LLVLComposition* compp = region->getComposition();
LLTextureCtrl* texture_ctrl;
// Are these 4 texture IDs or 4 material IDs? Who knows! Let's set the IDs on both pickers for now.
LLTextureCtrl* asset_ctrl;
std::string buffer;
for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i)
{
buffer = llformat("texture_detail_%d", i);
texture_ctrl = getChild<LLTextureCtrl>(buffer);
if(texture_ctrl)
asset_ctrl = getChild<LLTextureCtrl>(buffer);
if(asset_ctrl)
{
LL_DEBUGS() << "Detail Texture " << i << ": "
<< compp->getDetailTextureID(i) << LL_ENDL;
LLUUID tmp_id(compp->getDetailTextureID(i));
texture_ctrl->setImageAssetID(tmp_id);
<< compp->getDetailAssetID(i) << LL_ENDL;
LLUUID tmp_id(compp->getDetailAssetID(i));
asset_ctrl->setImageAssetID(tmp_id);
}
}
for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i)
{
buffer = llformat("material_detail_%d", i);
asset_ctrl = getChild<LLTextureCtrl>(buffer);
if(asset_ctrl)
{
LLUUID tmp_id(compp->getDetailAssetID(i));
asset_ctrl->setImageAssetID(tmp_id);
}
}
@ -1499,17 +1618,45 @@ BOOL LLPanelRegionTerrainInfo::sendUpdate()
}
}
LLTextureCtrl* texture_ctrl;
LLTextureCtrl* asset_ctrl;
std::string id_str;
LLMessageSystem* msg = gMessageSystem;
// Use material IDs instead of texture IDs if all material IDs are set, AND the mode is set to PBR materials.
S32 materials_used = 0;
LLComboBox* material_type_ctrl = getChild<LLComboBox>("terrain_material_type");
if (material_type_ctrl)
{
const TerrainMaterialType material_type = material_type_from_index(material_type_ctrl->getCurrentIndex());
const bool is_material_selected = material_type == TerrainMaterialType::PBR_MATERIAL;
if (is_material_selected)
{
for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i)
{
buffer = llformat("material_detail_%d", i);
asset_ctrl = getChild<LLTextureCtrl>(buffer);
if(asset_ctrl && asset_ctrl->getImageAssetID().notNull())
{
++materials_used;
}
}
}
}
for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i)
{
buffer = llformat("texture_detail_%d", i);
texture_ctrl = getChild<LLTextureCtrl>(buffer);
if(texture_ctrl)
if (materials_used == TERRAIN_TEXTURE_COUNT)
{
buffer = llformat("material_detail_%d", i);
asset_ctrl = getChild<LLTextureCtrl>(buffer);
}
else
{
buffer = llformat("texture_detail_%d", i);
asset_ctrl = getChild<LLTextureCtrl>(buffer);
}
if(asset_ctrl)
{
LLUUID tmp_id(texture_ctrl->getImageAssetID());
LLUUID tmp_id(asset_ctrl->getImageAssetID());
tmp_id.toString(id_str);
buffer = llformat("%d %s", i, id_str.c_str());
strings.push_back(buffer);

View File

@ -75,9 +75,9 @@ class LLFloaterRegionInfo : public LLFloater
public:
/*virtual*/ void onOpen(const LLSD& key);
/*virtual*/ void onClose(bool app_quitting);
/*virtual*/ BOOL postBuild();
void onOpen(const LLSD& key) override;
void onClose(bool app_quitting) override;
BOOL postBuild() override;
static void processEstateOwnerRequest(LLMessageSystem* msg, void**);
@ -98,7 +98,7 @@ public:
static LLPanelRegionEnvironment* getPanelEnvironment();
// from LLPanel
virtual void refresh();
void refresh() override;
void onRegionChanged();
void requestRegionInfo();
@ -144,7 +144,7 @@ public:
virtual bool refreshFromRegion(LLViewerRegion* region);
virtual bool estateUpdate(LLMessageSystem* msg) { return true; }
virtual BOOL postBuild();
BOOL postBuild() override;
virtual void updateChild(LLUICtrl* child_ctrl);
void enableButton(const std::string& btn_name, BOOL enable = TRUE);
@ -184,16 +184,15 @@ public:
: LLPanelRegionInfo() {}
~LLPanelRegionGeneralInfo() {}
virtual bool refreshFromRegion(LLViewerRegion* region);
bool refreshFromRegion(LLViewerRegion* region) override;
// LLPanel
virtual BOOL postBuild();
BOOL postBuild() override;
void onBtnSet();
void setObjBonusFactor(F32 object_bonus_factor) {mObjBonusFactor = object_bonus_factor;}
protected:
virtual BOOL sendUpdate();
BOOL sendUpdate() override;
void onClickKick();
void onKickCommit(const uuid_vec_t& ids);
static void onClickKickAll(void* userdata);
@ -214,13 +213,13 @@ public:
LLPanelRegionDebugInfo()
: LLPanelRegionInfo(), mTargetAvatar() {}
~LLPanelRegionDebugInfo() {}
// LLPanel
virtual BOOL postBuild();
BOOL postBuild() override;
virtual bool refreshFromRegion(LLViewerRegion* region);
bool refreshFromRegion(LLViewerRegion* region) override;
protected:
virtual BOOL sendUpdate();
BOOL sendUpdate() override;
void onClickChooseAvatar();
void callbackAvatarID(const uuid_vec_t& ids, const std::vector<LLAvatarName> names);
@ -247,9 +246,9 @@ public:
LLPanelRegionTerrainInfo() : LLPanelRegionInfo() {}
~LLPanelRegionTerrainInfo() {}
virtual BOOL postBuild(); // LLPanel
BOOL postBuild() override;
virtual bool refreshFromRegion(LLViewerRegion* region); // refresh local settings from region update from simulator
bool refreshFromRegion(LLViewerRegion* region) override; // refresh local settings from region update from simulator
void setEnvControls(bool available); // Whether environment settings are available for this region
BOOL validateTextureSizes();
@ -257,7 +256,8 @@ public:
//static void onChangeAnything(LLUICtrl* ctrl, void* userData); // callback for any change, to enable commit button
virtual BOOL sendUpdate();
void refresh() override;
void onSelectMaterialType();
static void onClickDownloadRaw(void*);
static void onClickUploadRaw(void*);
@ -265,6 +265,9 @@ public:
bool callbackBakeTerrain(const LLSD& notification, const LLSD& response);
bool callbackTextureHeights(const LLSD& notification, const LLSD& response);
protected:
BOOL sendUpdate() override;
private:
bool mConfirmedTextureHeights;
bool mAskedTextureHeights;
@ -303,13 +306,12 @@ public:
static void updateEstateName(const std::string& name);
static void updateEstateOwnerName(const std::string& name);
virtual bool refreshFromRegion(LLViewerRegion* region);
virtual bool estateUpdate(LLMessageSystem* msg);
bool refreshFromRegion(LLViewerRegion* region) override;
bool estateUpdate(LLMessageSystem* msg) override;
// LLPanel
virtual BOOL postBuild();
virtual void updateChild(LLUICtrl* child_ctrl);
virtual void refresh();
BOOL postBuild() override;
void updateChild(LLUICtrl* child_ctrl) override;
void refresh() override;
void refreshFromEstate();
@ -319,7 +321,7 @@ public:
void setOwnerName(const std::string& name);
protected:
virtual BOOL sendUpdate();
BOOL sendUpdate() override;
// confirmation dialog callback
bool callbackChangeLindenEstate(const LLSD& notification, const LLSD& response);
@ -339,17 +341,16 @@ public:
LLPanelEstateCovenant();
~LLPanelEstateCovenant() {}
// LLPanel
virtual BOOL postBuild();
virtual void updateChild(LLUICtrl* child_ctrl);
virtual bool refreshFromRegion(LLViewerRegion* region);
virtual bool estateUpdate(LLMessageSystem* msg);
BOOL postBuild() override;
void updateChild(LLUICtrl* child_ctrl) override;
bool refreshFromRegion(LLViewerRegion* region) override;
bool estateUpdate(LLMessageSystem* msg) override;
// LLView overrides
BOOL handleDragAndDrop(S32 x, S32 y, MASK mask,
BOOL drop, EDragAndDropType cargo_type,
void *cargo_data, EAcceptance *accept,
std::string& tooltip_msg);
std::string& tooltip_msg) override;
static bool confirmChangeCovenantCallback(const LLSD& notification, const LLSD& response);
static void resetCovenantID(void* userdata);
static bool confirmResetCovenantCallback(const LLSD& notification, const LLSD& response);
@ -382,7 +383,7 @@ public:
} EAssetStatus;
protected:
virtual BOOL sendUpdate();
BOOL sendUpdate() override;
LLTextBox* mEstateNameText;
LLTextBox* mEstateOwnerText;
LLTextBox* mLastModifiedText;
@ -401,16 +402,19 @@ class LLPanelRegionExperiences : public LLPanelRegionInfo
public:
LLPanelRegionExperiences(){}
/*virtual*/ BOOL postBuild();
virtual BOOL sendUpdate();
BOOL postBuild() override;
static bool experienceCoreConfirm(const LLSD& notification, const LLSD& response);
static void sendEstateExperienceDelta(U32 flags, const LLUUID& agent_id);
static void infoCallback(LLHandle<LLPanelRegionExperiences> handle, const LLSD& content);
bool refreshFromRegion(LLViewerRegion* region);
bool refreshFromRegion(LLViewerRegion* region) override;
void sendPurchaseRequest()const;
void processResponse( const LLSD& content );
protected:
BOOL sendUpdate() override;
private:
void refreshRegionExperiences();
@ -435,8 +439,8 @@ class LLPanelEstateAccess : public LLPanelRegionInfo
public:
LLPanelEstateAccess();
virtual BOOL postBuild();
virtual void updateChild(LLUICtrl* child_ctrl);
BOOL postBuild() override;
void updateChild(LLUICtrl* child_ctrl) override;
void updateControls(LLViewerRegion* region);
void updateLists();
@ -444,7 +448,7 @@ public:
void setPendingUpdate(bool pending) { mPendingUpdate = pending; }
bool getPendingUpdate() { return mPendingUpdate; }
virtual bool refreshFromRegion(LLViewerRegion* region);
bool refreshFromRegion(LLViewerRegion* region) override;
private:
void onClickAddAllowedAgent();

View File

@ -471,7 +471,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->materialComplete();
asset_data->mMaterial->materialComplete(false);
delete asset_data;
}
else
@ -556,7 +556,7 @@ void LLGLTFMaterialList::onAssetLoadComplete(const LLUUID& id, LLAssetType::ETyp
LL_DEBUGS("GLTF") << "Failed to get material " << id << LL_ENDL;
}
asset_data->mMaterial->materialComplete();
asset_data->mMaterial->materialComplete(true);
delete asset_data;
});

View File

@ -0,0 +1,566 @@
/**
* @file llgltfmaterialpreviewmgr.cpp
*
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2023, 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$
*/
#include "llviewerprecompiledheaders.h"
#include "llgltfmaterialpreviewmgr.h"
#include <memory>
#include <vector>
#include "llavatarappearancedefines.h"
#include "llenvironment.h"
#include "llselectmgr.h"
#include "llviewercamera.h"
#include "llviewercontrol.h"
#include "llviewerobject.h"
#include "llviewershadermgr.h"
#include "llviewertexturelist.h"
#include "llviewerwindow.h"
#include "llvolumemgr.h"
#include "pipeline.h"
LLGLTFMaterialPreviewMgr gGLTFMaterialPreviewMgr;
namespace
{
constexpr S32 FULLY_LOADED = 0;
constexpr S32 NOT_LOADED = 99;
};
LLGLTFPreviewTexture::MaterialLoadLevels::MaterialLoadLevels()
{
for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
{
levels[i] = NOT_LOADED;
}
}
S32& LLGLTFPreviewTexture::MaterialLoadLevels::operator[](size_t i)
{
llassert(i >= 0 && i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT);
return levels[i];
}
const S32& LLGLTFPreviewTexture::MaterialLoadLevels::operator[](size_t i) const
{
llassert(i >= 0 && i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT);
return levels[i];
}
bool LLGLTFPreviewTexture::MaterialLoadLevels::operator<(const MaterialLoadLevels& other) const
{
bool less = false;
for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
{
if (((*this)[i] > other[i])) { return false; }
less = less || ((*this)[i] < other[i]);
}
return less;
}
bool LLGLTFPreviewTexture::MaterialLoadLevels::operator>(const MaterialLoadLevels& other) const
{
bool great = false;
for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
{
if (((*this)[i] < other[i])) { return false; }
great = great || ((*this)[i] > other[i]);
}
return great;
}
namespace
{
void fetch_texture_for_ui(LLPointer<LLViewerFetchedTexture>& img, const LLUUID& id)
{
if (!img && id.notNull())
{
if (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(id))
{
LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
if (obj)
{
LLViewerTexture* viewerTexture = obj->getBakedTextureForMagicId(id);
img = viewerTexture ? dynamic_cast<LLViewerFetchedTexture*>(viewerTexture) : NULL;
}
}
else
{
img = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
}
}
if (img)
{
img->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
img->forceToSaveRawImage(0);
}
};
// *NOTE: Does not use the same conventions as texture discard level. Lower is better.
S32 get_texture_load_level(const LLPointer<LLViewerFetchedTexture>& texture)
{
if (!texture) { return FULLY_LOADED; }
const S32 raw_level = texture->getDiscardLevel();
if (raw_level < 0) { return NOT_LOADED; }
return raw_level;
}
LLGLTFPreviewTexture::MaterialLoadLevels get_material_load_levels(LLFetchedGLTFMaterial& material)
{
llassert(!material.isFetching());
using MaterialTextures = LLPointer<LLViewerFetchedTexture>*[LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT];
MaterialTextures textures;
textures[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR] = &material.mBaseColorTexture;
textures[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL] = &material.mNormalTexture;
textures[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS] = &material.mMetallicRoughnessTexture;
textures[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE] = &material.mEmissiveTexture;
LLGLTFPreviewTexture::MaterialLoadLevels levels;
for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
{
fetch_texture_for_ui(*textures[i], material.mTextureId[i]);
levels[i] = get_texture_load_level(*textures[i]);
}
return levels;
}
// Is the material loaded enough to start rendering a preview?
bool is_material_loaded_enough_for_ui(LLFetchedGLTFMaterial& material)
{
if (material.isFetching())
{
return false;
}
LLGLTFPreviewTexture::MaterialLoadLevels levels = get_material_load_levels(material);
for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
{
if (levels[i] == NOT_LOADED)
{
return false;
}
}
return true;
}
}; // namespace
LLGLTFPreviewTexture::LLGLTFPreviewTexture(LLPointer<LLFetchedGLTFMaterial> material, S32 width)
: LLViewerDynamicTexture(width, width, 4, EOrder::ORDER_MIDDLE, FALSE)
, mGLTFMaterial(material)
{
}
// static
LLPointer<LLGLTFPreviewTexture> LLGLTFPreviewTexture::create(LLPointer<LLFetchedGLTFMaterial> material)
{
return new LLGLTFPreviewTexture(material, LLPipeline::MAX_BAKE_WIDTH);
}
void LLGLTFPreviewTexture::preRender(BOOL clear_depth)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
MaterialLoadLevels current_load = get_material_load_levels(*mGLTFMaterial.get());
if (current_load < mBestLoad)
{
mShouldRender = true;
mBestLoad = current_load;
}
if (!mShouldRender) { return; }
LLViewerDynamicTexture::preRender(clear_depth);
}
namespace {
struct GLTFPreviewModel
{
GLTFPreviewModel(LLPointer<LLDrawInfo>& info, const LLMatrix4& mat)
: mDrawInfo(info)
, mModelMatrix(mat)
{
mDrawInfo->mModelMatrix = &mModelMatrix;
}
GLTFPreviewModel(GLTFPreviewModel&) = delete;
~GLTFPreviewModel()
{
// No model matrix necromancy
llassert(gGLLastMatrix != &mModelMatrix);
gGLLastMatrix = nullptr;
}
LLPointer<LLDrawInfo> mDrawInfo;
LLMatrix4 mModelMatrix; // Referenced by mDrawInfo
};
using PreviewSpherePart = std::unique_ptr<GLTFPreviewModel>;
using PreviewSphere = std::vector<PreviewSpherePart>;
// Like LLVolumeGeometryManager::registerFace but without batching or too-many-indices/vertices checking.
PreviewSphere create_preview_sphere(LLPointer<LLFetchedGLTFMaterial>& material, const LLMatrix4& model_matrix)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
const LLColor4U vertex_color(material->mBaseColor);
LLPrimitive prim;
prim.init_primitive(LL_PCODE_VOLUME);
LLVolumeParams params;
params.setType(LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE);
params.setBeginAndEndS(0.f, 1.f);
params.setBeginAndEndT(0.f, 1.f);
params.setRatio(1, 1);
params.setShear(0, 0);
constexpr auto MAX_LOD = LLVolumeLODGroup::NUM_LODS - 1;
prim.setVolume(params, MAX_LOD);
LLVolume* volume = prim.getVolume();
llassert(volume);
for (LLVolumeFace& face : volume->getVolumeFaces())
{
face.createTangents();
}
PreviewSphere preview_sphere;
preview_sphere.reserve(volume->getNumFaces());
LLPointer<LLVertexBuffer> buf = new LLVertexBuffer(
LLVertexBuffer::MAP_VERTEX |
LLVertexBuffer::MAP_NORMAL |
LLVertexBuffer::MAP_TEXCOORD0 |
LLVertexBuffer::MAP_COLOR |
LLVertexBuffer::MAP_TANGENT
);
U32 nv = 0;
U32 ni = 0;
for (LLVolumeFace& face : volume->getVolumeFaces())
{
nv += face.mNumVertices;
ni += face.mNumIndices;
}
buf->allocateBuffer(nv, ni);
// UV hacks
// Higher factor helps to see more details on the preview sphere
const LLVector2 uv_factor(2.0f, 2.0f);
// Offset places center of material in center of view
const LLVector2 uv_offset(-0.5f, -0.5f);
LLStrider<U16> indices;
LLStrider<LLVector4a> positions;
LLStrider<LLVector4a> normals;
LLStrider<LLVector2> texcoords;
LLStrider<LLColor4U> colors;
LLStrider<LLVector4a> tangents;
buf->getIndexStrider(indices);
buf->getVertexStrider(positions);
buf->getNormalStrider(normals);
buf->getTexCoord0Strider(texcoords);
buf->getColorStrider(colors);
buf->getTangentStrider(tangents);
U32 index_offset = 0;
U32 vertex_offset = 0;
for (const LLVolumeFace& face : volume->getVolumeFaces())
{
for (S32 i = 0; i < face.mNumIndices; ++i)
{
*indices++ = face.mIndices[i] + vertex_offset;
}
for (S32 v = 0; v < face.mNumVertices; ++v)
{
*positions++ = face.mPositions[v];
*normals++ = face.mNormals[v];
LLVector2 uv(face.mTexCoords[v]);
uv.scaleVec(uv_factor);
uv += uv_offset;
*texcoords++ = uv;
*colors++ = vertex_color;
*tangents++ = face.mTangents[v];
}
constexpr LLViewerTexture* no_media = nullptr;
LLPointer<LLDrawInfo> info = new LLDrawInfo(U16(vertex_offset), U16(vertex_offset + face.mNumVertices - 1), face.mNumIndices, index_offset, no_media, buf.get());
info->mGLTFMaterial = material;
preview_sphere.emplace_back(std::make_unique<GLTFPreviewModel>(info, model_matrix));
index_offset += face.mNumIndices;
vertex_offset += face.mNumVertices;
}
buf->unmapBuffer();
return preview_sphere;
}
void set_preview_sphere_material(PreviewSphere& preview_sphere, LLPointer<LLFetchedGLTFMaterial>& material)
{
llassert(!preview_sphere.empty());
if (preview_sphere.empty()) { return; }
const LLColor4U vertex_color(material->mBaseColor);
// See comments about unmapBuffer in llvertexbuffer.h
for (PreviewSpherePart& part : preview_sphere)
{
LLDrawInfo* info = part->mDrawInfo.get();
info->mGLTFMaterial = material;
LLVertexBuffer* buf = info->mVertexBuffer.get();
LLStrider<LLColor4U> colors;
const S32 count = info->mEnd - info->mStart + 1;
buf->getColorStrider(colors, info->mStart, count);
for (S32 i = 0; i < count; ++i)
{
*colors++ = vertex_color;
}
buf->unmapBuffer();
}
}
PreviewSphere& get_preview_sphere(LLPointer<LLFetchedGLTFMaterial>& material, const LLMatrix4& model_matrix)
{
static PreviewSphere preview_sphere;
if (preview_sphere.empty())
{
preview_sphere = create_preview_sphere(material, model_matrix);
}
else
{
set_preview_sphere_material(preview_sphere, material);
}
return preview_sphere;
}
// Final, direct modifications to shader constants, just before render
void fixup_shader_constants(LLGLSLShader& shader)
{
// Sunlight intensity of 0 no matter what
shader.uniform1i(LLShaderMgr::SUN_UP_FACTOR, 1);
shader.uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, 1, LLColor3::white.mV);
shader.uniform1f(LLShaderMgr::DENSITY_MULTIPLIER, 0.0f);
// Ignore sun shadow (if enabled)
for (U32 i = 0; i < 6; i++)
{
const S32 channel = shader.getTextureChannel(LLShaderMgr::DEFERRED_SHADOW0+i);
if (channel != -1)
{
gGL.getTexUnit(channel)->bind(LLViewerFetchedTexture::sWhiteImagep, TRUE);
}
}
}
// Set a variable to a value temporarily, and restor the variable's old value
// when this object leaves scope.
template<typename T>
struct SetTemporarily
{
T* mRef;
T mOldVal;
SetTemporarily(T* var, T temp_val)
{
mRef = var;
mOldVal = *mRef;
*mRef = temp_val;
}
~SetTemporarily()
{
*mRef = mOldVal;
}
};
}; // namespace
BOOL LLGLTFPreviewTexture::render()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
if (!mShouldRender) { return FALSE; }
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
LLGLDepthTest(GL_FALSE);
LLGLDisable stencil(GL_STENCIL_TEST);
LLGLDisable scissor(GL_SCISSOR_TEST);
SetTemporarily<bool> no_dof(&LLPipeline::RenderDepthOfField, false);
SetTemporarily<bool> no_glow(&LLPipeline::sRenderGlow, false);
SetTemporarily<bool> no_ssr(&LLPipeline::RenderScreenSpaceReflections, false);
SetTemporarily<U32> no_fxaa(&LLPipeline::RenderFSAASamples, U32(0));
SetTemporarily<LLPipeline::RenderTargetPack*> use_auxiliary_render_target(&gPipeline.mRT, &gPipeline.mAuxillaryRT);
LLVector3 light_dir3(1.0f, 1.0f, 1.0f);
light_dir3.normalize();
const LLVector4 light_dir = LLVector4(light_dir3, 0);
const S32 old_local_light_count = gSavedSettings.get<S32>("RenderLocalLightCount");
gSavedSettings.set<S32>("RenderLocalLightCount", 0);
gPipeline.mReflectionMapManager.forceDefaultProbeAndUpdateUniforms();
LLViewerCamera camera;
// Calculate the object distance at which the object of a given radius will
// span the partial width of the screen given by fill_ratio.
// Assume the primitive has a scale of 1 (this is the default).
constexpr F32 fill_ratio = 0.8f;
constexpr F32 object_radius = 0.5f;
const F32 object_distance = (object_radius / fill_ratio) * tan(camera.getDefaultFOV());
// Negative coordinate shows the textures on the sphere right-side up, when
// combined with the UV hacks in create_preview_sphere
const LLVector3 object_position(0.0, -object_distance, 0.0);
LLMatrix4 object_transform;
object_transform.translate(object_position);
// Set up camera and viewport
const LLVector3 origin(0.0, 0.0, 0.0);
camera.lookAt(origin, object_position);
camera.setAspect(mFullHeight / mFullWidth);
const LLRect texture_rect(0, mFullHeight, mFullWidth, 0);
camera.setPerspective(NOT_FOR_SELECTION, texture_rect.mLeft, texture_rect.mBottom, texture_rect.getWidth(), texture_rect.getHeight(), FALSE, camera.getNear(), MAX_FAR_CLIP*2.f);
// Generate sphere object on-the-fly. Discard afterwards. (Vertex buffer is
// discarded, but the sphere should be cached in LLVolumeMgr.)
PreviewSphere& preview_sphere = get_preview_sphere(mGLTFMaterial, object_transform);
gPipeline.setupHWLights();
glh::matrix4f mat = copy_matrix(gGLModelView);
glh::vec4f transformed_light_dir(light_dir.mV);
mat.mult_matrix_vec(transformed_light_dir);
SetTemporarily<LLVector4> force_sun_direction_high_graphics(&gPipeline.mTransformedSunDir, LLVector4(transformed_light_dir.v));
// Override lights to ensure the sun is always shining from a certain direction (low graphics)
// See also force_sun_direction_high_graphics and fixup_shader_constants
{
LLLightState* light = gGL.getLight(0);
light->setPosition(light_dir);
constexpr bool sun_up = true;
light->setSunPrimary(sun_up);
}
LLRenderTarget& screen = gPipeline.mAuxillaryRT.screen;
// *HACK: Force reset of the model matrix
gGLLastMatrix = nullptr;
#if 0
if (mGLTFMaterial->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_OPAQUE || mGLTFMaterial->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_MASK)
{
// *TODO: Opaque/alpha mask rendering
}
else
#endif
{
// Alpha blend rendering
screen.bindTarget();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
LLGLSLShader& shader = gDeferredPBRAlphaProgram;
gPipeline.bindDeferredShader(shader);
fixup_shader_constants(shader);
for (PreviewSpherePart& part : preview_sphere)
{
LLRenderPass::pushGLTFBatch(*part->mDrawInfo);
}
gPipeline.unbindDeferredShader(shader);
screen.flush();
}
gPipeline.copyScreenSpaceReflections(&screen, &gPipeline.mSceneMap);
gPipeline.generateLuminance(&screen, &gPipeline.mLuminanceMap);
gPipeline.generateExposure(&gPipeline.mLuminanceMap, &gPipeline.mExposureMap);
gPipeline.gammaCorrect(&screen, &gPipeline.mPostMap);
LLVertexBuffer::unbind();
gPipeline.generateGlow(&gPipeline.mPostMap);
gPipeline.combineGlow(&gPipeline.mPostMap, &screen);
gPipeline.renderDoF(&screen, &gPipeline.mPostMap);
gPipeline.applyFXAA(&gPipeline.mPostMap, &screen);
// Final render
gDeferredPostNoDoFProgram.bind();
// From LLPipeline::renderFinalize: "Whatever is last in the above post processing chain should _always_ be rendered directly here. If not, expect problems."
gDeferredPostNoDoFProgram.bindTexture(LLShaderMgr::DEFERRED_DIFFUSE, &screen);
gDeferredPostNoDoFProgram.bindTexture(LLShaderMgr::DEFERRED_DEPTH, mBoundTarget, true);
{
LLGLDepthTest depth_test(GL_TRUE, GL_TRUE, GL_ALWAYS);
gPipeline.mScreenTriangleVB->setBuffer();
gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
}
gDeferredPostNoDoFProgram.unbind();
// Clean up
gPipeline.setupHWLights();
gPipeline.mReflectionMapManager.forceDefaultProbeAndUpdateUniforms(false);
gSavedSettings.set<S32>("RenderLocalLightCount", old_local_light_count);
return TRUE;
}
void LLGLTFPreviewTexture::postRender(BOOL success)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
if (!mShouldRender) { return; }
mShouldRender = false;
LLViewerDynamicTexture::postRender(success);
}
LLPointer<LLViewerTexture> LLGLTFMaterialPreviewMgr::getPreview(LLPointer<LLFetchedGLTFMaterial> &material)
{
if (!material)
{
return nullptr;
}
static LLCachedControl<bool> sUIPreviewMaterial(gSavedSettings, "UIPreviewMaterial", false);
if (!sUIPreviewMaterial)
{
fetch_texture_for_ui(material->mBaseColorTexture, material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR]);
return material->mBaseColorTexture;
}
if (!is_material_loaded_enough_for_ui(*material))
{
return nullptr;
}
return LLGLTFPreviewTexture::create(material);
}

View File

@ -0,0 +1,82 @@
/**
* @file llgltfmaterialpreviewmgr.h
*
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2023, 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$
*/
#pragma once
#include "lldrawpool.h"
#include "lldynamictexture.h"
#include "llfetchedgltfmaterial.h"
#include "llsingleton.h"
#include "lltexture.h"
class LLGLTFPreviewTexture : public LLViewerDynamicTexture
{
protected:
LLGLTFPreviewTexture(LLPointer<LLFetchedGLTFMaterial> material, S32 width);
public:
// Width scales with size of material's textures
static LLPointer<LLGLTFPreviewTexture> create(LLPointer<LLFetchedGLTFMaterial> material);
BOOL needsRender() override { return mNeedsRender; }
void preRender(BOOL clear_depth = TRUE) override;
BOOL render() override;
void postRender(BOOL success) override;
struct MaterialLoadLevels
{
S32 levels[LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT];
MaterialLoadLevels();
S32& operator[](size_t i);
const S32& operator[](size_t i) const;
// Less is better
// Returns false if lhs is not strictly less or equal for all levels
bool operator<(const MaterialLoadLevels& other) const;
// Less is better
// Returns false if lhs is not strictly greater or equal for all levels
bool operator>(const MaterialLoadLevels& other) const;
};
private:
LLPointer<LLFetchedGLTFMaterial> mGLTFMaterial;
bool mNeedsRender = true;
bool mShouldRender = true;
MaterialLoadLevels mBestLoad;
};
class LLGLTFMaterialPreviewMgr
{
public:
// Returns null if the material is not loaded yet.
// *NOTE: User should cache the texture if the same material is being previewed
LLPointer<LLViewerTexture> getPreview(LLPointer<LLFetchedGLTFMaterial> &material);
};
extern LLGLTFMaterialPreviewMgr gGLTFMaterialPreviewMgr;

View File

@ -0,0 +1,559 @@
/**
* @file LLHeroProbeManager.cpp
* @brief LLHeroProbeManager class implementation
*
* $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$
*/
#include "llviewerprecompiledheaders.h"
#include "llheroprobemanager.h"
#include "llreflectionmapmanager.h"
#include "llviewercamera.h"
#include "llspatialpartition.h"
#include "llviewerregion.h"
#include "pipeline.h"
#include "llviewershadermgr.h"
#include "llviewercontrol.h"
#include "llenvironment.h"
#include "llstartup.h"
#include "llagent.h"
#include "llagentcamera.h"
#include "llviewerwindow.h"
#include "llviewerjoystick.h"
#include "llviewermediafocus.h"
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)
{
if (LLViewerCamera::getInstance())
{
LLVector3 origin = LLViewerCamera::getInstance()->getOrigin();
origin.mV[2] += 64.f;
probe->mOrigin.load3(origin.mV);
}
}
LLHeroProbeManager::LLHeroProbeManager()
{
}
// helper class to seed octree with probes
void LLHeroProbeManager::update()
{
if (!LLPipeline::RenderMirrors || gTeleportDisplay || LLStartUp::getStartupState() < STATE_PRECACHE)
{
return;
}
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
llassert(!gCubeSnapshot); // assert a snapshot is not in progress
if (LLAppViewer::instance()->logoutRequestSent())
{
return;
}
initReflectionMaps();
if (!mRenderTarget.isComplete())
{
U32 color_fmt = GL_RGBA16F;
U32 targetRes = mProbeResolution; // super sample
mRenderTarget.allocate(targetRes, targetRes, color_fmt, true);
}
if (mMipChain.empty())
{
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);
res /= 2;
}
}
llassert(mProbes[0] == mDefaultProbe);
LLVector4a probe_pos;
LLVector3 camera_pos = LLViewerCamera::instance().mOrigin;
F32 near_clip = 0.1f;
if (mHeroVOList.size() > 0)
{
// Find our nearest hero candidate.
float last_distance = 99999.f;
for (auto vo : mHeroVOList)
{
if (vo && !vo->isDead())
{
if (vo->mDrawable.notNull())
{
if (vo->mDrawable->mDistanceWRTCamera < last_distance)
{
mNearestHero = vo;
last_distance = vo->mDrawable->mDistanceWRTCamera;
}
}
else
{
// Valid drawables only please. Unregister this one.
unregisterViewerObject(vo);
}
}
else
{
unregisterViewerObject(vo);
}
}
if (mNearestHero != nullptr && !mNearestHero->isDead() && mNearestHero->mDrawable.notNull())
{
LLVector3 hero_pos = mNearestHero->getPositionAgent();
LLVector3 face_normal = LLVector3(0, 0, 1);
face_normal *= mNearestHero->mDrawable->getXform()->getWorldRotation();
face_normal.normalize();
LLVector3 offset = camera_pos - hero_pos;
LLVector3 project = face_normal * (offset * face_normal);
LLVector3 reject = offset - project;
LLVector3 point = (reject - project) + hero_pos;
mCurrentClipPlane.setVec(hero_pos, face_normal);
mMirrorPosition = hero_pos;
mMirrorNormal = face_normal;
probe_pos.load3(point.mV);
}
else
{
mNearestHero = nullptr;
}
mHeroProbeStrength = 1;
}
else
{
probe_pos.load3(camera_pos.mV);
}
static LLCachedControl<S32> sDetail(gSavedSettings, "RenderHeroReflectionProbeDetail", -1);
static LLCachedControl<S32> sLevel(gSavedSettings, "RenderHeroReflectionProbeLevel", 3);
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("hpmu - realtime");
// Probe 0 is always our mirror probe.
mProbes[0]->mOrigin = probe_pos;
bool radiance_pass = gPipeline.mReflectionMapManager.isRadiancePass();
gPipeline.mReflectionMapManager.mRadiancePass = true;
mRenderingMirror = true;
for (U32 j = 0; j < mProbes.size(); j++)
{
for (U32 i = 0; i < 6; ++i)
{
updateProbeFace(mProbes[j], i, near_clip);
}
}
mRenderingMirror = false;
gPipeline.mReflectionMapManager.mRadiancePass = radiance_pass;
}
}
// 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 LLHeroProbeManager::updateProbeFace(LLReflectionMap* probe, U32 face, F32 near_clip)
{
// hacky hot-swap of camera specific render targets
gPipeline.mRT = &gPipeline.mHeroProbeRT;
probe->update(mRenderTarget.getWidth(), face, true, near_clip);
gPipeline.mRT = &gPipeline.mMainRT;
S32 sourceIdx = mReflectionProbeCount;
// Unlike the reflectionmap manager, all probes are considered "realtime" for hero probes.
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
{
gGL.matrixMode(gGL.MM_MODELVIEW);
gGL.pushMatrix();
gGL.loadIdentity();
gGL.matrixMode(gGL.MM_PROJECTION);
gGL.pushMatrix();
gGL.loadIdentity();
gGL.flush();
U32 res = mProbeResolution * 2;
static LLStaticHashedString resScale("resScale");
static LLStaticHashedString direction("direction");
static LLStaticHashedString znear("znear");
static LLStaticHashedString zfar("zfar");
LLRenderTarget *screen_rt = &gPipeline.mHeroProbeRT.screen;
LLRenderTarget *depth_rt = &gPipeline.mHeroProbeRT.deferredScreen;
// perform a gaussian blur on the super sampled render before downsampling
{
gGaussianProgram.bind();
gGaussianProgram.uniform1f(resScale, 1.f / (mProbeResolution * 2));
S32 diffuseChannel = gGaussianProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_TEXTURE);
// horizontal
gGaussianProgram.uniform2f(direction, 1.f, 0.f);
gGL.getTexUnit(diffuseChannel)->bind(screen_rt);
mRenderTarget.bindTarget();
gPipeline.mScreenTriangleVB->setBuffer();
gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
mRenderTarget.flush();
// vertical
gGaussianProgram.uniform2f(direction, 0.f, 1.f);
gGL.getTexUnit(diffuseChannel)->bind(&mRenderTarget);
screen_rt->bindTarget();
gPipeline.mScreenTriangleVB->setBuffer();
gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
screen_rt->flush();
gGaussianProgram.unbind();
}
S32 mips = log2((F32)mProbeResolution) + 0.5f;
gReflectionMipProgram.bind();
S32 diffuseChannel = gReflectionMipProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_TEXTURE);
S32 depthChannel = gReflectionMipProgram.enableTexture(LLShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_TEXTURE);
for (int i = 0; i < mMipChain.size(); ++i)
{
LL_PROFILE_GPU_ZONE("probe mip");
mMipChain[i].bindTarget();
if (i == 0)
{
gGL.getTexUnit(diffuseChannel)->bind(screen_rt);
}
else
{
gGL.getTexUnit(diffuseChannel)->bind(&(mMipChain[i - 1]));
}
gGL.getTexUnit(depthChannel)->bind(depth_rt, true);
gReflectionMipProgram.uniform1f(resScale, 1.f / (mProbeResolution * 2));
gReflectionMipProgram.uniform1f(znear, probe->getNearClip());
gReflectionMipProgram.uniform1f(zfar, MAX_FAR_CLIP);
gPipeline.mScreenTriangleVB->setBuffer();
gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
res /= 2;
S32 mip = i - (mMipChain.size() - mips);
if (mip >= 0)
{
LL_PROFILE_GPU_ZONE("probe mip copy");
mTexture->bind(0);
glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, 0, 0, sourceIdx * 6 + face, 0, 0, res, res);
mTexture->unbind();
}
mMipChain[i].flush();
}
gGL.popMatrix();
gGL.matrixMode(gGL.MM_MODELVIEW);
gGL.popMatrix();
gGL.getTexUnit(diffuseChannel)->unbind(LLTexUnit::TT_TEXTURE);
gReflectionMipProgram.unbind();
}
if (face == 5)
{
mMipChain[0].bindTarget();
static LLStaticHashedString sSourceIdx("sourceIdx");
{
//generate radiance map (even if this is not the irradiance map, we need the mip chain for the irradiance map)
gHeroRadianceGenProgram.bind();
mVertexBuffer->setBuffer();
S32 channel = gHeroRadianceGenProgram.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY);
mTexture->bind(channel);
gHeroRadianceGenProgram.uniform1i(sSourceIdx, sourceIdx);
gHeroRadianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_MAX_LOD, mMaxProbeLOD);
gHeroRadianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_STRENGTH, mHeroProbeStrength);
U32 res = mMipChain[0].getWidth();
for (int i = 0; i < mMipChain.size(); ++i)
{
LL_PROFILE_GPU_ZONE("probe radiance gen");
static LLStaticHashedString sMipLevel("mipLevel");
static LLStaticHashedString sRoughness("roughness");
static LLStaticHashedString sWidth("u_width");
static LLStaticHashedString sStrength("probe_strength");
gHeroRadianceGenProgram.uniform1f(sRoughness, (F32) i / (F32) (mMipChain.size() - 1));
gHeroRadianceGenProgram.uniform1f(sMipLevel, i);
gHeroRadianceGenProgram.uniform1i(sWidth, mProbeResolution);
gHeroRadianceGenProgram.uniform1f(sStrength, 1);
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);
}
}
gHeroRadianceGenProgram.unbind();
}
mMipChain[0].flush();
}
}
void LLHeroProbeManager::updateUniforms()
{
if (!LLPipeline::sReflectionProbesEnabled)
{
return;
}
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
struct HeroProbeData
{
LLVector4 heroPosition[1];
GLint heroProbeCount = 1;
};
HeroProbeData hpd;
LLMatrix4a modelview;
modelview.loadu(gGLModelView);
LLVector4a oa; // scratch space for transformed origin
oa.set(0, 0, 0, 0);
hpd.heroProbeCount = 1;
modelview.affineTransform(mProbes[0]->mOrigin, oa);
hpd.heroPosition[0].set(oa.getF32ptr());
//copy rpd into uniform buffer object
if (mUBO == 0)
{
glGenBuffers(1, &mUBO);
}
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmsu - update buffer");
glBindBuffer(GL_UNIFORM_BUFFER, mUBO);
glBufferData(GL_UNIFORM_BUFFER, sizeof(HeroProbeData), &hpd, GL_STREAM_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
}
void LLHeroProbeManager::setUniforms()
{
if (!LLPipeline::sReflectionProbesEnabled)
{
return;
}
if (mUBO == 0)
{
updateUniforms();
}
glBindBufferBase(GL_UNIFORM_BUFFER, 1, mUBO);
}
void LLHeroProbeManager::renderDebug()
{
gDebugProgram.bind();
for (auto& probe : mProbes)
{
renderReflectionProbe(probe);
}
gDebugProgram.unbind();
}
void LLHeroProbeManager::initReflectionMaps()
{
U32 count = LL_MAX_HERO_PROBE_COUNT;
if (mTexture.isNull() || mReflectionProbeCount != count || mReset)
{
mReset = false;
mReflectionProbeCount = count;
mProbeResolution = gSavedSettings.getS32("RenderHeroProbeResolution");
mMaxProbeLOD = log2f(mProbeResolution) - 1.f; // number of mips - 1
mTexture = new LLCubeMapArray();
// store mReflectionProbeCount+2 cube maps, final two cube maps are used for render target and radiance map generation source)
mTexture->allocate(mProbeResolution, 3, mReflectionProbeCount + 2);
if (mDefaultProbe.isNull())
{
llassert(mProbes.empty()); // default probe MUST be the first probe created
mDefaultProbe = new LLReflectionMap();
mProbes.push_back(mDefaultProbe);
}
llassert(mProbes[0] == mDefaultProbe);
// For hero probes, we treat this as the main mirror probe.
mDefaultProbe->mCubeIndex = 0;
mDefaultProbe->mCubeArray = mTexture;
mDefaultProbe->mDistance = gSavedSettings.getF32("RenderHeroProbeDistance");
mDefaultProbe->mRadius = 4096.f;
mDefaultProbe->mProbeIndex = 0;
touch_default_probe(mDefaultProbe);
mProbes.push_back(mDefaultProbe);
}
if (mVertexBuffer.isNull())
{
U32 mask = LLVertexBuffer::MAP_VERTEX;
LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(mask);
buff->allocateBuffer(4, 0);
LLStrider<LLVector3> v;
buff->getVertexStrider(v);
v[0] = LLVector3(-1, -1, -1);
v[1] = LLVector3(1, -1, -1);
v[2] = LLVector3(-1, 1, -1);
v[3] = LLVector3(1, 1, -1);
buff->unmapBuffer();
mVertexBuffer = buff;
}
}
void LLHeroProbeManager::cleanup()
{
mVertexBuffer = nullptr;
mRenderTarget.release();
mHeroRenderTarget.release();
mMipChain.clear();
mTexture = nullptr;
mProbes.clear();
mReflectionMaps.clear();
mDefaultProbe = nullptr;
mUpdatingProbe = nullptr;
glDeleteBuffers(1, &mUBO);
mUBO = 0;
mHeroVOList.clear();
mNearestHero = nullptr;
}
void LLHeroProbeManager::doOcclusion()
{
LLVector4a eye;
eye.load3(LLViewerCamera::instance().getOrigin().mV);
for (auto& probe : mProbes)
{
if (probe != nullptr && probe != mDefaultProbe)
{
probe->doOcclusion(eye);
}
}
}
void LLHeroProbeManager::registerViewerObject(LLVOVolume* drawablep)
{
llassert(drawablep != nullptr);
if (mHeroVOList.find(drawablep) == mHeroVOList.end())
{
// Probe isn't in our list for consideration. Add it.
mHeroVOList.insert(drawablep);
}
}
void LLHeroProbeManager::unregisterViewerObject(LLVOVolume* drawablep)
{
if (mHeroVOList.find(drawablep) != mHeroVOList.end())
{
mHeroVOList.erase(drawablep);
}
}

View File

@ -0,0 +1,141 @@
/**
* @file llheroprobemanager.h
* @brief LLHeroProbeManager class declaration
*
* $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$
*/
#pragma once
#include "llreflectionmap.h"
#include "llrendertarget.h"
#include "llcubemaparray.h"
#include "llcubemap.h"
#include "lldrawable.h"
class LLSpatialGroup;
class LLViewerObject;
// number of reflection probes to keep in vram
#define LL_MAX_HERO_PROBE_COUNT 2
class alignas(16) LLHeroProbeManager
{
LL_ALIGN_NEW
public:
enum class DetailLevel
{
STATIC_ONLY = 0,
STATIC_AND_DYNAMIC,
REALTIME = 2
};
// allocate an environment map of the given resolution
LLHeroProbeManager();
// release any GL state
void cleanup();
// maintain reflection probes
void update();
// debug display, called from llspatialpartition if reflection
// probe debug display is active
void renderDebug();
// call once at startup to allocate cubemap arrays
void initReflectionMaps();
// perform occlusion culling on all active reflection probes
void doOcclusion();
void registerViewerObject(LLVOVolume *drawablep);
void unregisterViewerObject(LLVOVolume* drawablep);
bool isMirrorPass() const { return mRenderingMirror; }
LLVector3 mMirrorPosition;
LLVector3 mMirrorNormal;
private:
friend class LLPipeline;
// update UBO used for rendering (call only once per render pipe flush)
void updateUniforms();
// bind UBO used for rendering
void setUniforms();
// render target for cube snapshots
// used to generate mipmaps without doing a copy-to-texture
LLRenderTarget mRenderTarget;
LLRenderTarget mHeroRenderTarget;
std::vector<LLRenderTarget> mMipChain;
// storage for reflection probe radiance maps (plus two scratch space cubemaps)
LLPointer<LLCubeMapArray> mTexture;
// vertex buffer for pushing verts to filter shaders
LLPointer<LLVertexBuffer> mVertexBuffer;
LLPlane mCurrentClipPlane;
// update the specified face of the specified probe
void updateProbeFace(LLReflectionMap* probe, U32 face, F32 near_clip);
// list of active reflection maps
std::vector<LLPointer<LLReflectionMap> > mProbes;
// handle to UBO
U32 mUBO = 0;
// list of maps being used for rendering
std::vector<LLReflectionMap*> mReflectionMaps;
LLReflectionMap* mUpdatingProbe = nullptr;
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
U32 mReflectionProbeCount;
// resolution of reflection probes
U32 mProbeResolution = 1024;
// maximum LoD of reflection probes (mip levels - 1)
F32 mMaxProbeLOD = 6.f;
F32 mHeroProbeStrength = 1.f;
bool mIsInTransition = false;
// if true, reset all probe render state on the next update (for teleports and sky changes)
bool mReset = false;
bool mRenderingMirror = false;
std::set<LLPointer<LLVOVolume>> mHeroVOList;
LLPointer<LLVOVolume> mNearestHero;
};

View File

@ -1870,7 +1870,7 @@ static void pack_textures(
if (normal_img)
{
// create a losslessly compressed version of the normal map
normal_j2c = LLViewerTextureList::convertToUploadFile(normal_img, 1024, false, true);
normal_j2c = LLViewerTextureList::convertToUploadFile(normal_img, 2048, false, true);
LL_DEBUGS("MaterialEditor") << "Normal: " << normal_j2c->getDataSize() << LL_ENDL;
}

View File

@ -1793,6 +1793,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
getChild<LLUICtrl>("shinyOffsetV")->setValue(offset_y);
getChild<LLUICtrl>("glossiness")->setValue(material->getSpecularLightExponent());
getChild<LLUICtrl>("environment")->setValue(material->getEnvironmentIntensity());
getChild<LLUICtrl>("mirror")->setValue(material->getEnvironmentIntensity());
updateShinyControls(!material->getSpecularID().isNull(), true);
}

View File

@ -145,6 +145,7 @@ protected:
void sendTexGen(); // applies and sends bump map
void sendShiny(U32 shininess); // applies and sends shininess
void sendFullbright(); // applies and sends full bright
void sendGlow();
void alignTestureLayer();
@ -234,7 +235,7 @@ protected:
static void onCommitShiny( LLUICtrl* ctrl, void* userdata);
static void onCommitAlphaMode( LLUICtrl* ctrl, void* userdata);
static void onCommitFullbright( LLUICtrl* ctrl, void* userdata);
static void onCommitGlow( LLUICtrl* ctrl, void *userdata);
static void onCommitGlow( LLUICtrl* ctrl, void *userdata);
static void onCommitPlanarAlign( LLUICtrl* ctrl, void* userdata);
static void onCommitRepeatsPerMeter( LLUICtrl* ctrl, void* userinfo);

View File

@ -150,7 +150,7 @@ BOOL LLPanelVolume::postBuild()
// REFLECTION PROBE Parameters
{
childSetCommitCallback("Reflection Probe", onCommitIsReflectionProbe, this);
childSetCommitCallback("Probe Dynamic", onCommitProbe, this);
childSetCommitCallback("Probe Update Type", onCommitProbe, this);
childSetCommitCallback("Probe Volume Type", onCommitProbe, this);
childSetCommitCallback("Probe Ambiance", onCommitProbe, this);
childSetCommitCallback("Probe Near Clip", onCommitProbe, this);
@ -304,7 +304,7 @@ void LLPanelVolume::getState( )
getChildView("select_single")->setVisible(true);
getChildView("select_single")->setEnabled(true);
}
// Light properties
BOOL is_light = volobjp && volobjp->getIsLight();
getChild<LLUICtrl>("Light Checkbox Ctrl")->setValue(is_light);
@ -392,17 +392,25 @@ void LLPanelVolume::getState( )
bool probe_enabled = is_probe && editable && single_volume;
bool mirrors_enabled = LLPipeline::RenderMirrors;
getChildView("Probe Update Type")->setVisible(mirrors_enabled);
getChildView("Probe Update Label")->setVisible(mirrors_enabled);
getChildView("Probe Dynamic")->setVisible(!mirrors_enabled);
getChildView("Probe Dynamic")->setEnabled(probe_enabled);
getChildView("Probe Update Type")->setEnabled(probe_enabled);
getChildView("Probe Volume Type")->setEnabled(probe_enabled);
getChildView("Probe Ambiance")->setEnabled(probe_enabled);
getChildView("Probe Near Clip")->setEnabled(probe_enabled);
getChildView("Probe Update Label")->setEnabled(probe_enabled);
if (!probe_enabled)
{
getChild<LLComboBox>("Probe Volume Type", true)->clear();
getChild<LLSpinCtrl>("Probe Ambiance", true)->clear();
getChild<LLSpinCtrl>("Probe Near Clip", true)->clear();
getChild<LLCheckBoxCtrl>("Probe Dynamic", true)->clear();
getChild<LLComboBox>("Probe Update Type", true)->clear();
}
else
{
@ -416,10 +424,28 @@ void LLPanelVolume::getState( )
volume_type = "Sphere";
}
std::string update_type;
if (volobjp->getReflectionProbeIsDynamic())
{
update_type = "Dynamic";
}
else if (volobjp->getReflectionProbeIsMirror())
{
update_type = "Mirror";
}
else
{
update_type = "Static";
}
getChildView("Probe Ambiance")->setEnabled(update_type != "Mirror");
getChildView("Probe Near Clip")->setEnabled(update_type != "Mirror");
getChild<LLComboBox>("Probe Volume Type", true)->setValue(volume_type);
getChild<LLSpinCtrl>("Probe Ambiance", true)->setValue(volobjp->getReflectionProbeAmbiance());
getChild<LLSpinCtrl>("Probe Near Clip", true)->setValue(volobjp->getReflectionProbeNearClip());
getChild<LLCheckBoxCtrl>("Probe Dynamic", true)->setValue(volobjp->getReflectionProbeIsDynamic());
getChild<LLComboBox>("Probe Update Type", true)->setValue(update_type);
}
// Animated Mesh
@ -706,7 +732,7 @@ void LLPanelVolume::clearCtrls()
getChildView("Reflection Probe")->setEnabled(false);;
getChildView("Probe Volume Type")->setEnabled(false);
getChildView("Probe Dynamic")->setEnabled(false);
getChildView("Probe Update Type")->setEnabled(false);
getChildView("Probe Ambiance")->setEnabled(false);
getChildView("Probe Near Clip")->setEnabled(false);
getChildView("Animated Mesh Checkbox Ctrl")->setEnabled(false);
@ -1399,7 +1425,14 @@ void LLPanelVolume::onCommitProbe(LLUICtrl* ctrl, void* userdata)
volobjp->setReflectionProbeAmbiance((F32)self->getChild<LLUICtrl>("Probe Ambiance")->getValue().asReal());
volobjp->setReflectionProbeNearClip((F32)self->getChild<LLUICtrl>("Probe Near Clip")->getValue().asReal());
volobjp->setReflectionProbeIsDynamic(self->getChild<LLUICtrl>("Probe Dynamic")->getValue().asBoolean());
std::string update_type = self->getChild<LLUICtrl>("Probe Update Type")->getValue().asString();
volobjp->setReflectionProbeIsDynamic(update_type == "Dynamic");
volobjp->setReflectionProbeIsMirror(update_type == "Mirror");
self->getChildView("Probe Ambiance")->setEnabled(update_type != "Mirror");
self->getChildView("Probe Near Clip")->setEnabled(update_type != "Mirror");
std::string shape_type = self->getChild<LLUICtrl>("Probe Volume Type")->getValue().asString();

View File

@ -57,7 +57,7 @@ public:
void refresh();
void sendIsLight();
// when an object is becoming a refleciton probe, present a dialog asking for confirmation
// otherwise, send the reflection probe update immediately
void sendIsReflectionProbe();

View File

@ -49,7 +49,7 @@ LLReflectionMap::~LLReflectionMap()
}
}
void LLReflectionMap::update(U32 resolution, U32 face)
void LLReflectionMap::update(U32 resolution, U32 face, bool force_dynamic, F32 near_clip, bool useClipPlane, LLPlane clipPlane)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
mLastUpdateTime = gFrameTimeSeconds;
@ -63,7 +63,10 @@ void LLReflectionMap::update(U32 resolution, U32 face)
{
resolution /= 2;
}
gViewerWindow->cubeSnapshot(LLVector3(mOrigin), mCubeArray, mCubeIndex, face, getNearClip(), getIsDynamic());
F32 clip = (near_clip > 0) ? near_clip : getNearClip();
gViewerWindow->cubeSnapshot(LLVector3(mOrigin), mCubeArray, mCubeIndex, face, clip, getIsDynamic() || force_dynamic, useClipPlane, clipPlane);
}
void LLReflectionMap::autoAdjustOrigin()

View File

@ -36,6 +36,15 @@ class alignas(16) LLReflectionMap : public LLRefCount
{
LL_ALIGN_NEW
public:
enum class ProbeType
{
ALL = 0,
RADIANCE,
IRRADIANCE,
REFLECTION
};
// allocate an environment map of the given resolution
LLReflectionMap();
@ -43,7 +52,7 @@ public:
// update this environment map
// resolution - size of cube map to generate
void update(U32 resolution, U32 face);
void update(U32 resolution, U32 face, bool force_dynamic = false, F32 near_clip = -1.f, bool useClipPlane = false, LLPlane clipPlane = LLPlane(LLVector3(0, 0, 0), LLVector3(0, 0, 1)));
// for volume partition probes, try to place this probe in the best spot
void autoAdjustOrigin();
@ -127,5 +136,7 @@ public:
GLuint mOcclusionQuery = 0;
bool mOccluded = false;
U32 mOcclusionPendingFrames = 0;
ProbeType mType;
};

View File

@ -27,6 +27,9 @@
#include "llviewerprecompiledheaders.h"
#include "llreflectionmapmanager.h"
#include <vector>
#include "llviewercamera.h"
#include "llspatialpartition.h"
#include "llviewerregion.h"
@ -306,8 +309,8 @@ void LLReflectionMapManager::update()
}
}
if (realtime &&
closestDynamic == nullptr &&
if (realtime &&
closestDynamic == nullptr &&
probe->mCubeIndex != -1 &&
probe->getIsDynamic())
{
@ -322,7 +325,7 @@ void LLReflectionMapManager::update()
// should do a full irradiance pass on "odd" frames and a radiance pass on "even" frames
closestDynamic->autoAdjustOrigin();
// store and override the value of "isRadiancePass" -- parts of the render pipe rely on "isRadiancePass" to set
// store and override the value of "isRadiancePass" -- parts of the render pipe rely on "isRadiancePass" to set
// lighting values etc
bool radiance_pass = isRadiancePass();
mRadiancePass = mRealtimeRadiancePass;
@ -573,7 +576,7 @@ void LLReflectionMapManager::doProbeUpdate()
// 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
// 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.
@ -734,6 +737,7 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face)
mTexture->bind(channel);
gRadianceGenProgram.uniform1i(sSourceIdx, sourceIdx);
gRadianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_MAX_LOD, mMaxProbeLOD);
gRadianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_STRENGTH, 1.f);
U32 res = mMipChain[0].getWidth();
@ -898,14 +902,14 @@ void LLReflectionMapManager::updateUniforms()
// see class3/deferred/reflectionProbeF.glsl
struct ReflectionProbeData
{
// for box probes, matrix that transforms from camera space to a [-1, 1] cube representing the bounding box of
// 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];
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];
LLVector4 refSphere[LL_MAX_REFLECTION_PROBE_COUNT];
// extra parameters
// extra parameters
// x - irradiance scale
// y - radiance scale
// z - fade in
@ -917,14 +921,14 @@ void LLReflectionMapManager::updateUniforms()
// [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];
GLint refIndex[LL_MAX_REFLECTION_PROBE_COUNT][4];
// list of neighbor indices
GLint refNeighbor[4096];
GLint refNeighbor[4096];
GLint refBucket[256][4]; //lookup table for which index to start with for the given Z depth
// numbrer of active refmaps
GLint refmapCount;
GLint refmapCount;
};
mReflectionMaps.resize(mReflectionProbeCount);
@ -1152,7 +1156,7 @@ void LLReflectionMapManager::setUniforms()
}
if (mUBO == 0)
{
{
updateUniforms();
}
glBindBufferBase(GL_UNIFORM_BUFFER, 1, mUBO);
@ -1343,8 +1347,8 @@ void LLReflectionMapManager::initReflectionMaps()
}
}
void LLReflectionMapManager::cleanup()
{
void LLReflectionMapManager::cleanup()
{
mVertexBuffer = nullptr;
mRenderTarget.release();
@ -1383,3 +1387,39 @@ void LLReflectionMapManager::doOcclusion()
}
}
}
void LLReflectionMapManager::forceDefaultProbeAndUpdateUniforms(bool force)
{
static std::vector<bool> mProbeWasOccluded;
if (force)
{
llassert(mProbeWasOccluded.empty());
for (size_t i = 0; i < mProbes.size(); ++i)
{
auto& probe = mProbes[i];
mProbeWasOccluded.push_back(probe->mOccluded);
if (probe != nullptr && probe != mDefaultProbe)
{
probe->mOccluded = true;
}
}
updateUniforms();
}
else
{
llassert(mProbes.size() == mProbeWasOccluded.size());
const size_t n = llmin(mProbes.size(), mProbeWasOccluded.size());
for (size_t i = 0; i < n; ++i)
{
auto& probe = mProbes[i];
llassert(probe->mOccluded == (probe != mDefaultProbe));
probe->mOccluded = mProbeWasOccluded[i];
}
mProbeWasOccluded.clear();
mProbeWasOccluded.shrink_to_fit();
}
}

View File

@ -43,21 +43,23 @@ class LLViewerObject;
// reflection probe mininum scale
#define LL_REFLECTION_PROBE_MINIMUM_SCALE 1.f;
void renderReflectionProbe(LLReflectionMap* probe);
class alignas(16) LLReflectionMapManager
{
LL_ALIGN_NEW
public:
enum class DetailLevel
enum class DetailLevel
{
STATIC_ONLY = 0,
STATIC_AND_DYNAMIC,
REALTIME = 2
};
// allocate an environment map of the given resolution
// allocate an environment map of the given resolution
LLReflectionMapManager();
// release any GL state
// release any GL state
void cleanup();
// maintain reflection probes
@ -106,8 +108,14 @@ public:
// perform occlusion culling on all active reflection probes
void doOcclusion();
// *HACK: "cull" all reflection probes except the default one. Only call
// this if you don't intend to call updateUniforms directly. Call again
// with false when done.
void forceDefaultProbeAndUpdateUniforms(bool force = true);
private:
friend class LLPipeline;
friend class LLHeroProbeManager;
// initialize mCubeFree array to default values
void initCubeFree();
@ -119,7 +127,7 @@ private:
// returns -1 if allocation failed
S32 allocateCubeIndex();
// update the neighbors of the given probe
// update the neighbors of the given probe
void updateNeighbors(LLReflectionMap* probe);
// update UBO used for rendering (call only once per render pipe flush)

View File

@ -718,11 +718,11 @@ void LLSettingsVOSky::applySpecial(void *ptarget, bool force)
LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
// TODO -- make these getters return vec3s
LLVector3 sunDiffuse = LLVector3(psky->getSunlightColor().mV);
LLVector3 moonDiffuse = LLVector3(psky->getMoonlightColor().mV);
LLVector3 sun_light_color = LLVector3(psky->getSunlightColor().mV);
LLVector3 moon_light_color = LLVector3(psky->getMoonlightColor().mV);
shader->uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, sunDiffuse);
shader->uniform3fv(LLShaderMgr::MOONLIGHT_COLOR, moonDiffuse);
shader->uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, sun_light_color);
shader->uniform3fv(LLShaderMgr::MOONLIGHT_COLOR, moon_light_color);
shader->uniform3fv(LLShaderMgr::CLOUD_COLOR, LLVector3(psky->getCloudColor().mV));
@ -765,9 +765,9 @@ void LLSettingsVOSky::applySpecial(void *ptarget, bool force)
shader->uniform1f(LLShaderMgr::SKY_HDR_SCALE, auto_adjust_hdr_scale);
LLColor3 blue_horizon = getBlueHorizon() * auto_adjust_blue_horizon_scale;
LLColor3 blue_density = getBlueDensity() * auto_adjust_blue_density_scale;
LLColor3 sun_diffuse = getSunDiffuse() * auto_adjust_sun_color_scale;
sun_light_color = sun_light_color * auto_adjust_sun_color_scale;
shader->uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, sun_diffuse.mV);
shader->uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, sun_light_color.mV);
shader->uniform3fv(LLShaderMgr::BLUE_DENSITY, blue_density.mV);
shader->uniform3fv(LLShaderMgr::BLUE_HORIZON, blue_horizon.mV);
@ -1009,6 +1009,7 @@ void LLSettingsVOWater::applySpecial(void *ptarget, bool force)
glh::matrix4f mat(modelView);
glh::matrix4f invtrans = mat.inverse().transpose();
invtrans.m[3] = invtrans.m[7] = invtrans.m[11] = 0.f;
glh::vec3f enorm;
glh::vec3f ep;
invtrans.mult_matrix_vec(norm, enorm);
@ -1017,12 +1018,29 @@ void LLSettingsVOWater::applySpecial(void *ptarget, bool force)
LLVector4 waterPlane(enorm.v[0], enorm.v[1], enorm.v[2], -ep.dot(enorm));
norm = glh::vec3f(gPipeline.mHeroProbeManager.mMirrorNormal.mV);
p = glh::vec3f(gPipeline.mHeroProbeManager.mMirrorPosition.mV);
invtrans.mult_matrix_vec(norm, enorm);
enorm.normalize();
mat.mult_matrix_vec(p, ep);
LLVector4 mirrorPlane(enorm.v[0], enorm.v[1], enorm.v[2], -ep.dot(enorm));
LLDrawPoolAlpha::sWaterPlane = waterPlane;
shader->uniform4fv(LLShaderMgr::WATER_WATERPLANE, waterPlane.mV);
shader->uniform4fv(LLShaderMgr::CLIP_PLANE, mirrorPlane.mV);
LLVector4 light_direction = env.getClampedLightNorm();
if (gPipeline.mHeroProbeManager.isMirrorPass())
{
shader->uniform1f(LLShaderMgr::MIRROR_FLAG, 1);
}
else
{
shader->uniform1f(LLShaderMgr::MIRROR_FLAG, 0);
}
F32 waterFogKS = 1.f / llmax(light_direction.mV[2], WATER_FOG_LIGHT_CLAMP);
shader->uniform1f(LLShaderMgr::WATER_FOGKS, waterFogKS);

View File

@ -47,6 +47,7 @@
#include "pipeline.h"
#include "llmeshrepository.h"
#include "llrender.h"
#include "lldrawpool.h"
#include "lloctree.h"
#include "llphysicsshapebuilderutil.h"
#include "llvoavatar.h"
@ -2000,7 +2001,11 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
drawBoxOutline(pos,size);
}
}
// *TODO: LLDrawables which are not part of LLVOVolumes fall into a different
// code path which uses a shader - it was tested to be faster than mapping a
// vertex buffer in the terrain case. Consider using it for LLVOVolumes as well
// to simplify and speed up this debug code. Alternatively, a compute shader is
// likely faster. -Cosmic,2023-09-28
void renderNormals(LLDrawable *drawablep)
{
if (!drawablep->isVisible())
@ -2008,11 +2013,13 @@ void renderNormals(LLDrawable *drawablep)
LLVertexBuffer::unbind();
LLViewerObject* obj = drawablep->getVObj();
LLVOVolume *vol = drawablep->getVOVolume();
if (vol)
if (obj)
{
LLVolume *volume = vol->getVolume();
LLGLEnable blend(GL_BLEND);
LLGLDepthTest gl_depth(GL_TRUE, GL_FALSE);
// Drawable's normals & tangents are stored in model space, i.e. before any scaling is applied.
//
@ -2021,68 +2028,136 @@ void renderNormals(LLDrawable *drawablep)
// transform. We get that effect here by pre-applying the inverse scale (twice, because
// one forward scale will be re-applied via the MVP in the vertex shader)
LLVector3 scale_v3 = vol->getScale();
float scale_len = scale_v3.length();
LLVector4a obj_scale(scale_v3.mV[VX], scale_v3.mV[VY], scale_v3.mV[VZ]);
obj_scale.normalize3();
LLVector4a inv_scale;
float scale_len;
if (vol)
{
LLVector3 scale_v3 = vol->getScale();
LLVector4a obj_scale(scale_v3.mV[VX], scale_v3.mV[VY], scale_v3.mV[VZ]);
obj_scale.normalize3();
// Create inverse-scale vector for normals
inv_scale.set(1.0 / scale_v3.mV[VX], 1.0 / scale_v3.mV[VY], 1.0 / scale_v3.mV[VZ], 0.0);
inv_scale.mul(inv_scale); // Squared, to apply inverse scale twice
inv_scale.normalize3fast();
scale_len = scale_v3.length();
}
else
{
inv_scale.set(1.0, 1.0, 1.0, 0.0);
scale_len = 1.0;
}
gGL.pushMatrix();
if (vol)
{
gGL.multMatrix((F32 *) vol->getRelativeXform().mMatrix);
}
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
// Normals &tangent line segments get scaled along with the object. Divide by scale length
// to keep the as-viewed lengths (relatively) constant with the debug setting length
float draw_length = gSavedSettings.getF32("RenderDebugNormalScale") / scale_len;
// Create inverse-scale vector for normals
LLVector4a inv_scale(1.0 / scale_v3.mV[VX], 1.0 / scale_v3.mV[VY], 1.0 / scale_v3.mV[VZ]);
inv_scale.mul(inv_scale); // Squared, to apply inverse scale twice
inv_scale.normalize3fast();
gGL.pushMatrix();
gGL.multMatrix((F32 *) vol->getRelativeXform().mMatrix);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
std::vector<LLVolumeFace>* faces = nullptr;
std::vector<LLFace*>* drawable_faces = nullptr;
if (vol)
{
const LLVolumeFace &face = volume->getVolumeFace(i);
gGL.flush();
gGL.diffuseColor4f(1, 1, 0, 1);
gGL.begin(LLRender::LINES);
for (S32 j = 0; j < face.mNumVertices; ++j)
{
LLVector4a n, p;
n.setMul(face.mNormals[j], 1.0);
n.mul(inv_scale); // Pre-scale normal, so it's left with an inverse-transpose xform after MVP
n.normalize3fast();
n.mul(draw_length);
p.setAdd(face.mPositions[j], n);
gGL.vertex3fv(face.mPositions[j].getF32ptr());
gGL.vertex3fv(p.getF32ptr());
}
gGL.end();
// Tangents are simple vectors and do not require reorientation via pre-scaling
if (face.mTangents)
{
gGL.flush();
gGL.diffuseColor4f(0, 1, 1, 1);
gGL.begin(LLRender::LINES);
for (S32 j = 0; j < face.mNumVertices; ++j)
{
LLVector4a t, p;
t.setMul(face.mTangents[j], 1.0f);
t.normalize3fast();
t.mul(draw_length);
p.setAdd(face.mPositions[j], t);
gGL.vertex3fv(face.mPositions[j].getF32ptr());
gGL.vertex3fv(p.getF32ptr());
}
gGL.end();
}
LLVolume* volume = vol->getVolume();
faces = &volume->getVolumeFaces();
}
else
{
drawable_faces = &drawablep->getFaces();
}
if (faces)
{
for (auto it = faces->begin(); it != faces->end(); ++it)
{
const LLVolumeFace& face = *it;
gGL.flush();
gGL.diffuseColor4f(1, 1, 0, 1);
gGL.begin(LLRender::LINES);
for (S32 j = 0; j < face.mNumVertices; ++j)
{
LLVector4a n, p;
n.setMul(face.mNormals[j], 1.0);
n.mul(inv_scale); // Pre-scale normal, so it's left with an inverse-transpose xform after MVP
n.normalize3fast();
n.mul(draw_length);
p.setAdd(face.mPositions[j], n);
gGL.vertex3fv(face.mPositions[j].getF32ptr());
gGL.vertex3fv(p.getF32ptr());
}
gGL.end();
// Tangents are simple vectors and do not require reorientation via pre-scaling
if (face.mTangents)
{
gGL.flush();
gGL.diffuseColor4f(0, 1, 1, 1);
gGL.begin(LLRender::LINES);
for (S32 j = 0; j < face.mNumVertices; ++j)
{
LLVector4a t, p;
t.setMul(face.mTangents[j], 1.0f);
t.normalize3fast();
t.mul(draw_length);
p.setAdd(face.mPositions[j], t);
gGL.vertex3fv(face.mPositions[j].getF32ptr());
gGL.vertex3fv(p.getF32ptr());
}
gGL.end();
}
}
}
else if (drawable_faces)
{
// *HACK: Prepare to restore previous shader as other debug code depends on a simpler shader being present
llassert(LLGLSLShader::sCurBoundShaderPtr == &gDebugProgram);
LLGLSLShader* prev_shader = LLGLSLShader::sCurBoundShaderPtr;
for (auto it = drawable_faces->begin(); it != drawable_faces->end(); ++it)
{
LLFace* facep = *it;
LLFace& face = **it;
LLVertexBuffer* buf = face.getVertexBuffer();
if (!buf) { continue; }
U32 mask_vn = LLVertexBuffer::TYPE_VERTEX | LLVertexBuffer::TYPE_NORMAL;
if ((buf->getTypeMask() & mask_vn) != mask_vn) { continue; }
LLGLSLShader* shader;
if ((buf->getTypeMask() & LLVertexBuffer::TYPE_TANGENT) != LLVertexBuffer::TYPE_TANGENT)
{
shader = &gNormalDebugProgram[NORMAL_DEBUG_SHADER_DEFAULT];
}
else
{
shader = &gNormalDebugProgram[NORMAL_DEBUG_SHADER_WITH_TANGENTS];
}
shader->bind();
shader->uniform1f(LLShaderMgr::DEBUG_NORMAL_DRAW_LENGTH, draw_length);
LLRenderPass::applyModelMatrix(&facep->getDrawable()->getRegion()->mRenderMatrix);
buf->setBuffer();
// *NOTE: The render type in the vertex shader is TRIANGLES, but gets converted to LINES in the geometry shader
// *NOTE: For terrain normal debug, this seems to also include vertices for water, which is technically not part of the terrain. Should fix that at some point.
buf->drawRange(LLRender::TRIANGLES, face.getGeomIndex(), face.getGeomIndex() + face.getGeomCount()-1, face.getIndicesCount(), face.getIndicesStart());
}
if (prev_shader)
{
prev_shader->bind();
}
}
gGL.popMatrix();
}

View File

@ -643,17 +643,18 @@ void LLSurface::updatePatchVisibilities(LLAgent &agent)
}
}
BOOL LLSurface::idleUpdate(F32 max_update_time)
template<bool PBR>
bool LLSurface::idleUpdate(F32 max_update_time)
{
if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_TERRAIN))
{
return FALSE;
return false;
}
// Perform idle time update of non-critical stuff.
// In this case, texture and normal updates.
LLTimer update_timer;
BOOL did_update = FALSE;
bool did_update = false;
// If the Z height data has changed, we need to rebuild our
// property line vertex arrays.
@ -669,13 +670,13 @@ BOOL LLSurface::idleUpdate(F32 max_update_time)
{
std::set<LLSurfacePatch *>::iterator curiter = iter++;
LLSurfacePatch *patchp = *curiter;
patchp->updateNormals();
patchp->updateNormals<PBR>();
patchp->updateVerticalStats();
if (max_update_time == 0.f || update_timer.getElapsedTimeF32() < max_update_time)
{
if (patchp->updateTexture())
{
did_update = TRUE;
did_update = true;
patchp->clearDirty();
mDirtyPatchList.erase(curiter);
}
@ -691,6 +692,9 @@ BOOL LLSurface::idleUpdate(F32 max_update_time)
return did_update;
}
template bool LLSurface::idleUpdate</*PBR=*/false>(F32 max_update_time);
template bool LLSurface::idleUpdate</*PBR=*/true>(F32 max_update_time);
void LLSurface::decompressDCTPatch(LLBitPack &bitpack, LLGroupHeader *gopp, BOOL b_large_patch)
{

View File

@ -112,7 +112,8 @@ public:
LLSurfacePatch *resolvePatchGlobal(const LLVector3d &position_global) const;
// Update methods (called during idle, normally)
BOOL idleUpdate(F32 max_update_time);
template<bool PBR>
bool idleUpdate(F32 max_update_time);
BOOL containsPosition(const LLVector3 &position);
@ -224,6 +225,9 @@ private:
static S32 sTextureSize; // Size of the surface texture
};
extern template bool LLSurface::idleUpdate</*PBR=*/false>(F32 max_update_time);
extern template bool LLSurface::idleUpdate</*PBR=*/true>(F32 max_update_time);
// . __.

View File

@ -221,7 +221,9 @@ void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3
*vertex = pos_agent-mVObjp->getRegion()->getOriginAgent();
LLVector3 rel_pos = pos_agent - mSurfacep->getOriginAgent();
LLVector3 tex_pos = rel_pos * (1.f/surface_stride);
// *NOTE: Only PBR terrain uses the UVs right now. Texture terrain just ignores it.
// *NOTE: In the future, UVs and horizontal position will no longer have a 1:1 relationship for PBR terrain
LLVector3 tex_pos = rel_pos;
tex0->mV[0] = tex_pos.mV[0];
tex0->mV[1] = tex_pos.mV[1];
tex1->mV[0] = mSurfacep->getRegion()->getCompositionXY(llfloor(mOriginRegion.mV[0])+x, llfloor(mOriginRegion.mV[1])+y);
@ -241,7 +243,8 @@ void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3
}
void LLSurfacePatch::calcNormal(const U32 x, const U32 y, const U32 stride)
template<>
void LLSurfacePatch::calcNormal</*PBR=*/false>(const U32 x, const U32 y, const U32 stride)
{
U32 patch_width = mSurfacep->mPVArray.mPatchWidth;
U32 surface_stride = mSurfacep->getGridsPerEdge();
@ -354,6 +357,166 @@ void LLSurfacePatch::calcNormal(const U32 x, const U32 y, const U32 stride)
*(mDataNorm + surface_stride * y + x) = normal;
}
template<>
void LLSurfacePatch::calcNormal</*PBR=*/true>(const U32 x, const U32 y, const U32 stride)
{
llassert(mDataNorm);
constexpr U32 index = 0;
const U32 surface_stride = mSurfacep->getGridsPerEdge();
LLVector3& normal_out = *(mDataNorm + surface_stride * y + x);
calcNormalFlat(normal_out, x, y, index);
}
// Calculate the flat normal of a triangle whose least coordinate is specified by the given x,y values.
// If index = 0, calculate the normal of the first triangle, otherwise calculate the normal of the second.
void LLSurfacePatch::calcNormalFlat(LLVector3& normal_out, const U32 x, const U32 y, const U32 index)
{
llassert(index == 0 || index == 1);
U32 patch_width = mSurfacep->mPVArray.mPatchWidth;
U32 surface_stride = mSurfacep->getGridsPerEdge();
// Vertex stride is always 1 because we want the flat surface of the current triangle face
constexpr U32 stride = 1;
const F32 mpg = mSurfacep->getMetersPerGrid() * stride;
S32 poffsets[2][2][2];
poffsets[0][0][0] = x;
poffsets[0][0][1] = y;
poffsets[0][1][0] = x;
poffsets[0][1][1] = y + stride;
poffsets[1][0][0] = x + stride;
poffsets[1][0][1] = y;
poffsets[1][1][0] = x + stride;
poffsets[1][1][1] = y + stride;
const LLSurfacePatch *ppatches[2][2];
// LLVector3 p1, p2, p3, p4;
ppatches[0][0] = this;
ppatches[0][1] = this;
ppatches[1][0] = this;
ppatches[1][1] = this;
U32 i, j;
for (i = 0; i < 2; i++)
{
for (j = 0; j < 2; j++)
{
if (poffsets[i][j][0] < 0)
{
if (!ppatches[i][j]->getNeighborPatch(WEST))
{
poffsets[i][j][0] = 0;
}
else
{
poffsets[i][j][0] += patch_width;
ppatches[i][j] = ppatches[i][j]->getNeighborPatch(WEST);
}
}
if (poffsets[i][j][1] < 0)
{
if (!ppatches[i][j]->getNeighborPatch(SOUTH))
{
poffsets[i][j][1] = 0;
}
else
{
poffsets[i][j][1] += patch_width;
ppatches[i][j] = ppatches[i][j]->getNeighborPatch(SOUTH);
}
}
if (poffsets[i][j][0] >= (S32)patch_width)
{
if (!ppatches[i][j]->getNeighborPatch(EAST))
{
poffsets[i][j][0] = patch_width - 1;
}
else
{
poffsets[i][j][0] -= patch_width;
ppatches[i][j] = ppatches[i][j]->getNeighborPatch(EAST);
}
}
if (poffsets[i][j][1] >= (S32)patch_width)
{
if (!ppatches[i][j]->getNeighborPatch(NORTH))
{
poffsets[i][j][1] = patch_width - 1;
}
else
{
poffsets[i][j][1] -= patch_width;
ppatches[i][j] = ppatches[i][j]->getNeighborPatch(NORTH);
}
}
}
}
LLVector3 p00(-mpg,-mpg,
*(ppatches[0][0]->mDataZ
+ poffsets[0][0][0]
+ poffsets[0][0][1]*surface_stride));
LLVector3 p01(-mpg,+mpg,
*(ppatches[0][1]->mDataZ
+ poffsets[0][1][0]
+ poffsets[0][1][1]*surface_stride));
LLVector3 p10(+mpg,-mpg,
*(ppatches[1][0]->mDataZ
+ poffsets[1][0][0]
+ poffsets[1][0][1]*surface_stride));
LLVector3 p11(+mpg,+mpg,
*(ppatches[1][1]->mDataZ
+ poffsets[1][1][0]
+ poffsets[1][1][1]*surface_stride));
// Triangle index / coordinate convention
// for a single surface patch
//
// p01 p11
//
// ^ ._____.
// | |\ |
// | | \ 1 |
// | | \ |
// | 0 \ |
// y |____\|
//
// p00 x ---> p10
//
// (z up / out of the screen due to right-handed coordinate system)
LLVector3 normal;
if (index == 0)
{
LLVector3 c1 = p10 - p00;
LLVector3 c2 = p01 - p00;
normal = c1;
normal %= c2;
normal.normVec();
}
else // index == 1
{
LLVector3 c1 = p11 - p01;
LLVector3 c2 = p11 - p10;
normal = c1;
normal %= c2;
normal.normVec();
}
llassert(&normal_out);
normal_out = normal;
}
const LLVector3 &LLSurfacePatch::getNormal(const U32 x, const U32 y) const
{
U32 surface_stride = mSurfacep->getGridsPerEdge();
@ -451,6 +614,7 @@ void LLSurfacePatch::updateVerticalStats()
}
template<bool PBR>
void LLSurfacePatch::updateNormals()
{
if (mSurfacep->mType == 'w')
@ -468,9 +632,9 @@ void LLSurfacePatch::updateNormals()
{
for (j = 0; j <= grids_per_patch_edge; j++)
{
calcNormal(grids_per_patch_edge, j, 2);
calcNormal(grids_per_patch_edge - 1, j, 2);
calcNormal(grids_per_patch_edge - 2, j, 2);
calcNormal<PBR>(grids_per_patch_edge, j, 2);
calcNormal<PBR>(grids_per_patch_edge - 1, j, 2);
calcNormal<PBR>(grids_per_patch_edge - 2, j, 2);
}
dirty_patch = TRUE;
@ -481,9 +645,9 @@ void LLSurfacePatch::updateNormals()
{
for (i = 0; i <= grids_per_patch_edge; i++)
{
calcNormal(i, grids_per_patch_edge, 2);
calcNormal(i, grids_per_patch_edge - 1, 2);
calcNormal(i, grids_per_patch_edge - 2, 2);
calcNormal<PBR>(i, grids_per_patch_edge, 2);
calcNormal<PBR>(i, grids_per_patch_edge - 1, 2);
calcNormal<PBR>(i, grids_per_patch_edge - 2, 2);
}
dirty_patch = TRUE;
@ -494,8 +658,8 @@ void LLSurfacePatch::updateNormals()
{
for (j = 0; j < grids_per_patch_edge; j++)
{
calcNormal(0, j, 2);
calcNormal(1, j, 2);
calcNormal<PBR>(0, j, 2);
calcNormal<PBR>(1, j, 2);
}
dirty_patch = TRUE;
}
@ -505,8 +669,8 @@ void LLSurfacePatch::updateNormals()
{
for (i = 0; i < grids_per_patch_edge; i++)
{
calcNormal(i, 0, 2);
calcNormal(i, 1, 2);
calcNormal<PBR>(i, 0, 2);
calcNormal<PBR>(i, 1, 2);
}
dirty_patch = TRUE;
}
@ -582,10 +746,10 @@ void LLSurfacePatch::updateNormals()
// We've got a northeast patch in the same surface.
// The z and normals will be handled by that patch.
}
calcNormal(grids_per_patch_edge, grids_per_patch_edge, 2);
calcNormal(grids_per_patch_edge, grids_per_patch_edge - 1, 2);
calcNormal(grids_per_patch_edge - 1, grids_per_patch_edge, 2);
calcNormal(grids_per_patch_edge - 1, grids_per_patch_edge - 1, 2);
calcNormal<PBR>(grids_per_patch_edge, grids_per_patch_edge, 2);
calcNormal<PBR>(grids_per_patch_edge, grids_per_patch_edge - 1, 2);
calcNormal<PBR>(grids_per_patch_edge - 1, grids_per_patch_edge, 2);
calcNormal<PBR>(grids_per_patch_edge - 1, grids_per_patch_edge - 1, 2);
dirty_patch = TRUE;
}
@ -596,7 +760,7 @@ void LLSurfacePatch::updateNormals()
{
for (i=2; i < grids_per_patch_edge - 2; i++)
{
calcNormal(i, j, 2);
calcNormal<PBR>(i, j, 2);
}
}
dirty_patch = TRUE;
@ -613,6 +777,9 @@ void LLSurfacePatch::updateNormals()
}
}
template void LLSurfacePatch::updateNormals</*PBR=*/false>();
template void LLSurfacePatch::updateNormals</*PBR=*/true>();
void LLSurfacePatch::updateEastEdge()
{
U32 grids_per_patch_edge = mSurfacep->getGridsPerPatchEdge();
@ -739,7 +906,7 @@ void LLSurfacePatch::updateGL()
updateCompositionStats();
F32 tex_patch_size = meters_per_grid*grids_per_patch_edge;
if (comp->generateTexture((F32)origin_region[VX], (F32)origin_region[VY],
if (comp->generateMinimapTileLand((F32)origin_region[VX], (F32)origin_region[VY],
tex_patch_size, tex_patch_size))
{
mSTexUpdate = FALSE;

View File

@ -77,6 +77,7 @@ public:
void updateVerticalStats();
void updateCompositionStats();
template<bool PBR>
void updateNormals();
void updateEastEdge();
@ -102,9 +103,18 @@ public:
LLVector3 getPointAgent(const U32 x, const U32 y) const; // get the point at the offset.
LLVector2 getTexCoords(const U32 x, const U32 y) const;
// Per-vertex normals
// *TODO: PBR=true is a test implementation solely for proof-of-concept.
// Final implementation would likely be very different and may not even use
// this function. If we decide to keep calcNormalFlat, remove index as it
// is a debug parameter for testing.
template<bool PBR>
void calcNormal(const U32 x, const U32 y, const U32 stride);
const LLVector3 &getNormal(const U32 x, const U32 y) const;
// Per-triangle normals for flat edges
void calcNormalFlat(LLVector3& normal_out, const U32 x, const U32 y, const U32 index /* 0 or 1 */);
void eval(const U32 x, const U32 y, const U32 stride,
LLVector3 *vertex, LLVector3 *normal, LLVector2 *tex0, LLVector2 *tex1);
@ -181,5 +191,8 @@ protected:
LLSurface *mSurfacep; // Pointer to "parent" surface
};
extern template void LLSurfacePatch::updateNormals</*PBR=*/false>();
extern template void LLSurfacePatch::updateNormals</*PBR=*/true>();
#endif // LL_LLSURFACEPATCH_H

View File

@ -72,6 +72,7 @@
#include "llradiogroup.h"
#include "llfloaterreg.h"
#include "llgltfmaterialpreviewmgr.h"
#include "lllocalbitmaps.h"
#include "lllocalgltfmaterials.h"
#include "llerror.h"
@ -659,6 +660,7 @@ void LLFloaterTexturePicker::draw()
if( mOwner )
{
mTexturep = NULL;
LLPointer<LLFetchedGLTFMaterial> old_material = mGLTFMaterial;
mGLTFMaterial = NULL;
if (mImageAssetID.notNull())
{
@ -666,10 +668,27 @@ void LLFloaterTexturePicker::draw()
{
mGLTFMaterial = (LLFetchedGLTFMaterial*) gGLTFMaterialList.getMaterial(mImageAssetID);
llassert(mGLTFMaterial == nullptr || dynamic_cast<LLFetchedGLTFMaterial*>(gGLTFMaterialList.getMaterial(mImageAssetID)) != nullptr);
if (mGLTFPreview.isNull() || mGLTFMaterial.isNull() || (old_material.notNull() && (old_material.get() != mGLTFMaterial.get())))
{
// Only update the preview if needed, since gGLTFMaterialPreviewMgr does not cache the preview.
if (mGLTFMaterial.isNull())
{
mGLTFPreview = nullptr;
}
else
{
mGLTFPreview = gGLTFMaterialPreviewMgr.getPreview(mGLTFMaterial);
}
}
if (mGLTFPreview)
{
mGLTFPreview->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
}
}
else
{
LLPointer<LLViewerFetchedTexture> texture = NULL;
mGLTFPreview = nullptr;
if (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(mImageAssetID))
{
@ -679,7 +698,7 @@ void LLFloaterTexturePicker::draw()
if (obj)
{
LLViewerTexture* viewerTexture = obj->getBakedTextureForMagicId(mImageAssetID);
texture = viewerTexture ? dynamic_cast<LLViewerFetchedTexture*>(viewerTexture) : NULL;
texture = viewerTexture ? dynamic_cast<LLViewerFetchedTexture*>(viewerTexture) : NULL;
}
}
@ -720,27 +739,25 @@ void LLFloaterTexturePicker::draw()
// If the floater is focused, don't apply its alpha to the texture (STORM-677).
const F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
LLViewerTexture* texture = nullptr;
LLViewerTexture* preview;
if (mGLTFMaterial)
{
texture = mGLTFMaterial->getUITexture();
preview = mGLTFPreview.get();
}
else
{
texture = mTexturep.get();
preview = mTexturep.get();
}
if( texture )
if( preview )
{
if( texture->getComponents() == 4 )
preview->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) );
if( preview->getComponents() == 4 )
{
gl_rect_2d_checkerboard( interior, alpha );
}
gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), texture, UI_VERTEX_COLOR % alpha );
// Pump the priority
texture->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) );
gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), preview, UI_VERTEX_COLOR % alpha );
}
else if (!mFallbackImage.isNull())
{
@ -1639,7 +1656,7 @@ LLTextureCtrl::LLTextureCtrl(const LLTextureCtrl::Params& p)
mShowLoadingPlaceholder( TRUE ),
mOpenTexPreview(false),
mBakeTextureEnabled(true),
mInventoryPickType(PICK_TEXTURE),
mInventoryPickType(p.pick_type),
mImageAssetID(p.image_id),
mDefaultImageAssetID(p.default_image_id),
mDefaultImageName(p.default_image_name),
@ -2157,48 +2174,73 @@ void LLTextureCtrl::draw()
{
mBorder->setKeyboardFocusHighlight(hasFocus());
LLPointer<LLViewerTexture> preview = NULL;
if (!mValid)
{
mTexturep = NULL;
mGLTFMaterial = NULL;
mGLTFPreview = NULL;
}
else if (!mImageAssetID.isNull())
{
LLPointer<LLViewerFetchedTexture> texture = NULL;
if (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(mImageAssetID))
{
LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
if (obj)
{
LLViewerTexture* viewerTexture = obj->getBakedTextureForMagicId(mImageAssetID);
texture = viewerTexture ? dynamic_cast<LLViewerFetchedTexture*>(viewerTexture) : NULL;
mTexturep = viewerTexture ? dynamic_cast<LLViewerFetchedTexture*>(viewerTexture) : NULL;
mGLTFMaterial = NULL;
mGLTFPreview = NULL;
preview = mTexturep;
}
}
if (texture.isNull())
if (preview.isNull())
{
LLPointer<LLFetchedGLTFMaterial> old_material = mGLTFMaterial;
mGLTFMaterial = NULL;
mTexturep = NULL;
if (mInventoryPickType == PICK_MATERIAL)
{
LLPointer<LLFetchedGLTFMaterial> material = gGLTFMaterialList.getMaterial(mImageAssetID);
if (material)
mGLTFMaterial = gGLTFMaterialList.getMaterial(mImageAssetID);
if (mGLTFPreview.isNull() || mGLTFMaterial.isNull() || (old_material.notNull() && (old_material.get() != mGLTFMaterial.get())))
{
texture = material->getUITexture();
// Only update the preview if needed, since gGLTFMaterialPreviewMgr does not cache the preview.
if (mGLTFMaterial.isNull())
{
mGLTFPreview = nullptr;
}
else
{
mGLTFPreview = gGLTFMaterialPreviewMgr.getPreview(mGLTFMaterial);
}
}
if (mGLTFPreview)
{
mGLTFPreview->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
}
preview = mGLTFPreview;
}
else
{
texture = LLViewerTextureManager::getFetchedTexture(mImageAssetID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
texture->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
texture->forceToSaveRawImage(0);
mTexturep = LLViewerTextureManager::getFetchedTexture(mImageAssetID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
mTexturep->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
mTexturep->forceToSaveRawImage(0);
preview = mTexturep;
}
}
mTexturep = texture;
}
else//mImageAssetID == LLUUID::null
{
mTexturep = NULL;
mGLTFMaterial = NULL;
mGLTFPreview = NULL;
}
// Border
@ -2211,15 +2253,15 @@ void LLTextureCtrl::draw()
// If we're in a focused floater, don't apply the floater's alpha to the texture (STORM-677).
const F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
if( mTexturep )
if( preview )
{
if( mTexturep->getComponents() == 4 )
if( preview->getComponents() == 4 )
{
gl_rect_2d_checkerboard( interior, alpha );
}
gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), mTexturep, UI_VERTEX_COLOR % alpha);
mTexturep->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) );
gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), preview, UI_VERTEX_COLOR % alpha);
preview->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) );
}
else if (!mFallbackImage.isNull())
{
@ -2366,6 +2408,16 @@ LLSD LLTextureCtrl::getValue() const
return LLSD(getImageAssetID());
}
namespace LLInitParam
{
void TypeValues<EPickInventoryType>::declareValues()
{
declare("texture_material", PICK_TEXTURE_MATERIAL);
declare("texture", PICK_TEXTURE);
declare("material", PICK_MATERIAL);
}
}

View File

@ -64,13 +64,6 @@ bool get_is_predefined_texture(LLUUID asset_id);
LLUUID get_copy_free_item_by_asset_id(LLUUID image_id, bool no_trans_perm = false);
bool get_can_copy_texture(LLUUID image_id);
enum LLPickerSource
{
PICKER_INVENTORY,
PICKER_LOCAL,
PICKER_BAKE,
PICKER_UNKNOWN, // on cancel, default ids
};
typedef enum e_pick_inventory_type
{
@ -79,6 +72,23 @@ typedef enum e_pick_inventory_type
PICK_MATERIAL = 2,
} EPickInventoryType;
namespace LLInitParam
{
template<>
struct TypeValues<EPickInventoryType> : public TypeValuesHelper<EPickInventoryType>
{
static void declareValues();
};
}
enum LLPickerSource
{
PICKER_INVENTORY,
PICKER_LOCAL,
PICKER_BAKE,
PICKER_UNKNOWN, // on cancel, default ids
};
//////////////////////////////////////////////////////////////////////////////////////////
// LLTextureCtrl
@ -100,6 +110,7 @@ public:
Optional<LLUUID> image_id;
Optional<LLUUID> default_image_id;
Optional<std::string> default_image_name;
Optional<EPickInventoryType> pick_type;
Optional<bool> allow_no_texture;
Optional<bool> can_apply_immediately;
Optional<bool> no_commit_on_selection; // alternative mode: commit occurs and the widget gets dirty
@ -117,6 +128,7 @@ public:
: image_id("image"),
default_image_id("default_image_id"),
default_image_name("default_image_name"),
pick_type("pick_type", PICK_TEXTURE),
allow_no_texture("allow_no_texture", false),
can_apply_immediately("can_apply_immediately"),
no_commit_on_selection("no_commit_on_selection", false),
@ -250,6 +262,8 @@ private:
commit_callback_t mOnCloseCallback;
texture_selected_callback mOnTextureSelectedCallback;
LLPointer<LLViewerFetchedTexture> mTexturep;
LLPointer<LLFetchedGLTFMaterial> mGLTFMaterial;
LLPointer<LLViewerTexture> mGLTFPreview;
LLUIColor mBorderColor;
LLUUID mImageItemID;
LLUUID mImageAssetID;
@ -382,6 +396,7 @@ protected:
LLPointer<LLViewerTexture> mTexturep;
LLPointer<LLFetchedGLTFMaterial> mGLTFMaterial;
LLPointer<LLViewerTexture> mGLTFPreview;
LLView* mOwner;
LLUUID mImageAssetID; // Currently selected texture

View File

@ -764,6 +764,12 @@ BOOL LLViewerCamera::cameraUnderWater() const
{
LLViewerRegion* regionp = LLWorld::instance().getRegionFromPosAgent(getOrigin());
if (gPipeline.mHeroProbeManager.isMirrorPass())
{
// TODO: figure out how to handle this case
return FALSE;
}
if (!regionp)
{
regionp = gAgent.getRegion();

View File

@ -54,6 +54,7 @@
#include "llvotree.h"
#include "llvovolume.h"
#include "llworld.h"
#include "llvlcomposition.h"
#include "pipeline.h"
#include "llviewerjoystick.h"
#include "llviewerobjectlist.h"
@ -117,12 +118,25 @@ static bool handleRenderFarClipChanged(const LLSD& newvalue)
return false;
}
static bool handleTerrainDetailChanged(const LLSD& newvalue)
static bool handleTerrainScaleChanged(const LLSD& newvalue)
{
LLDrawPoolTerrain::sDetailMode = newvalue.asInteger();
F64 scale = newvalue.asReal();
if (scale != 0.0)
{
LLDrawPoolTerrain::sDetailScale = F32(1.0 / scale);
}
return true;
}
static bool handlePBRTerrainScaleChanged(const LLSD& newvalue)
{
F64 scale = newvalue.asReal();
if (scale != 0.0)
{
LLDrawPoolTerrain::sPBRDetailScale = F32(1.0 / scale);
}
return true;
}
static bool handleDebugAvatarJointsChanged(const LLSD& newvalue)
{
@ -650,6 +664,16 @@ void handleFPSTuningStrategyChanged(const LLSD& newValue)
const auto newval = gSavedSettings.getU32("TuningFPSStrategy");
LLPerfStats::tunables.userFPSTuningStrategy = newval;
}
void handleLocalTerrainChanged(const LLSD& newValue)
{
for (U32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i)
{
const auto setting = gSavedSettings.getString(std::string("LocalTerrainAsset") + std::to_string(i + 1));
const LLUUID materialID(setting);
gLocalTerrainMaterials.setDetailAssetID(i, materialID);
}
}
////////////////////////////////////////////////////////////////////////////
LLPointer<LLControlVariable> setting_get_control(LLControlGroup& group, const std::string& setting)
@ -684,7 +708,11 @@ void settings_setup_listeners()
{
setting_setup_signal_listener(gSavedSettings, "FirstPersonAvatarVisible", handleRenderAvatarMouselookChanged);
setting_setup_signal_listener(gSavedSettings, "RenderFarClip", handleRenderFarClipChanged);
setting_setup_signal_listener(gSavedSettings, "RenderTerrainDetail", handleTerrainDetailChanged);
setting_setup_signal_listener(gSavedSettings, "RenderTerrainScale", handleTerrainScaleChanged);
setting_setup_signal_listener(gSavedSettings, "RenderTerrainPBRScale", handlePBRTerrainScaleChanged);
setting_setup_signal_listener(gSavedSettings, "RenderTerrainPBRDetail", handleSetShaderChanged);
setting_setup_signal_listener(gSavedSettings, "RenderTerrainPBRPlanarSampleCount", handleSetShaderChanged);
setting_setup_signal_listener(gSavedSettings, "RenderTerrainPBRTriplanarBlendFactor", handleSetShaderChanged);
setting_setup_signal_listener(gSavedSettings, "OctreeStaticObjectSizeFactor", handleRepartition);
setting_setup_signal_listener(gSavedSettings, "OctreeDistanceFactor", handleRepartition);
setting_setup_signal_listener(gSavedSettings, "OctreeMaxNodeCapacity", handleRepartition);
@ -830,6 +858,10 @@ void settings_setup_listeners()
setting_setup_signal_listener(gSavedSettings, "AutoTuneImpostorFarAwayDistance", handleUserImpostorDistanceChanged);
setting_setup_signal_listener(gSavedSettings, "AutoTuneImpostorByDistEnabled", handleUserImpostorByDistEnabledChanged);
setting_setup_signal_listener(gSavedSettings, "TuningFPSStrategy", handleFPSTuningStrategyChanged);
setting_setup_signal_listener(gSavedSettings, "LocalTerrainAsset1", handleLocalTerrainChanged);
setting_setup_signal_listener(gSavedSettings, "LocalTerrainAsset2", handleLocalTerrainChanged);
setting_setup_signal_listener(gSavedSettings, "LocalTerrainAsset3", handleLocalTerrainChanged);
setting_setup_signal_listener(gSavedSettings, "LocalTerrainAsset4", handleLocalTerrainChanged);
setting_setup_signal_listener(gSavedPerAccountSettings, "AvatarHoverOffsetZ", handleAvatarHoverOffsetChanged);
}

View File

@ -656,6 +656,14 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
if (!gDisconnected)
{
// Render mirrors and associated hero probes before we render the rest of the scene.
// This ensures the scene state in the hero probes are exactly the same as the rest of the scene before we render it.
if (gPipeline.RenderMirrors && !gSnapshot)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Update hero probes");
gPipeline.mHeroProbeManager.update();
}
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 1");
LLAppViewer::instance()->pingMainloopTimeout("Display:Update");
if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
@ -696,7 +704,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
}
gPipeline.updateGL();
stop_glerror();
LLAppViewer::instance()->pingMainloopTimeout("Display:Cull");
@ -1064,7 +1072,7 @@ void display_cube_face()
LLSpatialGroup::sNoDelete = TRUE;
S32 occlusion = LLPipeline::sUseOcclusion;
LLPipeline::sUseOcclusion = 0; // occlusion data is from main camera point of view, don't read or write it during cube snapshots
LLPipeline::sUseOcclusion = 1; // occlusion data is from main camera point of view, don't read or write it during cube snapshots
//gDepthDirty = TRUE; //let "real" render pipe know it can't trust the depth buffer for occlusion data
static LLCullResult result;

View File

@ -2122,6 +2122,20 @@ class LLAdvancedPurgeShaderCache : public view_listener_t
}
};
/////////////////////
// REBUILD TERRAIN //
/////////////////////
class LLAdvancedRebuildTerrain : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
gPipeline.rebuildTerrain();
return true;
}
};
////////////////////
// EVENT Recorder //
///////////////////
@ -9492,6 +9506,10 @@ void initialize_menus()
view_listener_t::addMenu(new LLAdvancedClickRenderProfile(), "Advanced.ClickRenderProfile");
view_listener_t::addMenu(new LLAdvancedClickRenderBenchmark(), "Advanced.ClickRenderBenchmark");
view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache");
if (gSavedSettings.get<bool>("RenderTerrainPBREnabled"))
{
view_listener_t::addMenu(new LLAdvancedRebuildTerrain(), "Advanced.RebuildTerrain");
}
#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
view_listener_t::addMenu(new LLAdvancedHandleToggleHackedGodmode(), "Advanced.HandleToggleHackedGodmode");

Some files were not shown because too many files have changed in this diff Show More