diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 0683bf3548..b21c9b7d83 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -31,6 +31,7 @@ #include "llmath.h" #include "v4coloru.h" +#include "v3color.h" #include "llimagebmp.h" #include "llimagetga.h" @@ -1045,6 +1046,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 @@ -1130,7 +1159,7 @@ void LLImageRaw::composite( LLImageRaw* src ) } // These assertions are nonsense. - // llassert(3 == src->getComponents()); + // llassert((3 == src->getComponents()) || (4 == src->getComponents())); // llassert(3 == dst->getComponents()); // if( 3 == dst->getComponents() ) @@ -1310,6 +1339,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::duplicate() { if(getNumRefs() < 2) diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 7327334ec4..4f3f610160 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -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< 1. diff --git a/indra/llmath/llcamera.h b/indra/llmath/llcamera.h index c4d04f5d02..e1d3536f66 100644 --- a/indra/llmath/llcamera.h +++ b/indra/llmath/llcamera.h @@ -65,7 +65,6 @@ class LLCamera : public LLCoordFrame { public: - LLCamera(const LLCamera& rhs) { *this = rhs; diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index bfeb055599..a4ab5e8ded 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -6512,9 +6512,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; @@ -6532,7 +6529,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++) @@ -7242,7 +7239,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 diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index e39397613b..7c1757ddea 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -1157,6 +1157,8 @@ private: 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); diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index 43d095f73a..b18b56c59d 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -56,6 +56,7 @@ public: bool hasAlphaMask = false; bool hasReflectionProbes = false; bool attachNothing = false; + bool isPBRTerrain = false; // include: shaders\class1\deferred\pbrterrainUtilF.glsl }; // ============= Structure for caching shader uniforms =============== diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h index b1264c65a4..d05ac0c761 100644 --- a/indra/llrender/llgltexture.h +++ b/indra/llrender/llgltexture.h @@ -42,7 +42,7 @@ class LLGLTexture : public LLTexture public: enum { - MAX_IMAGE_SIZE_DEFAULT = 1024, + MAX_IMAGE_SIZE_DEFAULT = 2048, INVALID_DISCARD_LEVEL = 0x7fff }; diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index c107292193..81ebd9f1af 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -277,6 +277,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) { @@ -1392,8 +1400,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"); diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index ca62c84f36..bc11a3f154 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -264,8 +264,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" diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index d2cb979714..c488ce696f 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -1335,6 +1335,10 @@ bool LLVertexBuffer::getNormalStrider(LLStrider& strider, U32 index, { return VertexBufferStrider::get(*this, strider, index, count); } +bool LLVertexBuffer::getNormalStrider(LLStrider& strider, U32 index, S32 count) +{ + return VertexBufferStrider::get(*this, strider, index, count); +} bool LLVertexBuffer::getTangentStrider(LLStrider& strider, U32 index, S32 count) { return VertexBufferStrider::get(*this, strider, index, count); diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index cde5b7b794..4b6f1ad213 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -180,6 +180,7 @@ public: bool getTexCoord1Strider(LLStrider& strider, U32 index=0, S32 count = -1); bool getTexCoord2Strider(LLStrider& strider, U32 index=0, S32 count = -1); bool getNormalStrider(LLStrider& strider, U32 index=0, S32 count = -1); + bool getNormalStrider(LLStrider& strider, U32 index = 0, S32 count = -1); bool getTangentStrider(LLStrider& strider, U32 index=0, S32 count = -1); bool getTangentStrider(LLStrider& strider, U32 index=0, S32 count = -1); bool getColorStrider(LLStrider& strider, U32 index=0, S32 count = -1); @@ -191,10 +192,6 @@ public: bool getWeight4Strider(LLStrider& strider, U32 index=0, S32 count = -1); bool getClothWeightStrider(LLStrider& strider, U32 index=0, S32 count = -1); // - bool getBasecolorTexcoordStrider(LLStrider& strider, U32 index=0, S32 count = -1); - bool getNormalTexcoordStrider(LLStrider& strider, U32 index=0, S32 count = -1); - bool getMetallicRoughnessTexcoordStrider(LLStrider& strider, U32 index=0, S32 count = -1); - bool getEmissiveTexcoordStrider(LLStrider& strider, U32 index=0, S32 count = -1); void setPositionData(const LLVector4a* data); void setTexCoordData(const LLVector2* data); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index be2375d0b8..8e719cc145 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -423,6 +423,7 @@ set(viewer_SOURCE_FILES llgiveinventory.cpp llglsandbox.cpp llgltfmateriallist.cpp + llgltfmaterialpreviewmgr.cpp llgroupactions.cpp llgroupiconctrl.cpp llgrouplist.cpp @@ -1216,6 +1217,7 @@ set(viewer_HEADER_FILES llgesturemgr.h llgiveinventory.h llgltfmateriallist.h + llgltfmaterialpreviewmgr.h llgroupactions.h llgroupiconctrl.h llgrouplist.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 9331c7f350..d560d39b35 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -13787,7 +13787,7 @@ Change of this parameter will affect the layout of buttons in notification toast Type F32 Value - 2.0 + 1.0 RendeSkyAutoAdjustBlueHorizonScale @@ -13942,7 +13942,7 @@ Change of this parameter will affect the layout of buttons in notification toast RenderTerrainScale Comment - Terrain detail texture scale + Terrain detail texture scale (meters) Persist 1 Type @@ -13950,6 +13950,50 @@ Change of this parameter will affect the layout of buttons in notification toast Value 12.0 + RenderTerrainPBRDetail + + Comment + Detail level for PBR terrain. 0 is full detail. Negative values drop rendering features in accordance with the GLTF specification, which reduces the number of texture binds. Some Intel and Mac graphics drivers do not support more than 16 texture binds. Because PBR terrain exceeds this limit at the highest detail level, reducing texture binds is necessary for compatibility. + Persist + 1 + Type + S32 + Value + 0 + + RenderTerrainPBRScale + + Comment + PBR terrain detail texture scale (meters) + Persist + 1 + Type + F32 + Value + 4.0 + + RenderTerrainPBRPlanarSampleCount + + Comment + How many UV planes to sample PBR terrain textures from. 1 is "flat", 3 is triplanar mapping (aka box mapping) + Persist + 1 + Type + S32 + Value + 3 + + RenderTerrainPBRTriplanarBlendFactor + + Comment + Higher values create sharper transitions, but are more likely to produce artifacts. + Persist + 1 + Type + F32 + Value + 8.0 + FSATIFullTextureMem Comment @@ -19436,7 +19480,7 @@ Change of this parameter will affect the layout of buttons in notification toast Type S32 Value - 2048 + 1024 max_texture_dimension_Y @@ -19447,7 +19491,7 @@ Change of this parameter will affect the layout of buttons in notification toast Type S32 Value - 2048 + 1024 teleport_offer_invitation_max_length @@ -20985,6 +21029,50 @@ Change of this parameter will affect the layout of buttons in notification toast Boolean Value 0 + + LocalTerrainAsset1 + + Comment + 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. + Persist + 0 + Type + String + Value + 00000000-0000-0000-0000-000000000000 + + LocalTerrainAsset2 + + Comment + 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. + Persist + 0 + Type + String + Value + 00000000-0000-0000-0000-000000000000 + + LocalTerrainAsset3 + + Comment + 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. + Persist + 0 + Type + String + Value + 00000000-0000-0000-0000-000000000000 + + LocalTerrainAsset4 + + Comment + 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. + Persist + 0 + Type + String + Value + 00000000-0000-0000-0000-000000000000 PathfindingRetrieveNeighboringRegion diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl new file mode 100644 index 0000000000..db03e0885c --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl @@ -0,0 +1,272 @@ +/** + * @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 + +#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 + +// TODO: Decide if this struct needs to be declared +struct TerrainMix +{ + vec4 weight; + int type; +}; + +TerrainMix get_terrain_mix_weights(float alpha1, float alpha2, float alphaFinal); + +// TODO: Decide if this struct needs to be declared +struct PBRMix +{ + vec4 col; // RGB color with alpha, linear space + vec3 orm; // Occlusion, roughness, metallic + vec3 vNt; // Unpacked normal texture sample, vector +#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 + , sampler2D tex_orm + , sampler2D tex_vNt +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , sampler2D tex_emissive +#endif + , vec4 factor_col + , vec3 factor_orm +#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; + +// *TODO: More configurable quality level which disables PBR features on machines +// with limited texture availability +// 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; +uniform sampler2D detail_0_normal; +uniform sampler2D detail_1_normal; +uniform sampler2D detail_2_normal; +uniform sampler2D detail_3_normal; +uniform sampler2D detail_0_metallic_roughness; +uniform sampler2D detail_1_metallic_roughness; +uniform sampler2D detail_2_metallic_roughness; +uniform sampler2D detail_3_metallic_roughness; +#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 +uniform vec4 metallicFactors; +uniform vec4 roughnessFactors; +#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); + + // 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); + + 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 + , detail_0_metallic_roughness + , detail_0_normal +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , detail_0_emissive +#endif + , baseColorFactors[0] + , orm_factors[0] +#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 + , detail_1_metallic_roughness + , detail_1_normal +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , detail_1_emissive +#endif + , baseColorFactors[1] + , orm_factors[1] +#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 + , detail_2_metallic_roughness + , detail_2_normal +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , detail_2_emissive +#endif + , baseColorFactors[2] + , orm_factors[2] +#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 + , detail_3_metallic_roughness + , detail_3_normal +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , detail_3_emissive +#endif + , baseColorFactors[3] + , orm_factors[3] +#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)); + + // 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; + + +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) +#define emissive mix.emissive +#else +#define emissive vec3(0) +#endif + frag_data[0] = max(vec4(mix.col.xyz, 0.0), vec4(0)); // Diffuse + frag_data[1] = max(vec4(mix.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 +} + diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl new file mode 100644 index 0000000000..316b751590 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl @@ -0,0 +1,396 @@ +/** + * @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 + +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 + vec3 orm; // Occlusion, roughness, metallic + vec3 vNt; // Unpacked normal texture sample, vector +#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); + mix.orm = vec3(0); + mix.vNt = vec3(0); +#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); + mix.orm = mix1.orm + (mix2.orm * mix2_weight); + mix.vNt = mix1.vNt + (mix2.vNt * mix2_weight); +#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 + , sampler2D tex_orm + , sampler2D tex_vNt +#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); + mix.orm = texture(tex_orm, uv).xyz; + mix.vNt = texture(tex_vNt, uv).xyz*2.0-1.0; +#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 + , sampler2D tex_orm + , sampler2D tex_vNt +#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 + , tex_orm + , tex_vNt +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , tex_emissive +#endif + ); + // Triplanar-specific normal texture fix + mix_x.vNt = _t_normal_post_x(mix_x.vNt); + 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 + , tex_orm + , tex_vNt +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , tex_emissive +#endif + ); + // Triplanar-specific normal texture fix + mix_y.vNt = _t_normal_post_y(mix_y.vNt); + 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 + , tex_orm + , tex_vNt +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , tex_emissive +#endif + ); + // Triplanar-specific normal texture fix + // *NOTE: Bottom face has not been tested + mix_z.vNt = _t_normal_post_z(mix_z.vNt); + 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 + , vec3 factor_orm +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , vec3 factor_emissive +#endif + ) +{ + PBRMix mix = mix_in; + mix.col *= factor_col; + mix.orm *= factor_orm; +#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 + , sampler2D tex_orm + , sampler2D tex_vNt +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , sampler2D tex_emissive +#endif + , vec4 factor_col + , vec3 factor_orm +#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 + , tex_orm + , tex_vNt +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , tex_emissive +#endif + ); + + mix = multiply_factors_pbr(mix + , factor_col + , factor_orm +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , factor_emissive +#endif + ); + + return mix; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl new file mode 100644 index 0000000000..dbb9404219 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl @@ -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); +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl b/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl index f6d3b59e85..33a78fd26d 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl @@ -30,7 +30,6 @@ 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 +40,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() @@ -67,7 +64,7 @@ void main() 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); diff --git a/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl b/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl index 636dfed4ba..732333311c 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl @@ -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 diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt index 942b84fce9..109a57eb50 100644 --- a/indra/newview/featuretable.txt +++ b/indra/newview/featuretable.txt @@ -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,7 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 0 RenderTerrainDetail 1 0 RenderTerrainLODFactor 1 1 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTreeLODFactor 1 0 RenderVolumeLODFactor 1 1.5 RenderDeferredSSAO 1 0 @@ -123,6 +126,7 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 0 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 1.0 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 2.0 RenderDeferredSSAO 1 0 @@ -150,6 +154,7 @@ RenderLocalLightCount 1 512 RenderTransparentWater 1 0 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 2.0 RenderDeferredSSAO 1 0 @@ -179,6 +184,7 @@ RenderLocalLightCount 1 1024 RenderTransparentWater 1 1 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 2.0 RenderDeferredSSAO 1 0 @@ -208,6 +214,7 @@ RenderLocalLightCount 1 2048 RenderTransparentWater 1 1 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRPlanarSampleCount 1 3 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 2.0 RenderDeferredSSAO 1 1 @@ -236,6 +243,7 @@ RenderMaxPartCount 1 4096 RenderLocalLightCount 1 4096 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRPlanarSampleCount 1 3 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 2.0 @@ -264,6 +272,7 @@ RenderLocalLightCount 1 8192 RenderMaxPartCount 1 8192 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRPlanarSampleCount 1 3 RenderTransparentWater 1 1 RenderTreeLODFactor 1 1.0 RenderVolumeLODFactor 1 3.0 @@ -321,3 +330,5 @@ RenderFSAASamples 0 0 RenderReflectionsEnabled 0 0 RenderReflectionProbeDetail 0 0 +list TexUnit16orLess +RenderTerrainPBRDetail 1 -1 diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt index bebc96031d..ab4e240202 100644 --- a/indra/newview/featuretable_mac.txt +++ b/indra/newview/featuretable_mac.txt @@ -45,6 +45,7 @@ RenderObjectBump 1 1 RenderLocalLightCount 1 4096 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRPlanarSampleCount 1 3 RenderTransparentWater 1 1 RenderTreeLODFactor 1 1.0 RenderVBOEnable 1 1 @@ -89,6 +90,7 @@ RenderLocalLightCount 1 8 RenderMaxPartCount 1 256 RenderTerrainDetail 1 0 RenderTerrainLODFactor 1 1 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTransparentWater 1 0 RenderTreeLODFactor 1 0 RenderVolumeLODFactor 1 1.5 @@ -118,6 +120,7 @@ RenderMaxPartCount 1 2048 RenderLocalLightCount 1 256 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 1.0 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.5 @@ -147,6 +150,7 @@ RenderMaxPartCount 1 4096 RenderLocalLightCount 1 512 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.5 @@ -176,6 +180,7 @@ RenderMaxPartCount 1 4096 RenderLocalLightCount 1 1024 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 2.0 @@ -205,6 +210,7 @@ RenderMaxPartCount 1 4096 RenderLocalLightCount 1 2048 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRPlanarSampleCount 1 3 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 2.0 @@ -234,6 +240,7 @@ RenderMaxPartCount 1 4096 RenderLocalLightCount 1 4096 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRPlanarSampleCount 1 3 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 2.0 @@ -262,6 +269,7 @@ RenderLocalLightCount 1 8192 RenderMaxPartCount 1 8192 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRPlanarSampleCount 1 3 RenderTransparentWater 1 1 RenderTreeLODFactor 1 1.0 RenderVolumeLODFactor 1 3.0 @@ -308,6 +316,9 @@ RenderShadowDetail 0 0 list TexUnit8orLess RenderDeferredSSAO 0 0 +list TexUnit16orLess +RenderTerrainPBRDetail 1 -1 + list AMD RenderDeferredSSAO 1 0 diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 4e7bdc041f..1a28094974 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -245,6 +245,7 @@ #include "pipeline.h" #include "llgesturemgr.h" #include "llsky.h" +#include "llvlcomposition.h" #include "llvlmanager.h" #include "llviewercamera.h" #include "lldrawpoolbump.h" diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index 50210b06c4..556760632a 100644 --- a/indra/newview/lldrawpool.cpp +++ b/indra/newview/lldrawpool.cpp @@ -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)) diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h index 0925a01439..c69f386c6d 100644 --- a/indra/newview/lldrawpool.h +++ b/indra/newview/lldrawpool.h @@ -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); diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp index f04ce97522..4f31fb0942 100644 --- a/indra/newview/lldrawpoolterrain.cpp +++ b/indra/newview/lldrawpoolterrain.cpp @@ -54,8 +54,11 @@ const F32 DETAIL_SCALE = 1.f/16.f; int DebugDetailMap = 0; -S32 LLDrawPoolTerrain::sDetailMode = 1; +const S32 PBR_DETAIL_EMISSIVE = 0; + +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"); @@ -68,11 +71,14 @@ LLDrawPoolTerrain::LLDrawPoolTerrain(LLViewerTexture *texturep) : // Attempt to speed up things a little // sDetailScale = 1.f/gSavedSettings.getF32("RenderTerrainScale"); - // sDetailMode = gSavedSettings.getS32("RenderTerrainDetail"); + // sPBRDetailScale = 1.f/gSavedSettings.getF32("RenderTerrainPBRScale"); + // sPBRDetailMode = gSavedSettings.getS32("RenderTerrainPBRDetail"); static LLCachedControl RenderTerrainScale(gSavedSettings, "RenderTerrainScale"); - static LLCachedControl RenderTerrainDetail(gSavedSettings, "RenderTerrainDetail"); + static LLCachedControl RenderTerrainPBRScale(gSavedSettings, "RenderTerrainPBRScale"); + static LLCachedControl RenderTerrainPBRDetail(gSavedSettings, "RenderTerrainPBRDetail"); sDetailScale = 1.f/RenderTerrainScale; - sDetailMode = RenderTerrainDetail(); + sPBRDetailScale = 1.f/RenderTerrainPBRScale; + sPBRDetailMode = RenderTerrainPBRDetail(); // mAlphaRampImagep = LLViewerTextureManager::getFetchedTexture(IMG_ALPHA_GRAD); @@ -114,18 +120,12 @@ U32 LLDrawPoolTerrain::getVertexDataMask() void LLDrawPoolTerrain::prerender() { // Use faster LLCachedControls for frequently visited locations - //sDetailMode = gSavedSettings.getS32("RenderTerrainDetail"); - static LLCachedControl renderTerrainDetail(gSavedSettings, "RenderTerrainDetail"); - sDetailMode = renderTerrainDetail(); + //sPBRDetailMode = gSavedSettings.getS32("RenderTerrainPBRDetail"); + static LLCachedControl renderTerrainPBRDetail(gSavedSettings, "RenderTerrainPBRDetail"); + sPBRDetailMode = renderTerrainPBRDetail(); // } -//static -S32 LLDrawPoolTerrain::getDetailMode() -{ - return sDetailMode; -} - void LLDrawPoolTerrain::boostTerrainDetailTextures() { // Hack! Get the region that this draw pool is rendering from! @@ -133,8 +133,36 @@ 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& tex = compp->mDetailTextures[i]; + llassert(tex.notNull()); + tex->setBoostLevel(level); + tex->addTextureStats(stats); + + LLPointer& mat = compp->mDetailMaterials[i]; + llassert(mat.notNull()); + if (mat->mBaseColorTexture) + { + mat->mBaseColorTexture->setBoostLevel(level); + mat->mBaseColorTexture->addTextureStats(stats); + } + if (mat->mNormalTexture) + { + mat->mNormalTexture->setBoostLevel(level); + mat->mNormalTexture->addTextureStats(stats); + } + if (mat->mMetallicRoughnessTexture) + { + mat->mMetallicRoughnessTexture->setBoostLevel(level); + mat->mMetallicRoughnessTexture->addTextureStats(stats); + } + if (mat->mEmissiveTexture) + { + mat->mEmissiveTexture->setBoostLevel(level); + mat->mEmissiveTexture->addTextureStats(stats); + } } } @@ -142,10 +170,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) @@ -220,19 +244,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(); } @@ -241,9 +254,34 @@ void LLDrawPoolTerrain::drawLoop() void LLDrawPoolTerrain::renderFullShader() { + const BOOL use_local_materials = gLocalTerrainMaterials.materialsReady(TRUE); // 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(); + // [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) LLViewerTexture *detail_texture0p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[0] : LLViewerFetchedTexture::sDefaultDiffuseImagep; LLViewerTexture *detail_texture1p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[1] : LLViewerFetchedTexture::sDefaultDiffuseImagep; @@ -344,6 +382,197 @@ 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 (*materials)[LLVLComposition::ASSET_COUNT] = &compp->mDetailMaterials; + + if (local_materials) + { + // Override region terrain with the global local override terrain + materials = &gLocalTerrainMaterials.mDetailMaterials; + } + + constexpr U32 terrain_material_count = 1 + LLViewerShaderMgr::TERRAIN_DETAIL3_BASE_COLOR - LLViewerShaderMgr::TERRAIN_DETAIL0_BASE_COLOR; + 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) + { + const LLFetchedGLTFMaterial* material = (*materials)[i].get(); + + LLViewerTexture *detail_basecolor_texturep = material->mBaseColorTexture; + LLViewerTexture *detail_normal_texturep = material->mNormalTexture; + LLViewerTexture *detail_metalrough_texturep = material->mMetallicRoughnessTexture; + LLViewerTexture *detail_emissive_texturep = 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(); + + 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(); + + 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 >= 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 LLFetchedGLTFMaterial* material = (*materials)[i].get(); + + 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); + 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 >= 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); + sShader->disableTexture(LLViewerShaderMgr::TERRAIN_DETAIL0_NORMAL + i); + sShader->disableTexture(LLViewerShaderMgr::TERRAIN_DETAIL0_METALLIC_ROUGHNESS + i); + if (sPBRDetailMode >= 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(); + + gGL.getTexUnit(detail_normal[i])->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(detail_normal[i])->disable(); + gGL.getTexUnit(detail_normal[i])->activate(); + + gGL.getTexUnit(detail_metalrough[i])->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(detail_metalrough[i])->disable(); + gGL.getTexUnit(detail_metalrough[i])->activate(); + + if (sPBRDetailMode >= 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 diff --git a/indra/newview/lldrawpoolterrain.h b/indra/newview/lldrawpoolterrain.h index 03bef31541..13f031c8e7 100644 --- a/indra/newview/lldrawpoolterrain.h +++ b/indra/newview/lldrawpoolterrain.h @@ -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 m2DAlphaRampImagep; LLPointer 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: diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp index 3807226933..58d21ca539 100644 --- a/indra/newview/lldrawpooltree.cpp +++ b/indra/newview/lldrawpooltree.cpp @@ -91,17 +91,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); diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index 4d25080eba..aecb9e4fbc 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -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(); + 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(); @@ -211,11 +218,14 @@ BOOL LLViewerDynamicTexture::updateAllInstances() if (dynamicTexture->needsRender()) { LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("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; { @@ -238,10 +248,7 @@ BOOL LLViewerDynamicTexture::updateAllInstances() } } - if (use_fbo) - { - gPipeline.mBake.flush(); - } + bake_target.flush(); gGL.flush(); diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index 5ca86624fe..508e0f306d 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -674,6 +674,10 @@ void LLFeatureManager::applyBaseMasks() { maskFeatures("TexUnit8orLess"); } + if (gGLManager.mNumTextureImageUnits <= 16) + { + maskFeatures("TexUnit16orLess"); + } if (gGLManager.mVRAM > 512) { maskFeatures("VRAMGT512"); diff --git a/indra/newview/llfetchedgltfmaterial.cpp b/indra/newview/llfetchedgltfmaterial.cpp index 46b9dffae9..97b959e5cb 100644 --- a/indra/newview/llfetchedgltfmaterial.cpp +++ b/indra/newview/llfetchedgltfmaterial.cpp @@ -37,8 +37,6 @@ LLFetchedGLTFMaterial::LLFetchedGLTFMaterial() : LLGLTFMaterial() , mExpectedFlusTime(0.f) - , mActive(true) - , mFetching(false) { } @@ -242,10 +240,11 @@ void LLFetchedGLTFMaterial::onMaterialComplete(std::function material_co materialCompleteCallbacks.push_back(material_complete); } -void LLFetchedGLTFMaterial::materialComplete() +void LLFetchedGLTFMaterial::materialComplete(bool success) { llassert(mFetching); mFetching = false; + mFetchSuccess = success; for (std::function material_complete : materialCompleteCallbacks) { @@ -254,55 +253,3 @@ void LLFetchedGLTFMaterial::materialComplete() materialCompleteCallbacks.clear(); materialCompleteCallbacks.shrink_to_fit(); } - -LLPointer LLFetchedGLTFMaterial::getUITexture() -{ - if (mFetching) - { - return nullptr; - } - - auto fetch_texture_for_ui = [](LLPointer& 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(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; -} diff --git a/indra/newview/llfetchedgltfmaterial.h b/indra/newview/llfetchedgltfmaterial.h index a9e539633d..3fa4619d8c 100644 --- a/indra/newview/llfetchedgltfmaterial.h +++ b/indra/newview/llfetchedgltfmaterial.h @@ -49,8 +49,7 @@ public: void bind(LLViewerTexture* media_tex = nullptr); bool isFetching() const { return mFetching; } - - LLPointer getUITexture(); + bool isLoaded() const { return !mFetching && mFetchSuccess; } void addTextureEntry(LLTextureEntry* te) override; void removeTextureEntry(LLTextureEntry* te) override; @@ -65,18 +64,16 @@ public: std::set mTextureEntires; - // Texture used for previewing the material in the UI - LLPointer 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> materialCompleteCallbacks; }; diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 33d18f7f23..3b002f1bf0 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -653,6 +653,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() { @@ -1493,6 +1513,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("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) { @@ -1510,7 +1541,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; @@ -1566,12 +1597,20 @@ BOOL LLPanelRegionTerrainInfo::postBuild() initCtrl("terrain_raise_spin"); initCtrl("terrain_lower_spin"); + getChild("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) { @@ -1591,6 +1630,61 @@ BOOL LLPanelRegionTerrainInfo::postBuild() return LLPanelRegionInfo::postBuild(); } +// virtual +void LLPanelRegionTerrainInfo::refresh() +{ + std::string buffer; + + bool has_material_assets = false; + for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i) + { + buffer = llformat("material_detail_%d", i); + LLTextureCtrl* material_ctrl = getChild(buffer); + if (material_ctrl && material_ctrl->getImageAssetID().notNull()) + { + has_material_assets = true; + break; + } + } + + LLComboBox* material_type_ctrl = getChild("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; + material_type_ctrl->setEnabled(!(is_material_selected && has_material_assets)); + } +} + +void LLPanelRegionTerrainInfo::onSelectMaterialType() +{ + LLComboBox* material_type_ctrl = getChild("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(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(buffer); + if (texture_ctrl) + { + texture_ctrl->setVisible(show_material_controls); + } + } +} + // virtual bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region) { @@ -1607,18 +1701,30 @@ bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region) getChild("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(buffer); - if(texture_ctrl) + asset_ctrl = getChild(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(buffer); + if(asset_ctrl) + { + LLUUID tmp_id(compp->getDetailAssetID(i)); + asset_ctrl->setImageAssetID(tmp_id); } } @@ -1694,17 +1800,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("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(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(buffer); - if(texture_ctrl) + if (materials_used == TERRAIN_TEXTURE_COUNT) + { + buffer = llformat("material_detail_%d", i); + asset_ctrl = getChild(buffer); + } + else + { + buffer = llformat("texture_detail_%d", i); + asset_ctrl = getChild(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); diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h index 371de36f3b..c197dff3f3 100644 --- a/indra/newview/llfloaterregioninfo.h +++ b/indra/newview/llfloaterregioninfo.h @@ -78,9 +78,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**); @@ -104,7 +104,7 @@ public: // Aurora Sim - Region Settings Panel // from LLPanel - virtual void refresh(); + void refresh() override; void onRegionChanged(); void requestRegionInfo(); @@ -150,7 +150,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); @@ -210,16 +210,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); @@ -240,13 +239,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 names); @@ -273,9 +272,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(); @@ -283,7 +282,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*); @@ -295,6 +295,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; @@ -333,13 +336,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(); @@ -349,7 +351,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); @@ -369,17 +371,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); @@ -412,7 +413,7 @@ public: } EAssetStatus; protected: - virtual BOOL sendUpdate(); + BOOL sendUpdate() override; LLTextBox* mEstateNameText; LLTextBox* mEstateOwnerText; LLTextBox* mLastModifiedText; @@ -431,16 +432,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 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(); @@ -465,8 +469,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(); @@ -474,7 +478,7 @@ public: void setPendingUpdate(bool pending) { mPendingUpdate = pending; } bool getPendingUpdate() { return mPendingUpdate; } - virtual bool refreshFromRegion(LLViewerRegion* region); + bool refreshFromRegion(LLViewerRegion* region) override; // Moved to public static void sendEstateAccessDelta(U32 flags, const LLUUID& agent_id); diff --git a/indra/newview/llgltfmateriallist.cpp b/indra/newview/llgltfmateriallist.cpp index 92c58a2dbc..a9216ae656 100644 --- a/indra/newview/llgltfmateriallist.cpp +++ b/indra/newview/llgltfmateriallist.cpp @@ -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; }); diff --git a/indra/newview/llgltfmaterialpreviewmgr.cpp b/indra/newview/llgltfmaterialpreviewmgr.cpp new file mode 100644 index 0000000000..a8ea3429f4 --- /dev/null +++ b/indra/newview/llgltfmaterialpreviewmgr.cpp @@ -0,0 +1,555 @@ +/** + * @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 +#include + +#include "llavatarappearancedefines.h" +#include "llenvironment.h" +#include "llselectmgr.h" +#include "llviewercamera.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& 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(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& 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) + { + using MaterialTextures = LLPointer*[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 material, S32 width) + : LLViewerDynamicTexture(width, width, 4, EOrder::ORDER_MIDDLE, FALSE) + , mGLTFMaterial(material) +{ +} + +// static +LLPointer LLGLTFPreviewTexture::create(LLPointer 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& 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 mDrawInfo; + LLMatrix4 mModelMatrix; // Referenced by mDrawInfo +}; + +using PreviewSpherePart = std::unique_ptr; +using PreviewSphere = std::vector; + +// Like LLVolumeGeometryManager::registerFace but without batching or too-many-indices/vertices checking. +PreviewSphere create_preview_sphere(LLPointer& 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 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 indices; + LLStrider positions; + LLStrider normals; + LLStrider texcoords; + LLStrider colors; + LLStrider 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 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(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& 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 colors; + const S32 count = info->mEnd - info->mStart; + buf->getColorStrider(colors, info->mStart, count); + for (S32 i = 0; i < count; ++i) + { + *colors++ = vertex_color; + } + buf->unmapBuffer(); + } +} + +PreviewSphere& get_preview_sphere(LLPointer& 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 +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 no_dof(&LLPipeline::RenderDepthOfField, false); + SetTemporarily no_glow(&LLPipeline::sRenderGlow, false); + SetTemporarily no_ssr(&LLPipeline::RenderScreenSpaceReflections, false); + SetTemporarily no_fxaa(&LLPipeline::RenderFSAASamples, U32(0)); + SetTemporarily 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); + SetTemporarily sun_light_only(&LLPipeline::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 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); + + return TRUE; +} + +void LLGLTFPreviewTexture::postRender(BOOL success) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; + + if (!mShouldRender) { return; } + mShouldRender = false; + + LLViewerDynamicTexture::postRender(success); +} + +// static +LLPointer LLGLTFMaterialPreviewMgr::getPreview(LLPointer &material) +{ + if (!material) + { + return nullptr; + } + + if (!is_material_loaded_enough_for_ui(*material)) + { + return nullptr; + } + + return LLGLTFPreviewTexture::create(material); +} diff --git a/indra/newview/llgltfmaterialpreviewmgr.h b/indra/newview/llgltfmaterialpreviewmgr.h new file mode 100644 index 0000000000..cc40a6f2e2 --- /dev/null +++ b/indra/newview/llgltfmaterialpreviewmgr.h @@ -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 material, S32 width); + +public: + // Width scales with size of material's textures + static LLPointer create(LLPointer 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 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 getPreview(LLPointer &material); +}; + +extern LLGLTFMaterialPreviewMgr gGLTFMaterialPreviewMgr; diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 0817e832cd..fb29cf34be 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -1875,7 +1875,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; } diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp index 69674417c1..2b6985b214 100644 --- a/indra/newview/llreflectionmapmanager.cpp +++ b/indra/newview/llreflectionmapmanager.cpp @@ -27,6 +27,9 @@ #include "llviewerprecompiledheaders.h" #include "llreflectionmapmanager.h" + +#include + #include "llviewercamera.h" #include "llspatialpartition.h" #include "llviewerregion.h" @@ -1383,3 +1386,39 @@ void LLReflectionMapManager::doOcclusion() } } } + +void LLReflectionMapManager::forceDefaultProbeAndUpdateUniforms(bool force) +{ + static std::vector 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(); + } +} diff --git a/indra/newview/llreflectionmapmanager.h b/indra/newview/llreflectionmapmanager.h index b77a33da89..dd641452ae 100644 --- a/indra/newview/llreflectionmapmanager.h +++ b/indra/newview/llreflectionmapmanager.h @@ -106,6 +106,11 @@ 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; diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp index 0e745d6cff..3ef9f31d39 100644 --- a/indra/newview/llsurfacepatch.cpp +++ b/indra/newview/llsurfacepatch.cpp @@ -246,7 +246,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); @@ -869,7 +871,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; diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 9fcf6b65bc..aae37f0ef9 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -72,6 +72,7 @@ #include "llradiogroup.h" #include "llfloaterreg.h" +#include "llgltfmaterialpreviewmgr.h" #include "lllocalbitmaps.h" #include "lllocalgltfmaterials.h" #include "llerror.h" @@ -721,6 +722,7 @@ void LLFloaterTexturePicker::draw() if( mOwner ) { mTexturep = NULL; + LLPointer old_material = mGLTFMaterial; mGLTFMaterial = NULL; if (mImageAssetID.notNull()) { @@ -728,10 +730,23 @@ void LLFloaterTexturePicker::draw() { mGLTFMaterial = (LLFetchedGLTFMaterial*) gGLTFMaterialList.getMaterial(mImageAssetID); llassert(mGLTFMaterial == nullptr || dynamic_cast(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); + } + } } else { LLPointer texture = NULL; + mGLTFPreview = nullptr; if (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(mImageAssetID)) { @@ -741,7 +756,7 @@ void LLFloaterTexturePicker::draw() if (obj) { LLViewerTexture* viewerTexture = obj->getBakedTextureForMagicId(mImageAssetID); - texture = viewerTexture ? dynamic_cast(viewerTexture) : NULL; + texture = viewerTexture ? dynamic_cast(viewerTexture) : NULL; } } @@ -783,27 +798,29 @@ 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 = nullptr; if (mGLTFMaterial) { - texture = mGLTFMaterial->getUITexture(); + preview = mGLTFPreview.get(); } else { - texture = mTexturep.get(); + preview = mTexturep.get(); + if (mTexturep) + { + // Pump the priority + mTexturep->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) ); + } } - if( texture ) + if( preview ) { - if( texture->getComponents() == 4 ) + 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()) { @@ -1786,7 +1803,7 @@ LLTextureCtrl::LLTextureCtrl(const LLTextureCtrl::Params& p) mShowLoadingPlaceholder( TRUE ), mOpenTexPreview(!p.enabled), // For texture preview mode mBakeTextureEnabled(true), - mInventoryPickType(PICK_TEXTURE), + mInventoryPickType(p.pick_type), mImageAssetID(p.image_id), mDefaultImageAssetID(p.default_image_id), mDefaultImageName(p.default_image_name), @@ -2344,48 +2361,69 @@ void LLTextureCtrl::draw() { mBorder->setKeyboardFocusHighlight(hasFocus()); + LLPointer preview = NULL; + if (!mValid) { mTexturep = NULL; + mGLTFMaterial = NULL; + mGLTFPreview = NULL; } else if (!mImageAssetID.isNull()) { - LLPointer texture = NULL; - if (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(mImageAssetID)) { LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); if (obj) { LLViewerTexture* viewerTexture = obj->getBakedTextureForMagicId(mImageAssetID); - texture = viewerTexture ? dynamic_cast(viewerTexture) : NULL; + mTexturep = viewerTexture ? dynamic_cast(viewerTexture) : NULL; + mGLTFMaterial = NULL; + mGLTFPreview = NULL; + + preview = mTexturep; } } - if (texture.isNull()) + if (preview.isNull()) { + LLPointer old_material = mGLTFMaterial; + mGLTFMaterial = NULL; + mTexturep = NULL; if (mInventoryPickType == PICK_MATERIAL) { - LLPointer 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); + } } + + 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 @@ -2400,15 +2438,18 @@ 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); + if (mTexturep) + { + mTexturep->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) ); + } // Mask texture if desired if (mIsMasked) { @@ -2594,3 +2635,18 @@ void LLTextureCtrl::updateLabelColor() mCaption->setReadOnlyColor(mTextDisabledColor.get()); } // + +namespace LLInitParam +{ + void TypeValues::declareValues() + { + declare("texture_material", PICK_TEXTURE_MATERIAL); + declare("texture", PICK_TEXTURE); + declare("material", PICK_MATERIAL); + } +} + + + + + diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h index aae52ddcca..f93a3925bb 100644 --- a/indra/newview/lltexturectrl.h +++ b/indra/newview/lltexturectrl.h @@ -65,13 +65,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 { @@ -80,6 +73,23 @@ typedef enum e_pick_inventory_type PICK_MATERIAL = 2, } EPickInventoryType; +namespace LLInitParam +{ + template<> + struct TypeValues : public TypeValuesHelper + { + static void declareValues(); + }; +} + +enum LLPickerSource +{ + PICKER_INVENTORY, + PICKER_LOCAL, + PICKER_BAKE, + PICKER_UNKNOWN, // on cancel, default ids +}; + ////////////////////////////////////////////////////////////////////////////////////////// // LLTextureCtrl @@ -101,6 +111,7 @@ public: Optional image_id; Optional default_image_id; Optional default_image_name; + Optional pick_type; Optional allow_no_texture; Optional can_apply_immediately; Optional no_commit_on_selection; // alternative mode: commit occurs and the widget gets dirty @@ -122,6 +133,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), @@ -266,6 +278,8 @@ private: commit_callback_t mOnCloseCallback; texture_selected_callback mOnTextureSelectedCallback; LLPointer mTexturep; + LLPointer mGLTFMaterial; + LLPointer mGLTFPreview; LLUIColor mBorderColor; LLUUID mImageItemID; LLUUID mImageAssetID; @@ -411,6 +425,7 @@ protected: LLPointer mTexturep; LLPointer mGLTFMaterial; + LLPointer mGLTFPreview; LLView* mOwner; LLUUID mImageAssetID; // Currently selected texture diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 6c04622b71..3808c313d6 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -60,6 +60,7 @@ #include "llvotree.h" #include "llvovolume.h" #include "llworld.h" +#include "llvlcomposition.h" #include "pipeline.h" #include "llviewerjoystick.h" #include "llviewerobjectlist.h" @@ -197,12 +198,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) { @@ -1080,6 +1094,16 @@ void handleFPSTuningStrategyChanged(const LLSD& newValue) 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); + } +} + // FIRE-6809: Quickly moving the bandwidth slider has no effect void handleBandwidthChanged(const LLSD& newValue) { @@ -1132,7 +1156,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); @@ -1288,6 +1316,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); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index bc2a9e34a5..3f53c6a5ab 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -3191,20 +3191,20 @@ void LLViewerRegion::unpackRegionHandshake() // Get the 4 textures for land msg->getUUID("RegionInfo", "TerrainDetail0", tmp_id); - changed |= (tmp_id != compp->getDetailTextureID(0)); - compp->setDetailTextureID(0, tmp_id); + changed |= (tmp_id != compp->getDetailAssetID(0)); + compp->setDetailAssetID(0, tmp_id); msg->getUUID("RegionInfo", "TerrainDetail1", tmp_id); - changed |= (tmp_id != compp->getDetailTextureID(1)); - compp->setDetailTextureID(1, tmp_id); + changed |= (tmp_id != compp->getDetailAssetID(1)); + compp->setDetailAssetID(1, tmp_id); msg->getUUID("RegionInfo", "TerrainDetail2", tmp_id); - changed |= (tmp_id != compp->getDetailTextureID(2)); - compp->setDetailTextureID(2, tmp_id); + changed |= (tmp_id != compp->getDetailAssetID(2)); + compp->setDetailAssetID(2, tmp_id); msg->getUUID("RegionInfo", "TerrainDetail3", tmp_id); - changed |= (tmp_id != compp->getDetailTextureID(3)); - compp->setDetailTextureID(3, tmp_id); + changed |= (tmp_id != compp->getDetailAssetID(3)); + compp->setDetailAssetID(3, tmp_id); // Get the start altitude and range values for land textures F32 tmp_f32; diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 5084effc59..0957f5c0d4 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -69,6 +69,14 @@ bool LLViewerShaderMgr::sSkipReload = false; LLVector4 gShinyOrigin; +S32 clamp_terrain_mapping(S32 mapping) +{ + // 1 = "flat", 2 not implemented, 3 = triplanar mapping + mapping = llclamp(mapping, 1, 3); + if (mapping == 2) { mapping = 1; } + return mapping; +} + //utility shaders LLGLSLShader gOcclusionProgram; LLGLSLShader gSkinnedOcclusionProgram; @@ -218,6 +226,7 @@ LLGLSLShader gDeferredSkinnedPBROpaqueProgram; LLGLSLShader gHUDPBRAlphaProgram; LLGLSLShader gDeferredPBRAlphaProgram; LLGLSLShader gDeferredSkinnedPBRAlphaProgram; +LLGLSLShader gDeferredPBRTerrainProgram; //helper for making a rigged variant of a given shader bool make_rigged_variant(LLGLSLShader& shader, LLGLSLShader& riggedShader) @@ -275,7 +284,7 @@ LLViewerShaderMgr::LLViewerShaderMgr() : mShaderList.push_back(&gDeferredEmissiveProgram); mShaderList.push_back(&gDeferredSkinnedEmissiveProgram); mShaderList.push_back(&gDeferredAvatarEyesProgram); - mShaderList.push_back(&gDeferredAvatarAlphaProgram); + mShaderList.push_back(&gDeferredAvatarAlphaProgram); mShaderList.push_back(&gDeferredWLSkyProgram); mShaderList.push_back(&gDeferredWLCloudProgram); mShaderList.push_back(&gDeferredWLMoonProgram); @@ -627,6 +636,15 @@ std::string LLViewerShaderMgr::loadBasicShaders() attribs["REF_SAMPLE_COUNT"] = "32"; } + { // PBR terrain + const S32 mapping = clamp_terrain_mapping(gSavedSettings.getS32("RenderTerrainPBRPlanarSampleCount")); + attribs["TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT"] = llformat("%d", mapping); + const F32 triplanar_factor = gSavedSettings.getF32("RenderTerrainPBRTriplanarBlendFactor"); + attribs["TERRAIN_TRIPLANAR_BLEND_FACTOR"] = llformat("%.2f", triplanar_factor); + S32 detail = gSavedSettings.getS32("RenderTerrainPBRDetail"); + attribs["TERRAIN_PBR_DETAIL"] = llformat("%d", detail); + } + LLGLSLShader::sGlobalDefines = attribs; // We no longer have to bind the shaders to global glhandles, they are automatically added to a map now. @@ -664,6 +682,7 @@ std::string LLViewerShaderMgr::loadBasicShaders() index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/deferredUtil.glsl", 1) ); index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/shadowUtil.glsl", 1) ); index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/aoUtil.glsl", 1) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/pbrterrainUtilF.glsl", 1) ); index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/reflectionProbeF.glsl", has_reflection_probes ? 3 : 2) ); index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/screenSpaceReflUtil.glsl", ssr ? 3 : 1) ); index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); @@ -968,6 +987,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredSkinnedPBROpaqueProgram.unload(); gDeferredPBRAlphaProgram.unload(); gDeferredSkinnedPBRAlphaProgram.unload(); + gDeferredPBRTerrainProgram.unload(); // [RLVa:KB] - @setsphere gRlvSphereProgram.unload(); @@ -1262,6 +1282,34 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() success = shader->createShader(NULL, NULL); llassert(success); } + + if (success) + { + S32 detail = gSavedSettings.getS32("RenderTerrainPBRDetail"); + detail = llclamp(detail, TERRAIN_PBR_DETAIL_MIN, TERRAIN_PBR_DETAIL_MAX); + const S32 mapping = clamp_terrain_mapping(gSavedSettings.getS32("RenderTerrainPBRPlanarSampleCount")); + gDeferredPBRTerrainProgram.mName = llformat("Deferred PBR Terrain Shader %d %s", + detail, + (mapping == 1 ? "flat" : "triplanar")); + gDeferredPBRTerrainProgram.mFeatures.encodesNormal = true; + gDeferredPBRTerrainProgram.mFeatures.hasSrgb = true; + gDeferredPBRTerrainProgram.mFeatures.isAlphaLighting = true; + gDeferredPBRTerrainProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels + gDeferredPBRTerrainProgram.mFeatures.calculatesAtmospherics = true; + gDeferredPBRTerrainProgram.mFeatures.hasAtmospherics = true; + gDeferredPBRTerrainProgram.mFeatures.hasGamma = true; + gDeferredPBRTerrainProgram.mFeatures.hasTransport = true; + gDeferredPBRTerrainProgram.mFeatures.isPBRTerrain = true; + + gDeferredPBRTerrainProgram.mShaderFiles.clear(); + gDeferredPBRTerrainProgram.mShaderFiles.push_back(make_pair("deferred/pbrterrainV.glsl", GL_VERTEX_SHADER)); + gDeferredPBRTerrainProgram.mShaderFiles.push_back(make_pair("deferred/pbrterrainF.glsl", GL_FRAGMENT_SHADER)); + gDeferredPBRTerrainProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + gDeferredPBRTerrainProgram.addPermutation("TERRAIN_PBR_DETAIL", llformat("%d", detail)); + gDeferredPBRTerrainProgram.addPermutation("TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT", llformat("%d", mapping)); + success = gDeferredPBRTerrainProgram.createShader(NULL, NULL); + llassert(success); + } if (success) { @@ -1975,8 +2023,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredTerrainProgram.mName = "Deferred Terrain Shader"; gDeferredTerrainProgram.mFeatures.encodesNormal = true; gDeferredTerrainProgram.mFeatures.hasSrgb = true; - gDeferredTerrainProgram.mFeatures.calculatesLighting = false; - gDeferredTerrainProgram.mFeatures.hasLighting = false; gDeferredTerrainProgram.mFeatures.isAlphaLighting = true; gDeferredTerrainProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels gDeferredTerrainProgram.mFeatures.calculatesAtmospherics = true; diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index 3788615c18..9c07210d50 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -276,4 +276,16 @@ extern LLGLSLShader gPBRGlowProgram; extern LLGLSLShader gDeferredPBROpaqueProgram; extern LLGLSLShader gDeferredPBRAlphaProgram; extern LLGLSLShader gHUDPBRAlphaProgram; + +// Encodes detail level for dropping textures, in accordance with the GLTF spec +// 0 is highest detail, -1 drops emissive, etc +// https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#additional-textures +enum TerrainPBRDetail : S32 +{ + TERRAIN_PBR_DETAIL_MAX = 0, + TERRAIN_PBR_DETAIL_EMISSIVE = 0, + TERRAIN_PBR_DETAIL_OCCLUSION = -1, + TERRAIN_PBR_DETAIL_MIN = -1, +}; +extern LLGLSLShader gDeferredPBRTerrainProgram; #endif diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index beca344d17..4fda68c80f 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1775,7 +1775,7 @@ void LLViewerFetchedTexture::processTextureStats() { if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT) { - mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 + mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 2048 and max size ever is 4096 } else { @@ -1788,7 +1788,7 @@ void LLViewerFetchedTexture::processTextureStats() } else { - U32 desired_size = MAX_IMAGE_SIZE_DEFAULT; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 + U32 desired_size = MAX_IMAGE_SIZE_DEFAULT; // MAX_IMAGE_SIZE_DEFAULT = 2048 and max size ever is 4096 // Keep restriction on "fetched" (seems to be HUD) textures as well if (mBoostLevel <= LLGLTexture::BOOST_SCULPTED) { @@ -3181,7 +3181,7 @@ void LLViewerLODTexture::processTextureStats() { mDesiredDiscardLevel = 0; if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT) - mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 + mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 2048 and max size ever is 4096 } else if (mBoostLevel < LLGLTexture::BOOST_HIGH && mMaxVirtualSize <= 10.f) { @@ -3226,7 +3226,7 @@ void LLViewerLODTexture::processTextureStats() discard_level = floorf(discard_level); F32 min_discard = 0.f; - U32 desired_size = MAX_IMAGE_SIZE_DEFAULT; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 + U32 desired_size = MAX_IMAGE_SIZE_DEFAULT; // MAX_IMAGE_SIZE_DEFAULT = 2048 and max size ever is 4096 if (mBoostLevel <= LLGLTexture::BOOST_SCULPTED) { desired_size = DESIRED_NORMAL_TEXTURE_SIZE; diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp index d462c9aabb..5b4381cdcc 100644 --- a/indra/newview/llvlcomposition.cpp +++ b/indra/newview/llvlcomposition.cpp @@ -34,12 +34,16 @@ #include "lltextureview.h" #include "llviewertexture.h" #include "llviewertexturelist.h" +#include "llfetchedgltfmaterial.h" +#include "llgltfmateriallist.h" #include "llviewerregion.h" #include "noise.h" #include "llregionhandle.h" // for from_region_handle #include "llviewercontrol.h" +static const U32 BASE_SIZE = 128; + F32 bilinear(const F32 v00, const F32 v01, const F32 v10, const F32 v11, const F32 x_frac, const F32 y_frac) { @@ -57,18 +61,199 @@ F32 bilinear(const F32 v00, const F32 v01, const F32 v10, const F32 v11, const F return result; } +LLTerrainMaterials::LLTerrainMaterials() +{ + for (S32 i = 0; i < ASSET_COUNT; ++i) + { + mMaterialTexturesSet[i] = false; + } +} + +LLTerrainMaterials::~LLTerrainMaterials() +{ +} + +BOOL LLTerrainMaterials::generateMaterials() +{ + if (texturesReady(TRUE)) + { + return TRUE; + } + + if (materialsReady(TRUE)) + { + return TRUE; + } + + return FALSE; +} + +LLUUID LLTerrainMaterials::getDetailAssetID(S32 asset) +{ + llassert(mDetailTextures[asset] && mDetailMaterials[asset]); + // *HACK: Assume both the the material and texture were fetched in the same + // way using the same UUID. However, we may not know at this point which + // one will load. + return mDetailTextures[asset]->getID(); +} + +LLPointer fetch_terrain_texture(const LLUUID& id) +{ + if (id.isNull()) + { + return nullptr; + } + + LLPointer tex = LLViewerTextureManager::getFetchedTexture(id); + tex->setNoDelete(); + return tex; +} + +void LLTerrainMaterials::setDetailAssetID(S32 asset, const LLUUID& id) +{ + // This is terrain texture, but we are not setting it as BOOST_TERRAIN + // since we will be manipulating it later as needed. + mDetailTextures[asset] = fetch_terrain_texture(id); + LLPointer& mat = mDetailMaterials[asset]; + mat = id.isNull() ? nullptr : gGLTFMaterialList.getMaterial(id); + mMaterialTexturesSet[asset] = false; +} + +LLTerrainMaterials::Type LLTerrainMaterials::getMaterialType() +{ + LL_PROFILE_ZONE_SCOPED; + + const BOOL use_textures = texturesReady() || !materialsReady(); + return use_textures ? Type::TEXTURE : Type::PBR; +} + +BOOL LLTerrainMaterials::texturesReady(BOOL boost) +{ + BOOL ready = TRUE; + for (S32 i = 0; i < ASSET_COUNT; i++) + { + if (!textureReady(mDetailTextures[i], boost)) + { + ready = FALSE; + } + } + return ready; +} + +BOOL LLTerrainMaterials::materialsReady(BOOL boost) +{ + BOOL ready = TRUE; + for (S32 i = 0; i < ASSET_COUNT; i++) + { + if (!materialReady(mDetailMaterials[i], mMaterialTexturesSet[i], boost)) + { + ready = FALSE; + } + } + return ready; +} + +// Boost the texture loading priority +// Return true when ready to use (i.e. texture is sufficiently loaded) +// static +BOOL LLTerrainMaterials::textureReady(LLPointer& tex, BOOL boost) +{ + llassert(tex.notNull()); + + if (tex->getDiscardLevel() < 0) + { + if (boost) + { + tex->setBoostLevel(LLGLTexture::BOOST_TERRAIN); // in case we are at low detail + tex->addTextureStats(BASE_SIZE*BASE_SIZE); + } + return FALSE; + } + if ((tex->getDiscardLevel() != 0 && + (tex->getWidth() < BASE_SIZE || + tex->getHeight() < BASE_SIZE))) + { + if (boost) + { + S32 width = tex->getFullWidth(); + S32 height = tex->getFullHeight(); + S32 min_dim = llmin(width, height); + S32 ddiscard = 0; + while (min_dim > BASE_SIZE && ddiscard < MAX_DISCARD_LEVEL) + { + ddiscard++; + min_dim /= 2; + } + tex->setBoostLevel(LLGLTexture::BOOST_TERRAIN); // in case we are at low detail + tex->setMinDiscardLevel(ddiscard); + tex->addTextureStats(BASE_SIZE*BASE_SIZE); // priority + } + return FALSE; + } + if (tex->getComponents() == 0) + { + return FALSE; + } + return TRUE; +} + +// Boost the loading priority of every known texture in the material +// Return true when ready to use (i.e. material and all textures within are sufficiently loaded) +// static +BOOL LLTerrainMaterials::materialReady(LLPointer& mat, bool& textures_set, BOOL boost) +{ + if (!mat || !mat->isLoaded()) + { + return FALSE; + } + + // Material is loaded, but textures may not be + if (!textures_set) + { + // *NOTE: These can sometimes be set to to nullptr due to + // updateTEMaterialTextures. For the sake of robustness, we emulate + // that fetching behavior by setting textures of null IDs to nullptr. + mat->mBaseColorTexture = fetch_terrain_texture(mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR]); + mat->mNormalTexture = fetch_terrain_texture(mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL]); + mat->mMetallicRoughnessTexture = fetch_terrain_texture(mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS]); + mat->mEmissiveTexture = fetch_terrain_texture(mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE]); + textures_set = true; + + return FALSE; + } + + if (mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR].notNull() && !textureReady(mat->mBaseColorTexture, boost)) + { + return FALSE; + } + if (mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL].notNull() && !textureReady(mat->mNormalTexture, boost)) + { + return FALSE; + } + if (mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].notNull() && !textureReady(mat->mMetallicRoughnessTexture, boost)) + { + return FALSE; + } + if (mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE].notNull() && !textureReady(mat->mEmissiveTexture, boost)) + { + return FALSE; + } + + return TRUE; +} + LLVLComposition::LLVLComposition(LLSurface *surfacep, const U32 width, const F32 scale) : - LLViewerLayer(width, scale), - mParamsReady(FALSE) + LLTerrainMaterials(), + LLViewerLayer(width, scale) { - mSurfacep = surfacep; - // Load Terrain Textures - Original ones - setDetailTextureID(0, TERRAIN_DIRT_DETAIL); - setDetailTextureID(1, TERRAIN_GRASS_DETAIL); - setDetailTextureID(2, TERRAIN_MOUNTAIN_DETAIL); - setDetailTextureID(3, TERRAIN_ROCK_DETAIL); + setDetailAssetID(0, TERRAIN_DIRT_DETAIL); + setDetailAssetID(1, TERRAIN_GRASS_DETAIL); + setDetailAssetID(2, TERRAIN_MOUNTAIN_DETAIL); + setDetailAssetID(3, TERRAIN_ROCK_DETAIL); + + mSurfacep = surfacep; // Initialize the texture matrix to defaults. for (S32 i = 0; i < CORNER_COUNT; ++i) @@ -76,14 +261,12 @@ LLVLComposition::LLVLComposition(LLSurface *surfacep, const U32 width, const F32 mStartHeight[i] = gSavedSettings.getF32("TerrainColorStartHeight"); mHeightRange[i] = gSavedSettings.getF32("TerrainColorHeightRange"); } - mTexScaleX = 16.f; - mTexScaleY = 16.f; - mTexturesLoaded = FALSE; } LLVLComposition::~LLVLComposition() { + LLTerrainMaterials::~LLTerrainMaterials(); } @@ -92,20 +275,6 @@ void LLVLComposition::setSurface(LLSurface *surfacep) mSurfacep = surfacep; } - -void LLVLComposition::setDetailTextureID(S32 corner, const LLUUID& id) -{ - if(id.isNull()) - { - return; - } - // This is terrain texture, but we are not setting it as BOOST_TERRAIN - // since we will be manipulating it later as needed. - mDetailTextures[corner] = LLViewerTextureManager::getFetchedTexture(id); - mDetailTextures[corner]->setNoDelete() ; - mRawImages[corner] = NULL; -} - BOOL LLVLComposition::generateHeights(const F32 x, const F32 y, const F32 width, const F32 height) { @@ -149,10 +318,6 @@ BOOL LLVLComposition::generateHeights(const F32 x, const F32 y, const F32 noise_magnitude = 2.f; // Degree to which noise modulates composition layer (versus // simple height) - // Heights map into textures as 0-1 = first, 1-2 = second, etc. - // So we need to compress heights into this range. - const S32 NUM_TEXTURES = 4; - const F32 xyScaleInv = (1.f / xyScale); const F32 zScaleInv = (1.f / zScale); @@ -202,7 +367,7 @@ BOOL LLVLComposition::generateHeights(const F32 x, const F32 y, twiddle += turbulence2(vec, 2)*slope_squared; // High frequency component twiddle *= noise_magnitude; - F32 scaled_noisy_height = (height + twiddle - start_height) * F32(NUM_TEXTURES) / height_range; + F32 scaled_noisy_height = (height + twiddle - start_height) * F32(ASSET_COUNT) / height_range; scaled_noisy_height = llmax(0.f, scaled_noisy_height); scaled_noisy_height = llmin(3.f, scaled_noisy_height); @@ -212,49 +377,20 @@ BOOL LLVLComposition::generateHeights(const F32 x, const F32 y, return TRUE; } -static const U32 BASE_SIZE = 128; +LLTerrainMaterials gLocalTerrainMaterials; BOOL LLVLComposition::generateComposition() { - if (!mParamsReady) { // All the parameters haven't been set yet (we haven't gotten the message from the sim) return FALSE; } - for (S32 i = 0; i < 4; i++) - { - if (mDetailTextures[i]->getDiscardLevel() < 0) - { - mDetailTextures[i]->setBoostLevel(LLGLTexture::BOOST_TERRAIN); // in case we are at low detail - mDetailTextures[i]->addTextureStats(BASE_SIZE*BASE_SIZE); - return FALSE; - } - if ((mDetailTextures[i]->getDiscardLevel() != 0 && - (mDetailTextures[i]->getWidth() < BASE_SIZE || - mDetailTextures[i]->getHeight() < BASE_SIZE))) - { - S32 width = mDetailTextures[i]->getFullWidth(); - S32 height = mDetailTextures[i]->getFullHeight(); - S32 min_dim = llmin(width, height); - S32 ddiscard = 0; - while (min_dim > BASE_SIZE && ddiscard < MAX_DISCARD_LEVEL) - { - ddiscard++; - min_dim /= 2; - } - mDetailTextures[i]->setBoostLevel(LLGLTexture::BOOST_TERRAIN); // in case we are at low detail - mDetailTextures[i]->setMinDiscardLevel(ddiscard); - mDetailTextures[i]->addTextureStats(BASE_SIZE*BASE_SIZE); // priority - return FALSE; - } - } - - return TRUE; + return LLTerrainMaterials::generateMaterials(); } -BOOL LLVLComposition::generateTexture(const F32 x, const F32 y, +BOOL LLVLComposition::generateMinimapTileLand(const F32 x, const F32 y, const F32 width, const F32 height) { LL_PROFILE_ZONE_SCOPED @@ -262,8 +398,6 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y, llassert(x >= 0.f); llassert(y >= 0.f); - LLTimer gen_timer; - /////////////////////////// // // Generate raw data arrays for surface textures @@ -271,15 +405,61 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y, // // These have already been validated by generateComposition. - U8* st_data[4]; - S32 st_data_size[4]; // for debugging + U8* st_data[ASSET_COUNT]; + S32 st_data_size[ASSET_COUNT]; // for debugging - for (S32 i = 0; i < 4; i++) + const bool use_textures = getMaterialType() != LLTerrainMaterials::Type::PBR; + // *TODO: Remove this as it is reduandant computation (first and foremost + // because getMaterialType() does something similar, but also... shouldn't + // the textures/materials already be loaded by now?) + if (use_textures) + { + if (!texturesReady()) { return FALSE; } + } + else + { + if (!materialsReady()) { return FALSE; } + } + + for (S32 i = 0; i < ASSET_COUNT; i++) { if (mRawImages[i].isNull()) { // Read back a raw image for this discard level, if it exists - S32 min_dim = llmin(mDetailTextures[i]->getFullWidth(), mDetailTextures[i]->getFullHeight()); + LLViewerFetchedTexture* tex; + LLViewerFetchedTexture* tex_emissive; // Can be null + bool has_base_color_factor; + bool has_emissive_factor; + LLColor3 base_color_factor; + LLColor3 emissive_factor; + if (use_textures) + { + tex = mDetailTextures[i]; + tex_emissive = nullptr; + has_base_color_factor = false; + has_emissive_factor = false; + llassert(tex); + } + else + { + tex = mDetailMaterials[i]->mBaseColorTexture; + tex_emissive = mDetailMaterials[i]->mEmissiveTexture; + base_color_factor = LLColor3(mDetailMaterials[i]->mBaseColor); + // *HACK: Treat alpha as black + base_color_factor *= (mDetailMaterials[i]->mBaseColor.mV[VW]); + emissive_factor = mDetailMaterials[i]->mEmissiveColor; + has_base_color_factor = (base_color_factor.mV[VX] != 1.f || + base_color_factor.mV[VY] != 1.f || + base_color_factor.mV[VZ] != 1.f); + has_emissive_factor = (emissive_factor.mV[VX] != 1.f || + emissive_factor.mV[VY] != 1.f || + emissive_factor.mV[VZ] != 1.f); + } + + if (!tex) { tex = LLViewerFetchedTexture::sWhiteImagep; } + // tex_emissive can be null, and then will be ignored + + S32 min_dim = llmin(tex->getFullWidth(), tex->getFullHeight()); S32 ddiscard = 0; while (min_dim > BASE_SIZE && ddiscard < MAX_DISCARD_LEVEL) { @@ -287,31 +467,80 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y, min_dim /= 2; } - BOOL delete_raw = (mDetailTextures[i]->reloadRawImage(ddiscard) != NULL) ; - if(mDetailTextures[i]->getRawImageLevel() != ddiscard)//raw iamge is not ready, will enter here again later. + BOOL delete_raw = (tex->reloadRawImage(ddiscard) != NULL) ; + if(tex->getRawImageLevel() != ddiscard) { - if (mDetailTextures[i]->getFetchPriority() <= 0.0f && !mDetailTextures[i]->hasSavedRawImage()) + // Raw image is not ready, will enter here again later. + if (tex->getFetchPriority() <= 0.0f && !tex->hasSavedRawImage()) { - mDetailTextures[i]->setBoostLevel(LLGLTexture::BOOST_MAP); - mDetailTextures[i]->forceToRefetchTexture(ddiscard); + tex->setBoostLevel(LLGLTexture::BOOST_MAP); + tex->forceToRefetchTexture(ddiscard); } if(delete_raw) { - mDetailTextures[i]->destroyRawImage() ; + tex->destroyRawImage() ; } - LL_DEBUGS("Terrain") << "cached raw data for terrain detail texture is not ready yet: " << mDetailTextures[i]->getID() << " Discard: " << ddiscard << LL_ENDL; return FALSE; } + if (tex_emissive) + { + if(tex_emissive->getRawImageLevel() != ddiscard) + { + // Raw image is not ready, will enter here again later. + if (tex_emissive->getFetchPriority() <= 0.0f && !tex_emissive->hasSavedRawImage()) + { + tex_emissive->setBoostLevel(LLGLTexture::BOOST_MAP); + tex_emissive->forceToRefetchTexture(ddiscard); + } - mRawImages[i] = mDetailTextures[i]->getRawImage() ; + if(delete_raw) + { + tex_emissive->destroyRawImage() ; + } + return FALSE; + } + } + + mRawImages[i] = tex->getRawImage() ; if(delete_raw) { - mDetailTextures[i]->destroyRawImage() ; + tex->destroyRawImage() ; } - if (mDetailTextures[i]->getWidth(ddiscard) != BASE_SIZE || - mDetailTextures[i]->getHeight(ddiscard) != BASE_SIZE || - mDetailTextures[i]->getComponents() != 3) + + // *TODO: This isn't quite right for PBR: + // 1) It does not convert the color images from SRGB to linear + // before mixing (which will always require copying the image). + // 2) It mixes emissive and base color before mixing terrain + // materials, but it should be the other way around + // 3) The composite function used to put emissive into base color + // is not an alpha blend. + // Long-term, we should consider a method that is more + // maintainable. Shaders, perhaps? Bake shaders to textures? + LLPointer raw_emissive; + if (tex_emissive) + { + raw_emissive = tex_emissive->getRawImage(); + if (has_emissive_factor || + tex_emissive->getWidth(ddiscard) != BASE_SIZE || + tex_emissive->getHeight(ddiscard) != BASE_SIZE || + tex_emissive->getComponents() != 4) + { + LLPointer newraw_emissive = new LLImageRaw(BASE_SIZE, BASE_SIZE, 4); + // Copy RGB, leave alpha alone (set to opaque by default) + newraw_emissive->copy(mRawImages[i]); + if (has_emissive_factor) + { + newraw_emissive->tint(emissive_factor); + } + raw_emissive = newraw_emissive; // deletes old + } + } + if (has_base_color_factor || + raw_emissive || + tex->getWidth(ddiscard) != BASE_SIZE || + tex->getHeight(ddiscard) != BASE_SIZE || + tex->getComponents() != 3) { LLPointer newraw = new LLImageRaw(BASE_SIZE, BASE_SIZE, 3); // guard against bad alloc here that leads to crash in composite @@ -323,6 +552,15 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y, } // newraw->composite(mRawImages[i]); + if (has_base_color_factor) + { + newraw->tint(base_color_factor); + } + // Apply emissive texture + if (raw_emissive) + { + newraw->composite(raw_emissive); + } mRawImages[i] = newraw; // deletes old } } @@ -344,12 +582,12 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y, if (x_end > mWidth) { - LL_WARNS("Terrain") << "x end > width" << LL_ENDL; + llassert(false); x_end = mWidth; } if (y_end > mWidth) { - LL_WARNS("Terrain") << "y end > width" << LL_ENDL; + llassert(false); y_end = mWidth; } @@ -379,7 +617,7 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y, if (tex_comps != st_comps) { - LL_WARNS("Terrain") << "Base texture comps != input texture comps" << LL_ENDL; + llassert(false); return FALSE; } @@ -470,7 +708,7 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y, } texturep->setSubImage(raw, tex_x_begin, tex_y_begin, tex_x_end - tex_x_begin, tex_y_end - tex_y_begin); - for (S32 i = 0; i < 4; i++) + for (S32 i = 0; i < ASSET_COUNT; i++) { // Un-boost detatil textures (will get re-boosted if rendering in high detail) mDetailTextures[i]->setBoostLevel(LLGLTexture::BOOST_NONE); @@ -480,21 +718,21 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y, return TRUE; } -LLUUID LLVLComposition::getDetailTextureID(S32 corner) -{ - return mDetailTextures[corner]->getID(); -} - -LLViewerFetchedTexture* LLVLComposition::getDetailTexture(S32 corner) -{ - return mDetailTextures[corner]; -} - F32 LLVLComposition::getStartHeight(S32 corner) { return mStartHeight[corner]; } +void LLVLComposition::setDetailAssetID(S32 asset, const LLUUID& id) +{ + if (id.isNull()) + { + return; + } + LLTerrainMaterials::setDetailAssetID(asset, id); + mRawImages[asset] = NULL; +} + void LLVLComposition::setStartHeight(S32 corner, const F32 start_height) { mStartHeight[corner] = start_height; diff --git a/indra/newview/llvlcomposition.h b/indra/newview/llvlcomposition.h index 2dd04ac5a5..d59c0f95bb 100644 --- a/indra/newview/llvlcomposition.h +++ b/indra/newview/llvlcomposition.h @@ -28,11 +28,54 @@ #define LL_LLVLCOMPOSITION_H #include "llviewerlayer.h" -#include "llviewertexture.h" +#include "llpointer.h" + +#include "llimage.h" class LLSurface; -class LLVLComposition : public LLViewerLayer +class LLViewerFetchedTexture; +class LLFetchedGLTFMaterial; + +class LLTerrainMaterials +{ +public: + friend class LLDrawPoolTerrain; + + LLTerrainMaterials(); + virtual ~LLTerrainMaterials(); + + // Heights map into textures (or materials) as 0-1 = first, 1-2 = second, etc. + // So we need to compress heights into this range. + static const S32 ASSET_COUNT = 4; + + enum class Type + { + TEXTURE, + PBR, + COUNT + }; + + BOOL generateMaterials(); + + LLUUID getDetailAssetID(S32 asset); + virtual void setDetailAssetID(S32 asset, const LLUUID& id); + Type getMaterialType(); + BOOL texturesReady(BOOL boost = FALSE); + BOOL materialsReady(BOOL boost = FALSE); + +protected: + static BOOL textureReady(LLPointer& tex, BOOL boost = FALSE); + static BOOL materialReady(LLPointer& mat, bool& textures_set, BOOL boost = FALSE); + LLPointer mDetailTextures[ASSET_COUNT]; + LLPointer mDetailMaterials[ASSET_COUNT]; + bool mMaterialTexturesSet[ASSET_COUNT]; +}; + +// Local materials to override all regions +extern LLTerrainMaterials gLocalTerrainMaterials; + +class LLVLComposition : public LLTerrainMaterials, public LLViewerLayer { public: LLVLComposition(LLSurface *surfacep, const U32 width, const F32 scale); @@ -44,7 +87,11 @@ public: BOOL generateHeights(const F32 x, const F32 y, const F32 width, const F32 height); BOOL generateComposition(); // Generate texture from composition values. - BOOL generateTexture(const F32 x, const F32 y, const F32 width, const F32 height); + BOOL generateMinimapTileLand(const F32 x, const F32 y, const F32 width, const F32 height); + + // Heights map into textures (or materials) as 0-1 = first, 1-2 = second, etc. + // So we need to compress heights into this range. + static const S32 ASSET_COUNT = 4; // Use these as indeces ito the get/setters below that use 'corner' enum ECorner @@ -55,12 +102,11 @@ public: NORTHEAST = 3, CORNER_COUNT = 4 }; - LLUUID getDetailTextureID(S32 corner); - LLViewerFetchedTexture* getDetailTexture(S32 corner); + + void setDetailAssetID(S32 asset, const LLUUID& id) override; F32 getStartHeight(S32 corner); F32 getHeightRange(S32 corner); - void setDetailTextureID(S32 corner, const LLUUID& id); void setStartHeight(S32 corner, F32 start_height); void setHeightRange(S32 corner, F32 range); @@ -68,19 +114,21 @@ public: friend class LLDrawPoolTerrain; void setParamsReady() { mParamsReady = TRUE; } BOOL getParamsReady() const { return mParamsReady; } -protected: - BOOL mParamsReady; - LLSurface *mSurfacep; - BOOL mTexturesLoaded; - LLPointer mDetailTextures[CORNER_COUNT]; - LLPointer mRawImages[CORNER_COUNT]; +protected: + static BOOL textureReady(LLPointer& tex, BOOL boost = FALSE); + static BOOL materialReady(LLPointer& mat, bool& textures_set, BOOL boost = FALSE); + + BOOL mParamsReady = FALSE; + LLSurface *mSurfacep; + + LLPointer mRawImages[LLTerrainMaterials::ASSET_COUNT]; F32 mStartHeight[CORNER_COUNT]; F32 mHeightRange[CORNER_COUNT]; - F32 mTexScaleX; - F32 mTexScaleY; + F32 mTexScaleX = 16.f; + F32 mTexScaleY = 16.f; }; #endif //LL_LLVLCOMPOSITION_H diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp index 42dbc304dd..802f940f5b 100644 --- a/indra/newview/llvosurfacepatch.cpp +++ b/indra/newview/llvosurfacepatch.cpp @@ -39,6 +39,7 @@ #include "llviewerobjectlist.h" #include "llviewerregion.h" #include "llvlcomposition.h" +#include "llvolume.h" #include "llvovolume.h" #include "pipeline.h" #include "llspatialpartition.h" @@ -241,48 +242,50 @@ BOOL LLVOSurfacePatch::updateLOD() return TRUE; } -void LLVOSurfacePatch::getGeometry(LLStrider &verticesp, - LLStrider &normalsp, - LLStrider &texCoords0p, - LLStrider &texCoords1p, - LLStrider &indicesp) +void LLVOSurfacePatch::getTerrainGeometry(LLStrider &verticesp, + LLStrider &normalsp, + LLStrider &texCoords0p, + LLStrider &texCoords1p, + LLStrider &indicesp) { LLFace* facep = mDrawable->getFace(0); - if (facep) - { - U32 index_offset = facep->getGeomIndex(); + if (!facep) + { + return; + } - updateMainGeometry(facep, - verticesp, - normalsp, - texCoords0p, - texCoords1p, - indicesp, - index_offset); - updateNorthGeometry(facep, - verticesp, - normalsp, - texCoords0p, - texCoords1p, - indicesp, - index_offset); - updateEastGeometry(facep, - verticesp, - normalsp, - texCoords0p, - texCoords1p, - indicesp, - index_offset); - } + U32 index_offset = facep->getGeomIndex(); + + updateMainGeometry(facep, + verticesp, + normalsp, + texCoords0p, + texCoords1p, + indicesp, + index_offset); + updateNorthGeometry(facep, + verticesp, + normalsp, + texCoords0p, + texCoords1p, + indicesp, + index_offset); + updateEastGeometry(facep, + verticesp, + normalsp, + texCoords0p, + texCoords1p, + indicesp, + index_offset); } void LLVOSurfacePatch::updateMainGeometry(LLFace *facep, - LLStrider &verticesp, - LLStrider &normalsp, - LLStrider &texCoords0p, - LLStrider &texCoords1p, - LLStrider &indicesp, - U32 &index_offset) + LLStrider &verticesp, + LLStrider &normalsp, + LLStrider &texCoords0p, + LLStrider &texCoords1p, + LLStrider &indicesp, + U32 &index_offset) { S32 i, j, x, y; @@ -381,12 +384,12 @@ void LLVOSurfacePatch::updateMainGeometry(LLFace *facep, void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep, - LLStrider &verticesp, - LLStrider &normalsp, - LLStrider &texCoords0p, - LLStrider &texCoords1p, - LLStrider &indicesp, - U32 &index_offset) + LLStrider &verticesp, + LLStrider &normalsp, + LLStrider &texCoords0p, + LLStrider &texCoords1p, + LLStrider &indicesp, + U32 &index_offset) { S32 i, x, y; @@ -571,12 +574,12 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep, } void LLVOSurfacePatch::updateEastGeometry(LLFace *facep, - LLStrider &verticesp, - LLStrider &normalsp, - LLStrider &texCoords0p, - LLStrider &texCoords1p, - LLStrider &indicesp, - U32 &index_offset) + LLStrider &verticesp, + LLStrider &normalsp, + LLStrider &texCoords0p, + LLStrider &texCoords1p, + LLStrider &indicesp, + U32 &index_offset) { S32 i, x, y; @@ -982,6 +985,49 @@ LLTerrainPartition::LLTerrainPartition(LLViewerRegion* regionp) mPartitionType = LLViewerRegion::PARTITION_TERRAIN; } +// Do not add vertices; honor strict vertex count specified by strider_vertex_count +void gen_terrain_tangents(U16 strider_vertex_count, + U32 strider_index_count, + LLStrider &verticesp, + LLStrider &normalsp, + LLStrider &tangentsp, + LLStrider &texCoords0p, + LLStrider &indicesp) +{ + LL_PROFILE_ZONE_SCOPED + + LLVector4a *vertices = new LLVector4a[strider_vertex_count]; + LLVector4a *normals = new LLVector4a[strider_vertex_count]; + LLVector4a *tangents = new LLVector4a[strider_vertex_count]; + std::vector texcoords(strider_vertex_count); + std::vector indices(strider_index_count); + + for (U16 v = 0; v < strider_vertex_count; ++v) + { + F32 *vert = verticesp[v].mV; + vertices[v] = LLVector4a(vert[0], vert[1], vert[2], 1.f); + F32 *n = normalsp[v].mV; + normals[v] = LLVector4a(n[0], n[1], n[2], 1.f); + tangents[v] = tangentsp[v]; + texcoords[v] = texCoords0p[v]; + } + for (U32 i = 0; i < strider_index_count; ++i) + { + indices[i] = indicesp[i]; + } + + LLCalculateTangentArray(strider_vertex_count, vertices, normals, texcoords.data(), strider_index_count / 3, indices.data(), tangents); + + for (U16 v = 0; v < strider_vertex_count; ++v) + { + tangentsp[v] = tangents[v]; + } + + delete[] vertices; + delete[] normals; + delete[] tangents; +} + void LLTerrainPartition::getGeometry(LLSpatialGroup* group) { LL_PROFILE_ZONE_SCOPED; @@ -989,35 +1035,57 @@ void LLTerrainPartition::getGeometry(LLSpatialGroup* group) LLVertexBuffer* buffer = group->mVertexBuffer; //get vertex buffer striders - LLStrider vertices; - LLStrider normals; - LLStrider texcoords2; - LLStrider texcoords; - LLStrider indices; + LLStrider vertices_start; + LLStrider normals_start; + LLStrider tangents_start; + LLStrider texcoords_start; + LLStrider texcoords2_start; + LLStrider indices_start; - llassert_always(buffer->getVertexStrider(vertices)); - llassert_always(buffer->getNormalStrider(normals)); - llassert_always(buffer->getTexCoord0Strider(texcoords)); - llassert_always(buffer->getTexCoord1Strider(texcoords2)); - llassert_always(buffer->getIndexStrider(indices)); + llassert_always(buffer->getVertexStrider(vertices_start)); + llassert_always(buffer->getNormalStrider(normals_start)); + llassert_always(buffer->getTangentStrider(tangents_start)); + llassert_always(buffer->getTexCoord0Strider(texcoords_start)); + llassert_always(buffer->getTexCoord1Strider(texcoords2_start)); + llassert_always(buffer->getIndexStrider(indices_start)); - U32 indices_index = 0; - U32 index_offset = 0; + U32 indices_index = 0; + U32 index_offset = 0; - for (std::vector::iterator i = mFaceList.begin(); i != mFaceList.end(); ++i) - { - LLFace* facep = *i; + { + LLStrider vertices = vertices_start; + LLStrider normals = normals_start; + LLStrider texcoords = texcoords_start; + LLStrider texcoords2 = texcoords2_start; + LLStrider indices = indices_start; - facep->setIndicesIndex(indices_index); - facep->setGeomIndex(index_offset); - facep->setVertexBuffer(buffer); + for (std::vector::iterator i = mFaceList.begin(); i != mFaceList.end(); ++i) + { + LLFace* facep = *i; - LLVOSurfacePatch* patchp = (LLVOSurfacePatch*) facep->getViewerObject(); - patchp->getGeometry(vertices, normals, texcoords, texcoords2, indices); + facep->setIndicesIndex(indices_index); + facep->setGeomIndex(index_offset); + facep->setVertexBuffer(buffer); - indices_index += facep->getIndicesCount(); - index_offset += facep->getGeomCount(); - } + LLVOSurfacePatch* patchp = (LLVOSurfacePatch*) facep->getViewerObject(); + patchp->getTerrainGeometry(vertices, normals, texcoords, texcoords2, indices); + + indices_index += facep->getIndicesCount(); + index_offset += facep->getGeomCount(); + } + } + + const bool has_tangents = tangents_start.get() != nullptr; + if (has_tangents) + { + LLStrider vertices = vertices_start; + LLStrider normals = normals_start; + LLStrider tangents = tangents_start; + LLStrider texcoords = texcoords_start; + LLStrider indices = indices_start; + + gen_terrain_tangents(index_offset, indices_index, vertices, normals, tangents, texcoords, indices); + } buffer->unmapBuffer(); mFaceList.clear(); diff --git a/indra/newview/llvosurfacepatch.h b/indra/newview/llvosurfacepatch.h index aed67162d1..a3dcb945d1 100644 --- a/indra/newview/llvosurfacepatch.h +++ b/indra/newview/llvosurfacepatch.h @@ -63,11 +63,11 @@ public: /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); /*virtual*/ BOOL updateLOD(); /*virtual*/ void updateFaceSize(S32 idx); - void getGeometry(LLStrider &verticesp, - LLStrider &normalsp, - LLStrider &texCoords0p, - LLStrider &texCoords1p, - LLStrider &indicesp); + void getTerrainGeometry(LLStrider &verticesp, + LLStrider &normalsp, + LLStrider &texCoords0p, + LLStrider &texCoords1p, + LLStrider &indicesp); /*virtual*/ void updateTextures(); /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 320cca897a..cebd96a28c 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -177,6 +177,7 @@ F32 LLPipeline::CameraFocusTransitionTime; F32 LLPipeline::CameraFNumber; F32 LLPipeline::CameraFocalLength; F32 LLPipeline::CameraFieldOfView; +S32 LLPipeline::RenderLocalLightCount; F32 LLPipeline::RenderShadowNoise; F32 LLPipeline::RenderShadowBlurSize; F32 LLPipeline::RenderSSAOScale; @@ -215,6 +216,8 @@ S32 LLPipeline::RenderScreenSpaceReflectionGlossySamples; S32 LLPipeline::RenderBufferVisualization; LLTrace::EventStatHandle LLPipeline::sStatBatchSize("renderbatchsize"); +const U32 LLPipeline::MAX_BAKE_WIDTH = 512; + const F32 BACKLIGHT_DAY_MAGNITUDE_OBJECT = 0.1f; const F32 BACKLIGHT_NIGHT_MAGNITUDE_OBJECT = 0.08f; const F32 ALPHA_BLEND_CUTOFF = 0.598f; @@ -560,6 +563,7 @@ void LLPipeline::init() connectRefreshCachedSettingsSafe("CameraFNumber"); connectRefreshCachedSettingsSafe("CameraFocalLength"); connectRefreshCachedSettingsSafe("CameraFieldOfView"); + connectRefreshCachedSettingsSafe("RenderLocalLightCount"); connectRefreshCachedSettingsSafe("RenderShadowNoise"); connectRefreshCachedSettingsSafe("RenderShadowBlurSize"); connectRefreshCachedSettingsSafe("RenderSSAOScale"); @@ -830,10 +834,13 @@ LLPipeline::eFBOStatus LLPipeline::doAllocateScreenBuffer(U32 resX, U32 resY) bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; - if (mRT == &mMainRT && sReflectionProbesEnabled) + if (mRT == &mMainRT) { // hacky -- allocate auxillary buffer - gCubeSnapshot = TRUE; - mReflectionMapManager.initReflectionMaps(); + if (sReflectionProbesEnabled) + { + gCubeSnapshot = TRUE; + mReflectionMapManager.initReflectionMaps(); + } mRT = &mAuxillaryRT; U32 res = mReflectionMapManager.mProbeResolution * 4; //multiply by 4 because probes will be 16x super sampled allocateScreenBuffer(res, res, samples); @@ -1109,6 +1116,7 @@ void LLPipeline::refreshCachedSettings() CameraFNumber = gSavedSettings.getF32("CameraFNumber"); CameraFocalLength = gSavedSettings.getF32("CameraFocalLength"); CameraFieldOfView = gSavedSettings.getF32("CameraFieldOfView"); + RenderLocalLightCount = gSavedSettings.getS32("RenderLocalLightCount"); RenderShadowNoise = gSavedSettings.getF32("RenderShadowNoise"); RenderShadowBlurSize = gSavedSettings.getF32("RenderShadowBlurSize"); RenderSSAOScale = gSavedSettings.getF32("RenderSSAOScale"); @@ -1174,7 +1182,6 @@ void LLPipeline::releaseGLBuffers() releaseLUTBuffers(); mWaterDis.release(); - mBake.release(); mSceneMap.release(); @@ -1253,12 +1260,6 @@ void LLPipeline::createGLBuffers() stop_glerror(); assertInitialized(); - // Use FBO for bake tex - // Allow higher resolution rendering in mesh render preview - //mBake.allocate(512, 512, GL_RGBA, true); // SL-12781 Build > Upload > Model; 3D Preview - mBake.allocate(1024, 1024, GL_RGBA, true); // SL-12781 Build > Upload > Model; 3D Preview - // - stop_glerror(); GLuint resX = gViewerWindow->getWorldViewWidthRaw(); @@ -5369,7 +5370,7 @@ void LLPipeline::calcNearbyLights(LLCamera& camera) return; } - static LLCachedControl local_light_count(gSavedSettings, "RenderLocalLightCount", 256); + const S32 local_light_count = LLPipeline::RenderLocalLightCount; if (local_light_count >= 1) { @@ -5638,7 +5639,7 @@ void LLPipeline::setupHWLights() mLightMovingMask = 0; - static LLCachedControl local_light_count(gSavedSettings, "RenderLocalLightCount", 256); + const S32 local_light_count = LLPipeline::RenderLocalLightCount; if (local_light_count >= 1) { @@ -6678,7 +6679,7 @@ void LLPipeline::renderAlphaObjects(bool rigged) LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up); LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width); LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(ALPHA_BLEND_CUTOFF); - mSimplePool->pushRiggedGLTFBatch(*pparams, lastAvatar, lastMeshId); + LLRenderPass::pushRiggedGLTFBatch(*pparams, lastAvatar, lastMeshId); } else { @@ -6704,7 +6705,7 @@ void LLPipeline::renderAlphaObjects(bool rigged) LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up); LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width); LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(ALPHA_BLEND_CUTOFF); - mSimplePool->pushGLTFBatch(*pparams); + LLRenderPass::pushGLTFBatch(*pparams); } else { @@ -8145,7 +8146,7 @@ void LLPipeline::renderDeferredLighting() unbindDeferredShader(gDeferredSoftenProgram); } - static LLCachedControl local_light_count(gSavedSettings, "RenderLocalLightCount", 256); + const S32 local_light_count = LLPipeline::RenderLocalLightCount; if (local_light_count > 0) { diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 2d58da8fb5..035bc73936 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -707,6 +707,7 @@ public: RenderTargetPack mMainRT; // auxillary 512x512 render target pack + // used by reflection probes and dynamic texture bakes RenderTargetPack mAuxillaryRT; // currently used render target pack @@ -767,7 +768,7 @@ public: //water distortion texture (refraction) LLRenderTarget mWaterDis; - LLRenderTarget mBake; + static const U32 MAX_BAKE_WIDTH; //texture for making the glow LLRenderTarget mGlow[3]; @@ -1038,6 +1039,7 @@ public: static F32 CameraFNumber; static F32 CameraFocalLength; static F32 CameraFieldOfView; + static S32 RenderLocalLightCount; static F32 RenderShadowNoise; static F32 RenderShadowBlurSize; static F32 RenderSSAOScale; diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index ad6f4446dc..c648bdf226 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -4139,7 +4139,7 @@ Are you sure you want to return objects owned by [USER_NAME]? Could not set region textures: Terrain texture [TEXTURE_NUM] has an invalid bit depth of [TEXTURE_BIT_DEPTH]. -Replace texture [TEXTURE_NUM] with a 24-bit [MAX_SIZE]x[MAX_SIZE] or smaller image then click "Apply" again. +Replace texture [TEXTURE_NUM] with an RGB [MAX_SIZE]x[MAX_SIZE] or smaller image then click "Apply" again. fail @@ -4150,7 +4150,7 @@ Replace texture [TEXTURE_NUM] with a 24-bit [MAX_SIZE]x[MAX_SIZE] or smaller ima Could not set region textures: Terrain texture [TEXTURE_NUM] is too large at [TEXTURE_SIZE_X]x[TEXTURE_SIZE_Y]. -Replace texture [TEXTURE_NUM] with a 24-bit [MAX_SIZE]x[MAX_SIZE] or smaller image then click "Apply" again. +Replace texture [TEXTURE_NUM] with an RGB [MAX_SIZE]x[MAX_SIZE] or smaller image then click "Apply" again. + + + + - Terrain Textures (1024x1024, 24 bit .tga files) + width="200"> + Maximum size: 1024x1024 + + + +