diff --git a/autobuild.xml b/autobuild.xml index ffdb4981c3..e474620aaf 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1934,6 +1934,18 @@ mikktspace + canonical_repo + https://bitbucket.org/lindenlab/3p-mikktspace + copyright + Copyright (C) 2011 by Morten S. Mikkelsen, Copyright (C) 2022 Blender Authors + description + Mikktspace Tangent Generator + license + Apache 2.0 + license_file + mikktspace.txt + name + mikktspace platforms darwin64 @@ -1941,58 +1953,46 @@ archive hash - 6cc1585dba85b0226a2e7033a7e2a2ceaae7c983 + 65edf85c36a10001e32bdee582bec4732137208b hash_algorithm sha1 url - https://github.com/secondlife/3p-mikktspace/releases/download/v1-5cee1f4/mikktspace-1-darwin64-5cee1f4.tar.zst + https://github.com/secondlife/3p-mikktspace/releases/download/v2-e967e1b/mikktspace-1-darwin64-8756084692.tar.zst name darwin64 - windows64 - - archive - - hash - 6b7d01ad54e4a88a001f66840c32329cedb28202 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-mikktspace/releases/download/v1-5cee1f4/mikktspace-1-windows64-5cee1f4.tar.zst - - name - windows64 - linux64 archive hash - edc9782bf209e17ad1845498b42f16d733582082 + fa9dcee4584df7e7271fdf69c08e6fd3122a47fc hash_algorithm sha1 url - https://github.com/secondlife/3p-mikktspace/releases/download/v1-5cee1f4/mikktspace-1-linux64-5cee1f4.tar.zst + https://github.com/secondlife/3p-mikktspace/releases/download/v2-e967e1b/mikktspace-1-linux64-8756084692.tar.zst name linux64 + windows64 + + archive + + hash + 130b33a70bdb3a8a188376c6a91840bdb61380a8 + hash_algorithm + sha1 + url + https://github.com/secondlife/3p-mikktspace/releases/download/v2-e967e1b/mikktspace-1-windows64-8756084692.tar.zst + + name + windows64 + - license - Copyright (C) 2011 by Morten S. Mikkelsen - license_file - mikktspace.txt - copyright - Copyright (C) 2011 by Morten S. Mikkelsen version 1 - name - mikktspace - canonical_repo - https://bitbucket.org/lindenlab/3p-mikktspace - description - Mikktspace Tangent Generator minizip-ng @@ -3175,6 +3175,46 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors description zlib data compression library for the next generation systems + tinyexr + + platforms + + common + + archive + + hash + 8278a2368136cb12319ca00e7aceb2829bf3ebd8 + hash_algorithm + sha1 + url + https://github.com/secondlife/3p-tinyexr/releases/download/v1.0.8-ba4bc64/tinyexr-v1.0.8-common-9373975608.tar.zst + + name + common + + + license + 3-clause BSD + license_file + LICENSES/tinyexr_license.txt + copyright + Copyright (c) 2014 - 2021, Syoyo Fujita and many contributors. + version + v1.0.8 + name + tinyexr + vcs_branch + dependabot/github_actions/secondlife/action-autobuild-4 + vcs_revision + 4dc4d1d90d82a22843e2adf5130f9ecb5ee5769e + vcs_url + https://github.com/secondlife/3p-tinyexr + description + tinyexr import library + source_type + git + package_description diff --git a/doc/contributions.txt b/doc/contributions.txt index ed1db26203..5c338493c3 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -248,6 +248,7 @@ Ansariel Hiller SL-4126 SL-20224 SL-20524 + secondlife/viewer#1051 Aralara Rajal Arare Chantilly CHUIBUG-191 diff --git a/doc/testplans/RenderMaxTextureResolution.md b/doc/testplans/RenderMaxTextureResolution.md new file mode 100644 index 0000000000..2b117050c7 --- /dev/null +++ b/doc/testplans/RenderMaxTextureResolution.md @@ -0,0 +1,16 @@ +The Setting RenderMaxTextureResolution controls the maximum resolution of non-boosted textures as displayed by the viewer. + +Valid values are 512-2048 (clamped in C++). + +![image](https://github.com/secondlife/viewer/assets/23218274/d0f889fc-8135-41d2-9d83-871ad4eebed5) + +![image](https://github.com/secondlife/viewer/assets/23218274/19950828-7eb1-4bb2-85d7-f35c63b34294) + +![image](https://github.com/secondlife/viewer/assets/23218274/249afc83-4de6-488d-a05e-4877d08573b1) + +Test Asset available on beta grid: +Object: 'Damaged Helmet', AssetID 0623e759-11b5-746c-a75e-7ba1caa6eb0e + + + + diff --git a/doc/testplans/hdri_local_preview.md b/doc/testplans/hdri_local_preview.md new file mode 100644 index 0000000000..ba4f085100 --- /dev/null +++ b/doc/testplans/hdri_local_preview.md @@ -0,0 +1,21 @@ +A resident may swap out their sky for an EXR format HDRI for the purposes of previewing how their object would render in Second Life in an environment that matches the supplied HDRI. This should aid in matching inworld lighting with external tools so artists can know if their content has imported properly. + +To load an HDRI, click Develop->Render Tests->HDRI Preview: + +![image](https://github.com/secondlife/viewer/assets/23218274/fbdeab5f-dc1f-4406-be19-0c9ee7437b3f) + +Choose an EXR image. A library of publicly available HDRIs can be found here: https://polyhaven.com/hdris + +The Personal Lighting floater will open, and the sky will be replaced with the HDRI you chose. Reflection Probes will reset, and the scene will be illuminated by the HDRI. + +Three debug settings affect how the HDRI is displayed: + +RenderHDRIExposure - Exposure adjustment of HDRI when previewing an HDRI. Units are EV. Sane values would be -10 to 10. +RenderHDRIRotation - Rotation (in degrees) of environment when previewing an HDRI. +RenderHDRISplitScreen - What percentage of screen to render using HDRI vs EEP sky. + +Exposure and Rotation should behave similarly to the rotation and exposure controls in Substance Painter. + +Split Screen can be used to display an EEP sky side-by-side with an HDRI sky to aid in authoring an EEP sky that matches an HDRI sky. It is currently expected that EEP sun disc, moon, clouds, and stars do not render when previewing an HDRI, but that may change in the future. + + diff --git a/doc/testplans/material_preview.md b/doc/testplans/material_preview.md new file mode 100644 index 0000000000..6d2768f72a --- /dev/null +++ b/doc/testplans/material_preview.md @@ -0,0 +1,83 @@ +# Material Preview + +## Overview + +Material preview is a UI feature which displays a lit spherical preview of a PBR material. It can be found in the following UIs: + +- The material picker swatch + - In the build floater, in the Texture tab, when applying a PBR material + - (If the feature is enabled) In the Region/Estate floater, in the Terrain tab, when applying PBR materials to terrain +- In the floater to select a material from inventory, which can be opened by clicking the material picker swatch + +## Known Issues + +These are known issues that the current implementation of this feature does not address: + +- The material preview in the build floater is a preview of the base material ID only, and ignores other properties on the prim face like material overrides (https://github.com/secondlife/viewer/issues/865) +- Alpha mask previews as alpha blend (https://github.com/secondlife/viewer/issues/866) +- Double-sided previews as single-sided (https://github.com/secondlife/viewer/issues/867) +- Material preview inherits some of its lighting from the current environment, and reflections from the default reflection probe (https://github.com/secondlife/viewer/issues/868) + +## General Regression Testing + +- Check that the material preview swatch looks OK with different materials selected +- Check that the material preview swatch runs reasonably well on different systems, especially when the select material from inventory floater is also open + - In particular: AMD, MacOS, minimum spec machines +- Watch out for regressions in rendering caused by opening a floater with a material preview swatch + +## Bug Fixes + +### Disappearing Objects Fix Test + +This test is recommended for verifying that https://github.com/secondlife/viewer-issues/issues/72 is fixed. + +#### Symptoms + +When the bug occurs, one or more of following types of objects could randomly disappear in the world, permanently until relog: + +- Objects +- Water level in current region +- Adjacent region/void water + +Note: Disappearing objects in reflections have a different root cause and are not covered by the fix. + +#### Bug Reproduction Steps + +Verify the disappearing objects bug does not reproduce, given the following steps: + +- Runtime prerequisites: Material preview swatch may not be available in your viewer or region if this feature is still behind a feature flag. It is safe to enable this feature manually by setting, "UIPreviewMaterial" to True in the advanced settings. The setting will persist for the current session. +- Region prerequisites: Unknown, but a region with lots of objects in it seems to increase repro rate. The following locations have been known to easily reproduce the bug, as of 2024-02-16: + - http://maps.secondlife.com/secondlife/LindenWorld%20B/161/75/47 + - [secondlife://Aditi/secondlife/Rumpus%20Room%202048/128/128/24](secondlife://Aditi/secondlife/Rumpus%20Room%202048/128/128/24) +- Right click an object and select, "Edit item" +- Go to texture tab, select PBR Metallic Roughness from dropdown, and click the button to select material from inventory +- Ensure "Apply now" is checked in the inventory selection floater +- Alternate between different materials from the inventory selection floater +- Look around the world and check for permanently disappeared objects. + +### Dynamic Exposure Influence Fix Test + +This test is recommended for verifying that https://github.com/secondlife/viewer-issues/issues/72 is fixed. + +#### Symptoms + +Dynamic exposure in the world could be influenced by the material preview being displayed. If a material preview was being generated in a given frame, then, depending on the current environment, the user would observe an unpleasant flashing effect in the environment: + +- The world view could suddenly get darker and then fade back to normal exposure levels +- The world view could suddenly get brighter and then fade back to normal exposure levels + +#### Bug Reproduction Steps + +Verify the dynamic exposure influence bug does not reproduce. Test using a few environment presets such as Default Midday, Sunset, and Midnight. + +- Right click an object and select, "Edit item" +- Go to texture tab, select PBR Metallic Roughness from dropdown, and click the button to select material from inventory +- Alternate between different materials from the inventory selection floater + +#### Regression Testing + +Dynamic exposure in the world should continue to work correctly. In particular: + +- Exposure should fade gradually from high exposure to low exposure and back as needed +- Exposure should decrease in brighter environments +- Exposure should increase in darker environments diff --git a/doc/testplans/pbr_terrain_appearance.md b/doc/testplans/pbr_terrain_appearance.md new file mode 100644 index 0000000000..f6d54029b5 --- /dev/null +++ b/doc/testplans/pbr_terrain_appearance.md @@ -0,0 +1,37 @@ +# PBR Terrain Appearance + +## Tiling + +The southwest corner of a region with PBR materials should exactly match up with the bottom left corner of the material texture(s). + +If two adjacent regions have the same PBR terrain settings, then: + +- There should not be seams between the two regions at their shared border +- The ground should not suddenly slide beneath the avatar when moving between regions (except due to movement of the avatar, which is not covered by this test plan) + +## Feature Gating + +PBR terrain should have lower detail on lower graphics settings. PBR terrain will also not show emissive textures on some machines (like Macs) which do not support more than 16 textures. + +### Triplanar Mapping + +Triplanar mapping improves the texture repeats on the sides of terrain slopes. + +Availability of Triplanar mapping: + +- Medium-High and below: No triplanar mapping +- High and above: Triplanar mapping + +### PBR Textures + +At the highest graphics support level, PBR terrain supports all PBR textures. + +Availability of PBR textures varies by machine and graphics setting: + +- Low: Base color only (looks similar to texture terrain) +- Medium-Low, and machines that do not support greater than 16 textures such as Macs: All PBR textures enabled except emissive textures. +- Medium: All PBR textures enabled + +### PBR Alpha + +PBR terrain does not support materials with alpha blend or double-sided. In addition, the viewer does not make any guarantees about what will render behind the terrain if alpha is used. diff --git a/doc/testplans/pbr_terrain_composition.md b/doc/testplans/pbr_terrain_composition.md new file mode 100644 index 0000000000..aadd97a94b --- /dev/null +++ b/doc/testplans/pbr_terrain_composition.md @@ -0,0 +1,76 @@ +# PBR Terrain Composition + +## Feature Availability + +PBR Terrain is visible for all viewers with the PBR Terrain feature, regardless of if the feature flag is enabled. + +There is only one set of four asset IDs applied to the terrain. In other words, unlike PBR materials on prims, there is no fallback texture set for viewers that do not support PBR terrain. Viewers without support will view terrain as blank (solid grey or white). + +## Editing Terrain Composition + +All tests in this section assume the PBR terrain feature flag is enabled, and that the user has appropriate permissions to modify the terrain textures. + +### Feature Availability + +On the client, the advanced setting `RenderTerrainPBREnabled` is the PBR terrain feature flag. + +The PBR terrain feature flag should be set automatically when logging in/teleporting to a new region. + +- The flag should be enabled on regions where the PBR terrain feature is enabled +- Otherwise the flag should be disabled + +When the PBR terrain feature flag is disabled: + +- The "PBR Metallic Roughness" checkbox should not be visible +- The user should not be able to apply PBR terrain to the region, only textures. + +When the PBR terrain feature flag is enabled: + +- The "PBR Metallic Roughness" checkbox should be visible +- The user should be able to apply PBR terrain or textures to the region, depending on if the "PBR Metallic Roughness" checkbox is checked. + +### Current Composition Type + +When the Region/Estate floater is opened to the terrain Tab, the current terrain should be shown in the four swatches, and the "PBR Metallic Roughness" checkbox should be checked or unchecked accordingly. + +- If it is texture terrain, the "PBR Metallic Roughness" checkbox should be unchecked, and the floater should display the four textures applied to the terrain. +- If it is material terrain, the "PBR Metallic Roughness" checkbox should be checked, and the floater should display the four materials applied to the terrain. + +In addition, where possible, textual labels and descriptions in the tab should make sense given the current value of the "PBR Metallic Roughness" checkbox. If the checkbox is unchecked, the labels should refer to textures. If the checkbox is checked, the labels should refer to materials. + +### Toggling Composition Type + +When toggling the "PBR Metallic Roughness" checkbox to the opposite value, which does not correspond to the current terrain type, one of the following sets of four terrain swatches will be displayed: + +- The default textures/materials + - For textures, this is the default terrain texture set + - For materials, this is all blank materials, but this is subject to change +- The previously applied texture/material set + - History is available on a best-effort basis only. In particular, the history does not persist on viewer restart. + +When toggling back the "PBR Metallic Roughness" checkbox to the original value, assuming nothing else has changed, then the current terrain should be shown in the four swatches again. + +### Saving Composition + +A user with appropriate permissions can change and save the textures or materials to the terrain. If the "PBR Metallic Roughness" checkbox is checked, the user applies materials, otherwise the user applies textures. + +The user should not be allowed to set the texture or material swatches to null. + +Saving may fail for the following reasons: + +- A terrain or material texture is invalid +- A terrain texture is greater than the max texture upload resolution + +If saving the terrain fails for any reason, the terrain should not be updated. + +Unlike a viewer without PBR terrain support, the new viewer will no longer treat textures with alpha channels as invalid. + +## Graphics Features + +Texture terrain with transparency is not permitted to be applied in the viewer. + +See [PBR Terrain Appearance](./pbr_terrain_appearance.md) for supported PBR terrain features. + +## Minimap + +The minimap should display the terrain with appropriate textures and colors. diff --git a/doc/testplans/terrain_loading.md b/doc/testplans/terrain_loading.md new file mode 100644 index 0000000000..c1b170fcf8 --- /dev/null +++ b/doc/testplans/terrain_loading.md @@ -0,0 +1,29 @@ +# Terrain Loading + +## Behavior overview + +- Texture terrain should load if textures are applied to the region, and no PBR Metallic Roughness materials are applied. +- PBR terrain should load if PBR materials are applied to the region, even if the RenderTerrainPBREnabled feature flag is disabled in debug settings. This setting only disables the display of PBR materials in the Region / Estate > Terrain UI. +- Related subsystem: A change to the PBR terrain loading system may affect the texture terrain loading system and vice-versa +- Related subsystem: Minimap should load if terrain loads + - They may not finish loading at the same time + +## Implementation details + +This section is provided mainly for clarification of how the terrain loading system works. + +The simulator sends 4 terrain composition UUIDs to the viewer for the region. The viewer does not know ahead-of-time if the terrain composition uses textures or materials. Therefore, to expedite terrain loading, the viewer makes up to 8 "top-level" asset requests simultaneously: + +- Up to 4 texture asset requests, one for each UUID +- Up to 4 material asset requests, one for each UUID + +It is therefore expected that half of these asset lookups will fail. + +The viewer inspects the load success of these top-level assets to make the binary decision of whether to render all 4 texture assets or all 4 material assets. This determines the choice of composition for terrain both in-world and on the minimap. + +The minimap also attempts to wait for textures to partially load before it can render a tile for a given region: + +- When rendering texture terrain, the minimap attempts to wait for top-level texture assets to partially load +- When rendering PBR material terrain, the minimap attempts to wait for any base color/emissive textures in the materials to partially load, if they are present + +We don't make guarantees that the minimap tile will render for the region if any aforementioned required textures/materials fail to sufficiently load. However, the minimap may make a best-effort attempt to render the region by ignoring or replacing data. diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 171e94ff34..69d8332ced 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -55,6 +55,8 @@ set(cmake_SOURCE_FILES PulseAudio.cmake Python.cmake TemplateCheck.cmake + TinyEXR.cmake + TinyGLTF.cmake Tut.cmake UI.cmake UnixInstall.cmake diff --git a/indra/cmake/TinyEXR.cmake b/indra/cmake/TinyEXR.cmake new file mode 100644 index 0000000000..e6d142d19d --- /dev/null +++ b/indra/cmake/TinyEXR.cmake @@ -0,0 +1,7 @@ +# -*- cmake -*- +include(Prebuilt) + +use_prebuilt_binary(tinyexr) + +set(TINYEXR_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tinyexr) + diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index f588f1c060..e265daab2e 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -484,21 +484,69 @@ void LLAvatarAppearance::computeBodySize() mCurrBodySizeState["mAnkleLeft scale"] = mAnkleLeftp->getScale(); mCurrBodySizeState["mFootLeft pos"] = mFootLeftp->getPosition(); - F32 old_height = mBodySize.mV[VZ]; + LLVector3 pelvis_scale = mPelvisp->getScale(); + + // some of the joints have not been cached + LLVector3 skull = mSkullp->getPosition(); + //LLVector3 skull_scale = mSkullp->getScale(); + + LLVector3 neck = mNeckp->getPosition(); + LLVector3 neck_scale = mNeckp->getScale(); + + LLVector3 chest = mChestp->getPosition(); + LLVector3 chest_scale = mChestp->getScale(); + + // the rest of the joints have been cached + LLVector3 head = mHeadp->getPosition(); + LLVector3 head_scale = mHeadp->getScale(); + + LLVector3 torso = mTorsop->getPosition(); + LLVector3 torso_scale = mTorsop->getScale(); + + LLVector3 hip = mHipLeftp->getPosition(); + LLVector3 hip_scale = mHipLeftp->getScale(); + + LLVector3 knee = mKneeLeftp->getPosition(); + LLVector3 knee_scale = mKneeLeftp->getScale(); + + LLVector3 ankle = mAnkleLeftp->getPosition(); + LLVector3 ankle_scale = mAnkleLeftp->getScale(); + + LLVector3 foot = mFootLeftp->getPosition(); + F32 old_offset = mAvatarOffset.mV[VZ]; - // TODO: Measure the real depth and width - mPelvisToFoot = computePelvisToFoot(); - F32 new_height = computeBodyHeight(); - mBodySize.set(DEFAULT_AGENT_DEPTH, DEFAULT_AGENT_WIDTH, new_height); // [RLVa:KB] - Checked: 2013-03-03 (RLVa-1.4.8) - F32 new_offset = getAvatarOffset(); + mAvatarOffset.mV[VZ] = getAvatarOffset(); // [/RLVa:KB] -// F32 new_offset = getVisualParamWeight(AVATAR_HOVER); - mAvatarOffset.set(0, 0, new_offset); +// mAvatarOffset.mV[VZ] = getVisualParamWeight(AVATAR_HOVER); - if (mBodySize.mV[VZ] != old_height || new_offset != old_offset) + mPelvisToFoot = hip.mV[VZ] * pelvis_scale.mV[VZ] - + knee.mV[VZ] * hip_scale.mV[VZ] - + ankle.mV[VZ] * knee_scale.mV[VZ] - + foot.mV[VZ] * ankle_scale.mV[VZ]; + + LLVector3 new_body_size; + new_body_size.mV[VZ] = mPelvisToFoot + + // the sqrt(2) correction below is an approximate + // correction to get to the top of the head + F_SQRT2 * (skull.mV[VZ] * head_scale.mV[VZ]) + + head.mV[VZ] * neck_scale.mV[VZ] + + neck.mV[VZ] * chest_scale.mV[VZ] + + chest.mV[VZ] * torso_scale.mV[VZ] + + torso.mV[VZ] * pelvis_scale.mV[VZ]; + + // TODO -- measure the real depth and width + new_body_size.mV[VX] = DEFAULT_AGENT_DEPTH; + new_body_size.mV[VY] = DEFAULT_AGENT_WIDTH; + + mAvatarOffset.mV[VX] = 0.0f; + mAvatarOffset.mV[VY] = 0.0f; + + if (new_body_size != mBodySize || old_offset != mAvatarOffset.mV[VZ]) { + mBodySize = new_body_size; + // [Legacy Bake] bodySizeChanged(); @@ -506,29 +554,6 @@ void LLAvatarAppearance::computeBodySize() } } -F32 LLAvatarAppearance::computeBodyHeight() -{ - F32 result = mPelvisToFoot + - // all these relative positions usually are positive - mPelvisp->getScale().mV[VZ] * mTorsop->getPosition().mV[VZ] + - mTorsop->getScale().mV[VZ] * mChestp->getPosition().mV[VZ] + - mChestp->getScale().mV[VZ] * mNeckp->getPosition().mV[VZ] + - mNeckp->getScale().mV[VZ] * mHeadp->getPosition().mV[VZ] + - mHeadp->getScale().mV[VZ] * mSkullp->getPosition().mV[VZ] * 2; - return result; -} - -F32 LLAvatarAppearance::computePelvisToFoot() -{ - F32 result = - // all these relative positions usually are negative - mPelvisp->getScale().mV[VZ] * mHipLeftp->getPosition().mV[VZ] + - mHipLeftp->getScale().mV[VZ] * mKneeLeftp->getPosition().mV[VZ] + - mKneeLeftp->getScale().mV[VZ] * mAnkleLeftp->getPosition().mV[VZ] + - mAnkleLeftp->getScale().mV[VZ] * mFootLeftp->getPosition().mV[VZ] / 2; - return -result; -} - // [RLVa:KB] - Checked: 2013-03-03 (RLVa-1.4.8) F32 LLAvatarAppearance::getAvatarOffset() /*const*/ { diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index 434b9a4c2e..3617ce2bb6 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -153,8 +153,6 @@ public: void compareJointStateMaps(joint_state_map_t& last_state, joint_state_map_t& curr_state); void computeBodySize(); - F32 computeBodyHeight(); - F32 computePelvisToFoot(); public: typedef std::vector avatar_joint_list_t; diff --git a/indra/llcommon/indra_constants.cpp b/indra/llcommon/indra_constants.cpp index d24a221671..329dfcbe37 100644 --- a/indra/llcommon/indra_constants.cpp +++ b/indra/llcommon/indra_constants.cpp @@ -89,3 +89,4 @@ const LLUUID IMG_USE_BAKED_AUX1 ("9742065b-19b5-297c-858a-29711d539043"); const LLUUID IMG_USE_BAKED_AUX2 ("03642e83-2bd1-4eb9-34b4-4c47ed586d2d"); const LLUUID IMG_USE_BAKED_AUX3 ("edd51b77-fc10-ce7a-4b3d-011dfc349e4f"); +const LLUUID BLANK_MATERIAL_ASSET_ID ("968cbad0-4dad-d64e-71b5-72bf13ad051a"); diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index d776a06da1..0899fb6372 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -240,6 +240,8 @@ LL_COMMON_API extern const LLUUID DEFAULT_OBJECT_SPECULAR; LL_COMMON_API extern const LLUUID DEFAULT_OBJECT_NORMAL; LL_COMMON_API extern const LLUUID BLANK_OBJECT_NORMAL; +LL_COMMON_API extern const LLUUID BLANK_MATERIAL_ASSET_ID; + // radius within which a chat message is fully audible const F32 CHAT_NORMAL_RADIUS = 20.f; diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index aa8eca7d90..8612f9353f 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-06-03 * @brief Implementation for llcoros. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, 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$ */ diff --git a/indra/llcommon/llstrider.h b/indra/llcommon/llstrider.h index 6c76ab8104..06cf8d3480 100644 --- a/indra/llcommon/llstrider.h +++ b/indra/llcommon/llstrider.h @@ -37,8 +37,8 @@ template class LLStrider }; U32 mSkip; public: - LLStrider() { mObjectp = NULL; mSkip = sizeof(Object); } + LLStrider(Object* first) { mObjectp = first; mSkip = sizeof(Object); } ~LLStrider() { } const LLStrider& operator = (Object *first) { mObjectp = first; return *this;} diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 5f7655279e..f175436299 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" @@ -1022,6 +1023,28 @@ void LLImageRaw::verticalFlip() } +bool LLImageRaw::checkHasTransparentPixels() +{ + if (getComponents() != 4) + { + return false; + } + + U8* data = getData(); + U32 pixels = getWidth() * getHeight(); + + // check alpha channel for all 255 + for (U32 i = 0; i < pixels; ++i) + { + if (data[i * 4 + 3] != 255) + { + return true; + } + } + + return false; +} + bool LLImageRaw::optimizeAwayAlpha() { LLImageDataLock lock(this); @@ -1061,6 +1084,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) { LLImageDataLock lock(this); @@ -1156,7 +1207,7 @@ void LLImageRaw::composite( const 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() ) @@ -1345,6 +1396,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) @@ -1895,6 +1970,73 @@ void LLImageRaw::compositeRowScaled4onto3( const U8* in, U8* out, S32 in_pixel_l } } + +void LLImageRaw::addEmissive(LLImageRaw* src) +{ + LLImageRaw* dst = this; // Just for clarity. + + if (!validateSrcAndDst(__FUNCTION__, src, dst)) + { + return; + } + + llassert((3 == src->getComponents()) || (4 == src->getComponents())); + llassert(3 == dst->getComponents()); + + if( 3 == dst->getComponents() ) + { + if( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ) + { + addEmissiveUnscaled(src); + } + else + { + addEmissiveScaled(src); + } + } +} + +void LLImageRaw::addEmissiveUnscaled(LLImageRaw* src) +{ + LLImageRaw* dst = this; // Just for clarity. + + llassert((3 == src->getComponents()) || (4 == src->getComponents())); + llassert((3 == dst->getComponents()) || (4 == dst->getComponents())); + llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ); + + U8* const src_data = src->getData(); + U8* const dst_data = dst->getData(); + for(S32 y = 0; y < dst->getHeight(); ++y) + { + const S32 src_row_offset = src->getComponents() * src->getWidth() * y; + const S32 dst_row_offset = dst->getComponents() * dst->getWidth() * y; + for (S32 x = 0; x < dst->getWidth(); ++x) + { + const S32 src_offset = src_row_offset + (x * src->getComponents()); + const S32 dst_offset = dst_row_offset + (x * dst->getComponents()); + U8* const src_pixel = src_data + src_offset; + U8* const dst_pixel = dst_data + dst_offset; + dst_pixel[0] = llmin(255, dst_pixel[0] + src_pixel[0]); + dst_pixel[1] = llmin(255, dst_pixel[1] + src_pixel[1]); + dst_pixel[2] = llmin(255, dst_pixel[2] + src_pixel[2]); + } + } +} + +void LLImageRaw::addEmissiveScaled(LLImageRaw* src) +{ + LLImageRaw* dst = this; // Just for clarity. + + llassert( (4 == src->getComponents()) && (3 == dst->getComponents()) ); + + LLImageRaw temp(dst->getWidth(), dst->getHeight(), dst->getComponents()); + llassert_always(temp.getDataSize() > 0); + temp.copyScaled(src); + + dst->addEmissiveUnscaled(&temp); +} + + // static bool LLImageRaw::validateSrcAndDst(std::string func, const LLImageRaw* src, const LLImageRaw* dst) { diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index d86742ab8c..f79c4ed217 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 ( const S32 MAX_NB_LAYERS = 64; // Max number of layers we'll entertain in SL (practical limit) const S32 MIN_IMAGE_SIZE = (1< 1. @@ -279,6 +287,12 @@ public: // Src and dst can be any size. Src and dst can each have 3 or 4 components. void composite( const LLImageRaw* src ); + // Emissive operations used by minimap + // Roughly emulates GLTF emissive texture, but is not GLTF-compliant + // *TODO: Remove in favor of shader + void addEmissive(LLImageRaw* src); + void addEmissiveScaled(LLImageRaw* src); + void addEmissiveUnscaled(LLImageRaw* src); protected: // Src and dst can be any size. Src has 4 components. Dst has 3 components. void compositeScaled4onto3( const LLImageRaw* src ); diff --git a/indra/llimage/llimagedxt.cpp b/indra/llimage/llimagedxt.cpp index 6b960f9077..1e60713b6d 100644 --- a/indra/llimage/llimagedxt.cpp +++ b/indra/llimage/llimagedxt.cpp @@ -451,7 +451,7 @@ bool LLImageDXT::convertToDXR() if (!newdata) { LLError::LLUserWarningMsg::showOutOfMemory(); - LL_ERRS() << "Out of memory in LLImageDXT::convertToDXR()" << LL_ENDL; + LL_WARNS() << "Out of memory in LLImageDXT::convertToDXR()" << LL_ENDL; return false; } llassert(total_bytes > 0); diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp index 2820785079..5197590edf 100644 --- a/indra/llinventory/llsettingssky.cpp +++ b/indra/llinventory/llsettingssky.cpp @@ -411,7 +411,6 @@ LLSettingsSky::LLSettingsSky(const LLSD &data) : mNextRainbowTextureId(), mNextHaloTextureId() { - mCanAutoAdjust = !data.has(SETTING_REFLECTION_PROBE_AMBIANCE); } LLSettingsSky::LLSettingsSky(): @@ -434,8 +433,6 @@ void LLSettingsSky::replaceSettings(LLSD settings) mNextBloomTextureId.setNull(); mNextRainbowTextureId.setNull(); mNextHaloTextureId.setNull(); - - mCanAutoAdjust = !settings.has(SETTING_REFLECTION_PROBE_AMBIANCE); } void LLSettingsSky::replaceWithSky(LLSettingsSky::ptr_t pother) @@ -448,7 +445,6 @@ void LLSettingsSky::replaceWithSky(LLSettingsSky::ptr_t pother) mNextBloomTextureId = pother->mNextBloomTextureId; mNextRainbowTextureId = pother->mNextRainbowTextureId; mNextHaloTextureId = pother->mNextHaloTextureId; - mCanAutoAdjust = pother->mCanAutoAdjust; } void LLSettingsSky::blend(const LLSettingsBase::ptr_t &end, F64 blendf) @@ -1150,7 +1146,6 @@ void LLSettingsSky::setSkyIceLevel(F32 ice_level) void LLSettingsSky::setReflectionProbeAmbiance(F32 ambiance) { - mCanAutoAdjust = false; // we've now touched this sky in a "new" way, it can no longer auto adjust setValue(SETTING_REFLECTION_PROBE_AMBIANCE, ambiance); } @@ -1452,24 +1447,6 @@ F32 LLSettingsSky::getReflectionProbeAmbiance(bool auto_adjust) const return mSettings[SETTING_REFLECTION_PROBE_AMBIANCE].asReal(); } -F32 LLSettingsSky::getTotalReflectionProbeAmbiance(F32 cloud_shadow_scale, bool auto_adjust) const -{ -#if 0 - // feed cloud shadow back into reflection probe ambiance to mimic pre-reflection-probe behavior - // without brightening dark/interior spaces - F32 probe_ambiance = getReflectionProbeAmbiance(auto_adjust); - - if (probe_ambiance > 0.f && probe_ambiance < 1.f) - { - probe_ambiance += (1.f - probe_ambiance) * getCloudShadow() * cloud_shadow_scale; - } - - return probe_ambiance; -#else - return getReflectionProbeAmbiance(auto_adjust); -#endif -} - F32 LLSettingsSky::getSkyBottomRadius() const { return mSettings[SETTING_SKY_BOTTOM_RADIUS].asReal(); @@ -1814,3 +1791,8 @@ LLUUID LLSettingsSky::getNextBloomTextureId() const return mNextBloomTextureId; } +// if true, this sky is a candidate for auto-adjustment +bool LLSettingsSky::canAutoAdjust() const +{ + return !mSettings.has(SETTING_REFLECTION_PROBE_AMBIANCE); +} diff --git a/indra/llinventory/llsettingssky.h b/indra/llinventory/llsettingssky.h index 8aade96484..222ab040cb 100644 --- a/indra/llinventory/llsettingssky.h +++ b/indra/llinventory/llsettingssky.h @@ -62,7 +62,7 @@ public: static const std::string SETTING_DOME_OFFSET; static const std::string SETTING_DOME_RADIUS; static const std::string SETTING_GAMMA; - static const std::string SETTING_GLOW; + static const std::string SETTING_GLOW; static const std::string SETTING_LIGHT_NORMAL; static const std::string SETTING_MAX_Y; static const std::string SETTING_MOON_ROTATION; @@ -92,7 +92,7 @@ public: static const std::string SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR; static const std::string SETTING_DENSITY_PROFILE_LINEAR_TERM; static const std::string SETTING_DENSITY_PROFILE_CONSTANT_TERM; - + static const std::string SETTING_SKY_MOISTURE_LEVEL; static const std::string SETTING_SKY_DROPLET_RADIUS; static const std::string SETTING_SKY_ICE_LEVEL; @@ -117,7 +117,7 @@ public: virtual std::string getSettingsType() const SETTINGS_OVERRIDE { return std::string("sky"); } virtual LLSettingsType::type_e getSettingsTypeValue() const SETTINGS_OVERRIDE { return LLSettingsType::ST_SKY; } - // Settings status + // Settings status virtual void blend(const LLSettingsBase::ptr_t &end, F64 blendf) SETTINGS_OVERRIDE; virtual void replaceSettings(LLSD settings) SETTINGS_OVERRIDE; @@ -129,7 +129,7 @@ public: F32 getSkyBottomRadius() const; F32 getSkyTopRadius() const; F32 getSunArcRadians() const; - F32 getMieAnisotropy() const; + F32 getMieAnisotropy() const; F32 getSkyMoistureLevel() const; F32 getSkyDropletRadius() const; @@ -139,10 +139,6 @@ public: // auto_adjust - if true and canAutoAdjust() is true, return 1.0 F32 getReflectionProbeAmbiance(bool auto_adjust = false) const; - // get the probe ambiance setting to use for rendering (adjusted by cloud shadow, aka cloud coverage) - // auto_adjust - if true and canAutoAdjust() is true, return 1.0 - F32 getTotalReflectionProbeAmbiance(F32 cloud_shadow_scale, bool auto_adjust = false) const; - // Return first (only) profile layer represented in LLSD LLSD getRayleighConfig() const; LLSD getMieConfig() const; @@ -200,7 +196,7 @@ public: F32 getCloudShadow() const; void setCloudShadow(F32 val); - + F32 getCloudVariance() const; void setCloudVariance(F32 val); @@ -299,7 +295,7 @@ public: // color based on brightness LLColor3 getMoonlightColor() const; - + LLColor4 getMoonAmbient() const; LLColor3 getMoonDiffuse() const; LLColor4 getSunAmbient() const; @@ -340,7 +336,7 @@ public: virtual void updateSettings() SETTINGS_OVERRIDE; // if true, this sky is a candidate for auto-adjustment - bool canAutoAdjust() const { return mCanAutoAdjust; } + bool canAutoAdjust() const; protected: static const std::string SETTING_LEGACY_EAST_ANGLE; @@ -385,9 +381,6 @@ private: mutable LLColor4 mTotalAmbient; mutable LLColor4 mHazeColor; - // if true, this sky is a candidate for auto adjustment - bool mCanAutoAdjust = true; - typedef std::map mapNameToUniformId_t; static mapNameToUniformId_t sNameToUniformMapping; diff --git a/indra/llmath/llcamera.h b/indra/llmath/llcamera.h index 3b52810855..b6e0e4a2be 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/llmatrix4a.h b/indra/llmath/llmatrix4a.h index 348feba27e..cf4e522467 100644 --- a/indra/llmath/llmatrix4a.h +++ b/indra/llmath/llmatrix4a.h @@ -56,6 +56,16 @@ public: return (F32*)&mMatrix; } + inline LLMatrix4& asMatrix4() + { + return *(LLMatrix4*)this; + } + + inline const LLMatrix4& asMatrix4() const + { + return *(LLMatrix4*)this; + } + inline void clear() { mMatrix[0].clear(); diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index c6af3807b8..20b26833d4 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -45,16 +45,15 @@ #include "llmatrix3a.h" #include "lloctree.h" #include "llvolume.h" -#include "llvolumeoctree.h" #include "llstl.h" #include "llsdserialize.h" #include "llvector4a.h" #include "llmatrix4a.h" #include "llmeshoptimizer.h" #include "lltimer.h" +#include "llvolumeoctree.h" -#include "mikktspace/mikktspace.h" -#include "mikktspace/mikktspace.c" // insert mikktspace implementation into llvolume object file +#include "mikktspace/mikktspace.hh" #include "meshoptimizer/meshoptimizer.h" @@ -5512,14 +5511,58 @@ struct MikktData n[i].normalize(); tc[i].set(face->mTexCoords[idx]); + if (idx >= face->mNumVertices) + { + // invalid index + // replace with a valid index to avoid crashes + idx = face->mNumVertices - 1; + face->mIndices[i] = idx; + + // Needs better logging + LL_DEBUGS_ONCE("LLVOLUME") << "Invalid index, substituting" << LL_ENDL; + } + if (face->mWeights) { w[i].set(face->mWeights[idx].getF32ptr()); } } } -}; + uint32_t GetNumFaces() + { + return uint32_t(face->mNumIndices / 3); + } + + uint32_t GetNumVerticesOfFace(const uint32_t face_num) + { + return 3; + } + + mikk::float3 GetPosition(const uint32_t face_num, const uint32_t vert_num) + { + F32* v = p[face_num * 3 + vert_num].mV; + return mikk::float3(v); + } + + mikk::float3 GetTexCoord(const uint32_t face_num, const uint32_t vert_num) + { + F32* uv = tc[face_num * 3 + vert_num].mV; + return mikk::float3(uv[0], uv[1], 1.0f); + } + + mikk::float3 GetNormal(const uint32_t face_num, const uint32_t vert_num) + { + F32* normal = n[face_num * 3 + vert_num].mV; + return mikk::float3(normal); + } + + void SetTangentSpace(const uint32_t face_num, const uint32_t vert_num, mikk::float3 T, bool orientation) + { + S32 i = face_num * 3 + vert_num; + t[i].set(T.x, T.y, T.z, orientation ? 1.0f : -1.0f); + } +}; bool LLVolumeFace::cacheOptimize(bool gen_tangents) { //optimize for vertex cache according to Forsyth method: @@ -5531,62 +5574,9 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents) { // generate mikkt space tangents before cache optimizing since the index buffer may change // a bit of a hack to do this here, but this function gets called exactly once for the lifetime of a mesh // and is executed on a background thread - SMikkTSpaceInterface ms; - - ms.m_getNumFaces = [](const SMikkTSpaceContext* pContext) - { - MikktData* data = (MikktData*)pContext->m_pUserData; - LLVolumeFace* face = data->face; - return face->mNumIndices / 3; - }; - - ms.m_getNumVerticesOfFace = [](const SMikkTSpaceContext* pContext, const int iFace) - { - return 3; - }; - - ms.m_getPosition = [](const SMikkTSpaceContext* pContext, float fvPosOut[], const int iFace, const int iVert) - { - MikktData* data = (MikktData*)pContext->m_pUserData; - F32* v = data->p[iFace * 3 + iVert].mV; - fvPosOut[0] = v[0]; - fvPosOut[1] = v[1]; - fvPosOut[2] = v[2]; - }; - - ms.m_getNormal = [](const SMikkTSpaceContext* pContext, float fvNormOut[], const int iFace, const int iVert) - { - MikktData* data = (MikktData*)pContext->m_pUserData; - F32* n = data->n[iFace * 3 + iVert].mV; - fvNormOut[0] = n[0]; - fvNormOut[1] = n[1]; - fvNormOut[2] = n[2]; - }; - - ms.m_getTexCoord = [](const SMikkTSpaceContext* pContext, float fvTexcOut[], const int iFace, const int iVert) - { - MikktData* data = (MikktData*)pContext->m_pUserData; - F32* tc = data->tc[iFace * 3 + iVert].mV; - fvTexcOut[0] = tc[0]; - fvTexcOut[1] = tc[1]; - }; - - ms.m_setTSpaceBasic = [](const SMikkTSpaceContext* pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert) - { - MikktData* data = (MikktData*)pContext->m_pUserData; - S32 i = iFace * 3 + iVert; - - data->t[i].set(fvTangent); - data->t[i].mV[3] = fSign; - }; - - ms.m_setTSpace = nullptr; - MikktData data(this); - - SMikkTSpaceContext ctx = { &ms, &data }; - - genTangSpaceDefault(&ctx); + mikk::Mikktspace ctx(data); + ctx.genTangSpace(); //re-weld meshopt_Stream mos[] = @@ -5607,9 +5597,6 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents) if (vert_count < 65535 && vert_count != 0) { - std::vector indices; - indices.resize(mNumIndices); - //copy results back into volume resizeVertices(vert_count); @@ -5699,8 +5686,7 @@ void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVe ND_OCTREE_LOG << "Creating octree with scale " << scaler << " mNumIndices " << mNumIndices << ND_OCTREE_LOG_END; llassert(mNumIndices % 3 == 0); - mOctree = new LLOctreeRoot(center, size, NULL); - new LLVolumeOctreeListener(mOctree); + mOctree = new LLVolumeOctree(center, size); const U32 num_triangles = mNumIndices / 3; // Initialize all the triangles we need mOctreeTriangles = new LLVolumeTriangle[num_triangles]; @@ -5763,7 +5749,7 @@ void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVe while (!mOctree->balance()) { } //calculate AABB for each node - LLVolumeOctreeRebound rebound(this); + LLVolumeOctreeRebound rebound; rebound.traverse(mOctree); if (gDebugGL) @@ -5776,12 +5762,12 @@ void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVe void LLVolumeFace::destroyOctree() { delete mOctree; - mOctree = NULL; + mOctree = nullptr; delete[] mOctreeTriangles; - mOctreeTriangles = NULL; + mOctreeTriangles = nullptr; } -const LLOctreeNode* LLVolumeFace::getOctree() const +const LLVolumeOctree* LLVolumeFace::getOctree() const { return mOctree; } @@ -6496,9 +6482,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; @@ -6516,7 +6499,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 (S32 i = 0; i < mNumVertices; i++) @@ -7244,7 +7227,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 b1766159b7..c8c03e1d1a 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -41,6 +41,7 @@ template class LLOctreeNode; class LLVolumeFace; class LLVolume; class LLVolumeTriangle; +class LLVolumeOctree; #include "lluuid.h" #include "v4color.h" @@ -916,7 +917,7 @@ public: void createOctree(F32 scaler = 0.25f, const LLVector4a& center = LLVector4a(0,0,0), const LLVector4a& size = LLVector4a(0.5f,0.5f,0.5f)); void destroyOctree(); // Get a reference to the octree, which may be null - const LLOctreeNode* getOctree() const; + const LLVolumeOctree* getOctree() const; enum { @@ -990,7 +991,7 @@ public: LLVector3 mNormalizedScale = LLVector3(1,1,1); private: - LLOctreeNode* mOctree; + LLVolumeOctree* mOctree; LLVolumeTriangle* mOctreeTriangles; bool createUnCutCubeCap(LLVolume* volume, bool partial_build = false); @@ -1155,6 +1156,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/llmath/llvolumeoctree.cpp b/indra/llmath/llvolumeoctree.cpp index abcd47ea23..00c0988092 100644 --- a/indra/llmath/llvolumeoctree.cpp +++ b/indra/llmath/llvolumeoctree.cpp @@ -91,15 +91,15 @@ void LLVolumeOctreeListener::handleChildAddition(const LLOctreeNode { public: - const LLVolumeFace* mFace; LLVector4a mStart; LLVector4a mDir; LLVector4a mEnd; @@ -121,10 +120,13 @@ public: LLVector4a* mNormal; LLVector4a* mTangent; F32* mClosestT; + LLVolumeFace* mFace; bool mHitFace; + const LLVolumeTriangle* mHitTriangle = nullptr; LLOctreeTriangleRayIntersect(const LLVector4a& start, const LLVector4a& dir, - const LLVolumeFace* face, F32* closest_t, + LLVolumeFace* face, + F32* closest_t, LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent); void traverse(const LLOctreeNode* node); @@ -137,4 +139,91 @@ class LLVolumeOctreeValidate : public LLOctreeTraveler* branch); }; +class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst +{ +public: + LLVolumeOctreeRebound() + { + } + + virtual void visit(const LLOctreeNode* branch) + { //this is a depth first traversal, so it's safe to assum all children have complete + //bounding data + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + + LLVolumeOctreeListener* node = (LLVolumeOctreeListener*)branch->getListener(0); + + LLVector4a& min = node->mExtents[0]; + LLVector4a& max = node->mExtents[1]; + + if (!branch->isEmpty()) + { //node has data, find AABB that binds data set + const LLVolumeTriangle* tri = *(branch->getDataBegin()); + + //initialize min/max to first available vertex + min = *(tri->mV[0]); + max = *(tri->mV[0]); + + for (LLOctreeNode::const_element_iter iter = branch->getDataBegin(); iter != branch->getDataEnd(); ++iter) + { //for each triangle in node + + //stretch by triangles in node + tri = *iter; + + min.setMin(min, *tri->mV[0]); + min.setMin(min, *tri->mV[1]); + min.setMin(min, *tri->mV[2]); + + max.setMax(max, *tri->mV[0]); + max.setMax(max, *tri->mV[1]); + max.setMax(max, *tri->mV[2]); + } + } + else if (branch->getChildCount() > 0) + { //no data, but child nodes exist + LLVolumeOctreeListener* child = (LLVolumeOctreeListener*)branch->getChild(0)->getListener(0); + + //initialize min/max to extents of first child + min = child->mExtents[0]; + max = child->mExtents[1]; + } + else + { + llassert(!branch->isLeaf()); // Empty leaf + } + + for (S32 i = 0; i < branch->getChildCount(); ++i) + { //stretch by child extents + LLVolumeOctreeListener* child = (LLVolumeOctreeListener*)branch->getChild(i)->getListener(0); + min.setMin(min, child->mExtents[0]); + max.setMax(max, child->mExtents[1]); + } + + node->mBounds[0].setAdd(min, max); + node->mBounds[0].mul(0.5f); + + node->mBounds[1].setSub(max, min); + node->mBounds[1].mul(0.5f); + } +}; + +class LLVolumeOctree : public LLOctreeRoot, public LLRefCount +{ +public: + LLVolumeOctree(const LLVector4a& center, const LLVector4a& size) + : + LLOctreeRoot(center, size, nullptr), + LLRefCount() + { + new LLVolumeOctreeListener(this); + } + + LLVolumeOctree() + : LLOctreeRoot(LLVector4a::getZero(), LLVector4a(1.f,1.f,1.f), nullptr), + LLRefCount() + { + new LLVolumeOctreeListener(this); + } +}; + #endif diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index 91cc55d0c7..d8f58e7e4c 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -601,7 +601,7 @@ void LLPluginProcessParent::idle(void) params.args.add("-e"); params.args.add("tell application \"Terminal\""); params.args.add("-e"); - params.args.add(STRINGIZE("set win to do script \"gdb -pid " + params.args.add(STRINGIZE("set win to do script \"lldb -pid " << mProcess->getProcessID() << "\"")); params.args.add("-e"); params.args.add("do script \"continue\" in win"); diff --git a/indra/llprimitive/llgltfmaterial.h b/indra/llprimitive/llgltfmaterial.h index 9f817d6a19..e9b48a60dd 100644 --- a/indra/llprimitive/llgltfmaterial.h +++ b/indra/llprimitive/llgltfmaterial.h @@ -233,10 +233,17 @@ protected: void updateLocalTexDataDigest(); public: + // *TODO: If/when we implement additional GLTF extensions, they may not be + // compatible with our GLTF terrain implementation. We may want to disallow + // materials with some features from being set on terrain, if their + // implementation on terrain is not compliant with the spec: + // - KHR_materials_transmission: Probably OK? + // - KHR_materials_ior: Probably OK? + // - KHR_materials_volume: Likely incompatible, as our terrain + // heightmaps cannot currently be described as finite enclosed + // volumes. + // See also LLPanelRegionTerrainInfo::validateMaterials // These fields are local to viewer and are a part of local bitmap support - // IMPORTANT: do not move this member down (and do not move - // mLocalTexDataDigest either): the getHash() method does rely on the - // current ordering. HB typedef std::map local_tex_map_t; local_tex_map_t mTrackingIdToLocalTexture; diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index 9d89ffc586..60609f23e1 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -1948,6 +1948,19 @@ void LLReflectionProbeParams::setIsDynamic(bool is_dynamic) } } + +void LLReflectionProbeParams::setIsMirror(bool is_mirror) +{ + if (is_mirror) + { + mFlags |= FLAG_MIRROR; + } + else + { + mFlags &= ~FLAG_MIRROR; + } +} + //============================================================================ LLFlexibleObjectData::LLFlexibleObjectData() { diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index 9bd1f60649..1d1078bbdb 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -194,6 +194,7 @@ public: { FLAG_BOX_VOLUME = 0x01, // use a box influence volume FLAG_DYNAMIC = 0x02, // render dynamic objects (avatars) into this Reflection Probe + FLAG_MIRROR = 0x04, // This probe is used for reflections on realtime mirrors. }; protected: @@ -217,11 +218,13 @@ public: void setClipDistance(F32 distance) { mClipDistance = llclamp(distance, REFLECTION_PROBE_MIN_CLIP_DISTANCE, REFLECTION_PROBE_MAX_CLIP_DISTANCE); } void setIsBox(bool is_box); void setIsDynamic(bool is_dynamic); + void setIsMirror(bool is_mirror); F32 getAmbiance() const { return mAmbiance; } F32 getClipDistance() const { return mClipDistance; } bool getIsBox() const { return (mFlags & FLAG_BOX_VOLUME) != 0; } bool getIsDynamic() const { return (mFlags & FLAG_DYNAMIC) != 0; } + bool getIsMirror() const { return (mFlags & FLAG_MIRROR) != 0; } }; //------------------------------------------------- diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp index 9ebbeac482..ac482ffbf9 100644 --- a/indra/llprimitive/lltextureentry.cpp +++ b/indra/llprimitive/lltextureentry.cpp @@ -685,6 +685,7 @@ S32 LLTextureEntry::setMaterialParams(const LLMaterialPtr pMaterialParams) mMaterialUpdatePending = true; } mMaterial = pMaterialParams; + return TEM_CHANGE_TEXTURE; } diff --git a/indra/llprimitive/tests/llgltfmaterial_test.cpp b/indra/llprimitive/tests/llgltfmaterial_test.cpp index 7a276c7b82..823a36ec3a 100644 --- a/indra/llprimitive/tests/llgltfmaterial_test.cpp +++ b/indra/llprimitive/tests/llgltfmaterial_test.cpp @@ -1,26 +1,26 @@ -/** +/** * @file llgltfmaterial_test.cpp * - * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * $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$ + * $/LicenseInfo$ */ #include "linden_common.h" diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index 2c12220477..24997ec7ef 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -1190,6 +1190,8 @@ S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTex LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL; return -1; } + + S32 index = mTexture[uniform]; if (index != -1) { diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index 698da92877..3d00c311fd 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -49,13 +49,14 @@ public: bool hasShadows = false; bool hasAmbientOcclusion = false; bool hasSrgb = false; - bool encodesNormal = false; // include: shaders\class1\environment\encodeNormF.glsl bool isDeferred = false; bool hasScreenSpaceReflections = false; bool disableTextureIndex = false; bool hasAlphaMask = false; bool hasReflectionProbes = false; bool attachNothing = false; + bool hasHeroProbes = false; + bool isPBRTerrain = false; }; // ============= Structure for caching shader uniforms =============== diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp index 2d8a8fd178..08f5770102 100644 --- a/indra/llrender/llgltexture.cpp +++ b/indra/llrender/llgltexture.cpp @@ -49,6 +49,10 @@ LLGLTexture::LLGLTexture(const LLImageRaw* raw, bool usemipmaps) mUseMipMaps = usemipmaps ; // Create an empty image of the specified size and width mGLTexturep = new LLImageGL(raw, usemipmaps) ; + mFullWidth = mGLTexturep->getCurrentWidth(); + mFullHeight = mGLTexturep->getCurrentHeight(); + mComponents = mGLTexturep->getComponents(); + setTexelsPerImage(); } LLGLTexture::~LLGLTexture() @@ -95,7 +99,8 @@ void LLGLTexture::setBoostLevel(S32 level) mBoostLevel = level ; if(mBoostLevel != LLGLTexture::BOOST_NONE && mBoostLevel != LLGLTexture::BOOST_ICON - && mBoostLevel != LLGLTexture::BOOST_THUMBNAIL) + && mBoostLevel != LLGLTexture::BOOST_THUMBNAIL + && mBoostLevel != LLGLTexture::BOOST_TERRAIN) { setNoDelete() ; } diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h index 9e71f51540..f63f529ba8 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 }; @@ -52,10 +52,11 @@ public: BOOST_AVATAR , BOOST_AVATAR_BAKED , BOOST_SCULPTED , + BOOST_TERRAIN , // Needed for minimap generation for now. Lower than BOOST_HIGH so the texture stats don't get forced, i.e. texture stats are manually managed by minimap/terrain instead. BOOST_HIGH = 10, BOOST_BUMP , - BOOST_TERRAIN , // has to be high priority for minimap / low detail + BOOST_UNUSED_1 , // Placeholder to avoid disrupting habits around texture debug BOOST_SELECTED , BOOST_AVATAR_BAKED_SELF , BOOST_AVATAR_SELF , // needed for baking avatar diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 99e735dd14..c8dc2399a3 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -2124,10 +2124,6 @@ void LLRender::diffuseColor3f(F32 r, F32 g, F32 b) { shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r,g,b,1.f); } - else - { - glColor3f(r,g,b); - } } void LLRender::diffuseColor3fv(const F32* c) @@ -2139,10 +2135,6 @@ void LLRender::diffuseColor3fv(const F32* c) { shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, c[0], c[1], c[2], 1.f); } - else - { - glColor3fv(c); - } } void LLRender::diffuseColor4f(F32 r, F32 g, F32 b, F32 a) @@ -2154,10 +2146,6 @@ void LLRender::diffuseColor4f(F32 r, F32 g, F32 b, F32 a) { shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r,g,b,a); } - else - { - glColor4f(r,g,b,a); - } } void LLRender::diffuseColor4fv(const F32* c) @@ -2169,10 +2157,6 @@ void LLRender::diffuseColor4fv(const F32* c) { shader->uniform4fv(LLShaderMgr::DIFFUSE_COLOR, 1, c); } - else - { - glColor4fv(c); - } } void LLRender::diffuseColor4ubv(const U8* c) @@ -2184,10 +2168,6 @@ void LLRender::diffuseColor4ubv(const U8* c) { shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, c[0]/255.f, c[1]/255.f, c[2]/255.f, c[3]/255.f); } - else - { - glColor4ubv(c); - } } void LLRender::diffuseColor4ub(U8 r, U8 g, U8 b, U8 a) @@ -2199,10 +2179,6 @@ void LLRender::diffuseColor4ub(U8 r, U8 g, U8 b, U8 a) { shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r/255.f, g/255.f, b/255.f, a/255.f); } - else - { - glColor4ub(r,g,b,a); - } } diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index 85a710d55c..b573618ee6 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -567,4 +567,31 @@ bool LLRenderTarget::isBoundInStack() const return cur == this; } +void LLRenderTarget::swapFBORefs(LLRenderTarget& other) +{ + // Must be initialized + llassert(mFBO); + llassert(other.mFBO); + // Must be unbound + // *NOTE: mPreviousRT can be non-null even if this target is unbound - presumably for debugging purposes? + llassert(sCurFBO != mFBO); + llassert(sCurFBO != other.mFBO); + llassert(!isBoundInStack()); + llassert(!other.isBoundInStack()); + + // Must be same type + llassert(sUseFBO == other.sUseFBO); + llassert(mResX == other.mResX); + llassert(mResY == other.mResY); + llassert(mInternalFormat == other.mInternalFormat); + llassert(mTex.size() == other.mTex.size()); + llassert(mDepth == other.mDepth); + llassert(mUseDepth == other.mUseDepth); + llassert(mGenerateMipMaps == other.mGenerateMipMaps); + llassert(mMipLevels == other.mMipLevels); + llassert(mUsage == other.mUsage); + + std::swap(mFBO, other.mFBO); + std::swap(mTex, other.mTex); +} diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h index b5745b5b49..340276a752 100644 --- a/indra/llrender/llrendertarget.h +++ b/indra/llrender/llrendertarget.h @@ -169,6 +169,9 @@ public: static LLRenderTarget* getCurrentBoundTarget() { return sBoundTarget; } + // *HACK + void swapFBORefs(LLRenderTarget& other); + protected: U32 mResX; U32 mResY; diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 60e1b89b8e..981c3786f6 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -44,6 +44,7 @@ using std::make_pair; using std::string; LLShaderMgr * LLShaderMgr::sInstance = NULL; +bool LLShaderMgr::sMirrorsEnabled = false; LLShaderMgr::LLShaderMgr() { @@ -183,7 +184,13 @@ bool LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) // Attach Fragment Shader Features Next /////////////////////////////////////// -// NOTE order of shader object attaching is VERY IMPORTANT!!! + // NOTE order of shader object attaching is VERY IMPORTANT!!! + + if (!shader->attachFragmentObject("deferred/globalF.glsl")) + { + return false; + } + if (features->hasSrgb || features->hasAtmospherics || features->calculatesAtmospherics || features->isDeferred) { if (!shader->attachFragmentObject("environment/srgbF.glsl")) @@ -257,14 +264,6 @@ bool LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) } } - if (features->encodesNormal) - { - if (!shader->attachFragmentObject("environment/encodeNormF.glsl")) - { - return false; - } - } - if (features->hasAtmospherics || features->isDeferred) { if (!shader->attachFragmentObject("windlight/atmosphericsFuncs.glsl")) { @@ -277,6 +276,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) { @@ -321,7 +328,7 @@ bool LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) return false; } } - shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1); + shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels, 1); } } @@ -578,21 +585,38 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev } else { - //set version to 1.40 - shader_code_text[shader_code_count++] = strdup("#version 140\n"); - //some implementations of GLSL 1.30 require integer precision be explicitly declared - extra_code_text[extra_code_count++] = strdup("precision mediump int;\n"); - extra_code_text[extra_code_count++] = strdup("precision highp float;\n"); + if (type == GL_GEOMETRY_SHADER) + { + //set version to 1.50 + shader_code_text[shader_code_count++] = strdup("#version 150\n"); + //some implementations of GLSL 1.30 require integer precision be explicitly declared + extra_code_text[extra_code_count++] = strdup("precision mediump int;\n"); + extra_code_text[extra_code_count++] = strdup("precision highp float;\n"); + } + else + { + //set version to 1.40 + shader_code_text[shader_code_count++] = strdup("#version 140\n"); + //some implementations of GLSL 1.30 require integer precision be explicitly declared + extra_code_text[extra_code_count++] = strdup("precision mediump int;\n"); + extra_code_text[extra_code_count++] = strdup("precision highp float;\n"); + } } extra_code_text[extra_code_count++] = strdup("#define FXAA_GLSL_130 1\n"); } + if (sMirrorsEnabled) + { + extra_code_text[extra_code_count++] = strdup("#define HERO_PROBES 1\n"); + } + // Use alpha float to store bit flags // See: C++: addDeferredAttachment(), shader: frag_data[2] extra_code_text[extra_code_count++] = strdup("#define GBUFFER_FLAG_SKIP_ATMOS 0.0 \n"); // atmo kill extra_code_text[extra_code_count++] = strdup("#define GBUFFER_FLAG_HAS_ATMOS 0.34\n"); // bit 0 extra_code_text[extra_code_count++] = strdup("#define GBUFFER_FLAG_HAS_PBR 0.67\n"); // bit 1 + extra_code_text[extra_code_count++] = strdup("#define GBUFFER_FLAG_HAS_HDRI 1.0\n"); // bit 2 extra_code_text[extra_code_count++] = strdup("#define GET_GBUFFER_FLAG(flag) (abs(norm.w-flag)< 0.1)\n"); if (defines) @@ -1198,6 +1222,9 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("emissiveColor"); mReservedUniforms.push_back("metallicFactor"); mReservedUniforms.push_back("roughnessFactor"); + mReservedUniforms.push_back("mirror_flag"); + mReservedUniforms.push_back("clipPlane"); + mReservedUniforms.push_back("clipSign"); mReservedUniforms.push_back("diffuseMap"); mReservedUniforms.push_back("altDiffuseMap"); @@ -1210,6 +1237,7 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("sceneDepth"); mReservedUniforms.push_back("reflectionProbes"); mReservedUniforms.push_back("irradianceProbes"); + mReservedUniforms.push_back("heroProbes"); mReservedUniforms.push_back("cloud_noise_texture"); mReservedUniforms.push_back("cloud_noise_texture_next"); mReservedUniforms.push_back("fullbright"); @@ -1392,8 +1420,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"); @@ -1415,6 +1467,7 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("cloud_variance"); mReservedUniforms.push_back("reflection_probe_ambiance"); mReservedUniforms.push_back("max_probe_lod"); + mReservedUniforms.push_back("probe_strength"); mReservedUniforms.push_back("sh_input_r"); mReservedUniforms.push_back("sh_input_g"); @@ -1425,6 +1478,8 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("sun_up_factor"); mReservedUniforms.push_back("moonlight_color"); + mReservedUniforms.push_back("debug_normal_draw_length"); + llassert(mReservedUniforms.size() == END_RESERVED_UNIFORMS); std::set dupe_check; diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 716df42956..d658470fb8 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -85,6 +85,9 @@ public: EMISSIVE_COLOR, // "emissiveColor" METALLIC_FACTOR, // "metallicFactor" ROUGHNESS_FACTOR, // "roughnessFactor" + MIRROR_FLAG, // "mirror_flag" + CLIP_PLANE, // "clipPlane" + CLIP_SIGN, // "clipSign" DIFFUSE_MAP, // "diffuseMap" ALTERNATE_DIFFUSE_MAP, // "altDiffuseMap" SPECULAR_MAP, // "specularMap" @@ -96,6 +99,7 @@ public: SCENE_DEPTH, // "sceneDepth" REFLECTION_PROBES, // "reflectionProbes" IRRADIANCE_PROBES, // "irradianceProbes" + HERO_PROBE, // "heroProbes" CLOUD_NOISE_MAP, // "cloud_noise_texture" CLOUD_NOISE_MAP_NEXT, // "cloud_noise_texture_next" FULLBRIGHT, // "fullbright" @@ -264,8 +268,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" @@ -292,6 +320,7 @@ public: REFLECTION_PROBE_AMBIANCE, // "reflection_probe_ambiance" REFLECTION_PROBE_MAX_LOD, // "max_probe_lod" + REFLECTION_PROBE_STRENGTH, // "probe_strength" SH_INPUT_L1R, // "sh_input_r" SH_INPUT_L1G, // "sh_input_g" SH_INPUT_L1B, // "sh_input_b" @@ -300,6 +329,9 @@ public: WATER_EDGE_FACTOR, // "water_edge" SUN_UP_FACTOR, // "sun_up_factor" MOONLIGHT_COLOR, // "moonlight_color" + + DEBUG_NORMAL_DRAW_LENGTH, // "debug_normal_draw_length" + END_RESERVED_UNIFORMS } eGLSLReservedUniforms; // clang-format on @@ -349,6 +381,7 @@ public: bool mShaderCacheInitialized = false; bool mShaderCacheEnabled = false; std::string mShaderCacheDir; + static bool sMirrorsEnabled; protected: diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 9e46a748e6..e6b788ac26 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -674,7 +674,7 @@ void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVecto U16 idx = indicesp[i]; gGL.vertex3fv(pos[idx].getF32ptr()); } -} + } gGL.end(); gGL.flush(); } @@ -756,8 +756,8 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi llassert(mGLBuffer == sGLRenderBuffer); llassert(mGLIndices == sGLRenderIndices); gGL.syncMatrices(); - glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT, - (GLvoid*) (indices_offset * sizeof(U16))); + glDrawRangeElements(sGLMode[mode], start, end, count, mIndicesType, + (GLvoid*) (indices_offset * (size_t) mIndicesStride)); } void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const @@ -1154,7 +1154,7 @@ U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count) } // flush the given byte range -// target -- "targret" parameter for glBufferSubData +// target -- "target" parameter for glBufferSubData // start -- first byte to copy // end -- last byte to copy (NOT last byte + 1) // data -- mMappedData or mMappedIndexData @@ -1316,6 +1316,8 @@ bool LLVertexBuffer::getVertexStrider(LLStrider& strider, U32 index, } bool LLVertexBuffer::getIndexStrider(LLStrider& strider, U32 index, S32 count) { + llassert(mIndicesStride == 2); // cannot access 32-bit indices with U16 strider + llassert(mIndicesType == GL_UNSIGNED_SHORT); return VertexBufferStrider::get(*this, strider, index, count); } bool LLVertexBuffer::getTexCoord0Strider(LLStrider& strider, U32 index, S32 count) @@ -1334,6 +1336,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); @@ -1529,4 +1535,39 @@ void LLVertexBuffer::setColorData(const LLColor4U* data) flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_COLOR], mOffsets[TYPE_COLOR] + sTypeSize[TYPE_COLOR] * getNumVerts() - 1, (U8*) data); } +void LLVertexBuffer::setNormalData(const LLVector4a* data) +{ + llassert(sGLRenderBuffer == mGLBuffer); + flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_NORMAL], mOffsets[TYPE_NORMAL] + sTypeSize[TYPE_NORMAL] * getNumVerts() - 1, (U8*) data); +} + +void LLVertexBuffer::setTangentData(const LLVector4a* data) +{ + llassert(sGLRenderBuffer == mGLBuffer); + flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TANGENT], mOffsets[TYPE_TANGENT] + sTypeSize[TYPE_TANGENT] * getNumVerts() - 1, (U8*) data); +} + +void LLVertexBuffer::setWeight4Data(const LLVector4a* data) +{ + llassert(sGLRenderBuffer == mGLBuffer); + flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_WEIGHT4], mOffsets[TYPE_WEIGHT4] + sTypeSize[TYPE_WEIGHT4] * getNumVerts() - 1, (U8*) data); +} + +void LLVertexBuffer::setIndexData(const U16* data) +{ + llassert(sGLRenderIndices == mGLIndices); + flush_vbo(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(U16) * getNumIndices() - 1, (U8*) data); +} + +void LLVertexBuffer::setIndexData(const U32* data) +{ + llassert(sGLRenderIndices == mGLIndices); + if (mIndicesType != GL_UNSIGNED_INT) + { // HACK -- vertex buffers are initialized as 16-bit indices, but can be switched to 32-bit indices + mIndicesType = GL_UNSIGNED_INT; + mIndicesStride = 4; + mNumIndices /= 2; + } + flush_vbo(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(U32) * getNumIndices() - 1, (U8*)data); +} diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index bc290c25cf..51a7943217 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,15 +192,15 @@ 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 setNormalData(const LLVector4a* data); + void setTangentData(const LLVector4a* data); + void setWeight4Data(const LLVector4a* data); void setTexCoordData(const LLVector2* data); void setColorData(const LLColor4U* data); - + void setIndexData(const U16* data); + void setIndexData(const U32* data); U32 getNumVerts() const { return mNumVerts; } U32 getNumIndices() const { return mNumIndices; } @@ -231,6 +232,8 @@ protected: U32 mGLIndices = 0; // GL IBO handle U32 mNumVerts = 0; // Number of vertices allocated U32 mNumIndices = 0; // Number of indices allocated + U32 mIndicesType = GL_UNSIGNED_SHORT; // type of indices in index buffer + U32 mIndicesStride = 2; // size of each index in bytes U32 mOffsets[TYPE_MAX]; // byte offsets into mMappedData of each attribute U8* mMappedData = nullptr; // pointer to currently mapped data (NULL if unmapped) diff --git a/indra/llui/llemojihelper.cpp b/indra/llui/llemojihelper.cpp index a8714ba7d0..2d0db0280e 100644 --- a/indra/llui/llemojihelper.cpp +++ b/indra/llui/llemojihelper.cpp @@ -103,20 +103,34 @@ void LLEmojiHelper::showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, c if (mHelperHandle.isDead()) { LLFloater* pHelperFloater = LLFloaterReg::getInstance(DEFAULT_EMOJI_HELPER_FLOATER); + // Try to prevent failed build of emoji picker from killing the viewer. + if(!pHelperFloater) + { + LL_WARNS() << "Cannot show emoji helper, reason unknown." << LL_ENDL; + return; + } + // mHelperHandle = pHelperFloater->getHandle(); mHelperCommitConn = pHelperFloater->setCommitCallback(std::bind([&](const LLSD& sdValue) { onCommitEmoji(utf8str_to_wstring(sdValue.asStringRef())[0]); }, std::placeholders::_2)); } setHostCtrl(hostctrl_p); mEmojiCommitCb = cb; - S32 floater_x, floater_y; - if (!hostctrl_p->localPointToOtherView(local_x, local_y, &floater_x, &floater_y, gFloaterView)) + S32 floater_x=0, floater_y=0;// initialise to avoid warnings + if (hostctrl_p && !hostctrl_p->localPointToOtherView(local_x, local_y, &floater_x, &floater_y, gFloaterView))// another unchecked pointer access { - LL_ERRS() << "Cannot show emoji helper for non-floater controls." << LL_ENDL; + LL_WARNS() << "Cannot show emoji helper for non-floater controls." << LL_ENDL; // Is this really worth crashing over? return; } LLFloater* pHelperFloater = mHelperHandle.get(); + // Be a bit paranoid - the previous code should have ensured this or returned. + if (!pHelperFloater) + { + LL_WARNS() << "Helper floater unexpectedly null." << LL_ENDL; + return; + } + // LLRect rect = pHelperFloater->getRect(); S32 left = floater_x - HELPER_FLOATER_OFFSET_X; S32 top = floater_y - HELPER_FLOATER_OFFSET_Y + rect.getHeight(); diff --git a/indra/llui/lltransutil.cpp b/indra/llui/lltransutil.cpp index bc80ab8cde..09d5e888e7 100644 --- a/indra/llui/lltransutil.cpp +++ b/indra/llui/lltransutil.cpp @@ -50,7 +50,7 @@ bool LLTransUtil::parseStrings(const std::string& xml_filename, const std::setdumpCurrentDirectories(LLError::LEVEL_WARN); - LL_ERRS() << "Couldn't load string table " << xml_filename << " " << errno << LL_ENDL; + LL_ERRS() << "Couldn't load string table " << xml_filename << ". Please reinstall viewer from https://www.firestormviewer.org/download and contact https://www.firestormviewer.org/support if issue persists after reinstall." << LL_ENDL; return false; } diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 098d5ca037..a7fd92f619 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -37,6 +37,7 @@ include(OpenGL) include(OpenSSL) include(PNG) include(TemplateCheck) +include(TinyEXR) include(ThreeJS) include(Tracy) include(UI) @@ -167,7 +168,6 @@ set(viewer_SOURCE_FILES fsscrolllistctrl.cpp fsslurlcommand.cpp fsworldmapmessage.cpp - groupchatlistener.cpp lggbeamcolormapfloater.cpp lggbeammapfloater.cpp lggbeammaps.cpp @@ -183,6 +183,12 @@ set(viewer_SOURCE_FILES vjfloaterlocalmesh.cpp vjlocalmeshimportdae.cpp + gltfscenemanager.cpp + gltf/asset.cpp + gltf/accessor.cpp + gltf/primitive.cpp + gltf/animation.cpp + groupchatlistener.cpp llaccountingcostmanager.cpp llaisapi.cpp llagent.cpp @@ -424,6 +430,7 @@ set(viewer_SOURCE_FILES llgiveinventory.cpp llglsandbox.cpp llgltfmateriallist.cpp + llgltfmaterialpreviewmgr.cpp llgroupactions.cpp llgroupiconctrl.cpp llgrouplist.cpp @@ -633,6 +640,7 @@ set(viewer_SOURCE_FILES llrecentpeople.cpp llreflectionmap.cpp llreflectionmapmanager.cpp + llheroprobemanager.cpp llregioninfomodel.cpp llregionposition.cpp llremoteparcelrequest.cpp @@ -958,8 +966,6 @@ set(viewer_HEADER_FILES fsslurl.h fsslurlcommand.h fsworldmapmessage.h - groupchatlistener.h - llaccountingcost.h lggbeamcolormapfloater.h lggbeammapfloater.h lggbeammaps.h @@ -974,6 +980,14 @@ set(viewer_HEADER_FILES vjfloaterlocalmesh.h vjlocalmeshimportdae.h + gltfscenemanager.h + groupchatlistener.h + gltf/asset.h + gltf/accessor.h + gltf/buffer_util.h + gltf/primitive.h + gltf/animation.h + llaccountingcost.h llaccountingcostmanager.h llaisapi.h llagent.h @@ -1218,6 +1232,7 @@ set(viewer_HEADER_FILES llgesturemgr.h llgiveinventory.h llgltfmateriallist.h + llgltfmaterialpreviewmgr.h llgroupactions.h llgroupiconctrl.h llgrouplist.h @@ -1413,6 +1428,7 @@ set(viewer_HEADER_FILES llrecentpeople.h llreflectionmap.h llreflectionmapmanager.h + llheroprobemanager.h llregioninfomodel.h llregionposition.h llremoteparcelrequest.h diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index 2fe040f424..5978ab1324 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -7.1.8 +7.1.9 diff --git a/indra/newview/app_settings/graphic_preset_controls.xml b/indra/newview/app_settings/graphic_preset_controls.xml index 94868c70e2..5a08a37639 100644 --- a/indra/newview/app_settings/graphic_preset_controls.xml +++ b/indra/newview/app_settings/graphic_preset_controls.xml @@ -25,6 +25,8 @@ RenderDeferredSSAO RenderDepthOfField RenderDepthOfFieldInEditMode + RenderDesaturateIrradiance + RenderDiffuseLuminanceScale RenderDisablePostProcessing RenderPostProcessingHDR RenderDefaultProbeUpdatePeriod @@ -38,9 +40,18 @@ RenderGlowIterations RenderGlowNoise RenderGlowResolutionPow + RenderHDRIExposure + RenderHDRIRotation + RenderHDRISplitScreen + RenderHDRIIrradianceOnly + RenderHeroProbeResolution + RenderHeroProbeDistance + RenderHeroProbeUpdateRate + RenderHeroProbeConservativeUpdateMultiplier RenderLocalLightCount RenderMaxPartCount RenderMaxVRAMBudget + RenderMirrors RenderQualityPerformance RenderReflectionsEnabled RenderReflectionProbeAmbiance @@ -74,7 +85,12 @@ RenderSunDynamicRange RenderTerrainDetail RenderTerrainLODFactor + RenderTerrainPBRDetail + RenderTerrainPBRScale + RenderTerrainPBRPlanarSampleCount + RenderTerrainPBRTriplanarBlendFactor RenderTerrainScale + RenderMaxTextureResolution RenderTreeLODFactor RenderTransparentWater RenderUnloadedAvatar diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index dc27316eb3..b58bb1d703 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1944,7 +1944,7 @@ Value 0 - AutoAcceptNewInventory + AutoAcceptNewInventory Comment Automatically accept new notecards/textures/landmarks @@ -10360,7 +10360,7 @@ Change of this parameter will affect the layout of buttons in notification toast OctreeAlphaDistanceFactor Comment - Multiplier on alpha object distance for determining octree node size + Multiplier on alpha object distance for determining octree node size. First two parameters are currently unused. Third parameter is distance at which to perform detailed alpha sorting. Persist 1 Type @@ -10369,7 +10369,7 @@ Change of this parameter will affect the layout of buttons in notification toast 0.1 0.0 - 0.0 + 64.0 Backup 0 @@ -10473,17 +10473,6 @@ Change of this parameter will affect the layout of buttons in notification toast Value 32.0 - RenderCloudShadowAmbianceFactor - - Comment - Amount that cloud shadow (aka cloud coverage) contributes to reflection probe ambiance - Persist - 1 - Type - F32 - Value - 0.1 - RenderCPUBasis Comment @@ -10818,6 +10807,17 @@ Change of this parameter will affect the layout of buttons in notification toast Backup 0 + RenderMirrors + + Comment + Renders realtime mirrors. + Persist + 1 + Type + Boolean + Value + 0 + RenderScreenSpaceReflections Comment @@ -10947,6 +10947,17 @@ Change of this parameter will affect the layout of buttons in notification toast Backup 0 + RenderDesaturateIrradiance + + Comment + Desaturate irradiance to remove blue tint + Persist + 1 + Type + Boolean + Value + 1 + RenderDebugAlphaMask Comment @@ -11030,6 +11041,50 @@ Change of this parameter will affect the layout of buttons in notification toast Value 0 + RenderHDRIExposure + + Comment + Exposure adjustment of HDRI when previewing an HDRI. Units are EV. Sane values would be -10 to 10. + Persist + 1 + Type + F32 + Value + 0.0 + + RenderHDRIRotation + + Comment + Rotation (in degrees) of environment when previewing an HDRI. + Persist + 1 + Type + F32 + Value + 0.0 + + RenderHDRISplitScreen + + Comment + What percentage of screen to render using HDRI vs EEP sky. + Persist + 1 + Type + F32 + Value + 1.0 + + RenderHDRIIrradianceOnly + + Comment + Only use HDRI sky for irradiance map when RenderHDRISplitScreen is 0 + Persist + 1 + Type + Boolean + Value + 0 + RenderMaxOpenGLVersion Comment @@ -11062,6 +11117,17 @@ Change of this parameter will affect the layout of buttons in notification toast U32 Value 16 + + RenderMaxTextureResolution + + Comment + Maximum texture resolution to download for non-boosted textures. + Persist + 1 + Type + U32 + Value + 2048 RenderDebugTextureBind @@ -12174,6 +12240,50 @@ Change of this parameter will affect the layout of buttons in notification toast Value 0 + RenderHeroProbeResolution + + Comment + Resolution to render hero probes used for mirrors, water, etc. + Persist + 1 + Type + S32 + Value + 1024 + + RenderHeroProbeDistance + + Comment + Distance in meters for hero probes to render out to. + Persist + 1 + Type + F32 + Value + 8 + + RenderHeroProbeUpdateRate + + Comment + How many frames to wait for until it's time to render the probe. E.g., every other frame (1), every two frames (2), every three frames (3) etc. + Persist + 1 + Type + S32 + Value + 2 + + RenderHeroProbeConservativeUpdateMultiplier + + Comment + How many probe updates to wait until it's time to update faces that are not directly facing the camera. Acts as a multiplier. E.g., frames to the periphery of the camera updating once every 3 updates, vs ones directly facing the camera updating every update. + Persist + 1 + Type + S32 + Value + 16 + RenderReflectionProbeVolumes Comment @@ -12390,51 +12500,62 @@ Change of this parameter will affect the layout of buttons in notification toast 3 RenderReflectionRes - - Comment - Reflection map resolution. - Persist - 1 - Type - S32 - Value - 64 - - RenderResolutionDivisor - - Comment - Divisor for rendering 3D scene at reduced resolution. - Persist - 1 - Type - U32 - Value - 1 - Backup - 0 - - RenderResolutionMultiplier - - Comment - Multiplier for rendering 3D scene at reduced resolution. Valid values: 0 < RenderResolutionMultiplier <= 1.0 - Persist - 1 - Type - F32 - Value - 1.0 - - RenderShaderLightingMaxLevel - - Comment - Max lighting level to use in the shader (class 3 is default, 2 is less lights, 1 is sun/moon only. Works around shader compiler bugs on certain platforms.) - Persist - 1 - Type - S32 - Value - 3 - + + Comment + Reflection map resolution. + Persist + 1 + Type + S32 + Value + 64 + + RenderReservedTextureIndices + + Comment + Count of texture indices to reserve for shadow and reflection maps when using indexed texture rendering. Probably only want to set from the login screen. + Persist + 1 + Type + S32 + Value + 14 + + RenderResolutionDivisor + + Comment + Divisor for rendering 3D scene at reduced resolution. + Persist + 1 + Type + U32 + Value + 1 + Backup + 0 + + RenderResolutionMultiplier + + Comment + Multiplier for rendering 3D scene at reduced resolution. Valid values: 0 < RenderResolutionMultiplier <= 1.0 + Persist + 1 + Type + F32 + Value + 1.0 + + RenderShaderLightingMaxLevel + + Comment + Max lighting level to use in the shader (class 3 is default, 2 is less lights, 1 is sun/moon only. Works around shader compiler bugs on certain platforms.) + Persist + 1 + Type + S32 + Value + 3 + RenderSkyAutoAdjustLegacy Comment @@ -12556,6 +12677,17 @@ Change of this parameter will affect the layout of buttons in notification toast F32 Value 0.5 + + RenderDiffuseLuminanceScale + + Comment + Luminance adjustment for diffuse surfaces to aid auto-exposure behavior + Persist + 0 + Type + F32 + Value + 0.5 RenderShaderLODThreshold @@ -12621,7 +12753,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 @@ -12629,6 +12761,83 @@ Change of this parameter will affect the layout of buttons in notification toast Value 12.0 + RenderTerrainPBREnabled + + Comment + EXPERIMENTAL: Enable PBR Terrain features. + Persist + 1 + Type + Boolean + Value + 0 + + RenderTerrainPBRForce + + Comment + Force-load PBR terrain if enabled + Persist + 0 + Type + Boolean + Value + 0 + + RenderTerrainPBRDetail + + Comment + Detail level for PBR terrain. 0 is full detail. Negative values drop rendering features, in accordance with the GLTF specification when possible, which reduces the number of texture binds. + Persist + 1 + Type + S32 + Value + 0 + + RenderTerrainPBRScale + + Comment + PBR terrain detail texture scale (meters) + Persist + 1 + Type + F32 + Value + 8.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 + + RenderTerrainPBRNormalsEnabled + + Comment + EXPERIMENTAL: Change normal gen for PBR Terrain. + Persist + 1 + Type + Boolean + Value + 0 + RenderTrackerBeacon Comment @@ -15563,6 +15772,17 @@ Change of this parameter will affect the layout of buttons in notification toast Value 2 + UIPreviewMaterial + + Comment + Whether or not PBR material swatch is enabled + Persist + 1 + Type + Boolean + Value + 0 + UIResizeBarHeight Comment @@ -17881,7 +18101,7 @@ Change of this parameter will affect the layout of buttons in notification toast Type S32 Value - 2048 + 1024 max_texture_dimension_Y @@ -17892,7 +18112,7 @@ Change of this parameter will affect the layout of buttons in notification toast Type S32 Value - 2048 + 1024 teleport_offer_invitation_max_length @@ -19352,6 +19572,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/avatarEyesV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarEyesV.glsl index d9a6c9e5f1..d3ca3ec8c1 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/avatarEyesV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/avatarEyesV.glsl @@ -26,6 +26,7 @@ uniform mat3 normal_matrix; uniform mat4 texture_matrix0; uniform mat4 modelview_projection_matrix; +uniform mat4 modelview_matrix; in vec3 position; in vec3 normal; @@ -35,10 +36,12 @@ in vec2 texcoord0; out vec3 vary_normal; out vec4 vertex_color; out vec2 vary_texcoord0; +out vec3 vary_position; void main() { //transform vertex + vary_position = (modelview_matrix * vec4(position.xyz, 1.0)).xyz; gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl index 63d8e12e62..b904df3a1b 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl @@ -25,7 +25,7 @@ /*[EXTRA_CODE_HERE]*/ -out vec4 frag_data[3]; +out vec4 frag_data[4]; uniform sampler2D diffuseMap; @@ -33,11 +33,14 @@ uniform float minimum_alpha; in vec3 vary_normal; in vec2 vary_texcoord0; +in vec3 vary_position; -vec2 encode_normal(vec3 n); +void mirrorClip(vec3 pos); void main() { + mirrorClip(vary_position); + vec4 diff = texture(diffuseMap, vary_texcoord0.xy); if (diff.a < minimum_alpha) @@ -48,6 +51,7 @@ void main() frag_data[0] = vec4(diff.rgb, 0.0); frag_data[1] = vec4(0,0,0,0); vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS); + frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS); + frag_data[3] = vec4(0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarV.glsl index 74d16592de..aabbbac12a 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/avatarV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/avatarV.glsl @@ -35,6 +35,7 @@ in vec4 weight; out vec3 vary_normal; out vec2 vary_texcoord0; +out vec3 vary_position; void main() { @@ -57,6 +58,7 @@ void main() vary_normal = norm; + vary_position = pos.xyz; gl_Position = projection_matrix * pos; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl index 19fc660c2d..8627ab1852 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl @@ -1,24 +1,24 @@ -/** +/** * @file blurLightF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2007, 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$ */ @@ -40,18 +40,18 @@ uniform float kern_scale; in vec2 vary_fragcoord; vec4 getPosition(vec2 pos_screen); -vec3 getNorm(vec2 pos_screen); +vec4 getNorm(vec2 pos_screen); -void main() +void main() { vec2 tc = vary_fragcoord.xy; - vec3 norm = getNorm(tc); + vec4 norm = getNorm(tc); vec3 pos = getPosition(tc).xyz; vec4 ccol = texture(lightMap, tc).rgba; - + vec2 dlt = kern_scale * delta / (1.0+norm.xy*norm.xy); dlt /= max(-pos.z*dist_factor, 1.0); - + vec2 defined_weight = kern[0].xy; // special case the first (centre) sample's weight in the blur; we have to sample it anyway so we get it for 'free' vec4 col = defined_weight.xyxx * ccol; @@ -75,15 +75,15 @@ void main() k[1] = (k[0]+k[2])*0.5f; k[3] = (k[2]+k[4])*0.5f; k[5] = (k[4]+k[6])*0.5f; - + for (int i = 1; i < 7; i++) { vec2 samptc = tc + k[i].z*dlt*2.0; samptc /= screen_res; - vec3 samppos = getPosition(samptc).xyz; + vec3 samppos = getPosition(samptc).xyz; float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane - + if (d*d <= pointplanedist_tolerance_pow2) { col += texture(lightMap, samptc)*k[i].xyxx; @@ -95,10 +95,10 @@ void main() { vec2 samptc = tc - k[i].z*dlt*2.0; samptc /= screen_res; - vec3 samppos = getPosition(samptc).xyz; + vec3 samppos = getPosition(samptc).xyz; float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane - + if (d*d <= pointplanedist_tolerance_pow2) { col += texture(lightMap, samptc)*k[i].xyxx; @@ -108,7 +108,7 @@ void main() col /= defined_weight.xyxx; //col.y *= col.y; - + frag_color = max(col, vec4(0)); #ifdef IS_AMD_CARD diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl index 11deecafbb..2cc3085cd0 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl @@ -37,11 +37,13 @@ in vec3 vary_mat2; in vec4 vertex_color; in vec2 vary_texcoord0; +in vec3 vary_position; -vec2 encode_normal(vec3 n); - +void mirrorClip(vec3 pos); void main() { + mirrorClip(vary_position); + vec4 col = texture(diffuseMap, vary_texcoord0.xy); if(col.a < minimum_alpha) @@ -60,6 +62,6 @@ void main() frag_data[1] = vertex_color.aaaa; // spec //frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested vec3 nvn = normalize(tnorm); - frag_data[2] = vec4(encode_normal(nvn), vertex_color.a, GBUFFER_FLAG_HAS_ATMOS); - frag_data[3] = vec4(0); + frag_data[2] = vec4(nvn, GBUFFER_FLAG_HAS_ATMOS); + frag_data[3] = vec4(vertex_color.a, 0, 0, 0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl index 4ac757be65..a381392f6c 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl @@ -23,6 +23,7 @@ * $/LicenseInfo$ */ +uniform mat4 modelview_matrix; uniform mat3 normal_matrix; uniform mat4 texture_matrix0; uniform mat4 modelview_projection_matrix; @@ -38,11 +39,11 @@ out vec3 vary_mat1; out vec3 vary_mat2; out vec4 vertex_color; out vec2 vary_texcoord0; +out vec3 vary_position; #ifdef HAS_SKIN mat4 getObjectSkinnedTransform(); uniform mat4 projection_matrix; -uniform mat4 modelview_matrix; #endif void main() @@ -52,11 +53,13 @@ void main() mat4 mat = getObjectSkinnedTransform(); mat = modelview_matrix * mat; vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz; + vary_position = pos; gl_Position = projection_matrix*vec4(pos, 1.0); vec3 n = normalize((mat * vec4(normal.xyz+position.xyz, 1.0)).xyz-pos.xyz); vec3 t = normalize((mat * vec4(tangent.xyz+position.xyz, 1.0)).xyz-pos.xyz); #else + vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz; gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); vec3 n = normalize(normal_matrix * normal); vec3 t = normalize(normal_matrix * tangent.xyz); diff --git a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl index 5ef3d63eb2..01543732d0 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl @@ -50,6 +50,7 @@ SOFTWARE. uniform sampler2D normalMap; uniform sampler2D depthMap; +uniform sampler2D emissiveRect; uniform sampler2D projectionMap; // rgba uniform sampler2D brdfLut; @@ -140,40 +141,11 @@ vec2 getScreenCoordinate(vec2 screenpos) return sc - vec2(1.0, 1.0); } -// See: https://aras-p.info/texts/CompactNormalStorage.html -// Method #4: Spheremap Transform, Lambert Azimuthal Equal-Area projection -vec3 getNorm(vec2 screenpos) +vec4 getNorm(vec2 screenpos) { - vec2 enc = texture(normalMap, screenpos.xy).xy; - vec2 fenc = enc*4-2; - float f = dot(fenc,fenc); - float g = sqrt(1-f/4); - vec3 n; - n.xy = fenc*g; - n.z = 1-f/2; - return n; -} - -vec3 getNormalFromPacked(vec4 packedNormalEnvIntensityFlags) -{ - vec2 enc = packedNormalEnvIntensityFlags.xy; - vec2 fenc = enc*4-2; - float f = dot(fenc,fenc); - float g = sqrt(1-f/4); - vec3 n; - n.xy = fenc*g; - n.z = 1-f/2; - return normalize(n); // TODO: Is this normalize redundant? -} - -// return packedNormalEnvIntensityFlags since GBUFFER_FLAG_HAS_PBR needs .w -// See: C++: addDeferredAttachments(), GLSL: softenLightF -vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity) -{ - vec4 packedNormalEnvIntensityFlags = texture(normalMap, screenpos.xy); - n = getNormalFromPacked( packedNormalEnvIntensityFlags ); - envIntensity = packedNormalEnvIntensityFlags.z; - return packedNormalEnvIntensityFlags; + vec4 norm = texture(normalMap, screenpos.xy); + norm.xyz = normalize(norm.xyz); + return norm; } // get linear depth value given a depth buffer sample d and znear and zfar values diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl index c2fb3201f4..1751e17814 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl @@ -31,14 +31,18 @@ uniform float minimum_alpha; uniform sampler2D diffuseMap; +in vec3 vary_position; + in vec3 vary_normal; in vec4 vertex_color; in vec2 vary_texcoord0; -vec2 encode_normal(vec3 n); +void mirrorClip(vec3 pos); void main() { + mirrorClip(vary_position); + vec4 col = texture(diffuseMap, vary_texcoord0.xy) * vertex_color; if (col.a < minimum_alpha) @@ -49,7 +53,7 @@ void main() frag_data[0] = vec4(col.rgb, 0.0); frag_data[1] = vec4(0,0,0,0); // spec vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS); + frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS); frag_data[3] = vec4(0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl index dce1f91bc3..f5b517a8ea 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl @@ -28,16 +28,19 @@ out vec4 frag_data[4]; in vec3 vary_normal; +in vec3 vary_position; uniform float minimum_alpha; in vec4 vertex_color; in vec2 vary_texcoord0; -vec2 encode_normal(vec3 n); +void mirrorClip(vec3 pos); void main() { + mirrorClip(vary_position); + vec4 col = diffuseLookup(vary_texcoord0.xy) * vertex_color; if (col.a < minimum_alpha) @@ -48,6 +51,6 @@ void main() frag_data[0] = vec4(col.rgb, 0.0); frag_data[1] = vec4(0,0,0,0); vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS); + frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS); frag_data[3] = vec4(0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl index 1fc719dde5..89ea0c1710 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl @@ -34,8 +34,6 @@ uniform sampler2D diffuseMap; in vec3 vary_normal; in vec2 vary_texcoord0; -vec2 encode_normal(vec3 n); - void main() { vec4 col = texture(diffuseMap, vary_texcoord0.xy); @@ -48,7 +46,7 @@ void main() frag_data[0] = vec4(col.rgb, 0.0); frag_data[1] = vec4(0,0,0,0); // spec vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS); + frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS); frag_data[3] = vec4(0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl index d3d375b20a..7f056a51e8 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl @@ -32,17 +32,19 @@ uniform sampler2D diffuseMap; in vec3 vary_normal; in vec4 vertex_color; in vec2 vary_texcoord0; +in vec3 vary_position; -vec2 encode_normal(vec3 n); +void mirrorClip(vec3 pos); void main() { + mirrorClip(vary_position); vec3 col = vertex_color.rgb * texture(diffuseMap, vary_texcoord0.xy).rgb; frag_data[0] = vec4(col, 0.0); frag_data[1] = vertex_color.aaaa; // spec //frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), vertex_color.a, GBUFFER_FLAG_HAS_ATMOS); - frag_data[3] = vec4(0); + frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS); + frag_data[3] = vec4(vertex_color.a, 0, 0, 0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl index afdd043c7c..5c73878ba9 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl @@ -30,12 +30,14 @@ out vec4 frag_data[4]; in vec3 vary_normal; in vec4 vertex_color; in vec2 vary_texcoord0; +in vec3 vary_position; -vec2 encode_normal(vec3 n); +void mirrorClip(vec3 pos); vec3 linear_to_srgb(vec3 c); void main() { + mirrorClip(vary_position); vec3 col = vertex_color.rgb * diffuseLookup(vary_texcoord0.xy).rgb; vec3 spec; @@ -44,6 +46,6 @@ void main() frag_data[0] = vec4(col, 0.0); frag_data[1] = vec4(spec, vertex_color.a); // spec vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), vertex_color.a, GBUFFER_FLAG_HAS_ATMOS); - frag_data[3] = vec4(0); + frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS); + frag_data[3] = vec4(vertex_color.a, 0, 0, 0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl index 304c01ecc3..4bd31cef9e 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl @@ -36,13 +36,16 @@ out vec3 vary_normal; out vec4 vertex_color; out vec2 vary_texcoord0; +out vec3 vary_position; void passTextureIndex(); +uniform mat4 modelview_matrix; + #ifdef HAS_SKIN mat4 getObjectSkinnedTransform(); uniform mat4 projection_matrix; -uniform mat4 modelview_matrix; + #endif void main() @@ -51,9 +54,11 @@ void main() mat4 mat = getObjectSkinnedTransform(); mat = modelview_matrix * mat; vec4 pos = mat * vec4(position.xyz, 1.0); + vary_position = pos.xyz; gl_Position = projection_matrix * pos; vary_normal = normalize((mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz); #else + vary_position = (modelview_matrix * vec4(position.xyz, 1.0)).xyz; gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); vary_normal = normalize(normal_matrix * normal); #endif diff --git a/indra/newview/app_settings/shaders/class1/deferred/exposureF.glsl b/indra/newview/app_settings/shaders/class1/deferred/exposureF.glsl index 709b47dcbd..eff7221ae7 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/exposureF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/exposureF.glsl @@ -1,34 +1,36 @@ -/** +/** * @file exposureF.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]*/ out vec4 frag_color; uniform sampler2D emissiveRect; +#ifdef USE_LAST_EXPOSURE uniform sampler2D exposureMap; +#endif uniform float dt; uniform vec2 noiseVec; @@ -41,7 +43,7 @@ float lum(vec3 col) return dot(l, col); } -void main() +void main() { vec2 tc = vec2(0.5,0.5); @@ -51,11 +53,13 @@ void main() L /= max_L; L = pow(L, 2.0); float s = mix(dynamic_exposure_params.z, dynamic_exposure_params.y, L); - + +#ifdef USE_LAST_EXPOSURE float prev = texture(exposureMap, vec2(0.5,0.5)).r; s = mix(prev, s, min(dt*2.0*abs(prev-s), 0.04)); - +#endif + frag_color = max(vec4(s, s, s, dt), vec4(0.0)); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl index ec6a4a502f..52dfed06ae 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl @@ -1,28 +1,28 @@ -/** +/** * @file deferred/fullbrightF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2007, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - + /*[EXTRA_CODE_HERE]*/ out vec4 frag_color; @@ -50,9 +50,11 @@ void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, ou vec4 applySkyAndWaterFog(vec3 pos, vec3 additive, vec3 atten, vec4 color); #endif -void main() -{ +void mirrorClip(vec3 pos); +void main() +{ + mirrorClip(vary_position); #ifdef IS_ALPHA waterClip(vary_position.xyz); #endif @@ -88,7 +90,7 @@ void main() calcAtmosphericVars(pos.xyz, vec3(0), 1.0, sunlit, amblit, additive, atten); color.rgb = applySkyAndWaterFog(pos, additive, atten, color).rgb; - + #endif #endif diff --git a/indra/newview/app_settings/shaders/class1/deferred/globalF.glsl b/indra/newview/app_settings/shaders/class1/deferred/globalF.glsl new file mode 100644 index 0000000000..7e3e7d9271 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/globalF.glsl @@ -0,0 +1,45 @@ +/** + * @file class1/deferred/globalF.glsl + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + + // Global helper functions included in every fragment shader + // DO NOT declare sampler uniforms here as OS X doesn't compile + // them out + +uniform float mirror_flag; +uniform vec4 clipPlane; +uniform float clipSign; + +void mirrorClip(vec3 pos) +{ + if (mirror_flag > 0) + { + if ((dot(pos.xyz, clipPlane.xyz) + clipPlane.w) < 0.0) + { + discard; + } + } +} + diff --git a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl index 5561a3d488..99cb23839a 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl @@ -37,7 +37,6 @@ uniform sampler2D specularMap; in vec2 vary_texcoord0; vec3 linear_to_srgb(vec3 c); -vec2 encode_normal (vec3 n); void main() { @@ -53,6 +52,6 @@ void main() frag_data[0] = vec4(col.rgb, 0.0); frag_data[1] = spec; - frag_data[2] = vec4(encode_normal(norm.xyz),0,GBUFFER_FLAG_HAS_ATMOS); + frag_data[2] = vec4(norm.xyz, GBUFFER_FLAG_HAS_ATMOS); frag_data[3] = vec4(0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl b/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl index b9337a357f..95b2f80e06 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl @@ -1,32 +1,32 @@ -/** +/** * @file luminanceF.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]*/ -// take a luminance sample of diffuseRect and emissiveRect +// take a luminance sample of diffuseRect and emissiveRect out vec4 frag_color; @@ -34,6 +34,8 @@ in vec2 vary_fragcoord; uniform sampler2D diffuseRect; uniform sampler2D emissiveRect; +uniform sampler2D normalMap; +uniform float diffuse_luminance_scale; float lum(vec3 col) { @@ -41,11 +43,25 @@ float lum(vec3 col) return dot(l, col); } -void main() +void main() { vec2 tc = vary_fragcoord*0.6+0.2; tc.y -= 0.1; // HACK - nudge exposure sample down a little bit to favor ground over sky - vec3 c = texture(diffuseRect, tc).rgb + texture(emissiveRect, tc).rgb; + vec3 c = texture(diffuseRect, tc).rgb; + + vec4 norm = texture(normalMap, tc); + + if (!GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_HDRI) && + !GET_GBUFFER_FLAG(GBUFFER_FLAG_SKIP_ATMOS)) + { + // Apply the diffuse luminance scale to objects but not the sky + // Prevents underexposing when looking at bright environments + // while still allowing for realistically bright skies. + c *= diffuse_luminance_scale; + } + + c += texture(emissiveRect, tc).rgb; + float L = lum(c); frag_color = vec4(max(L, 0.0)); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl index 5e48ff709f..b6528dfcf8 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl @@ -28,25 +28,18 @@ #define DIFFUSE_ALPHA_MODE_MASK 2 #define DIFFUSE_ALPHA_MODE_EMISSIVE 3 -#ifdef HAS_SKIN uniform mat4 modelview_matrix; uniform mat4 projection_matrix; +uniform mat4 modelview_projection_matrix; + +#ifdef HAS_SKIN mat4 getObjectSkinnedTransform(); #else uniform mat3 normal_matrix; -uniform mat4 modelview_projection_matrix; -#endif - -#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) - -#if !defined(HAS_SKIN) -uniform mat4 modelview_matrix; #endif out vec3 vary_position; -#endif - uniform mat4 texture_matrix0; in vec3 position; @@ -85,9 +78,7 @@ void main() vec3 pos = (mat*vec4(position.xyz,1.0)).xyz; -#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) vary_position = pos; -#endif gl_Position = projection_matrix*vec4(pos,1.0); @@ -133,10 +124,8 @@ void main() vertex_color = diffuse_color; -#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) #if !defined(HAS_SKIN) vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz; #endif -#endif } diff --git a/indra/newview/app_settings/shaders/class1/deferred/moonF.glsl b/indra/newview/app_settings/shaders/class1/deferred/moonF.glsl index 03a8518c36..6ef556d7e8 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/moonF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/moonF.glsl @@ -1,28 +1,28 @@ -/** +/** * @file class1\deferred\moonF.glsl * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2005, 2020 Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - + /*[EXTRA_CODE_HERE]*/ out vec4 frag_data[4]; @@ -34,7 +34,7 @@ uniform sampler2D diffuseMap; in vec2 vary_texcoord0; -void main() +void main() { // Restore Pre-EEP alpha fade moon near horizon float fade = 1.0; @@ -55,7 +55,7 @@ void main() frag_data[0] = vec4(0); frag_data[1] = vec4(0.0); - frag_data[2] = vec4(0.0, 0.0, 0.0, GBUFFER_FLAG_HAS_ATMOS); + frag_data[2] = vec4(0.0, 0.0, 0.0, GBUFFER_FLAG_SKIP_ATMOS); frag_data[3] = vec4(c.rgb, c.a); // Added and commented out for a ground truth. Do not uncomment - Geenz diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrShadowAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrShadowAlphaMaskF.glsl index c1fb9f5d84..35b7602569 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbrShadowAlphaMaskF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbrShadowAlphaMaskF.glsl @@ -1,24 +1,24 @@ -/** +/** * @file pbrShadowAlphaMaskF.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$ */ @@ -33,9 +33,9 @@ in vec4 vertex_color; in vec2 vary_texcoord0; uniform float minimum_alpha; -void main() +void main() { - float alpha = texture(diffuseMap,vary_texcoord0.xy).a; + float alpha = texture(diffuseMap,vary_texcoord0.xy).a * vertex_color.a; if (alpha < minimum_alpha) { diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl index ed19fba228..380d493636 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl @@ -1,24 +1,24 @@ -/** +/** * @file pbropaqueF.glsl * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2022, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -28,7 +28,7 @@ #ifndef IS_HUD -// deferred opaque implementation +// deferred opaque implementation uniform sampler2D diffuseMap; //always in sRGB space @@ -54,28 +54,38 @@ in vec2 emissive_texcoord; uniform float minimum_alpha; // PBR alphaMode: MASK, See: mAlphaCutoff, setAlphaCutoff() -vec2 encode_normal(vec3 n); vec3 linear_to_srgb(vec3 c); vec3 srgb_to_linear(vec3 c); +uniform vec4 clipPlane; +uniform float clipSign; + +void mirrorClip(vec3 pos); + uniform mat3 normal_matrix; void main() { + mirrorClip(vary_position); + vec4 basecolor = texture(diffuseMap, base_color_texcoord.xy).rgba; + basecolor.rgb = srgb_to_linear(basecolor.rgb); + + basecolor *= vertex_color; + if (basecolor.a < minimum_alpha) { discard; } - vec3 col = vertex_color.rgb * srgb_to_linear(basecolor.rgb); + vec3 col = basecolor.rgb; // from mikktspace.com vec3 vNt = texture(bumpMap, normal_texcoord.xy).xyz*2.0-1.0; float sign = vary_sign; vec3 vN = vary_normal; vec3 vT = vary_tangent.xyz; - + vec3 vB = sign * cross(vN, vT); vec3 tnorm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); @@ -85,7 +95,7 @@ void main() // roughness 0.0 // metal 0.0 vec3 spec = texture(specularMap, metallic_roughness_texcoord.xy).rgb; - + spec.g *= roughnessFactor; spec.b *= metallicFactor; @@ -102,8 +112,8 @@ void main() //emissive = tnorm*0.5+0.5; // See: C++: addDeferredAttachments(), GLSL: softenLightF frag_data[0] = max(vec4(col, 0.0), vec4(0)); // Diffuse - frag_data[1] = max(vec4(spec.rgb,vertex_color.a), vec4(0)); // PBR linear packed Occlusion, Roughness, Metal. - frag_data[2] = max(vec4(encode_normal(tnorm), vertex_color.a, GBUFFER_FLAG_HAS_PBR), vec4(0)); // normal, environment intensity, flags + frag_data[1] = max(vec4(spec.rgb,0.0), vec4(0)); // PBR linear packed Occlusion, Roughness, Metal. + frag_data[2] = vec4(tnorm, GBUFFER_FLAG_HAS_PBR); // 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/pbropaqueV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl index 53e4b732df..fd020afd57 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl @@ -28,8 +28,9 @@ //deferred opaque implementation -#ifdef HAS_SKIN uniform mat4 modelview_matrix; + +#ifdef HAS_SKIN uniform mat4 projection_matrix; mat4 getObjectSkinnedTransform(); #else @@ -59,6 +60,7 @@ out vec4 vertex_color; out vec3 vary_tangent; flat out float vary_sign; out vec3 vary_normal; +out vec3 vary_position; vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); @@ -71,10 +73,11 @@ void main() mat = modelview_matrix * mat; vec3 pos = (mat*vec4(position.xyz,1.0)).xyz; - + vary_position = pos; gl_Position = projection_matrix*vec4(pos,1.0); #else + vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz; //transform vertex gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); #endif 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..0de2d348c3 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl @@ -0,0 +1,347 @@ +/** + * @file class1\deferred\terrainF.glsl + * + * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2023, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +/*[EXTRA_CODE_HERE]*/ + +#define TERRAIN_PBR_DETAIL_EMISSIVE 0 +#define TERRAIN_PBR_DETAIL_OCCLUSION -1 +#define TERRAIN_PBR_DETAIL_NORMAL -2 +#define TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS -3 + +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 +#define TerrainCoord vec4[2] +#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1 +#define TerrainCoord vec2 +#endif + +#define MIX_X 1 << 3 +#define MIX_Y 1 << 4 +#define MIX_Z 1 << 5 +#define MIX_W 1 << 6 + +struct TerrainMix +{ + vec4 weight; + int type; +}; + +TerrainMix get_terrain_mix_weights(float alpha1, float alpha2, float alphaFinal); + +struct PBRMix +{ + vec4 col; // RGB color with alpha, linear space +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION) + vec3 orm; // Occlusion, roughness, metallic +#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + vec2 rm; // Roughness, metallic +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) + vec3 vNt; // Unpacked normal texture sample, vector +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + vec3 emissive; // RGB emissive color, linear space +#endif +}; + +PBRMix init_pbr_mix(); + +PBRMix terrain_sample_and_multiply_pbr( + TerrainCoord terrain_coord + , sampler2D tex_col +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + , sampler2D tex_orm +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) + , sampler2D tex_vNt +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , sampler2D tex_emissive +#endif + , vec4 factor_col +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION) + , vec3 factor_orm +#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + , vec2 factor_rm +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , vec3 factor_emissive +#endif + ); + +PBRMix mix_pbr(PBRMix mix1, PBRMix mix2, float mix2_weight); + +out vec4 frag_data[4]; + +uniform sampler2D alpha_ramp; + +// https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#additional-textures +uniform sampler2D detail_0_base_color; +uniform sampler2D detail_1_base_color; +uniform sampler2D detail_2_base_color; +uniform sampler2D detail_3_base_color; +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) +uniform sampler2D detail_0_normal; +uniform sampler2D detail_1_normal; +uniform sampler2D detail_2_normal; +uniform sampler2D detail_3_normal; +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) +uniform sampler2D detail_0_metallic_roughness; +uniform sampler2D detail_1_metallic_roughness; +uniform sampler2D detail_2_metallic_roughness; +uniform sampler2D detail_3_metallic_roughness; +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) +uniform sampler2D detail_0_emissive; +uniform sampler2D detail_1_emissive; +uniform sampler2D detail_2_emissive; +uniform sampler2D detail_3_emissive; +#endif + +uniform vec4[4] baseColorFactors; // See also vertex_color in pbropaqueV.glsl +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) +uniform vec4 metallicFactors; +uniform vec4 roughnessFactors; +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) +uniform vec3[4] emissiveColors; +#endif +uniform vec4 minimum_alphas; // PBR alphaMode: MASK, See: mAlphaCutoff, setAlphaCutoff() + +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 +in vec4[2] vary_coords; +#endif +in vec3 vary_position; +in vec3 vary_normal; +in vec3 vary_tangent; +flat in float vary_sign; +in vec4 vary_texcoord0; +in vec4 vary_texcoord1; + +void mirrorClip(vec3 position); + +float terrain_mix(TerrainMix tm, vec4 tms4); + +void main() +{ + // Make sure we clip the terrain if we're in a mirror. + mirrorClip(vary_position); + +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 + TerrainCoord terrain_texcoord = vary_coords; +#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1 + TerrainCoord terrain_texcoord = vary_texcoord0.xy; +#endif + + float alpha1 = texture(alpha_ramp, vary_texcoord0.zw).a; + float alpha2 = texture(alpha_ramp,vary_texcoord1.xy).a; + float alphaFinal = texture(alpha_ramp, vary_texcoord1.zw).a; + + TerrainMix tm = get_terrain_mix_weights(alpha1, alpha2, alphaFinal); + +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION) + // RGB = Occlusion, Roughness, Metal + // default values, see LLViewerTexture::sDefaultPBRORMImagep + // occlusion 1.0 + // roughness 0.0 + // metal 0.0 + vec3[4] orm_factors; + orm_factors[0] = vec3(1.0, roughnessFactors.x, metallicFactors.x); + orm_factors[1] = vec3(1.0, roughnessFactors.y, metallicFactors.y); + orm_factors[2] = vec3(1.0, roughnessFactors.z, metallicFactors.z); + orm_factors[3] = vec3(1.0, roughnessFactors.w, metallicFactors.w); +#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + vec2[4] rm_factors; + rm_factors[0] = vec2(roughnessFactors.x, metallicFactors.x); + rm_factors[1] = vec2(roughnessFactors.y, metallicFactors.y); + rm_factors[2] = vec2(roughnessFactors.z, metallicFactors.z); + rm_factors[3] = vec2(roughnessFactors.w, metallicFactors.w); +#endif + + PBRMix pbr_mix = init_pbr_mix(); + PBRMix mix2; + switch (tm.type & MIX_X) + { + case MIX_X: + mix2 = terrain_sample_and_multiply_pbr( + terrain_texcoord + , detail_0_base_color +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + , detail_0_metallic_roughness +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) + , detail_0_normal +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , detail_0_emissive +#endif + , baseColorFactors[0] +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION) + , orm_factors[0] +#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + , rm_factors[0] +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , emissiveColors[0] +#endif + ); + pbr_mix = mix_pbr(pbr_mix, mix2, tm.weight.x); + break; + default: + break; + } + switch (tm.type & MIX_Y) + { + case MIX_Y: + mix2 = terrain_sample_and_multiply_pbr( + terrain_texcoord + , detail_1_base_color +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + , detail_1_metallic_roughness +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) + , detail_1_normal +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , detail_1_emissive +#endif + , baseColorFactors[1] +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION) + , orm_factors[1] +#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + , rm_factors[1] +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , emissiveColors[1] +#endif + ); + pbr_mix = mix_pbr(pbr_mix, mix2, tm.weight.y); + break; + default: + break; + } + switch (tm.type & MIX_Z) + { + case MIX_Z: + mix2 = terrain_sample_and_multiply_pbr( + terrain_texcoord + , detail_2_base_color +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + , detail_2_metallic_roughness +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) + , detail_2_normal +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , detail_2_emissive +#endif + , baseColorFactors[2] +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION) + , orm_factors[2] +#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + , rm_factors[2] +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , emissiveColors[2] +#endif + ); + pbr_mix = mix_pbr(pbr_mix, mix2, tm.weight.z); + break; + default: + break; + } + switch (tm.type & MIX_W) + { + case MIX_W: + mix2 = terrain_sample_and_multiply_pbr( + terrain_texcoord + , detail_3_base_color +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + , detail_3_metallic_roughness +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) + , detail_3_normal +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , detail_3_emissive +#endif + , baseColorFactors[3] +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION) + , orm_factors[3] +#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + , rm_factors[3] +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , emissiveColors[3] +#endif + ); + pbr_mix = mix_pbr(pbr_mix, mix2, tm.weight.w); + break; + default: + break; + } + + float minimum_alpha = terrain_mix(tm, minimum_alphas); + if (pbr_mix.col.a < minimum_alpha) + { + discard; + } + float base_color_factor_alpha = terrain_mix(tm, vec4(baseColorFactors[0].z, baseColorFactors[1].z, baseColorFactors[2].z, baseColorFactors[3].z)); + +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) + // from mikktspace.com + vec3 vNt = pbr_mix.vNt; + vec3 vN = vary_normal; + vec3 vT = vary_tangent.xyz; + + vec3 vB = vary_sign * cross(vN, vT); + vec3 tnorm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); + + tnorm *= gl_FrontFacing ? 1.0 : -1.0; +#else + vec3 tnorm = vary_normal; + tnorm *= gl_FrontFacing ? 1.0 : -1.0; +#endif + + +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) +#define mix_emissive pbr_mix.emissive +#else +#define mix_emissive vec3(0) +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION) +#define mix_orm pbr_mix.orm +#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) +#define mix_orm vec3(1.0, pbr_mix.rm) +#else +// Matte plastic potato terrain +#define mix_orm vec3(1.0, 1.0, 0.0) +#endif + frag_data[0] = max(vec4(pbr_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] = vec4(tnorm, GBUFFER_FLAG_HAS_PBR); // normal, flags + frag_data[3] = max(vec4(mix_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..935c3f9301 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl @@ -0,0 +1,473 @@ +/** + * @file class1\deferred\pbrterrainUtilF.glsl + * + * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2023, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +/*[EXTRA_CODE_HERE]*/ + +/** + * Triplanar mapping implementation adapted from Inigo Quilez' example shader, + * MIT license. + * https://www.shadertoy.com/view/MtsGWH + * Copyright © 2015 Inigo Quilez + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: The above copyright + * notice and this permission notice shall be included in all copies or + * substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", + * WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#define TERRAIN_PBR_DETAIL_EMISSIVE 0 +#define TERRAIN_PBR_DETAIL_OCCLUSION -1 +#define TERRAIN_PBR_DETAIL_NORMAL -2 +#define TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS -3 + +in vec3 vary_vertex_normal; + +vec3 srgb_to_linear(vec3 c); + +// A relatively agressive threshold for terrain material mixing sampling +// cutoff. This ensures that only one or two materials are used in most places, +// making PBR terrain blending more performant. Should be greater than 0 to work. +#define TERRAIN_RAMP_MIX_THRESHOLD 0.1 +// A small threshold for triplanar mapping sampling cutoff. This and +// TERRAIN_TRIPLANAR_BLEND_FACTOR together ensures that only one or two samples +// per texture are used in most places, making triplanar mapping more +// performant. Should be greater than 0 to work. +// There's also an artistic design choice in the use of these factors, and the +// use of triplanar generally. Don't take these triplanar constants for granted. +#define TERRAIN_TRIPLANAR_MIX_THRESHOLD 0.01 + +#define SAMPLE_X 1 << 0 +#define SAMPLE_Y 1 << 1 +#define SAMPLE_Z 1 << 2 +#define MIX_X 1 << 3 +#define MIX_Y 1 << 4 +#define MIX_Z 1 << 5 +#define MIX_W 1 << 6 + +struct PBRMix +{ + vec4 col; // RGB color with alpha, linear space +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION) + vec3 orm; // Occlusion, roughness, metallic +#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + vec2 rm; // Roughness, metallic +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) + vec3 vNt; // Unpacked normal texture sample, vector +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + vec3 emissive; // RGB emissive color, linear space +#endif +}; + +PBRMix init_pbr_mix() +{ + PBRMix mix; + mix.col = vec4(0); +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION) + mix.orm = vec3(0); +#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + mix.rm = vec2(0); +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) + mix.vNt = vec3(0); +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + mix.emissive = vec3(0); +#endif + return mix; +} + +// Usage example, for two weights: +// vec2 weights = ... // Weights must add up to 1 +// PBRMix mix = init_pbr_mix(); +// PBRMix mix1 = ... +// mix = mix_pbr(mix, mix1, weights.x); +// PBRMix mix2 = ... +// mix = mix_pbr(mix, mix2, weights.y); +PBRMix mix_pbr(PBRMix mix1, PBRMix mix2, float mix2_weight) +{ + PBRMix mix; + mix.col = mix1.col + (mix2.col * mix2_weight); +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION) + mix.orm = mix1.orm + (mix2.orm * mix2_weight); +#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + mix.rm = mix1.rm + (mix2.rm * mix2_weight); +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) + mix.vNt = mix1.vNt + (mix2.vNt * mix2_weight); +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + mix.emissive = mix1.emissive + (mix2.emissive * mix2_weight); +#endif + return mix; +} + +PBRMix sample_pbr( + vec2 uv + , sampler2D tex_col +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + , sampler2D tex_orm +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) + , sampler2D tex_vNt +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , sampler2D tex_emissive +#endif + ) +{ + PBRMix mix; + mix.col = texture(tex_col, uv); + mix.col.rgb = srgb_to_linear(mix.col.rgb); +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION) + mix.orm = texture(tex_orm, uv).xyz; +#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + mix.rm = texture(tex_orm, uv).yz; +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) + mix.vNt = texture(tex_vNt, uv).xyz*2.0-1.0; +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + mix.emissive = srgb_to_linear(texture(tex_emissive, uv).xyz); +#endif + return mix; +} + +struct TerrainTriplanar +{ + vec3 weight; + int type; +}; + +struct TerrainMix +{ + vec4 weight; + int type; +}; + +#define TerrainMixSample vec4[4] +#define TerrainMixSample3 vec3[4] + +TerrainMix get_terrain_mix_weights(float alpha1, float alpha2, float alphaFinal) +{ + TerrainMix tm; + vec4 sample_x = vec4(1,0,0,0); + vec4 sample_y = vec4(0,1,0,0); + vec4 sample_z = vec4(0,0,1,0); + vec4 sample_w = vec4(0,0,0,1); + + tm.weight = mix( mix(sample_w, sample_z, alpha2), mix(sample_y, sample_x, alpha1), alphaFinal ); + tm.weight -= TERRAIN_RAMP_MIX_THRESHOLD; + ivec4 usage = max(ivec4(0), ivec4(ceil(tm.weight))); + // Prevent negative weights and keep weights balanced + tm.weight = tm.weight*vec4(usage); + tm.weight /= (tm.weight.x + tm.weight.y + tm.weight.z + tm.weight.w); + + tm.type = (usage.x * MIX_X) | + (usage.y * MIX_Y) | + (usage.z * MIX_Z) | + (usage.w * MIX_W); + return tm; +} + +TerrainTriplanar _t_triplanar() +{ + float sharpness = TERRAIN_TRIPLANAR_BLEND_FACTOR; + float threshold = TERRAIN_TRIPLANAR_MIX_THRESHOLD; + vec3 weight_signed = pow(abs(vary_vertex_normal), vec3(sharpness)); + weight_signed /= (weight_signed.x + weight_signed.y + weight_signed.z); + weight_signed -= vec3(threshold); + TerrainTriplanar tw; + // *NOTE: Make sure the threshold doesn't affect the materials + tw.weight = max(vec3(0), weight_signed); + tw.weight /= (tw.weight.x + tw.weight.y + tw.weight.z); + ivec3 usage = ivec3(round(max(vec3(0), sign(weight_signed)))); + tw.type = ((usage.x) * SAMPLE_X) | + ((usage.y) * SAMPLE_Y) | + ((usage.z) * SAMPLE_Z); + return tw; +} + +// Assume weights add to 1 +float terrain_mix(TerrainMix tm, vec4 tms4) +{ + return (tm.weight.x * tms4[0]) + + (tm.weight.y * tms4[1]) + + (tm.weight.z * tms4[2]) + + (tm.weight.w * tms4[3]); +} + +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 +// Triplanar mapping + +// Pre-transformed texture coordinates for each axial uv slice (Packing: xy, yz, (-x)z, unused) +#define TerrainCoord vec4[2] + +vec2 _t_uv(vec2 uv_unflipped, float sign_or_zero) +{ + // Handle case where sign is 0 + float sign = (2.0*sign_or_zero) + 1.0; + sign /= abs(sign); + // If the vertex normal is negative, flip the texture back + // right-side up. + vec2 uv = uv_unflipped * vec2(sign, 1); + return uv; +} + +vec3 _t_normal_post_1(vec3 vNt0, float sign_or_zero) +{ + // Assume normal is unpacked + vec3 vNt1 = vNt0; + // Get sign + float sign = sign_or_zero; + // Handle case where sign is 0 + sign = (2.0*sign) + 1.0; + sign /= abs(sign); + // If the sign is negative, rotate normal by 180 degrees + vNt1.xy = (min(0, sign) * vNt1.xy) + (min(0, -sign) * -vNt1.xy); + return vNt1; +} + +// Triplanar-specific normal texture fixes +vec3 _t_normal_post_x(vec3 vNt0) +{ + vec3 vNt_x = _t_normal_post_1(vNt0, sign(vary_vertex_normal.x)); + // *HACK: Transform normals according to orientation of the UVs + vNt_x.xy = vec2(-vNt_x.y, vNt_x.x); + return vNt_x; +} +vec3 _t_normal_post_y(vec3 vNt0) +{ + vec3 vNt_y = _t_normal_post_1(vNt0, sign(vary_vertex_normal.y)); + // *HACK: Transform normals according to orientation of the UVs + vNt_y.xy = -vNt_y.xy; + return vNt_y; +} +vec3 _t_normal_post_z(vec3 vNt0) +{ + vec3 vNt_z = _t_normal_post_1(vNt0, sign(vary_vertex_normal.z)); + return vNt_z; +} + +PBRMix terrain_sample_pbr( + TerrainCoord terrain_coord + , TerrainTriplanar tw + , sampler2D tex_col +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + , sampler2D tex_orm +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) + , sampler2D tex_vNt +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , sampler2D tex_emissive +#endif + ) +{ + PBRMix mix = init_pbr_mix(); + +#define get_uv_x() _t_uv(terrain_coord[0].zw, sign(vary_vertex_normal.x)) +#define get_uv_y() _t_uv(terrain_coord[1].xy, sign(vary_vertex_normal.y)) +#define get_uv_z() _t_uv(terrain_coord[0].xy, sign(vary_vertex_normal.z)) + switch (tw.type & SAMPLE_X) + { + case SAMPLE_X: + PBRMix mix_x = sample_pbr( + get_uv_x() + , tex_col +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + , tex_orm +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) + , tex_vNt +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , tex_emissive +#endif + ); +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) + // Triplanar-specific normal texture fix + mix_x.vNt = _t_normal_post_x(mix_x.vNt); +#endif + mix = mix_pbr(mix, mix_x, tw.weight.x); + break; + default: + break; + } + + switch (tw.type & SAMPLE_Y) + { + case SAMPLE_Y: + PBRMix mix_y = sample_pbr( + get_uv_y() + , tex_col +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + , tex_orm +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) + , tex_vNt +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , tex_emissive +#endif + ); +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) + // Triplanar-specific normal texture fix + mix_y.vNt = _t_normal_post_y(mix_y.vNt); +#endif + mix = mix_pbr(mix, mix_y, tw.weight.y); + break; + default: + break; + } + + switch (tw.type & SAMPLE_Z) + { + case SAMPLE_Z: + PBRMix mix_z = sample_pbr( + get_uv_z() + , tex_col +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + , tex_orm +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) + , tex_vNt +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , tex_emissive +#endif + ); +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) + // Triplanar-specific normal texture fix + // *NOTE: Bottom face has not been tested + mix_z.vNt = _t_normal_post_z(mix_z.vNt); +#endif + mix = mix_pbr(mix, mix_z, tw.weight.z); + break; + default: + break; + } + + return mix; +} + +#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1 + +#define TerrainCoord vec2 + +#define terrain_sample_pbr sample_pbr + +#endif + +PBRMix multiply_factors_pbr( + PBRMix mix_in + , vec4 factor_col +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION) + , vec3 factor_orm +#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + , vec2 factor_rm +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , vec3 factor_emissive +#endif + ) +{ + PBRMix mix = mix_in; + mix.col *= factor_col; +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION) + mix.orm *= factor_orm; +#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + mix.rm *= factor_rm; +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + mix.emissive *= factor_emissive; +#endif + return mix; +} + +PBRMix terrain_sample_and_multiply_pbr( + TerrainCoord terrain_coord + , sampler2D tex_col +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + , sampler2D tex_orm +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) + , sampler2D tex_vNt +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , sampler2D tex_emissive +#endif + , vec4 factor_col +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION) + , vec3 factor_orm +#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + , vec2 factor_rm +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , vec3 factor_emissive +#endif + ) +{ + PBRMix mix = terrain_sample_pbr( + terrain_coord +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 + , _t_triplanar() +#endif + , tex_col +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + , tex_orm +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) + , tex_vNt +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , tex_emissive +#endif + ); + + mix = multiply_factors_pbr(mix + , factor_col +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION) + , factor_orm +#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + , factor_rm +#endif +#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE) + , factor_emissive +#endif + ); + + return mix; +} 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..ed52297314 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl @@ -0,0 +1,96 @@ +/** + * @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_matrix; +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; +out vec3 vary_position; + +// *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 terrain_texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform); +vec3 terrain_tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform); + +void main() +{ + //transform vertex + gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); + vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz; + + 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(terrain_tangent_space_transform(vec4(t, tangent.w), n, texture_base_color_transform)); + 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 = terrain_texture_transform(position.xy, texture_base_color_transform); + // yz + vary_coords[0].zw = terrain_texture_transform(position.yz, texture_base_color_transform); + // (-x)z + vary_coords[1].xy = terrain_texture_transform(position.xz * vec2(-1, 1), texture_base_color_transform); +#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1 + vary_texcoord0.xy = terrain_texture_transform(position.xy, texture_base_color_transform); +#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/postDeferredGammaCorrect.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl index 7a25f63260..a0eb6cfbb8 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl @@ -97,6 +97,7 @@ vec3 toneMapACES_Hill(vec3 color) uniform float exposure; uniform float gamma; +uniform float aces_mix; vec3 toneMap(vec3 color) { @@ -106,7 +107,7 @@ vec3 toneMap(vec3 color) color *= exposure * exp_scale; // mix ACES and Linear here as a compromise to avoid over-darkening legacy content - color = mix(toneMapACES_Hill(color), color, 0.3); + color = mix(toneMapACES_Hill(color), color, aces_mix); #endif return color; @@ -152,6 +153,15 @@ float noise(vec2 x) { //============================= +void debugExposure(inout vec3 color) +{ + float exp_scale = texture(exposureMap, vec2(0.5,0.5)).r; + exp_scale *= 0.5; + if (abs(vary_fragcoord.y-exp_scale) < 0.01 && vary_fragcoord.x < 0.1) + { + color = vec3(1,0,0); + } +} vec3 legacyGamma(vec3 color) { @@ -181,6 +191,7 @@ void main() vec3 nz = vec3(noise(seed.rg), noise(seed.gb), noise(seed.rb)); diff.rgb += nz*0.003; + //debugExposure(diff.rgb); frag_color = max(diff, vec4(0)); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl b/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl index a07a4301bc..785c748234 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl @@ -1,24 +1,24 @@ -/** +/** * @file class1/deferred/skyF.glsl * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2005, 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$ */ @@ -27,6 +27,15 @@ in vec3 vary_HazeColor; in float vary_LightNormPosDot; +#ifdef HAS_HDRI +in vec4 vary_position; +in vec3 vary_rel_pos; +uniform float sky_hdr_scale; +uniform float hdri_split_screen; +uniform mat3 env_mat; +uniform sampler2D environmentMap; +#endif + uniform sampler2D rainbow_map; uniform sampler2D halo_map; @@ -37,6 +46,9 @@ uniform float ice_level; out vec4 frag_data[4]; vec3 srgb_to_linear(vec3 c); +vec3 linear_to_srgb(vec3 c); + +#define PI 3.14159265 ///////////////////////////////////////////////////////////////////////// // The fragment shader for the sky @@ -71,24 +83,42 @@ vec3 halo22(float d) void main() { - // Potential Fill-rate optimization. Add cloud calculation - // back in and output alpha of 0 (so that alpha culling kills - // the fragment) if the sky wouldn't show up because the clouds - // are fully opaque. + vec3 color; +#ifdef HAS_HDRI + vec3 frag_coord = vary_position.xyz/vary_position.w; + if (-frag_coord.x > ((1.0-hdri_split_screen)*2.0-1.0)) + { + vec3 pos = normalize(vary_rel_pos); + pos = env_mat * pos; + vec2 texCoord = vec2(atan(pos.z, pos.x) + PI, acos(pos.y)) / vec2(2.0 * PI, PI); + color = textureLod(environmentMap, texCoord.xy, 0).rgb * sky_hdr_scale; + color = min(color, vec3(8192*8192*16)); // stupidly large value arrived at by binary search -- avoids framebuffer corruption from some HDRIs - vec3 color = vary_HazeColor; + frag_data[2] = vec4(0.0,0.0,0.0,GBUFFER_FLAG_HAS_HDRI); + } + else +#endif + { + // Potential Fill-rate optimization. Add cloud calculation + // back in and output alpha of 0 (so that alpha culling kills + // the fragment) if the sky wouldn't show up because the clouds + // are fully opaque. - float rel_pos_lightnorm = vary_LightNormPosDot; - float optic_d = rel_pos_lightnorm; - vec3 halo_22 = halo22(optic_d); - color.rgb += rainbow(optic_d); - color.rgb += halo_22; - color.rgb *= 2.; - color.rgb = clamp(color.rgb, vec3(0), vec3(5)); + color = vary_HazeColor; + + float rel_pos_lightnorm = vary_LightNormPosDot; + float optic_d = rel_pos_lightnorm; + vec3 halo_22 = halo22(optic_d); + color.rgb += rainbow(optic_d); + color.rgb += halo_22; + color.rgb *= 2.; + color.rgb = clamp(color.rgb, vec3(0), vec3(5)); + + frag_data[2] = vec4(0.0,0.0,0.0,GBUFFER_FLAG_SKIP_ATMOS); + } frag_data[0] = vec4(0); frag_data[1] = vec4(0); - frag_data[2] = vec4(0.0,0.0,0.0,GBUFFER_FLAG_SKIP_ATMOS); //1.0 in norm.w masks off fog frag_data[3] = vec4(color.rgb, 1.0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/skyV.glsl b/indra/newview/app_settings/shaders/class1/deferred/skyV.glsl index 6110b6ade0..24d2db2183 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/skyV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/skyV.glsl @@ -35,6 +35,11 @@ in vec3 position; out vec3 vary_HazeColor; out float vary_LightNormPosDot; +#ifdef HAS_HDRI +out vec4 vary_position; +out vec3 vary_rel_pos; +#endif + // Inputs uniform vec3 camPosLocal; @@ -72,6 +77,11 @@ void main() // Get relative position vec3 rel_pos = position.xyz - camPosLocal.xyz + vec3(0, 50, 0); +#ifdef HAS_HDRI + vary_rel_pos = rel_pos; + vary_position = pos; +#endif + // Adj position vector to clamp altitude if (rel_pos.y > 0.) { @@ -92,13 +102,13 @@ void main() // Initialize temp variables vec3 sunlight = (sun_up_factor == 1) ? sunlight_color : moonlight_color * 0.7; //magic 0.7 to match legacy color - + // Sunlight attenuation effect (hue and brightness) due to atmosphere // this is used later for sunlight modulation at various altitudes vec3 light_atten = (blue_density + vec3(haze_density * 0.25)) * (density_multiplier * max_y); // Calculate relative weights - vec3 combined_haze = abs(blue_density) + vec3(abs(haze_density)); + vec3 combined_haze = max(abs(blue_density) + vec3(abs(haze_density)), vec3(1e-6)); vec3 blue_weight = blue_density / combined_haze; vec3 haze_weight = haze_density / combined_haze; @@ -142,7 +152,7 @@ void main() sunlight *= max(0.0, (1. - cloud_shadow)); // Haze color below cloud - vec3 add_below_cloud = (blue_horizon * blue_weight * (sunlight + ambient) + vec3 add_below_cloud = (blue_horizon * blue_weight * (sunlight + ambient) + (haze_horizon * haze_weight) * (sunlight * haze_glow + ambient)); // Attenuate cloud color by atmosphere diff --git a/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl b/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl index bee9e6d2fe..5f598f84a7 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl @@ -1,28 +1,28 @@ -/** +/** * @file class1\deferred\terrainF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2007, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - + /*[EXTRA_CODE_HERE]*/ out vec4 frag_data[4]; @@ -38,12 +38,13 @@ in vec3 vary_normal; in vec4 vary_texcoord0; in vec4 vary_texcoord1; -vec2 encode_normal(vec3 n); +void mirrorClip(vec3 position); void main() { + mirrorClip(pos); /// Note: This should duplicate the blending functionality currently used for the terrain rendering. - + vec4 color0 = texture(detail_0, vary_texcoord0.xy); vec4 color1 = texture(detail_1, vary_texcoord0.xy); vec4 color2 = texture(detail_2, vary_texcoord0.xy); @@ -53,13 +54,13 @@ void main() float alpha2 = texture(alpha_ramp,vary_texcoord1.xy).a; float alphaFinal = texture(alpha_ramp, vary_texcoord1.zw).a; vec4 outColor = mix( mix(color3, color2, alpha2), mix(color1, color0, alpha1), alphaFinal ); - - outColor.a = 0.0; // yes, downstream atmospherics - + + outColor.a = 0.0; // yes, downstream atmospherics + frag_data[0] = outColor; frag_data[1] = vec4(0.0,0.0,0.0,-1.0); vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS); + frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS); frag_data[3] = vec4(0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl b/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl index aab2abff1e..b4ab7cd169 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl @@ -1,36 +1,36 @@ -/** +/** * @file class1\environment\terrainV.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2007, 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_matrix; uniform mat4 modelview_projection_matrix; in vec3 position; in vec3 normal; in vec4 diffuse_color; -in vec2 texcoord0; in vec2 texcoord1; out vec3 pos; @@ -41,18 +41,18 @@ 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.z = 0; + tcoord.w = 1; - tcoord = mat * tcoord; - - return tcoord; + tcoord = mat * tcoord; + + return tcoord.xy; } void main() @@ -62,15 +62,15 @@ void main() vec4 t_pos = modelview_projection_matrix * pre_pos; gl_Position = t_pos; - pos = t_pos.xyz; + pos = (modelview_matrix*pre_pos).xyz; vary_normal = normalize(normal_matrix * normal); - + // Transform and pass tex coords - vary_texcoord0.xy = texgen_object(vec4(position, 1.0), vec4(texcoord0,0,1), texture_matrix0, object_plane_s, object_plane_t).xy; - + vary_texcoord0.xy = texgen_object(vec4(position, 1.0), texture_matrix0, object_plane_s, object_plane_t); + vec4 t = vec4(texcoord1,0,1); - + vary_texcoord0.zw = t.xy; vary_texcoord1.xy = t.xy-vec2(2.0, 0.0); vary_texcoord1.zw = t.xy-vec2(1.0, 0.0); diff --git a/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl b/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl index 8e641522e3..7c02cb9d4a 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl @@ -1,24 +1,24 @@ -/** +/** * @file class1/deferred/textureUtilV.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$ */ @@ -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 @@ -77,6 +77,19 @@ vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl return texcoord; } +// Similar to texture_transform but no offset during coordinate system +// conversion, and no texture animation support. +vec2 terrain_texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform) +{ + vec2 texcoord = vertex_texcoord; + + texcoord.y = -texcoord.y; + texcoord = khr_texture_transform(texcoord, khr_gltf_transform[0].xy, khr_gltf_transform[0].z, khr_gltf_transform[1].xy); + texcoord.y = -texcoord.y; + + return texcoord; +} + // Take the rotation only from both transforms and apply to the tangent. This // accounts for the change of the topology of the normal texture when a texture // rotation is applied to it. @@ -120,3 +133,25 @@ vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] kh return (weights.x * vertex_binormal.xyz) + (weights.y * vertex_tangent.xyz); } + +// Similar to tangent_space_transform but no no texture animation support. +vec3 terrain_tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform) +{ + // Immediately convert to left-handed coordinate system ((0,1) -> (0, -1)) + vec2 weights = vec2(0, -1); + + // Apply KHR_texture_transform (rotation only) + float khr_rotation = khr_gltf_transform[0].z; + mat2 khr_rotation_mat = mat2( + cos(khr_rotation),-sin(khr_rotation), + sin(khr_rotation), cos(khr_rotation) + ); + weights = khr_rotation_mat * weights; + + // Convert back to right-handed coordinate system + weights.y = -weights.y; + + vec3 vertex_binormal = vertex_tangent.w * cross(vertex_normal, vertex_tangent.xyz); + + return (weights.x * vertex_binormal.xyz) + (weights.y * vertex_tangent.xyz); +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl b/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl index db6070f328..05922ecb1a 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl @@ -32,13 +32,14 @@ uniform sampler2D diffuseMap; in vec4 vertex_color; in vec3 vary_normal; in vec2 vary_texcoord0; +in vec3 vary_position; uniform float minimum_alpha; -vec2 encode_normal(vec3 n); - +void mirrorClip(vec3 pos); void main() { + mirrorClip(vary_position); vec4 col = texture(diffuseMap, vary_texcoord0.xy); if (col.a < minimum_alpha) { @@ -48,6 +49,6 @@ void main() frag_data[0] = vec4(vertex_color.rgb*col.rgb, 0.0); frag_data[1] = vec4(0,0,0,0); vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS); + frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS); frag_data[3] = vec4(0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/treeV.glsl b/indra/newview/app_settings/shaders/class1/deferred/treeV.glsl index 81900fba70..ef5602f1e5 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/treeV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/treeV.glsl @@ -24,6 +24,7 @@ */ uniform mat4 texture_matrix0; +uniform mat4 modelview_matrix; uniform mat4 modelview_projection_matrix; uniform mat3 normal_matrix; @@ -34,11 +35,14 @@ in vec2 texcoord0; out vec3 vary_normal; out vec4 vertex_color; out vec2 vary_texcoord0; +out vec3 vary_position; void main() { //transform vertex gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); + vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz; + vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; vary_normal = normalize(normal_matrix * normal); diff --git a/indra/newview/app_settings/shaders/class1/environment/encodeNormF.glsl b/indra/newview/app_settings/shaders/class1/interface/normaldebugF.glsl similarity index 70% rename from indra/newview/app_settings/shaders/class1/environment/encodeNormF.glsl rename to indra/newview/app_settings/shaders/class1/interface/normaldebugF.glsl index ca3e4f6718..2bfd45f3b0 100644 --- a/indra/newview/app_settings/shaders/class1/environment/encodeNormF.glsl +++ b/indra/newview/app_settings/shaders/class1/interface/normaldebugF.glsl @@ -1,9 +1,9 @@ /** - * @file encodeNormF.glsl + * @file normaldebugF.glsl * - * $LicenseInfo:firstyear=2018&license=viewerlgpl$ + * $LicenseInfo:firstyear=2023&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2018, Linden Research, Inc. + * 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 @@ -23,12 +23,11 @@ * $/LicenseInfo$ */ -// Lambert Azimuthal Equal-Area projection -// See: https://aras-p.info/texts/CompactNormalStorage.html -// Also see: A_bit_more_deferred_-_CryEngine3.ppt -vec2 encode_normal(vec3 n) -{ - float f = sqrt(8 * n.z + 8); - return n.xy / f + 0.5; -} +out vec4 frag_color; +in vec4 vertex_color; + +void main() +{ + frag_color = max(vertex_color, vec4(0)); +} diff --git a/indra/newview/app_settings/shaders/class1/interface/normaldebugG.glsl b/indra/newview/app_settings/shaders/class1/interface/normaldebugG.glsl new file mode 100644 index 0000000000..51d05cd507 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/normaldebugG.glsl @@ -0,0 +1,76 @@ +/** + * @file normaldebugG.glsl + * + * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2023, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +// *NOTE: Geometry shaders have a reputation for being slow. Consider using +// compute shaders instead, which have a reputation for being fast. This +// geometry shader in particular seems to run fine on my machine, but I won't +// vouch for this in performance-critical areas. +// -Cosmic,2023-09-28 + +out vec4 vertex_color; + +in vec4 normal_g[]; +#ifdef HAS_ATTRIBUTE_TANGENT +in vec4 tangent_g[]; +#endif + +layout(triangles) in; +#ifdef HAS_ATTRIBUTE_TANGENT +layout(line_strip, max_vertices = 12) out; +#else +layout(line_strip, max_vertices = 6) out; +#endif + +void triangle_normal_debug(int i) +{ + // Normal + vec4 normal_color = vec4(1.0, 1.0, 0.0, 1.0); + gl_Position = gl_in[i].gl_Position; + vertex_color = normal_color; + EmitVertex(); + gl_Position = normal_g[i]; + vertex_color = normal_color; + EmitVertex(); + EndPrimitive(); + +#ifdef HAS_ATTRIBUTE_TANGENT + // Tangent + vec4 tangent_color = vec4(0.0, 1.0, 1.0, 1.0); + gl_Position = gl_in[i].gl_Position; + vertex_color = tangent_color; + EmitVertex(); + gl_Position = tangent_g[i]; + vertex_color = tangent_color; + EmitVertex(); + EndPrimitive(); +#endif +} + +void main() +{ + triangle_normal_debug(0); + triangle_normal_debug(1); + triangle_normal_debug(2); +} diff --git a/indra/newview/app_settings/shaders/class1/interface/normaldebugV.glsl b/indra/newview/app_settings/shaders/class1/interface/normaldebugV.glsl new file mode 100644 index 0000000000..ae726190c7 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/normaldebugV.glsl @@ -0,0 +1,74 @@ +/** + * @file normaldebugV.glsl + * + * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2023, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +in vec3 position; +in vec3 normal; +out vec4 normal_g; +#ifdef HAS_ATTRIBUTE_TANGENT +in vec4 tangent; +out vec4 tangent_g; +#endif + +uniform float debug_normal_draw_length; + +#ifdef HAS_SKIN +mat4 getObjectSkinnedTransform(); +#else +uniform mat3 normal_matrix; +#endif +uniform mat4 projection_matrix; +uniform mat4 modelview_matrix; + +// *NOTE: Should use the modelview_projection_matrix here in the non-skinned +// case for efficiency, but opting for the simplier implementation for now as +// this is debug code. Also, the skinned version hasn't beeen tested yet. +// world_pos = mat * vec4(position.xyz, 1.0) +vec4 get_screen_normal(vec3 position, vec4 world_pos, vec3 normal, mat4 mat) +{ + vec4 world_norm = mat * vec4((position + normal), 1.0); + world_norm.xyz -= world_pos.xyz; + world_norm.xyz = debug_normal_draw_length * normalize(world_norm.xyz); + world_norm.xyz += world_pos.xyz; + return projection_matrix * world_norm; +} + +void main() +{ +#ifdef HAS_SKIN + mat4 mat = getObjectSkinnedTransform(); + mat = modelview_matrix * mat; +#else +#define mat modelview_matrix +#endif + + vec4 world_pos = mat * vec4(position.xyz,1.0); + + gl_Position = projection_matrix * world_pos; + normal_g = get_screen_normal(position.xyz, world_pos, normal.xyz, mat); +#ifdef HAS_ATTRIBUTE_TANGENT + tangent_g = get_screen_normal(position.xyz, world_pos, tangent.xyz, mat); +#endif +} + diff --git a/indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl b/indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl index eb0f7297ad..feb0947649 100644 --- a/indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl +++ b/indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl @@ -38,6 +38,7 @@ in vec3 vary_dir; uniform float mipLevel; uniform int u_width; uniform float max_probe_lod; +uniform float probe_strength; // ============================================================================================================= @@ -129,7 +130,7 @@ vec4 prefilterEnvMap(vec3 R) float totalWeight = 0.0; float envMapDim = float(textureSize(reflectionProbes, 0).s); float roughness = mipLevel/max_probe_lod; - int numSamples = max(int(32*roughness), 1); + int numSamples = max(int(PROBE_FILTER_SAMPLES*roughness), 1); float numMips = max_probe_lod+1; @@ -163,5 +164,6 @@ void main() { vec3 N = normalize(vary_dir); frag_color = max(prefilterEnvMap(N), vec4(0)); + frag_color.a *= probe_strength; } // ============================================================================================================= diff --git a/indra/newview/app_settings/shaders/class1/objects/bumpF.glsl b/indra/newview/app_settings/shaders/class1/objects/bumpF.glsl index db26e64f17..09a505d69d 100644 --- a/indra/newview/app_settings/shaders/class1/objects/bumpF.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/bumpF.glsl @@ -30,9 +30,13 @@ uniform sampler2D texture1; in vec2 vary_texcoord0; in vec2 vary_texcoord1; +in vec3 vary_position; + +void mirrorClip(vec3 pos); void main() { + mirrorClip(vary_position); float tex0 = texture(texture0, vary_texcoord0.xy).a; float tex1 = texture(texture1, vary_texcoord1.xy).a; diff --git a/indra/newview/app_settings/shaders/class1/objects/bumpV.glsl b/indra/newview/app_settings/shaders/class1/objects/bumpV.glsl index 834c20e14d..95cdfb6fae 100644 --- a/indra/newview/app_settings/shaders/class1/objects/bumpV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/bumpV.glsl @@ -23,6 +23,7 @@ * $/LicenseInfo$ */ +uniform mat4 modelview_matrix; uniform mat4 texture_matrix0; uniform mat4 modelview_projection_matrix; @@ -32,11 +33,11 @@ in vec2 texcoord1; out vec2 vary_texcoord0; out vec2 vary_texcoord1; +out vec3 vary_position; #ifdef HAS_SKIN mat4 getObjectSkinnedTransform(); uniform mat4 projection_matrix; -uniform mat4 modelview_matrix; #endif void main() @@ -46,8 +47,10 @@ void main() mat4 mat = getObjectSkinnedTransform(); mat = modelview_matrix * mat; vec4 pos = mat * vec4(position.xyz, 1.0); + vary_position = pos.xyz; gl_Position = projection_matrix * pos; #else + vary_position = (modelview_matrix * vec4(position.xyz, 1.0)).xyz; gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0); #endif vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsFuncs.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsFuncs.glsl index b7cd3f0589..d077670c96 100644 --- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsFuncs.glsl +++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsFuncs.glsl @@ -57,16 +57,16 @@ void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, ou vec3 rel_pos_norm = normalize(rel_pos); float rel_pos_len = length(rel_pos); - + vec3 sunlight = (sun_up_factor == 1) ? sunlight_color: moonlight_color; - + // sunlight attenuation effect (hue and brightness) due to atmosphere // this is used later for sunlight modulation at various altitudes vec3 light_atten = (blue_density + vec3(haze_density * 0.25)) * (density_multiplier * max_y); // I had thought blue_density and haze_density should have equal weighting, // but attenuation due to haze_density tends to seem too strong - vec3 combined_haze = blue_density + vec3(haze_density); + vec3 combined_haze = max(blue_density + vec3(haze_density), vec3(1e-6)); vec3 blue_weight = blue_density / combined_haze; vec3 haze_weight = vec3(haze_density) / combined_haze; @@ -98,7 +98,7 @@ void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, ou haze_glow = max(haze_glow, .001); // set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot) haze_glow *= glow.x; // higher glow.x gives dimmer glow (because next step is 1 / "angle") - haze_glow = pow(haze_glow, glow.z); + haze_glow = clamp(pow(haze_glow, glow.z), -100000, 100000); // glow.z should be negative, so we're doing a sort of (1 / "angle") function // add "minimum anti-solar illumination" @@ -119,7 +119,7 @@ void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, ou additive = (blue_horizon.rgb * blue_weight.rgb) * (cs + tmpAmbient.rgb) + (haze_horizon * haze_weight.rgb) * (cs * haze_glow + tmpAmbient.rgb); // brightness of surface both sunlight and ambient - + sunlit = sunlight.rgb; amblit = tmpAmbient; @@ -128,7 +128,7 @@ void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, ou vec3 srgb_to_linear(vec3 col); -// provide a touch of lighting in the opposite direction of the sun light +// provide a touch of lighting in the opposite direction of the sun light // so areas in shadow don't lose all detail float ambientLighting(vec3 norm, vec3 light_dir) { @@ -150,7 +150,7 @@ void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, ou // (allows for mixing of light sources other than sunlight e.g. reflection probes) sunlit *= sky_sunlight_scale; amblit *= sky_ambient_scale; - + amblit = srgb_to_linear(amblit); amblit *= ambientLighting(norm, light_dir); } diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl index e6bdaf265e..210ecce8db 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl @@ -68,7 +68,6 @@ void waterClip(vec3 pos); vec3 srgb_to_linear(vec3 c); vec3 linear_to_srgb(vec3 c); -vec2 encode_normal (vec3 n); vec4 applySkyAndWaterFog(vec3 pos, vec3 additive, vec3 atten, vec4 color); void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive); @@ -78,6 +77,8 @@ float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen); float getAmbientClamp(); +void mirrorClip(vec3 pos); + void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit_linear); @@ -167,6 +168,8 @@ vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 diffuse, vec3 v, vec3 n, vec void main() { + mirrorClip(vary_position); + vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5; vec4 pos = vec4(vary_position, 1.0); diff --git a/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl index 34d86b6147..059c2a64ce 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl @@ -1,24 +1,24 @@ -/** +/** * @file class1\deferred\pbralphaF.glsl * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2022, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -87,9 +87,10 @@ vec4 applySkyAndWaterFog(vec3 pos, vec3 additive, vec3 atten, vec4 color); void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist); float calcLegacyDistanceAttenuation(float distance, float falloff); float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen); -void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, +void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, vec2 tc, vec3 pos, vec3 norm, float glossiness, bool transparent, vec3 amblit_linear); +void mirrorClip(vec3 pos); void waterClip(vec3 pos); void calcDiffuseSpecular(vec3 baseColor, float metallic, inout vec3 diffuseColor, inout vec3 specularColor); @@ -110,15 +111,15 @@ vec3 pbrBaseLight(vec3 diffuseColor, vec3 additive, vec3 atten); -vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor, - float perceptualRoughness, +vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor, + float perceptualRoughness, float metallic, vec3 n, // normal vec3 v, // surface point to camera vec3 l); //surface point to light -vec3 calcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor, - float perceptualRoughness, +vec3 calcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor, + float perceptualRoughness, float metallic, vec3 n, // normal vec3 p, // pixel position @@ -156,6 +157,8 @@ vec3 calcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor, void main() { + mirrorClip(vary_position); + vec3 color = vec3(0,0,0); vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir; @@ -178,7 +181,7 @@ void main() float sign = vary_sign; vec3 vN = vary_normal; vec3 vT = vary_tangent.xyz; - + vec3 vB = sign * cross(vN, vT); vec3 norm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); @@ -215,7 +218,7 @@ void main() vec3 irradiance = vec3(0); vec3 radiance = vec3(0); sampleReflectionProbes(irradiance, radiance, vary_position.xy*0.5+0.5, pos.xyz, norm.xyz, gloss, true, amblit); - + vec3 diffuseColor; vec3 specularColor; calcDiffuseSpecular(col.rgb, metallic, diffuseColor, specularColor); @@ -242,7 +245,7 @@ void main() color.rgb = applySkyAndWaterFog(pos.xyz, additive, atten, vec4(color, 1.0)).rgb; float a = basecolor.a*vertex_color.a; - + frag_color = max(vec4(color.rgb,a), vec4(0)); } @@ -292,7 +295,7 @@ void main() // emissiveMap here is a vanilla RGB texture encoded as sRGB, manually convert to linear colorEmissive *= srgb_to_linear(texture(emissiveMap, emissive_texcoord.xy).rgb); - + float a = basecolor.a*vertex_color.a; color += colorEmissive; diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl index 10bfe2c5d5..1bd5f5a718 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl @@ -1,24 +1,24 @@ -/** +/** * @file sunLightF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2007, 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$ */ @@ -35,23 +35,23 @@ in vec2 vary_fragcoord; uniform vec3 sun_dir; uniform float shadow_bias; -vec3 getNorm(vec2 pos_screen); +vec4 getNorm(vec2 pos_screen); vec4 getPosition(vec2 pos_screen); float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen); float sampleSpotShadow(vec3 pos, vec3 norm, int index, vec2 pos_screen); -void main() +void main() { vec2 pos_screen = vary_fragcoord.xy; vec4 pos = getPosition(pos_screen); - vec3 norm = getNorm(pos_screen); + vec4 norm = getNorm(pos_screen); vec4 col; - col.r = sampleDirectionalShadow(pos.xyz, norm, pos_screen); + col.r = sampleDirectionalShadow(pos.xyz, norm.xyz, pos_screen); col.g = 1.0f; - col.b = sampleSpotShadow(pos.xyz, norm, 0, pos_screen); - col.a = sampleSpotShadow(pos.xyz, norm, 1, pos_screen); + col.b = sampleSpotShadow(pos.xyz, norm.xyz, 0, pos_screen); + col.a = sampleSpotShadow(pos.xyz, norm.xyz, 1, pos_screen); frag_color = clamp(col, vec4(0), vec4(1)); } diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl index 2f1819bff7..e0333b6044 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl @@ -1,27 +1,27 @@ -/** +/** * @file class2/deferred/sunLightSSAOF.glsl * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2007, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - + /*[EXTRA_CODE_HERE]*/ out vec4 frag_color; @@ -32,23 +32,23 @@ out vec4 frag_color; in vec2 vary_fragcoord; vec4 getPosition(vec2 pos_screen); -vec3 getNorm(vec2 pos_screen); +vec4 getNorm(vec2 pos_screen); float sampleDirectionalShadow(vec3 shadow_pos, vec3 norm, vec2 pos_screen); float sampleSpotShadow(vec3 shadow_pos, vec3 norm, int index, vec2 pos_screen); float calcAmbientOcclusion(vec4 pos, vec3 norm, vec2 pos_screen); -void main() +void main() { vec2 pos_screen = vary_fragcoord.xy; vec4 pos = getPosition(pos_screen); - vec3 norm = getNorm(pos_screen); + vec4 norm = getNorm(pos_screen); vec4 col; - col.r = sampleDirectionalShadow(pos.xyz, norm, pos_screen); - col.g = calcAmbientOcclusion(pos, norm, pos_screen); - col.b = sampleSpotShadow(pos.xyz, norm, 0, pos_screen); - col.a = sampleSpotShadow(pos.xyz, norm, 1, pos_screen); + col.r = sampleDirectionalShadow(pos.xyz, norm.xyz, pos_screen); + col.g = calcAmbientOcclusion(pos, norm.xyz, pos_screen); + col.b = sampleSpotShadow(pos.xyz, norm.xyz, 0, pos_screen); + col.a = sampleSpotShadow(pos.xyz, norm.xyz, 1, pos_screen); frag_color = clamp(col, vec4(0), vec4(1)); } diff --git a/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl index 22408387b1..03dc3d7113 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl @@ -53,8 +53,11 @@ void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity); +void mirrorClip(vec3 pos); + void main() { + mirrorClip(vary_position); #ifdef HAS_DIFFUSE_LOOKUP vec4 color = diffuseLookup(vary_texcoord0.xy); #else diff --git a/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl index 7f75b16cf0..4af57e3b80 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl @@ -33,7 +33,7 @@ uniform vec3 moon_dir; uniform int sun_up_factor; in vec2 vary_fragcoord; -vec3 getNorm(vec2 pos_screen); +vec4 getNorm(vec2 pos_screen); vec4 getPositionWithDepth(vec2 pos_screen, float depth); void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive); @@ -53,8 +53,7 @@ void main() vec2 tc = vary_fragcoord.xy; float depth = getDepth(tc.xy); vec4 pos = getPositionWithDepth(tc, depth); - vec4 norm = texture(normalMap, tc); - norm.xyz = getNorm(tc); + vec4 norm = getNorm(tc); vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir; vec3 color = vec3(0); @@ -68,16 +67,16 @@ void main() calcAtmosphericVarsLinear(pos.xyz, norm.xyz, light_dir, sunlit, amblit, additive, atten); vec3 sunlit_linear = srgb_to_linear(sunlit); - + // mask off atmospherics below water (when camera is under water) bool do_atmospherics = false; - + if (dot(vec3(0), waterPlane.xyz) + waterPlane.w > 0.0 || dot(pos.xyz, waterPlane.xyz) + waterPlane.w > 0.0) { do_atmospherics = true; } - + vec3 irradiance = vec3(0); vec3 radiance = vec3(0); @@ -102,5 +101,5 @@ void main() } frag_color = max(vec4(color.rgb, alpha), vec4(0)); //output linear since local lights will be added to this shader's results - + } diff --git a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl index 20f063fe3e..d3e19cf4a8 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl @@ -45,6 +45,13 @@ void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float vec3 srgb_to_linear(vec3 cs); vec3 linear_to_srgb(vec3 cs); +uniform mat4 modelview_matrix; +uniform mat3 normal_matrix; + +in vec3 vary_position; + +void mirrorClip(vec3 pos); + #if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) out vec4 frag_color; @@ -66,12 +73,12 @@ uniform vec4 morphFactor; uniform vec3 camPosLocal; uniform mat3 env_mat; +uniform float is_mirror; + uniform vec3 sun_dir; uniform vec3 moon_dir; in vec2 vary_fragcoord; -in vec3 vary_position; - uniform mat4 proj_mat; uniform mat4 inv_proj; uniform vec2 screen_res; @@ -209,8 +216,6 @@ in vec3 vary_normal; in vec4 vertex_color; in vec2 vary_texcoord0; -vec2 encode_normal(vec3 n); - // get the transformed normal and apply glossiness component from normal map vec3 getNormal(inout float glossiness) { @@ -285,12 +290,12 @@ float getShadow(vec3 pos, vec3 norm) void main() { + mirrorClip(vary_position); waterClip(); // diffcol == diffuse map combined with vertex color vec4 diffcol = texture(diffuseMap, vary_texcoord0.xy); diffcol.rgb *= vertex_color.rgb; - alphaMask(diffcol.a); // spec == specular map combined with specular color @@ -299,8 +304,6 @@ void main() float glossiness = specular_color.a; vec3 norm = getNormal(glossiness); - vec2 abnormal = encode_normal(norm.xyz); - float emissive = getEmissive(diffcol); #if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) @@ -407,10 +410,15 @@ void main() #else // mode is not DIFFUSE_ALPHA_MODE_BLEND, encode to gbuffer // deferred path // See: C++: addDeferredAttachment(), shader: softenLightF.glsl - frag_data[0] = vec4(diffcol.rgb, emissive); // gbuffer is sRGB for legacy materials - frag_data[1] = vec4(spec.rgb, glossiness); // XYZ = Specular color. W = Specular exponent. - frag_data[2] = vec4(encode_normal(norm), env, GBUFFER_FLAG_HAS_ATMOS);; // XY = Normal. Z = Env. intensity. W = 1 skip atmos (mask off fog) - frag_data[3] = vec4(0); + + float flag = GBUFFER_FLAG_HAS_ATMOS; + + frag_data[0] = max(vec4(diffcol.rgb, emissive), vec4(0)); // gbuffer is sRGB for legacy materials + frag_data[1] = max(vec4(spec.rgb, glossiness), vec4(0)); // XYZ = Specular color. W = Specular exponent. + frag_data[2] = vec4(norm, flag); // XY = Normal. Z = Env. intensity. W = 1 skip atmos (mask off fog) + frag_data[3] = vec4(env, 0, 0, 0); + #endif } + diff --git a/indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl index 31aca8a745..edfd6cbced 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl @@ -48,7 +48,7 @@ in vec4 vary_fragcoord; void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist); float calcLegacyDistanceAttenuation(float distance, float falloff); vec4 getPosition(vec2 pos_screen); -vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity); +vec4 getNorm(vec2 screenpos); vec2 getScreenXY(vec4 clip); vec2 getScreenCoord(vec4 clip); vec3 srgb_to_linear(vec3 c); @@ -56,8 +56,8 @@ vec3 srgb_to_linear(vec3 c); // Util vec3 hue_to_rgb(float hue); -vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor, - float perceptualRoughness, +vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor, + float perceptualRoughness, float metallic, vec3 n, // normal vec3 v, // surface point to camera @@ -74,9 +74,8 @@ void main() discard; } - float envIntensity; // not used for this shader - vec3 n; - vec4 norm = getNormalEnvIntensityFlags(tc, n, envIntensity); // need `norm.w` for GET_GBUFFER_FLAG() + vec4 norm = getNorm(tc); // need `norm.w` for GET_GBUFFER_FLAG() + vec3 n = norm.xyz; vec4 spec = texture(specularRect, tc); vec3 diffuse = texture(diffuseRect, tc).rgb; @@ -92,7 +91,7 @@ void main() float metallic = orm.b; vec3 f0 = vec3(0.04); vec3 baseColor = diffuse.rgb; - + vec3 diffuseColor = baseColor.rgb*(vec3(1.0)-f0); diffuseColor *= 1.0 - metallic; diff --git a/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl index c27310cf89..60be9f4407 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl @@ -1,28 +1,28 @@ -/** +/** * @file class3\deferred\pointLightF.glsl * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2022, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - + /*[EXTRA_CODE_HERE]*/ out vec4 frag_color; @@ -52,15 +52,15 @@ uniform vec4 viewport; void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist); float calcLegacyDistanceAttenuation(float distance, float falloff); -vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity); +vec4 getNorm(vec2 screenpos); vec4 getPosition(vec2 pos_screen); vec2 getScreenXY(vec4 clip); vec2 getScreenCoord(vec4 clip); vec3 srgb_to_linear(vec3 c); float getDepth(vec2 tc); -vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor, - float perceptualRoughness, +vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor, + float perceptualRoughness, float metallic, vec3 n, // normal vec3 v, // surface point to camera @@ -72,9 +72,8 @@ void main() vec2 tc = getScreenCoord(vary_fragcoord); vec3 pos = getPosition(tc).xyz; - float envIntensity; - vec3 n; - vec4 norm = getNormalEnvIntensityFlags(tc, n, envIntensity); // need `norm.w` for GET_GBUFFER_FLAG() + vec4 norm = getNorm(tc); // need `norm.w` for GET_GBUFFER_FLAG() + vec3 n = norm.xyz; vec3 diffuse = texture(diffuseRect, tc).rgb; vec4 spec = texture(specularRect, tc); @@ -94,13 +93,13 @@ void main() if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR)) { - vec3 colorEmissive = texture(emissiveRect, tc).rgb; + vec3 colorEmissive = texture(emissiveRect, tc).rgb; vec3 orm = spec.rgb; float perceptualRoughness = orm.g; float metallic = orm.b; vec3 f0 = vec3(0.04); vec3 baseColor = diffuse.rgb; - + vec3 diffuseColor = baseColor.rgb*(vec3(1.0)-f0); diffuseColor *= 1.0 - metallic; @@ -137,7 +136,7 @@ void main() final_color += lit*scol*color.rgb*spec.rgb; } } - + if (dot(final_color, final_color) <= 0.0) { discard; diff --git a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl index ae81a4b472..90c84cc428 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl @@ -31,6 +31,7 @@ float tapScreenSpaceReflection(int totalSamples, vec2 tc, vec3 viewPos, vec3 n, uniform samplerCubeArray reflectionProbes; uniform samplerCubeArray irradianceProbes; + uniform sampler2D sceneMap; uniform int cube_snapshot; uniform float max_probe_lod; @@ -47,14 +48,16 @@ layout (std140) uniform ReflectionProbes /// box[0..2] - plane 0 .. 2 in [A,B,C,D] notation // box[3][0..2] - plane thickness mat4 refBox[MAX_REFMAP_COUNT]; + mat4 heroBox; // list of bounding spheres for reflection probes sorted by distance to camera (closest first) vec4 refSphere[MAX_REFMAP_COUNT]; - // extra parameters + // extra parameters // x - irradiance scale // y - radiance scale // z - fade in // w - znear vec4 refParams[MAX_REFMAP_COUNT]; + vec4 heroSphere; // index of cube map in reflectionProbes for a corresponding reflection probe // e.g. cube map channel of refSphere[2] is stored in refIndex[2] // refIndex.x - cubemap channel in reflectionProbes @@ -70,6 +73,10 @@ layout (std140) uniform ReflectionProbes // number of reflection probes present in refSphere int refmapCount; + + int heroShape; + int heroMipCount; + int heroProbeCount; }; // Inputs @@ -95,7 +102,7 @@ bool shouldSampleProbe(int i, vec3 pos) if (refIndex[i].w < 0) { vec4 v = refBox[i] * vec4(pos, 1.0); - if (abs(v.x) > 1 || + if (abs(v.x) > 1 || abs(v.y) > 1 || abs(v.z) > 1) { @@ -222,7 +229,7 @@ void preProbeSample(vec3 pos) } } count++; - + ++neighborIdx; } @@ -244,56 +251,56 @@ void preProbeSample(vec3 pos) // original reference implementation: /* -bool intersect(const Ray &ray) const -{ - float t0, t1; // solutions for t if the ray intersects -#if 0 +bool intersect(const Ray &ray) const +{ + float t0, t1; // solutions for t if the ray intersects +#if 0 // geometric solution - Vec3f L = center - orig; - float tca = L.dotProduct(dir); + Vec3f L = center - orig; + float tca = L.dotProduct(dir); // if (tca < 0) return false; - float d2 = L.dotProduct(L) - tca * tca; - if (d2 > radius2) return false; - float thc = sqrt(radius2 - d2); - t0 = tca - thc; - t1 = tca + thc; -#else + float d2 = L.dotProduct(L) - tca * tca; + if (d2 > radius2) return false; + float thc = sqrt(radius2 - d2); + t0 = tca - thc; + t1 = tca + thc; +#else // analytic solution - Vec3f L = orig - center; - float a = dir.dotProduct(dir); - float b = 2 * dir.dotProduct(L); - float c = L.dotProduct(L) - radius2; - if (!solveQuadratic(a, b, c, t0, t1)) return false; -#endif - if (t0 > t1) std::swap(t0, t1); - - if (t0 < 0) { - t0 = t1; // if t0 is negative, let's use t1 instead - if (t0 < 0) return false; // both t0 and t1 are negative - } - - t = t0; - - return true; + Vec3f L = orig - center; + float a = dir.dotProduct(dir); + float b = 2 * dir.dotProduct(L); + float c = L.dotProduct(L) - radius2; + if (!solveQuadratic(a, b, c, t0, t1)) return false; +#endif + if (t0 > t1) std::swap(t0, t1); + + if (t0 < 0) { + t0 = t1; // if t0 is negative, let's use t1 instead + if (t0 < 0) return false; // both t0 and t1 are negative + } + + t = t0; + + return true; } */ // adapted -- assume that origin is inside sphere, return intersection of ray with edge of sphere vec3 sphereIntersect(vec3 origin, vec3 dir, vec3 center, float radius2) -{ - float t0, t1; // solutions for t if the ray intersects +{ + float t0, t1; // solutions for t if the ray intersects - vec3 L = center - origin; + vec3 L = center - origin; float tca = dot(L,dir); - float d2 = dot(L,L) - tca * tca; - - float thc = sqrt(radius2 - d2); - t0 = tca - thc; - t1 = tca + thc; + float d2 = dot(L,L) - tca * tca; + float thc = sqrt(radius2 - d2); + t0 = tca - thc; + t1 = tca + thc; + vec3 v = origin + dir * t1; - return v; -} + return v; +} void swap(inout float a, inout float b) { @@ -305,17 +312,17 @@ void swap(inout float a, inout float b) // debug implementation, make no assumptions about origin void sphereIntersectDebug(vec3 origin, vec3 dir, vec3 center, float radius2, float depth, inout vec4 col) { - float t[2]; // solutions for t if the ray intersects + float t[2]; // solutions for t if the ray intersects // geometric solution - vec3 L = center - origin; + vec3 L = center - origin; float tca = dot(L, dir); // if (tca < 0) return false; - float d2 = dot(L, L) - tca * tca; - if (d2 > radius2) return; - float thc = sqrt(radius2 - d2); - t[0] = tca - thc; - t[1] = tca + thc; + float d2 = dot(L, L) - tca * tca; + if (d2 > radius2) return; + float thc = sqrt(radius2 - d2); + t[0] = tca - thc; + t[1] = tca + thc; for (int i = 0; i < 2; ++i) { @@ -365,11 +372,11 @@ return texCUBE(envMap, ReflDirectionWS); // i - probe index in refBox/refSphere // d - distance to nearest wall in clip space // scale - scale of box, default 1.0 -vec3 boxIntersect(vec3 origin, vec3 dir, int i, out float d, float scale) +vec3 boxIntersect(vec3 origin, vec3 dir, mat4 i, out float d, float scale) { // Intersection with OBB convert to unit box space // Transform in local unit parallax cube space (scaled and rotated) - mat4 clipToLocal = refBox[i]; + mat4 clipToLocal = i; vec3 RayLS = mat3(clipToLocal) * dir; vec3 PositionLS = (clipToLocal * vec4(origin, 1.0)).xyz; @@ -388,7 +395,7 @@ vec3 boxIntersect(vec3 origin, vec3 dir, int i, out float d, float scale) return IntersectPositionCS; } -vec3 boxIntersect(vec3 origin, vec3 dir, int i, out float d) +vec3 boxIntersect(vec3 origin, vec3 dir, mat4 i, out float d) { return boxIntersect(origin, dir, i, d, 1.0); } @@ -404,8 +411,8 @@ void debugBoxCol(vec3 ro, vec3 rd, float t, vec3 p, inout vec4 col) bool behind = dot(v,v) > dot(pos,pos); float w = 0.25; - - if (behind) + + if (behind) { w *= 0.5; w /= (length(v)-length(pos))*0.5+1.0; @@ -419,7 +426,7 @@ void debugBoxCol(vec3 ro, vec3 rd, float t, vec3 p, inout vec4 col) // cribbed from https://iquilezles.org/articles/intersectors/ // axis aligned box centered at the origin, with size boxSize -void boxIntersectionDebug( in vec3 ro, in vec3 p, vec3 boxSize, inout vec4 col) +void boxIntersectionDebug( in vec3 ro, in vec3 p, vec3 boxSize, inout vec4 col) { vec3 rd = normalize(p-ro); @@ -443,10 +450,10 @@ void boxIntersectionDebug( in vec3 ro, in vec3 p, vec3 boxSize, inout vec4 col) } -void boxIntersectDebug(vec3 origin, vec3 pos, int i, inout vec4 col) +void boxIntersectDebug(vec3 origin, vec3 pos, mat4 i, inout vec4 col) { - mat4 clipToLocal = refBox[i]; - + mat4 clipToLocal = i; + // transform into unit cube space origin = (clipToLocal * vec4(origin, 1.0)).xyz; pos = (clipToLocal * vec4(pos, 1.0)).xyz; @@ -462,16 +469,16 @@ void boxIntersectDebug(vec3 origin, vec3 pos, int i, inout vec4 col) // r - radius of probe influence volume // i - index of probe in refSphere // dw - distance weight -float sphereWeight(vec3 pos, vec3 dir, vec3 origin, float r, int i, out float dw) +float sphereWeight(vec3 pos, vec3 dir, vec3 origin, float r, vec4 i, out float dw) { - float r1 = r * 0.5; // 50% of radius (outer sphere to start interpolating down) + float r1 = r * 0.5; // 50% of radius (outer sphere to start interpolating down) vec3 delta = pos.xyz - origin; float d2 = max(length(delta), 0.001); float atten = 1.0 - max(d2 - r1, 0.0) / max((r - r1), 0.001); float w = 1.0 / d2; - w *= refParams[i].z; + w *= i.z; dw = w * atten * max(r, 1.0)*4; @@ -488,7 +495,7 @@ float sphereWeight(vec3 pos, vec3 dir, vec3 origin, float r, int i, out float dw // lod - which mip to sample (lower is higher res, sharper reflections) // c - center of probe // r2 - radius of probe squared -// i - index of probe +// i - index of probe vec3 tapRefMap(vec3 pos, vec3 dir, out float w, out float dw, float lod, vec3 c, int i) { // parallax adjustment @@ -497,7 +504,7 @@ vec3 tapRefMap(vec3 pos, vec3 dir, out float w, out float dw, float lod, vec3 c, if (refIndex[i].w < 0) { // box probe float d = 0; - v = boxIntersect(pos, dir, i, d); + v = boxIntersect(pos, dir, refBox[i], d); w = max(d, 0.001); } @@ -507,18 +514,18 @@ vec3 tapRefMap(vec3 pos, vec3 dir, out float w, out float dw, float lod, vec3 c, float rr = r * r; - v = sphereIntersect(pos, dir, c, + v = sphereIntersect(pos, dir, c, refIndex[i].w < 1 ? 4096.0*4096.0 : // <== effectively disable parallax correction for automatically placed probes to keep from bombing the world with obvious spheres rr); - w = sphereWeight(pos, dir, refSphere[i].xyz, r, i, dw); + w = sphereWeight(pos, dir, refSphere[i].xyz, r, refParams[i], dw); } v -= c; vec3 d = normalize(v); v = env_mat * v; - + vec4 ret = textureLod(reflectionProbes, vec4(v.xyz, refIndex[i].x), lod) * refParams[i].y; return ret.rgb; @@ -529,7 +536,7 @@ vec3 tapRefMap(vec3 pos, vec3 dir, out float w, out float dw, float lod, vec3 c, // dir - pixel normal // w - weight of sample (distance and angular attenuation) // dw - weight of sample (distance only) -// i - index of probe +// i - index of probe vec3 tapIrradianceMap(vec3 pos, vec3 dir, out float w, out float dw, vec3 c, int i, vec3 amblit) { // parallax adjustment @@ -537,7 +544,7 @@ vec3 tapIrradianceMap(vec3 pos, vec3 dir, out float w, out float dw, vec3 c, int if (refIndex[i].w < 0) { float d = 0.0; - v = boxIntersect(pos, dir, i, d, 3.0); + v = boxIntersect(pos, dir, refBox[i], d, 3.0); w = max(d, 0.001); } else @@ -547,16 +554,16 @@ vec3 tapIrradianceMap(vec3 pos, vec3 dir, out float w, out float dw, vec3 c, int // pad sphere for manual probe extending into automatic probe space float rr = r * r; - v = sphereIntersect(pos, dir, c, + v = sphereIntersect(pos, dir, c, refIndex[i].w < 1 ? 4096.0*4096.0 : // <== effectively disable parallax correction for automatically placed probes to keep from bombing the world with obvious spheres rr); - w = sphereWeight(pos, dir, refSphere[i].xyz, r, i, dw); + w = sphereWeight(pos, dir, refSphere[i].xyz, r, refParams[i], dw); } v -= c; v = env_mat * v; - + vec3 col = textureLod(irradianceProbes, vec4(v.xyz, refIndex[i].x), 0).rgb * refParams[i].x; col = mix(amblit, col, min(refParams[i].x, 1.0)); @@ -618,7 +625,7 @@ vec3 sampleProbes(vec3 pos, vec3 dir, float lod) col[1] *= 1.0/wsum[1]; col[0] = vec3(0); } - + return col[1]+col[0]; } @@ -647,7 +654,7 @@ vec3 sampleProbeAmbient(vec3 pos, vec3 dir, vec3 amblit) { continue; } - + { float w = 0; float dw = 0; @@ -677,10 +684,53 @@ vec3 sampleProbeAmbient(vec3 pos, vec3 dir, vec3 amblit) col[1] *= 1.0/wsum[1]; col[0] = vec3(0); } - + return col[1]+col[0]; } +#if defined(HERO_PROBES) + +uniform vec4 clipPlane; +uniform samplerCubeArray heroProbes; + +void tapHeroProbe(inout vec3 glossenv, vec3 pos, vec3 norm, float glossiness) +{ + float clipDist = dot(pos.xyz, clipPlane.xyz) + clipPlane.w; + float w = 0; + float dw = 0; + float falloffMult = 10; + vec3 refnormpersp = reflect(pos.xyz, norm.xyz); + if (heroShape < 1) + { + float d = 0; + boxIntersect(pos, norm, heroBox, d, 1.0); + + w = max(d, 0); + } + else + { + float r = heroSphere.w; + + w = sphereWeight(pos, refnormpersp, heroSphere.xyz, r, vec4(1), dw); + } + + clipDist = clipDist * 0.95 + 0.05; + clipDist = clamp(clipDist * falloffMult, 0, 1); + w = clamp(w * falloffMult * clipDist, 0, 1); + w = mix(0, w, clamp(glossiness - 0.75, 0, 1) * 4); // We only generate a quarter of the mips for the hero probes. Linearly interpolate between normal probes and hero probes based upon glossiness. + glossenv = mix(glossenv, textureLod(heroProbes, vec4(env_mat * refnormpersp, 0), (1.0-glossiness)*heroMipCount).xyz, w); +} + +#else + +void tapHeroProbe(inout vec3 glossenv, vec3 pos, vec3 norm, float glossiness) +{ +} + +#endif + + + void doProbeSample(inout vec3 ambenv, inout vec3 glossenv, vec2 tc, vec3 pos, vec3 norm, float glossiness, bool transparent, vec3 amblit) { @@ -712,6 +762,8 @@ void doProbeSample(inout vec3 ambenv, inout vec3 glossenv, glossenv = mix(glossenv, ssr.rgb, ssr.a); } #endif + + tapHeroProbe(glossenv, pos, norm, glossiness); } void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, @@ -747,7 +799,7 @@ void debugTapRefMap(vec3 pos, vec3 dir, float depth, int i, inout vec4 col) { if (refIndex[i].w < 0) { - boxIntersectDebug(origin, pos, i, col); + boxIntersectDebug(origin, pos, refBox[i], col); } else { @@ -799,8 +851,9 @@ void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout { float lod = (1.0-glossiness)*reflection_lods; glossenv = sampleProbes(pos, normalize(refnormpersp), lod); + } - + if (envIntensity > 0.0) { legacyenv = sampleProbes(pos, normalize(refnormpersp), 0.0); @@ -826,6 +879,9 @@ void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout } #endif + tapHeroProbe(glossenv, pos, norm, glossiness); + tapHeroProbe(legacyenv, pos, norm, 1.0); + glossenv = clamp(glossenv, vec3(0), vec3(10)); } diff --git a/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflPostF.glsl b/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflPostF.glsl index 63fa4ecc55..deb276ef9d 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflPostF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflPostF.glsl @@ -40,36 +40,33 @@ uniform sampler2D specularRect; uniform sampler2D diffuseRect; uniform sampler2D diffuseMap; -vec3 getNorm(vec2 screenpos); +vec4 getNorm(vec2 screenpos); float getDepth(vec2 pos_screen); float linearDepth(float d, float znear, float zfar); float linearDepth01(float d, float znear, float zfar); vec4 getPositionWithDepth(vec2 pos_screen, float depth); vec4 getPosition(vec2 pos_screen); -vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity); float random (vec2 uv); float tapScreenSpaceReflection(int totalSamples, vec2 tc, vec3 viewPos, vec3 n, inout vec4 collectedColor, sampler2D source, float glossiness); -void main() +void main() { vec2 tc = vary_fragcoord.xy; float depth = linearDepth01(getDepth(tc), zNear, zFar); - float envIntensity; - vec3 n; - vec4 norm = getNormalEnvIntensityFlags(tc, n, envIntensity); // need `norm.w` for GET_GBUFFER_FLAG() + vec4 norm = getNorm(tc); // need `norm.w` for GET_GBUFFER_FLAG() vec3 pos = getPositionWithDepth(tc, getDepth(tc)).xyz; vec4 spec = texture(specularRect, tc); vec2 hitpixel; - + vec4 diffuse = texture(diffuseRect, tc); vec3 specCol = spec.rgb; vec4 fcol = texture(diffuseMap, tc); - if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR)) + if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR)) { vec3 orm = specCol.rgb; float perceptualRoughness = orm.g; @@ -84,7 +81,7 @@ void main() vec4 collectedColor = vec4(0); - float w = tapScreenSpaceReflection(4, tc, pos, n, collectedColor, diffuseMap, 0); + float w = tapScreenSpaceReflection(4, tc, pos, norm.xyz, collectedColor, diffuseMap, 0); collectedColor.rgb *= specCol.rgb; diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl index 47b5934b84..96c32734e4 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl @@ -50,6 +50,7 @@ uniform float ssao_irradiance_max; #endif // Inputs +uniform vec4 clipPlane; uniform mat3 env_mat; uniform mat3 ssao_effect_mat; uniform vec3 sun_dir; @@ -60,7 +61,7 @@ in vec2 vary_fragcoord; uniform mat4 inv_proj; uniform vec2 screen_res; -vec3 getNorm(vec2 pos_screen); +vec4 getNorm(vec2 pos_screen); vec4 getPositionWithDepth(vec2 pos_screen, float depth); void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive); @@ -104,8 +105,8 @@ vec3 pbrBaseLight(vec3 diffuseColor, vec3 additive, vec3 atten); -vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor, - float perceptualRoughness, +vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor, + float perceptualRoughness, float metallic, vec3 n, // normal vec3 v, // surface point to camera @@ -127,13 +128,13 @@ void main() vec2 tc = vary_fragcoord.xy; float depth = getDepth(tc.xy); vec4 pos = getPositionWithDepth(tc, depth); - vec4 norm = texture(normalMap, tc); - float envIntensity = norm.z; - norm.xyz = getNorm(tc); + vec4 norm = getNorm(tc); + vec3 colorEmissive = texture(emissiveRect, tc).rgb; + float envIntensity = colorEmissive.r; vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir; vec4 baseColor = texture(diffuseRect, tc); - vec4 spec = texture(specularRect, vary_fragcoord.xy); // NOTE: PBR linear Emissive + vec4 spec = texture(specularRect, tc); // NOTE: PBR linear Emissive #if defined(HAS_SUN_SHADOW) || defined(HAS_SSAO) vec2 scol_ambocc = texture(lightMap, vary_fragcoord.xy).rg; @@ -168,15 +169,15 @@ void main() if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR)) { - vec3 orm = texture(specularRect, tc).rgb; + vec3 orm = spec.rgb; float perceptualRoughness = orm.g; float metallic = orm.b; float ao = orm.r; - vec3 colorEmissive = texture(emissiveRect, tc).rgb; + // PBR IBL float gloss = 1.0 - perceptualRoughness; - + sampleReflectionProbes(irradiance, radiance, tc, pos.xyz, norm.xyz, gloss, false, amblit_linear); adjustIrradiance(irradiance, ambocc); @@ -188,10 +189,15 @@ void main() vec3 v = -normalize(pos.xyz); color = pbrBaseLight(diffuseColor, specularColor, metallic, v, norm.xyz, perceptualRoughness, light_dir, sunlit_linear, scol, radiance, irradiance, colorEmissive, ao, additive, atten); } - else if (!GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_ATMOS)) + else if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_HDRI)) { - //should only be true of WL sky, just port over base color value - color = texture(emissiveRect, tc).rgb; + // actual HDRI sky, just copy color value + color = colorEmissive.rgb; + } + else if (GET_GBUFFER_FLAG(GBUFFER_FLAG_SKIP_ATMOS)) + { + //should only be true of WL sky, port over base color value and scale for fake HDR + color = colorEmissive.rgb; color = srgb_to_linear(color); color *= sky_hdr_scale; } @@ -199,7 +205,7 @@ void main() { // legacy shaders are still writng sRGB to gbuffer baseColor.rgb = srgb_to_linear(baseColor.rgb); - + spec.rgb = srgb_to_linear(spec.rgb); float da = clamp(dot(norm.xyz, light_dir.xyz), 0.0, 1.0); @@ -218,7 +224,7 @@ void main() vec3 sun_contrib = min(da, scol) * sunlit_linear; color.rgb += sun_contrib; color.rgb *= baseColor.rgb; - + vec3 refnormpersp = reflect(pos.xyz, norm.xyz); if (spec.a > 0.0) @@ -244,10 +250,11 @@ void main() // add radiance map applyGlossEnv(color, glossenv, spec, pos.xyz, norm.xyz); + } color.rgb = mix(color.rgb, baseColor.rgb, baseColor.a); - + if (envIntensity > 0.0) { // add environment map applyLegacyEnv(color, legacyenv, spec, pos.xyz, norm.xyz, envIntensity); diff --git a/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl index 871c7ce812..319fa86148 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl @@ -1,28 +1,28 @@ -/** +/** * @file class3\deferred\spotLightF.glsl * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2022, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - + /*[EXTRA_CODE_HERE]*/ out vec4 frag_color; @@ -72,7 +72,7 @@ uniform mat4 inv_proj; void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist); float calcLegacyDistanceAttenuation(float distance, float falloff); bool clipProjectedLightVars(vec3 center, vec3 pos, out float dist, out float l_dist, out vec3 lv, out vec4 proj_tc ); -vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity); +vec4 getNorm(vec2 screenpos); vec3 getProjectedLightAmbiance(float amb_da, float attenuation, float lit, float nl, float noise, vec2 projected_uv); vec3 getProjectedLightDiffuseColor(float light_distance, vec2 projected_uv ); vec2 getScreenCoord(vec4 clip); @@ -83,8 +83,8 @@ vec4 getPosition(vec2 pos_screen); const float M_PI = 3.14159265; -vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor, - float perceptualRoughness, +vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor, + float perceptualRoughness, float metallic, vec3 n, // normal vec3 v, // surface point to camera @@ -112,18 +112,17 @@ void main() } float shadow = 1.0; - + if (proj_shadow_idx >= 0) { vec4 shd = texture(lightMap, tc); shadow = (proj_shadow_idx==0)?shd.b:shd.a; shadow += shadow_fade; - shadow = clamp(shadow, 0.0, 1.0); + shadow = clamp(shadow, 0.0, 1.0); } - float envIntensity; - vec3 n; - vec4 norm = getNormalEnvIntensityFlags(tc, n, envIntensity); + vec4 norm = getNorm(tc); + vec3 n = norm.xyz; float dist_atten = calcLegacyDistanceAttenuation(dist, falloff); if (dist_atten <= 0.0) @@ -145,13 +144,12 @@ void main() if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR)) { - vec3 colorEmissive = texture(emissiveRect, tc).rgb; vec3 orm = spec.rgb; float perceptualRoughness = orm.g; float metallic = orm.b; vec3 f0 = vec3(0.04); vec3 baseColor = diffuse.rgb; - + vec3 diffuseColor = baseColor.rgb*(vec3(1.0)-f0); diffuseColor *= 1.0 - metallic; @@ -169,7 +167,7 @@ void main() if (nl > 0.0) { amb_da += (nl*0.5 + 0.5) * proj_ambiance; - + dlit = getProjectedLightDiffuseColor( l_dist, proj_tc.xy ); vec3 intensity = dist_atten * dlit * 3.25 * shadow; // Legacy attenuation, magic number to balance with legacy materials @@ -182,6 +180,8 @@ void main() } else { + float envIntensity = texture(emissiveRect, tc).r; + diffuse = srgb_to_linear(diffuse); spec.rgb = srgb_to_linear(spec.rgb); @@ -205,11 +205,11 @@ void main() // unshadowed for consistency between forward and deferred? amb_da += (nl*0.5+0.5) /* * (1.0-shadow) */ * proj_ambiance; } - + amb_rgb = getProjectedLightAmbiance( amb_da, dist_atten, lit, nl, 1.0, proj_tc.xy ); final_color += diffuse.rgb * amb_rgb * max(dot(-normalize(lv), n), 0.0); } - + if (spec.a > 0.0) { dlit *= min(nl*6.0, 1.0) * dist_atten; @@ -218,7 +218,7 @@ void main() float gtdenom = 2 * nh; float gt = max(0, min(gtdenom * nv / vh, gtdenom * nl / vh)); - + if (nh > 0.0) { float scol = fres*texture(lightFunc, vec2(nh, spec.a)).r*gt/(nh*nl); @@ -226,26 +226,26 @@ void main() speccol = clamp(speccol, vec3(0), vec3(1)); final_color += speccol; } - } + } if (envIntensity > 0.0) { vec3 ref = reflect(normalize(pos), n); - + //project from point pos in direction ref to plane proj_p, proj_n vec3 pdelta = proj_p-pos; float ds = dot(ref, proj_n); - + if (ds < 0.0) { vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds; - + vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0)); if (stc.z > 0.0) { stc /= stc.w; - + if (stc.x < 1.0 && stc.y < 1.0 && stc.x > 0.0 && diff --git a/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl index 61059e2339..f6bef1e498 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl @@ -43,7 +43,7 @@ void main() float depth = getDepth(tc.xy); if (above_water > 0) - { + { // we want to depth test when the camera is above water, but some GPUs have a hard time // with depth testing against render targets that are bound for sampling in the same shader // so we do it manually here @@ -56,10 +56,9 @@ void main() } vec4 pos = getPositionWithDepth(tc, depth); - vec4 norm = texture(normalMap, tc); vec4 fogged = getWaterFogView(pos.xyz); frag_color = max(fogged, vec4(0)); //output linear since local lights will be added to this shader's results - + } diff --git a/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl b/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl index 3bf606a252..728d70ebb2 100644 --- a/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl +++ b/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl @@ -55,9 +55,11 @@ in vec4 view; in vec3 vary_position; vec4 applyWaterFogViewLinearNoClip(vec3 pos, vec4 color); +void mirrorClip(vec3 position); void main() { + mirrorClip(vary_position); vec4 color; //get detail normals diff --git a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl index 88c38c46a2..a5592188a9 100644 --- a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl +++ b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl @@ -35,6 +35,8 @@ vec3 scaleSoftClipFragLinear(vec3 l); void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive); vec4 applyWaterFogViewLinear(vec3 pos, vec4 color); +void mirrorClip(vec3 pos); + // PBR interface vec2 BRDF(float NoV, float roughness); @@ -129,6 +131,7 @@ vec3 getPositionWithNDC(vec3 ndc); void main() { + mirrorClip(vary_position); vN = vary_normal; vT = vary_tangent; vB = cross(vN, vT); diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt index 942b84fce9..7cdb304bfb 100644 --- a/indra/newview/featuretable.txt +++ b/indra/newview/featuretable.txt @@ -1,4 +1,4 @@ -version 59 +version 60 // The version number above should be incremented IF AND ONLY IF some // change has been made that is sufficiently important to justify // resetting the graphics preferences of all users to the recommended @@ -48,6 +48,8 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 2 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 3 RenderTreeLODFactor 1 1.0 RenderVBOEnable 1 1 RenderVBOMappingDisable 1 1 @@ -73,6 +75,7 @@ RenderGLMultiThreadedTextures 1 0 RenderGLMultiThreadedMedia 1 1 RenderReflectionProbeResolution 1 128 RenderScreenSpaceReflections 1 1 +RenderMirrors 1 1 // @@ -94,6 +97,8 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 0 RenderTerrainDetail 1 0 RenderTerrainLODFactor 1 1 +RenderTerrainPBRDetail 1 -4 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTreeLODFactor 1 0 RenderVolumeLODFactor 1 1.5 RenderDeferredSSAO 1 0 @@ -103,6 +108,11 @@ WLSkyDetail 1 96 RenderFSAASamples 1 0 RenderScreenSpaceReflections 1 0 RenderReflectionProbeLevel 1 0 +RenderMirrors 1 0 +RenderHeroProbeResolution 1 256 +RenderHeroProbeDistance 1 4 +RenderHeroProbeUpdateRate 1 4 +RenderHeroProbeConservativeUpdateMultiplier 1 16 // // Medium Low Graphics Settings @@ -123,6 +133,8 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 0 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 1.0 +RenderTerrainPBRDetail 1 -1 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 2.0 RenderDeferredSSAO 1 0 @@ -132,6 +144,11 @@ WLSkyDetail 1 96 RenderFSAASamples 1 0 RenderScreenSpaceReflections 1 0 RenderReflectionProbeLevel 1 0 +RenderMirrors 1 0 +RenderHeroProbeResolution 1 256 +RenderHeroProbeDistance 1 6 +RenderHeroProbeUpdateRate 1 3 +RenderHeroProbeConservativeUpdateMultiplier 1 16 // // Medium Graphics Settings (standard) @@ -150,6 +167,8 @@ RenderLocalLightCount 1 512 RenderTransparentWater 1 0 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 2.0 RenderDeferredSSAO 1 0 @@ -161,6 +180,11 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 0 RenderScreenSpaceReflections 1 0 RenderReflectionProbeLevel 1 1 +RenderMirrors 1 0 +RenderHeroProbeResolution 1 512 +RenderHeroProbeDistance 1 6 +RenderHeroProbeUpdateRate 1 3 +RenderHeroProbeConservativeUpdateMultiplier 1 16 // // Medium High Graphics Settings @@ -179,6 +203,8 @@ RenderLocalLightCount 1 1024 RenderTransparentWater 1 1 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 2.0 RenderDeferredSSAO 1 0 @@ -190,6 +216,11 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 1 RenderScreenSpaceReflections 1 0 RenderReflectionProbeLevel 1 2 +RenderMirrors 1 0 +RenderHeroProbeResolution 1 512 +RenderHeroProbeDistance 1 6 +RenderHeroProbeUpdateRate 1 2 +RenderHeroProbeConservativeUpdateMultiplier 1 8 // // High Graphics Settings (SSAO + sun shadows) @@ -208,6 +239,8 @@ RenderLocalLightCount 1 2048 RenderTransparentWater 1 1 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 3 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 2.0 RenderDeferredSSAO 1 1 @@ -219,6 +252,11 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 1 RenderScreenSpaceReflections 1 0 RenderReflectionProbeLevel 1 3 +RenderMirrors 1 1 +RenderHeroProbeResolution 1 512 +RenderHeroProbeDistance 1 8 +RenderHeroProbeUpdateRate 1 2 +RenderHeroProbeConservativeUpdateMultiplier 1 8 // // High Ultra Graphics Settings (deferred + SSAO + all shadows) @@ -236,6 +274,8 @@ RenderMaxPartCount 1 4096 RenderLocalLightCount 1 4096 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 3 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 2.0 @@ -248,6 +288,11 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 1 RenderScreenSpaceReflections 1 0 RenderReflectionProbeLevel 1 3 +RenderMirrors 1 1 +RenderHeroProbeResolution 1 1024 +RenderHeroProbeDistance 1 16 +RenderHeroProbeUpdateRate 1 1 +RenderHeroProbeConservativeUpdateMultiplier 1 4 // // Ultra graphics (REALLY PURTY!) @@ -264,6 +309,8 @@ RenderLocalLightCount 1 8192 RenderMaxPartCount 1 8192 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 3 RenderTransparentWater 1 1 RenderTreeLODFactor 1 1.0 RenderVolumeLODFactor 1 3.0 @@ -277,6 +324,11 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 1 RenderScreenSpaceReflections 1 0 RenderReflectionProbeLevel 1 3 +RenderMirrors 1 1 +RenderHeroProbeResolution 1 2048 +RenderHeroProbeDistance 1 16 +RenderHeroProbeUpdateRate 1 1 +RenderHeroProbeConservativeUpdateMultiplier 1 4 // // Class Unknown Hardware (unknown) @@ -285,6 +337,7 @@ list Unknown RenderShadowDetail 1 0 RenderDeferredSSAO 1 0 RenderUseAdvancedAtmospherics 1 0 +RenderMirrors 1 0 // // VRAM > 512MB @@ -306,6 +359,7 @@ RenderTransparentWater 1 0 RenderDeferredSSAO 0 0 RenderShadowDetail 0 0 RenderReflectionProbeDetail 0 -1 +RenderMirrors 0 0 list Intel RenderAnisotropic 1 0 @@ -320,4 +374,7 @@ list GL3 RenderFSAASamples 0 0 RenderReflectionsEnabled 0 0 RenderReflectionProbeDetail 0 0 +RenderMirrors 0 0 +list TexUnit16orLess +RenderTerrainPBRDetail 1 -1 diff --git a/indra/newview/featuretable_linux.txt b/indra/newview/featuretable_linux.txt index 64d9dc84f9..1d6156bcb1 100644 --- a/indra/newview/featuretable_linux.txt +++ b/indra/newview/featuretable_linux.txt @@ -1,4 +1,4 @@ -version 46 +version 47 // The version number above should be incremented IF AND ONLY IF some // change has been made that is sufficiently important to justify // resetting the graphics preferences of all users to the recommended @@ -48,6 +48,8 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 2 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 3 RenderTreeLODFactor 1 1.0 RenderVBOEnable 1 1 RenderVBOMappingDisable 1 1 @@ -94,6 +96,8 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 0 RenderTerrainDetail 1 0 RenderTerrainLODFactor 1 1 +RenderTerrainPBRDetail 1 -4 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTreeLODFactor 1 0 RenderVolumeLODFactor 1 1.5 RenderDeferredSSAO 1 0 @@ -103,6 +107,11 @@ WLSkyDetail 1 96 RenderFSAASamples 1 0 RenderScreenSpaceReflections 1 0 RenderReflectionProbeLevel 1 0 +RenderMirrors 1 0 +RenderHeroProbeResolution 1 256 +RenderHeroProbeDistance 1 4 +RenderHeroProbeUpdateRate 1 4 +RenderHeroProbeConservativeUpdateMultiplier 1 16 // // Medium Low Graphics Settings @@ -123,6 +132,8 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 0 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 1.0 +RenderTerrainPBRDetail 1 -1 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 2.0 RenderDeferredSSAO 1 0 @@ -132,6 +143,11 @@ WLSkyDetail 1 96 RenderFSAASamples 1 0 RenderScreenSpaceReflections 1 0 RenderReflectionProbeLevel 1 0 +RenderMirrors 1 0 +RenderHeroProbeResolution 1 256 +RenderHeroProbeDistance 1 6 +RenderHeroProbeUpdateRate 1 3 +RenderHeroProbeConservativeUpdateMultiplier 1 16 // // Medium Graphics Settings (standard) @@ -150,6 +166,8 @@ RenderLocalLightCount 1 512 RenderTransparentWater 1 0 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 2.0 RenderDeferredSSAO 1 0 @@ -161,6 +179,11 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 0 RenderScreenSpaceReflections 1 0 RenderReflectionProbeLevel 1 1 +RenderMirrors 1 0 +RenderHeroProbeResolution 1 512 +RenderHeroProbeDistance 1 6 +RenderHeroProbeUpdateRate 1 3 +RenderHeroProbeConservativeUpdateMultiplier 1 16 // // Medium High Graphics Settings @@ -179,6 +202,8 @@ RenderLocalLightCount 1 1024 RenderTransparentWater 1 1 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 2.0 RenderDeferredSSAO 1 0 @@ -190,6 +215,11 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 1 RenderScreenSpaceReflections 1 0 RenderReflectionProbeLevel 1 2 +RenderMirrors 1 0 +RenderHeroProbeResolution 1 512 +RenderHeroProbeDistance 1 6 +RenderHeroProbeUpdateRate 1 2 +RenderHeroProbeConservativeUpdateMultiplier 1 8 // // High Graphics Settings (SSAO + sun shadows) @@ -208,6 +238,8 @@ RenderLocalLightCount 1 2048 RenderTransparentWater 1 1 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 3 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 2.0 RenderDeferredSSAO 1 1 @@ -219,6 +251,11 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 1 RenderScreenSpaceReflections 1 0 RenderReflectionProbeLevel 1 3 +RenderMirrors 1 0 +RenderHeroProbeResolution 1 1024 +RenderHeroProbeDistance 1 8 +RenderHeroProbeUpdateRate 1 2 +RenderHeroProbeConservativeUpdateMultiplier 1 8 // // High Ultra Graphics Settings (deferred + SSAO + all shadows) @@ -236,6 +273,8 @@ RenderMaxPartCount 1 4096 RenderLocalLightCount 1 4096 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 3 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 2.0 @@ -248,6 +287,11 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 1 RenderScreenSpaceReflections 1 0 RenderReflectionProbeLevel 1 3 +RenderMirrors 1 0 +RenderHeroProbeResolution 1 1024 +RenderHeroProbeDistance 1 16 +RenderHeroProbeUpdateRate 1 1 +RenderHeroProbeConservativeUpdateMultiplier 1 4 // // Ultra graphics (REALLY PURTY!) @@ -264,6 +308,8 @@ RenderLocalLightCount 1 8192 RenderMaxPartCount 1 8192 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 3 RenderTransparentWater 1 1 RenderTreeLODFactor 1 1.0 RenderVolumeLODFactor 1 3.0 @@ -277,6 +323,11 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 1 RenderScreenSpaceReflections 1 0 RenderReflectionProbeLevel 1 3 +RenderMirrors 1 1 +RenderHeroProbeResolution 1 2048 +RenderHeroProbeDistance 1 16 +RenderHeroProbeUpdateRate 1 1 +RenderHeroProbeConservativeUpdateMultiplier 1 4 // // Class Unknown Hardware (unknown) @@ -285,6 +336,7 @@ list Unknown RenderShadowDetail 1 0 RenderDeferredSSAO 1 0 RenderUseAdvancedAtmospherics 1 0 +RenderMirrors 1 0 // // VRAM > 512MB @@ -306,6 +358,7 @@ RenderTransparentWater 1 0 RenderDeferredSSAO 0 0 RenderShadowDetail 0 0 RenderReflectionProbeDetail 0 -1 +RenderMirrors 0 0 list Intel RenderAnisotropic 1 0 @@ -326,5 +379,8 @@ list GL3 RenderFSAASamples 0 0 RenderReflectionsEnabled 0 0 RenderReflectionProbeDetail 0 0 +RenderMirrors 0 0 RenderGLMultiThreadedTextures 0 0 +list TexUnit16orLess +RenderTerrainPBRDetail 1 -1 diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt index bebc96031d..a183f88422 100644 --- a/indra/newview/featuretable_mac.txt +++ b/indra/newview/featuretable_mac.txt @@ -1,4 +1,4 @@ -version 56 +version 57 // The version number above should be incremented IF AND ONLY IF some // change has been made that is sufficiently important to justify // resetting the graphics preferences of all users to the recommended @@ -45,6 +45,8 @@ RenderObjectBump 1 1 RenderLocalLightCount 1 4096 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 3 RenderTransparentWater 1 1 RenderTreeLODFactor 1 1.0 RenderVBOEnable 1 1 @@ -72,6 +74,7 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 2 RenderScreenSpaceReflections 1 1 RenderReflectionProbeLevel 1 3 +RenderMirrors 1 1 // // Low Graphics Settings @@ -89,6 +92,8 @@ RenderLocalLightCount 1 8 RenderMaxPartCount 1 256 RenderTerrainDetail 1 0 RenderTerrainLODFactor 1 1 +RenderTerrainPBRDetail 1 -4 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTransparentWater 1 0 RenderTreeLODFactor 1 0 RenderVolumeLODFactor 1 1.5 @@ -101,6 +106,11 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 0 RenderScreenSpaceReflections 1 0 RenderReflectionProbeLevel 1 0 +RenderMirrors 1 0 +RenderHeroProbeResolution 1 256 +RenderHeroProbeDistance 1 4 +RenderHeroProbeUpdateRate 1 4 +RenderHeroProbeConservativeUpdateMultiplier 1 16 // // Medium Low Graphics Settings @@ -118,6 +128,8 @@ RenderMaxPartCount 1 2048 RenderLocalLightCount 1 256 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 1.0 +RenderTerrainPBRDetail 1 -1 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.5 @@ -130,6 +142,11 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 0 RenderScreenSpaceReflections 1 0 RenderReflectionProbeLevel 1 0 +RenderMirrors 1 0 +RenderHeroProbeResolution 1 256 +RenderHeroProbeDistance 1 6 +RenderHeroProbeUpdateRate 1 3 +RenderHeroProbeConservativeUpdateMultiplier 1 16 // // Medium Graphics Settings (standard) @@ -147,6 +164,8 @@ RenderMaxPartCount 1 4096 RenderLocalLightCount 1 512 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.5 @@ -159,6 +178,11 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 0 RenderScreenSpaceReflections 1 0 RenderReflectionProbeLevel 1 0 +RenderMirrors 1 0 +RenderHeroProbeResolution 1 512 +RenderHeroProbeDistance 1 6 +RenderHeroProbeUpdateRate 1 3 +RenderHeroProbeConservativeUpdateMultiplier 1 16 // // Medium High Graphics Settings @@ -176,6 +200,8 @@ RenderMaxPartCount 1 4096 RenderLocalLightCount 1 1024 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 1 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 2.0 @@ -188,6 +214,11 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 0 RenderScreenSpaceReflections 1 0 RenderReflectionProbeLevel 1 0 +RenderMirrors 1 0 +RenderHeroProbeResolution 1 512 +RenderHeroProbeDistance 1 6 +RenderHeroProbeUpdateRate 1 2 +RenderHeroProbeConservativeUpdateMultiplier 1 8 // // High Graphics Settings (SSAO + sun shadows) @@ -205,6 +236,8 @@ RenderMaxPartCount 1 4096 RenderLocalLightCount 1 2048 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 3 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 2.0 @@ -217,6 +250,11 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 1 RenderScreenSpaceReflections 1 0 RenderReflectionProbeLevel 1 1 +RenderMirrors 1 1 +RenderHeroProbeResolution 1 512 +RenderHeroProbeDistance 1 8 +RenderHeroProbeUpdateRate 1 2 +RenderHeroProbeConservativeUpdateMultiplier 1 8 // // High Ultra Graphics Settings (SSAO + all shadows) @@ -234,6 +272,8 @@ RenderMaxPartCount 1 4096 RenderLocalLightCount 1 4096 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 3 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 2.0 @@ -246,6 +286,11 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 1 RenderScreenSpaceReflections 1 0 RenderReflectionProbeLevel 1 2 +RenderMirrors 1 1 +RenderHeroProbeResolution 1 512 +RenderHeroProbeDistance 1 16 +RenderHeroProbeUpdateRate 1 1 +RenderHeroProbeConservativeUpdateMultiplier 1 4 // // Ultra graphics (REALLY PURTY!) @@ -262,6 +307,8 @@ RenderLocalLightCount 1 8192 RenderMaxPartCount 1 8192 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 +RenderTerrainPBRDetail 1 0 +RenderTerrainPBRPlanarSampleCount 1 3 RenderTransparentWater 1 1 RenderTreeLODFactor 1 1.0 RenderVolumeLODFactor 1 3.0 @@ -275,6 +322,11 @@ RenderReflectionsEnabled 1 1 RenderReflectionProbeDetail 1 1 RenderScreenSpaceReflections 1 0 RenderReflectionProbeLevel 1 3 +RenderMirrors 1 1 +RenderHeroProbeResolution 1 1024 +RenderHeroProbeDistance 1 16 +RenderHeroProbeUpdateRate 1 1 +RenderHeroProbeConservativeUpdateMultiplier 1 4 // // Class Unknown Hardware (unknown) @@ -283,6 +335,7 @@ list Unknown RenderShadowDetail 1 0 RenderDeferredSSAO 1 0 RenderUseAdvancedAtmospherics 1 0 +RenderMirrors 1 0 // @@ -304,10 +357,14 @@ RenderTerrainDetail 1 0 RenderDeferredSSAO 0 0 RenderUseAdvancedAtmospherics 0 0 RenderShadowDetail 0 0 +RenderMirrors 0 0 list TexUnit8orLess RenderDeferredSSAO 0 0 +list TexUnit16orLess +RenderTerrainPBRDetail 1 -1 + list AMD RenderDeferredSSAO 1 0 @@ -319,3 +376,4 @@ list GL3 RenderFSAASamples 0 0 RenderReflectionProbeDetail 0 0 RenderReflectionsEnabled 0 0 +RenderMirrors 0 0 diff --git a/indra/newview/fspanelface.cpp b/indra/newview/fspanelface.cpp index 6a1b3ae28e..337a94a3d1 100644 --- a/indra/newview/fspanelface.cpp +++ b/indra/newview/fspanelface.cpp @@ -794,7 +794,7 @@ bool FSPanelFace::postBuild() // PBR Base Material swatch // mMaterialCtrlPBR->setDefaultImageAssetID(LLUUID::null); // we have no default material, and null is standard for LLUUID -Zi - mMaterialCtrlPBR->setBlankImageAssetID(LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID); + mMaterialCtrlPBR->setBlankImageAssetID(BLANK_MATERIAL_ASSET_ID); mMaterialCtrlPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this)); mMaterialCtrlPBR->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelPbr, this)); mMaterialCtrlPBR->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectPbr, this)); @@ -2407,7 +2407,7 @@ void FSPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, { mVOInventoryListener = nullptr; } - if (!func.mIdenticalMaterial || func.mMaterialId.isNull() || func.mMaterialId == LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID) + if (!func.mIdenticalMaterial || func.mMaterialId.isNull() || func.mMaterialId == BLANK_MATERIAL_ASSET_ID) { mAgentInventoryListener = nullptr; } diff --git a/indra/newview/fsradarentry.cpp b/indra/newview/fsradarentry.cpp index d4fe667f8e..2170c2f908 100644 --- a/indra/newview/fsradarentry.cpp +++ b/indra/newview/fsradarentry.cpp @@ -78,15 +78,13 @@ void FSRadarEntry::requestProperties() { if (!mPropertiesRequested && mID.notNull()) { - // NOTE: typically we request these once on creation to avoid excess traffic/processing. - //This means updates to these properties won't typically be seen while target is in nearby range. - LLAvatarPropertiesProcessor* processor = LLAvatarPropertiesProcessor::getInstance(); - processor->addObserver(mID, this); - if (auto region = gAgent.getRegion()) { if (region->capabilitiesReceived()) { + LLAvatarPropertiesProcessor* processor = LLAvatarPropertiesProcessor::getInstance(); + processor->addObserver(mID, this); + if (LLGridManager::instance().isInSecondLife() || region->isCapabilityAvailable(CAPNAME)) { processor->sendAvatarPropertiesRequest(mID); diff --git a/indra/newview/gltf/accessor.cpp b/indra/newview/gltf/accessor.cpp new file mode 100644 index 0000000000..55d36b7a32 --- /dev/null +++ b/indra/newview/gltf/accessor.cpp @@ -0,0 +1,66 @@ +/** + * @file accessor.cpp + * @brief LL GLTF Implementation + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "../llviewerprecompiledheaders.h" + +#include "asset.h" + +using namespace LL::GLTF; + +const Buffer& Buffer::operator=(const tinygltf::Buffer& src) +{ + mData = src.data; + mName = src.name; + mUri = src.uri; + return *this; +} + +const BufferView& BufferView::operator=(const tinygltf::BufferView& src) +{ + mBuffer = src.buffer; + mByteLength = src.byteLength; + mByteOffset = src.byteOffset; + mByteStride = src.byteStride; + mTarget = src.target; + mName = src.name; + return *this; +} + +const Accessor& Accessor::operator=(const tinygltf::Accessor& src) +{ + mBufferView = src.bufferView; + mByteOffset = src.byteOffset; + mComponentType = src.componentType; + mCount = src.count; + mType = src.type; + mNormalized = src.normalized; + mName = src.name; + mMax = src.maxValues; + mMin = src.minValues; + + return *this; +} + diff --git a/indra/newview/gltf/accessor.h b/indra/newview/gltf/accessor.h new file mode 100644 index 0000000000..9b8265d8da --- /dev/null +++ b/indra/newview/gltf/accessor.h @@ -0,0 +1,95 @@ +#pragma once + +/** + * @file asset.h + * @brief LL GLTF Implementation + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "../lltinygltfhelper.h" +#include "llstrider.h" + +// LL GLTF Implementation +namespace LL +{ + namespace GLTF + { + class Asset; + + constexpr S32 INVALID_INDEX = -1; + + class Buffer + { + public: + std::vector mData; + std::string mName; + std::string mUri; + + const Buffer& operator=(const tinygltf::Buffer& src); + }; + + class BufferView + { + public: + S32 mBuffer = INVALID_INDEX; + S32 mByteLength; + S32 mByteOffset; + S32 mByteStride; + S32 mTarget; + S32 mComponentType; + + std::string mName; + + const BufferView& operator=(const tinygltf::BufferView& src); + + }; + + class Accessor + { + public: + S32 mBufferView = INVALID_INDEX; + S32 mByteOffset; + S32 mComponentType; + S32 mCount; + std::vector mMax; + std::vector mMin; + + enum class Type : S32 + { + SCALAR = TINYGLTF_TYPE_SCALAR, + VEC2 = TINYGLTF_TYPE_VEC2, + VEC3 = TINYGLTF_TYPE_VEC3, + VEC4 = TINYGLTF_TYPE_VEC4, + MAT2 = TINYGLTF_TYPE_MAT2, + MAT3 = TINYGLTF_TYPE_MAT3, + MAT4 = TINYGLTF_TYPE_MAT4 + }; + + S32 mType; + bool mNormalized; + std::string mName; + + const Accessor& operator=(const tinygltf::Accessor& src); + }; + } +} diff --git a/indra/newview/gltf/animation.cpp b/indra/newview/gltf/animation.cpp new file mode 100644 index 0000000000..da6d02b356 --- /dev/null +++ b/indra/newview/gltf/animation.cpp @@ -0,0 +1,287 @@ +/** + * @file animation.cpp + * @brief LL GLTF Animation Implementation + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "../llviewerprecompiledheaders.h" + +#include "asset.h" +#include "buffer_util.h" + +using namespace LL::GLTF; + +void Animation::allocateGLResources(Asset& asset) +{ + if (!mSamplers.empty()) + { + mMinTime = FLT_MAX; + mMaxTime = -FLT_MAX; + for (auto& sampler : mSamplers) + { + sampler.allocateGLResources(asset); + mMinTime = llmin(sampler.mMinTime, mMinTime); + mMaxTime = llmax(sampler.mMaxTime, mMaxTime); + } + } + else + { + mMinTime = mMaxTime = 0.f; + } + + for (auto& channel : mRotationChannels) + { + channel.allocateGLResources(asset, mSamplers[channel.mSampler]); + } + + for (auto& channel : mTranslationChannels) + { + channel.allocateGLResources(asset, mSamplers[channel.mSampler]); + } +} + +void Animation::update(Asset& asset, F32 dt) +{ + mTime += dt; + + apply(asset, mTime); +} + +void Animation::apply(Asset& asset, float time) +{ + // convert time to animation loop time + time = fmod(time, mMaxTime - mMinTime) + mMinTime; + + // apply each channel + for (auto& channel : mRotationChannels) + { + channel.apply(asset, mSamplers[channel.mSampler], time); + } + + for (auto& channel : mTranslationChannels) + { + channel.apply(asset, mSamplers[channel.mSampler], time); + } +}; + + +void Animation::Sampler::allocateGLResources(Asset& asset) +{ + Accessor& accessor = asset.mAccessors[mInput]; + mMinTime = accessor.mMin[0]; + mMaxTime = accessor.mMax[0]; + + mFrameTimes.resize(accessor.mCount); + + LLStrider frame_times = mFrameTimes.data(); + copy(asset, accessor, frame_times); +} + +void Animation::Sampler::getFrameInfo(Asset& asset, F32 time, U32& frameIndex, F32& t) +{ + if (time < mMinTime) + { + frameIndex = 0; + t = 0.0f; + return; + } + + if (mFrameTimes.size() > 1) + { + if (time > mMaxTime) + { + frameIndex = mFrameTimes.size() - 2; + t = 1.0f; + return; + } + + frameIndex = mFrameTimes.size() - 2; + t = 1.f; + + for (U32 i = 0; i < mFrameTimes.size() - 1; i++) + { + if (time >= mFrameTimes[i] && time < mFrameTimes[i + 1]) + { + frameIndex = i; + t = (time - mFrameTimes[i]) / (mFrameTimes[i + 1] - mFrameTimes[i]); + return; + } + } + } + else + { + frameIndex = 0; + t = 0.0f; + } +} + +void Animation::RotationChannel::allocateGLResources(Asset& asset, Animation::Sampler& sampler) +{ + Accessor& accessor = asset.mAccessors[sampler.mOutput]; + + copy(asset, accessor, mRotations); +} + +void Animation::RotationChannel::apply(Asset& asset, Sampler& sampler, F32 time) +{ + U32 frameIndex; + F32 t; + + Node& node = asset.mNodes[mTarget.mNode]; + + sampler.getFrameInfo(asset, time, frameIndex, t); + + if (sampler.mFrameTimes.size() == 1) + { + node.setRotation(mRotations[0]); + } + else + { + // interpolate + LLQuaternion q0(mRotations[frameIndex].get_value()); + LLQuaternion q1(mRotations[frameIndex + 1].get_value()); + + LLQuaternion qf = slerp(t, q0, q1); + + qf.normalize(); + node.setRotation(glh::quaternionf(qf.mQ)); + } +} + +void Animation::TranslationChannel::allocateGLResources(Asset& asset, Animation::Sampler& sampler) +{ + Accessor& accessor = asset.mAccessors[sampler.mOutput]; + + copy(asset, accessor, mTranslations); +} + +void Animation::TranslationChannel::apply(Asset& asset, Sampler& sampler, F32 time) +{ + U32 frameIndex; + F32 t; + + Node& node = asset.mNodes[mTarget.mNode]; + + sampler.getFrameInfo(asset, time, frameIndex, t); + + if (sampler.mFrameTimes.size() == 1) + { + node.setTranslation(mTranslations[0]); + } + else + { + // interpolate + const glh::vec3f& v0 = mTranslations[frameIndex]; + const glh::vec3f& v1 = mTranslations[frameIndex + 1]; + + glh::vec3f vf = v0 + t * (v1 - v0); + + node.setTranslation(vf); + } +} + +void Animation::ScaleChannel::allocateGLResources(Asset& asset, Animation::Sampler& sampler) +{ + Accessor& accessor = asset.mAccessors[sampler.mOutput]; + + copy(asset, accessor, mScales); +} + +void Animation::ScaleChannel::apply(Asset& asset, Sampler& sampler, F32 time) +{ + U32 frameIndex; + F32 t; + + Node& node = asset.mNodes[mTarget.mNode]; + + sampler.getFrameInfo(asset, time, frameIndex, t); + + if (sampler.mFrameTimes.size() == 1) + { + node.setScale(mScales[0]); + } + else + { + // interpolate + const glh::vec3f& v0 = mScales[frameIndex]; + const glh::vec3f& v1 = mScales[frameIndex + 1]; + + glh::vec3f vf = v0 + t * (v1 - v0); + + node.setScale(vf); + } +} + +const Animation& Animation::operator=(const tinygltf::Animation& src) +{ + mName = src.name; + + mSamplers.resize(src.samplers.size()); + for (U32 i = 0; i < src.samplers.size(); ++i) + { + mSamplers[i] = src.samplers[i]; + } + + for (U32 i = 0; i < src.channels.size(); ++i) + { + if (src.channels[i].target_path == "rotation") + { + mRotationChannels.push_back(RotationChannel()); + mRotationChannels.back() = src.channels[i]; + } + + if (src.channels[i].target_path == "translation") + { + mTranslationChannels.push_back(TranslationChannel()); + mTranslationChannels.back() = src.channels[i]; + } + + if (src.channels[i].target_path == "scale") + { + mScaleChannels.push_back(ScaleChannel()); + mScaleChannels.back() = src.channels[i]; + } + } + + return *this; +} + +void Skin::allocateGLResources(Asset& asset) +{ + if (mInverseBindMatrices != INVALID_INDEX) + { + Accessor& accessor = asset.mAccessors[mInverseBindMatrices]; + copy(asset, accessor, mInverseBindMatricesData); + } +} + +const Skin& Skin::operator=(const tinygltf::Skin& src) +{ + mName = src.name; + mSkeleton = src.skeleton; + mInverseBindMatrices = src.inverseBindMatrices; + mJoints = src.joints; + + return *this; +} + diff --git a/indra/newview/gltf/animation.h b/indra/newview/gltf/animation.h new file mode 100644 index 0000000000..869eae963a --- /dev/null +++ b/indra/newview/gltf/animation.h @@ -0,0 +1,181 @@ +#pragma once + +/** + * @file animation.h + * @brief LL GLTF Animation Implementation + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "accessor.h" + +// LL GLTF Implementation +namespace LL +{ + namespace GLTF + { + class Asset; + + class Animation + { + public: + class Sampler + { + public: + std::vector mFrameTimes; + + F32 mMinTime = -FLT_MAX; + F32 mMaxTime = FLT_MAX; + + S32 mInput = INVALID_INDEX; + S32 mOutput = INVALID_INDEX; + std::string mInterpolation; + + void allocateGLResources(Asset& asset); + + const Sampler& operator=(const tinygltf::AnimationSampler& src) + { + mInput = src.input; + mOutput = src.output; + mInterpolation = src.interpolation; + + return *this; + } + + // get the frame index and time for the specified time + // asset -- the asset to reference for Accessors + // time -- the animation time to get the frame info for + // frameIndex -- index of the closest frame that precedes the specified time + // t - interpolant value between the frameIndex and the next frame + void getFrameInfo(Asset& asset, F32 time, U32& frameIndex, F32& t); + }; + + class Channel + { + public: + class Target + { + public: + S32 mNode = INVALID_INDEX; + std::string mPath; + }; + + S32 mSampler = INVALID_INDEX; + Target mTarget; + std::string mTargetPath; + std::string mName; + + const Channel& operator=(const tinygltf::AnimationChannel& src) + { + mSampler = src.sampler; + + mTarget.mNode = src.target_node; + mTarget.mPath = src.target_path; + + return *this; + } + + }; + + class RotationChannel : public Channel + { + public: + std::vector mRotations; + + const RotationChannel& operator=(const tinygltf::AnimationChannel& src) + { + Channel::operator=(src); + return *this; + } + + // prepare data needed for rendering + // asset -- asset to reference for Accessors + // sampler -- Sampler associated with this channel + void allocateGLResources(Asset& asset, Sampler& sampler); + + void apply(Asset& asset, Sampler& sampler, F32 time); + }; + + class TranslationChannel : public Channel + { + public: + std::vector mTranslations; + + const TranslationChannel& operator=(const tinygltf::AnimationChannel& src) + { + Channel::operator=(src); + return *this; + } + + // prepare data needed for rendering + // asset -- asset to reference for Accessors + // sampler -- Sampler associated with this channel + void allocateGLResources(Asset& asset, Sampler& sampler); + + void apply(Asset& asset, Sampler& sampler, F32 time); + }; + + class ScaleChannel : public Channel + { + public: + std::vector mScales; + + const ScaleChannel& operator=(const tinygltf::AnimationChannel& src) + { + Channel::operator=(src); + return *this; + } + + // prepare data needed for rendering + // asset -- asset to reference for Accessors + // sampler -- Sampler associated with this channel + void allocateGLResources(Asset& asset, Sampler& sampler); + + void apply(Asset& asset, Sampler& sampler, F32 time); + }; + + std::string mName; + std::vector mSamplers; + + // min/max time values for all samplers combined + F32 mMinTime = 0.f; + F32 mMaxTime = 0.f; + + // current time of the animation + F32 mTime = 0.f; + + std::vector mRotationChannels; + std::vector mTranslationChannels; + std::vector mScaleChannels; + + const Animation& operator=(const tinygltf::Animation& src); + + void allocateGLResources(Asset& asset); + + void update(Asset& asset, float dt); + + // apply this animation at the specified time + void apply(Asset& asset, F32 time); + }; + + } +} diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp new file mode 100644 index 0000000000..1a4971a16e --- /dev/null +++ b/indra/newview/gltf/asset.cpp @@ -0,0 +1,664 @@ +/** + * @file asset.cpp + * @brief LL GLTF Implementation + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "../llviewerprecompiledheaders.h" + +#include "asset.h" +#include "llvolumeoctree.h" +#include "../llviewershadermgr.h" +#include "../llviewercontrol.h" + +using namespace LL::GLTF; + +void Scene::updateTransforms(Asset& asset) +{ + LLMatrix4a identity; + identity.setIdentity(); + for (auto& nodeIndex : mNodes) + { + Node& node = asset.mNodes[nodeIndex]; + node.updateTransforms(asset, identity); + } +} + +void Scene::updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview) +{ + for (auto& nodeIndex : mNodes) + { + Node& node = asset.mNodes[nodeIndex]; + node.updateRenderTransforms(asset, modelview); + } +} + +void Node::updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview) +{ + matMul(mMatrix, modelview, mRenderMatrix); + + for (auto& childIndex : mChildren) + { + Node& child = asset.mNodes[childIndex]; + child.updateRenderTransforms(asset, mRenderMatrix); + } +} + +LLMatrix4a inverse(const LLMatrix4a& mat); + +void Node::updateTransforms(Asset& asset, const LLMatrix4a& parentMatrix) +{ + makeMatrixValid(); + matMul(mMatrix, parentMatrix, mAssetMatrix); + mAssetMatrixInv = inverse(mAssetMatrix); + + S32 my_index = this - &asset.mNodes[0]; + + for (auto& childIndex : mChildren) + { + Node& child = asset.mNodes[childIndex]; + child.mParent = my_index; + child.updateTransforms(asset, mAssetMatrix); + } +} + +void Asset::updateTransforms() +{ + for (auto& scene : mScenes) + { + scene.updateTransforms(*this); + } +} + +void Asset::updateRenderTransforms(const LLMatrix4a& modelview) +{ +#if 0 + // traverse hierarchy and update render transforms from scratch + for (auto& scene : mScenes) + { + scene.updateRenderTransforms(*this, modelview); + } +#else + // use mAssetMatrix to update render transforms from node list + for (auto& node : mNodes) + { + //if (node.mMesh != INVALID_INDEX) + { + matMul(node.mAssetMatrix, modelview, node.mRenderMatrix); + } + } + +#endif + +} + +S32 Asset::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, + LLVector4a* intersection, // return the intersection point + LLVector2* tex_coord, // return the texture coordinates of the intersection point + LLVector4a* normal, // return the surface normal at the intersection point + LLVector4a* tangent, // return the surface tangent at the intersection point + S32* primitive_hitp +) +{ + S32 node_hit = -1; + S32 primitive_hit = -1; + + LLVector4a local_start; + LLVector4a asset_end = end; + LLVector4a local_end; + LLVector4a p; + + + for (auto& node : mNodes) + { + if (node.mMesh != INVALID_INDEX) + { + + bool newHit = false; + + // transform start and end to this node's local space + node.mAssetMatrixInv.affineTransform(start, local_start); + node.mAssetMatrixInv.affineTransform(asset_end, local_end); + + Mesh& mesh = mMeshes[node.mMesh]; + for (auto& primitive : mesh.mPrimitives) + { + const LLVolumeTriangle* tri = primitive.lineSegmentIntersect(local_start, local_end, &p, tex_coord, normal, tangent); + if (tri) + { + newHit = true; + local_end = p; + + // pointer math to get the node index + node_hit = &node - &mNodes[0]; + llassert(&mNodes[node_hit] == &node); + + //pointer math to get the primitive index + primitive_hit = &primitive - &mesh.mPrimitives[0]; + llassert(&mesh.mPrimitives[primitive_hit] == &primitive); + } + } + + if (newHit) + { + // shorten line segment on hit + node.mAssetMatrix.affineTransform(p, asset_end); + + // transform results back to asset space + if (intersection) + { + *intersection = asset_end; + } + + if (normal || tangent) + { + LLMatrix4 normalMatrix(node.mAssetMatrixInv.getF32ptr()); + + normalMatrix.transpose(); + + LLMatrix4a norm_mat; + norm_mat.loadu((F32*)normalMatrix.mMatrix); + + if (normal) + { + LLVector4a n = *normal; + F32 w = n.getF32ptr()[3]; + n.getF32ptr()[3] = 0.0f; + + norm_mat.affineTransform(n, *normal); + normal->getF32ptr()[3] = w; + } + + if (tangent) + { + LLVector4a t = *tangent; + F32 w = t.getF32ptr()[3]; + t.getF32ptr()[3] = 0.0f; + + norm_mat.affineTransform(t, *tangent); + tangent->getF32ptr()[3] = w; + } + } + } + } + } + + if (node_hit != -1) + { + if (primitive_hitp) + { + *primitive_hitp = primitive_hit; + } + } + + return node_hit; +} + + +void Node::makeMatrixValid() +{ + if (!mMatrixValid && mTRSValid) + { + glh::matrix4f rot; + mRotation.get_value(rot); + + glh::matrix4f trans; + trans.set_translate(mTranslation); + + glh::matrix4f sc; + sc.set_scale(mScale); + + glh::matrix4f t; + //t = sc * rot * trans; + //t = trans * rot * sc; // best so far, still wrong on negative scale + //t = sc * trans * rot; + t = trans * sc * rot; + + mMatrix.loadu(t.m); + mMatrixValid = true; + } +} + +void Node::makeTRSValid() +{ + if (!mTRSValid && mMatrixValid) + { + glh::matrix4f t(mMatrix.getF32ptr()); + + glh::vec4f p = t.get_column(3); + mTranslation.set_value(p.v[0], p.v[1], p.v[2]); + + mScale.set_value(t.get_column(0).length(), t.get_column(1).length(), t.get_column(2).length()); + mRotation.set_value(t); + mTRSValid = true; + } +} + +void Node::setRotation(const glh::quaternionf& q) +{ + makeTRSValid(); + mRotation = q; + mMatrixValid = false; +} + +void Node::setTranslation(const glh::vec3f& t) +{ + makeTRSValid(); + mTranslation = t; + mMatrixValid = false; +} + +void Node::setScale(const glh::vec3f& s) +{ + makeTRSValid(); + mScale = s; + mMatrixValid = false; +} + +const Node& Node::operator=(const tinygltf::Node& src) +{ + F32* dstMatrix = mMatrix.getF32ptr(); + + if (src.matrix.size() == 16) + { + // Node has a transformation matrix, just copy it + for (U32 i = 0; i < 16; ++i) + { + dstMatrix[i] = (F32)src.matrix[i]; + } + + mMatrixValid = true; + } + else if (!src.rotation.empty() || !src.translation.empty() || !src.scale.empty()) + { + // node has rotation/translation/scale, convert to matrix + if (src.rotation.size() == 4) + { + mRotation = glh::quaternionf((F32)src.rotation[0], (F32)src.rotation[1], (F32)src.rotation[2], (F32)src.rotation[3]); + } + + if (src.translation.size() == 3) + { + mTranslation = glh::vec3f((F32)src.translation[0], (F32)src.translation[1], (F32)src.translation[2]); + } + + glh::vec3f scale; + if (src.scale.size() == 3) + { + mScale = glh::vec3f((F32)src.scale[0], (F32)src.scale[1], (F32)src.scale[2]); + } + else + { + mScale.set_value(1.f, 1.f, 1.f); + } + + mTRSValid = true; + } + else + { + // node specifies no transformation, set to identity + mMatrix.setIdentity(); + } + + mChildren = src.children; + mMesh = src.mesh; + mSkin = src.skin; + mName = src.name; + + return *this; +} + +void Asset::render(bool opaque, bool rigged) +{ + if (rigged) + { + gGL.loadIdentity(); + } + + for (auto& node : mNodes) + { + if (node.mSkin != INVALID_INDEX) + { + if (rigged) + { + Skin& skin = mSkins[node.mSkin]; + skin.uploadMatrixPalette(*this, node); + } + else + { + //skip static nodes if we're rendering rigged + continue; + } + } + else if (rigged) + { + // skip rigged nodes if we're not rendering rigged + continue; + } + + + if (node.mMesh != INVALID_INDEX) + { + Mesh& mesh = mMeshes[node.mMesh]; + for (auto& primitive : mesh.mPrimitives) + { + if (!rigged) + { + gGL.loadMatrix((F32*)node.mRenderMatrix.mMatrix); + } + bool cull = true; + if (primitive.mMaterial != INVALID_INDEX) + { + Material& material = mMaterials[primitive.mMaterial]; + + if ((material.mMaterial->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_BLEND) == opaque) + { + continue; + } + material.mMaterial->bind(); + cull = !material.mMaterial->mDoubleSided; + } + else + { + if (!opaque) + { + continue; + } + LLFetchedGLTFMaterial::sDefault.bind(); + } + + LLGLDisable cull_face(!cull ? GL_CULL_FACE : 0); + + primitive.mVertexBuffer->setBuffer(); + if (primitive.mVertexBuffer->getNumIndices() > 0) + { + primitive.mVertexBuffer->draw(primitive.mGLMode, primitive.mVertexBuffer->getNumIndices(), 0); + } + else + { + primitive.mVertexBuffer->drawArrays(primitive.mGLMode, 0, primitive.mVertexBuffer->getNumVerts()); + } + + } + } + } +} + +void Asset::renderOpaque() +{ + render(true); +} + +void Asset::renderTransparent() +{ + render(false); +} + +void Asset::update() +{ + F32 dt = gFrameTimeSeconds - mLastUpdateTime; + + if (dt > 0.f) + { + mLastUpdateTime = gFrameTimeSeconds; + if (mAnimations.size() > 0) + { + static LLCachedControl anim_idx(gSavedSettings, "GLTFAnimationIndex", 0); + static LLCachedControl anim_speed(gSavedSettings, "GLTFAnimationSpeed", 1.f); + + U32 idx = llclamp(anim_idx(), 0U, mAnimations.size() - 1); + mAnimations[idx].update(*this, dt*anim_speed); + } + + updateTransforms(); + } +} + +void Asset::allocateGLResources(const std::string& filename, const tinygltf::Model& model) +{ + // do images first as materials may depend on images + for (auto& image : mImages) + { + image.allocateGLResources(); + } + + // do materials before meshes as meshes may depend on materials + for (U32 i = 0; i < mMaterials.size(); ++i) + { + mMaterials[i].allocateGLResources(*this); + LLTinyGLTFHelper::getMaterialFromModel(filename, model, i, mMaterials[i].mMaterial, mMaterials[i].mName, true); + } + + for (auto& mesh : mMeshes) + { + mesh.allocateGLResources(*this); + } + + for (auto& animation : mAnimations) + { + animation.allocateGLResources(*this); + } + + for (auto& skin : mSkins) + { + skin.allocateGLResources(*this); + } +} + +const Asset& Asset::operator=(const tinygltf::Model& src) +{ + mScenes.resize(src.scenes.size()); + for (U32 i = 0; i < src.scenes.size(); ++i) + { + mScenes[i] = src.scenes[i]; + } + + mNodes.resize(src.nodes.size()); + for (U32 i = 0; i < src.nodes.size(); ++i) + { + mNodes[i] = src.nodes[i]; + } + + mMeshes.resize(src.meshes.size()); + for (U32 i = 0; i < src.meshes.size(); ++i) + { + mMeshes[i] = src.meshes[i]; + } + + mMaterials.resize(src.materials.size()); + for (U32 i = 0; i < src.materials.size(); ++i) + { + mMaterials[i] = src.materials[i]; + } + + mBuffers.resize(src.buffers.size()); + for (U32 i = 0; i < src.buffers.size(); ++i) + { + mBuffers[i] = src.buffers[i]; + } + + mBufferViews.resize(src.bufferViews.size()); + for (U32 i = 0; i < src.bufferViews.size(); ++i) + { + mBufferViews[i] = src.bufferViews[i]; + } + + mTextures.resize(src.textures.size()); + for (U32 i = 0; i < src.textures.size(); ++i) + { + mTextures[i] = src.textures[i]; + } + + mSamplers.resize(src.samplers.size()); + for (U32 i = 0; i < src.samplers.size(); ++i) + { + mSamplers[i] = src.samplers[i]; + } + + mImages.resize(src.images.size()); + for (U32 i = 0; i < src.images.size(); ++i) + { + mImages[i] = src.images[i]; + } + + mAccessors.resize(src.accessors.size()); + for (U32 i = 0; i < src.accessors.size(); ++i) + { + mAccessors[i] = src.accessors[i]; + } + + mAnimations.resize(src.animations.size()); + for (U32 i = 0; i < src.animations.size(); ++i) + { + mAnimations[i] = src.animations[i]; + } + + mSkins.resize(src.skins.size()); + for (U32 i = 0; i < src.skins.size(); ++i) + { + mSkins[i] = src.skins[i]; + } + + return *this; +} + +const Material& Material::operator=(const tinygltf::Material& src) +{ + mName = src.name; + return *this; +} + +void Material::allocateGLResources(Asset& asset) +{ + // allocate material + mMaterial = new LLFetchedGLTFMaterial(); +} + +const Mesh& Mesh::operator=(const tinygltf::Mesh& src) +{ + mPrimitives.resize(src.primitives.size()); + for (U32 i = 0; i < src.primitives.size(); ++i) + { + mPrimitives[i] = src.primitives[i]; + } + + mWeights = src.weights; + mName = src.name; + + return *this; +} + +void Mesh::allocateGLResources(Asset& asset) +{ + for (auto& primitive : mPrimitives) + { + primitive.allocateGLResources(asset); + } +} + +const Scene& Scene::operator=(const tinygltf::Scene& src) +{ + mNodes = src.nodes; + mName = src.name; + + return *this; +} + +const Texture& Texture::operator=(const tinygltf::Texture& src) +{ + mSampler = src.sampler; + mSource = src.source; + mName = src.name; + + return *this; +} + +const Sampler& Sampler::operator=(const tinygltf::Sampler& src) +{ + mMagFilter = src.magFilter; + mMinFilter = src.minFilter; + mWrapS = src.wrapS; + mWrapT = src.wrapT; + mName = src.name; + + return *this; +} + +void Skin::uploadMatrixPalette(Asset& asset, Node& node) +{ + // prepare matrix palette + + // modelview will be applied by the shader, so assume matrix palette is in asset space + std::vector t_mp; + + t_mp.resize(mJoints.size()); + + for (U32 i = 0; i < mJoints.size(); ++i) + { + Node& joint = asset.mNodes[mJoints[i]]; + + //t_mp[i].set_value(joint.mRenderMatrix.getF32ptr()); + //t_mp[i] = t_mp[i] * mInverseBindMatricesData[i]; + + //t_mp[i].set_value(joint.mRenderMatrix.getF32ptr()); + //t_mp[i] = mInverseBindMatricesData[i] * t_mp[i]; + + t_mp[i].set_value(joint.mRenderMatrix.getF32ptr()); + t_mp[i] = t_mp[i] * mInverseBindMatricesData[i]; + + } + + std::vector glmp; + + glmp.resize(mJoints.size() * 12); + + F32* mp = glmp.data(); + + for (U32 i = 0; i < mJoints.size(); ++i) + { + F32* m = (F32*)t_mp[i].m; + + U32 idx = i * 12; + + mp[idx + 0] = m[0]; + mp[idx + 1] = m[1]; + mp[idx + 2] = m[2]; + mp[idx + 3] = m[12]; + + mp[idx + 4] = m[4]; + mp[idx + 5] = m[5]; + mp[idx + 6] = m[6]; + mp[idx + 7] = m[13]; + + mp[idx + 8] = m[8]; + mp[idx + 9] = m[9]; + mp[idx + 10] = m[10]; + mp[idx + 11] = m[14]; + } + + LLGLSLShader::sCurBoundShaderPtr->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX, + mJoints.size(), + GL_FALSE, + (GLfloat*)glmp.data()); +} + diff --git a/indra/newview/gltf/asset.h b/indra/newview/gltf/asset.h new file mode 100644 index 0000000000..5ceac74a8a --- /dev/null +++ b/indra/newview/gltf/asset.h @@ -0,0 +1,264 @@ +#pragma once + +/** + * @file asset.h + * @brief LL GLTF Implementation + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llvertexbuffer.h" +#include "llvolumeoctree.h" +#include "../lltinygltfhelper.h" +#include "accessor.h" +#include "primitive.h" +#include "animation.h" + +extern F32SecondsImplicit gFrameTimeSeconds; + +// LL GLTF Implementation +namespace LL +{ + namespace GLTF + { + class Asset; + + class Material + { + public: + // use LLFetchedGLTFMaterial for now, but eventually we'll want to use + // a more flexible GLTF material implementation instead of the fixed packing + // version we use for sharable GLTF material assets + LLPointer mMaterial; + std::string mName; + + const Material& operator=(const tinygltf::Material& src); + + void allocateGLResources(Asset& asset); + }; + + class Mesh + { + public: + std::vector mPrimitives; + std::vector mWeights; + std::string mName; + + const Mesh& operator=(const tinygltf::Mesh& src); + + void allocateGLResources(Asset& asset); + }; + + class Node + { + public: + LLMatrix4a mMatrix; //local transform + LLMatrix4a mRenderMatrix; //transform for rendering + LLMatrix4a mAssetMatrix; //transform from local to asset space + LLMatrix4a mAssetMatrixInv; //transform from asset to local space + + glh::vec3f mTranslation; + glh::quaternionf mRotation; + glh::vec3f mScale; + + // if true, mMatrix is valid and up to date + bool mMatrixValid = false; + + // if true, translation/rotation/scale are valid and up to date + bool mTRSValid = false; + + bool mNeedsApplyMatrix = false; + + std::vector mChildren; + S32 mParent = INVALID_INDEX; + + S32 mMesh = INVALID_INDEX; + S32 mSkin = INVALID_INDEX; + + std::string mName; + + const Node& operator=(const tinygltf::Node& src); + + // Set mRenderMatrix to a transform that can be used for the current render pass + // modelview -- parent's render matrix + void updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview); + + // update mAssetMatrix and mAssetMatrixInv + void updateTransforms(Asset& asset, const LLMatrix4a& parentMatrix); + + // ensure mMatrix is valid -- if mMatrixValid is false and mTRSValid is true, will update mMatrix to match Translation/Rotation/Scale + void makeMatrixValid(); + + // ensure Translation/Rotation/Scale are valid -- if mTRSValid is false and mMatrixValid is true, will update Translation/Rotation/Scale to match mMatrix + void makeTRSValid(); + + // Set rotation of this node + // SIDE EFFECT: invalidates mMatrix + void setRotation(const glh::quaternionf& rotation); + + // Set translation of this node + // SIDE EFFECT: invalidates mMatrix + void setTranslation(const glh::vec3f& translation); + + // Set scale of this node + // SIDE EFFECT: invalidates mMatrix + void setScale(const glh::vec3f& scale); + }; + + class Skin + { + public: + S32 mInverseBindMatrices = INVALID_INDEX; + S32 mSkeleton = INVALID_INDEX; + std::vector mJoints; + std::string mName; + std::vector mInverseBindMatricesData; + + void allocateGLResources(Asset& asset); + void uploadMatrixPalette(Asset& asset, Node& node); + + const Skin& operator=(const tinygltf::Skin& src); + }; + + class Scene + { + public: + std::vector mNodes; + std::string mName; + + const Scene& operator=(const tinygltf::Scene& src); + + void updateTransforms(Asset& asset); + void updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview); + }; + + class Texture + { + public: + S32 mSampler = INVALID_INDEX; + S32 mSource = INVALID_INDEX; + std::string mName; + + const Texture& operator=(const tinygltf::Texture& src); + }; + + class Sampler + { + public: + S32 mMagFilter; + S32 mMinFilter; + S32 mWrapS; + S32 mWrapT; + std::string mName; + + const Sampler& operator=(const tinygltf::Sampler& src); + }; + + class Image + { + public: + std::string mName; + std::string mUri; + std::string mMimeType; + std::vector mData; + S32 mWidth; + S32 mHeight; + S32 mComponent; + S32 mBits; + LLPointer mTexture; + + const Image& operator=(const tinygltf::Image& src) + { + mName = src.name; + mUri = src.uri; + mMimeType = src.mimeType; + mData = src.image; + mWidth = src.width; + mHeight = src.height; + mComponent = src.component; + mBits = src.bits; + + return *this; + } + + void allocateGLResources() + { + // allocate texture + + } + }; + + // C++ representation of a GLTF Asset + class Asset : public LLRefCount + { + public: + std::vector mScenes; + std::vector mNodes; + std::vector mMeshes; + std::vector mMaterials; + std::vector mBuffers; + std::vector mBufferViews; + std::vector mTextures; + std::vector mSamplers; + std::vector mImages; + std::vector mAccessors; + std::vector mAnimations; + std::vector mSkins; + + // the last time update() was called according to gFrameTimeSeconds + F32 mLastUpdateTime = gFrameTimeSeconds; + + // prepare the asset for rendering + void allocateGLResources(const std::string& filename, const tinygltf::Model& model); + + // Called periodically (typically once per frame) + // Any ongoing work (such as animations) should be handled here + // NOT guaranteed to be called every frame + // MAY be called more than once per frame + // Upon return, all Node Matrix transforms should be up to date + void update(); + + // update asset-to-node and node-to-asset transforms + void updateTransforms(); + + // update node render transforms + void updateRenderTransforms(const LLMatrix4a& modelview); + + void render(bool opaque, bool rigged = false); + void renderOpaque(); + void renderTransparent(); + + // return the index of the node that the line segment intersects with, or -1 if no hit + // input and output values must be in this asset's local coordinate frame + S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, + LLVector4a* intersection = nullptr, // return the intersection point + LLVector2* tex_coord = nullptr, // return the texture coordinates of the intersection point + LLVector4a* normal = nullptr, // return the surface normal at the intersection point + LLVector4a* tangent = nullptr, // return the surface tangent at the intersection point + S32* primitive_hitp = nullptr // return the index of the primitive that was hit + ); + + const Asset& operator=(const tinygltf::Model& src); + + }; + } +} diff --git a/indra/newview/gltf/buffer_util.h b/indra/newview/gltf/buffer_util.h new file mode 100644 index 0000000000..1440e4c6f8 --- /dev/null +++ b/indra/newview/gltf/buffer_util.h @@ -0,0 +1,415 @@ +#pragma once + +/** + * @file buffer_util.inl + * @brief LL GLTF Implementation + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +// inline template implementations for copying data out of GLTF buffers +// DO NOT include from header files to avoid the need to rebuild the whole project +// whenever we add support for more types + +#ifdef _MSC_VER +#define LL_FUNCSIG __FUNCSIG__ +#else +#define LL_FUNCSIG __PRETTY_FUNCTION__ +#endif + +namespace LL +{ + namespace GLTF + { + // copy one Scalar from src to dst + template + static void copyScalar(S* src, T& dst) + { + LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; + } + + // copy one vec2 from src to dst + template + static void copyVec2(S* src, T& dst) + { + LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; + } + + // copy one vec3 from src to dst + template + static void copyVec3(S* src, T& dst) + { + LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; + } + + // copy one vec4 from src to dst + template + static void copyVec4(S* src, T& dst) + { + LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; + } + + // copy one vec2 from src to dst + template + static void copyMat2(S* src, T& dst) + { + LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; + } + + // copy one vec3 from src to dst + template + static void copyMat3(S* src, T& dst) + { + LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; + } + + // copy one vec4 from src to dst + template + static void copyMat4(S* src, T& dst) + { + LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; + } + + //========================================================================================================= + // concrete implementations for different types of source and destination + //========================================================================================================= + +// suppress unused function warning -- clang complains here but these specializations are definitely used +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif + +// make gcc ignore this as well +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic push +#endif +// + + template<> + void copyScalar(F32* src, F32& dst) + { + dst = *src; + } + + template<> + void copyScalar(U32* src, U32& dst) + { + dst = *src; + } + + template<> + void copyScalar(U32* src, U16& dst) + { + dst = *src; + } + + template<> + void copyScalar(U16* src, U16& dst) + { + dst = *src; + } + + template<> + void copyScalar(U16* src, U32& dst) + { + dst = *src; + } + + template<> + void copyScalar(U8* src, U16& dst) + { + dst = *src; + } + + template<> + void copyScalar(U8* src, U32& dst) + { + dst = *src; + } + + template<> + void copyVec2(F32* src, LLVector2& dst) + { + dst.set(src[0], src[1]); + } + + template<> + void copyVec3(F32* src, glh::vec3f& dst) + { + dst.set_value(src[0], src[1], src[2]); + } + + template<> + void copyVec3(F32* src, LLVector4a& dst) + { + dst.load3(src); + } + + template<> + void copyVec3(U16* src, LLColor4U& dst) + { + dst.set(src[0], src[1], src[2], 255); + } + + template<> + void copyVec4(U8* src, LLColor4U& dst) + { + dst.set(src[0], src[1], src[2], src[3]); + } + + template<> + void copyVec4(U16* src, LLColor4U& dst) + { + dst.set(src[0], src[1], src[2], src[3]); + } + + template<> + void copyVec4(F32* src, LLColor4U& dst) + { + dst.set(src[0]*255, src[1]*255, src[2]*255, src[3]*255); + } + + template<> + void copyVec4(F32* src, LLVector4a& dst) + { + dst.loadua(src); + } + + template<> + void copyVec4(U16* src, LLVector4a& dst) + { + dst.set(src[0], src[1], src[2], src[3]); + } + + template<> + void copyVec4(U8* src, LLVector4a& dst) + { + dst.set(src[0], src[1], src[2], src[3]); + } + + template<> + void copyVec4(F32* src, glh::quaternionf& dst) + { + dst.set_value(src); + } + + template<> + void copyMat4(F32* src, glh::matrix4f& dst) + { + dst.set_value(src); + } + +// make gcc ignore this as well +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +// + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + + //========================================================================================================= + + // copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy + template + static void copyScalar(S* src, LLStrider dst, S32 stride, S32 count) + { + for (S32 i = 0; i < count; ++i) + { + copyScalar(src, *dst); + dst++; + src = (S*)((U8*)src + stride); + } + } + + // copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy + template + static void copyVec2(S* src, LLStrider dst, S32 stride, S32 count) + { + for (S32 i = 0; i < count; ++i) + { + copyVec2(src, *dst); + dst++; + src = (S*)((U8*)src + stride); + } + } + + // copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy + template + static void copyVec3(S* src, LLStrider dst, S32 stride, S32 count) + { + for (S32 i = 0; i < count; ++i) + { + copyVec3(src, *dst); + dst++; + src = (S*)((U8*)src + stride); + } + } + + // copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy + template + static void copyVec4(S* src, LLStrider dst, S32 stride, S32 count) + { + for (S32 i = 0; i < count; ++i) + { + copyVec4(src, *dst); + dst++; + src = (S*)((U8*)src + stride); + } + } + + // copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy + template + static void copyMat2(S* src, LLStrider dst, S32 stride, S32 count) + { + for (S32 i = 0; i < count; ++i) + { + copyMat2(src, *dst); + dst++; + src = (S*)((U8*)src + stride); + } + } + + // copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy + template + static void copyMat3(S* src, LLStrider dst, S32 stride, S32 count) + { + for (S32 i = 0; i < count; ++i) + { + copyMat3(src, *dst); + dst++; + src = (S*)((U8*)src + stride); + } + } + + // copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy + template + static void copyMat4(S* src, LLStrider dst, S32 stride, S32 count) + { + for (S32 i = 0; i < count; ++i) + { + copyMat4(src, *dst); + dst++; + src = (S*)((U8*)src + stride); + } + } + + template + static void copy(Asset& asset, Accessor& accessor, const S* src, LLStrider& dst, S32 byteStride) + { + if (accessor.mType == (S32)Accessor::Type::SCALAR) + { + S32 stride = byteStride == 0 ? sizeof(S) * 1 : byteStride; + copyScalar((S*)src, dst, stride, accessor.mCount); + } + else if (accessor.mType == (S32)Accessor::Type::VEC2) + { + S32 stride = byteStride == 0 ? sizeof(S) * 2 : byteStride; + copyVec2((S*)src, dst, stride, accessor.mCount); + } + else if (accessor.mType == (S32)Accessor::Type::VEC3) + { + S32 stride = byteStride == 0 ? sizeof(S) * 3 : byteStride; + copyVec3((S*)src, dst, stride, accessor.mCount); + } + else if (accessor.mType == (S32)Accessor::Type::VEC4) + { + S32 stride = byteStride == 0 ? sizeof(S) * 4 : byteStride; + copyVec4((S*)src, dst, stride, accessor.mCount); + } + else if (accessor.mType == (S32)Accessor::Type::MAT2) + { + S32 stride = byteStride == 0 ? sizeof(S) * 4 : byteStride; + copyMat2((S*)src, dst, stride, accessor.mCount); + } + else if (accessor.mType == (S32)Accessor::Type::MAT3) + { + S32 stride = byteStride == 0 ? sizeof(S) * 9 : byteStride; + copyMat3((S*)src, dst, stride, accessor.mCount); + } + else if (accessor.mType == (S32)Accessor::Type::MAT4) + { + S32 stride = byteStride == 0 ? sizeof(S) * 16 : byteStride; + copyMat4((S*)src, dst, stride, accessor.mCount); + } + else + { + LL_ERRS("GLTF") << "Unsupported accessor type" << LL_ENDL; + } + } + + // copy data from accessor to strider + template + static void copy(Asset& asset, Accessor& accessor, LLStrider& dst) + { + const BufferView& bufferView = asset.mBufferViews[accessor.mBufferView]; + const Buffer& buffer = asset.mBuffers[bufferView.mBuffer]; + const U8* src = buffer.mData.data() + bufferView.mByteOffset + accessor.mByteOffset; + + if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_FLOAT) + { + LL::GLTF::copy(asset, accessor, (const F32*)src, dst, bufferView.mByteStride); + } + else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) + { + LL::GLTF::copy(asset, accessor, (const U16*)src, dst, bufferView.mByteStride); + } + else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) + { + LL::GLTF::copy(asset, accessor, (const U32*)src, dst, bufferView.mByteStride); + } + else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) + { + LL::GLTF::copy(asset, accessor, (const U8*)src, dst, bufferView.mByteStride); + } + else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_SHORT) + { + LL::GLTF::copy(asset, accessor, (const S16*)src, dst, bufferView.mByteStride); + } + else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_BYTE) + { + LL::GLTF::copy(asset, accessor, (const S8*)src, dst, bufferView.mByteStride); + } + else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_DOUBLE) + { + LL::GLTF::copy(asset, accessor, (const F64*)src, dst, bufferView.mByteStride); + } + else + { + LL_ERRS("GLTF") << "Unsupported component type" << LL_ENDL; + } + } + + // copy data from accessor to vector + template + static void copy(Asset& asset, Accessor& accessor, std::vector& dst) + { + dst.resize(accessor.mCount); + LLStrider strider = dst.data(); + copy(asset, accessor, strider); + } + } +} + diff --git a/indra/newview/gltf/primitive.cpp b/indra/newview/gltf/primitive.cpp new file mode 100644 index 0000000000..b57a0af18d --- /dev/null +++ b/indra/newview/gltf/primitive.cpp @@ -0,0 +1,400 @@ +/** + * @file primitive.cpp + * @brief LL GLTF Implementation + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "../llviewerprecompiledheaders.h" + +#include "asset.h" +#include "buffer_util.h" + +#include "../lltinygltfhelper.h" + +using namespace LL::GLTF; + +void Primitive::allocateGLResources(Asset& asset) +{ + // allocate vertex buffer + // We diverge from the intent of the GLTF format here to work with our existing render pipeline + // GLTF wants us to copy the buffer views into GPU storage as is and build render commands that source that data. + // For our engine, though, it's better to rearrange the buffers at load time into a layout that's more consistent. + // The GLTF native approach undoubtedly works well if you can count on VAOs, but VAOs perform much worse with our scenes. + + // load vertex data + for (auto& it : mAttributes) + { + const std::string& attribName = it.first; + Accessor& accessor = asset.mAccessors[it.second]; + + // load vertex data + if (attribName == "POSITION") + { + copy(asset, accessor, mPositions); + } + else if (attribName == "NORMAL") + { + copy(asset, accessor, mNormals); + } + else if (attribName == "TANGENT") + { + copy(asset, accessor, mTangents); + } + else if (attribName == "COLOR_0") + { + copy(asset, accessor, mColors); + } + else if (attribName == "TEXCOORD_0") + { + copy(asset, accessor, mTexCoords); + } + else if (attribName == "JOINTS_0") + { + copy(asset, accessor, mJoints); + } + else if (attribName == "WEIGHTS_0") + { + copy(asset, accessor, mWeights); + } + } + + // copy index buffer + if (mIndices != INVALID_INDEX) + { + Accessor& accessor = asset.mAccessors[mIndices]; + copy(asset, accessor, mIndexArray); + } + + U32 mask = ATTRIBUTE_MASK; + + if (!mWeights.empty()) + { + mask |= LLVertexBuffer::MAP_WEIGHT4; + } + + mVertexBuffer = new LLVertexBuffer(mask); + mVertexBuffer->allocateBuffer(mPositions.size(), mIndexArray.size()*2); // double the size of the index buffer for 32-bit indices + + mVertexBuffer->setBuffer(); + mVertexBuffer->setPositionData(mPositions.data()); + + if (!mIndexArray.empty()) + { + mVertexBuffer->setIndexData(mIndexArray.data()); + } + + if (mTexCoords.empty()) + { + mTexCoords.resize(mPositions.size()); + } + + // flip texcoord y, upload, then flip back (keep the off-spec data in vram only) + for (auto& tc : mTexCoords) + { + tc[1] = 1.f - tc[1]; + } + mVertexBuffer->setTexCoordData(mTexCoords.data()); + + for (auto& tc : mTexCoords) + { + tc[1] = 1.f - tc[1]; + } + + if (mColors.empty()) + { + mColors.resize(mPositions.size(), LLColor4U::white); + } + + // bake material basecolor into color array + if (mMaterial != INVALID_INDEX) + { + const Material& material = asset.mMaterials[mMaterial]; + LLColor4 baseColor = material.mMaterial->mBaseColor; + for (auto& dst : mColors) + { + dst = LLColor4U(baseColor * LLColor4(dst)); + } + } + + mVertexBuffer->setColorData(mColors.data()); + + if (mNormals.empty()) + { + mNormals.resize(mPositions.size(), LLVector4a(0, 0, 1, 0)); + } + + mVertexBuffer->setNormalData(mNormals.data()); + + if (mTangents.empty()) + { + // TODO: generate tangents if needed + mTangents.resize(mPositions.size(), LLVector4a(1, 0, 0, 1)); + } + + mVertexBuffer->setTangentData(mTangents.data()); + + if (!mWeights.empty()) + { + std::vector weight_data; + weight_data.resize(mWeights.size()); + + F32 max_weight = 1.f - FLT_EPSILON*100.f; + LLVector4a maxw(max_weight, max_weight, max_weight, max_weight); + for (U32 i = 0; i < mWeights.size(); ++i) + { + LLVector4a& w = weight_data[i]; + w.setMin(mWeights[i], maxw); + w.add(mJoints[i]); + }; + + mVertexBuffer->setWeight4Data(weight_data.data()); + } + + createOctree(); + + mVertexBuffer->unbind(); +} + +void initOctreeTriangle(LLVolumeTriangle* tri, F32 scaler, S32 i0, S32 i1, S32 i2, const LLVector4a& v0, const LLVector4a& v1, const LLVector4a& v2) +{ + //store pointers to vertex data + tri->mV[0] = &v0; + tri->mV[1] = &v1; + tri->mV[2] = &v2; + + //store indices + tri->mIndex[0] = i0; + tri->mIndex[1] = i1; + tri->mIndex[2] = i2; + + //get minimum point + LLVector4a min = v0; + min.setMin(min, v1); + min.setMin(min, v2); + + //get maximum point + LLVector4a max = v0; + max.setMax(max, v1); + max.setMax(max, v2); + + //compute center + LLVector4a center; + center.setAdd(min, max); + center.mul(0.5f); + + tri->mPositionGroup = center; + + //compute "radius" + LLVector4a size; + size.setSub(max, min); + + tri->mRadius = size.getLength3().getF32() * scaler; +} + +void Primitive::createOctree() +{ + // create octree + mOctree = new LLVolumeOctree(); + + F32 scaler = 0.25f; + + if (mMode == TINYGLTF_MODE_TRIANGLES) + { + const U32 num_triangles = mVertexBuffer->getNumIndices() / 3; + // Initialize all the triangles we need + mOctreeTriangles.resize(num_triangles); + + for (U32 triangle_index = 0; triangle_index < num_triangles; ++triangle_index) + { //for each triangle + const U32 index = triangle_index * 3; + LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index]; + S32 i0 = mIndexArray[index]; + S32 i1 = mIndexArray[index + 1]; + S32 i2 = mIndexArray[index + 2]; + + const LLVector4a& v0 = mPositions[i0]; + const LLVector4a& v1 = mPositions[i1]; + const LLVector4a& v2 = mPositions[i2]; + + initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2); + + //insert + mOctree->insert(tri); + } + } + else if (mMode == TINYGLTF_MODE_TRIANGLE_STRIP) + { + const U32 num_triangles = mVertexBuffer->getNumIndices() - 2; + // Initialize all the triangles we need + mOctreeTriangles.resize(num_triangles); + + for (U32 triangle_index = 0; triangle_index < num_triangles; ++triangle_index) + { //for each triangle + const U32 index = triangle_index + 2; + LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index]; + S32 i0 = mIndexArray[index]; + S32 i1 = mIndexArray[index - 1]; + S32 i2 = mIndexArray[index - 2]; + + const LLVector4a& v0 = mPositions[i0]; + const LLVector4a& v1 = mPositions[i1]; + const LLVector4a& v2 = mPositions[i2]; + + initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2); + + //insert + mOctree->insert(tri); + } + } + else if (mMode == TINYGLTF_MODE_TRIANGLE_FAN) + { + const U32 num_triangles = mVertexBuffer->getNumIndices() - 2; + // Initialize all the triangles we need + mOctreeTriangles.resize(num_triangles); + + for (U32 triangle_index = 0; triangle_index < num_triangles; ++triangle_index) + { //for each triangle + const U32 index = triangle_index + 2; + LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index]; + S32 i0 = mIndexArray[0]; + S32 i1 = mIndexArray[index - 1]; + S32 i2 = mIndexArray[index - 2]; + + const LLVector4a& v0 = mPositions[i0]; + const LLVector4a& v1 = mPositions[i1]; + const LLVector4a& v2 = mPositions[i2]; + + initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2); + + //insert + mOctree->insert(tri); + } + } + else if (mMode == TINYGLTF_MODE_POINTS || + mMode == TINYGLTF_MODE_LINE || + mMode == TINYGLTF_MODE_LINE_LOOP || + mMode == TINYGLTF_MODE_LINE_STRIP) + { + // nothing to do, no volume... maybe add some collision geometry around these primitive types? + } + + else + { + LL_ERRS() << "Unsupported Primitive mode" << LL_ENDL; + } + + //remove unneeded octree layers + while (!mOctree->balance()) {} + + //calculate AABB for each node + LLVolumeOctreeRebound rebound; + rebound.traverse(mOctree); +} + +const LLVolumeTriangle* Primitive::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, + LLVector4a* intersection, LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent_out) +{ + if (mOctree.isNull()) + { + return nullptr; + } + + LLVector4a dir; + dir.setSub(end, start); + + F32 closest_t = 2.f; // must be larger than 1 + + //create a proxy LLVolumeFace for the raycast + LLVolumeFace face; + face.mPositions = mPositions.data(); + face.mTexCoords = mTexCoords.data(); + face.mNormals = mNormals.data(); + face.mTangents = mTangents.data(); + face.mIndices = nullptr; // unreferenced + + face.mNumIndices = mIndexArray.size(); + face.mNumVertices = mPositions.size(); + + LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, tangent_out); + intersect.traverse(mOctree); + + // null out proxy data so it doesn't get freed + face.mPositions = face.mNormals = face.mTangents = nullptr; + face.mIndices = nullptr; + face.mTexCoords = nullptr; + + return intersect.mHitTriangle; +} + +Primitive::~Primitive() +{ + mOctree = nullptr; +} + + +const Primitive& Primitive::operator=(const tinygltf::Primitive& src) +{ + // load material + mMaterial = src.material; + + // load mode + mMode = src.mode; + + // load indices + mIndices = src.indices; + + // load attributes + for (auto& it : src.attributes) + { + mAttributes[it.first] = it.second; + } + + switch (mMode) + { + case TINYGLTF_MODE_POINTS: + mGLMode = LLRender::POINTS; + break; + case TINYGLTF_MODE_LINE: + mGLMode = LLRender::LINES; + break; + case TINYGLTF_MODE_LINE_LOOP: + mGLMode = LLRender::LINE_LOOP; + break; + case TINYGLTF_MODE_LINE_STRIP: + mGLMode = LLRender::LINE_STRIP; + break; + case TINYGLTF_MODE_TRIANGLES: + mGLMode = LLRender::TRIANGLES; + break; + case TINYGLTF_MODE_TRIANGLE_STRIP: + mGLMode = LLRender::TRIANGLE_STRIP; + break; + case TINYGLTF_MODE_TRIANGLE_FAN: + mGLMode = LLRender::TRIANGLE_FAN; + break; + default: + mGLMode = GL_TRIANGLES; + } + + return *this; +} diff --git a/indra/newview/gltf/primitive.h b/indra/newview/gltf/primitive.h new file mode 100644 index 0000000000..07e8e7deb2 --- /dev/null +++ b/indra/newview/gltf/primitive.h @@ -0,0 +1,93 @@ +#pragma once + +/** + * @file primitive.h + * @brief LL GLTF Implementation + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llvertexbuffer.h" +#include "llvolumeoctree.h" + +// LL GLTF Implementation +namespace LL +{ + namespace GLTF + { + class Asset; + + constexpr U32 ATTRIBUTE_MASK = + LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_NORMAL | + LLVertexBuffer::MAP_TEXCOORD0 | + LLVertexBuffer::MAP_TANGENT | + LLVertexBuffer::MAP_COLOR; + + class Primitive + { + public: + ~Primitive(); + + // GPU copy of mesh data + LLPointer mVertexBuffer; + + // CPU copy of mesh data + std::vector mTexCoords; + std::vector mNormals; + std::vector mTangents; + std::vector mPositions; + std::vector mJoints; + std::vector mWeights; + std::vector mColors; + std::vector mIndexArray; + + // raycast acceleration structure + LLPointer mOctree; + std::vector mOctreeTriangles; + + S32 mMaterial = -1; + U32 mMode = TINYGLTF_MODE_TRIANGLES; // default to triangles + U32 mGLMode = LLRender::TRIANGLES; + S32 mIndices = -1; + std::unordered_map mAttributes; + + // create octree based on vertex buffer + // must be called before buffer is unmapped and after buffer is populated with good data + void createOctree(); + + //get the LLVolumeTriangle that intersects with the given line segment at the point + //closest to start. Moves end to the point of intersection. Returns nullptr if no intersection. + //Line segment must be in the same coordinate frame as this Primitive + const LLVolumeTriangle* lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, + LLVector4a* intersection = NULL, // return the intersection point + LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point + LLVector4a* normal = NULL, // return the surface normal at the intersection point + LLVector4a* tangent = NULL // return the surface tangent at the intersection point + ); + + const Primitive& operator=(const tinygltf::Primitive& src); + + void allocateGLResources(Asset& asset); + }; + } +} diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp new file mode 100644 index 0000000000..655f7d6568 --- /dev/null +++ b/indra/newview/gltfscenemanager.cpp @@ -0,0 +1,563 @@ +/** + * @file gltfscenemanager.cpp + * @brief Builds menus out of items. + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "gltfscenemanager.h" +#include "llviewermenufile.h" +#include "llappviewer.h" +#include "lltinygltfhelper.h" +#include "llvertexbuffer.h" +#include "llselectmgr.h" +#include "llagent.h" +#include "llnotificationsutil.h" +#include "llvoavatarself.h" +#include "llvolumeoctree.h" +#include "gltf/asset.h" +#include "pipeline.h" +#include "llviewershadermgr.h" + + +using namespace LL; + +// temporary location of LL GLTF Implementation +using namespace LL::GLTF; + +void GLTFSceneManager::load() +{ + LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject(); + + if (obj) + { + // Load a scene from disk + LLFilePickerReplyThread::startPicker( + [](const std::vector& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter) + { + if (LLAppViewer::instance()->quitRequested()) + { + return; + } + if (filenames.size() > 0) + { + GLTFSceneManager::instance().load(filenames[0]); + } + }, + LLFilePicker::FFLOAD_GLTF, + true); + } + else + { + LLNotificationsUtil::add("GLTFPreviewSelection"); + } +} + +void GLTFSceneManager::load(const std::string& filename) +{ + tinygltf::Model model; + LLTinyGLTFHelper::loadModel(filename, model); + + LLPointer asset = new Asset(); + *asset = model; + + gDebugProgram.bind(); // bind a shader to satisfy LLVertexBuffer assertions + asset->allocateGLResources(filename, model); + asset->updateTransforms(); + + // hang the asset off the currently selected object, or off of the avatar if no object is selected + LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject(); + + if (obj) + { // assign to self avatar + obj->mGLTFAsset = asset; + + if (std::find(mObjects.begin(), mObjects.end(), obj) == mObjects.end()) + { + mObjects.push_back(obj); + } + } +} + +GLTFSceneManager::~GLTFSceneManager() +{ + mObjects.clear(); +} + +void GLTFSceneManager::renderOpaque() +{ + render(true); +} + +void GLTFSceneManager::renderAlpha() +{ + render(false); +} + +void GLTFSceneManager::update() +{ + for (U32 i = 0; i < mObjects.size(); ++i) + { + if (mObjects[i]->isDead() || mObjects[i]->mGLTFAsset == nullptr) + { + mObjects.erase(mObjects.begin() + i); + --i; + continue; + } + + Asset* asset = mObjects[i]->mGLTFAsset; + + asset->update(); + + } +} + +void GLTFSceneManager::render(bool opaque, bool rigged) +{ + // for debugging, just render the whole scene as opaque + // by traversing the whole scenegraph + // Assumes camera transform is already set and + // appropriate shader is already bound + + gGL.matrixMode(LLRender::MM_MODELVIEW); + + for (U32 i = 0; i < mObjects.size(); ++i) + { + if (mObjects[i]->isDead() || mObjects[i]->mGLTFAsset == nullptr) + { + mObjects.erase(mObjects.begin() + i); + --i; + continue; + } + + Asset* asset = mObjects[i]->mGLTFAsset; + + gGL.pushMatrix(); + + LLMatrix4a mat = mObjects[i]->getGLTFAssetToAgentTransform(); + + LLMatrix4a modelview; + modelview.loadu(gGLModelView); + + matMul(mat, modelview, modelview); + + asset->updateRenderTransforms(modelview); + asset->render(opaque, rigged); + + gGL.popMatrix(); + } +} + +LLMatrix4a inverse(const LLMatrix4a& mat) +{ + glh::matrix4f m((F32*)mat.mMatrix); + m = m.inverse(); + LLMatrix4a ret; + ret.loadu(m.m); + return ret; +} + +bool GLTFSceneManager::lineSegmentIntersect(LLVOVolume* obj, Asset* asset, const LLVector4a& start, const LLVector4a& end, S32 face, bool pick_transparent, bool pick_rigged, bool pick_unselectable, S32* node_hit, S32* primitive_hit, + LLVector4a* intersection, LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent) +{ + // line segment intersection test + // start and end should be in agent space + // volume space and asset space should be the same coordinate frame + // results should be transformed back to agent space + + bool ret = false; + + LLVector4a local_start; + LLVector4a local_end; + + LLMatrix4a asset_to_agent = obj->getGLTFAssetToAgentTransform(); + LLMatrix4a agent_to_asset = inverse(asset_to_agent); + + agent_to_asset.affineTransform(start, local_start); + agent_to_asset.affineTransform(end, local_end); + + LLVector4a p; + LLVector4a n; + LLVector2 tc; + LLVector4a tn; + + if (intersection != NULL) + { + p = *intersection; + } + + if (tex_coord != NULL) + { + tc = *tex_coord; + } + + if (normal != NULL) + { + n = *normal; + } + + if (tangent != NULL) + { + tn = *tangent; + } + + S32 hit_node_index = asset->lineSegmentIntersect(local_start, local_end, &p, &tc, &n, &tn, primitive_hit); + + if (hit_node_index >= 0) + { + local_end = p; + if (node_hit != NULL) + { + *node_hit = hit_node_index; + } + + if (intersection != NULL) + { + asset_to_agent.affineTransform(p, *intersection); + } + + if (normal != NULL) + { + LLVector3 v_n(n.getF32ptr()); + normal->load3(obj->volumeDirectionToAgent(v_n).mV); + (*normal).normalize3fast(); + } + + if (tangent != NULL) + { + LLVector3 v_tn(tn.getF32ptr()); + + LLVector4a trans_tangent; + trans_tangent.load3(obj->volumeDirectionToAgent(v_tn).mV); + + LLVector4Logical mask; + mask.clear(); + mask.setElement<3>(); + + tangent->setSelectWithMask(mask, tn, trans_tangent); + (*tangent).normalize3fast(); + } + + if (tex_coord != NULL) + { + *tex_coord = tc; + } + + ret = true; + } + + return ret; +} + +LLDrawable* GLTFSceneManager::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, + bool pick_transparent, + bool pick_rigged, + bool pick_unselectable, + bool pick_reflection_probe, + S32* node_hit, // return the index of the node that was hit + S32* primitive_hit, // return the index of the primitive that was hit + LLVector4a* intersection, // return the intersection point + LLVector2* tex_coord, // return the texture coordinates of the intersection point + LLVector4a* normal, // return the surface normal at the intersection point + LLVector4a* tangent) // return the surface tangent at the intersection point +{ + LLDrawable* drawable = nullptr; + + LLVector4a local_end = end; + LLVector4a position; + + for (U32 i = 0; i < mObjects.size(); ++i) + { + if (mObjects[i]->isDead() || mObjects[i]->mGLTFAsset == nullptr || !mObjects[i]->getVolume()) + { + mObjects.erase(mObjects.begin() + i); + --i; + continue; + } + + // temporary debug -- always double check objects that have GLTF scenes hanging off of them even if the ray doesn't intersect the object bounds + if (lineSegmentIntersect((LLVOVolume*) mObjects[i].get(), mObjects[i]->mGLTFAsset, start, local_end, -1, pick_transparent, pick_rigged, pick_unselectable, node_hit, primitive_hit, &position, tex_coord, normal, tangent)) + { + local_end = position; + if (intersection) + { + *intersection = position; + } + drawable = mObjects[i]->mDrawable; + } + } + + return drawable; +} + +void drawBoxOutline(const LLVector4a& pos, const LLVector4a& size); + +extern LLVector4a gDebugRaycastStart; +extern LLVector4a gDebugRaycastEnd; + +void renderOctreeRaycast(const LLVector4a& start, const LLVector4a& end, const LLVolumeOctree* octree); + +void renderAssetDebug(LLViewerObject* obj, Asset* asset) +{ + // render debug + // assumes appropriate shader is already bound + // assumes modelview matrix is already set + + gGL.pushMatrix(); + + // get raycast in asset space + LLMatrix4a agent_to_asset = obj->getAgentToGLTFAssetTransform(); + + LLVector4a start; + LLVector4a end; + + agent_to_asset.affineTransform(gDebugRaycastStart, start); + agent_to_asset.affineTransform(gDebugRaycastEnd, end); + + + for (auto& node : asset->mNodes) + { + Mesh& mesh = asset->mMeshes[node.mMesh]; + + if (node.mMesh != INVALID_INDEX) + { + gGL.loadMatrix((F32*)node.mRenderMatrix.mMatrix); + + // draw bounding box of mesh primitives + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES)) + { + gGL.color3f(0.f, 1.f, 1.f); + + for (auto& primitive : mesh.mPrimitives) + { + auto* listener = (LLVolumeOctreeListener*) primitive.mOctree->getListener(0); + + LLVector4a center = listener->mBounds[0]; + LLVector4a size = listener->mBounds[1]; + + drawBoxOutline(center, size); + } + } + +#if 0 + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST)) + { + gGL.flush(); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + // convert raycast to node local space + LLVector4a local_start; + LLVector4a local_end; + + node.mAssetMatrixInv.affineTransform(start, local_start); + node.mAssetMatrixInv.affineTransform(end, local_end); + + for (auto& primitive : mesh.mPrimitives) + { + if (primitive.mOctree.notNull()) + { + renderOctreeRaycast(local_start, local_end, primitive.mOctree); + } + } + + gGL.flush(); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } +#endif + } + } + + gGL.popMatrix(); +} + +void GLTFSceneManager::renderDebug() +{ + if (!gPipeline.hasRenderDebugMask( + LLPipeline::RENDER_DEBUG_BBOXES | + LLPipeline::RENDER_DEBUG_RAYCAST | + LLPipeline::RENDER_DEBUG_NODES)) + { + return; + } + + gDebugProgram.bind(); + + LLGLDisable cullface(GL_CULL_FACE); + LLGLEnable blend(GL_BLEND); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gPipeline.disableLights(); + + // force update all mRenderMatrix, not just nodes with meshes + for (auto& obj : mObjects) + { + if (obj->isDead() || obj->mGLTFAsset == nullptr) + { + continue; + } + + LLMatrix4a mat = obj->getGLTFAssetToAgentTransform(); + + LLMatrix4a modelview; + modelview.loadu(gGLModelView); + + matMul(mat, modelview, modelview); + + Asset* asset = obj->mGLTFAsset; + + for (auto& node : asset->mNodes) + { + matMul(node.mAssetMatrix, modelview, node.mRenderMatrix); + } + } + + for (auto& obj : mObjects) + { + if (obj->isDead() || obj->mGLTFAsset == nullptr) + { + continue; + } + + Asset* asset = obj->mGLTFAsset; + + LLMatrix4a mat = obj->getGLTFAssetToAgentTransform(); + + LLMatrix4a modelview; + modelview.loadu(gGLModelView); + + matMul(mat, modelview, modelview); + + renderAssetDebug(obj, asset); + } + + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_NODES)) + { //render node hierarchy + + for (U32 i = 0; i < 2; ++i) + { + LLGLDepthTest depth(GL_TRUE, i == 0 ? GL_FALSE : GL_TRUE, i == 0 ? GL_GREATER : GL_LEQUAL); + LLGLState blend(GL_BLEND, i == 0 ? GL_TRUE : GL_FALSE); + + + gGL.pushMatrix(); + + for (auto& obj : mObjects) + { + if (obj->isDead() || obj->mGLTFAsset == nullptr) + { + continue; + } + + LLMatrix4a mat = obj->getGLTFAssetToAgentTransform(); + + LLMatrix4a modelview; + modelview.loadu(gGLModelView); + + matMul(mat, modelview, modelview); + + Asset* asset = obj->mGLTFAsset; + + for (auto& node : asset->mNodes) + { + // force update all mRenderMatrix, not just nodes with meshes + matMul(node.mAssetMatrix, modelview, node.mRenderMatrix); + + gGL.loadMatrix(node.mRenderMatrix.getF32ptr()); + // render x-axis red, y-axis green, z-axis blue + gGL.color4f(1.f, 0.f, 0.f, 0.5f); + gGL.begin(LLRender::LINES); + gGL.vertex3f(0.f, 0.f, 0.f); + gGL.vertex3f(1.f, 0.f, 0.f); + gGL.end(); + gGL.flush(); + + gGL.color4f(0.f, 1.f, 0.f, 0.5f); + gGL.begin(LLRender::LINES); + gGL.vertex3f(0.f, 0.f, 0.f); + gGL.vertex3f(0.f, 1.f, 0.f); + gGL.end(); + gGL.flush(); + + gGL.begin(LLRender::LINES); + gGL.color4f(0.f, 0.f, 1.f, 0.5f); + gGL.vertex3f(0.f, 0.f, 0.f); + gGL.vertex3f(0.f, 0.f, 1.f); + gGL.end(); + gGL.flush(); + + // render path to child nodes cyan + gGL.color4f(0.f, 1.f, 1.f, 0.5f); + gGL.begin(LLRender::LINES); + for (auto& child_idx : node.mChildren) + { + Node& child = asset->mNodes[child_idx]; + gGL.vertex3f(0.f, 0.f, 0.f); + gGL.vertex3fv(child.mMatrix.getTranslation().getF32ptr()); + } + gGL.end(); + gGL.flush(); + } + } + + gGL.popMatrix(); + } + + } + + + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST)) + { + S32 node_hit = -1; + S32 primitive_hit = -1; + LLVector4a intersection; + + LLDrawable* drawable = lineSegmentIntersect(gDebugRaycastStart, gDebugRaycastEnd, true, true, true, true, &node_hit, &primitive_hit, &intersection, nullptr, nullptr, nullptr); + + if (drawable) + { + gGL.pushMatrix(); + Asset* asset = drawable->getVObj()->mGLTFAsset; + Node* node = &asset->mNodes[node_hit]; + Primitive* primitive = &asset->mMeshes[node->mMesh].mPrimitives[primitive_hit]; + + gGL.flush(); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + gGL.color3f(1, 0, 1); + drawBoxOutline(intersection, LLVector4a(0.1f, 0.1f, 0.1f, 0.f)); + + gGL.loadMatrix((F32*) node->mRenderMatrix.mMatrix); + + + + auto* listener = (LLVolumeOctreeListener*) primitive->mOctree->getListener(0); + drawBoxOutline(listener->mBounds[0], listener->mBounds[1]); + + gGL.flush(); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + gGL.popMatrix(); + } + } + gDebugProgram.unbind(); +} + diff --git a/indra/newview/gltfscenemanager.h b/indra/newview/gltfscenemanager.h new file mode 100644 index 0000000000..34b9b46df5 --- /dev/null +++ b/indra/newview/gltfscenemanager.h @@ -0,0 +1,69 @@ +#pragma once + +/** + * @file gltfscenemanager.h + * @brief Builds menus out of items. + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llsingleton.h" +#include "llviewerobject.h" + +namespace LL +{ + class GLTFSceneManager : public LLSimpleton + { + public: + ~GLTFSceneManager(); + // load GLTF file from disk + + void load(); // open filepicker to choose asset + void load(const std::string& filename); // load asset from filename + + void update(); + void render(bool opaque, bool rigged = false); + void renderOpaque(); + void renderAlpha(); + + LLDrawable* lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, + bool pick_transparent, + bool pick_rigged, + bool pick_unselectable, + bool pick_reflection_probe, + S32* node_hit, // return the index of the node that was hit + S32* primitive_hit, // return the index of the primitive that was hit + LLVector4a* intersection, // return the intersection point + LLVector2* tex_coord, // return the texture coordinates of the intersection point + LLVector4a* normal, // return the surface normal at the intersection point + LLVector4a* tangent); // return the surface tangent at the intersection point + + bool lineSegmentIntersect(LLVOVolume* obj, GLTF::Asset* asset, const LLVector4a& start, const LLVector4a& end, S32 face, bool pick_transparent, bool pick_rigged, bool pick_unselectable, S32* face_hitp, S32* primitive_hitp, + LLVector4a* intersection, LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent); + + void renderDebug(); + + std::vector> mObjects; + }; +} + + diff --git a/indra/newview/llagentbenefits.cpp b/indra/newview/llagentbenefits.cpp index 52dfb99867..d09faeb9e0 100644 --- a/indra/newview/llagentbenefits.cpp +++ b/indra/newview/llagentbenefits.cpp @@ -25,6 +25,7 @@ #include "llviewerprecompiledheaders.h" #include "llagentbenefits.h" +#include "llviewertexture.h" // OpenSim legacy economy #include "llagent.h" @@ -106,6 +107,26 @@ bool LLAgentBenefits::init(const LLSD& benefits_sd) return false; } + if (benefits_sd.has("large_texture_upload_cost")) + { + LLSD large_texture_cost = benefits_sd.get("large_texture_upload_cost"); + if (large_texture_cost.isArray()) + { + LLSD::array_const_iterator end = large_texture_cost.endArray(); + LLSD::array_const_iterator it = large_texture_cost.beginArray(); + for (; it != end; ++it) + { + m_2k_texture_upload_cost.push_back(it->asInteger()); + } + std::sort(m_2k_texture_upload_cost.begin(), m_2k_texture_upload_cost.end()); + } + } + + if (m_2k_texture_upload_cost.empty()) + { + m_2k_texture_upload_cost.push_back(m_texture_upload_cost); + } + // FIXME PREMIUM - either use this field or get rid of it m_initalized = true; return true; @@ -122,15 +143,15 @@ S32 LLAgentBenefits::getAnimatedObjectLimit() const else { S32 max_attach = 0; - if (gAgent.getRegion()) - { - LLSD features; - gAgent.getRegion()->getSimulatorFeatures(features); - if (features.has("AnimatedObjects")) + if (gAgent.getRegion()) { - max_attach = features["AnimatedObjects"]["MaxAgentAnimatedObjectAttachments"].asInteger(); + LLSD features; + gAgent.getRegion()->getSimulatorFeatures(features); + if (features.has("AnimatedObjects")) + { + max_attach = features["AnimatedObjects"]["MaxAgentAnimatedObjectAttachments"].asInteger(); + } } - } return max_attach; } // @@ -212,6 +233,49 @@ S32 LLAgentBenefits::getTextureUploadCost() const // } +S32 LLAgentBenefits::getTextureUploadCost(const LLViewerTexture* tex) const +{ + if (tex) + { + S32 area = tex->getFullHeight() * tex->getFullWidth(); + if (area >= MIN_2K_TEXTURE_AREA) + { + return get2KTextureUploadCost(area); + } + else + { + return getTextureUploadCost(); + } + } + return 0; +} + +S32 LLAgentBenefits::getTextureUploadCost(const LLImageBase* tex) const +{ + if (tex) + { + S32 area = tex->getHeight() * tex->getWidth(); + if (area >= MIN_2K_TEXTURE_AREA) + { + return get2KTextureUploadCost(area); + } + else + { + return getTextureUploadCost(); + } + } + return getTextureUploadCost(); +} + +S32 LLAgentBenefits::get2KTextureUploadCost(S32 area) const +{ + if (m_2k_texture_upload_cost.empty()) + { + return m_texture_upload_cost; + } + return m_2k_texture_upload_cost[0]; +} + bool LLAgentBenefits::findUploadCost(LLAssetType::EType& asset_type, S32& cost) const { bool succ = false; diff --git a/indra/newview/llagentbenefits.h b/indra/newview/llagentbenefits.h index 1afc80a6cc..ff23241aa9 100644 --- a/indra/newview/llagentbenefits.h +++ b/indra/newview/llagentbenefits.h @@ -30,9 +30,14 @@ #include "llsd.h" #include "llassettype.h" +class LLViewerTexture; +class LLImageBase; + class LLAgentBenefits { public: + static constexpr S32 MIN_2K_TEXTURE_AREA = 1024 * 1024 + 1; + LLAgentBenefits(); ~LLAgentBenefits(); LOG_CLASS(LLAgentBenefits); @@ -47,6 +52,9 @@ public: S32 getPicksLimit() const; S32 getSoundUploadCost() const; S32 getTextureUploadCost() const; + S32 getTextureUploadCost(const LLViewerTexture* tex) const; + S32 getTextureUploadCost(const LLImageBase* tex) const; + S32 get2KTextureUploadCost(S32 area) const; bool findUploadCost(LLAssetType::EType& asset_type, S32& cost) const; @@ -59,6 +67,7 @@ private: S32 m_picks_limit; S32 m_sound_upload_cost; S32 m_texture_upload_cost; + std::vector m_2k_texture_upload_cost; bool m_initalized; }; diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 1e32caa08c..9fa7d95bf8 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -2823,7 +2823,7 @@ void LLAgentCamera::setFocusGlobal(const LLPickInfo& pick) { LLViewerObject* objectp = gObjectList.findObject(pick.mObjectID); - if (objectp) + if (objectp && pick.mGLTFNodeIndex == -1) { // focus on object plus designated offset // which may or may not be same as pick.mPosGlobal diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index b6722a3bbb..b350c8fc8e 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -243,6 +243,7 @@ #include "pipeline.h" #include "llgesturemgr.h" #include "llsky.h" +#include "llvlcomposition.h" #include "llvlmanager.h" #include "llviewercamera.h" #include "lldrawpoolbump.h" @@ -253,6 +254,8 @@ #include "llavatariconctrl.h" #include "llgroupiconctrl.h" #include "llviewerassetstats.h" +#include "gltfscenemanager.h" + #include "workqueue.h" using namespace LL; @@ -1474,6 +1477,8 @@ bool LLAppViewer::init() LLWorld::createInstance(); LLSelectMgr::createInstance(); LLViewerCamera::createInstance(); + LL::GLTFSceneManager::createInstance(); + #if LL_WINDOWS if (!mSecondInstance) @@ -2505,7 +2510,7 @@ bool LLAppViewer::cleanup() ll_close_fail_log(); LLError::LLCallStacks::cleanup(); - + LL::GLTFSceneManager::deleteSingleton(); LLEnvironment::deleteSingleton(); LLSelectMgr::deleteSingleton(); LLViewerEventRecorder::deleteSingleton(); @@ -5711,6 +5716,7 @@ void LLAppViewer::idle() { LLPerfStats::tunedAvatars=0; // reset the number of avatars that have been tweaked. gObjectList.update(gAgent); + LL::GLTFSceneManager::instance().update(); } } diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h index 37af23c53a..f4ffebecd7 100644 --- a/indra/newview/lldrawable.h +++ b/indra/newview/lldrawable.h @@ -286,6 +286,7 @@ public: ANIMATED_CHILD = 0x01000000, ACTIVE_CHILD = 0x02000000, FOR_UNLOAD = 0x04000000, //should be unload from memory + MIRROR = 0x08000000, // Used as a mirror, needs a hero probe position to be calculated. } EDrawableFlags; public: diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index ea623b93fc..9ba4f7f300 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 1f1d9e2121..01a29f71a0 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/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index d5c0e3e981..9d18b66ba7 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -49,6 +49,7 @@ #include "llspatialpartition.h" #include "llglcommonfunc.h" #include "llvoavatar.h" +#include "gltfscenemanager.h" #include "llenvironment.h" @@ -261,6 +262,15 @@ void LLDrawPoolAlpha::forwardRender(bool rigged) mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // } gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); + if (rigged) + { // draw GLTF scene to depth buffer before rigged alpha + gPipeline.bindDeferredShader(gDeferredPBRAlphaProgram); + LL::GLTFSceneManager::instance().render(false, false); + + gPipeline.bindDeferredShader(*gDeferredPBRAlphaProgram.mRiggedVariant); + LL::GLTFSceneManager::instance().render(false, true); + } + // If the face is more than 90% transparent, then don't update the Depth buffer for Dof // We don't want the nearly invisible objects to cause of DoF effects renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, false, rigged); @@ -835,6 +845,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged) params.mVertexBuffer->setBuffer(); params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset); + stop_glerror(); if (reset_minimum_alpha) { diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 890132f771..62a199293c 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -704,8 +704,7 @@ void LLBumpImageList::updateImages() { for (bump_image_map_t::iterator iter = mBrightnessEntries.begin(); iter != mBrightnessEntries.end(); ) { - bump_image_map_t::iterator curiter = iter++; - LLViewerTexture* image = curiter->second; + LLViewerTexture* image = iter->second; if( image ) { bool destroy = true; @@ -724,9 +723,11 @@ void LLBumpImageList::updateImages() if( destroy ) { //LL_INFOS() << "*** Destroying bright " << (void*)image << LL_ENDL; - mBrightnessEntries.erase(curiter); // deletes the image thanks to reference counting + iter = mBrightnessEntries.erase(iter); // deletes the image thanks to reference counting + continue; } } + ++iter; } for (bump_image_map_t::iterator iter = mDarknessEntries.begin(); iter != mDarknessEntries.end(); ) diff --git a/indra/newview/lldrawpoolpbropaque.cpp b/indra/newview/lldrawpoolpbropaque.cpp index 303afa51db..a32b6b1687 100644 --- a/indra/newview/lldrawpoolpbropaque.cpp +++ b/indra/newview/lldrawpoolpbropaque.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lldrawpoolpbropaque.cpp * @brief LLDrawPoolGLTFPBR class implementation * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2022, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -30,6 +30,7 @@ #include "lldrawpoolpbropaque.h" #include "llviewershadermgr.h" #include "pipeline.h" +#include "gltfscenemanager.h" LLDrawPoolGLTFPBR::LLDrawPoolGLTFPBR(U32 type) : LLRenderPass(type) @@ -54,9 +55,13 @@ void LLDrawPoolGLTFPBR::renderDeferred(S32 pass) llassert(!LLPipeline::sRenderingHUDs); gDeferredPBROpaqueProgram.bind(); + + LL::GLTFSceneManager::instance().renderOpaque(); pushGLTFBatches(mRenderType); + gDeferredPBROpaqueProgram.bind(true); + LL::GLTFSceneManager::instance().render(true, true); pushRiggedGLTFBatches(mRenderType + 1); } diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp index 4b1061cee2..bf9ede8555 100644 --- a/indra/newview/lldrawpoolterrain.cpp +++ b/indra/newview/lldrawpoolterrain.cpp @@ -54,8 +54,9 @@ const F32 DETAIL_SCALE = 1.f/16.f; int DebugDetailMap = 0; -S32 LLDrawPoolTerrain::sDetailMode = 1; +S32 LLDrawPoolTerrain::sPBRDetailMode = 0; F32 LLDrawPoolTerrain::sDetailScale = DETAIL_SCALE; +F32 LLDrawPoolTerrain::sPBRDetailScale = DETAIL_SCALE; static LLGLSLShader* sShader = NULL; static LLTrace::BlockTimerStatHandle FTM_SHADOW_TERRAIN("Terrain Shadow"); @@ -68,11 +69,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,38 +118,24 @@ 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! LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion(); 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); - } + compp->boost(); } 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 +210,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 +220,34 @@ void LLDrawPoolTerrain::drawLoop() void LLDrawPoolTerrain::renderFullShader() { + const bool use_local_materials = gLocalTerrainMaterials.materialsReady(true, false); // Hack! Get the region that this draw pool is rendering from! LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion(); LLVLComposition *compp = regionp->getComposition(); + const bool use_textures = !use_local_materials && (compp->getMaterialType() == LLTerrainMaterials::Type::TEXTURE); + + if (use_textures) + { + // Use textures + sShader = &gDeferredTerrainProgram; + sShader->bind(); + renderFullShaderTextures(); + } + else + { + // Use materials + sShader = &gDeferredPBRTerrainProgram; + sShader->bind(); + renderFullShaderPBR(use_local_materials); + } +} + +void LLDrawPoolTerrain::renderFullShaderTextures() +{ + // Hack! Get the region that this draw pool is rendering from! + LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion(); + LLVLComposition *compp = regionp->getComposition(); + // [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 +348,228 @@ 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 (*fetched_materials)[LLVLComposition::ASSET_COUNT] = &compp->mDetailMaterials; + + constexpr U32 terrain_material_count = LLVLComposition::ASSET_COUNT; +#ifdef SHOW_ASSERT + constexpr U32 shader_material_count = 1 + LLViewerShaderMgr::TERRAIN_DETAIL3_BASE_COLOR - LLViewerShaderMgr::TERRAIN_DETAIL0_BASE_COLOR; + llassert(shader_material_count == terrain_material_count); +#endif + + if (local_materials) + { + // Override region terrain with the global local override terrain + fetched_materials = &gLocalTerrainMaterials.mDetailMaterials; + } + const LLGLTFMaterial* materials[terrain_material_count]; + for (U32 i = 0; i < terrain_material_count; ++i) + { + materials[i] = (*fetched_materials)[i].get(); + if (!materials[i]) { materials[i] = &LLGLTFMaterial::sDefault; } + } + + S32 detail_basecolor[terrain_material_count]; + S32 detail_normal[terrain_material_count]; + S32 detail_metalrough[terrain_material_count]; + S32 detail_emissive[terrain_material_count]; + + for (U32 i = 0; i < terrain_material_count; ++i) + { + LLViewerTexture* detail_basecolor_texturep = nullptr; + LLViewerTexture* detail_normal_texturep = nullptr; + LLViewerTexture* detail_metalrough_texturep = nullptr; + LLViewerTexture* detail_emissive_texturep = nullptr; + + const LLFetchedGLTFMaterial* fetched_material = (*fetched_materials)[i].get(); + if (fetched_material) + { + detail_basecolor_texturep = fetched_material->mBaseColorTexture; + detail_normal_texturep = fetched_material->mNormalTexture; + detail_metalrough_texturep = fetched_material->mMetallicRoughnessTexture; + detail_emissive_texturep = fetched_material->mEmissiveTexture; + } + + detail_basecolor[i] = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_DETAIL0_BASE_COLOR + i); + if (detail_basecolor_texturep) + { + gGL.getTexUnit(detail_basecolor[i])->bind(detail_basecolor_texturep); + } + else + { + gGL.getTexUnit(detail_basecolor[i])->bind(LLViewerFetchedTexture::sWhiteImagep); + } + gGL.getTexUnit(detail_basecolor[i])->setTextureAddressMode(LLTexUnit::TAM_WRAP); + gGL.getTexUnit(detail_basecolor[i])->activate(); + + if (sPBRDetailMode >= TERRAIN_PBR_DETAIL_NORMAL) + { + detail_normal[i] = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_DETAIL0_NORMAL + i); + if (detail_normal_texturep) + { + gGL.getTexUnit(detail_normal[i])->bind(detail_normal_texturep); + } + else + { + gGL.getTexUnit(detail_normal[i])->bind(LLViewerFetchedTexture::sFlatNormalImagep); + } + gGL.getTexUnit(detail_normal[i])->setTextureAddressMode(LLTexUnit::TAM_WRAP); + gGL.getTexUnit(detail_normal[i])->activate(); + } + + if (sPBRDetailMode >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + { + detail_metalrough[i] = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_DETAIL0_METALLIC_ROUGHNESS + i); + if (detail_metalrough_texturep) + { + gGL.getTexUnit(detail_metalrough[i])->bind(detail_metalrough_texturep); + } + else + { + gGL.getTexUnit(detail_metalrough[i])->bind(LLViewerFetchedTexture::sWhiteImagep); + } + gGL.getTexUnit(detail_metalrough[i])->setTextureAddressMode(LLTexUnit::TAM_WRAP); + gGL.getTexUnit(detail_metalrough[i])->activate(); + } + + if (sPBRDetailMode >= TERRAIN_PBR_DETAIL_EMISSIVE) + { + detail_emissive[i] = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_DETAIL0_EMISSIVE + i); + if (detail_emissive_texturep) + { + gGL.getTexUnit(detail_emissive[i])->bind(detail_emissive_texturep); + } + else + { + gGL.getTexUnit(detail_emissive[i])->bind(LLViewerFetchedTexture::sWhiteImagep); + } + gGL.getTexUnit(detail_emissive[i])->setTextureAddressMode(LLTexUnit::TAM_WRAP); + gGL.getTexUnit(detail_emissive[i])->activate(); + } + } + + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + llassert(shader); + + LLGLTFMaterial::TextureTransform base_color_transform; + base_color_transform.mScale = LLVector2(sPBRDetailScale, sPBRDetailScale); + // *TODO: mOffset and mRotation left at defaults for now. (per-material texture transforms are implemented in another branch) + F32 base_color_packed[8]; + base_color_transform.getPacked(base_color_packed); + // *HACK: Use the same texture repeats for all PBR terrain textures for now + // (not compliant with KHR texture transform spec) + shader->uniform4fv(LLShaderMgr::TEXTURE_BASE_COLOR_TRANSFORM, 2, (F32*)base_color_packed); + + LLSettingsWater::ptr_t pwater = LLEnvironment::instance().getCurrentWater(); + + // + // Alpha Ramp + // + S32 alpha_ramp = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP); + gGL.getTexUnit(alpha_ramp)->bind(m2DAlphaRampImagep); + gGL.getTexUnit(alpha_ramp)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + + // + // GLTF uniforms + // + + LLColor4 base_color_factors[terrain_material_count]; + F32 metallic_factors[terrain_material_count]; + F32 roughness_factors[terrain_material_count]; + LLColor3 emissive_colors[terrain_material_count]; + F32 minimum_alphas[terrain_material_count]; + for (U32 i = 0; i < terrain_material_count; ++i) + { + const LLGLTFMaterial* material = materials[i]; + + base_color_factors[i] = material->mBaseColor; + metallic_factors[i] = material->mMetallicFactor; + roughness_factors[i] = material->mRoughnessFactor; + emissive_colors[i] = material->mEmissiveColor; + // glTF 2.0 Specification 3.9.4. Alpha Coverage + // mAlphaCutoff is only valid for LLGLTFMaterial::ALPHA_MODE_MASK + // Use 0 here due to GLTF terrain blending (LLGLTFMaterial::bind uses + // -1 for easier debugging) + F32 min_alpha = -0.0f; + if (material->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_MASK) + { + // dividing the alpha cutoff by transparency here allows the shader to compare against + // the alpha value of the texture without needing the transparency value + min_alpha = material->mAlphaCutoff/material->mBaseColor.mV[3]; + } + minimum_alphas[i] = min_alpha; + } + shader->uniform4fv(LLShaderMgr::TERRAIN_BASE_COLOR_FACTORS, terrain_material_count, (F32*)base_color_factors); + if (sPBRDetailMode >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + { + shader->uniform4f(LLShaderMgr::TERRAIN_METALLIC_FACTORS, metallic_factors[0], metallic_factors[1], metallic_factors[2], metallic_factors[3]); + shader->uniform4f(LLShaderMgr::TERRAIN_ROUGHNESS_FACTORS, roughness_factors[0], roughness_factors[1], roughness_factors[2], roughness_factors[3]); + } + if (sPBRDetailMode >= TERRAIN_PBR_DETAIL_EMISSIVE) + { + shader->uniform3fv(LLShaderMgr::TERRAIN_EMISSIVE_COLORS, terrain_material_count, (F32*)emissive_colors); + } + shader->uniform4f(LLShaderMgr::TERRAIN_MINIMUM_ALPHAS, minimum_alphas[0], minimum_alphas[1], minimum_alphas[2], minimum_alphas[3]); + + // GL_BLEND disabled by default + drawLoop(); + + // Disable multitexture + + sShader->disableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP); + + gGL.getTexUnit(alpha_ramp)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(alpha_ramp)->disable(); + gGL.getTexUnit(alpha_ramp)->activate(); + + for (U32 i = 0; i < terrain_material_count; ++i) + { + sShader->disableTexture(LLViewerShaderMgr::TERRAIN_DETAIL0_BASE_COLOR + i); + if (sPBRDetailMode >= TERRAIN_PBR_DETAIL_NORMAL) + { + sShader->disableTexture(LLViewerShaderMgr::TERRAIN_DETAIL0_NORMAL + i); + } + if (sPBRDetailMode >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + { + sShader->disableTexture(LLViewerShaderMgr::TERRAIN_DETAIL0_METALLIC_ROUGHNESS + i); + } + if (sPBRDetailMode >= TERRAIN_PBR_DETAIL_EMISSIVE) + { + sShader->disableTexture(LLViewerShaderMgr::TERRAIN_DETAIL0_EMISSIVE + i); + } + + gGL.getTexUnit(detail_basecolor[i])->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(detail_basecolor[i])->disable(); + gGL.getTexUnit(detail_basecolor[i])->activate(); + + if (sPBRDetailMode >= TERRAIN_PBR_DETAIL_NORMAL) + { + gGL.getTexUnit(detail_normal[i])->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(detail_normal[i])->disable(); + gGL.getTexUnit(detail_normal[i])->activate(); + } + + if (sPBRDetailMode >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS) + { + gGL.getTexUnit(detail_metalrough[i])->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(detail_metalrough[i])->disable(); + gGL.getTexUnit(detail_metalrough[i])->activate(); + } + + if (sPBRDetailMode >= TERRAIN_PBR_DETAIL_EMISSIVE) + { + gGL.getTexUnit(detail_emissive[i])->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(detail_emissive[i])->disable(); + gGL.getTexUnit(detail_emissive[i])->activate(); + } + } +} + void LLDrawPoolTerrain::hilightParcelOwners() { { //use fullbright shader for highlighting diff --git a/indra/newview/lldrawpoolterrain.h b/indra/newview/lldrawpoolterrain.h index 2c27733f37..a8097fb58b 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 aa089e4770..d7b5124202 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/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp index 0eeabdd795..047e9a8112 100644 --- a/indra/newview/lldrawpoolwlsky.cpp +++ b/indra/newview/lldrawpoolwlsky.cpp @@ -44,6 +44,7 @@ #include "llsky.h" #include "llvowlsky.h" #include "llsettingsvo.h" +#include "llviewercontrol.h" extern bool gCubeSnapshot; @@ -127,6 +128,19 @@ void LLDrawPoolWLSky::renderDome(const LLVector3& camPosLocal, F32 camHeightLoca gGL.popMatrix(); } +extern LLPointer gEXRImage; + +static bool use_hdri_sky() +{ + static LLCachedControl hdri_split(gSavedSettings, "RenderHDRISplitScreen", 1.f); + static LLCachedControl irradiance_only(gSavedSettings, "RenderHDRIIrradianceOnly", false); + + return gCubeSnapshot && (!irradiance_only || !gPipeline.mReflectionMapManager.isRadiancePass()) ? gEXRImage.notNull() : // always use HDRI for reflection probes when available + gEXRImage.notNull() ? hdri_split > 0.f : // fallback to EEP sky when split screen is zero + false; // no HDRI available, always use EEP sky + +} + void LLDrawPoolWLSky::renderSkyHazeDeferred(const LLVector3& camPosLocal, F32 camHeightLocal) const { if (!gSky.mVOSkyp) @@ -138,9 +152,34 @@ void LLDrawPoolWLSky::renderSkyHazeDeferred(const LLVector3& camPosLocal, F32 ca if (gPipeline.canUseWindLightShaders() && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY)) { - LLGLSPipelineDepthTestSkyBox sky(true, true); + if (use_hdri_sky()) + { + sky_shader = &gEnvironmentMapProgram; + sky_shader->bind(); + S32 idx = sky_shader->enableTexture(LLShaderMgr::ENVIRONMENT_MAP); + if (idx > -1) + { + gGL.getTexUnit(idx)->bind(gEXRImage); + } - sky_shader->bind(); + static LLCachedControl hdri_exposure(gSavedSettings, "RenderHDRIExposure", 0.0f); + static LLCachedControl hdri_rotation(gSavedSettings, "RenderHDRIRotation", 0.f); + static LLCachedControl hdri_split(gSavedSettings, "RenderHDRISplitScreen", 1.f); + static LLStaticHashedString hdri_split_screen("hdri_split_screen"); + + LLMatrix3 rot; + rot.setRot(0.f, hdri_rotation*DEG_TO_RAD, 0.f); + + sky_shader->uniform1f(LLShaderMgr::SKY_HDR_SCALE, powf(2.f, hdri_exposure)); + sky_shader->uniformMatrix3fv(LLShaderMgr::DEFERRED_ENV_MAT, 1, GL_FALSE, (F32*) rot.mMatrix); + sky_shader->uniform1f(hdri_split_screen, gCubeSnapshot ? 1.f : hdri_split); + } + else + { + sky_shader->bind(); + } + + LLGLSPipelineDepthTestSkyBox sky(true, true); sky_shader->uniform1i(LLShaderMgr::CUBE_SNAPSHOT, gCubeSnapshot ? 1 : 0); @@ -180,7 +219,7 @@ void LLDrawPoolWLSky::renderSkyHazeDeferred(const LLVector3& camPosLocal, F32 ca void LLDrawPoolWLSky::renderStarsDeferred(const LLVector3& camPosLocal) const { - if (!gSky.mVOSkyp) + if (!gSky.mVOSkyp || use_hdri_sky()) { return; } @@ -251,6 +290,11 @@ void LLDrawPoolWLSky::renderStarsDeferred(const LLVector3& camPosLocal) const void LLDrawPoolWLSky::renderSkyCloudsDeferred(const LLVector3& camPosLocal, F32 camHeightLocal, LLGLSLShader* cloudshader) const { + if (use_hdri_sky()) + { + return; + } + if (gPipeline.canUseWindLightShaders() && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLOUDS) && gSky.mVOSkyp && gSky.mVOSkyp->getCloudNoiseTex()) { LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); @@ -310,7 +354,7 @@ void LLDrawPoolWLSky::renderSkyCloudsDeferred(const LLVector3& camPosLocal, F32 void LLDrawPoolWLSky::renderHeavenlyBodies() { - if (!gSky.mVOSkyp) return; + if (!gSky.mVOSkyp || use_hdri_sky()) return; LLGLSPipelineBlendSkyBox gls_skybox(true, true); // SL-14113 we need moon to write to depth to clip stars behind @@ -438,8 +482,6 @@ void LLDrawPoolWLSky::renderDeferred(S32 pass) const F32 camHeightLocal = LLEnvironment::instance().getCamHeight(); - gGL.setColorMask(true, false); - LLVector3 const & origin = LLViewerCamera::getInstance()->getOrigin(); if (gPipeline.canUseWindLightShaders()) @@ -456,7 +498,6 @@ void LLDrawPoolWLSky::renderDeferred(S32 pass) renderSkyCloudsDeferred(origin, camHeightLocal, cloud_shader); } } - gGL.setColorMask(true, true); } diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index da88f80d0f..38faaadc67 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -118,6 +118,8 @@ bool LLViewerDynamicTexture::render() //----------------------------------------------------------------------------- void LLViewerDynamicTexture::preRender(bool clear_depth) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; + //use the bottom left corner mOrigin.set(0, 0); @@ -181,19 +183,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) + if (!bake_target.isComplete()) { - gPipeline.mBake.bindTarget(); - gPipeline.mBake.clear(); + 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 +220,13 @@ 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 +249,7 @@ bool LLViewerDynamicTexture::updateAllInstances() } } - if (use_fbo) - { - gPipeline.mBake.flush(); - } + bake_target.flush(); gGL.flush(); diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp index 0225b5dc26..d253fdbf4f 100644 --- a/indra/newview/llenvironment.cpp +++ b/indra/newview/llenvironment.cpp @@ -1810,8 +1810,6 @@ void LLEnvironment::update(const LLViewerCamera * cam) updateSettingsUniforms(); - // *TODO: potential optimization - this block may only need to be - // executed some of the time. For example for water shaders only. { LLViewerShaderMgr::shader_iter shaders_iter, end_shaders; end_shaders = LLViewerShaderMgr::instance()->endShaders(); @@ -1822,6 +1820,10 @@ void LLEnvironment::update(const LLViewerCamera * cam) || shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER)) { shaders_iter->mUniformsDirty = true; + if (shaders_iter->mRiggedVariant) + { + shaders_iter->mRiggedVariant->mUniformsDirty = true; + } } } } @@ -1903,8 +1905,10 @@ void LLEnvironment::updateGLVariablesForSettings(LLShaderUniforms* uniforms, con case LLSD::TypeArray: { LLVector4 vect4(value); + // always identify as a radiance pass if desaturating irradiance is disabled + static LLCachedControl desaturate_irradiance(gSavedSettings, "RenderDesaturateIrradiance", true); - if (gCubeSnapshot && !gPipeline.mReflectionMapManager.isRadiancePass()) + if (desaturate_irradiance && gCubeSnapshot && !gPipeline.mReflectionMapManager.isRadiancePass()) { // maximize and remove tinting if this is an irradiance map render pass and the parameter feeds into the sky background color auto max_vec = [](LLVector4 col) { @@ -3109,7 +3113,7 @@ void LLEnvironment::DayTransition::animate() // pause probe updates and reset reflection maps on sky change - gPipeline.mReflectionMapManager.pause(); + gPipeline.mReflectionMapManager.pause(mTransitionTime); gPipeline.mReflectionMapManager.reset(); mSky = mStartSky->buildClone(); @@ -3712,7 +3716,7 @@ namespace mInjectedSky->setSource(target_sky); // clear reflection probes and pause updates during sky change - gPipeline.mReflectionMapManager.pause(); + gPipeline.mReflectionMapManager.pause(transition); gPipeline.mReflectionMapManager.reset(); mBlenderSky = std::make_shared(target_sky, start_sky, psky, transition); diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 5a6a97ddec..cbc360f65a 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -1333,7 +1333,7 @@ bool LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_color) { //decide if shiny goes in alpha channel of color if (tep && - !isInAlphaPool()) // <--- alpha channel MUST contain transparency, not shiny + !isInAlphaPool() && tep->getGLTFRenderMaterial() == nullptr) // <--- alpha channel MUST contain transparency, not shiny { LLMaterial* mat = tep->getMaterialParams().get(); @@ -1954,7 +1954,7 @@ bool LLFace::getGeometryVolume(const LLVolume& volume, S32* vp = (S32*) &val; *vp = index; - llassert(index <= LLGLSLShader::sIndexedTextureChannels-1); + llassert(index < LLGLSLShader::sIndexedTextureChannels); LLVector4Logical mask; mask.clear(); diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index 07b5130c3e..7e9b2a8267 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 a70f0f9179..ecee28b5fc 100644 --- a/indra/newview/llfetchedgltfmaterial.cpp +++ b/indra/newview/llfetchedgltfmaterial.cpp @@ -34,18 +34,19 @@ #include "llshadermgr.h" #include "pipeline.h" +//static +LLFetchedGLTFMaterial LLFetchedGLTFMaterial::sDefault; + LLFetchedGLTFMaterial::LLFetchedGLTFMaterial() : LLGLTFMaterial() , mExpectedFlusTime(0.f) - , mActive(true) - , mFetching(false) { } LLFetchedGLTFMaterial::~LLFetchedGLTFMaterial() { - + } LLFetchedGLTFMaterial& LLFetchedGLTFMaterial::operator=(const LLFetchedGLTFMaterial& rhs) @@ -76,9 +77,7 @@ void LLFetchedGLTFMaterial::bind(LLViewerTexture* media_tex) { if (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 = mAlphaCutoff/mBaseColor.mV[3]; + min_alpha = mAlphaCutoff; } shader->uniform1f(LLShaderMgr::MINIMUM_ALPHA, min_alpha); } @@ -242,10 +241,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 +254,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 3352438660..7550c75b45 100644 --- a/indra/newview/llfetchedgltfmaterial.h +++ b/indra/newview/llfetchedgltfmaterial.h @@ -40,6 +40,8 @@ public: virtual ~LLFetchedGLTFMaterial(); LLFetchedGLTFMaterial& operator=(const LLFetchedGLTFMaterial& rhs); + // LLGLTFMaterial::operator== is defined, but LLFetchedGLTFMaterial::operator== is not. + bool operator==(const LLGLTFMaterial& rhs) const = delete; // If this material is loaded, fire the given function void onMaterialComplete(std::function material_complete); @@ -49,8 +51,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 +66,18 @@ public: std::set mTextureEntires; - // Texture used for previewing the material in the UI - LLPointer mPreviewTexture; - + // default material for when assets don't have one + static LLFetchedGLTFMaterial sDefault; 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/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 9596674817..c0992ae9d6 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -67,6 +67,7 @@ LLFilePicker LLFilePicker::sInstance; #define RAW_FILTER L"RAW files (*.raw)\0*.raw\0" #define MODEL_FILTER L"Model files (*.dae)\0*.dae\0" #define MATERIAL_FILTER L"GLTF Files (*.gltf; *.glb)\0*.gltf;*.glb\0" +#define HDRI_FILTER L"HDRI Files (*.exr)\0*.exr\0" #define MATERIAL_TEXTURES_FILTER L"GLTF Import (*.gltf; *.glb; *.tga; *.bmp; *.jpg; *.jpeg; *.png)\0*.gltf;*.glb;*.tga;*.bmp;*.jpg;*.jpeg;*.png\0" #define SCRIPT_FILTER L"Script files (*.lsl)\0*.lsl\0" #define DICTIONARY_FILTER L"Dictionary files (*.dic; *.xcu)\0*.dic;*.xcu\0" @@ -248,6 +249,10 @@ bool LLFilePicker::setupFilter(ELoadFilter filter) IMAGE_FILTER \ L"\0"; break; + case FFLOAD_HDRI: + mOFN.lpstrFilter = HDRI_FILTER \ + L"\0"; + break; case FFLOAD_SCRIPT: mOFN.lpstrFilter = SCRIPT_FILTER \ L"\0"; @@ -725,6 +730,9 @@ std::unique_ptr> LLFilePicker::navOpenFilterProc(ELoadF allowedv->push_back("gltf"); allowedv->push_back("glb"); break; + case FFLOAD_HDRI: + allowedv->push_back("exr"); + break; case FFLOAD_MODEL: case FFLOAD_COLLADA: allowedv->push_back("dae"); @@ -744,12 +752,12 @@ std::unique_ptr> LLFilePicker::navOpenFilterProc(ELoadF break; case FFLOAD_DIRECTORY: break; - // Import filter - case FFLOAD_IMPORT: + // Import filter + case FFLOAD_IMPORT: allowedv->push_back("oxp"); //allowedv->push_back("hpa"); - break; - // + break; + // default: LL_WARNS() << "Unsupported format." << LL_ENDL; } @@ -1952,6 +1960,10 @@ bool LLFilePicker::openFileDialog( int32_t filter, bool blocking, EType aType ) file_type = "material_files"; file_dialog_filter = "*.{gltf,glb}"; break; + case FFLOAD_HDRI: + file_type = "hdri_files"; + file_dialog_filter = "*.{exr}"; + break; case FFLOAD_MATERIAL_TEXTURE: file_type = "material_texture_files"; file_dialog_filter = "*.{gltf,glb,tga,bmp,jpg,jpeg,png}"; diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index e64294dc7b..2db82cef31 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -96,6 +96,7 @@ public: FFLOAD_EXE = 14, // Note: EXE will be treated as ALL on Windows and Linux but not on Darwin FFLOAD_MATERIAL = 15, FFLOAD_MATERIAL_TEXTURE = 16, + FFLOAD_HDRI = 17, // Firestorm additions FFLOAD_IMPORT = 50 diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index 0b65041448..bb26013e41 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -34,6 +34,7 @@ #include "llimagepng.h" #include "llagent.h" +#include "llagentbenefits.h" #include "llbutton.h" #include "llcheckboxctrl.h" #include "llcombobox.h" @@ -286,6 +287,15 @@ void LLFloaterImagePreview::onBtnUpload() onBtnOK(); } // + +//----------------------------------------------------------------------------- +// getExpectedUploadCost() +//----------------------------------------------------------------------------- +S32 LLFloaterImagePreview::getExpectedUploadCost() const +{ + return LLAgentBenefitsMgr::current().getTextureUploadCost(mRawImagep); +} + //----------------------------------------------------------------------------- // LLFloaterImagePreview() //----------------------------------------------------------------------------- @@ -572,7 +582,7 @@ bool LLFloaterImagePreview::loadImage(const std::string& src_filename) return false; } - raw_image->biasedScaleToPowerOfTwo(1024); + raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); mRawImagep = raw_image; } catch (...) diff --git a/indra/newview/llfloaterimagepreview.h b/indra/newview/llfloaterimagepreview.h index e9c0fb47a4..94f65d12f0 100644 --- a/indra/newview/llfloaterimagepreview.h +++ b/indra/newview/llfloaterimagepreview.h @@ -49,17 +49,17 @@ protected: public: LLImagePreviewSculpted(S32 width, S32 height); - /*virtual*/ S8 getType() const ; + S8 getType() const override; void setPreviewTarget(LLImageRaw *imagep, F32 distance); void setTexture(U32 name) { mTextureName = name; } - bool render(); + bool render() override; void refresh(); void rotate(F32 yaw_radians, F32 pitch_radians); void zoom(F32 zoom_amt); void pan(F32 right, F32 up); - virtual bool needsRender() { return mNeedsUpdate; } + virtual bool needsRender() override { return mNeedsUpdate; } protected: bool mNeedsUpdate; @@ -82,18 +82,18 @@ protected: public: LLImagePreviewAvatar(S32 width, S32 height); - /*virtual*/ S8 getType() const ; + S8 getType() const override; void setPreviewTarget(const std::string& joint_name, const std::string& mesh_name, LLImageRaw* imagep, F32 distance, bool male); void setTexture(U32 name) { mTextureName = name; } void clearPreviewTexture(const std::string& mesh_name); - bool render(); + bool render() override; void refresh(); void rotate(F32 yaw_radians, F32 pitch_radians); void zoom(F32 zoom_amt); void pan(F32 right, F32 up); - virtual bool needsRender() { return mNeedsUpdate; } + virtual bool needsRender() override { return mNeedsUpdate; } protected: bool mNeedsUpdate; @@ -114,12 +114,14 @@ public: LLFloaterImagePreview(const std::string& filename); virtual ~LLFloaterImagePreview(); - virtual bool postBuild(); + bool postBuild() override; - bool handleMouseDown(S32 x, S32 y, MASK mask); - bool handleMouseUp(S32 x, S32 y, MASK mask); - bool handleHover(S32 x, S32 y, MASK mask); - bool handleScrollWheel(S32 x, S32 y, S32 clicks); + S32 getExpectedUploadCost() const override; + + bool handleMouseDown(S32 x, S32 y, MASK mask) override; + bool handleMouseUp(S32 x, S32 y, MASK mask) override; + bool handleHover(S32 x, S32 y, MASK mask) override; + bool handleScrollWheel(S32 x, S32 y, S32 clicks) override; static void onMouseCaptureLostImagePreview(LLMouseHandler*); @@ -127,7 +129,7 @@ public: protected: static void onPreviewTypeCommit(LLUICtrl*,void*); - void draw(); + void draw() override; bool loadImage(const std::string& filename); // detect and strip empty alpha layers from images on upload diff --git a/indra/newview/llfloaternamedesc.h b/indra/newview/llfloaternamedesc.h index 5996547b94..aa5571ccc0 100644 --- a/indra/newview/llfloaternamedesc.h +++ b/indra/newview/llfloaternamedesc.h @@ -47,7 +47,7 @@ public: void onBtnCancel(); void doCommit(); - S32 getExpectedUploadCost() const; + virtual S32 getExpectedUploadCost() const; protected: virtual void onCommit() override; diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 24b1d225d4..8032c4c021 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -156,6 +156,7 @@ #include "llviewershadermgr.h" #include "NACLantispam.h" #include "../llcrashlogger/llcrashlogger.h" +#include #if LL_WINDOWS #include #endif @@ -5291,41 +5292,13 @@ void LLPanelPreferenceSkins::refreshPreviewImage() // // Backup Settings -// copied from llxfer_file.cpp - Hopefully this will be part of LLFile some day -Zi -// added a safeguard so the destination file is only created when the source file exists -Zi -S32 copy_prefs_file(const std::string& from, const std::string& to) +static void copy_prefs_file(const std::string& from, const std::string& to) { - LL_WARNS() << "copying " << from << " to " << to << LL_ENDL; - S32 rv = 0; - LLFILE* in = LLFile::fopen(from, "rb"); /*Flawfinder: ignore*/ - if (!in) - { - LL_WARNS() << "couldn't open source file " << from << " - copy aborted." << LL_ENDL; - return -1; - } + LL_INFOS() << "Copying " << from << " to " << to << LL_ENDL; - LLFILE* out = LLFile::fopen(to, "wb"); /*Flawfinder: ignore*/ - if (!out) - { - fclose(in); - LL_WARNS() << "couldn't open destination file " << to << " - copy aborted." << LL_ENDL; - return -1; - } - - size_t read = 0; - constexpr S32 COPY_BUFFER_SIZE = 16384; - U8 buffer[COPY_BUFFER_SIZE]; - while (((read = fread(buffer, 1, sizeof(buffer), in)) > 0) - && (fwrite(buffer, 1, read, out) == read)); /* Flawfinder : ignore */ - if (ferror(in) || ferror(out)) - rv = -2; - - if (in) - fclose(in); - if (out) - fclose(out); - - return rv; + std::error_code ec; + if (!std::filesystem::copy_file(from, to, ec) || ec) + LL_WARNS() << "Couldn't copy file: " << ec.message() << LL_ENDL; } static LLPanelInjector t_pref_backup("panel_preference_backup"); diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index aaf73a79f1..174d44e1da 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -62,6 +62,7 @@ #include "llfloaterreg.h" #include "llfloaterregiondebugconsole.h" #include "llfloatertelehub.h" +#include "llgltfmateriallist.h" #include "llinventorymodel.h" #include "lllineeditor.h" #include "llnamelistctrl.h" @@ -86,7 +87,6 @@ #include "llviewerstats.h" #include "llviewertexteditor.h" #include "llviewerwindow.h" -#include "llvlcomposition.h" #include "lltrans.h" #include "llagentui.h" #include "llmeshrepository.h" @@ -107,7 +107,6 @@ // Aurora Sim - Region Settings Console #include "llviewermenufile.h" -const S32 TERRAIN_TEXTURE_COUNT = 4; const S32 CORNER_COUNT = 4; const U32 MAX_LISTED_NAMES = 100; @@ -359,7 +358,6 @@ void LLFloaterRegionInfo::onRegionChanged() } } -// static void LLFloaterRegionInfo::requestRegionInfo() { LLTabContainer* tab = findChild("region_panels"); @@ -653,6 +651,16 @@ LLPanelRegionEnvironment* LLFloaterRegionInfo::getPanelEnvironment() return panel; } +LLTerrainMaterials::Type material_type_from_ctrl(LLCheckBoxCtrl* ctrl) +{ + return ctrl->get() ? LLTerrainMaterials::Type::PBR : LLTerrainMaterials::Type::TEXTURE; +} + +void material_type_to_ctrl(LLCheckBoxCtrl* ctrl, LLTerrainMaterials::Type new_type) +{ + ctrl->set(new_type == LLTerrainMaterials::Type::PBR); +} + // static LLPanelRegionTerrainInfo* LLFloaterRegionInfo::getPanelRegionTerrain() { @@ -1493,16 +1501,23 @@ void LLPanelRegionDebugInfo::onClickDebugConsole(void* data) bool LLPanelRegionTerrainInfo::validateTextureSizes() { - static const S32 MAX_TERRAIN_TEXTURE_SIZE = 1024; - for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i) + if (mMaterialTypeCtrl) { - std::string buffer; - buffer = llformat("texture_detail_%d", i); - LLTextureCtrl* texture_ctrl = getChild(buffer); + const LLTerrainMaterials::Type material_type = material_type_from_ctrl(mMaterialTypeCtrl); + const bool is_material_selected = material_type == LLTerrainMaterials::Type::PBR; + if (is_material_selected) { return true; } + } + + bool valid = true; + static LLCachedControl max_texture_resolution(gSavedSettings, "RenderMaxTextureResolution", 2048); + const S32 max_terrain_texture_size = (S32)max_texture_resolution; + for(S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i) + { + LLTextureCtrl* texture_ctrl = mTextureDetailCtrl[i]; if (!texture_ctrl) continue; LLUUID image_asset_id = texture_ctrl->getImageAssetID(); - LLViewerTexture* img = LLViewerTextureManager::getFetchedTexture(image_asset_id); + LLViewerFetchedTexture* img = LLViewerTextureManager::getFetchedTexture(image_asset_id); S32 components = img->getComponents(); // Must ask for highest resolution version's width. JC S32 width = img->getFullWidth(); @@ -1510,31 +1525,133 @@ 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; args["TEXTURE_BIT_DEPTH"] = llformat("%d",components * 8); - args["MAX_SIZE"] = MAX_TERRAIN_TEXTURE_SIZE; + args["MAX_SIZE"] = max_terrain_texture_size; LLNotificationsUtil::add("InvalidTerrainBitDepth", args); - return false; + valid = false; + continue; } - if (width > MAX_TERRAIN_TEXTURE_SIZE || height > MAX_TERRAIN_TEXTURE_SIZE) + if (components == 4) + { + if (!img->hasSavedRawImage()) + { + // Raw image isn't loaded yet + // Assume it's invalid due to presence of alpha channel + LLSD args; + args["TEXTURE_NUM"] = i+1; + args["TEXTURE_BIT_DEPTH"] = llformat("%d",components * 8); + LLNotificationsUtil::add("InvalidTerrainAlphaNotFullyLoaded", args); + valid = false; + } + else + { + // Slower path: Calculate alpha from raw image pixels (not needed + // for GLTF materials, which use alphaMode to determine + // transparency) + // Raw image is pretty much guaranteed to be saved due to the texture swatches + LLImageRaw* raw = img->getSavedRawImage(); + if (raw->checkHasTransparentPixels()) + { + LLSD args; + args["TEXTURE_NUM"] = i+1; + LLNotificationsUtil::add("InvalidTerrainAlpha", args); + valid = false; + } + LL_WARNS() << "Terrain texture image in slot " << i << " with ID " << image_asset_id << " has alpha channel, but pixels are opaque. Is alpha being optimized away in the texture uploader?" << LL_ENDL; + } + } + + if (width > max_terrain_texture_size || height > max_terrain_texture_size) { LLSD args; args["TEXTURE_NUM"] = i+1; args["TEXTURE_SIZE_X"] = width; args["TEXTURE_SIZE_Y"] = height; - args["MAX_SIZE"] = MAX_TERRAIN_TEXTURE_SIZE; + args["MAX_SIZE"] = max_terrain_texture_size; LLNotificationsUtil::add("InvalidTerrainSize", args); - return false; - + valid = false; } } - return true; + return valid; +} + +bool LLPanelRegionTerrainInfo::validateMaterials() +{ + if (mMaterialTypeCtrl) + { + const LLTerrainMaterials::Type material_type = material_type_from_ctrl(mMaterialTypeCtrl); + const bool is_texture_selected = material_type == LLTerrainMaterials::Type::TEXTURE; + if (is_texture_selected) { return true; } + } + + // *TODO: If/when we implement additional GLTF extensions, they may not be + // compatible with our GLTF terrain implementation. We may want to disallow + // materials with some features from being set on terrain, if their + // implementation on terrain is not compliant with the spec: + // - KHR_materials_transmission: Probably OK? + // - KHR_materials_ior: Probably OK? + // - KHR_materials_volume: Likely incompatible, as our terrain + // heightmaps cannot currently be described as finite enclosed + // volumes. + // See also LLGLTFMaterial +#ifdef LL_WINDOWS + llassert(sizeof(LLGLTFMaterial) == 232); +#endif + + bool valid = true; + for (S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i) + { + LLTextureCtrl* material_ctrl = mMaterialDetailCtrl[i]; + if (!material_ctrl) { continue; } + + const LLUUID& material_asset_id = material_ctrl->getImageAssetID(); + llassert(material_asset_id.notNull()); + if (material_asset_id.isNull()) { return false; } + const LLFetchedGLTFMaterial* material = gGLTFMaterialList.getMaterial(material_asset_id); + if (!material->isLoaded()) + { + if (material->isFetching()) + { + LLSD args; + args["MATERIAL_NUM"] = i + 1; + LLNotificationsUtil::add("InvalidTerrainMaterialNotLoaded", args); + } + else // Loading failed + { + LLSD args; + args["MATERIAL_NUM"] = i + 1; + LLNotificationsUtil::add("InvalidTerrainMaterialLoadFailed", args); + } + valid = false; + continue; + } + + if (material->mDoubleSided) + { + LLSD args; + args["MATERIAL_NUM"] = i + 1; + LLNotificationsUtil::add("InvalidTerrainMaterialDoubleSided", args); + valid = false; + } + if (material->mAlphaMode != LLGLTFMaterial::ALPHA_MODE_OPAQUE && material->mAlphaMode != LLGLTFMaterial::ALPHA_MODE_MASK) + { + LLSD args; + args["MATERIAL_NUM"] = i + 1; + const char* alpha_mode = material->getAlphaMode(); + args["MATERIAL_ALPHA_MODE"] = alpha_mode; + LLNotificationsUtil::add("InvalidTerrainMaterialAlphaMode", args); + valid = false; + } + } + + return valid; } bool LLPanelRegionTerrainInfo::validateTextureHeights() @@ -1556,6 +1673,21 @@ bool LLPanelRegionTerrainInfo::validateTextureHeights() ///////////////////////////////////////////////////////////////////////////// // LLPanelRegionTerrainInfo ///////////////////////////////////////////////////////////////////////////// + +LLPanelRegionTerrainInfo::LLPanelRegionTerrainInfo() +: LLPanelRegionInfo() +{ + const LLUUID (&default_textures)[LLVLComposition::ASSET_COUNT] = LLVLComposition::getDefaultTextures(); + for (S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i) + { + mLastSetTextures[i] = default_textures[i]; + } + for (S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i) + { + mLastSetMaterials[i] = BLANK_MATERIAL_ASSET_ID; + } +} + // Initialize statics bool LLPanelRegionTerrainInfo::postBuild() @@ -1566,11 +1698,22 @@ bool LLPanelRegionTerrainInfo::postBuild() initCtrl("terrain_raise_spin"); initCtrl("terrain_lower_spin"); + mMaterialTypeCtrl = findChild("terrain_material_type"); + if (mMaterialTypeCtrl) { mMaterialTypeCtrl->setCommitCallback(boost::bind(&LLPanelRegionTerrainInfo::onSelectMaterialType, this)); } + std::string buffer; - for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i) + + for(S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i) { buffer = llformat("texture_detail_%d", i); initCtrl(buffer); + mTextureDetailCtrl[i] = findChild(buffer); + } + for(S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i) + { + buffer = llformat("material_detail_%d", i); + initCtrl(buffer); + mMaterialDetailCtrl[i] = findChild(buffer); } for(S32 i = 0; i < CORNER_COUNT; ++i) @@ -1591,6 +1734,57 @@ bool LLPanelRegionTerrainInfo::postBuild() return LLPanelRegionInfo::postBuild(); } +void LLPanelRegionTerrainInfo::onSelectMaterialType() +{ + updateForMaterialType(); + onChangeAnything(); +} + +void LLPanelRegionTerrainInfo::updateForMaterialType() +{ + if (!mMaterialTypeCtrl) { return; } + const LLTerrainMaterials::Type material_type = material_type_from_ctrl(mMaterialTypeCtrl); + const bool show_texture_controls = material_type == LLTerrainMaterials::Type::TEXTURE; + const bool show_material_controls = material_type == LLTerrainMaterials::Type::PBR; + + // Toggle visibility of correct swatches + for(S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i) + { + LLTextureCtrl* texture_ctrl = mTextureDetailCtrl[i]; + if (texture_ctrl) + { + texture_ctrl->setVisible(show_texture_controls); + } + } + for(S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i) + { + LLTextureCtrl* material_ctrl = mMaterialDetailCtrl[i]; + if (material_ctrl) + { + material_ctrl->setVisible(show_material_controls); + } + } + + // Toggle visibility of labels + LLUICtrl* texture_label = findChild("detail_texture_text"); + if (texture_label) { texture_label->setVisible(show_texture_controls); } + LLUICtrl* material_label = findChild("detail_material_text"); + if (material_label) { material_label->setVisible(show_material_controls); } + + // Toggle visibility of documentation labels for terrain blending ranges + const std::vector doc_suffixes { "5", "10", "11" }; + std::string buffer; + for (const std::string& suffix : doc_suffixes) + { + buffer = "height_text_lbl" + suffix; + LLUICtrl* texture_doc_label = findChild(buffer); + if (texture_doc_label) { texture_doc_label->setVisible(show_texture_controls); } + buffer += "_material"; + LLUICtrl* material_doc_label = findChild(buffer); + if (material_doc_label) { material_doc_label->setVisible(show_material_controls); } + } +} + // virtual bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region) { @@ -1607,21 +1801,99 @@ bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region) getChild("region_text")->setValue(LLSD(region->getName())); LLVLComposition* compp = region->getComposition(); - LLTextureCtrl* texture_ctrl; - std::string buffer; - for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i) + + static LLCachedControl feature_pbr_terrain_enabled(gSavedSettings, "RenderTerrainPBREnabled", false); + + const bool textures_ready = compp->texturesReady(false, false); + const bool materials_ready = feature_pbr_terrain_enabled && compp->materialsReady(false, false); + + bool set_texture_swatches; + bool set_material_swatches; + bool reset_texture_swatches; + bool reset_material_swatches; + LLTerrainMaterials::Type material_type; + if (!textures_ready && !materials_ready) { - buffer = llformat("texture_detail_%d", i); - texture_ctrl = getChild(buffer); - if(texture_ctrl) + // Are these 4 texture IDs or 4 material IDs? Who knows! Let's set + // the IDs on both pickers for now. + material_type = LLTerrainMaterials::Type::TEXTURE; + set_texture_swatches = true; + set_material_swatches = true; + reset_texture_swatches = false; + reset_material_swatches = false; + } + else + { + material_type = compp->getMaterialType(); + set_texture_swatches = material_type == LLTerrainMaterials::Type::TEXTURE; + set_material_swatches = !set_texture_swatches; + reset_texture_swatches = !set_texture_swatches; + reset_material_swatches = !set_material_swatches; + } + + if (mMaterialTypeCtrl) + { + material_type_to_ctrl(mMaterialTypeCtrl, material_type); + updateForMaterialType(); + mMaterialTypeCtrl->setVisible(feature_pbr_terrain_enabled); + } + + if (set_texture_swatches) + { + for(S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i) { - LL_DEBUGS() << "Detail Texture " << i << ": " - << compp->getDetailTextureID(i) << LL_ENDL; - LLUUID tmp_id(compp->getDetailTextureID(i)); - texture_ctrl->setImageAssetID(tmp_id); + LLTextureCtrl* asset_ctrl = mTextureDetailCtrl[i]; + if(asset_ctrl) + { + LL_DEBUGS("Terrain", "Texture") << "Detail Texture " << i << ": " + << compp->getDetailAssetID(i) << LL_ENDL; + LLUUID tmp_id(compp->getDetailAssetID(i)); + asset_ctrl->setImageAssetID(tmp_id); + } + } + } + if (set_material_swatches) + { + for(S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i) + { + LLTextureCtrl* asset_ctrl = mMaterialDetailCtrl[i]; + if(asset_ctrl) + { + LL_DEBUGS("Terrain", "Material") << "Detail Material " << i << ": " + << compp->getDetailAssetID(i) << LL_ENDL; + LLUUID tmp_id(compp->getDetailAssetID(i)); + asset_ctrl->setImageAssetID(tmp_id); + } + } + } + if (reset_texture_swatches) + { + for(S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i) + { + LL_DEBUGS("Terrain", "Texture") << "Reset Texture swatch " << i + << LL_ENDL; + LLTextureCtrl* asset_ctrl = mTextureDetailCtrl[i]; + if(asset_ctrl) + { + asset_ctrl->setImageAssetID(mLastSetTextures[i]); + } + } + } + if (reset_material_swatches) + { + for(S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i) + { + LL_DEBUGS("Terrain", "Material") << "Reset Material swatch " << i + << LL_ENDL; + LLTextureCtrl* asset_ctrl = mMaterialDetailCtrl[i]; + if(asset_ctrl) + { + asset_ctrl->setImageAssetID(mLastSetMaterials[i]); + } } } + std::string buffer; for(S32 i = 0; i < CORNER_COUNT; ++i) { buffer = llformat("height_start_spin_%d", i); @@ -1636,6 +1908,9 @@ bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region) getChild("region_text")->setValue(LLSD("")); } + // Update visibility of terrain swatches, etc + refresh(); + getChildView("download_raw_btn")->setEnabled(owner_or_god); getChildView("upload_raw_btn")->setEnabled(owner_or_god); getChildView("bake_terrain_btn")->setEnabled(owner_or_god); @@ -1648,21 +1923,6 @@ bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region) bool LLPanelRegionTerrainInfo::sendUpdate() { LL_INFOS() << "LLPanelRegionTerrainInfo::sendUpdate" << LL_ENDL; - std::string buffer; - strings_t strings; - LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - - // update the model - LLRegionInfoModel& region_info = LLRegionInfoModel::instance(); - region_info.mWaterHeight = (F32) getChild("water_height_spin")->getValue().asReal(); - region_info.mTerrainRaiseLimit = (F32) getChild("terrain_raise_spin")->getValue().asReal(); - region_info.mTerrainLowerLimit = (F32) getChild("terrain_lower_spin")->getValue().asReal(); - - // and sync the region with it - region_info.sendRegionTerrain(invoice); - - // ======================================= - // Assemble and send texturedetail message // Make sure user hasn't chosen wacky textures unless we're on Aurora-sim. // Aurora Sim - Region Settings Console @@ -1679,6 +1939,12 @@ bool LLPanelRegionTerrainInfo::sendUpdate() #endif // OPENSIM // Aurora Sim - Region Settings Console + // Prevent applying unsupported alpha blend/double-sided materials + if (!validateMaterials()) + { + return false; + } + // Check if terrain Elevation Ranges are correct if (gSavedSettings.getBOOL("RegionCheckTextureHeights") && !validateTextureHeights()) { @@ -1694,20 +1960,55 @@ bool LLPanelRegionTerrainInfo::sendUpdate() } } - LLTextureCtrl* texture_ctrl; + std::string buffer; + strings_t strings; + LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); + + // update the model + LLRegionInfoModel& region_info = LLRegionInfoModel::instance(); + region_info.mWaterHeight = (F32) getChild("water_height_spin")->getValue().asReal(); + region_info.mTerrainRaiseLimit = (F32) getChild("terrain_raise_spin")->getValue().asReal(); + region_info.mTerrainLowerLimit = (F32) getChild("terrain_lower_spin")->getValue().asReal(); + + // and sync the region with it + region_info.sendRegionTerrain(invoice); + + // ======================================= + // Assemble and send texturedetail message + std::string id_str; LLMessageSystem* msg = gMessageSystem; - for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i) + // Send either material IDs instead of texture IDs depending on + // material_type - they both occupy the same slot. + const LLTerrainMaterials::Type material_type = mMaterialTypeCtrl ? material_type_from_ctrl(mMaterialTypeCtrl) : LLTerrainMaterials::Type::TEXTURE; + for(S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i) { - buffer = llformat("texture_detail_%d", i); - texture_ctrl = getChild(buffer); - if(texture_ctrl) + LLTextureCtrl* asset_ctrl; + if (material_type == LLTerrainMaterials::Type::PBR) { - LLUUID tmp_id(texture_ctrl->getImageAssetID()); - tmp_id.toString(id_str); - buffer = llformat("%d %s", i, id_str.c_str()); - strings.push_back(buffer); + asset_ctrl = mMaterialDetailCtrl[i]; + } + else + { + asset_ctrl = mTextureDetailCtrl[i]; + } + + if (!asset_ctrl) { continue; } + + LLUUID tmp_id(asset_ctrl->getImageAssetID()); + tmp_id.toString(id_str); + buffer = llformat("%d %s", i, id_str.c_str()); + strings.push_back(buffer); + + // Store asset for later terrain editing + if (material_type == LLTerrainMaterials::Type::PBR) + { + mLastSetMaterials[i] = tmp_id; + } + else + { + mLastSetTextures[i] = tmp_id; } } sendEstateOwnerMessage(msg, "texturedetail", invoice, strings); diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h index 867a164380..da92f74ccd 100644 --- a/indra/newview/llfloaterregioninfo.h +++ b/indra/newview/llfloaterregioninfo.h @@ -36,6 +36,7 @@ #include "llpanel.h" #include "llextendedstatus.h" #include "llpanelenvironment.h" +#include "llvlcomposition.h" #include "lleventcoro.h" @@ -55,6 +56,7 @@ class LLRadioGroup; class LLSliderCtrl; class LLSpinCtrl; class LLTextBox; +class LLTextureCtrl; class LLPanelRegionGeneralInfo; // Aurora Sim - Region Settings Panel @@ -78,9 +80,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 +106,7 @@ public: // Aurora Sim - Region Settings Panel // from LLPanel - virtual void refresh(); + void refresh() override; void onRegionChanged(); void requestRegionInfo(); @@ -150,7 +152,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 +212,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 +241,13 @@ public: LLPanelRegionDebugInfo() : LLPanelRegionInfo(), mTargetAvatar() {} ~LLPanelRegionDebugInfo() {} - // LLPanel - virtual bool postBuild(); - virtual bool refreshFromRegion(LLViewerRegion* region); + bool postBuild() override; + + 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); @@ -270,20 +271,22 @@ class LLPanelRegionTerrainInfo : public LLPanelRegionInfo LOG_CLASS(LLPanelRegionTerrainInfo); public: - LLPanelRegionTerrainInfo() : LLPanelRegionInfo() {} + LLPanelRegionTerrainInfo(); ~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(); + bool validateMaterials(); bool validateTextureHeights(); //static void onChangeAnything(LLUICtrl* ctrl, void* userData); // callback for any change, to enable commit button - virtual bool sendUpdate(); + void onSelectMaterialType(); + void updateForMaterialType(); static void onClickDownloadRaw(void*); static void onClickUploadRaw(void*); @@ -295,9 +298,17 @@ 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; + LLCheckBoxCtrl* mMaterialTypeCtrl = nullptr; + LLTextureCtrl* mTextureDetailCtrl[LLTerrainMaterials::ASSET_COUNT]; + LLTextureCtrl* mMaterialDetailCtrl[LLTerrainMaterials::ASSET_COUNT]; + LLUUID mLastSetTextures[LLTerrainMaterials::ASSET_COUNT]; + LLUUID mLastSetMaterials[LLTerrainMaterials::ASSET_COUNT]; }; ///////////////////////////////////////////////////////////////////////////// @@ -333,13 +344,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 +359,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 +379,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 +421,7 @@ public: } EAssetStatus; protected: - virtual bool sendUpdate(); + bool sendUpdate() override; LLTextBox* mEstateNameText; LLTextBox* mEstateOwnerText; LLTextBox* mLastModifiedText; @@ -431,16 +440,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 +477,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 +486,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 7984478eb4..215f3dd3a7 100644 --- a/indra/newview/llgltfmateriallist.cpp +++ b/indra/newview/llgltfmateriallist.cpp @@ -55,8 +55,6 @@ LLGLTFMaterialList::modify_queue_t LLGLTFMaterialList::sModifyQueue; LLGLTFMaterialList::apply_queue_t LLGLTFMaterialList::sApplyQueue; LLSD LLGLTFMaterialList::sUpdates; -const LLUUID LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID("968cbad0-4dad-d64e-71b5-72bf13ad051a"); - #ifdef SHOW_ASSERT // return true if given data is (probably) valid update message for ModifyMaterialParams capability static bool is_valid_update(const LLSD& data) @@ -242,6 +240,7 @@ void LLGLTFMaterialList::applyOverrideMessage(LLMessageSystem* msg, const std::s } } } + region->cacheFullUpdateGLTFOverride(cache); LL_DEBUGS("GLTF") << "GLTF Material Override: " << cache.mObjectId << " " << cache.mLocalId << " " << cache.mRegionHandle << " (sides:" << (cache.mSides.size()) << ")" << LL_ENDL; } @@ -468,7 +467,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 @@ -553,7 +552,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/llgltfmateriallist.h b/indra/newview/llgltfmateriallist.h index c1e0dd0a64..6eab86ff0a 100644 --- a/indra/newview/llgltfmateriallist.h +++ b/indra/newview/llgltfmateriallist.h @@ -40,8 +40,6 @@ class LLGLTFOverrideCacheEntry; class LLGLTFMaterialList { public: - static const LLUUID BLANK_MATERIAL_ASSET_ID; - LLGLTFMaterialList() {} @@ -81,14 +79,14 @@ public: static void flushUpdates(void(*done_callback)(bool) = nullptr); static void addSelectionUpdateCallback(void(*update_callback)(const LLUUID& object_id, S32 side)); - + // Queue an explicit LLSD ModifyMaterialParams update apply given override data // overrides -- LLSD map (or array of maps) in the format: // object_id UUID(required) id of object // side integer(required) TE index of face to set, or -1 for all faces // gltf_json string(optional) override data to set, empty string nulls out override data, omissions of this parameter keeps existing data // asset_id UUID(optional) id of material asset to set, omission of this parameter keeps existing material asset id - // + // // NOTE: Unless you already have a gltf_json string you want to send, strongly prefer using queueModify // If the queue/flush API is insufficient, extend it. static void queueUpdate(const LLSD& data); diff --git a/indra/newview/llgltfmaterialpreviewmgr.cpp b/indra/newview/llgltfmaterialpreviewmgr.cpp new file mode 100644 index 0000000000..a198d1bdf4 --- /dev/null +++ b/indra/newview/llgltfmaterialpreviewmgr.cpp @@ -0,0 +1,590 @@ +/** + * @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 "llviewercontrol.h" +#include "llviewerobject.h" +#include "llviewershadermgr.h" +#include "llviewertexturelist.h" +#include "llviewerwindow.h" +#include "llvolumemgr.h" +#include "pipeline.h" + +LLGLTFMaterialPreviewMgr gGLTFMaterialPreviewMgr; + +namespace +{ + constexpr S32 FULLY_LOADED = 0; + constexpr S32 NOT_LOADED = 99; +}; + +LLGLTFPreviewTexture::MaterialLoadLevels::MaterialLoadLevels() +{ + for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i) + { + levels[i] = NOT_LOADED; + } +} + +bool LLGLTFPreviewTexture::MaterialLoadLevels::isFullyLoaded() +{ + for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i) + { + if (levels[i] != FULLY_LOADED) { return false; } + } + return true; +} + +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 (!img && id.notNull()) + { + if (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(id)) + { + LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + if (obj) + { + LLViewerTexture* viewerTexture = obj->getBakedTextureForMagicId(id); + img = viewerTexture ? dynamic_cast(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) + { + llassert(!material.isFetching()); + + 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); +} + +bool LLGLTFPreviewTexture::needsRender() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; + + if (!mShouldRender && mBestLoad.isFullyLoaded()) { return false; } + MaterialLoadLevels current_load = get_material_load_levels(*mGLTFMaterial.get()); + if (current_load < mBestLoad) + { + mShouldRender = true; + mBestLoad = current_load; + return true; + } + return false; +} + +void LLGLTFPreviewTexture::preRender(bool clear_depth) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; + + llassert(mShouldRender); + 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 + 1; + 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); + const S32 old_local_light_count = gSavedSettings.get("RenderLocalLightCount"); + gSavedSettings.set("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(); + } + + // *HACK: Hide mExposureMap from generateExposure + gPipeline.mExposureMap.swapFBORefs(gPipeline.mLastExposure); + + gPipeline.copyScreenSpaceReflections(&screen, &gPipeline.mSceneMap); + gPipeline.generateLuminance(&screen, &gPipeline.mLuminanceMap); + gPipeline.generateExposure(&gPipeline.mLuminanceMap, &gPipeline.mExposureMap, /*use_history = */ false); + 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); + + // *HACK: Restore mExposureMap (it will be consumed by generateExposure next frame) + gPipeline.mExposureMap.swapFBORefs(gPipeline.mLastExposure); + + // Final render + + gDeferredPostNoDoFProgram.bind(); + + // From LLPipeline::renderFinalize: "Whatever is last in the above post processing chain should _always_ be rendered directly here. If not, expect problems." + gDeferredPostNoDoFProgram.bindTexture(LLShaderMgr::DEFERRED_DIFFUSE, &screen); + gDeferredPostNoDoFProgram.bindTexture(LLShaderMgr::DEFERRED_DEPTH, mBoundTarget, true); + + { + LLGLDepthTest depth_test(GL_TRUE, GL_TRUE, GL_ALWAYS); + gPipeline.mScreenTriangleVB->setBuffer(); + gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); + } + + gDeferredPostNoDoFProgram.unbind(); + + // Clean up + gPipeline.setupHWLights(); + gPipeline.mReflectionMapManager.forceDefaultProbeAndUpdateUniforms(false); + gSavedSettings.set("RenderLocalLightCount", old_local_light_count); + + return true; +} + +void LLGLTFPreviewTexture::postRender(bool success) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; + + if (!mShouldRender) { return; } + mShouldRender = false; + + LLViewerDynamicTexture::postRender(success); +} + +LLPointer LLGLTFMaterialPreviewMgr::getPreview(LLPointer &material) +{ + if (!material) + { + return nullptr; + } + + static LLCachedControl sUIPreviewMaterial(gSavedSettings, "UIPreviewMaterial", false); + if (!sUIPreviewMaterial) + { + fetch_texture_for_ui(material->mBaseColorTexture, material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR]); + return material->mBaseColorTexture; + } + + if (!is_material_loaded_enough_for_ui(*material)) + { + return nullptr; + } + + return LLGLTFPreviewTexture::create(material); +} diff --git a/indra/newview/llgltfmaterialpreviewmgr.h b/indra/newview/llgltfmaterialpreviewmgr.h new file mode 100644 index 0000000000..f320886157 --- /dev/null +++ b/indra/newview/llgltfmaterialpreviewmgr.h @@ -0,0 +1,78 @@ +/** + * @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; + 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(); + bool isFullyLoaded(); + 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 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/llheroprobemanager.cpp b/indra/newview/llheroprobemanager.cpp new file mode 100644 index 0000000000..ad76101181 --- /dev/null +++ b/indra/newview/llheroprobemanager.cpp @@ -0,0 +1,628 @@ +/** + * @file LLHeroProbeManager.cpp + * @brief LLHeroProbeManager class implementation + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llheroprobemanager.h" +#include "llreflectionmapmanager.h" +#include "llviewercamera.h" +#include "llspatialpartition.h" +#include "llviewerregion.h" +#include "pipeline.h" +#include "llviewershadermgr.h" +#include "llviewercontrol.h" +#include "llenvironment.h" +#include "llstartup.h" +#include "llagent.h" +#include "llagentcamera.h" +#include "llviewerwindow.h" +#include "llviewerjoystick.h" +#include "llviewermediafocus.h" + +extern bool gCubeSnapshot; +extern bool gTeleportDisplay; + +// get the next highest power of two of v (or v if v is already a power of two) +//defined in llvertexbuffer.cpp +extern U32 nhpo2(U32 v); + +static void touch_default_probe(LLReflectionMap* probe) +{ + if (LLViewerCamera::getInstance()) + { + LLVector3 origin = LLViewerCamera::getInstance()->getOrigin(); + origin.mV[2] += 64.f; + + probe->mOrigin.load3(origin.mV); + } +} + +LLHeroProbeManager::LLHeroProbeManager() +{ +} + +LLHeroProbeManager::~LLHeroProbeManager() +{ + cleanup(); + + mHeroVOList.clear(); + mNearestHero = nullptr; +} + +// helper class to seed octree with probes +void LLHeroProbeManager::update() +{ + if (!LLPipeline::RenderMirrors || !LLPipeline::sReflectionProbesEnabled || gTeleportDisplay || LLStartUp::getStartupState() < STATE_PRECACHE) + { + return; + } + + LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; + llassert(!gCubeSnapshot); // assert a snapshot is not in progress + if (LLAppViewer::instance()->logoutRequestSent()) + { + return; + } + + initReflectionMaps(); + + if (!mRenderTarget.isComplete()) + { + U32 color_fmt = GL_RGBA16F; + mRenderTarget.allocate(mProbeResolution, mProbeResolution, color_fmt, true); + } + + if (mMipChain.empty()) + { + U32 res = mProbeResolution; + U32 count = log2((F32)res) + 0.5f; + + mMipChain.resize(count); + for (int i = 0; i < count; ++i) + { + mMipChain[i].allocate(res, res, GL_RGBA16F); + res /= 2; + } + } + + llassert(mProbes[0] == mDefaultProbe); + + LLVector4a probe_pos; + LLVector3 camera_pos = LLViewerCamera::instance().mOrigin; + bool probe_present = false; + LLQuaternion cameraOrientation = LLViewerCamera::instance().getQuaternion(); + LLVector3 cameraDirection = LLVector3::z_axis * cameraOrientation; + + if (mHeroVOList.size() > 0) + { + // Find our nearest hero candidate. + float last_distance = 99999.f; + float camera_center_distance = 99999.f; + for (auto vo : mHeroVOList) + { + if (vo && !vo->isDead() && vo->mDrawable.notNull() && vo->isReflectionProbe() && vo->getReflectionProbeIsBox()) + { + float distance = (LLViewerCamera::instance().getOrigin() - vo->getPositionAgent()).magVec(); + float center_distance = cameraDirection * (vo->getPositionAgent() - camera_pos); + + if (distance > LLViewerCamera::instance().getFar()) + continue; + + LLVector4a center; + center.load3(vo->getPositionAgent().mV); + LLVector4a size; + + size.load3(vo->getScale().mV); + + bool visible = LLViewerCamera::instance().AABBInFrustum(center, size); + + if (distance < last_distance && center_distance < camera_center_distance && visible) + { + probe_present = true; + mNearestHero = vo; + last_distance = distance; + camera_center_distance = center_distance; + } + } + else + { + unregisterViewerObject(vo); + } + } + + // Don't even try to do anything if we didn't find a single mirror present. + if (!probe_present) + return; + + if (mNearestHero != nullptr && !mNearestHero->isDead() && mNearestHero->mDrawable.notNull()) + { + LLVector3 hero_pos = mNearestHero->getPositionAgent(); + LLVector3 face_normal = LLVector3(0, 0, 1); + + face_normal *= mNearestHero->mDrawable->getWorldRotation(); + face_normal.normalize(); + + LLVector3 offset = camera_pos - hero_pos; + LLVector3 project = face_normal * (offset * face_normal); + LLVector3 reject = offset - project; + LLVector3 point = (reject - project) + hero_pos; + + mCurrentClipPlane.setVec(hero_pos, face_normal); + mMirrorPosition = hero_pos; + mMirrorNormal = face_normal; + + probe_pos.load3(point.mV); + + // Detect visible faces of a cube based on camera direction and distance + + // Define the cube faces + static LLVector3 cubeFaces[6] = { + LLVector3(1, 0, 0), + LLVector3(-1, 0, 0), + LLVector3(0, 1, 0), + LLVector3(0, -1, 0), + LLVector3(0, 0, 1), + LLVector3(0, 0, -1) + }; + + // Iterate through each face of the cube + for (int i = 0; i < 6; i++) + { + float cube_facing = fmax(-1, fmin(1.0f, cameraDirection * cubeFaces[i])); + + cube_facing = 1 - cube_facing; + + mFaceUpdateList[i] = ceilf(cube_facing * gPipeline.RenderHeroProbeConservativeUpdateMultiplier); + } + + + mProbes[0]->mOrigin = probe_pos; + } + else + { + mNearestHero = nullptr; + } + + mHeroProbeStrength = 1; + } +} + +void LLHeroProbeManager::renderProbes() +{ + if (!LLPipeline::RenderMirrors || !LLPipeline::sReflectionProbesEnabled || gTeleportDisplay || + LLStartUp::getStartupState() < STATE_PRECACHE) + { + return; + } + + static LLCachedControl sDetail(gSavedSettings, "RenderHeroReflectionProbeDetail", -1); + static LLCachedControl sLevel(gSavedSettings, "RenderHeroReflectionProbeLevel", 3); + + F32 near_clip = 0.01f; + if (mNearestHero != nullptr && (gPipeline.RenderHeroProbeUpdateRate == 0 || (gFrameCount % gPipeline.RenderHeroProbeUpdateRate) == 0) && + !gTeleportDisplay && !gDisconnected && !LLAppViewer::instance()->logoutRequestSent()) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("hpmu - realtime"); + + bool radiance_pass = gPipeline.mReflectionMapManager.isRadiancePass(); + + gPipeline.mReflectionMapManager.mRadiancePass = true; + mRenderingMirror = true; + + doOcclusion(); + + for (U32 j = 0; j < mProbes.size(); j++) + { + for (U32 i = 0; i < 6; ++i) + { + if (mFaceUpdateList[i] > 0 && mCurrentProbeUpdateFrame % mFaceUpdateList[i] == 0) + { + updateProbeFace(mProbes[j], i, mNearestHero->getReflectionProbeIsDynamic() && sDetail > 0, near_clip); + mCurrentProbeUpdateFrame = 0; + } + } + generateRadiance(mProbes[j]); + } + mRenderingMirror = false; + + gPipeline.mReflectionMapManager.mRadiancePass = radiance_pass; + + mProbes[0]->mViewerObject = mNearestHero; + mProbes[0]->autoAdjustOrigin(); + } + + mCurrentProbeUpdateFrame++; +} + +// Do the reflection map update render passes. +// For every 12 calls of this function, one complete reflection probe radiance map and irradiance map is generated +// First six passes render the scene with direct lighting only into a scratch space cube map at the end of the cube map array and generate +// a simple mip chain (not convolution filter). +// At the end of these passes, an irradiance map is generated for this probe and placed into the irradiance cube map array at the index for this probe +// The next six passes render the scene with both radiance and irradiance into the same scratch space cube map and generate a simple mip chain. +// At the end of these passes, a radiance map is generated for this probe and placed into the radiance cube map array at the index for this probe. +// In effect this simulates single-bounce lighting. +void LLHeroProbeManager::updateProbeFace(LLReflectionMap* probe, U32 face, bool is_dynamic, F32 near_clip) +{ + // hacky hot-swap of camera specific render targets + gPipeline.mRT = &gPipeline.mHeroProbeRT; + + probe->update(mRenderTarget.getWidth(), face, is_dynamic, near_clip); + + gPipeline.mRT = &gPipeline.mMainRT; + + S32 sourceIdx = mReflectionProbeCount; + + // Unlike the reflectionmap manager, all probes are considered "realtime" for hero probes. + sourceIdx += 1; + + gGL.setColorMask(true, true); + LLGLDepthTest depth(GL_FALSE, GL_FALSE); + LLGLDisable cull(GL_CULL_FACE); + LLGLDisable blend(GL_BLEND); + + // downsample to placeholder map + { + gGL.matrixMode(gGL.MM_MODELVIEW); + gGL.pushMatrix(); + gGL.loadIdentity(); + + gGL.matrixMode(gGL.MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + + gGL.flush(); + U32 res = mProbeResolution * 2; + + static LLStaticHashedString resScale("resScale"); + static LLStaticHashedString direction("direction"); + static LLStaticHashedString znear("znear"); + static LLStaticHashedString zfar("zfar"); + + LLRenderTarget *screen_rt = &gPipeline.mHeroProbeRT.screen; + LLRenderTarget *depth_rt = &gPipeline.mHeroProbeRT.deferredScreen; + + // perform a gaussian blur on the super sampled render before downsampling + { + gGaussianProgram.bind(); + gGaussianProgram.uniform1f(resScale, 1.f / (mProbeResolution * 2)); + S32 diffuseChannel = gGaussianProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_TEXTURE); + + // horizontal + gGaussianProgram.uniform2f(direction, 1.f, 0.f); + gGL.getTexUnit(diffuseChannel)->bind(screen_rt); + mRenderTarget.bindTarget(); + gPipeline.mScreenTriangleVB->setBuffer(); + gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); + mRenderTarget.flush(); + + // vertical + gGaussianProgram.uniform2f(direction, 0.f, 1.f); + gGL.getTexUnit(diffuseChannel)->bind(&mRenderTarget); + screen_rt->bindTarget(); + gPipeline.mScreenTriangleVB->setBuffer(); + gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); + screen_rt->flush(); + gGaussianProgram.unbind(); + } + + S32 mips = log2((F32)mProbeResolution) + 0.5f; + + gReflectionMipProgram.bind(); + S32 diffuseChannel = gReflectionMipProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_TEXTURE); + S32 depthChannel = gReflectionMipProgram.enableTexture(LLShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_TEXTURE); + + for (int i = 0; i < mMipChain.size(); ++i) + { + LL_PROFILE_GPU_ZONE("probe mip"); + mMipChain[i].bindTarget(); + if (i == 0) + { + gGL.getTexUnit(diffuseChannel)->bind(screen_rt); + } + else + { + gGL.getTexUnit(diffuseChannel)->bind(&(mMipChain[i - 1])); + } + + gGL.getTexUnit(depthChannel)->bind(depth_rt, true); + + gReflectionMipProgram.uniform1f(resScale, 1.f / (mProbeResolution * 2)); + gReflectionMipProgram.uniform1f(znear, probe->getNearClip()); + gReflectionMipProgram.uniform1f(zfar, MAX_FAR_CLIP); + + gPipeline.mScreenTriangleVB->setBuffer(); + gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); + + res /= 2; + + S32 mip = i - (mMipChain.size() - mips); + + if (mip >= 0) + { + LL_PROFILE_GPU_ZONE("probe mip copy"); + mTexture->bind(0); + + glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, 0, 0, sourceIdx * 6 + face, 0, 0, res, res); + + mTexture->unbind(); + } + mMipChain[i].flush(); + } + + gGL.popMatrix(); + gGL.matrixMode(gGL.MM_MODELVIEW); + gGL.popMatrix(); + + gGL.getTexUnit(diffuseChannel)->unbind(LLTexUnit::TT_TEXTURE); + gReflectionMipProgram.unbind(); + } +} + +// Separate out radiance generation as a separate stage. +// This is to better enable independent control over how we generate radiance vs. having it coupled with processing the final face of the probe. +// Useful when we may not always be rendering a full set of faces of the probe. +void LLHeroProbeManager::generateRadiance(LLReflectionMap* probe) +{ + S32 sourceIdx = mReflectionProbeCount; + + // Unlike the reflectionmap manager, all probes are considered "realtime" for hero probes. + sourceIdx += 1; + { + mMipChain[0].bindTarget(); + static LLStaticHashedString sSourceIdx("sourceIdx"); + + { + // generate radiance map (even if this is not the irradiance map, we need the mip chain for the irradiance map) + gHeroRadianceGenProgram.bind(); + mVertexBuffer->setBuffer(); + + S32 channel = gHeroRadianceGenProgram.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY); + mTexture->bind(channel); + gHeroRadianceGenProgram.uniform1i(sSourceIdx, sourceIdx); + gHeroRadianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_MAX_LOD, mMaxProbeLOD); + gHeroRadianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_STRENGTH, mHeroProbeStrength); + + U32 res = mMipChain[0].getWidth(); + + for (int i = 0; i < mMipChain.size() / 4; ++i) + { + LL_PROFILE_GPU_ZONE("probe radiance gen"); + static LLStaticHashedString sMipLevel("mipLevel"); + static LLStaticHashedString sRoughness("roughness"); + static LLStaticHashedString sWidth("u_width"); + static LLStaticHashedString sStrength("probe_strength"); + + gHeroRadianceGenProgram.uniform1f(sRoughness, (F32) i / (F32) (mMipChain.size() - 1)); + gHeroRadianceGenProgram.uniform1f(sMipLevel, i); + gHeroRadianceGenProgram.uniform1i(sWidth, mProbeResolution); + gHeroRadianceGenProgram.uniform1f(sStrength, 1); + + for (int cf = 0; cf < 6; ++cf) + { // for each cube face + LLCoordFrame frame; + frame.lookAt(LLVector3(0, 0, 0), LLCubeMapArray::sClipToCubeLookVecs[cf], LLCubeMapArray::sClipToCubeUpVecs[cf]); + + F32 mat[16]; + frame.getOpenGLRotation(mat); + gGL.loadMatrix(mat); + + mVertexBuffer->drawArrays(gGL.TRIANGLE_STRIP, 0, 4); + + glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, i, 0, 0, probe->mCubeIndex * 6 + cf, 0, 0, res, res); + } + + if (i != mMipChain.size() - 1) + { + res /= 2; + glViewport(0, 0, res, res); + } + } + + gHeroRadianceGenProgram.unbind(); + } + + mMipChain[0].flush(); + } +} + +void LLHeroProbeManager::updateUniforms() +{ + if (!gPipeline.RenderMirrors) + { + return; + } + + LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; + + LLMatrix4a modelview; + modelview.loadu(gGLModelView); + LLVector4a oa; // scratch space for transformed origin + oa.set(0, 0, 0, 0); + mHeroData.heroProbeCount = 1; + + if (mNearestHero != nullptr && !mNearestHero->isDead()) + { + if (mNearestHero->getReflectionProbeIsBox()) + { + LLVector3 s = mNearestHero->getScale().scaledVec(LLVector3(0.5f, 0.5f, 0.5f)); + mProbes[0]->mRadius = s.magVec(); + } + else + { + mProbes[0]->mRadius = mNearestHero->getScale().mV[0] * 0.5f; + } + + modelview.affineTransform(mProbes[0]->mOrigin, oa); + mHeroData.heroShape = 0; + if (!mProbes[0]->getBox(mHeroData.heroBox)) + { + mHeroData.heroShape = 1; + } + + mHeroData.heroSphere.set(oa.getF32ptr()); + mHeroData.heroSphere.mV[3] = mProbes[0]->mRadius; + } + + mHeroData.heroMipCount = mMipChain.size(); +} + +void LLHeroProbeManager::renderDebug() +{ + gDebugProgram.bind(); + + for (auto& probe : mProbes) + { + renderReflectionProbe(probe); + } + + gDebugProgram.unbind(); +} + + +void LLHeroProbeManager::initReflectionMaps() +{ + U32 count = LL_MAX_HERO_PROBE_COUNT; + + if ((mTexture.isNull() || mReflectionProbeCount != count || mReset) && LLPipeline::RenderMirrors) + { + + if (mReset) + { + cleanup(); + } + + mReset = false; + mReflectionProbeCount = count; + mProbeResolution = gSavedSettings.getS32("RenderHeroProbeResolution"); + mMaxProbeLOD = log2f(mProbeResolution) - 1.f; // number of mips - 1 + + mTexture = new LLCubeMapArray(); + + // store mReflectionProbeCount+2 cube maps, final two cube maps are used for render target and radiance map generation source) + mTexture->allocate(mProbeResolution, 3, mReflectionProbeCount + 2); + + if (mDefaultProbe.isNull()) + { + llassert(mProbes.empty()); // default probe MUST be the first probe created + mDefaultProbe = new LLReflectionMap(); + mProbes.push_back(mDefaultProbe); + } + + llassert(mProbes[0] == mDefaultProbe); + + // For hero probes, we treat this as the main mirror probe. + + mDefaultProbe->mCubeIndex = 0; + mDefaultProbe->mCubeArray = mTexture; + mDefaultProbe->mDistance = gSavedSettings.getF32("RenderHeroProbeDistance"); + mDefaultProbe->mRadius = 4096.f; + mDefaultProbe->mProbeIndex = 0; + touch_default_probe(mDefaultProbe); + + mProbes.push_back(mDefaultProbe); + } + + if (mVertexBuffer.isNull()) + { + U32 mask = LLVertexBuffer::MAP_VERTEX; + LLPointer buff = new LLVertexBuffer(mask); + buff->allocateBuffer(4, 0); + + LLStrider v; + + buff->getVertexStrider(v); + + v[0] = LLVector3(-1, -1, -1); + v[1] = LLVector3(1, -1, -1); + v[2] = LLVector3(-1, 1, -1); + v[3] = LLVector3(1, 1, -1); + + buff->unmapBuffer(); + + mVertexBuffer = buff; + } +} + +void LLHeroProbeManager::cleanup() +{ + mVertexBuffer = nullptr; + mRenderTarget.release(); + mHeroRenderTarget.release(); + + mMipChain.clear(); + + mTexture = nullptr; + + mProbes.clear(); + + mReflectionMaps.clear(); + + mDefaultProbe = nullptr; + mUpdatingProbe = nullptr; +} + +void LLHeroProbeManager::doOcclusion() +{ + LLVector4a eye; + eye.load3(LLViewerCamera::instance().getOrigin().mV); + + for (auto& probe : mProbes) + { + if (probe != nullptr && probe != mDefaultProbe) + { + probe->doOcclusion(eye); + } + } +} + +void LLHeroProbeManager::reset() +{ + mReset = true; +} + +bool LLHeroProbeManager::registerViewerObject(LLVOVolume* drawablep) +{ + llassert(drawablep != nullptr); + + if (std::find(mHeroVOList.begin(), mHeroVOList.end(), drawablep) == mHeroVOList.end()) + { + // Probe isn't in our list for consideration. Add it. + mHeroVOList.push_back(drawablep); + return true; + } + + return false; +} + +void LLHeroProbeManager::unregisterViewerObject(LLVOVolume* drawablep) +{ + std::vector>::iterator found_itr = std::find(mHeroVOList.begin(), mHeroVOList.end(), drawablep); + if (found_itr != mHeroVOList.end()) + { + mHeroVOList.erase(found_itr); + } +} diff --git a/indra/newview/llheroprobemanager.h b/indra/newview/llheroprobemanager.h new file mode 100644 index 0000000000..e45b0049b2 --- /dev/null +++ b/indra/newview/llheroprobemanager.h @@ -0,0 +1,159 @@ +/** + * @file llheroprobemanager.h + * @brief LLHeroProbeManager class declaration + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#pragma once + +#include "llreflectionmap.h" +#include "llrendertarget.h" +#include "llcubemaparray.h" +#include "llcubemap.h" +#include "lldrawable.h" + +class LLSpatialGroup; +class LLViewerObject; + +// number of reflection probes to keep in vram +#define LL_MAX_HERO_PROBE_COUNT 2 + +struct HeroProbeData +{ + LLMatrix4 heroBox; + LLVector4 heroSphere; + GLint heroShape; + GLint heroMipCount; + GLint heroProbeCount; +}; + +class alignas(16) LLHeroProbeManager +{ + LL_ALIGN_NEW +public: + enum class DetailLevel + { + STATIC_ONLY = 0, + STATIC_AND_DYNAMIC, + REALTIME = 2 + }; + + // allocate an environment map of the given resolution + LLHeroProbeManager(); + ~LLHeroProbeManager(); + + // release any GL state + void cleanup(); + + // maintain reflection probes + void update(); + + void renderProbes(); + + // debug display, called from llspatialpartition if reflection + // probe debug display is active + void renderDebug(); + + // call once at startup to allocate cubemap arrays + void initReflectionMaps(); + + // perform occlusion culling on all active reflection probes + void doOcclusion(); + + void reset(); + + bool registerViewerObject(LLVOVolume *drawablep); + void unregisterViewerObject(LLVOVolume* drawablep); + + bool isMirrorPass() const { return mRenderingMirror; } + + LLVector3 mMirrorPosition; + LLVector3 mMirrorNormal; + HeroProbeData mHeroData; + +private: + friend class LLPipeline; + friend class LLReflectionMapManager; + + // update UBO used for rendering (call only once per render pipe flush) + void updateUniforms(); + + // bind UBO used for rendering + + // render target for cube snapshots + // used to generate mipmaps without doing a copy-to-texture + LLRenderTarget mRenderTarget; + + LLRenderTarget mHeroRenderTarget; + + std::vector mMipChain; + + // storage for reflection probe radiance maps (plus two scratch space cubemaps) + LLPointer mTexture; + + // vertex buffer for pushing verts to filter shaders + LLPointer mVertexBuffer; + + LLPlane mCurrentClipPlane; + + + // update the specified face of the specified probe + void updateProbeFace(LLReflectionMap* probe, U32 face, bool is_dynamic, F32 near_clip); + void generateRadiance(LLReflectionMap *probe); + + // list of active reflection maps + std::vector> mProbes; + + // list of maps being used for rendering + std::vector mReflectionMaps; + + LLReflectionMap* mUpdatingProbe = nullptr; + + LLPointer mDefaultProbe; // default reflection probe to fall back to for pixels with no probe influences (should always be at cube index 0) + + // number of reflection probes to use for rendering + U32 mReflectionProbeCount; + + // resolution of reflection probes + U32 mProbeResolution = 1024; + + // maximum LoD of reflection probes (mip levels - 1) + F32 mMaxProbeLOD = 6.f; + + F32 mHeroProbeStrength = 1.f; + bool mIsInTransition = false; + + // if true, reset all probe render state on the next update (for teleports and sky changes) + bool mReset = false; + + bool mRenderingMirror = false; + std::map mFaceUpdateList; + + U32 mCurrentProbeUpdateFrame = 0; + + std::vector> mHeroVOList; + LLPointer mNearestHero; + + +}; + diff --git a/indra/newview/llmanip.cpp b/indra/newview/llmanip.cpp index 1db90873a8..1abff3cd7b 100644 --- a/indra/newview/llmanip.cpp +++ b/indra/newview/llmanip.cpp @@ -357,9 +357,16 @@ LLVector3 LLManip::getSavedPivotPoint() const LLVector3 LLManip::getPivotPoint() { + // Pivot point controls - //if (mObjectSelection->getFirstObject() && mObjectSelection->getObjectCount() == 1 && mObjectSelection->getSelectType() != SELECT_TYPE_HUD) + //LLViewerObject* object = mObjectSelection->getFirstObject(); + //if (object && mObjectSelection->getObjectCount() == 1 && mObjectSelection->getSelectType() != SELECT_TYPE_HUD) //{ + // LLSelectNode* select_node = mObjectSelection->getFirstNode(); + // if (select_node->mSelectedGLTFNode != -1) + // { + // return object->getGLTFNodePositionAgent(select_node->mSelectedGLTFNode); + // } // return mObjectSelection->getFirstObject()->getPivotPositionAgent(); //} //return LLSelectMgr::getInstance()->getBBoxOfSelection().getCenterAgent(); @@ -377,7 +384,15 @@ LLVector3 LLManip::getPivotPoint() LLViewerObject* root_object = mObjectSelection->getFirstRootObject(children_ok); if (root_object && (mObjectSelection->getObjectCount() == 1 || sActualRoot) && mObjectSelection->getSelectType() != SELECT_TYPE_HUD) { - pos = root_object->getPivotPositionAgent(); + LLSelectNode* select_node = mObjectSelection->getFirstNode(); + if (select_node->mSelectedGLTFNode != -1) + { + pos = root_object->getGLTFNodePositionAgent(select_node->mSelectedGLTFNode); + } + else + { + pos = root_object->getPivotPositionAgent(); + } scale = root_object->getScale(); rot = root_object->getRotation(); } diff --git a/indra/newview/llmaniprotate.cpp b/indra/newview/llmaniprotate.cpp index c2f4200852..5bdf3f81b5 100644 --- a/indra/newview/llmaniprotate.cpp +++ b/indra/newview/llmaniprotate.cpp @@ -556,6 +556,7 @@ void LLManipRotate::drag( S32 x, S32 y ) bool damped = mSmoothRotate; mSmoothRotate = false; + bool gltf_mode = false; for (LLObjectSelection::iterator iter = mObjectSelection->begin(); iter != mObjectSelection->end(); iter++) @@ -569,151 +570,174 @@ void LLManipRotate::drag( S32 x, S32 y ) ((root_object == NULL) || !root_object->isPermanentEnforced()) && (object->isRootEdit() || selectNode->mIndividualSelection)) { - if (!object->isRootEdit()) + + if (selectNode->mSelectedGLTFNode != -1) { - // child objects should not update if parent is selected - LLViewerObject* editable_root = (LLViewerObject*)object->getParent(); - if (editable_root->isSelected()) + LLQuaternion new_rot = selectNode->mSavedRotation * mRotation; + + object->setGLTFNodeRotationAgent(selectNode->mSelectedGLTFNode, new_rot); + + gltf_mode = true; + } + else if (!gltf_mode) + { + if (!object->isRootEdit()) { - // we will be moved properly by our parent, so skip - continue; - } - } - - LLQuaternion new_rot = selectNode->mSavedRotation * mRotation; - std::vector& child_positions = object->mUnselectedChildrenPositions ; - std::vector child_rotations; - if (object->isRootEdit() && selectNode->mIndividualSelection) - { - object->saveUnselectedChildrenRotation(child_rotations) ; - object->saveUnselectedChildrenPosition(child_positions) ; - } - - if (object->getParent() && object->mDrawable.notNull()) - { - LLQuaternion invParentRotation = object->mDrawable->mXform.getParent()->getWorldRotation(); - invParentRotation.transQuat(); - - object->setRotation(new_rot * invParentRotation, damped); - rebuild(object); - } - else - { - object->setRotation(new_rot, damped); - LLVOAvatar* avatar = object->asAvatar(); - if (avatar && avatar->isSelf() - && LLSelectMgr::getInstance()->mAllowSelectAvatar - && !object->getParent()) - { - // Normal avatars use object's orienttion, but self uses - // separate LLCoordFrame - // See LVOAvatar::updateOrientation() - if (gAgentCamera.getFocusOnAvatar()) + // child objects should not update if parent is selected + LLViewerObject* editable_root = (LLViewerObject*)object->getParent(); + if (editable_root->isSelected()) { - //Don't rotate camera with avatar - gAgentCamera.setFocusOnAvatar(false, false, false); + // we will be moved properly by our parent, so skip + continue; } - - LLVector3 at_axis = mAgentSelfAtAxis; - at_axis *= mRotation; - at_axis.mV[VZ] = 0.f; - at_axis.normalize(); - gAgent.resetAxes(at_axis); } - rebuild(object); - } - // for individually selected roots, we need to counterrotate all the children - if (object->isRootEdit() && selectNode->mIndividualSelection) - { - //RN: must do non-damped updates on these objects so relative rotation appears constant - // instead of having two competing slerps making the child objects appear to "wobble" - object->resetChildrenRotationAndPosition(child_rotations, child_positions) ; + LLQuaternion new_rot = selectNode->mSavedRotation * mRotation; + std::vector& child_positions = object->mUnselectedChildrenPositions; + std::vector child_rotations; + if (object->isRootEdit() && selectNode->mIndividualSelection) + { + object->saveUnselectedChildrenRotation(child_rotations); + object->saveUnselectedChildrenPosition(child_positions); + } + + if (object->getParent() && object->mDrawable.notNull()) + { + LLQuaternion invParentRotation = object->mDrawable->mXform.getParent()->getWorldRotation(); + invParentRotation.transQuat(); + + object->setRotation(new_rot * invParentRotation, damped); + rebuild(object); + } + else + { + object->setRotation(new_rot, damped); + LLVOAvatar* avatar = object->asAvatar(); + if (avatar && avatar->isSelf() + && LLSelectMgr::getInstance()->mAllowSelectAvatar + && !object->getParent()) + { + // Normal avatars use object's orienttion, but self uses + // separate LLCoordFrame + // See LVOAvatar::updateOrientation() + if (gAgentCamera.getFocusOnAvatar()) + { + //Don't rotate camera with avatar + gAgentCamera.setFocusOnAvatar(false, false, false); + } + + LLVector3 at_axis = mAgentSelfAtAxis; + at_axis *= mRotation; + at_axis.mV[VZ] = 0.f; + at_axis.normalize(); + gAgent.resetAxes(at_axis); + } + rebuild(object); + } + + // for individually selected roots, we need to counterrotate all the children + if (object->isRootEdit() && selectNode->mIndividualSelection) + { + //RN: must do non-damped updates on these objects so relative rotation appears constant + // instead of having two competing slerps making the child objects appear to "wobble" + object->resetChildrenRotationAndPosition(child_rotations, child_positions); + } } } } // update positions - for (LLObjectSelection::iterator iter = mObjectSelection->begin(); - iter != mObjectSelection->end(); iter++) + if (!gltf_mode) { - LLSelectNode* selectNode = *iter; - LLViewerObject* object = selectNode->getObject(); - LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit(); - - // to avoid cumulative position changes we calculate the objects new position using its saved position - if (object && object->permMove() && !object->isPermanentEnforced() && - ((root_object == NULL) || !root_object->isPermanentEnforced())) + for (LLObjectSelection::iterator iter = mObjectSelection->begin(); + iter != mObjectSelection->end(); iter++) { - LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter ); + LLSelectNode* selectNode = *iter; + LLViewerObject* object = selectNode->getObject(); + LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit(); - LLVector3 old_position; - LLVector3 new_position; - if (object->isAttachment() && object->mDrawable.notNull()) + // to avoid cumulative position changes we calculate the objects new position using its saved position + if (object && object->permMove() && !object->isPermanentEnforced() && + ((root_object == NULL) || !root_object->isPermanentEnforced())) { - // need to work in drawable space to handle selected items from multiple attachments - // (which have no shared frame of reference other than their render positions) - LLXform* parent_xform = object->mDrawable->getXform()->getParent(); - new_position = (selectNode->mSavedPositionLocal * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition(); - old_position = (object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();//object->getRenderPosition(); - } - else - { - new_position = gAgent.getPosAgentFromGlobal( selectNode->mSavedPositionGlobal ); - old_position = object->getPositionAgent(); - } + LLVector3 center = gAgent.getPosAgentFromGlobal(mRotationCenter); - new_position = (new_position - center) * mRotation; // new relative rotated position - new_position += center; + LLVector3 old_position; + LLVector3 new_position; - if (object->isRootEdit() && !object->isAttachment()) - { - LLVector3d new_pos_global = gAgent.getPosGlobalFromAgent(new_position); - new_pos_global = LLWorld::getInstance()->clipToVisibleRegions(selectNode->mSavedPositionGlobal, new_pos_global); - new_position = gAgent.getPosAgentFromGlobal(new_pos_global); - } - - // for individually selected child objects - if (!object->isRootEdit() && selectNode->mIndividualSelection) - { - LLViewerObject* parentp = (LLViewerObject*)object->getParent(); - if (!parentp->isSelected()) + if (selectNode->mSelectedGLTFNode != -1) { - if (object->isAttachment() && object->mDrawable.notNull()) - { - // find position relative to render position of parent - object->setPosition((new_position - parentp->getRenderPosition()) * ~parentp->getRenderRotation()); - rebuild(object); - } - else - { - object->setPositionParent((new_position - parentp->getPositionAgent()) * ~parentp->getRotationRegion()); - rebuild(object); - } - } - } - else if (object->isRootEdit()) - { - if (object->isAttachment() && object->mDrawable.notNull()) - { - LLXform* parent_xform = object->mDrawable->getXform()->getParent(); - object->setPosition((new_position - parent_xform->getWorldPosition()) * ~parent_xform->getWorldRotation()); - rebuild(object); + } else { - object->setPositionAgent(new_position); - rebuild(object); - } - } + if (object->isAttachment() && object->mDrawable.notNull()) + { + // need to work in drawable space to handle selected items from multiple attachments + // (which have no shared frame of reference other than their render positions) + LLXform* parent_xform = object->mDrawable->getXform()->getParent(); + new_position = (selectNode->mSavedPositionLocal * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition(); + old_position = (object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();//object->getRenderPosition(); + } + else + { + new_position = gAgent.getPosAgentFromGlobal(selectNode->mSavedPositionGlobal); + old_position = object->getPositionAgent(); + } - // for individually selected roots, we need to counter-translate all unselected children - if (object->isRootEdit() && selectNode->mIndividualSelection) - { - // only offset by parent's translation as we've already countered parent's rotation - rebuild(object); - object->resetChildrenPosition(old_position - new_position) ; + new_position = (new_position - center) * mRotation; // new relative rotated position + new_position += center; + + if (object->isRootEdit() && !object->isAttachment()) + { + LLVector3d new_pos_global = gAgent.getPosGlobalFromAgent(new_position); + new_pos_global = LLWorld::getInstance()->clipToVisibleRegions(selectNode->mSavedPositionGlobal, new_pos_global); + new_position = gAgent.getPosAgentFromGlobal(new_pos_global); + } + + // for individually selected child objects + if (!object->isRootEdit() && selectNode->mIndividualSelection) + { + LLViewerObject* parentp = (LLViewerObject*)object->getParent(); + if (!parentp->isSelected()) + { + if (object->isAttachment() && object->mDrawable.notNull()) + { + // find position relative to render position of parent + object->setPosition((new_position - parentp->getRenderPosition()) * ~parentp->getRenderRotation()); + rebuild(object); + } + else + { + object->setPositionParent((new_position - parentp->getPositionAgent()) * ~parentp->getRotationRegion()); + rebuild(object); + } + } + } + else if (object->isRootEdit()) + { + if (object->isAttachment() && object->mDrawable.notNull()) + { + LLXform* parent_xform = object->mDrawable->getXform()->getParent(); + object->setPosition((new_position - parent_xform->getWorldPosition()) * ~parent_xform->getWorldRotation()); + rebuild(object); + } + else + { + object->setPositionAgent(new_position); + rebuild(object); + } + } + + // for individually selected roots, we need to counter-translate all unselected children + if (object->isRootEdit() && selectNode->mIndividualSelection) + { + // only offset by parent's translation as we've already countered parent's rotation + rebuild(object); + object->resetChildrenPosition(old_position - new_position); + } + } } } } @@ -725,12 +749,13 @@ void LLManipRotate::drag( S32 x, S32 y ) LLSelectNode* selectNode = *iter; LLViewerObject*cur = selectNode->getObject(); LLViewerObject *root_object = (cur == NULL) ? NULL : cur->getRootEdit(); + if( cur->permModify() && cur->permMove() && !cur->isPermanentEnforced() && ((root_object == NULL) || !root_object->isPermanentEnforced()) && (!cur->isAvatar() || LLSelectMgr::getInstance()->mAllowSelectAvatar)) { - selectNode->mLastRotation = cur->getRotation(); - selectNode->mLastPositionLocal = cur->getPosition(); + selectNode->mLastRotation = cur->getRotation(); + selectNode->mLastPositionLocal = cur->getPosition(); } } diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp index 420b23acb4..fd1d6bb453 100644 --- a/indra/newview/llmaniptranslate.cpp +++ b/indra/newview/llmaniptranslate.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llmaniptranslate.cpp * @brief LLManipTranslate class implementation * @@ -677,119 +677,131 @@ bool LLManipTranslate::handleHover(S32 x, S32 y, MASK mask) LLVector3 clamped_relative_move_f = (F32)axis_magnitude * axis_f; // scalar multiply for (LLObjectSelection::iterator iter = mObjectSelection->begin(); - iter != mObjectSelection->end(); iter++) + iter != mObjectSelection->end(); iter++) { LLSelectNode* selectNode = *iter; LLViewerObject* object = selectNode->getObject(); - // Only apply motion to root objects and objects selected - // as "individual". - if (!object->isRootEdit() && !selectNode->mIndividualSelection) + if (selectNode->mSelectedGLTFNode != -1) { - continue; + // manipulating a GLTF node + clamped_relative_move_f -= selectNode->mLastMoveLocal; + object->moveGLTFNode(selectNode->mSelectedGLTFNode, clamped_relative_move_f); + selectNode->mLastMoveLocal += clamped_relative_move_f; } - - if (!object->isRootEdit()) + else { - // child objects should not update if parent is selected - LLViewerObject* editable_root = (LLViewerObject*)object->getParent(); - if (editable_root->isSelected()) + // Only apply motion to root objects and objects selected + // as "individual". + if (!object->isRootEdit() && !selectNode->mIndividualSelection) { - // we will be moved properly by our parent, so skip continue; } - } - LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit(); - if (object->permMove() && !object->isPermanentEnforced() && - ((root_object == NULL) || !root_object->isPermanentEnforced())) - { - // handle attachments in local space - if (object->isAttachment() && object->mDrawable.notNull()) + if (!object->isRootEdit()) { - // calculate local version of relative move - LLQuaternion objWorldRotation = object->mDrawable->mXform.getParent()->getWorldRotation(); - objWorldRotation.transQuat(); - - LLVector3 old_position_local = object->getPosition(); - LLVector3 new_position_local = selectNode->mSavedPositionLocal + (clamped_relative_move_f * objWorldRotation); - - //RN: I forget, but we need to do this because of snapping which doesn't often result - // in position changes even when the mouse moves - object->setPosition(new_position_local); - rebuild(object); - gAgentAvatarp->clampAttachmentPositions(); - new_position_local = object->getPosition(); - - if (selectNode->mIndividualSelection) + // child objects should not update if parent is selected + LLViewerObject* editable_root = (LLViewerObject*)object->getParent(); + if (editable_root->isSelected()) { - // counter-translate child objects if we are moving the root as an individual - object->resetChildrenPosition(old_position_local - new_position_local, true) ; + // we will be moved properly by our parent, so skip + continue; } } - else + + LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit(); + if (object->permMove() && !object->isPermanentEnforced() && + ((root_object == NULL) || !root_object->isPermanentEnforced())) { - // compute new position to send to simulators, but don't set it yet. - // We need the old position to know which simulator to send the move message to. - LLVector3d new_position_global = selectNode->mSavedPositionGlobal + clamped_relative_move; + // handle attachments in local space + if (object->isAttachment() && object->mDrawable.notNull()) + { + // calculate local version of relative move + LLQuaternion objWorldRotation = object->mDrawable->mXform.getParent()->getWorldRotation(); + objWorldRotation.transQuat(); - // Don't let object centers go too far underground - F64 min_height = LLWorld::getInstance()->getMinAllowedZ(object, object->getPositionGlobal()); - if (new_position_global.mdV[VZ] < min_height) - { - new_position_global.mdV[VZ] = min_height; - } + LLVector3 old_position_local = object->getPosition(); + LLVector3 new_position_local = selectNode->mSavedPositionLocal + (clamped_relative_move_f * objWorldRotation); - // For safety, cap heights where objects can be dragged -// -// if (new_position_global.mdV[VZ] > MAX_OBJECT_Z) -// { -// new_position_global.mdV[VZ] = MAX_OBJECT_Z; -// } - if (new_position_global.mdV[VZ] > LLWorld::getInstance()->getRegionMaxHeight()) - { - new_position_global.mdV[VZ] = LLWorld::getInstance()->getRegionMaxHeight(); - } -// - // Grass is always drawn on the ground, so clamp its position to the ground - if (object->getPCode() == LL_PCODE_LEGACY_GRASS) - { - new_position_global.mdV[VZ] = LLWorld::getInstance()->resolveLandHeightGlobal(new_position_global) + 1.f; - } - - if (object->isRootEdit()) - { - new_position_global = LLWorld::getInstance()->clipToVisibleRegions(object->getPositionGlobal(), new_position_global); - } - - // PR: Only update if changed - LLVector3 old_position_agent = object->getPositionAgent(); - LLVector3 new_position_agent = gAgent.getPosAgentFromGlobal(new_position_global); - if (object->isRootEdit()) - { - // finally, move parent object after children have calculated new offsets - object->setPositionAgent(new_position_agent); + //RN: I forget, but we need to do this because of snapping which doesn't often result + // in position changes even when the mouse moves + object->setPosition(new_position_local); rebuild(object); + gAgentAvatarp->clampAttachmentPositions(); + new_position_local = object->getPosition(); + + if (selectNode->mIndividualSelection) + { + // counter-translate child objects if we are moving the root as an individual + object->resetChildrenPosition(old_position_local - new_position_local, true); + } } else { - LLViewerObject* root_object = object->getRootEdit(); - new_position_agent -= root_object->getPositionAgent(); - new_position_agent = new_position_agent * ~root_object->getRotation(); - object->setPositionParent(new_position_agent, false); - rebuild(object); - } + // compute new position to send to simulators, but don't set it yet. + // We need the old position to know which simulator to send the move message to. + LLVector3d new_position_global = selectNode->mSavedPositionGlobal + clamped_relative_move; - if (selectNode->mIndividualSelection) - { - // counter-translate child objects if we are moving the root as an individual - object->resetChildrenPosition(old_position_agent - new_position_agent, true) ; + // Don't let object centers go too far underground + F64 min_height = LLWorld::getInstance()->getMinAllowedZ(object, object->getPositionGlobal()); + if (new_position_global.mdV[VZ] < min_height) + { + new_position_global.mdV[VZ] = min_height; + } + // For safety, cap heights where objects can be dragged +// +// if (new_position_global.mdV[VZ] > MAX_OBJECT_Z) +// { +// new_position_global.mdV[VZ] = MAX_OBJECT_Z; +// } + if (new_position_global.mdV[VZ] > LLWorld::getInstance()->getRegionMaxHeight()) + { + new_position_global.mdV[VZ] = LLWorld::getInstance()->getRegionMaxHeight(); + } + +// + + // Grass is always drawn on the ground, so clamp its position to the ground + if (object->getPCode() == LL_PCODE_LEGACY_GRASS) + { + new_position_global.mdV[VZ] = LLWorld::getInstance()->resolveLandHeightGlobal(new_position_global) + 1.f; + } + + if (object->isRootEdit()) + { + new_position_global = LLWorld::getInstance()->clipToVisibleRegions(object->getPositionGlobal(), new_position_global); + } + + // PR: Only update if changed + LLVector3 old_position_agent = object->getPositionAgent(); + LLVector3 new_position_agent = gAgent.getPosAgentFromGlobal(new_position_global); + if (object->isRootEdit()) + { + // finally, move parent object after children have calculated new offsets + object->setPositionAgent(new_position_agent); + rebuild(object); + } + else + { + LLViewerObject* root_object = object->getRootEdit(); + new_position_agent -= root_object->getPositionAgent(); + new_position_agent = new_position_agent * ~root_object->getRotation(); + object->setPositionParent(new_position_agent, false); + rebuild(object); + } + + if (selectNode->mIndividualSelection) + { + // counter-translate child objects if we are moving the root as an individual + object->resetChildrenPosition(old_position_agent - new_position_agent, true); + } } + selectNode->mLastPositionLocal = object->getPosition(); } - selectNode->mLastPositionLocal = object->getPosition(); } } + LLSelectMgr::getInstance()->updateSelectionCenter(); gAgentCamera.clearFocusObject(); dialog_refresh_all(); // ??? is this necessary? diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index cc75344fb4..0f91dc5eb7 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -492,11 +492,7 @@ bool LLMaterialEditor::postBuild() } else { - S32 upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(); - getChild("base_color_upload_fee")->setTextArg("[FEE]", llformat("%d", upload_cost)); - getChild("metallic_upload_fee")->setTextArg("[FEE]", llformat("%d", upload_cost)); - getChild("emissive_upload_fee")->setTextArg("[FEE]", llformat("%d", upload_cost)); - getChild("normal_upload_fee")->setTextArg("[FEE]", llformat("%d", upload_cost)); + refreshUploadCost(); } boost::function changes_callback = [this](LLUICtrl * ctrl, void* userData) @@ -815,6 +811,37 @@ void LLMaterialEditor::resetUnsavedChanges() } } +void LLMaterialEditor::refreshUploadCost() +{ + mExpectedUploadCost = 0; + if (mBaseColorTextureUploadId.notNull() && mBaseColorTextureUploadId == getBaseColorId() && mBaseColorFetched) + { + S32 upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(mBaseColorFetched); + mExpectedUploadCost += upload_cost; + getChild("base_color_upload_fee")->setTextArg("[FEE]", llformat("%d", upload_cost)); + } + if (mMetallicTextureUploadId.notNull() && mMetallicTextureUploadId == getMetallicRoughnessId() && mMetallicRoughnessFetched) + { + S32 upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(mMetallicRoughnessFetched); + mExpectedUploadCost += upload_cost; + getChild("metallic_upload_fee")->setTextArg("[FEE]", llformat("%d", upload_cost)); + } + if (mEmissiveTextureUploadId.notNull() && mEmissiveTextureUploadId == getEmissiveId() && mEmissiveFetched) + { + S32 upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(mEmissiveFetched); + mExpectedUploadCost += upload_cost; + getChild("emissive_upload_fee")->setTextArg("[FEE]", llformat("%d", upload_cost)); + } + if (mNormalTextureUploadId.notNull() && mNormalTextureUploadId == getNormalId() && mNormalFetched) + { + S32 upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(mNormalFetched); + mExpectedUploadCost += upload_cost; + getChild("normal_upload_fee")->setTextArg("[FEE]", llformat("%d", upload_cost)); + } + + getChild("total_upload_fee")->setTextArg("[FEE]", llformat("%d", mExpectedUploadCost)); +} + void LLMaterialEditor::markChangesUnsaved(U32 dirty_flag) { mUnsavedChanges |= dirty_flag; @@ -845,26 +872,15 @@ void LLMaterialEditor::markChangesUnsaved(U32 dirty_flag) setCanSave(false); } - S32 upload_texture_count = 0; - if (mBaseColorTextureUploadId.notNull() && mBaseColorTextureUploadId == getBaseColorId()) + if ((dirty_flag & MATERIAL_BASE_COLOR_TEX_DIRTY) + || (dirty_flag & MATERIAL_NORMAL_TEX_DIRTY) + || (dirty_flag & MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY) + || (dirty_flag & MATERIAL_EMISIVE_TEX_DIRTY) + || (dirty_flag == 0) + || (dirty_flag == U32_MAX)) { - upload_texture_count++; + refreshUploadCost(); } - if (mMetallicTextureUploadId.notNull() && mMetallicTextureUploadId == getMetallicRoughnessId()) - { - upload_texture_count++; - } - if (mEmissiveTextureUploadId.notNull() && mEmissiveTextureUploadId == getEmissiveId()) - { - upload_texture_count++; - } - if (mNormalTextureUploadId.notNull() && mNormalTextureUploadId == getNormalId()) - { - upload_texture_count++; - } - - mExpectedUploadCost = upload_texture_count * LLAgentBenefitsMgr::current().getTextureUploadCost(); - getChild("total_upload_fee")->setTextArg("[FEE]", llformat("%d", mExpectedUploadCost)); } void LLMaterialEditor::setCanSaveAs(bool value) @@ -1873,7 +1889,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; } @@ -2127,7 +2143,7 @@ bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vectorgetData(), img->getDataSize()); - U32 expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(); - + U32 expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(img); LLSD key = getKey(); std::function failed_upload([key](LLUUID assetId, LLSD response, std::string reason) { diff --git a/indra/newview/llmaterialeditor.h b/indra/newview/llmaterialeditor.h index be4aa219cd..232467460e 100644 --- a/indra/newview/llmaterialeditor.h +++ b/indra/newview/llmaterialeditor.h @@ -288,6 +288,7 @@ private: // utility function for building a description of the imported material // based on what we know about it. const std::string buildMaterialDescription(); + void refreshUploadCost(); void resetUnsavedChanges(); void markChangesUnsaved(U32 dirty_flag); diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 978294860f..781c85cc75 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -426,7 +426,7 @@ bool LLPanelFace::postBuild() if (pbr_ctrl) { pbr_ctrl->setDefaultImageAssetID(LLUUID::null); - pbr_ctrl->setBlankImageAssetID(LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID); + pbr_ctrl->setBlankImageAssetID(BLANK_MATERIAL_ASSET_ID); pbr_ctrl->setCommitCallback(boost::bind(&LLPanelFace::onCommitPbr, this, _2)); pbr_ctrl->setOnCancelCallback(boost::bind(&LLPanelFace::onCancelPbr, this, _2)); pbr_ctrl->setOnSelectCallback(boost::bind(&LLPanelFace::onSelectPbr, this, _2)); @@ -1957,6 +1957,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) mCtrlShinyOffsetV->setValue(offset_y); getChild("glossiness")->setValue(material->getSpecularLightExponent()); getChild("environment")->setValue(material->getEnvironmentIntensity()); + getChild("mirror")->setValue(material->getEnvironmentIntensity()); updateShinyControls(!material->getSpecularID().isNull(), true); } @@ -2206,7 +2207,7 @@ void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, { mVOInventoryListener = nullptr; } - if (!identical_pbr || pbr_id.isNull() || pbr_id == LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID) + if (!identical_pbr || pbr_id.isNull() || pbr_id == BLANK_MATERIAL_ASSET_ID) { mAgentInventoryListener = nullptr; } diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index 61a6f9f97e..71c62e01f7 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -147,6 +147,7 @@ protected: void sendTexGen(); // applies and sends bump map void sendShiny(U32 shininess); // applies and sends shininess void sendFullbright(); // applies and sends full bright + void sendGlow(); void alignTestureLayer(); diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index b20df4c7a8..818ec09760 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -397,14 +397,12 @@ bool LLPanelMainInventory::postBuild() mCombinationGalleryPanel->setSelectionChangeCallback(boost::bind(&LLPanelMainInventory::onCombinationGallerySelectionChanged, this, _1)); initListCommandsHandlers(); - const std::string texture_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost()); const std::string sound_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getSoundUploadCost()); const std::string animation_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getAnimationUploadCost()); LLMenuGL* menu = (LLMenuGL*)mMenuAddHandle.get(); if (menu) { - menu->getChild("Upload Image")->setLabelArg("[COST]", texture_upload_cost_str); menu->getChild("Upload Sound")->setLabelArg("[COST]", sound_upload_cost_str); menu->getChild("Upload Animation")->setLabelArg("[COST]", animation_upload_cost_str); } @@ -2933,10 +2931,8 @@ void LLPanelMainInventory::setUploadCostIfNeeded() LLMenuGL* menu = (LLMenuGL*)mMenuAddHandle.get(); if(mNeedUploadCost && menu) { - const std::string texture_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost()); const std::string sound_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getSoundUploadCost()); const std::string animation_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getAnimationUploadCost()); - menu->getChild("Upload Image")->setLabelArg("[COST]", texture_upload_cost_str); menu->getChild("Upload Sound")->setLabelArg("[COST]", sound_upload_cost_str); menu->getChild("Upload Animation")->setLabelArg("[COST]", animation_upload_cost_str); } diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index 1233e859e6..1044433737 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -150,7 +150,7 @@ bool LLPanelVolume::postBuild() // REFLECTION PROBE Parameters { childSetCommitCallback("Reflection Probe", onCommitIsReflectionProbe, this); - childSetCommitCallback("Probe Dynamic", onCommitProbe, this); + childSetCommitCallback("Probe Update Type", onCommitProbe, this); childSetCommitCallback("Probe Volume Type", onCommitProbe, this); childSetCommitCallback("Probe Ambiance", onCommitProbe, this); childSetCommitCallback("Probe Near Clip", onCommitProbe, this); @@ -391,22 +391,31 @@ void LLPanelVolume::getState( ) // Reflection Probe bool is_probe = volobjp && volobjp->isReflectionProbe(); + bool is_mirror = volobjp && volobjp->getReflectionProbeIsMirror(); getChild("Reflection Probe")->setValue(is_probe); getChildView("Reflection Probe")->setEnabled(editable && single_volume && volobjp && !volobjp->isMesh()); bool probe_enabled = is_probe && editable && single_volume; + bool mirrors_enabled = LLPipeline::RenderMirrors; + + getChildView("Probe Update Type")->setVisible(mirrors_enabled); + getChildView("Probe Update Label")->setVisible(mirrors_enabled); + getChildView("Probe Dynamic")->setVisible(!mirrors_enabled); + getChildView("Probe Dynamic")->setEnabled(probe_enabled); - getChildView("Probe Volume Type")->setEnabled(probe_enabled); - getChildView("Probe Ambiance")->setEnabled(probe_enabled); - getChildView("Probe Near Clip")->setEnabled(probe_enabled); + getChildView("Probe Update Type")->setEnabled(probe_enabled); + getChildView("Probe Volume Type")->setEnabled(probe_enabled && !is_mirror); + getChildView("Probe Ambiance")->setEnabled(probe_enabled && !is_mirror); + getChildView("Probe Near Clip")->setEnabled(probe_enabled && !is_mirror); + getChildView("Probe Update Label")->setEnabled(probe_enabled); if (!probe_enabled) { getChild("Probe Volume Type", true)->clear(); getChild("Probe Ambiance", true)->clear(); getChild("Probe Near Clip", true)->clear(); - getChild("Probe Dynamic", true)->clear(); + getChild("Probe Update Type", true)->clear(); } else { @@ -420,10 +429,30 @@ void LLPanelVolume::getState( ) volume_type = "Sphere"; } + + std::string update_type = "Static"; + + if (volobjp->getReflectionProbeIsDynamic() && !volobjp->getReflectionProbeIsMirror()) + { + update_type = "Dynamic"; + } + else if (volobjp->getReflectionProbeIsMirror() && !volobjp->getReflectionProbeIsDynamic()) + { + update_type = "Mirror"; + + } + else if (volobjp->getReflectionProbeIsDynamic() && volobjp->getReflectionProbeIsMirror()) + { + update_type = "Dynamic Mirror"; + } + + getChildView("Probe Ambiance")->setEnabled(!is_mirror); + getChildView("Probe Near Clip")->setEnabled(!is_mirror); + getChild("Probe Volume Type", true)->setValue(volume_type); getChild("Probe Ambiance", true)->setValue(volobjp->getReflectionProbeAmbiance()); getChild("Probe Near Clip", true)->setValue(volobjp->getReflectionProbeNearClip()); - getChild("Probe Dynamic", true)->setValue(volobjp->getReflectionProbeIsDynamic()); + getChild("Probe Update Type", true)->setValue(update_type); } // Animated Mesh @@ -714,7 +743,7 @@ void LLPanelVolume::clearCtrls() getChildView("Reflection Probe")->setEnabled(false);; getChildView("Probe Volume Type")->setEnabled(false); - getChildView("Probe Dynamic")->setEnabled(false); + getChildView("Probe Update Type")->setEnabled(false); getChildView("Probe Ambiance")->setEnabled(false); getChildView("Probe Near Clip")->setEnabled(false); getChildView("Animated Mesh Checkbox Ctrl")->setEnabled(false); @@ -1220,6 +1249,7 @@ void LLPanelVolume::onCopyLight() clipboard["reflection_probe"]["ambiance"] = volobjp->getReflectionProbeAmbiance(); clipboard["reflection_probe"]["near_clip"] = volobjp->getReflectionProbeNearClip(); clipboard["reflection_probe"]["dynamic"] = volobjp->getReflectionProbeIsDynamic(); + clipboard["reflection_probe"]["mirror"] = volobjp->getReflectionProbeIsMirror(); } mClipboardParams["light"] = clipboard; @@ -1277,6 +1307,7 @@ void LLPanelVolume::onPasteLight() volobjp->setReflectionProbeAmbiance((F32)clipboard["reflection_probe"]["ambiance"].asReal()); volobjp->setReflectionProbeNearClip((F32)clipboard["reflection_probe"]["near_clip"].asReal()); volobjp->setReflectionProbeIsDynamic(clipboard["reflection_probe"]["dynamic"].asBoolean()); + volobjp->setReflectionProbeIsMirror(clipboard["reflection_probe"]["mirror"].asBoolean()); } else { @@ -1459,11 +1490,22 @@ void LLPanelVolume::onCommitProbe(LLUICtrl* ctrl, void* userdata) volobjp->setReflectionProbeAmbiance((F32)self->getChild("Probe Ambiance")->getValue().asReal()); volobjp->setReflectionProbeNearClip((F32)self->getChild("Probe Near Clip")->getValue().asReal()); - volobjp->setReflectionProbeIsDynamic(self->getChild("Probe Dynamic")->getValue().asBoolean()); + + std::string update_type = self->getChild("Probe Update Type")->getValue().asString(); + + bool is_mirror = update_type.find("Mirror") != std::string::npos; + + self->getChildView("Probe Volume Type")->setEnabled(!is_mirror); + + volobjp->setReflectionProbeIsDynamic(update_type.find("Dynamic") != std::string::npos); + volobjp->setReflectionProbeIsMirror(is_mirror); + + self->getChildView("Probe Ambiance")->setEnabled(!is_mirror); + self->getChildView("Probe Near Clip")->setEnabled(!is_mirror); std::string shape_type = self->getChild("Probe Volume Type")->getValue().asString(); - bool is_box = shape_type == "Box"; + bool is_box = shape_type == "Box" || is_mirror; if (volobjp->setReflectionProbeIsBox(is_box)) { diff --git a/indra/newview/llreflectionmap.cpp b/indra/newview/llreflectionmap.cpp index f4b9d8b2c5..b780349433 100644 --- a/indra/newview/llreflectionmap.cpp +++ b/indra/newview/llreflectionmap.cpp @@ -49,7 +49,7 @@ LLReflectionMap::~LLReflectionMap() } } -void LLReflectionMap::update(U32 resolution, U32 face) +void LLReflectionMap::update(U32 resolution, U32 face, bool force_dynamic, F32 near_clip, bool useClipPlane, LLPlane clipPlane) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; mLastUpdateTime = gFrameTimeSeconds; @@ -63,7 +63,10 @@ void LLReflectionMap::update(U32 resolution, U32 face) { resolution /= 2; } - gViewerWindow->cubeSnapshot(LLVector3(mOrigin), mCubeArray, mCubeIndex, face, getNearClip(), getIsDynamic()); + + F32 clip = (near_clip > 0) ? near_clip : getNearClip(); + + gViewerWindow->cubeSnapshot(LLVector3(mOrigin), mCubeArray, mCubeIndex, face, clip, getIsDynamic() || force_dynamic, useClipPlane, clipPlane); } void LLReflectionMap::autoAdjustOrigin() @@ -165,7 +168,7 @@ void LLReflectionMap::autoAdjustOrigin() } } - else if (mViewerObject) + else if (mViewerObject && !mViewerObject->isDead()) { mPriority = 1; mOrigin.load3(mViewerObject->getPositionAgent().mV); diff --git a/indra/newview/llreflectionmap.h b/indra/newview/llreflectionmap.h index 924cf6233f..9e888f20d0 100644 --- a/indra/newview/llreflectionmap.h +++ b/indra/newview/llreflectionmap.h @@ -36,14 +36,23 @@ class alignas(16) LLReflectionMap : public LLRefCount { LL_ALIGN_NEW public: - // allocate an environment map of the given resolution + + enum class ProbeType + { + ALL = 0, + RADIANCE, + IRRADIANCE, + REFLECTION + }; + + // allocate an environment map of the given resolution LLReflectionMap(); ~LLReflectionMap(); // update this environment map // resolution - size of cube map to generate - void update(U32 resolution, U32 face); + void update(U32 resolution, U32 face, bool force_dynamic = false, F32 near_clip = -1.f, bool useClipPlane = false, LLPlane clipPlane = LLPlane(LLVector3(0, 0, 0), LLVector3(0, 0, 1))); // for volume partition probes, try to place this probe in the best spot void autoAdjustOrigin(); @@ -77,7 +86,7 @@ public: // point at which environment map was last generated from (in agent space) LLVector4a mOrigin; - + // distance from main viewer camera F32 mDistance = -1.f; @@ -97,7 +106,7 @@ public: // cube map used to sample this environment map LLPointer mCubeArray; S32 mCubeIndex = -1; // index into cube map array or -1 if not currently stored in cube map array - + // probe has had at least one full update and is ready to render bool mComplete = false; @@ -127,5 +136,7 @@ public: GLuint mOcclusionQuery = 0; bool mOccluded = false; U32 mOcclusionPendingFrames = 0; + + ProbeType mType; }; diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp index 1eb0428215..399f9d7503 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" @@ -35,6 +38,86 @@ #include "llviewercontrol.h" #include "llenvironment.h" #include "llstartup.h" +#include "llviewermenufile.h" +#include "llnotificationsutil.h" + +#if LL_WINDOWS +#pragma warning (push) +#pragma warning (disable : 4702) // compiler complains unreachable code +#endif +#define TINYEXR_USE_MINIZ 0 +#include "zlib.h" +#define TINYEXR_IMPLEMENTATION +#include "tinyexr/tinyexr.h" +#if LL_WINDOWS +#pragma warning (pop) +#endif + +LLPointer gEXRImage; + +void load_exr(const std::string& filename) +{ + // reset reflection maps when previewing a new HDRI + gPipeline.mReflectionMapManager.reset(); + gPipeline.mReflectionMapManager.initReflectionMaps(); + + float* out; // width * height * RGBA + int width; + int height; + const char* err = NULL; // or nullptr in C++11 + + int ret = LoadEXRWithLayer(&out, &width, &height, filename.c_str(), /* layername */ nullptr, &err); + if (ret == TINYEXR_SUCCESS) + { + U32 texName = 0; + LLImageGL::generateTextures(1, &texName); + + gEXRImage = new LLImageGL(texName, 4, GL_TEXTURE_2D, GL_RGB16F, GL_RGB16F, GL_FLOAT, LLTexUnit::TAM_CLAMP); + gEXRImage->setHasMipMaps(true); + gEXRImage->setUseMipMaps(true); + gEXRImage->setFilteringOption(LLTexUnit::TFO_TRILINEAR); + + gGL.getTexUnit(0)->bind(gEXRImage); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGBA, GL_FLOAT, out); + free(out); // release memory of image data + + glGenerateMipmap(GL_TEXTURE_2D); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + } + else + { + LLSD notif_args; + notif_args["WHAT"] = filename; + notif_args["REASON"] = "Unknown"; + if (err) + { + notif_args["REASON"] = std::string(err); + FreeEXRErrorMessage(err); // release memory of error message. + } + LLNotificationsUtil::add("CannotLoad", notif_args); + } +} + +void hdri_preview() +{ + LLFilePickerReplyThread::startPicker( + [](const std::vector& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter) + { + if (LLAppViewer::instance()->quitRequested()) + { + return; + } + if (filenames.size() > 0) + { + load_exr(filenames[0]); + } + }, + LLFilePicker::FFLOAD_HDRI, + true); +} extern bool gCubeSnapshot; extern bool gTeleportDisplay; @@ -130,6 +213,11 @@ void LLReflectionMapManager::update() return; } + if (mPaused && gFrameTimeSeconds > mResumeTime) + { + resume(); + } + initReflectionMaps(); if (!mRenderTarget.isComplete()) @@ -143,7 +231,7 @@ void LLReflectionMapManager::update() { U32 res = mProbeResolution; U32 count = log2((F32)res) + 0.5f; - + mMipChain.resize(count); for (U32 i = 0; i < count; ++i) { @@ -153,7 +241,7 @@ void LLReflectionMapManager::update() } llassert(mProbes[0] == mDefaultProbe); - + LLVector4a camera_pos; camera_pos.load3(LLViewerCamera::instance().getOrigin().mV); @@ -168,7 +256,7 @@ void LLReflectionMapManager::update() } mKillList.clear(); - + // process create list for (auto& probe : mCreateList) { @@ -184,12 +272,12 @@ void LLReflectionMapManager::update() bool did_update = false; - + static LLCachedControl sDetail(gSavedSettings, "RenderReflectionProbeDetail", -1); static LLCachedControl sLevel(gSavedSettings, "RenderReflectionProbeLevel", 3); bool realtime = sDetail >= (S32)LLReflectionMapManager::DetailLevel::REALTIME; - + LLReflectionMap* closestDynamic = nullptr; LLReflectionMap* oldestProbe = nullptr; @@ -251,7 +339,7 @@ void LLReflectionMapManager::update() --i; continue; } - + if (probe != mDefaultProbe && (!probe->isRelevant() || mPaused)) { // skip irrelevant probes (or all non-default probes if paused) @@ -354,7 +442,7 @@ void LLReflectionMapManager::update() { LLReflectionMap* probe = oldestProbe; llassert(probe->mCubeIndex != -1); - + probe->autoAdjustOrigin(); sUpdateCount++; @@ -548,7 +636,7 @@ void LLReflectionMapManager::doProbeUpdate() llassert(mUpdatingProbe != nullptr); updateProbeFace(mUpdatingProbe, mUpdatingFace); - + bool debug_updates = gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PROBE_UPDATES) && mUpdatingProbe->mViewerObject; if (++mUpdatingFace == 6) @@ -601,11 +689,11 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face) touch_default_probe(probe); gPipeline.pushRenderTypeMask(); - + //only render sky, water, terrain, and clouds gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, LLPipeline::RENDER_TYPE_WL_SKY, LLPipeline::RENDER_TYPE_WATER, LLPipeline::RENDER_TYPE_VOIDWATER, LLPipeline::RENDER_TYPE_CLOUDS, LLPipeline::RENDER_TYPE_TERRAIN, LLPipeline::END_RENDER_TYPES); - + probe->update(mRenderTarget.getWidth(), face); gPipeline.popRenderTypeMask(); @@ -614,7 +702,7 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face) { probe->update(mRenderTarget.getWidth(), face); } - + gPipeline.mRT = &gPipeline.mMainRT; S32 sourceIdx = mReflectionProbeCount; @@ -691,12 +779,12 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face) gGL.getTexUnit(diffuseChannel)->bind(&(mMipChain[i - 1])); } - + gReflectionMipProgram.uniform1f(resScale, 1.f/(mProbeResolution*2)); - + gPipeline.mScreenTriangleVB->setBuffer(); gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); - + res /= 2; GLint mip = i - (static_cast(mMipChain.size()) - mips); @@ -739,6 +827,7 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face) mTexture->bind(channel); gRadianceGenProgram.uniform1i(sSourceIdx, sourceIdx); gRadianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_MAX_LOD, mMaxProbeLOD); + gRadianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_STRENGTH, 1.f); U32 res = mMipChain[0].getWidth(); @@ -785,7 +874,7 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face) gIrradianceGenProgram.uniform1i(sSourceIdx, sourceIdx); gIrradianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_MAX_LOD, mMaxProbeLOD); - + mVertexBuffer->setBuffer(); int start_mip = 0; // find the mip target to start with based on irradiance map resolution @@ -832,9 +921,10 @@ void LLReflectionMapManager::reset() mReset = true; } -void LLReflectionMapManager::pause() +void LLReflectionMapManager::pause(F32 duration) { mPaused = true; + mResumeTime = gFrameTimeSeconds + duration; } void LLReflectionMapManager::resume() @@ -861,7 +951,7 @@ void LLReflectionMapManager::updateNeighbors(LLReflectionMap* probe) //remove from existing neighbors { LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmun - clear"); - + for (auto& other : probe->mNeighbors) { auto const & iter = std::find(other->mNeighbors.begin(), other->mNeighbors.end(), probe); @@ -907,6 +997,8 @@ void LLReflectionMapManager::updateUniforms() // the box probe LLMatrix4 refBox[LL_MAX_REFLECTION_PROBE_COUNT]; + LLMatrix4 heroBox; + // for sphere probes, origin (xyz) and radius (w) of refmaps in clip space LLVector4 refSphere[LL_MAX_REFLECTION_PROBE_COUNT]; @@ -917,6 +1009,8 @@ void LLReflectionMapManager::updateUniforms() // w - znear LLVector4 refParams[LL_MAX_REFLECTION_PROBE_COUNT]; + LLVector4 heroSphere; + // indices used by probe: // [i][0] - cubemap array index for this probe // [i][1] - index into "refNeighbor" for probes that intersect this probe @@ -930,6 +1024,10 @@ void LLReflectionMapManager::updateUniforms() GLint refBucket[256][4]; //lookup table for which index to start with for the given Z depth // numbrer of active refmaps GLint refmapCount; + + GLint heroShape; + GLint heroMipCount; + GLint heroProbeCount; }; mReflectionMaps.resize(mReflectionProbeCount); @@ -959,14 +1057,13 @@ void LLReflectionMapManager::updateUniforms() LLEnvironment& environment = LLEnvironment::instance(); LLSettingsSky::ptr_t psky = environment.getCurrentSky(); - static LLCachedControl cloud_shadow_scale(gSavedSettings, "RenderCloudShadowAmbianceFactor", 0.125f); static LLCachedControl should_auto_adjust(gSavedSettings, "RenderSkyAutoAdjustLegacy", true); - F32 minimum_ambiance = psky->getTotalReflectionProbeAmbiance(cloud_shadow_scale, should_auto_adjust); + F32 minimum_ambiance = psky->getReflectionProbeAmbiance(should_auto_adjust); bool is_ambiance_pass = gCubeSnapshot && !isRadiancePass(); F32 ambscale = is_ambiance_pass ? 0.f : 1.f; F32 radscale = is_ambiance_pass ? 0.5f : 1.f; - + for (auto* refmap : mReflectionMaps) { if (refmap == nullptr) @@ -1017,7 +1114,6 @@ void LLReflectionMapManager::updateUniforms() { refmap->mRadius = refmap->mViewerObject->getScale().mV[0] * 0.5f; } - } modelview.affineTransform(refmap->mOrigin, oa); rpd.refSphere[count].set(oa.getF32ptr()); @@ -1098,7 +1194,7 @@ void LLReflectionMapManager::updateUniforms() { // fill in gaps in refBucket S32 probe_idx = mReflectionProbeCount; - + for (int i = 0; i < 256; ++i) { if (i < count) @@ -1120,6 +1216,16 @@ void LLReflectionMapManager::updateUniforms() rpd.refmapCount = count; + gPipeline.mHeroProbeManager.updateUniforms(); + + // Get the hero data. + + rpd.heroBox = gPipeline.mHeroProbeManager.mHeroData.heroBox; + rpd.heroSphere = gPipeline.mHeroProbeManager.mHeroData.heroSphere; + rpd.heroShape = gPipeline.mHeroProbeManager.mHeroData.heroShape; + rpd.heroMipCount = gPipeline.mHeroProbeManager.mHeroData.heroMipCount; + rpd.heroProbeCount = gPipeline.mHeroProbeManager.mHeroData.heroProbeCount; + //copy rpd into uniform buffer object if (mUBO == 0) { @@ -1267,6 +1373,8 @@ void LLReflectionMapManager::initReflectionMaps() if (mTexture.isNull() || mReflectionProbeCount != count || mReset) { + gEXRImage = nullptr; + mReset = false; mReflectionProbeCount = count; mProbeResolution = nhpo2(llclamp(gSavedSettings.getU32("RenderReflectionProbeResolution"), (U32)64, (U32)512)); @@ -1324,7 +1432,6 @@ void LLReflectionMapManager::initReflectionMaps() mDefaultProbe->mComplete = default_complete; touch_default_probe(mDefaultProbe); - } if (mVertexBuffer.isNull()) @@ -1334,9 +1441,9 @@ void LLReflectionMapManager::initReflectionMaps() buff->allocateBuffer(4, 0); LLStrider v; - + buff->getVertexStrider(v); - + v[0] = LLVector3(-1, -1, -1); v[1] = LLVector3(1, -1, -1); v[2] = LLVector3(-1, 1, -1); @@ -1364,7 +1471,7 @@ void LLReflectionMapManager::cleanup() mReflectionMaps.clear(); mUpdatingFace = 0; - + mDefaultProbe = nullptr; mUpdatingProbe = nullptr; @@ -1388,3 +1495,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 bd4204468a..5c0651bc24 100644 --- a/indra/newview/llreflectionmapmanager.h +++ b/indra/newview/llreflectionmapmanager.h @@ -43,6 +43,8 @@ class LLViewerObject; // reflection probe mininum scale #define LL_REFLECTION_PROBE_MINIMUM_SCALE 1.f; +void renderReflectionProbe(LLReflectionMap* probe); + class alignas(16) LLReflectionMapManager { LL_ALIGN_NEW @@ -65,7 +67,7 @@ public: // add a probe for the given spatial group LLReflectionMap* addProbe(LLSpatialGroup* group = nullptr); - + // Populate "maps" with the N most relevant Reflection Maps where N is no more than maps.size() // If less than maps.size() ReflectionMaps are available, will assign trailing elements to nullptr. // maps -- presized array of Reflection Map pointers @@ -85,7 +87,8 @@ public: void reset(); // pause all updates other than the default probe - void pause(); + // duration - number of seconds to pause (default 10) + void pause(F32 duration = 10.f); // unpause (see pause) void resume(); @@ -106,8 +109,14 @@ public: // perform occlusion culling on all active reflection probes void doOcclusion(); + // *HACK: "cull" all reflection probes except the default one. Only call + // this if you don't intend to call updateUniforms directly. Call again + // with false when done. + void forceDefaultProbeAndUpdateUniforms(bool force = true); + private: friend class LLPipeline; + friend class LLHeroProbeManager; // initialize mCubeFree array to default values void initCubeFree(); @@ -151,7 +160,7 @@ private: // update the specified face of the specified probe void updateProbeFace(LLReflectionMap* probe, U32 face); - + // list of active reflection maps std::vector > mProbes; @@ -200,5 +209,6 @@ private: // if true, only update the default probe bool mPaused = false; + F32 mResumeTime = 0.f; }; diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 0bbcca8328..854dc9628a 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -479,7 +479,7 @@ void LLSelectMgr::overrideAvatarUpdates() //----------------------------------------------------------------------------- // Select just the object, not any other group members. //----------------------------------------------------------------------------- -LLObjectSelectionHandle LLSelectMgr::selectObjectOnly(LLViewerObject* object, S32 face) +LLObjectSelectionHandle LLSelectMgr::selectObjectOnly(LLViewerObject* object, S32 face, S32 gltf_node, S32 gltf_primitive) { llassert( object ); @@ -504,7 +504,7 @@ LLObjectSelectionHandle LLSelectMgr::selectObjectOnly(LLViewerObject* object, S3 // Place it in the list and tag it. // This will refresh dialogs. - addAsIndividual(object, face); + addAsIndividual(object, face, true, gltf_node, gltf_primitive); // Stop the object from moving (this anticipates changes on the // simulator in LLTask::userSelect) @@ -1104,7 +1104,7 @@ void LLSelectMgr::addAsFamily(std::vector& objects, bool add_to //----------------------------------------------------------------------------- // addAsIndividual() - a single object, face, etc //----------------------------------------------------------------------------- -void LLSelectMgr::addAsIndividual(LLViewerObject *objectp, S32 face, bool undoable) +void LLSelectMgr::addAsIndividual(LLViewerObject *objectp, S32 face, bool undoable, S32 gltf_node, S32 gltf_primitive) { // check to see if object is already in list LLSelectNode *nodep = mSelectedObjects->findNode(objectp); @@ -1151,6 +1151,13 @@ void LLSelectMgr::addAsIndividual(LLViewerObject *objectp, S32 face, bool undoab return; } + // Handle glTF node selection + if (gltf_node >= 0) + { + nodep->selectGLTFNode(gltf_node, gltf_primitive, true); + + } + saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); updateSelectionCenter(); dialog_refresh_all(); @@ -1869,7 +1876,7 @@ bool LLObjectSelection::applyRestrictedPbrMaterialToTEs(LLViewerInventoryItem* i LLUUID asset_id = item->getAssetUUID(); if (asset_id.isNull()) { - asset_id = LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID; + asset_id = BLANK_MATERIAL_ASSET_ID; } bool material_copied_all_faces = true; @@ -2131,7 +2138,7 @@ bool LLSelectMgr::selectionSetGLTFMaterial(const LLUUID& mat_id) asset_id = mItem->getAssetUUID(); if (asset_id.isNull()) { - asset_id = LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID; + asset_id = BLANK_MATERIAL_ASSET_ID; } } @@ -5453,46 +5460,57 @@ void LLSelectMgr::saveSelectedObjectTransform(EActionType action_type) { return true; // skip } - selectNode->mSavedPositionLocal = object->getPosition(); - if (object->isAttachment()) + + if (selectNode->mSelectedGLTFNode != -1) { - if (object->isRootEdit()) - { - LLXform* parent_xform = object->mDrawable->getXform()->getParent(); - if (parent_xform) - { - selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition()); - } - else - { - selectNode->mSavedPositionGlobal = object->getPositionGlobal(); - } - } - else - { - LLViewerObject* attachment_root = (LLViewerObject*)object->getParent(); - LLXform* parent_xform = attachment_root ? attachment_root->mDrawable->getXform()->getParent() : NULL; - if (parent_xform) - { - LLVector3 root_pos = (attachment_root->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition(); - LLQuaternion root_rot = (attachment_root->getRotation() * parent_xform->getWorldRotation()); - selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * root_rot) + root_pos); - } - else - { - selectNode->mSavedPositionGlobal = object->getPositionGlobal(); - } - } - selectNode->mSavedRotation = object->getRenderRotation(); + // save GLTF node state + object->getGLTFNodeTransformAgent(selectNode->mSelectedGLTFNode, &selectNode->mSavedPositionLocal, &selectNode->mSavedRotation, &selectNode->mSavedScale); + selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent(selectNode->mSavedPositionLocal); + selectNode->mLastMoveLocal.setZero(); } else { - selectNode->mSavedPositionGlobal = object->getPositionGlobal(); - selectNode->mSavedRotation = object->getRotationRegion(); - } + selectNode->mSavedPositionLocal = object->getPosition(); + if (object->isAttachment()) + { + if (object->isRootEdit()) + { + LLXform* parent_xform = object->mDrawable->getXform()->getParent(); + if (parent_xform) + { + selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition()); + } + else + { + selectNode->mSavedPositionGlobal = object->getPositionGlobal(); + } + } + else + { + LLViewerObject* attachment_root = (LLViewerObject*)object->getParent(); + LLXform* parent_xform = attachment_root ? attachment_root->mDrawable->getXform()->getParent() : NULL; + if (parent_xform) + { + LLVector3 root_pos = (attachment_root->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition(); + LLQuaternion root_rot = (attachment_root->getRotation() * parent_xform->getWorldRotation()); + selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * root_rot) + root_pos); + } + else + { + selectNode->mSavedPositionGlobal = object->getPositionGlobal(); + } + } + selectNode->mSavedRotation = object->getRenderRotation(); + } + else + { + selectNode->mSavedPositionGlobal = object->getPositionGlobal(); + selectNode->mSavedRotation = object->getRotationRegion(); + } - selectNode->mSavedScale = object->getScale(); - selectNode->saveTextureScaleRatios(mManager->mTextureChannel); + selectNode->mSavedScale = object->getScale(); + selectNode->saveTextureScaleRatios(mManager->mTextureChannel); + } return true; } } func(action_type, this); @@ -6953,7 +6971,6 @@ LLSelectNode::~LLSelectNode() } } - delete mPermissions; mPermissions = NULL; } @@ -6982,6 +6999,17 @@ void LLSelectNode::selectTE(S32 te_index, bool selected) mLastTESelected = te_index; } +void LLSelectNode::selectGLTFNode(S32 node_index, S32 primitive_index, bool selected) +{ + if (node_index < 0) + { + return; + } + + mSelectedGLTFNode = node_index; + mSelectedGLTFPrimitive = primitive_index; +} + bool LLSelectNode::isTESelected(S32 te_index) const { if (te_index < 0 || te_index >= mObject->getNumTEs()) diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index bf5180d7e5..57f91f89b5 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -193,6 +193,7 @@ public: void selectAllTEs(bool b); void selectTE(S32 te_index, bool selected); + void selectGLTFNode(S32 node_index, S32 primitive_index, bool selected); bool isTESelected(S32 te_index) const; bool hasSelectedTE() const { return TE_SELECT_MASK_ALL & mTESelectMask; } S32 getLastSelectedTE() const; @@ -235,6 +236,7 @@ public: S16 mInventorySerial; LLVector3 mSavedPositionLocal; // for interactively modifying object position LLVector3 mLastPositionLocal; + LLVector3 mLastMoveLocal; LLVector3d mSavedPositionGlobal; // for interactively modifying object position LLVector3 mSavedScale; // for interactively modifying object scale LLVector3 mLastScale; @@ -258,6 +260,8 @@ public: std::vector mSilhouetteVertices; // array of vertices to render silhouette of object std::vector mSilhouetteNormals; // array of normals to render silhouette of object bool mSilhouetteExists; // need to generate silhouette? + S32 mSelectedGLTFNode = -1; + S32 mSelectedGLTFPrimitive = -1; protected: LLPointer mObject; @@ -601,7 +605,7 @@ public: LLObjectSelectionHandle selectObjectAndFamily(LLViewerObject* object, bool add_to_end = false, bool ignore_select_owned = false); // For when you want just a child object. - LLObjectSelectionHandle selectObjectOnly(LLViewerObject* object, S32 face = SELECT_ALL_TES); + LLObjectSelectionHandle selectObjectOnly(LLViewerObject* object, S32 face = SELECT_ALL_TES, S32 gltf_node = -1, S32 gltf_primitive = -1); // Same as above, but takes a list of objects. Used by rectangle select. LLObjectSelectionHandle selectObjectAndFamily(const std::vector& object_list, bool send_to_sim = true); @@ -906,7 +910,7 @@ public: void remove(std::vector& objects); void remove(LLViewerObject* object, S32 te = SELECT_ALL_TES, bool undoable = true); void removeAll(); - void addAsIndividual(LLViewerObject* object, S32 te = SELECT_ALL_TES, bool undoable = true); + void addAsIndividual(LLViewerObject* object, S32 te = SELECT_ALL_TES, bool undoable = true, S32 gltf_node = -1, S32 gltf_primitive = -1); void promoteSelectionToRoot(); void demoteSelectionToIndividuals(); diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp index c10a782605..42927769de 100644 --- a/indra/newview/llsettingsvo.cpp +++ b/indra/newview/llsettingsvo.cpp @@ -718,11 +718,11 @@ void LLSettingsVOSky::applySpecial(void *ptarget, bool force) LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); // TODO -- make these getters return vec3s - LLVector3 sunDiffuse = LLVector3(psky->getSunlightColor().mV); - LLVector3 moonDiffuse = LLVector3(psky->getMoonlightColor().mV); + LLVector3 sun_light_color = LLVector3(psky->getSunlightColor().mV); + LLVector3 moon_light_color = LLVector3(psky->getMoonlightColor().mV); - shader->uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, sunDiffuse); - shader->uniform3fv(LLShaderMgr::MOONLIGHT_COLOR, moonDiffuse); + shader->uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, sun_light_color); + shader->uniform3fv(LLShaderMgr::MOONLIGHT_COLOR, moon_light_color); shader->uniform3fv(LLShaderMgr::CLOUD_COLOR, LLVector3(psky->getCloudColor().mV)); @@ -745,8 +745,7 @@ void LLSettingsVOSky::applySpecial(void *ptarget, bool force) shader->uniform1f(LLShaderMgr::SKY_SUNLIGHT_SCALE, sunlight_scale); shader->uniform1f(LLShaderMgr::SKY_AMBIENT_SCALE, ambient_scale); - static LLCachedControl cloud_shadow_scale(gSavedSettings, "RenderCloudShadowAmbianceFactor", 0.125f); - F32 probe_ambiance = getTotalReflectionProbeAmbiance(cloud_shadow_scale); + F32 probe_ambiance = getReflectionProbeAmbiance(); if (irradiance_pass) { // during an irradiance map update, disable ambient lighting (direct lighting only) and desaturate sky color (avoid tinting the world blue) @@ -765,9 +764,9 @@ void LLSettingsVOSky::applySpecial(void *ptarget, bool force) shader->uniform1f(LLShaderMgr::SKY_HDR_SCALE, auto_adjust_hdr_scale); LLColor3 blue_horizon = getBlueHorizon() * auto_adjust_blue_horizon_scale; LLColor3 blue_density = getBlueDensity() * auto_adjust_blue_density_scale; - LLColor3 sun_diffuse = getSunDiffuse() * auto_adjust_sun_color_scale; + sun_light_color = sun_light_color * auto_adjust_sun_color_scale; - shader->uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, sun_diffuse.mV); + shader->uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, sun_light_color.mV); shader->uniform3fv(LLShaderMgr::BLUE_DENSITY, blue_density.mV); shader->uniform3fv(LLShaderMgr::BLUE_HORIZON, blue_horizon.mV); @@ -1009,6 +1008,7 @@ void LLSettingsVOWater::applySpecial(void *ptarget, bool force) glh::matrix4f mat(modelView); glh::matrix4f invtrans = mat.inverse().transpose(); + invtrans.m[3] = invtrans.m[7] = invtrans.m[11] = 0.f; glh::vec3f enorm; glh::vec3f ep; invtrans.mult_matrix_vec(norm, enorm); @@ -1017,12 +1017,29 @@ void LLSettingsVOWater::applySpecial(void *ptarget, bool force) LLVector4 waterPlane(enorm.v[0], enorm.v[1], enorm.v[2], -ep.dot(enorm)); + norm = glh::vec3f(gPipeline.mHeroProbeManager.mMirrorNormal.mV); + p = glh::vec3f(gPipeline.mHeroProbeManager.mMirrorPosition.mV); + invtrans.mult_matrix_vec(norm, enorm); + enorm.normalize(); + mat.mult_matrix_vec(p, ep); + + LLVector4 mirrorPlane(enorm.v[0], enorm.v[1], enorm.v[2], -ep.dot(enorm)); + LLDrawPoolAlpha::sWaterPlane = waterPlane; shader->uniform4fv(LLShaderMgr::WATER_WATERPLANE, waterPlane.mV); - + shader->uniform4fv(LLShaderMgr::CLIP_PLANE, mirrorPlane.mV); LLVector4 light_direction = env.getClampedLightNorm(); + if (gPipeline.mHeroProbeManager.isMirrorPass()) + { + shader->uniform1f(LLShaderMgr::MIRROR_FLAG, 1); + } + else + { + shader->uniform1f(LLShaderMgr::MIRROR_FLAG, 0); + } + F32 waterFogKS = 1.f / llmax(light_direction.mV[2], WATER_FOG_LIGHT_CLAMP); shader->uniform1f(LLShaderMgr::WATER_FOGKS, waterFogKS); diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 0271944461..25b6378c91 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -47,6 +47,7 @@ #include "pipeline.h" #include "llmeshrepository.h" #include "llrender.h" +#include "lldrawpool.h" #include "lloctree.h" #include "llphysicsshapebuilderutil.h" #include "llvoavatar.h" @@ -2021,7 +2022,11 @@ void renderBoundingBox(LLDrawable* drawable, bool set_color = true) drawBoxOutline(pos,size); } } - +// *TODO: LLDrawables which are not part of LLVOVolumes fall into a different +// code path which uses a shader - it was tested to be faster than mapping a +// vertex buffer in the terrain case. Consider using it for LLVOVolumes as well +// to simplify and speed up this debug code. Alternatively, a compute shader is +// likely faster. -Cosmic,2023-09-28 void renderNormals(LLDrawable *drawablep) { if (!drawablep->isVisible()) @@ -2029,20 +2034,22 @@ void renderNormals(LLDrawable *drawablep) LLVertexBuffer::unbind(); + LLViewerObject* obj = drawablep->getVObj(); LLVOVolume *vol = drawablep->getVOVolume(); - if (vol) + if (obj) { // FIX and improve renderNormals debug static LLCachedControl showSelectedOnly(gSavedSettings, "OnlyShowSelectedNormals"); - if(showSelectedOnly && !drawablep->getVObj()->isSelected()) + if (showSelectedOnly && !obj->isSelected()) { - drawablep->getVObj()->setDebugText(""); + obj->setDebugText(""); return; } // - LLVolume *volume = vol->getVolume(); + LLGLEnable blend(GL_BLEND); + LLGLDepthTest gl_depth(GL_TRUE, GL_FALSE); // Drawable's normals & tangents are stored in model space, i.e. before any scaling is applied. // @@ -2051,66 +2058,134 @@ void renderNormals(LLDrawable *drawablep) // transform. We get that effect here by pre-applying the inverse scale (twice, because // one forward scale will be re-applied via the MVP in the vertex shader) - LLVector3 scale_v3 = vol->getScale(); - float scale_len = scale_v3.length(); - LLVector4a obj_scale(scale_v3.mV[VX], scale_v3.mV[VY], scale_v3.mV[VZ]); - obj_scale.normalize3(); + LLVector4a inv_scale; + float scale_len; + if (vol) + { + LLVector3 scale_v3 = vol->getScale(); + LLVector4a obj_scale(scale_v3.mV[VX], scale_v3.mV[VY], scale_v3.mV[VZ]); + obj_scale.normalize3(); + + // Create inverse-scale vector for normals + inv_scale.set(1.0 / scale_v3.mV[VX], 1.0 / scale_v3.mV[VY], 1.0 / scale_v3.mV[VZ], 0.0); + inv_scale.mul(inv_scale); // Squared, to apply inverse scale twice + + inv_scale.normalize3fast(); + scale_len = scale_v3.length(); + } + else + { + inv_scale.set(1.0, 1.0, 1.0, 0.0); + scale_len = 1.0; + } + + gGL.pushMatrix(); + if (vol) + { + gGL.multMatrix((F32 *) vol->getRelativeXform().mMatrix); + } + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); // Normals &tangent line segments get scaled along with the object. Divide by scale length // to keep the as-viewed lengths (relatively) constant with the debug setting length float draw_length = gSavedSettings.getF32("RenderDebugNormalScale") / scale_len; - // Create inverse-scale vector for normals - LLVector4a inv_scale(1.0 / scale_v3.mV[VX], 1.0 / scale_v3.mV[VY], 1.0 / scale_v3.mV[VZ]); - inv_scale.mul(inv_scale); // Squared, to apply inverse scale twice - inv_scale.normalize3fast(); - - gGL.pushMatrix(); - gGL.multMatrix((F32 *) vol->getRelativeXform().mMatrix); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) + std::vector* faces = nullptr; + std::vector* drawable_faces = nullptr; + if (vol) { - const LLVolumeFace &face = volume->getVolumeFace(i); + LLVolume* volume = vol->getVolume(); + faces = &volume->getVolumeFaces(); + } + else + { + drawable_faces = &drawablep->getFaces(); + } - gGL.flush(); - gGL.diffuseColor4f(1, 1, 0, 1); - gGL.begin(LLRender::LINES); - for (S32 j = 0; j < face.mNumVertices; ++j) + if (faces) + { + for (auto it = faces->begin(); it != faces->end(); ++it) { - LLVector4a n, p; + const LLVolumeFace& face = *it; - n.setMul(face.mNormals[j], 1.0); - n.mul(inv_scale); // Pre-scale normal, so it's left with an inverse-transpose xform after MVP - n.normalize3fast(); - n.mul(draw_length); - p.setAdd(face.mPositions[j], n); - - gGL.vertex3fv(face.mPositions[j].getF32ptr()); - gGL.vertex3fv(p.getF32ptr()); - } - gGL.end(); - - // Tangents are simple vectors and do not require reorientation via pre-scaling - if (face.mTangents) - { gGL.flush(); - gGL.diffuseColor4f(0, 1, 1, 1); + gGL.diffuseColor4f(1, 1, 0, 1); gGL.begin(LLRender::LINES); for (S32 j = 0; j < face.mNumVertices; ++j) { - LLVector4a t, p; + LLVector4a n, p; - t.setMul(face.mTangents[j], 1.0f); - t.normalize3fast(); - t.mul(draw_length); - p.setAdd(face.mPositions[j], t); + n.setMul(face.mNormals[j], 1.0); + n.mul(inv_scale); // Pre-scale normal, so it's left with an inverse-transpose xform after MVP + n.normalize3fast(); + n.mul(draw_length); + p.setAdd(face.mPositions[j], n); gGL.vertex3fv(face.mPositions[j].getF32ptr()); gGL.vertex3fv(p.getF32ptr()); } gGL.end(); + + // Tangents are simple vectors and do not require reorientation via pre-scaling + if (face.mTangents) + { + gGL.flush(); + gGL.diffuseColor4f(0, 1, 1, 1); + gGL.begin(LLRender::LINES); + for (S32 j = 0; j < face.mNumVertices; ++j) + { + LLVector4a t, p; + + t.setMul(face.mTangents[j], 1.0f); + t.normalize3fast(); + t.mul(draw_length); + p.setAdd(face.mPositions[j], t); + + gGL.vertex3fv(face.mPositions[j].getF32ptr()); + gGL.vertex3fv(p.getF32ptr()); + } + gGL.end(); + } + } + } + else if (drawable_faces) + { + // *HACK: Prepare to restore previous shader as other debug code depends on a simpler shader being present + llassert(LLGLSLShader::sCurBoundShaderPtr == &gDebugProgram); + LLGLSLShader* prev_shader = LLGLSLShader::sCurBoundShaderPtr; + for (auto it = drawable_faces->begin(); it != drawable_faces->end(); ++it) + { + LLFace* facep = *it; + LLFace& face = **it; + LLVertexBuffer* buf = face.getVertexBuffer(); + if (!buf) { continue; } + U32 mask_vn = LLVertexBuffer::TYPE_VERTEX | LLVertexBuffer::TYPE_NORMAL; + if ((buf->getTypeMask() & mask_vn) != mask_vn) { continue; } + + LLGLSLShader* shader; + if ((buf->getTypeMask() & LLVertexBuffer::TYPE_TANGENT) != LLVertexBuffer::TYPE_TANGENT) + { + shader = &gNormalDebugProgram[NORMAL_DEBUG_SHADER_DEFAULT]; + } + else + { + shader = &gNormalDebugProgram[NORMAL_DEBUG_SHADER_WITH_TANGENTS]; + } + shader->bind(); + + shader->uniform1f(LLShaderMgr::DEBUG_NORMAL_DRAW_LENGTH, draw_length); + + LLRenderPass::applyModelMatrix(&facep->getDrawable()->getRegion()->mRenderMatrix); + + buf->setBuffer(); + // *NOTE: The render type in the vertex shader is TRIANGLES, but gets converted to LINES in the geometry shader + // *NOTE: For terrain normal debug, this seems to also include vertices for water, which is technically not part of the terrain. Should fix that at some point. + buf->drawRange(LLRender::TRIANGLES, face.getGeomIndex(), face.getGeomIndex() + face.getGeomCount()-1, face.getIndicesCount(), face.getIndicesStart()); + } + if (prev_shader) + { + prev_shader->bind(); } } @@ -2902,10 +2977,8 @@ void renderLights(LLDrawable* drawablep) class LLRenderOctreeRaycast : public LLOctreeTriangleRayIntersect { public: - - LLRenderOctreeRaycast(const LLVector4a& start, const LLVector4a& dir, F32* closest_t) - : LLOctreeTriangleRayIntersect(start, dir, NULL, closest_t, NULL, NULL, NULL, NULL) + : LLOctreeTriangleRayIntersect(start, dir, nullptr, closest_t, NULL, NULL, NULL, NULL) { } @@ -2973,6 +3046,13 @@ public: } }; +void renderOctreeRaycast(const LLVector4a& start, const LLVector4a& end, const LLVolumeOctree* octree) +{ + F32 t = 1.f; + LLRenderOctreeRaycast render(start, end, &t); + render.traverse(octree); +} + void renderRaycast(LLDrawable* drawablep) { if (drawablep->getNumFaces()) @@ -3034,29 +3114,18 @@ void renderRaycast(LLDrawable* drawablep) { //render face positions - // Use a vbo for the static LLVertexBuffer::drawArray/Element functions; by Drake Arconis/Shyotl Kuhr - //LLVertexBuffer::unbind(); - //gGL.diffuseColor4f(0, 1, 1, 0.5f); - //glVertexPointer(3, GL_FLOAT, sizeof(LLVector4a), face.mPositions); - //gGL.syncMatrices(); - //glDrawElements(GL_TRIANGLES, face.mNumIndices, GL_UNSIGNED_SHORT, face.mIndices); - gGL.diffuseColor4f(0.f, 1.f, 1.f, 0.5f); - LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mPositions, NULL, face.mNumIndices, face.mIndices); - // + //gGL.diffuseColor4f(0,1,1,0.5f); + //LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mPositions, nullptr, face.mNumIndices, face.mIndices); } if (!volume->isUnique()) { - F32 t = 1.f; - if (!face.getOctree()) { ((LLVolumeFace*) &face)->createOctree(); } - LLRenderOctreeRaycast render(start, dir, &t); - - render.traverse(face.getOctree()); + renderOctreeRaycast(start, end, face.getOctree()); } gGL.popMatrix(); diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp index 61d41f6dd2..f8c04356e3 100644 --- a/indra/newview/llsurface.cpp +++ b/indra/newview/llsurface.cpp @@ -827,6 +827,7 @@ void LLSurface::updatePatchVisibilities(LLAgent &agent) } } +template bool LLSurface::idleUpdate(F32 max_update_time) { if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_TERRAIN)) @@ -853,7 +854,7 @@ bool LLSurface::idleUpdate(F32 max_update_time) { std::set::iterator curiter = iter++; LLSurfacePatch *patchp = *curiter; - patchp->updateNormals(); + patchp->updateNormals(); patchp->updateVerticalStats(); if (max_update_time == 0.f || update_timer.getElapsedTimeF32() < max_update_time) { @@ -875,6 +876,9 @@ bool LLSurface::idleUpdate(F32 max_update_time) return did_update; } +template bool LLSurface::idleUpdate(F32 max_update_time); +template bool LLSurface::idleUpdate(F32 max_update_time); + void LLSurface::decompressDCTPatch(LLBitPack &bitpack, LLGroupHeader *gopp, bool b_large_patch) { diff --git a/indra/newview/llsurface.h b/indra/newview/llsurface.h index 42ec920d6c..0bd4d85469 100644 --- a/indra/newview/llsurface.h +++ b/indra/newview/llsurface.h @@ -115,6 +115,7 @@ public: LLSurfacePatch *resolvePatchGlobal(const LLVector3d &position_global) const; // Update methods (called during idle, normally) + template bool idleUpdate(F32 max_update_time); bool containsPosition(const LLVector3 &position); @@ -227,6 +228,9 @@ private: static S32 sTextureSize; // Size of the surface texture }; +extern template bool LLSurface::idleUpdate(F32 max_update_time); +extern template bool LLSurface::idleUpdate(F32 max_update_time); + // . __. diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp index 56001e8e29..dc3eec5268 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); @@ -266,7 +268,8 @@ void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3 } -void LLSurfacePatch::calcNormal(const U32 x, const U32 y, const U32 stride) +template<> +void LLSurfacePatch::calcNormal(const U32 x, const U32 y, const U32 stride) { U32 patch_width = mSurfacep->mPVArray.mPatchWidth; U32 surface_stride = mSurfacep->getGridsPerEdge(); @@ -418,6 +421,166 @@ void LLSurfacePatch::calcNormal(const U32 x, const U32 y, const U32 stride) *(mDataNorm + surface_stride * y + x) = normal; } +template<> +void LLSurfacePatch::calcNormal(const U32 x, const U32 y, const U32 stride) +{ + llassert(mDataNorm); + constexpr U32 index = 0; + + const U32 surface_stride = mSurfacep->getGridsPerEdge(); + LLVector3& normal_out = *(mDataNorm + surface_stride * y + x); + calcNormalFlat(normal_out, x, y, index); +} + +// Calculate the flat normal of a triangle whose least coordinate is specified by the given x,y values. +// If index = 0, calculate the normal of the first triangle, otherwise calculate the normal of the second. +void LLSurfacePatch::calcNormalFlat(LLVector3& normal_out, const U32 x, const U32 y, const U32 index) +{ + llassert(index == 0 || index == 1); + + U32 patch_width = mSurfacep->mPVArray.mPatchWidth; + U32 surface_stride = mSurfacep->getGridsPerEdge(); + + // Vertex stride is always 1 because we want the flat surface of the current triangle face + constexpr U32 stride = 1; + + const F32 mpg = mSurfacep->getMetersPerGrid() * stride; + + S32 poffsets[2][2][2]; + poffsets[0][0][0] = x; + poffsets[0][0][1] = y; + + poffsets[0][1][0] = x; + poffsets[0][1][1] = y + stride; + + poffsets[1][0][0] = x + stride; + poffsets[1][0][1] = y; + + poffsets[1][1][0] = x + stride; + poffsets[1][1][1] = y + stride; + + const LLSurfacePatch *ppatches[2][2]; + + // LLVector3 p1, p2, p3, p4; + + ppatches[0][0] = this; + ppatches[0][1] = this; + ppatches[1][0] = this; + ppatches[1][1] = this; + + U32 i, j; + for (i = 0; i < 2; i++) + { + for (j = 0; j < 2; j++) + { + if (poffsets[i][j][0] < 0) + { + if (!ppatches[i][j]->getNeighborPatch(WEST)) + { + poffsets[i][j][0] = 0; + } + else + { + poffsets[i][j][0] += patch_width; + ppatches[i][j] = ppatches[i][j]->getNeighborPatch(WEST); + } + } + if (poffsets[i][j][1] < 0) + { + if (!ppatches[i][j]->getNeighborPatch(SOUTH)) + { + poffsets[i][j][1] = 0; + } + else + { + poffsets[i][j][1] += patch_width; + ppatches[i][j] = ppatches[i][j]->getNeighborPatch(SOUTH); + } + } + if (poffsets[i][j][0] >= (S32)patch_width) + { + if (!ppatches[i][j]->getNeighborPatch(EAST)) + { + poffsets[i][j][0] = patch_width - 1; + } + else + { + poffsets[i][j][0] -= patch_width; + ppatches[i][j] = ppatches[i][j]->getNeighborPatch(EAST); + } + } + if (poffsets[i][j][1] >= (S32)patch_width) + { + if (!ppatches[i][j]->getNeighborPatch(NORTH)) + { + poffsets[i][j][1] = patch_width - 1; + } + else + { + poffsets[i][j][1] -= patch_width; + ppatches[i][j] = ppatches[i][j]->getNeighborPatch(NORTH); + } + } + } + } + + LLVector3 p00(-mpg,-mpg, + *(ppatches[0][0]->mDataZ + + poffsets[0][0][0] + + poffsets[0][0][1]*surface_stride)); + LLVector3 p01(-mpg,+mpg, + *(ppatches[0][1]->mDataZ + + poffsets[0][1][0] + + poffsets[0][1][1]*surface_stride)); + LLVector3 p10(+mpg,-mpg, + *(ppatches[1][0]->mDataZ + + poffsets[1][0][0] + + poffsets[1][0][1]*surface_stride)); + LLVector3 p11(+mpg,+mpg, + *(ppatches[1][1]->mDataZ + + poffsets[1][1][0] + + poffsets[1][1][1]*surface_stride)); + + // Triangle index / coordinate convention + // for a single surface patch + // + // p01 p11 + // + // ^ ._____. + // | |\ | + // | | \ 1 | + // | | \ | + // | 0 \ | + // y |____\| + // + // p00 x ---> p10 + // + // (z up / out of the screen due to right-handed coordinate system) + + LLVector3 normal; + if (index == 0) + { + LLVector3 c1 = p10 - p00; + LLVector3 c2 = p01 - p00; + + normal = c1; + normal %= c2; + normal.normVec(); + } + else // index == 1 + { + LLVector3 c1 = p11 - p01; + LLVector3 c2 = p11 - p10; + + normal = c1; + normal %= c2; + normal.normVec(); + } + + llassert(&normal_out); + normal_out = normal; +} + const LLVector3 &LLSurfacePatch::getNormal(const U32 x, const U32 y) const { U32 surface_stride = mSurfacep->getGridsPerEdge(); @@ -515,6 +678,7 @@ void LLSurfacePatch::updateVerticalStats() } +template void LLSurfacePatch::updateNormals() { if (mSurfacep->mType == 'w') @@ -532,9 +696,9 @@ void LLSurfacePatch::updateNormals() { for (j = 0; j <= grids_per_patch_edge; j++) { - calcNormal(grids_per_patch_edge, j, 2); - calcNormal(grids_per_patch_edge - 1, j, 2); - calcNormal(grids_per_patch_edge - 2, j, 2); + calcNormal(grids_per_patch_edge, j, 2); + calcNormal(grids_per_patch_edge - 1, j, 2); + calcNormal(grids_per_patch_edge - 2, j, 2); } dirty_patch = true; @@ -557,9 +721,9 @@ void LLSurfacePatch::updateNormals() for (i = 0; i <= grids_per_patch_edge; i++) { - calcNormal(i, grids_per_patch_edge, 2); - calcNormal(i, grids_per_patch_edge - 1, 2); - calcNormal(i, grids_per_patch_edge - 2, 2); + calcNormal(i, grids_per_patch_edge, 2); + calcNormal(i, grids_per_patch_edge - 1, 2); + calcNormal(i, grids_per_patch_edge - 2, 2); } dirty_patch = true; @@ -580,8 +744,8 @@ void LLSurfacePatch::updateNormals() for (j = 0; j < grids_per_patch_edge; j++) { - calcNormal(0, j, 2); - calcNormal(1, j, 2); + calcNormal(0, j, 2); + calcNormal(1, j, 2); } dirty_patch = true; } @@ -602,8 +766,8 @@ void LLSurfacePatch::updateNormals() for (i = 0; i < grids_per_patch_edge; i++) { - calcNormal(i, 0, 2); - calcNormal(i, 1, 2); + calcNormal(i, 0, 2); + calcNormal(i, 1, 2); } dirty_patch = true; } @@ -702,10 +866,10 @@ void LLSurfacePatch::updateNormals() // We've got a northeast patch in the same surface. // The z and normals will be handled by that patch. } - calcNormal(grids_per_patch_edge, grids_per_patch_edge, 2); - calcNormal(grids_per_patch_edge, grids_per_patch_edge - 1, 2); - calcNormal(grids_per_patch_edge - 1, grids_per_patch_edge, 2); - calcNormal(grids_per_patch_edge - 1, grids_per_patch_edge - 1, 2); + calcNormal(grids_per_patch_edge, grids_per_patch_edge, 2); + calcNormal(grids_per_patch_edge, grids_per_patch_edge - 1, 2); + calcNormal(grids_per_patch_edge - 1, grids_per_patch_edge, 2); + calcNormal(grids_per_patch_edge - 1, grids_per_patch_edge - 1, 2); dirty_patch = true; } @@ -716,7 +880,7 @@ void LLSurfacePatch::updateNormals() { for (i=2; i < grids_per_patch_edge - 2; i++) { - calcNormal(i, j, 2); + calcNormal(i, j, 2); } } dirty_patch = true; @@ -733,6 +897,9 @@ void LLSurfacePatch::updateNormals() } } +template void LLSurfacePatch::updateNormals(); +template void LLSurfacePatch::updateNormals(); + void LLSurfacePatch::updateEastEdge() { U32 grids_per_patch_edge = mSurfacep->getGridsPerPatchEdge(); @@ -869,7 +1036,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/llsurfacepatch.h b/indra/newview/llsurfacepatch.h index 82a09c152b..195250d2c0 100644 --- a/indra/newview/llsurfacepatch.h +++ b/indra/newview/llsurfacepatch.h @@ -77,6 +77,7 @@ public: void updateVerticalStats(); void updateCompositionStats(); + template void updateNormals(); void updateEastEdge(); @@ -102,9 +103,18 @@ public: LLVector3 getPointAgent(const U32 x, const U32 y) const; // get the point at the offset. LLVector2 getTexCoords(const U32 x, const U32 y) const; + // Per-vertex normals + // *TODO: PBR=true is a test implementation solely for proof-of-concept. + // Final implementation would likely be very different and may not even use + // this function. If we decide to keep calcNormalFlat, remove index as it + // is a debug parameter for testing. + template void calcNormal(const U32 x, const U32 y, const U32 stride); const LLVector3 &getNormal(const U32 x, const U32 y) const; + // Per-triangle normals for flat edges + void calcNormalFlat(LLVector3& normal_out, const U32 x, const U32 y, const U32 index /* 0 or 1 */); + void eval(const U32 x, const U32 y, const U32 stride, LLVector3 *vertex, LLVector3 *normal, LLVector2 *tex0, LLVector2 *tex1); @@ -181,5 +191,8 @@ protected: LLSurface *mSurfacep; // Pointer to "parent" surface }; +extern template void LLSurfacePatch::updateNormals(); +extern template void LLSurfacePatch::updateNormals(); + #endif // LL_LLSURFACEPATCH_H diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 4a67dac20f..8600780c31 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" @@ -239,7 +240,7 @@ void LLFloaterTexturePicker::setImageID(const LLUUID& image_id, bool set_selecti LLInventoryItem* itemp = gInventory.getItem(inv_view->getUUID()); if (mInventoryPickType == PICK_MATERIAL - && mImageAssetID == LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID + && mImageAssetID == BLANK_MATERIAL_ASSET_ID && itemp && itemp->getAssetUUID().isNull()) { item_id = inv_view->getUUID(); @@ -310,7 +311,7 @@ void LLFloaterTexturePicker::setImageIDFromItem(const LLInventoryItem* itemp, bo if (mInventoryPickType == PICK_MATERIAL && asset_id.isNull()) { // If an inventory item has a null asset, consider it a valid blank material(gltf) - asset_id = LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID; + asset_id = BLANK_MATERIAL_ASSET_ID; } setImageID(asset_id, set_selection); } @@ -592,6 +593,8 @@ void LLFloaterTexturePicker::onClose(bool app_quitting) // FIRE-30431: Keep radio button mode selection in texture selection //sLastPickerMode = mModeSelector->getValue().asInteger(); sLastPickerMode = mModeSelector->getSelectedIndex(); + // *NOTE: Vertex buffer for sphere preview is still cached + mGLTFPreview = nullptr; } // virtual @@ -723,6 +726,7 @@ void LLFloaterTexturePicker::draw() if( mOwner ) { mTexturep = NULL; + LLPointer old_material = mGLTFMaterial; mGLTFMaterial = NULL; if (mImageAssetID.notNull()) { @@ -730,10 +734,27 @@ 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); + } + } + if (mGLTFPreview) + { + mGLTFPreview->setBoostLevel(LLGLTexture::BOOST_PREVIEW); + } } else { LLPointer texture = NULL; + mGLTFPreview = nullptr; if (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(mImageAssetID)) { @@ -785,27 +806,25 @@ void LLFloaterTexturePicker::draw() // If the floater is focused, don't apply its alpha to the texture (STORM-677). const F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency(); - LLViewerTexture* texture = nullptr; + LLViewerTexture* preview; if (mGLTFMaterial) { - texture = mGLTFMaterial->getUITexture(); + preview = mGLTFPreview.get(); } else { - texture = mTexturep.get(); + preview = mTexturep.get(); } - if( texture ) + if( preview ) { - if( texture->getComponents() == 4 ) + preview->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) ); + if( preview->getComponents() == 4 ) { gl_rect_2d_checkerboard( interior, alpha ); } - gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), texture, UI_VERTEX_COLOR % alpha ); - - // Pump the priority - texture->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) ); + gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), preview, UI_VERTEX_COLOR % alpha ); } else if (!mFallbackImage.isNull()) { @@ -859,7 +878,7 @@ const LLUUID& LLFloaterTexturePicker::findItemID(const LLUUID& asset_id, bool co } LLUUID loockup_id = asset_id; - if (mInventoryPickType == PICK_MATERIAL && loockup_id == LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID) + if (mInventoryPickType == PICK_MATERIAL && loockup_id == BLANK_MATERIAL_ASSET_ID) { // default asset id means we are looking for an inventory item with a default asset UUID (null) loockup_id = LLUUID::null; @@ -957,7 +976,7 @@ void LLFloaterTexturePicker::commitCallback(LLTextureCtrl::ETexturePickOp op) LLInventoryItem* itemp = gInventory.getItem(inv_view->getUUID()); if (mInventoryPickType == PICK_MATERIAL - && mImageAssetID == LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID + && mImageAssetID == BLANK_MATERIAL_ASSET_ID && itemp && itemp->getAssetUUID().isNull()) { inventory_id = inv_view->getUUID(); @@ -1788,7 +1807,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), @@ -1912,6 +1931,19 @@ void LLTextureCtrl::setFilterPermissionMasks(PermissionMask mask) setDnDFilterPermMask(mask); } +void LLTextureCtrl::onVisibilityChange(bool new_visibility) +{ + if (!new_visibility) + { + // *NOTE: Vertex buffer for sphere preview is still cached + mGLTFPreview = nullptr; + } + else + { + llassert(!mGLTFPreview); + } +} + void LLTextureCtrl::setVisible( bool visible ) { if( !visible ) @@ -2345,48 +2377,73 @@ 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); + } } + if (mGLTFPreview) + { + mGLTFPreview->setBoostLevel(LLGLTexture::BOOST_PREVIEW); + } + + preview = mGLTFPreview; } else { - texture = LLViewerTextureManager::getFetchedTexture(mImageAssetID, FTT_DEFAULT, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); - texture->setBoostLevel(LLGLTexture::BOOST_PREVIEW); - texture->forceToSaveRawImage(0); + mTexturep = LLViewerTextureManager::getFetchedTexture(mImageAssetID, FTT_DEFAULT, bool, 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 @@ -2401,15 +2458,15 @@ void LLTextureCtrl::draw() // If we're in a focused floater, don't apply the floater's alpha to the texture (STORM-677). const F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency(); - if( mTexturep ) + if( preview ) { - if( mTexturep->getComponents() == 4 ) + if( preview->getComponents() == 4 ) { gl_rect_2d_checkerboard( interior, alpha ); } - gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), mTexturep, UI_VERTEX_COLOR % alpha); - mTexturep->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) ); + gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), preview, UI_VERTEX_COLOR % alpha); + preview->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) ); // Mask texture if desired if (mIsMasked) { @@ -2537,7 +2594,7 @@ bool LLTextureCtrl::doDrop(LLInventoryItem* item) if (mInventoryPickType == PICK_MATERIAL && asset_id.isNull()) { // If an inventory material has a null asset, consider it a valid blank material(gltf) - asset_id = LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID; + asset_id = BLANK_MATERIAL_ASSET_ID; } setImageAssetID(asset_id); @@ -2595,3 +2652,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 d17b069a3f..e34a674060 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), @@ -144,26 +156,28 @@ public: // LLView interface - virtual bool handleMouseDown(S32 x, S32 y, MASK mask); - virtual bool handleDragAndDrop(S32 x, S32 y, MASK mask, - bool drop, EDragAndDropType cargo_type, void *cargo_data, - EAcceptance *accept, - std::string& tooltip_msg); - virtual bool handleHover(S32 x, S32 y, MASK mask); - virtual bool handleUnicodeCharHere(llwchar uni_char); + bool handleMouseDown(S32 x, S32 y, MASK mask) override; + bool handleDragAndDrop(S32 x, S32 y, MASK mask, + bool drop, EDragAndDropType cargo_type, void *cargo_data, + EAcceptance *accept, + std::string& tooltip_msg) override; + bool handleHover(S32 x, S32 y, MASK mask) override; + bool handleUnicodeCharHere(llwchar uni_char) override; - virtual void draw(); - virtual void setVisible( bool visible ); - virtual void setEnabled( bool enabled ); + void draw() override; + void setVisible( bool visible ) override; + void setEnabled( bool enabled ) override; - void setValid(bool valid); + void onVisibilityChange(bool new_visibility) override; + + void setValid(bool valid); // LLUICtrl interface - virtual void clear(); + void clear() override; // Takes a UUID, wraps get/setImageAssetID - virtual void setValue(const LLSD& value); - virtual LLSD getValue() const; + void setValue(const LLSD& value) override; + LLSD getValue() const override; // LLTextureCtrl interface void showPicker(bool take_focus); @@ -266,6 +280,8 @@ private: commit_callback_t mOnCloseCallback; texture_selected_callback mOnTextureSelectedCallback; LLPointer mTexturep; + LLPointer mGLTFMaterial; + LLPointer mGLTFPreview; LLUIColor mBorderColor; LLUUID mImageItemID; LLUUID mImageAssetID; @@ -411,6 +427,7 @@ protected: LLPointer mTexturep; LLPointer mGLTFMaterial; + LLPointer mGLTFPreview; LLView* mOwner; LLUUID mImageAssetID; // Currently selected texture diff --git a/indra/newview/lltinygltfhelper.cpp b/indra/newview/lltinygltfhelper.cpp index 7a36066830..cbce83d4c2 100644 --- a/indra/newview/lltinygltfhelper.cpp +++ b/indra/newview/lltinygltfhelper.cpp @@ -87,22 +87,32 @@ void LLTinyGLTFHelper::initFetchedTextures(tinygltf::Material& material, { strip_alpha_channel(mr_img); - if (occlusion_img && material.pbrMetallicRoughness.metallicRoughnessTexture.index != material.occlusionTexture.index) + if (occlusion_img) { - // occlusion is a distinct texture from pbrMetallicRoughness - // pack into mr red channel - int occlusion_idx = material.occlusionTexture.index; - int mr_idx = material.pbrMetallicRoughness.metallicRoughnessTexture.index; - if (occlusion_idx != mr_idx) + if (material.pbrMetallicRoughness.metallicRoughnessTexture.index != material.occlusionTexture.index) { - LLImageDataLock lockIn(occlusion_img); - LLImageDataLock lockOut(mr_img); - //scale occlusion image to match resolution of mr image - occlusion_img->scale(mr_img->getWidth(), mr_img->getHeight()); + // occlusion is a distinct texture from pbrMetallicRoughness + // pack into mr red channel + int occlusion_idx = material.occlusionTexture.index; + int mr_idx = material.pbrMetallicRoughness.metallicRoughnessTexture.index; + if (occlusion_idx != mr_idx) + { + LLImageDataLock lockIn(occlusion_img); + LLImageDataLock lockOut(mr_img); + //scale occlusion image to match resolution of mr image + occlusion_img->scale(mr_img->getWidth(), mr_img->getHeight()); - copy_red_channel(occlusion_img, mr_img); + copy_red_channel(occlusion_img, mr_img); + } } } + else if (material.occlusionTexture.index == -1) + { + // no occlusion, make sure red channel of ORM is all 255 + occlusion_img = new LLImageRaw(mr_img->getWidth(), mr_img->getHeight(), 3); + occlusion_img->clear(255, 255, 255); + copy_red_channel(occlusion_img, mr_img); + } } else if (occlusion_img) { @@ -150,7 +160,7 @@ const tinygltf::Image * LLTinyGLTFHelper::getImageFromTextureIndex(const tinyglt return nullptr; } -LLImageRaw * LLTinyGLTFHelper::getTexture(const std::string & folder, const tinygltf::Model & model, S32 texture_index, std::string & name) +LLImageRaw * LLTinyGLTFHelper::getTexture(const std::string & folder, const tinygltf::Model & model, S32 texture_index, std::string & name, bool flip) { const tinygltf::Image* image = getImageFromTextureIndex(model, texture_index); LLImageRaw* rawImage = nullptr; @@ -162,14 +172,17 @@ LLImageRaw * LLTinyGLTFHelper::getTexture(const std::string & folder, const tiny { name = image->name; rawImage = new LLImageRaw(&image->image[0], image->width, image->height, image->component); - rawImage->verticalFlip(); + if (flip) + { + rawImage->verticalFlip(); + } rawImage->optimizeAwayAlpha(); } return rawImage; } -LLImageRaw * LLTinyGLTFHelper::getTexture(const std::string & folder, const tinygltf::Model & model, S32 texture_index) +LLImageRaw * LLTinyGLTFHelper::getTexture(const std::string & folder, const tinygltf::Model & model, S32 texture_index, bool flip) { const tinygltf::Image* image = getImageFromTextureIndex(model, texture_index); LLImageRaw* rawImage = nullptr; @@ -180,7 +193,10 @@ LLImageRaw * LLTinyGLTFHelper::getTexture(const std::string & folder, const tiny image->component <= 4) { rawImage = new LLImageRaw(&image->image[0], image->width, image->height, image->component); - rawImage->verticalFlip(); + if (flip) + { + rawImage->verticalFlip(); + } rawImage->optimizeAwayAlpha(); } @@ -240,7 +256,8 @@ bool LLTinyGLTFHelper::getMaterialFromModel( const tinygltf::Model& model_in, S32 mat_index, LLFetchedGLTFMaterial* material, - std::string& material_name) + std::string& material_name, + bool flip) { llassert(material); @@ -259,18 +276,18 @@ bool LLTinyGLTFHelper::getMaterialFromModel( material_name = material_in.name; // get base color texture - LLPointer base_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.baseColorTexture.index); + LLPointer base_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.baseColorTexture.index, flip); // get normal map - LLPointer normal_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.normalTexture.index); + LLPointer normal_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.normalTexture.index, flip); // get metallic-roughness texture - LLPointer mr_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.metallicRoughnessTexture.index); + LLPointer mr_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.metallicRoughnessTexture.index, flip); // get emissive texture - LLPointer emissive_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.emissiveTexture.index); + LLPointer emissive_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.emissiveTexture.index, flip); // get occlusion map if needed LLPointer occlusion_img; if (material_in.occlusionTexture.index != material_in.pbrMetallicRoughness.metallicRoughnessTexture.index) { - occlusion_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.occlusionTexture.index); + occlusion_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.occlusionTexture.index, flip); } LLPointer base_color_tex; diff --git a/indra/newview/lltinygltfhelper.h b/indra/newview/lltinygltfhelper.h index 256f6c854f..da505b41e9 100644 --- a/indra/newview/lltinygltfhelper.h +++ b/indra/newview/lltinygltfhelper.h @@ -38,10 +38,8 @@ namespace LLTinyGLTFHelper { LLColor4 getColor(const std::vector& in); const tinygltf::Image* getImageFromTextureIndex(const tinygltf::Model& model, S32 texture_index); - LLImageRaw* getTexture(const std::string& folder, const tinygltf::Model& model, S32 texture_index, std::string& name); - LLImageRaw* getTexture(const std::string& folder, const tinygltf::Model& model, S32 texture_index); - - LLImageRaw* getTexture(const std::string& folder, const tinygltf::Model& model, S32 texture_index); + LLImageRaw* getTexture(const std::string& folder, const tinygltf::Model& model, S32 texture_index, std::string& name, bool flip = true); + LLImageRaw* getTexture(const std::string& folder, const tinygltf::Model& model, S32 texture_index, bool flip = true); bool loadModel(const std::string& filename, tinygltf::Model& model_out); @@ -50,7 +48,8 @@ namespace LLTinyGLTFHelper const tinygltf::Model& model, S32 mat_index, LLFetchedGLTFMaterial* material, - std::string& material_name); + std::string& material_name, + bool flip = true); void initFetchedTextures(tinygltf::Material& material, LLPointer& base_color_img, diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 0b31b0aaa6..39b9eff103 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -1096,51 +1096,71 @@ void set_texture_to_material(LLViewerObject* hit_obj, LLGLTFMaterial::TextureInfo drop_channel) { LLTextureEntry* te = hit_obj->getTE(hit_face); - if (te) + if (!te) { - LLPointer material = te->getGLTFMaterialOverride(); - - // make a copy to not invalidate existing - // material for multiple objects - if (material.isNull()) - { - // Start with a material override which does not make any changes - material = new LLGLTFMaterial(); - } - else - { - material = new LLGLTFMaterial(*material); - } - - switch (drop_channel) - { - case LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR: - default: - { - material->setBaseColorId(asset_id); - } - break; - - case LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS: - { - material->setOcclusionRoughnessMetallicId(asset_id); - } - break; - - case LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE: - { - material->setEmissiveId(asset_id); - } - break; - - case LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL: - { - material->setNormalId(asset_id); - } - break; - } - LLGLTFMaterialList::queueModify(hit_obj, hit_face, material); + return; } + + const LLUUID base_mat_id = hit_obj->getRenderMaterialID(hit_face); + if (base_mat_id.isNull()) + { + return; + } + + if (hit_obj->isInventoryDirty() && hit_obj->hasInventoryListeners()) + { + hit_obj->requestInventory(); + return; + } + + LLViewerInventoryItem* mat_item = hit_obj->getInventoryItemByAsset(base_mat_id); + if (mat_item && !mat_item->getPermissions().allowModifyBy(gAgentID)) + { + return; + } + + LLPointer material = te->getGLTFMaterialOverride(); + + // make a copy to not invalidate existing + // material for multiple objects + if (material.isNull()) + { + // Start with a material override which does not make any changes + material = new LLGLTFMaterial(); + } + else + { + material = new LLGLTFMaterial(*material); + } + + switch (drop_channel) + { + case LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR: + default: + { + material->setBaseColorId(asset_id); + } + break; + + case LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS: + { + material->setOcclusionRoughnessMetallicId(asset_id); + } + break; + + case LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE: + { + material->setEmissiveId(asset_id); + } + break; + + case LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL: + { + material->setNormalId(asset_id); + } + break; + } + LLGLTFMaterialList::queueModify(hit_obj, hit_face, material); } void LLToolDragAndDrop::dropTextureAllFaces(LLViewerObject* hit_obj, @@ -1281,7 +1301,7 @@ void LLToolDragAndDrop::dropMaterialOneFace(LLViewerObject* hit_obj, if (asset_id.isNull()) { // use blank material - asset_id = LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID; + asset_id = BLANK_MATERIAL_ASSET_ID; } hit_obj->setRenderMaterialID(hit_face, asset_id); @@ -1317,7 +1337,7 @@ void LLToolDragAndDrop::dropMaterialAllFaces(LLViewerObject* hit_obj, if (asset_id.isNull()) { // use blank material - asset_id = LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID; + asset_id = BLANK_MATERIAL_ASSET_ID; } hit_obj->setRenderMaterialIDs(asset_id); diff --git a/indra/newview/lltoolselect.cpp b/indra/newview/lltoolselect.cpp index fb8db94866..e402c7d2ef 100644 --- a/indra/newview/lltoolselect.cpp +++ b/indra/newview/lltoolselect.cpp @@ -224,7 +224,7 @@ LLObjectSelectionHandle LLToolSelect::handleObjectSelection(const LLPickInfo& pi if ( ignore_group ) { - LLSelectMgr::getInstance()->selectObjectOnly(object, SELECT_ALL_TES); + LLSelectMgr::getInstance()->selectObjectOnly(object, SELECT_ALL_TES, pick.mGLTFNodeIndex, pick.mGLTFPrimitiveIndex); } else { diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp index 2233428251..1097f3481d 100644 --- a/indra/newview/llviewerassetupload.cpp +++ b/indra/newview/llviewerassetupload.cpp @@ -162,9 +162,9 @@ LLSD LLResourceUploadInfo::generatePostBody() body["next_owner_mask"] = LLSD::Integer(mNextOwnerPerms); body["group_mask"] = LLSD::Integer(mGroupPerms); body["everyone_mask"] = LLSD::Integer(mEveryonePerms); + body["expected_upload_cost"] = mExpectedUploadCost; return body; - } void LLResourceUploadInfo::logPreparedUpload() diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp index cb286b031c..b73ed442ec 100644 --- a/indra/newview/llviewercamera.cpp +++ b/indra/newview/llviewercamera.cpp @@ -772,6 +772,12 @@ bool LLViewerCamera::cameraUnderWater() const { LLViewerRegion* regionp = LLWorld::instance().getRegionFromPosAgent(getOrigin()); + if (gPipeline.mHeroProbeManager.isMirrorPass()) + { + // TODO: figure out how to handle this case + return false; + } + if (!regionp) { regionp = gAgent.getRegion(); diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 0080009911..6df172a5a5 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) { @@ -541,6 +555,19 @@ static bool handleReflectionProbeDetailChanged(const LLSD& newvalue) gPipeline.createGLBuffers(); LLViewerShaderMgr::instance()->setShaders(); gPipeline.mReflectionMapManager.reset(); + gPipeline.mHeroProbeManager.reset(); + } + return true; +} + +static bool handleHeroProbeResolutionChanged(const LLSD &newvalue) +{ + if (gPipeline.isInit()) + { + LLPipeline::refreshCachedSettings(); + gPipeline.mHeroProbeManager.reset(); + gPipeline.releaseGLBuffers(); + gPipeline.createGLBuffers(); } return true; } @@ -1119,6 +1146,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) { @@ -1171,7 +1208,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); @@ -1216,6 +1257,7 @@ void settings_setup_listeners() setting_setup_signal_listener(gSavedSettings, "RenderReflectionProbeDetail", handleReflectionProbeDetailChanged); // setting_setup_signal_listener(gSavedSettings, "RenderReflectionsEnabled", handleReflectionsEnabled); // FIRE-33659 better way to enable/disable reflections setting_setup_signal_listener(gSavedSettings, "RenderScreenSpaceReflections", handleReflectionProbeDetailChanged); + setting_setup_signal_listener(gSavedSettings, "RenderHeroProbeResolution", handleHeroProbeResolutionChanged); setting_setup_signal_listener(gSavedSettings, "RenderShadowDetail", handleSetShaderChanged); setting_setup_signal_listener(gSavedSettings, "RenderDeferredSSAO", handleSetShaderChanged); setting_setup_signal_listener(gSavedSettings, "RenderPerformanceTest", handleRenderPerfTestChanged); @@ -1327,6 +1369,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/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 4eaae5f94e..5ede9ea817 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -768,6 +768,15 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot) if (!gDisconnected) { + // Render mirrors and associated hero probes before we render the rest of the scene. + // This ensures the scene state in the hero probes are exactly the same as the rest of the scene before we render it. + if (gPipeline.RenderMirrors && !gSnapshot) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Update hero probes"); + gPipeline.mHeroProbeManager.update(); + gPipeline.mHeroProbeManager.renderProbes(); + } + LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 1"); LLAppViewer::instance()->pingMainloopTimeout("Display:Update"); if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index bb5ab0ae02..db34f5a2ce 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -145,6 +145,7 @@ #include #include "llcleanup.h" #include "llviewershadermgr.h" +#include "gltfscenemanager.h" // [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) #include "fsavatarrenderpersistence.h" #include "rlvactions.h" @@ -669,10 +670,8 @@ void init_menus() gViewerWindow->setMenuBackgroundColor(false, !LLGridManager::getInstance()->isInSLBeta()); // *TODO:Also fix cost in llfolderview.cpp for Inventory menus - const std::string texture_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost()); const std::string sound_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getSoundUploadCost()); const std::string animation_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getAnimationUploadCost()); - gMenuHolder->childSetLabelArg("Upload Image", "[COST]", texture_upload_cost_str); gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", sound_upload_cost_str); gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", animation_upload_cost_str); @@ -907,10 +906,30 @@ U32 render_type_from_string(std::string render_type) { return LLPipeline::RENDER_TYPE_SIMPLE; } + if ("materials" == render_type) + { + return LLPipeline::RENDER_TYPE_MATERIALS; + } else if ("alpha" == render_type) { return LLPipeline::RENDER_TYPE_ALPHA; } + else if ("alpha_mask" == render_type) + { + return LLPipeline::RENDER_TYPE_ALPHA_MASK; + } + else if ("fullbright_alpha_mask" == render_type) + { + return LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK; + } + else if ("fullbright" == render_type) + { + return LLPipeline::RENDER_TYPE_FULLBRIGHT; + } + else if ("glow" == render_type) + { + return LLPipeline::RENDER_TYPE_GLOW; + } else if ("tree" == render_type) { return LLPipeline::RENDER_TYPE_TREE; @@ -1167,6 +1186,10 @@ U64 info_display_from_string(std::string info_display) { return LLPipeline::RENDER_DEBUG_OCTREE; } + else if ("nodes" == info_display) + { + return LLPipeline::RENDER_DEBUG_NODES; + } else if ("shadow frusta" == info_display) { return LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA; @@ -2494,6 +2517,20 @@ class LLAdvancedPurgeShaderCache : public view_listener_t } }; +///////////////////// +// REBUILD TERRAIN // +///////////////////// + + +class LLAdvancedRebuildTerrain : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + gPipeline.rebuildTerrain(); + return true; + } +}; + //////////////////// // EVENT Recorder // /////////////////// @@ -9156,21 +9193,21 @@ class LLAttachmentDetach : public view_listener_t } LLViewerObject* parent = (LLViewerObject*)objectp->getParent(); - while (parent) - { - if (parent->isAvatar()) - { - break; - } + while (parent) + { + if(parent->isAvatar()) + { + break; + } objectp = parent; - parent = (LLViewerObject*)parent->getParent(); - } + parent = (LLViewerObject*)parent->getParent(); + } // [RLVa:KB] - Checked: 2010-03-15 (RLVa-1.2.0a) | Modified: RLVa-1.0.5 // NOTE: copy/paste of the code in enable_detach() if ((rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) && gRlvAttachmentLocks.isLockedAttachment(objectp->getRootEdit())) - { + { return false; } // [/RLVa:KB] @@ -9178,8 +9215,8 @@ class LLAttachmentDetach : public view_listener_t // std::set to avoid dupplicate 'roots' from linksets mRemoveSet.insert(objectp->getAttachmentItemID()); - return true; - } + return true; + } bool mAvatarsInSelection; uuid_set_t mRemoveSet; } func; @@ -9199,7 +9236,7 @@ class LLAttachmentDetach : public view_listener_t if (func.mRemoveSet.empty()) { LL_WARNS() << "handle_detach() - no valid attachments in selection to detach" << LL_ENDL; - return true; + return true; } uuid_vec_t detach_list(func.mRemoveSet.begin(), func.mRemoveSet.end()); @@ -10011,6 +10048,30 @@ class LLAdvancedClickRenderBenchmark: public view_listener_t } }; +void hdri_preview(); + +class LLAdvancedClickHDRIPreview: public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + // open personal lighting floater when previewing an HDRI (keeps HDRI from implicitly unloading when opening build tools) + LLFloaterReg::showInstance("env_adjust_snapshot"); + hdri_preview(); + return true; + } +}; + + +class LLAdvancedClickGLTFScenePreview : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + // open personal lighting floater when previewing an HDRI (keeps HDRI from implicitly unloading when opening build tools) + LL::GLTFSceneManager::instance().load(); + return true; + } +}; + // these are used in the gl menus to set control values that require shader recompilation class LLToggleShaderControl : public view_listener_t { @@ -11916,6 +11977,8 @@ void LLUploadCostCalculator::calculateCost(const std::string& asset_type_str) if (asset_type_str == "texture") { + // This use minimal texture cost to allow bulk and + // texture upload menu options to be visible upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(); } else if (asset_type_str == "animation") @@ -12461,7 +12524,10 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedClickRenderShadowOption(), "Advanced.ClickRenderShadowOption"); view_listener_t::addMenu(new LLAdvancedClickRenderProfile(), "Advanced.ClickRenderProfile"); view_listener_t::addMenu(new LLAdvancedClickRenderBenchmark(), "Advanced.ClickRenderBenchmark"); + view_listener_t::addMenu(new LLAdvancedClickHDRIPreview(), "Advanced.ClickHDRIPreview"); + view_listener_t::addMenu(new LLAdvancedClickGLTFScenePreview(), "Advanced.ClickGLTFScenePreview"); view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache"); + view_listener_t::addMenu(new LLAdvancedRebuildTerrain(), "Advanced.RebuildTerrain"); //[FIX FIRE-1927 - enable DoubleClickTeleport shortcut : SJ] view_listener_t::addMenu(new FSAdvancedToggleDoubleClickAction, "Advanced.SetDoubleClickAction"); view_listener_t::addMenu(new FSAdvancedCheckEnabledDoubleClickAction, "Advanced.CheckEnabledDoubleClickAction"); diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 8ef5371d42..67e5ab7053 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -561,21 +561,39 @@ void do_bulk_upload(std::vector filenames, const LLSD& notification std::string ext = gDirUtilp->getExtension(filename); LLAssetType::EType asset_type; U32 codec; - S32 expected_upload_cost; - if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec) && - LLAgentBenefitsMgr::current().findUploadCost(asset_type, expected_upload_cost)) - { - LLResourceUploadInfo::ptr_t uploadInfo(new LLNewFileResourceUploadInfo( - filename, - asset_name, - asset_name, 0, - LLFolderType::FT_NONE, LLInventoryType::IT_NONE, - LLFloaterPerms::getNextOwnerPerms("Uploads"), - LLFloaterPerms::getGroupPerms("Uploads"), - LLFloaterPerms::getEveryonePerms("Uploads"), - expected_upload_cost)); + S32 expected_upload_cost = 0; - upload_new_resource(uploadInfo); + if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec)) + { + bool resource_upload = false; + if (asset_type == LLAssetType::AT_TEXTURE) + { + LLPointer image_frmted = LLImageFormatted::createFromType(codec); + if (gDirUtilp->fileExists(filename) && image_frmted->load(filename)) + { + expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(image_frmted); + resource_upload = true; + } + } + else if (LLAgentBenefitsMgr::current().findUploadCost(asset_type, expected_upload_cost)) + { + resource_upload = true; + } + + if (resource_upload) + { + LLResourceUploadInfo::ptr_t uploadInfo(new LLNewFileResourceUploadInfo( + filename, + asset_name, + asset_name, 0, + LLFolderType::FT_NONE, LLInventoryType::IT_NONE, + LLFloaterPerms::getNextOwnerPerms("Uploads"), + LLFloaterPerms::getGroupPerms("Uploads"), + LLFloaterPerms::getEveryonePerms("Uploads"), + expected_upload_cost)); + + upload_new_resource(uploadInfo); + } } // gltf does not use normal upload procedure @@ -617,17 +635,26 @@ bool get_bulk_upload_expected_cost(const std::vector& filenames, S3 U32 codec; S32 cost; - if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec) && - LLAgentBenefitsMgr::current().findUploadCost(asset_type, cost)) + if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec)) { - total_cost += cost; - file_count++; + if (asset_type == LLAssetType::AT_TEXTURE) + { + LLPointer image_frmted = LLImageFormatted::createFromType(codec); + if (gDirUtilp->fileExists(filename) && image_frmted->load(filename)) + { + total_cost += LLAgentBenefitsMgr::current().getTextureUploadCost(image_frmted); + file_count++; + } + } + else if (LLAgentBenefitsMgr::current().findUploadCost(asset_type, cost)) + { + total_cost += cost; + file_count++; + } } if (ext == "gltf" || ext == "glb") { - S32 texture_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(); - tinygltf::Model model; if (LLTinyGLTFHelper::loadModel(filename, model)) @@ -644,24 +671,22 @@ bool get_bulk_upload_expected_cost(const std::vector& filenames, S3 { // Todo: make it account for possibility of same texture in different // materials and even in scope of same material - S32 texture_count = 0; - if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR].notNull()) + if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR].notNull() && material->mBaseColorTexture) { - texture_count++; + total_cost += LLAgentBenefitsMgr::current().getTextureUploadCost(material->mBaseColorTexture); } - if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].notNull()) + if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].notNull() && material->mMetallicRoughnessTexture) { - texture_count++; + total_cost += LLAgentBenefitsMgr::current().getTextureUploadCost(material->mMetallicRoughnessTexture); } - if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL].notNull()) + if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL].notNull() && material->mNormalTexture) { - texture_count++; + total_cost += LLAgentBenefitsMgr::current().getTextureUploadCost(material->mNormalTexture); } - if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE].notNull()) + if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE].notNull() && material->mEmissiveTexture) { - texture_count++; + total_cost += LLAgentBenefitsMgr::current().getTextureUploadCost(material->mEmissiveTexture); } - total_cost += texture_count * texture_upload_cost; file_count++; } } diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 2a0dfc4303..3881183668 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -1538,6 +1538,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // alpha was flipped so that it zero encoded better coloru.mV[3] = 255 - coloru.mV[3]; + mText->setColor(LLColor4(coloru)); mText->setString(temp_string); // [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.4.0a) | Added: RLVa-1.0.0f @@ -1867,6 +1868,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, { std::string temp_string; dp->unpackString(temp_string, "Text"); + LLColor4U coloru; dp->unpackBinaryDataFixed(coloru.mV, 4, "Color"); coloru.mV[3] = 255 - coloru.mV[3]; @@ -4404,6 +4406,168 @@ const LLVector3 &LLViewerObject::getPositionAgent() const return mPositionAgent; } +LLMatrix4a LLViewerObject::getGLTFAssetToAgentTransform() const +{ + LLMatrix4 root; + root.initScale(getScale()); + root.rotate(getRenderRotation()); + root.translate(getPositionAgent()); + + LLMatrix4a mat; + mat.loadu((F32*)root.mMatrix); + + return mat; +} + +LLVector3 LLViewerObject::getGLTFNodePositionAgent(S32 node_index) const +{ + LLVector3 ret; + getGLTFNodeTransformAgent(node_index, &ret, nullptr, nullptr); + return ret; + +} + +LLMatrix4a LLViewerObject::getAgentToGLTFAssetTransform() const +{ + LLMatrix4 root; + LLVector3 scale = getScale(); + scale.mV[0] = 1.f / scale.mV[0]; + scale.mV[1] = 1.f / scale.mV[1]; + scale.mV[2] = 1.f / scale.mV[2]; + + root.translate(-getPositionAgent()); + root.rotate(~getRenderRotation()); + + LLMatrix4 scale_mat; + scale_mat.initScale(scale); + + root *= scale_mat; + LLMatrix4a mat; + mat.loadu((F32*)root.mMatrix); + + return mat; +} + +LLMatrix4a LLViewerObject::getGLTFNodeTransformAgent(S32 node_index) const +{ + LLMatrix4a mat; + + if (mGLTFAsset.notNull() && node_index >= 0 && node_index < mGLTFAsset->mNodes.size()) + { + auto& node = mGLTFAsset->mNodes[node_index]; + + LLMatrix4a asset_to_agent = getGLTFAssetToAgentTransform(); + LLMatrix4a node_to_agent; + matMul(node.mAssetMatrix, asset_to_agent, node_to_agent); + + mat = node_to_agent; + } + else + { + mat.setIdentity(); + } + + return mat; +} +void LLViewerObject::getGLTFNodeTransformAgent(S32 node_index, LLVector3* position, LLQuaternion* rotation, LLVector3* scale) const +{ + LLMatrix4a node_to_agent = getGLTFNodeTransformAgent(node_index); + + if (position) + { + LLVector4a p = node_to_agent.getTranslation(); + position->set(p.getF32ptr()); + } + + if (rotation) + { + rotation->set(node_to_agent.asMatrix4()); + } + + if (scale) + { + scale->mV[0] = node_to_agent.mMatrix[0].getLength3().getF32(); + scale->mV[1] = node_to_agent.mMatrix[1].getLength3().getF32(); + scale->mV[2] = node_to_agent.mMatrix[2].getLength3().getF32(); + } +} + +void decomposeMatrix(const LLMatrix4a& mat, LLVector3& position, LLQuaternion& rotation, LLVector3& scale) +{ + LLVector4a p = mat.getTranslation(); + position.set(p.getF32ptr()); + + rotation.set(mat.asMatrix4()); + + scale.mV[0] = mat.mMatrix[0].getLength3().getF32(); + scale.mV[1] = mat.mMatrix[1].getLength3().getF32(); + scale.mV[2] = mat.mMatrix[2].getLength3().getF32(); +} + +void LLViewerObject::setGLTFNodeRotationAgent(S32 node_index, const LLQuaternion& rotation) +{ + if (mGLTFAsset.notNull() && node_index >= 0 && node_index < mGLTFAsset->mNodes.size()) + { + auto& node = mGLTFAsset->mNodes[node_index]; + + LLMatrix4a agent_to_asset = getAgentToGLTFAssetTransform(); + LLMatrix4a agent_to_node = agent_to_asset; + + if (node.mParent != -1) + { + auto& parent = mGLTFAsset->mNodes[node.mParent]; + matMul(agent_to_asset, parent.mAssetMatrixInv, agent_to_node); + } + + LLQuaternion agent_to_node_rot(agent_to_node.asMatrix4()); + LLQuaternion new_rot; + + new_rot = rotation * agent_to_node_rot; + new_rot.normalize(); + + LLVector3 pos; + LLQuaternion rot; + LLVector3 scale; + decomposeMatrix(node.mMatrix, pos, rot, scale); + + node.mMatrix.asMatrix4().initAll(scale, new_rot, pos); + + mGLTFAsset->updateTransforms(); + } +} + +void LLViewerObject::moveGLTFNode(S32 node_index, const LLVector3& offset) +{ + if (mGLTFAsset.notNull() && node_index >= 0 && node_index < mGLTFAsset->mNodes.size()) + { + auto& node = mGLTFAsset->mNodes[node_index]; + + LLMatrix4a agent_to_asset = getAgentToGLTFAssetTransform(); + LLMatrix4a agent_to_node; + matMul(agent_to_asset, node.mAssetMatrixInv, agent_to_node); + + LLVector4a origin = LLVector4a::getZero(); + LLVector4a offset_v; + offset_v.load3(offset.mV); + + + agent_to_node.affineTransform(offset_v, offset_v); + agent_to_node.affineTransform(origin, origin); + + offset_v.sub(origin); + offset_v.getF32ptr()[3] = 1.f; + + LLMatrix4a trans; + trans.setIdentity(); + trans.mMatrix[3] = offset_v; + + matMul(trans, node.mMatrix, node.mMatrix); + + // TODO -- only update transforms for this node and its children (or use a dirty flag) + mGLTFAsset->updateTransforms(); + } +} + const LLVector3 &LLViewerObject::getPositionRegion() const { if (!isRoot()) @@ -5407,7 +5571,6 @@ S32 LLViewerObject::setTEFullbright(const U8 te, const U8 fullbright) return retval; } - S32 LLViewerObject::setTEMediaFlags(const U8 te, const U8 media_flags) { // this might need work for media type diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 2ab5eb72e8..2545de3784 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -45,6 +45,7 @@ #include "llbbox.h" #include "llrigginginfo.h" #include "llreflectionmap.h" +#include "gltf/asset.h" #include "fsregioncross.h" // Improved region crossing support @@ -320,6 +321,18 @@ public: virtual const LLVector3 &getPositionAgent() const; virtual const LLVector3 getRenderPosition() const; + LLMatrix4a getAgentToGLTFAssetTransform() const; + LLMatrix4a getGLTFAssetToAgentTransform() const; + LLVector3 getGLTFNodePositionAgent(S32 node_index) const; + LLMatrix4a getGLTFNodeTransformAgent(S32 node_index) const; + void getGLTFNodeTransformAgent(S32 node_index, LLVector3* position, LLQuaternion* rotation, LLVector3* scale) const; + + // move the node at the given index by the given offset in agent space + void moveGLTFNode(S32 node_index, const LLVector3& offset); + + // set the rotation in agent space of the given node + void setGLTFNodeRotationAgent(S32 node_index, const LLQuaternion& rotation); + virtual const LLVector3 getPivotPositionAgent() const; // Usually = to getPositionAgent, unless like flex objects it's not LLViewerObject* getRootEdit() const; @@ -739,6 +752,8 @@ public: F32 mPhysicsDensity; F32 mPhysicsRestitution; + // Associated GLTF Asset + LLPointer mGLTFAsset; // Pipeline classes LLPointer mDrawable; @@ -964,6 +979,7 @@ public: // reflection probe state bool mIsReflectionProbe = false; // if true, this object should register itself with LLReflectionProbeManager LLPointer mReflectionProbe = nullptr; // reflection probe coupled to this viewer object. If not null, should be deregistered when this object is destroyed + bool mIsHeroProbe = false; // This is a special case for mirrors and other high resolution probes. // the amount of GPU time (in ms) it took to render this object according to LLPipeline::profileAvatar // -1.f if no profile data available diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 9aca4786f7..285dd0a727 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -843,13 +843,9 @@ void LLViewerRegion::loadObjectCache() if(LLVOCache::instanceExists()) { LLVOCache & vocache = LLVOCache::instance(); - // FIRE-33808 - Material Override Cache causes long delays - // vocache.readFromCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap); - // vocache.readGenericExtrasFromCache(mHandle, mImpl->mCacheID, mImpl->mGLTFOverridesLLSD); - // mark as dirty if read fails to force a rewrite. + // Without this a "corrupted" vocache persists until a cache clear or other rewrite. Mark as dirty hereif read fails to force a rewrite. mCacheDirty = !vocache.readFromCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap); vocache.readGenericExtrasFromCache(mHandle, mImpl->mCacheID, mImpl->mGLTFOverridesLLSD, mImpl->mCacheMap); - // if (mImpl->mCacheMap.empty()) { @@ -1196,6 +1192,11 @@ void LLViewerRegion::dirtyHeights() } } +void LLViewerRegion::dirtyAllPatches() +{ + getLand().dirtyAllPatches(); +} + //physically delete the cache entry void LLViewerRegion::killCacheEntry(LLVOCacheEntry* entry, bool for_rendering) { @@ -1246,16 +1247,12 @@ void LLViewerRegion::killCacheEntry(LLVOCacheEntry* entry, bool for_rendering) child = entry->getChild(); } } - - // Fix the missing kill on overrides + // Kill the assocaited overrides mImpl->mGLTFOverridesLLSD.erase(entry->getLocalID()); - // //will remove it from the object cache, real deletion entry->setState(LLVOCacheEntry::INACTIVE); entry->removeOctreeEntry(); entry->setValid(false); - // Fix the missing kill on overrides - // // TODO kill extras/material overrides cache too } @@ -1700,7 +1697,19 @@ void LLViewerRegion::idleUpdate(F32 max_update_time) mLastUpdate = LLViewerOctreeEntryData::getCurrentFrame(); - mImpl->mLandp->idleUpdate(max_update_time); + static LLCachedControl pbr_terrain_enabled(gSavedSettings, "RenderTerrainPBREnabled", false); + static LLCachedControl pbr_terrain_experimental_normals(gSavedSettings, "RenderTerrainPBRNormalsEnabled", false); + bool pbr_material = mImpl->mCompositionp && (mImpl->mCompositionp->getMaterialType() == LLTerrainMaterials::Type::PBR); + bool pbr_land = pbr_material && pbr_terrain_enabled && pbr_terrain_experimental_normals; + + if (!pbr_land) + { + mImpl->mLandp->idleUpdate(max_update_time); + } + else + { + mImpl->mLandp->idleUpdate(max_update_time); + } if (mParcelOverlay) { @@ -2001,7 +2010,21 @@ LLViewerObject* LLViewerRegion::updateCacheEntry(U32 local_id, LLViewerObject* o // As above, but forcibly do the update. void LLViewerRegion::forceUpdate() { - mImpl->mLandp->idleUpdate(0.f); + constexpr F32 max_update_time = 0.f; + + static LLCachedControl pbr_terrain_enabled(gSavedSettings, "RenderTerrainPBREnabled", false); + static LLCachedControl pbr_terrain_experimental_normals(gSavedSettings, "RenderTerrainPBRNormalsEnabled", false); + bool pbr_material = mImpl->mCompositionp && (mImpl->mCompositionp->getMaterialType() == LLTerrainMaterials::Type::PBR); + bool pbr_land = pbr_material && pbr_terrain_enabled && pbr_terrain_experimental_normals; + + if (!pbr_land) + { + mImpl->mLandp->idleUpdate(max_update_time); + } + else + { + mImpl->mLandp->idleUpdate(max_update_time); + } if (mParcelOverlay) { @@ -2581,6 +2604,54 @@ void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features) setSimulatorFeaturesReceived(true); + // WARNING: this is called from a coroutine, and flipping saved settings has a LOT of side effects, shuttle + // the work below back to the main loop + // + + // copy features to lambda in case the region is deleted before the lambda is executed + LLSD features = mSimulatorFeatures; + + auto work = [=]() + { + // if region has MaxTextureResolution, set max_texture_dimension settings, otherwise use default + if (features.has("MaxTextureResolution")) + { + S32 max_texture_resolution = features["MaxTextureResolution"].asInteger(); + gSavedSettings.setS32("max_texture_dimension_X", max_texture_resolution); + gSavedSettings.setS32("max_texture_dimension_Y", max_texture_resolution); + } + else + { + gSavedSettings.setS32("max_texture_dimension_X", 1024); + gSavedSettings.setS32("max_texture_dimension_Y", 1024); + } + + if (features.has("PBRTerrainEnabled")) + { + bool enabled = features["PBRTerrainEnabled"]; + gSavedSettings.setBOOL("RenderTerrainPBREnabled", enabled); + } + else + { + gSavedSettings.setBOOL("RenderTerrainPBREnabled", false); + } + + if (features.has("PBRMaterialSwatchEnabled")) + { + bool enabled = features["PBRMaterialSwatchEnabled"]; + gSavedSettings.setBOOL("UIPreviewMaterial", enabled); + } + else + { + gSavedSettings.setBOOL("UIPreviewMaterial", false); + } + }; + + auto workqueue = LL::WorkQueue::getInstance("mainloop"); + if (workqueue) + { + LL::WorkQueue::postMaybe(workqueue, work); + } // Opensim #ifdef OPENSIM @@ -3218,20 +3289,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; @@ -3943,12 +4014,11 @@ void LLViewerRegion::applyCacheMiscExtras(LLViewerObject* obj) auto iter = mImpl->mGLTFOverridesLLSD.find(local_id); if (iter != mImpl->mGLTFOverridesLLSD.end()) { - // backfill the UUID if it was left empty + // UUID can be inserted null, so backfill the UUID if it was left empty if (iter->second.mObjectId.isNull()) { iter->second.mObjectId = obj->getID(); } - // llassert(iter->second.mGLTFMaterial.size() == iter->second.mSides.size()); for (auto& side : iter->second.mGLTFMaterial) diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 5863f406fa..5d38d0944a 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -180,6 +180,9 @@ public: // Call this whenever you change the height data in the region. // (Automatically called by LLSurfacePatch's update routine) void dirtyHeights(); + // Call this whenever you want to force all terrain to rebuild. + // (For example, if a global terrain config option has changed) + void dirtyAllPatches(); LLViewerParcelOverlay *getParcelOverlay() const { return mParcelOverlay; } diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 4be8ddb74c..837ed5fc11 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; @@ -77,12 +85,15 @@ LLGLSLShader gGlowCombineProgram; LLGLSLShader gReflectionMipProgram; LLGLSLShader gGaussianProgram; LLGLSLShader gRadianceGenProgram; +LLGLSLShader gHeroRadianceGenProgram; LLGLSLShader gIrradianceGenProgram; LLGLSLShader gGlowCombineFXAAProgram; LLGLSLShader gTwoTextureCompareProgram; LLGLSLShader gOneTextureFilterProgram; LLGLSLShader gDebugProgram; LLGLSLShader gSkinnedDebugProgram; +LLGLSLShader gNormalDebugProgram[NORMAL_DEBUG_SHADER_COUNT]; +LLGLSLShader gSkinnedNormalDebugProgram[NORMAL_DEBUG_SHADER_COUNT]; LLGLSLShader gClipProgram; LLGLSLShader gAlphaMaskProgram; LLGLSLShader gBenchmarkProgram; @@ -95,7 +106,6 @@ LLGLSLShader gObjectPreviewProgram; LLGLSLShader gSkinnedObjectPreviewProgram; LLGLSLShader gPhysicsPreviewProgram; LLGLSLShader gObjectFullbrightAlphaMaskProgram; -LLGLSLShader gSkinnedObjectFullbrightAlphaMaskProgram; LLGLSLShader gObjectBumpProgram; LLGLSLShader gSkinnedObjectBumpProgram; LLGLSLShader gObjectAlphaMaskNoColorProgram; @@ -187,10 +197,12 @@ LLGLSLShader gDeferredPostGammaCorrectProgram; LLGLSLShader gNoPostGammaCorrectProgram; LLGLSLShader gLegacyPostGammaCorrectProgram; LLGLSLShader gExposureProgram; +LLGLSLShader gExposureProgramNoFade; LLGLSLShader gLuminanceProgram; LLGLSLShader gFXAAProgram; LLGLSLShader gDeferredPostNoDoFProgram; LLGLSLShader gDeferredWLSkyProgram; +LLGLSLShader gEnvironmentMapProgram; LLGLSLShader gDeferredWLCloudProgram; LLGLSLShader gDeferredWLSunProgram; LLGLSLShader gDeferredWLMoonProgram; @@ -218,9 +230,10 @@ 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) +static bool make_rigged_variant(LLGLSLShader& shader, LLGLSLShader& riggedShader) { riggedShader.mName = llformat("Skinned %s", shader.mName.c_str()); riggedShader.mFeatures = shader.mFeatures; @@ -235,9 +248,49 @@ bool make_rigged_variant(LLGLSLShader& shader, LLGLSLShader& riggedShader) return riggedShader.createShader(NULL, NULL); } +#ifdef SHOW_ASSERT +// return true if there are no redundant shaders in the given vector +// also checks for redundant variants +static bool no_redundant_shaders(const std::vector& shaders) +{ + std::set names; + for (LLGLSLShader* shader : shaders) + { + if (names.find(shader->mName) != names.end()) + { + LL_WARNS("Shader") << "Redundant shader: " << shader->mName << LL_ENDL; + return false; + } + names.insert(shader->mName); + + if (shader->mRiggedVariant) + { + if (names.find(shader->mRiggedVariant->mName) != names.end()) + { + LL_WARNS("Shader") << "Redundant shader: " << shader->mRiggedVariant->mName << LL_ENDL; + return false; + } + names.insert(shader->mRiggedVariant->mName); + } + } + return true; +} +#endif + + LLViewerShaderMgr::LLViewerShaderMgr() : mShaderLevel(SHADER_COUNT, 0), mMaxAvatarShaderLevel(0) +{ +} + +LLViewerShaderMgr::~LLViewerShaderMgr() +{ + mShaderLevel.clear(); + mShaderList.clear(); +} + +void LLViewerShaderMgr::finalizeShaderList() { //ONLY shaders that need WL Param management should be added here mShaderList.push_back(&gAvatarProgram); @@ -246,9 +299,7 @@ LLViewerShaderMgr::LLViewerShaderMgr() : mShaderList.push_back(&gAvatarEyeballProgram); mShaderList.push_back(&gImpostorProgram); mShaderList.push_back(&gObjectBumpProgram); - mShaderList.push_back(&gSkinnedObjectBumpProgram); mShaderList.push_back(&gObjectFullbrightAlphaMaskProgram); - mShaderList.push_back(&gSkinnedObjectFullbrightAlphaMaskProgram); mShaderList.push_back(&gObjectAlphaMaskNoColorProgram); mShaderList.push_back(&gUnderWaterProgram); mShaderList.push_back(&gDeferredSunProgram); @@ -257,9 +308,7 @@ LLViewerShaderMgr::LLViewerShaderMgr() : mShaderList.push_back(&gDeferredSoftenProgram); mShaderList.push_back(&gDeferredAlphaProgram); mShaderList.push_back(&gHUDAlphaProgram); - mShaderList.push_back(&gDeferredSkinnedAlphaProgram); mShaderList.push_back(&gDeferredAlphaImpostorProgram); - mShaderList.push_back(&gDeferredSkinnedAlphaImpostorProgram); mShaderList.push_back(&gDeferredFullbrightProgram); mShaderList.push_back(&gHUDFullbrightProgram); mShaderList.push_back(&gDeferredFullbrightAlphaMaskProgram); @@ -268,31 +317,31 @@ LLViewerShaderMgr::LLViewerShaderMgr() : mShaderList.push_back(&gHUDFullbrightAlphaMaskAlphaProgram); mShaderList.push_back(&gDeferredFullbrightShinyProgram); mShaderList.push_back(&gHUDFullbrightShinyProgram); - mShaderList.push_back(&gDeferredSkinnedFullbrightShinyProgram); - mShaderList.push_back(&gDeferredSkinnedFullbrightProgram); - mShaderList.push_back(&gDeferredSkinnedFullbrightAlphaMaskProgram); - mShaderList.push_back(&gDeferredSkinnedFullbrightAlphaMaskAlphaProgram); mShaderList.push_back(&gDeferredEmissiveProgram); - mShaderList.push_back(&gDeferredSkinnedEmissiveProgram); mShaderList.push_back(&gDeferredAvatarEyesProgram); mShaderList.push_back(&gDeferredAvatarAlphaProgram); + mShaderList.push_back(&gEnvironmentMapProgram); mShaderList.push_back(&gDeferredWLSkyProgram); mShaderList.push_back(&gDeferredWLCloudProgram); mShaderList.push_back(&gDeferredWLMoonProgram); mShaderList.push_back(&gDeferredWLSunProgram); mShaderList.push_back(&gDeferredPBRAlphaProgram); mShaderList.push_back(&gHUDPBRAlphaProgram); - mShaderList.push_back(&gDeferredSkinnedPBRAlphaProgram); mShaderList.push_back(&gDeferredPostGammaCorrectProgram); // for gamma mShaderList.push_back(&gNoPostGammaCorrectProgram); mShaderList.push_back(&gLegacyPostGammaCorrectProgram); + mShaderList.push_back(&gDeferredDiffuseProgram); + mShaderList.push_back(&gDeferredBumpProgram); + mShaderList.push_back(&gDeferredPBROpaqueProgram); + mShaderList.push_back(&gDeferredAvatarProgram); + mShaderList.push_back(&gDeferredTerrainProgram); + mShaderList.push_back(&gDeferredPBRTerrainProgram); + mShaderList.push_back(&gDeferredDiffuseAlphaMaskProgram); + mShaderList.push_back(&gDeferredNonIndexedDiffuseAlphaMaskProgram); + mShaderList.push_back(&gDeferredTreeProgram); -} - -LLViewerShaderMgr::~LLViewerShaderMgr() -{ - mShaderLevel.clear(); - mShaderList.clear(); + // make sure there are no redundancies + llassert(no_redundant_shaders(mShaderList)); } // static @@ -347,6 +396,10 @@ void LLViewerShaderMgr::setShaders() return; } + mShaderList.clear(); + + LLShaderMgr::sMirrorsEnabled = LLPipeline::RenderMirrors; + if (!gGLManager.mHasRequirements) { // Viewer will show 'hardware requirements' warning later @@ -374,7 +427,10 @@ void LLViewerShaderMgr::setShaders() static LLCachedControl max_texture_index(gSavedSettings, "RenderMaxTextureIndex", 16); // when using indexed texture rendering, leave some texture units available for shadow and reflection maps - LLGLSLShader::sIndexedTextureChannels = llmax(llmin(gGLManager.mNumTextureImageUnits-12, (S32) max_texture_index), 1); + static LLCachedControl reserved_texture_units(gSavedSettings, "RenderReservedTextureIndices", 14); + + LLGLSLShader::sIndexedTextureChannels = + llclamp(max_texture_index, 1, gGLManager.mNumTextureImageUnits-reserved_texture_units); reentrance = true; @@ -528,6 +584,8 @@ void LLViewerShaderMgr::setShaders() } gPipeline.createGLBuffers(); + finalizeShaderList(); + reentrance = false; } @@ -627,6 +685,16 @@ 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"); + detail = llclamp(detail, TERRAIN_PBR_DETAIL_MIN, TERRAIN_PBR_DETAIL_MAX); + 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. @@ -659,11 +727,12 @@ std::string LLViewerShaderMgr::loadBasicShaders() index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/atmosphericsFuncs.glsl", mShaderLevel[SHADER_WINDLIGHT] ) ); index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/atmosphericsF.glsl", mShaderLevel[SHADER_WINDLIGHT] ) ); index_channels.push_back(-1); shaders.push_back( make_pair( "environment/waterFogF.glsl", mShaderLevel[SHADER_WATER] ) ); - index_channels.push_back(-1); shaders.push_back( make_pair( "environment/encodeNormF.glsl", mShaderLevel[SHADER_ENVIRONMENT] ) ); index_channels.push_back(-1); shaders.push_back( make_pair( "environment/srgbF.glsl", mShaderLevel[SHADER_ENVIRONMENT] ) ); 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/globalF.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] ) ); @@ -934,11 +1003,13 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredCoFProgram.unload(); gDeferredDoFCombineProgram.unload(); gExposureProgram.unload(); + gExposureProgramNoFade.unload(); gLuminanceProgram.unload(); gDeferredPostGammaCorrectProgram.unload(); gNoPostGammaCorrectProgram.unload(); gLegacyPostGammaCorrectProgram.unload(); gFXAAProgram.unload(); + gEnvironmentMapProgram.unload(); gDeferredWLSkyProgram.unload(); gDeferredWLCloudProgram.unload(); gDeferredWLSunProgram.unload(); @@ -968,6 +1039,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredSkinnedPBROpaqueProgram.unload(); gDeferredPBRAlphaProgram.unload(); gDeferredSkinnedPBRAlphaProgram.unload(); + gDeferredPBRTerrainProgram.unload(); // [RLVa:KB] - @setsphere gRlvSphereProgram.unload(); @@ -990,7 +1062,6 @@ bool LLViewerShaderMgr::loadShadersDeferred() if (success) { gDeferredDiffuseProgram.mName = "Deferred Diffuse Shader"; - gDeferredDiffuseProgram.mFeatures.encodesNormal = true; gDeferredDiffuseProgram.mFeatures.hasSrgb = true; gDeferredDiffuseProgram.mShaderFiles.clear(); gDeferredDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseV.glsl", GL_VERTEX_SHADER)); @@ -1004,7 +1075,6 @@ bool LLViewerShaderMgr::loadShadersDeferred() if (success) { gDeferredDiffuseAlphaMaskProgram.mName = "Deferred Diffuse Alpha Mask Shader"; - gDeferredDiffuseAlphaMaskProgram.mFeatures.encodesNormal = true; gDeferredDiffuseAlphaMaskProgram.mShaderFiles.clear(); gDeferredDiffuseAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/diffuseV.glsl", GL_VERTEX_SHADER)); gDeferredDiffuseAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/diffuseAlphaMaskIndexedF.glsl", GL_FRAGMENT_SHADER)); @@ -1017,7 +1087,6 @@ bool LLViewerShaderMgr::loadShadersDeferred() if (success) { gDeferredNonIndexedDiffuseAlphaMaskProgram.mName = "Deferred Diffuse Non-Indexed Alpha Mask Shader"; - gDeferredNonIndexedDiffuseAlphaMaskProgram.mFeatures.encodesNormal = true; gDeferredNonIndexedDiffuseAlphaMaskProgram.mShaderFiles.clear(); gDeferredNonIndexedDiffuseAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/diffuseV.glsl", GL_VERTEX_SHADER)); gDeferredNonIndexedDiffuseAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/diffuseAlphaMaskF.glsl", GL_FRAGMENT_SHADER)); @@ -1029,7 +1098,6 @@ bool LLViewerShaderMgr::loadShadersDeferred() if (success) { gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mName = "Deferred Diffuse Non-Indexed Alpha Mask No Color Shader"; - gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mFeatures.encodesNormal = true; gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mShaderFiles.clear(); gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mShaderFiles.push_back(make_pair("deferred/diffuseNoColorV.glsl", GL_VERTEX_SHADER)); gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mShaderFiles.push_back(make_pair("deferred/diffuseAlphaMaskNoColorF.glsl", GL_FRAGMENT_SHADER)); @@ -1041,7 +1109,6 @@ bool LLViewerShaderMgr::loadShadersDeferred() if (success) { gDeferredBumpProgram.mName = "Deferred Bump Shader"; - gDeferredBumpProgram.mFeatures.encodesNormal = true; gDeferredBumpProgram.mShaderFiles.clear(); gDeferredBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpV.glsl", GL_VERTEX_SHADER)); gDeferredBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpF.glsl", GL_FRAGMENT_SHADER)); @@ -1064,9 +1131,17 @@ bool LLViewerShaderMgr::loadShadersDeferred() { if (success) { - mShaderList.push_back(&gDeferredMaterialProgram[i]); + bool has_skin = i & 0x10; - gDeferredMaterialProgram[i].mName = llformat("Deferred Material Shader %d", i); + if (!has_skin) + { + mShaderList.push_back(&gDeferredMaterialProgram[i]); + gDeferredMaterialProgram[i].mName = llformat("Material Shader %d", i); + } + else + { + gDeferredMaterialProgram[i].mName = llformat("Skinned Material Shader %d", i); + } U32 alpha_mode = i & 0x3; @@ -1103,9 +1178,8 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredMaterialProgram[i].addPermutation("HAS_SUN_SHADOW", "1"); } - bool has_skin = i & 0x10; + gDeferredMaterialProgram[i].mFeatures.hasSrgb = true; - gDeferredMaterialProgram[i].mFeatures.encodesNormal = true; gDeferredMaterialProgram[i].mFeatures.calculatesAtmospherics = true; gDeferredMaterialProgram[i].mFeatures.hasAtmospherics = true; gDeferredMaterialProgram[i].mFeatures.hasGamma = true; @@ -1139,7 +1213,6 @@ bool LLViewerShaderMgr::loadShadersDeferred() if (success) { gDeferredPBROpaqueProgram.mName = "Deferred PBR Opaque Shader"; - gDeferredPBROpaqueProgram.mFeatures.encodesNormal = true; gDeferredPBROpaqueProgram.mFeatures.hasSrgb = true; gDeferredPBROpaqueProgram.mShaderFiles.clear(); @@ -1200,7 +1273,6 @@ bool LLViewerShaderMgr::loadShadersDeferred() shader->mFeatures.hasLighting = false; shader->mFeatures.isAlphaLighting = true; shader->mFeatures.hasSrgb = true; - shader->mFeatures.encodesNormal = true; shader->mFeatures.calculatesAtmospherics = true; shader->mFeatures.hasAtmospherics = true; shader->mFeatures.hasGamma = true; @@ -1263,11 +1335,37 @@ bool LLViewerShaderMgr::loadShadersDeferred() 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.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) { gDeferredTreeProgram.mName = "Deferred Tree Shader"; gDeferredTreeProgram.mShaderFiles.clear(); - gDeferredTreeProgram.mFeatures.encodesNormal = true; gDeferredTreeProgram.mShaderFiles.push_back(make_pair("deferred/treeV.glsl", GL_VERTEX_SHADER)); gDeferredTreeProgram.mShaderFiles.push_back(make_pair("deferred/treeF.glsl", GL_FRAGMENT_SHADER)); gDeferredTreeProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; @@ -1302,8 +1400,6 @@ bool LLViewerShaderMgr::loadShadersDeferred() { gDeferredImpostorProgram.mName = "Deferred Impostor Shader"; gDeferredImpostorProgram.mFeatures.hasSrgb = true; - gDeferredImpostorProgram.mFeatures.encodesNormal = true; - //gDeferredImpostorProgram.mFeatures.isDeferred = true; gDeferredImpostorProgram.mShaderFiles.clear(); gDeferredImpostorProgram.mShaderFiles.push_back(make_pair("deferred/impostorV.glsl", GL_VERTEX_SHADER)); gDeferredImpostorProgram.mShaderFiles.push_back(make_pair("deferred/impostorF.glsl", GL_FRAGMENT_SHADER)); @@ -1465,7 +1561,6 @@ bool LLViewerShaderMgr::loadShadersDeferred() shader->mFeatures.isAlphaLighting = true; shader->mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels shader->mFeatures.hasSrgb = true; - shader->mFeatures.encodesNormal = true; shader->mFeatures.calculatesAtmospherics = true; shader->mFeatures.hasAtmospherics = true; shader->mFeatures.hasGamma = true; @@ -1527,7 +1622,6 @@ bool LLViewerShaderMgr::loadShadersDeferred() shader->mFeatures.hasSrgb = true; shader->mFeatures.isAlphaLighting = true; - shader->mFeatures.encodesNormal = true; shader->mFeatures.hasShadows = use_sun_shadow; shader->mFeatures.hasReflectionProbes = true; shader->mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; @@ -1575,7 +1669,6 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredAvatarEyesProgram.mFeatures.hasAtmospherics = true; gDeferredAvatarEyesProgram.mFeatures.disableTextureIndex = true; gDeferredAvatarEyesProgram.mFeatures.hasSrgb = true; - gDeferredAvatarEyesProgram.mFeatures.encodesNormal = true; gDeferredAvatarEyesProgram.mFeatures.hasShadows = true; gDeferredAvatarEyesProgram.mShaderFiles.clear(); @@ -1973,10 +2066,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() if (success) { 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; @@ -1995,11 +2085,9 @@ bool LLViewerShaderMgr::loadShadersDeferred() { gDeferredAvatarProgram.mName = "Deferred Avatar Shader"; gDeferredAvatarProgram.mFeatures.hasSkinning = true; - gDeferredAvatarProgram.mFeatures.encodesNormal = true; gDeferredAvatarProgram.mShaderFiles.clear(); gDeferredAvatarProgram.mShaderFiles.push_back(make_pair("deferred/avatarV.glsl", GL_VERTEX_SHADER)); gDeferredAvatarProgram.mShaderFiles.push_back(make_pair("deferred/avatarF.glsl", GL_FRAGMENT_SHADER)); - gDeferredAvatarProgram.addPermutation("AVATAR_CLOTH", (mShaderLevel[SHADER_AVATAR] == 3) ? "1" : "0"); // Fix avatar cloth failing to work in deferred gDeferredAvatarProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = gDeferredAvatarProgram.createShader(NULL, NULL); llassert(success); @@ -2014,7 +2102,6 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredAvatarAlphaProgram.mFeatures.isAlphaLighting = true; gDeferredAvatarAlphaProgram.mFeatures.disableTextureIndex = true; gDeferredAvatarAlphaProgram.mFeatures.hasSrgb = true; - gDeferredAvatarAlphaProgram.mFeatures.encodesNormal = true; gDeferredAvatarAlphaProgram.mFeatures.calculatesAtmospherics = true; gDeferredAvatarAlphaProgram.mFeatures.hasAtmospherics = true; gDeferredAvatarAlphaProgram.mFeatures.hasGamma = true; @@ -2050,6 +2137,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gExposureProgram.mFeatures.isDeferred = true; gExposureProgram.mShaderFiles.clear(); gExposureProgram.clearPermutations(); + gExposureProgram.addPermutation("USE_LAST_EXPOSURE", "1"); gExposureProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER)); gExposureProgram.mShaderFiles.push_back(make_pair("deferred/exposureF.glsl", GL_FRAGMENT_SHADER)); gExposureProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; @@ -2057,6 +2145,20 @@ bool LLViewerShaderMgr::loadShadersDeferred() llassert(success); } + if (success) + { + gExposureProgramNoFade.mName = "Exposure (no fade)"; + gExposureProgramNoFade.mFeatures.hasSrgb = true; + gExposureProgramNoFade.mFeatures.isDeferred = true; + gExposureProgramNoFade.mShaderFiles.clear(); + gExposureProgramNoFade.clearPermutations(); + gExposureProgramNoFade.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER)); + gExposureProgramNoFade.mShaderFiles.push_back(make_pair("deferred/exposureF.glsl", GL_FRAGMENT_SHADER)); + gExposureProgramNoFade.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + success = gExposureProgramNoFade.createShader(NULL, NULL); + llassert(success); + } + if (success) { gLuminanceProgram.mName = "Luminance"; @@ -2174,6 +2276,26 @@ bool LLViewerShaderMgr::loadShadersDeferred() llassert(success); } + if (success) + { + gEnvironmentMapProgram.mName = "Environment Map Program"; + gEnvironmentMapProgram.mShaderFiles.clear(); + gEnvironmentMapProgram.mFeatures.calculatesAtmospherics = true; + gEnvironmentMapProgram.mFeatures.hasAtmospherics = true; + gEnvironmentMapProgram.mFeatures.hasGamma = true; + gEnvironmentMapProgram.mFeatures.hasSrgb = true; + + gEnvironmentMapProgram.clearPermutations(); + gEnvironmentMapProgram.addPermutation("HAS_HDRI", "1"); + gEnvironmentMapProgram.mShaderFiles.push_back(make_pair("deferred/skyV.glsl", GL_VERTEX_SHADER)); + gEnvironmentMapProgram.mShaderFiles.push_back(make_pair("deferred/skyF.glsl", GL_FRAGMENT_SHADER)); + gEnvironmentMapProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + gEnvironmentMapProgram.mShaderGroup = LLGLSLShader::SG_SKY; + + success = gEnvironmentMapProgram.createShader(NULL, NULL); + llassert(success); + } + if (success) { gDeferredWLSkyProgram.mName = "Deferred Windlight Sky Shader"; @@ -2327,7 +2449,6 @@ bool LLViewerShaderMgr::loadShadersObject() if (success) { gObjectBumpProgram.mName = "Bump Shader"; - gObjectBumpProgram.mFeatures.encodesNormal = true; gObjectBumpProgram.mShaderFiles.clear(); gObjectBumpProgram.mShaderFiles.push_back(make_pair("objects/bumpV.glsl", GL_VERTEX_SHADER)); gObjectBumpProgram.mShaderFiles.push_back(make_pair("objects/bumpF.glsl", GL_FRAGMENT_SHADER)); @@ -2676,6 +2797,33 @@ bool LLViewerShaderMgr::loadShadersInterface() success = success && gDebugProgram.createShader(NULL, NULL); } + if (success) + { + for (S32 variant = 0; variant < NORMAL_DEBUG_SHADER_COUNT; ++variant) + { + LLGLSLShader& shader = gNormalDebugProgram[variant]; + LLGLSLShader& skinned_shader = gSkinnedNormalDebugProgram[variant]; + shader.mName = "Normal Debug Shader"; + shader.mShaderFiles.clear(); + shader.mShaderFiles.push_back(make_pair("interface/normaldebugV.glsl", GL_VERTEX_SHADER)); + // *NOTE: Geometry shaders have a reputation for being slow. + // Consider using compute shaders instead, which have a reputation + // for being fast. This geometry shader in particular seems to run + // fine on my machine, but I won't vouch for this in + // performance-critical areas. -Cosmic,2023-09-28 + shader.mShaderFiles.push_back(make_pair("interface/normaldebugG.glsl", GL_GEOMETRY_SHADER)); + shader.mShaderFiles.push_back(make_pair("interface/normaldebugF.glsl", GL_FRAGMENT_SHADER)); + shader.mRiggedVariant = &skinned_shader; + shader.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; + if (variant == NORMAL_DEBUG_SHADER_WITH_TANGENTS) + { + shader.addPermutation("HAS_ATTRIBUTE_TANGENT", "1"); + } + success = make_rigged_variant(shader, skinned_shader); + success = success && shader.createShader(NULL, NULL); + } + } + if (success) { gClipProgram.mName = "Clip Shader"; @@ -2779,9 +2927,22 @@ bool LLViewerShaderMgr::loadShadersInterface() gRadianceGenProgram.mShaderFiles.push_back(make_pair("interface/radianceGenV.glsl", GL_VERTEX_SHADER)); gRadianceGenProgram.mShaderFiles.push_back(make_pair("interface/radianceGenF.glsl", GL_FRAGMENT_SHADER)); gRadianceGenProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; + gRadianceGenProgram.addPermutation("PROBE_FILTER_SAMPLES", "32"); success = gRadianceGenProgram.createShader(NULL, NULL); } + if (success && gGLManager.mHasCubeMapArray) + { + gHeroRadianceGenProgram.mName = "Hero Radiance Gen Shader"; + gHeroRadianceGenProgram.mShaderFiles.clear(); + gHeroRadianceGenProgram.mShaderFiles.push_back(make_pair("interface/radianceGenV.glsl", GL_VERTEX_SHADER)); + gHeroRadianceGenProgram.mShaderFiles.push_back(make_pair("interface/radianceGenF.glsl", GL_FRAGMENT_SHADER)); + gHeroRadianceGenProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; + gHeroRadianceGenProgram.addPermutation("HERO_PROBES", "1"); + gHeroRadianceGenProgram.addPermutation("PROBE_FILTER_SAMPLES", "4"); + success = gHeroRadianceGenProgram.createShader(NULL, NULL); + } + if (success && gGLManager.mHasCubeMapArray) { gIrradianceGenProgram.mName = "Irradiance Gen Shader"; diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index 91550fe0b1..594d88800b 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -41,6 +41,10 @@ public: LLViewerShaderMgr(); /* virtual */ ~LLViewerShaderMgr(); + // Add shaders to mShaderList for later uniform propagation + // Will assert on redundant shader entries in debug builds + void finalizeShaderList(); + // singleton pattern implementation static LLViewerShaderMgr * instance(); static void releaseInstance(); @@ -153,9 +157,18 @@ extern LLGLSLShader gGlowCombineProgram; extern LLGLSLShader gReflectionMipProgram; extern LLGLSLShader gGaussianProgram; extern LLGLSLShader gRadianceGenProgram; +extern LLGLSLShader gHeroRadianceGenProgram; extern LLGLSLShader gIrradianceGenProgram; extern LLGLSLShader gGlowCombineFXAAProgram; extern LLGLSLShader gDebugProgram; +enum NormalDebugShaderVariant : S32 +{ + NORMAL_DEBUG_SHADER_DEFAULT, + NORMAL_DEBUG_SHADER_WITH_TANGENTS, + NORMAL_DEBUG_SHADER_COUNT +}; +extern LLGLSLShader gNormalDebugProgram[NORMAL_DEBUG_SHADER_COUNT]; +extern LLGLSLShader gSkinnedNormalDebugProgram[NORMAL_DEBUG_SHADER_COUNT]; extern LLGLSLShader gClipProgram; extern LLGLSLShader gBenchmarkProgram; extern LLGLSLShader gReflectionProbeDisplayProgram; @@ -171,7 +184,6 @@ extern LLGLSLShader gOneTextureFilterProgram; //object shaders extern LLGLSLShader gObjectPreviewProgram; extern LLGLSLShader gPhysicsPreviewProgram; -extern LLGLSLShader gSkinnedObjectFullbrightAlphaMaskProgram; extern LLGLSLShader gObjectBumpProgram; extern LLGLSLShader gSkinnedObjectBumpProgram; extern LLGLSLShader gObjectAlphaMaskNoColorProgram; @@ -238,6 +250,7 @@ extern LLGLSLShader gDeferredPostGammaCorrectProgram; extern LLGLSLShader gNoPostGammaCorrectProgram; extern LLGLSLShader gLegacyPostGammaCorrectProgram; extern LLGLSLShader gExposureProgram; +extern LLGLSLShader gExposureProgramNoFade; extern LLGLSLShader gLuminanceProgram; extern LLGLSLShader gDeferredAvatarShadowProgram; extern LLGLSLShader gDeferredAvatarAlphaShadowProgram; @@ -254,6 +267,7 @@ extern LLGLSLShader gHUDFullbrightAlphaMaskAlphaProgram; extern LLGLSLShader gDeferredEmissiveProgram; extern LLGLSLShader gDeferredAvatarEyesProgram; extern LLGLSLShader gDeferredAvatarAlphaProgram; +extern LLGLSLShader gEnvironmentMapProgram; extern LLGLSLShader gDeferredWLSkyProgram; extern LLGLSLShader gDeferredWLCloudProgram; extern LLGLSLShader gDeferredWLSunProgram; @@ -276,4 +290,20 @@ extern LLGLSLShader gPBRGlowProgram; extern LLGLSLShader gDeferredPBROpaqueProgram; extern LLGLSLShader gDeferredPBRAlphaProgram; extern LLGLSLShader gHUDPBRAlphaProgram; + +// Encodes detail level for dropping textures, in accordance with the GLTF spec where possible +// 0 is highest detail, -1 drops emissive, etc +// Dropping metallic roughness is off-spec - Reserve for potato machines as needed +// 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_NORMAL = -2, + TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS = -3, + TERRAIN_PBR_DETAIL_BASE_COLOR = -4, + TERRAIN_PBR_DETAIL_MIN = -4, +}; +extern LLGLSLShader gDeferredPBRTerrainProgram; #endif diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 4807356985..5e8dc197e2 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1728,7 +1728,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 { @@ -1741,7 +1741,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) { @@ -3127,6 +3127,14 @@ void LLViewerLODTexture::processTextureStats() static LLCachedControl textures_fullres(gSavedSettings,"TextureLoadFullRes", false); + { // restrict texture resolution to download based on RenderMaxTextureResolution + static LLCachedControl max_texture_resolution(gSavedSettings, "RenderMaxTextureResolution", 2048); + // sanity clamp debug setting to avoid settings hack shenanigans + F32 tex_res = (F32)llclamp((S32)max_texture_resolution, 512, 2048); + tex_res *= tex_res; + mMaxVirtualSize = llmin(mMaxVirtualSize, tex_res); + } + if (textures_fullres) { mDesiredDiscardLevel = 0; @@ -3136,7 +3144,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) { @@ -3181,7 +3189,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/llviewertexture.h b/indra/newview/llviewertexture.h index 8441b1ca68..5cc58db5d1 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -428,7 +428,6 @@ public: bool isCachedRawImageReady() const {return mCachedRawImageReady ;} bool isRawImageValid()const { return mIsRawImageValid ; } void forceToSaveRawImage(S32 desired_discard = 0, F32 kept_time = 0.f) ; - void forceToRefetchTexture(S32 desired_discard = 0, F32 kept_time = 60.f); /*virtual*/ void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) override; void destroySavedRawImage() ; LLImageRaw* getSavedRawImage() ; @@ -454,6 +453,8 @@ public: protected: /*virtual*/ void switchToCachedImage() override; S32 getCurrentDiscardLevelForFetching() ; +public: // Needed for texture refresh + void forceToRefetchTexture(S32 desired_discard = 0, F32 kept_time = 60.f); private: void init(bool firstinit) ; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 337266caa4..1c5fc87db0 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -276,6 +276,8 @@ LLVector2 gDebugRaycastTexCoord; LLVector4a gDebugRaycastNormal; LLVector4a gDebugRaycastTangent; S32 gDebugRaycastFaceHit; +S32 gDebugRaycastGLTFNodeHit; +S32 gDebugRaycastGLTFPrimitiveHit; LLVector4a gDebugRaycastStart; LLVector4a gDebugRaycastEnd; @@ -3844,9 +3846,11 @@ void LLViewerWindow::updateUI() if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST)) { - gDebugRaycastFaceHit = -1; + gDebugRaycastFaceHit = gDebugRaycastGLTFNodeHit = gDebugRaycastGLTFPrimitiveHit = -1; gDebugRaycastObject = cursorIntersect(-1, -1, 512.f, NULL, -1, false, false, true, false, &gDebugRaycastFaceHit, + &gDebugRaycastGLTFNodeHit, + &gDebugRaycastGLTFPrimitiveHit, &gDebugRaycastIntersection, &gDebugRaycastTexCoord, &gDebugRaycastNormal, @@ -5461,6 +5465,8 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de bool pick_unselectable, bool pick_reflection_probe, S32* face_hit, + S32* gltf_node_hit, + S32* gltf_primitive_hit, LLVector4a *intersection, LLVector2 *uv, LLVector4a *normal, @@ -5561,7 +5567,7 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de if (!found) // if not found in HUD, look in world: { found = gPipeline.lineSegmentIntersectInWorld(mw_start, mw_end, pick_transparent, pick_rigged, pick_unselectable, pick_reflection_probe, - face_hit, intersection, uv, normal, tangent); + face_hit, gltf_node_hit, gltf_primitive_hit, intersection, uv, normal, tangent); if (found && !pick_transparent) { gDebugRaycastIntersection = *intersection; @@ -6533,7 +6539,7 @@ bool LLViewerWindow::simpleSnapshot(LLImageRaw* raw, S32 image_width, S32 image_ void display_cube_face(); -bool LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubearray, S32 cubeIndex, S32 face, F32 near_clip, bool dynamic_render) +bool LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubearray, S32 cubeIndex, S32 face, F32 near_clip, bool dynamic_render, bool useCustomClipPlane, LLPlane clipPlane) { // NOTE: implementation derived from LLFloater360Capture::capture360Images() and simpleSnapshot LL_PROFILE_ZONE_SCOPED_CATEGORY_APP; @@ -6564,6 +6570,14 @@ bool LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubea camera->setOrigin(origin); camera->setNear(near_clip); + LLPlane previousClipPlane; + + if (useCustomClipPlane) + { + previousClipPlane = camera->getUserClipPlane(); + camera->setUserClipPlane(clipPlane); + } + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); // stencil buffer is deprecated | GL_STENCIL_BUFFER_BIT); U32 dynamic_render_types[] = { @@ -6671,6 +6685,11 @@ bool LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubea gPipeline.resetDrawOrders(); mWorldViewRectRaw = window_rect; + if (useCustomClipPlane) + { + camera->setUserClipPlane(previousClipPlane); + } + // restore original view/camera/avatar settings settings *camera = saved_camera; set_current_modelview(saved_mod); @@ -7490,8 +7509,8 @@ LLPickInfo::LLPickInfo(const LLCoordGL& mouse_pos, void LLPickInfo::fetchResults() { - S32 face_hit = -1; + LLVector4a intersection, normal; LLVector4a tangent; @@ -7513,8 +7532,8 @@ void LLPickInfo::fetchResults() icon_dist = delta.getLength3().getF32(); } LLViewerObject* hit_object = gViewerWindow->cursorIntersect(mMousePt.mX, mMousePt.mY, 512.f, - NULL, -1, mPickTransparent, mPickRigged, mPickUnselectable, mPickReflectionProbe, &face_hit, - &intersection, &uv, &normal, &tangent, &start, &end); + nullptr, -1, mPickTransparent, mPickRigged, mPickUnselectable, mPickReflectionProbe, &face_hit, &mGLTFNodeIndex, &mGLTFPrimitiveIndex, + &intersection, &uv, &normal, &tangent, &start, &end); mPickPt = mMousePt; @@ -7676,6 +7695,8 @@ void LLPickInfo::getSurfaceInfo() if (gViewerWindow->cursorIntersect(ll_round((F32)mMousePt.mX), ll_round((F32)mMousePt.mY), 1024.f, objectp, -1, mPickTransparent, mPickRigged, mPickUnselectable, mPickReflectionProbe, &mObjectFace, + &mGLTFNodeIndex, + &mGLTFPrimitiveIndex, &intersection, &mSTCoords, &normal, diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 24353e9e93..d04a314b9e 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -120,6 +120,8 @@ public: LLUUID mParticleOwnerID; LLUUID mParticleSourceID; S32 mObjectFace; + S32 mGLTFNodeIndex = -1; + S32 mGLTFPrimitiveIndex = -1; LLHUDIcon* mHUDIcon; LLVector3 mIntersection; LLVector2 mUVCoords; @@ -377,7 +379,8 @@ public: // index - cube index in the array to use (cube index, not face-layer) // face - which cube face to update // near_clip - near clip setting to use - bool cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubearray, S32 index, S32 face, F32 near_clip, bool render_avatars); + bool cubeSnapshot(const LLVector3 &origin, LLCubeMapArray *cubearray, S32 index, S32 face, F32 near_clip, bool render_avatars, + bool customCullingPlane = false, LLPlane cullingPlane = LLPlane(LLVector3(0, 0, 0), LLVector3(0, 0, 1))); // special implementation of simpleSnapshot for reflection maps @@ -425,6 +428,8 @@ public: bool pick_unselectable = true, bool pick_reflection_probe = true, S32* face_hit = NULL, + S32* gltf_node_hit = nullptr, + S32* gltf_primitive_hit = nullptr, LLVector4a *intersection = NULL, LLVector2 *uv = NULL, LLVector4a *normal = NULL, diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp index b3ef357041..a7f46ea0a7 100644 --- a/indra/newview/llvlcomposition.cpp +++ b/indra/newview/llvlcomposition.cpp @@ -28,47 +28,360 @@ #include "llvlcomposition.h" +#include + #include "llerror.h" #include "v3math.h" #include "llsurface.h" #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" +extern LLColor4U MAX_WATER_COLOR; -F32 bilinear(const F32 v00, const F32 v01, const F32 v10, const F32 v11, const F32 x_frac, const F32 y_frac) +static const U32 BASE_SIZE = 128; +static const F32 TERRAIN_DECODE_PRIORITY = 2048.f * 2048.f; + +namespace { - // Not sure if this is the right math... - // Take weighted average of all four points (bilinear interpolation) - F32 result; + F32 bilinear(const F32 v00, const F32 v01, const F32 v10, const F32 v11, const F32 x_frac, const F32 y_frac) + { + // Not sure if this is the right math... + // Take weighted average of all four points (bilinear interpolation) + F32 result; - const F32 inv_x_frac = 1.f - x_frac; - const F32 inv_y_frac = 1.f - y_frac; - result = inv_x_frac*inv_y_frac*v00 - + x_frac*inv_y_frac*v10 - + inv_x_frac*y_frac*v01 - + x_frac*y_frac*v11; + const F32 inv_x_frac = 1.f - x_frac; + const F32 inv_y_frac = 1.f - y_frac; + result = inv_x_frac*inv_y_frac*v00 + + x_frac*inv_y_frac*v10 + + inv_x_frac*y_frac*v01 + + x_frac*y_frac*v11; - return result; + return result; + } + + void boost_minimap_texture(LLViewerFetchedTexture* tex, F32 virtual_size) + { + llassert(tex); + if (!tex) { return; } + + tex->setBoostLevel(LLGLTexture::BOOST_TERRAIN); // in case the raw image is at low detail + tex->addTextureStats(virtual_size); // priority + } + + void boost_minimap_material(LLFetchedGLTFMaterial* mat, F32 virtual_size) + { + if (!mat) { return; } + if (mat->mBaseColorTexture) { boost_minimap_texture(mat->mBaseColorTexture, virtual_size); } + if (mat->mNormalTexture) { boost_minimap_texture(mat->mNormalTexture, virtual_size); } + if (mat->mMetallicRoughnessTexture) { boost_minimap_texture(mat->mMetallicRoughnessTexture, virtual_size); } + if (mat->mEmissiveTexture) { boost_minimap_texture(mat->mEmissiveTexture, virtual_size); } + } + + void unboost_minimap_texture(LLViewerFetchedTexture* tex) + { + if (!tex) { return; } + tex->setBoostLevel(LLGLTexture::BOOST_NONE); + tex->setMinDiscardLevel(MAX_DISCARD_LEVEL + 1); + } + + void unboost_minimap_material(LLFetchedGLTFMaterial* mat) + { + if (!mat) { return; } + if (mat->mBaseColorTexture) { unboost_minimap_texture(mat->mBaseColorTexture); } + if (mat->mNormalTexture) { unboost_minimap_texture(mat->mNormalTexture); } + if (mat->mMetallicRoughnessTexture) { unboost_minimap_texture(mat->mMetallicRoughnessTexture); } + if (mat->mEmissiveTexture) { unboost_minimap_texture(mat->mEmissiveTexture); } + } +}; + +LLTerrainMaterials::LLTerrainMaterials() +{ + for (S32 i = 0; i < ASSET_COUNT; ++i) + { + mMaterialTexturesSet[i] = false; + } } +LLTerrainMaterials::~LLTerrainMaterials() +{ + unboost(); +} + +bool LLTerrainMaterials::generateMaterials() +{ + if (texturesReady(true, true)) + { + return true; + } + + if (materialsReady(true, true)) + { + return true; + } + + return false; +} + +void LLTerrainMaterials::boost() +{ + for (S32 i = 0; i < ASSET_COUNT; ++i) + { + LLPointer& tex = mDetailTextures[i]; + llassert(tex.notNull()); + boost_minimap_texture(tex, TERRAIN_DECODE_PRIORITY); + + LLPointer& mat = mDetailMaterials[i]; + boost_minimap_material(mat, TERRAIN_DECODE_PRIORITY); + } +} + +void LLTerrainMaterials::unboost() +{ + for (S32 i = 0; i < ASSET_COUNT; ++i) + { + LLPointer& tex = mDetailTextures[i]; + unboost_minimap_texture(tex); + + LLPointer& mat = mDetailMaterials[i]; + unboost_minimap_material(mat); + } +} + +LLUUID LLTerrainMaterials::getDetailAssetID(S32 asset) +{ + llassert(mDetailTextures[asset] && mDetailMaterials[asset]); + // 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] ? mDetailTextures[asset]->getID() : LLUUID::null; +} + +LLPointer fetch_terrain_texture(const LLUUID& id) +{ + if (id.isNull()) + { + return nullptr; + } + + LLPointer tex = LLViewerTextureManager::getFetchedTexture(id); + return tex; +} + +void LLTerrainMaterials::setDetailAssetID(S32 asset, const LLUUID& id) +{ + // *NOTE: If there were multiple terrain swatches using the same asset + // ID, the asset still in use will be temporarily unboosted. + // It will be boosted again during terrain rendering. + unboost_minimap_texture(mDetailTextures[asset]); + unboost_minimap_material(mDetailMaterials[asset]); + + // 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(false, false) || !materialsReady(false, false); + return use_textures ? Type::TEXTURE : Type::PBR; +} + +bool LLTerrainMaterials::texturesReady(bool boost, bool strict) +{ + bool ready[ASSET_COUNT]; + // *NOTE: Calls to textureReady may boost textures. Do not early-return. + for (S32 i = 0; i < ASSET_COUNT; i++) + { + ready[i] = mDetailTextures[i].notNull() && textureReady(mDetailTextures[i], boost); + } + + bool one_ready = false; + for (S32 i = 0; i < ASSET_COUNT; i++) + { + const bool current_ready = ready[i]; + one_ready = one_ready || current_ready; + if (!current_ready && strict) + { + return false; + } + } + return one_ready; +} + +bool LLTerrainMaterials::materialsReady(bool boost, bool strict) +{ + bool ready[ASSET_COUNT]; + // *NOTE: Calls to materialReady may boost materials/textures. Do not early-return. + for (S32 i = 0; i < ASSET_COUNT; i++) + { + ready[i] = materialReady(mDetailMaterials[i], mMaterialTexturesSet[i], boost, strict); + } + +#if 1 + static LLCachedControl sRenderTerrainPBREnabled(gSavedSettings, "RenderTerrainPBREnabled", false); + static LLCachedControl sRenderTerrainPBRForce(gSavedSettings, "RenderTerrainPBRForce", false); + if (sRenderTerrainPBREnabled && sRenderTerrainPBRForce) + { + bool defined = true; + for (S32 i = 0; i < ASSET_COUNT; i++) + { + if (!mDetailMaterials[i]) + { + defined = false; + break; + } + } + if (defined) + { + return true; + } + } +#endif + + bool one_ready = false; + for (S32 i = 0; i < ASSET_COUNT; i++) + { + const bool current_ready = ready[i]; + one_ready = one_ready || current_ready; + if (!current_ready && strict) + { + return false; + } + } + return one_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); + if (!tex) { return false; } + + if (tex->getDiscardLevel() < 0) + { + if (boost) + { + boost_minimap_texture(tex, BASE_SIZE*BASE_SIZE); + } + return false; + } + if ((tex->getDiscardLevel() != 0 && + (tex->getWidth() < BASE_SIZE || + tex->getHeight() < BASE_SIZE))) + { + if (boost) + { + boost_minimap_texture(tex, BASE_SIZE*BASE_SIZE); + + 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->setMinDiscardLevel(ddiscard); + } + 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 +// static +bool LLTerrainMaterials::materialReady(LLPointer &mat, bool &textures_set, bool boost, bool strict) +{ + if (!mat || !mat->isLoaded()) + { + return false; + } + + // Material is loaded, but textures may not be + if (!textures_set) + { + textures_set = true; + // *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]); + } + + // *NOTE: Calls to textureReady may boost textures. Do not early-return. + bool ready[LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT]; + ready[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR] = + mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR].isNull() || textureReady(mat->mBaseColorTexture, boost); + ready[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL] = + mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL].isNull() || textureReady(mat->mNormalTexture, boost); + ready[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS] = + mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].isNull() || + textureReady(mat->mMetallicRoughnessTexture, boost); + ready[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE] = + mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE].isNull() || textureReady(mat->mEmissiveTexture, boost); + + if (strict) + { + for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i) + { + if (!ready[i]) + { + return false; + } + } + } + + return true; +} + +// static +const LLUUID (&LLVLComposition::getDefaultTextures())[ASSET_COUNT] +{ + const static LLUUID default_textures[LLVLComposition::ASSET_COUNT] = + { + TERRAIN_DIRT_DETAIL, + TERRAIN_GRASS_DETAIL, + TERRAIN_MOUNTAIN_DETAIL, + TERRAIN_ROCK_DETAIL + }; + return default_textures; +} 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); + const LLUUID (&default_textures)[LLVLComposition::ASSET_COUNT] = LLVLComposition::getDefaultTextures(); + for (S32 i = 0; i < ASSET_COUNT; ++i) + { + setDetailAssetID(i, default_textures[i]); + } + + mSurfacep = surfacep; // Initialize the texture matrix to defaults. for (S32 i = 0; i < CORNER_COUNT; ++i) @@ -76,14 +389,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 +403,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 +446,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 +495,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 +505,122 @@ 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++) + return LLTerrainMaterials::generateMaterials(); +} + +namespace +{ + void prepare_fallback_image(LLImageRaw* raw_image) { - if (mDetailTextures[i]->getDiscardLevel() < 0) + raw_image->resize(BASE_SIZE, BASE_SIZE, 4); + raw_image->fill(LLColor4U::white); + } + + // Check if the raw image is loaded for this texture at a discard + // level the minimap can use, and if not then try to get it loaded. + bool prepare_raw_image(LLPointer& raw_image, bool emissive, LLViewerFetchedTexture* tex, bool& delete_raw_post) + { + if (!tex) { - mDetailTextures[i]->setBoostLevel(LLGLTexture::BOOST_TERRAIN); // in case we are at low detail - mDetailTextures[i]->addTextureStats(BASE_SIZE*BASE_SIZE); - return false; + if (!emissive) + { + prepare_fallback_image(raw_image); + } + else + { + llassert(!raw_image); + raw_image = nullptr; + } + return true; } - if ((mDetailTextures[i]->getDiscardLevel() != 0 && - (mDetailTextures[i]->getWidth() < BASE_SIZE || - mDetailTextures[i]->getHeight() < BASE_SIZE))) + if (raw_image) { - S32 width = mDetailTextures[i]->getFullWidth(); - S32 height = mDetailTextures[i]->getFullHeight(); - S32 min_dim = llmin(width, height); - S32 ddiscard = 0; + // Callback already initiated + if (raw_image->getDataSize() > 0) + { + // Callback finished + delete_raw_post = true; + return true; + } + else + { + return false; + } + } + + raw_image = new LLImageRaw(); + + S32 ddiscard = 0; + { + S32 min_dim = llmin(tex->getFullWidth(), tex->getFullHeight()); 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; } + + struct PendingImage + { + LLImageRaw* mRawImage; + S32 mDesiredDiscard; + LLUUID mTextureId; + PendingImage(LLImageRaw* raw_image, S32 ddiscard, const LLUUID& texture_id) + : mRawImage(raw_image) + , mDesiredDiscard(ddiscard) + , mTextureId(texture_id) + { + mRawImage->ref(); + } + ~PendingImage() + { + mRawImage->unref(); + } + }; + PendingImage* pending_image = new PendingImage(raw_image, ddiscard, tex->getID()); + + loaded_callback_func cb = [](bool success, LLViewerFetchedTexture * src_vi, LLImageRaw * src, LLImageRaw * src_aux, S32 discard_level, bool is_final, void* userdata) { + PendingImage* pending = (PendingImage*)userdata; + // Owning LLVLComposition still exists + + // Assume mRawImage only used by single LLVLComposition for now + const bool in_use_by_composition = pending->mRawImage->getNumRefs() > 1; + llassert(pending->mRawImage->getNumRefs()); + llassert(pending->mRawImage->getNumRefs() <= 2); + const bool needs_data = !pending->mRawImage->getDataSize(); + if (in_use_by_composition && needs_data) + { + if (success && pending->mDesiredDiscard == discard_level) + { + pending->mRawImage->resize(BASE_SIZE, BASE_SIZE, src->getComponents()); + pending->mRawImage->copyScaled(src); + } + else if (is_final) + { + prepare_fallback_image(pending->mRawImage); + } + } + + if (is_final) { delete pending; } + }; + tex->setLoadedCallback(cb, ddiscard, true, false, pending_image, nullptr); + tex->forceToSaveRawImage(ddiscard); + + return false; } +}; - return true; -} - -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 +628,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,47 +635,101 @@ 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; + if (use_textures) + { + if (!texturesReady(true, true)) { return false; } + } + else + { + if (!materialsReady(true, true)) { 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()); - S32 ddiscard = 0; - while (min_dim > BASE_SIZE && ddiscard < MAX_DISCARD_LEVEL) + LLViewerFetchedTexture* tex; + LLViewerFetchedTexture* tex_emissive; // Can be null + bool has_base_color_factor; + bool has_emissive_factor; + bool has_alpha; + LLColor3 base_color_factor; + LLColor3 emissive_factor; + if (use_textures) { - ddiscard++; - min_dim /= 2; + tex = mDetailTextures[i]; + tex_emissive = nullptr; + has_base_color_factor = false; + has_emissive_factor = false; + has_alpha = 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); + has_alpha = mDetailMaterials[i]->mAlphaMode != LLGLTFMaterial::ALPHA_MODE_OPAQUE; } - bool delete_raw = (mDetailTextures[i]->reloadRawImage(ddiscard) != NULL) ; - if(mDetailTextures[i]->getRawImageLevel() != ddiscard)//raw iamge is not ready, will enter here again later. + if (!tex) { tex = LLViewerFetchedTexture::sWhiteImagep; } + + bool delete_raw_post = false; + bool delete_raw_post_emissive = false; + if (!prepare_raw_image(mRawImagesBaseColor[i], false, tex, delete_raw_post)) { return false; } + if (tex_emissive && !prepare_raw_image(mRawImagesEmissive[i], true, tex_emissive, delete_raw_post_emissive)) { return false; } + // tex_emissive can be null, and then will be ignored + + // In the simplest case, the minimap image is just the base color. + // This will be replaced if we need to do any tinting/compositing. + mRawImages[i] = mRawImagesBaseColor[i]; + + // *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 + // Long-term, we should consider a method that is more + // maintainable. Shaders, perhaps? Bake shaders to textures? + LLPointer raw_emissive; + if (tex_emissive) { - if (mDetailTextures[i]->getFetchPriority() <= 0.0f && !mDetailTextures[i]->hasSavedRawImage()) + raw_emissive = mRawImagesEmissive[i]; + if (has_emissive_factor || + tex_emissive->getWidth(tex_emissive->getRawImageLevel()) != BASE_SIZE || + tex_emissive->getHeight(tex_emissive->getRawImageLevel()) != BASE_SIZE || + tex_emissive->getComponents() != 4) { - mDetailTextures[i]->setBoostLevel(LLGLTexture::BOOST_MAP); - mDetailTextures[i]->forceToRefetchTexture(ddiscard); + LLPointer newraw_emissive = new LLImageRaw(BASE_SIZE, BASE_SIZE, 4); + // Copy RGB, leave alpha alone (set to opaque by default) + newraw_emissive->copy(mRawImagesEmissive[i]); + if (has_emissive_factor) + { + newraw_emissive->tint(emissive_factor); + } + raw_emissive = newraw_emissive; } - - if(delete_raw) - { - mDetailTextures[i]->destroyRawImage() ; - } - LL_DEBUGS("Terrain") << "cached raw data for terrain detail texture is not ready yet: " << mDetailTextures[i]->getID() << " Discard: " << ddiscard << LL_ENDL; - return false; } - - mRawImages[i] = mDetailTextures[i]->getRawImage() ; - if(delete_raw) - { - mDetailTextures[i]->destroyRawImage() ; - } - if (mDetailTextures[i]->getWidth(ddiscard) != BASE_SIZE || - mDetailTextures[i]->getHeight(ddiscard) != BASE_SIZE || - mDetailTextures[i]->getComponents() != 3) + if (has_base_color_factor || + raw_emissive || + has_alpha || + tex->getWidth(tex->getRawImageLevel()) != BASE_SIZE || + tex->getHeight(tex->getRawImageLevel()) != 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 @@ -322,9 +740,41 @@ bool LLVLComposition::generateTexture(const F32 x, const F32 y, return(false); } // - newraw->composite(mRawImages[i]); + if (has_alpha) + { + // Approximate the water underneath terrain alpha with solid water color + newraw->clear( + MAX_WATER_COLOR.mV[VX], + MAX_WATER_COLOR.mV[VY], + MAX_WATER_COLOR.mV[VZ], + 255); + } + newraw->composite(mRawImagesBaseColor[i]); + if (has_base_color_factor) + { + newraw->tint(base_color_factor); + } + // Apply emissive texture + if (raw_emissive) + { + newraw->addEmissive(raw_emissive); + } + mRawImages[i] = newraw; // deletes old } + + if (delete_raw_post) + { + tex->destroyRawImage(); + } + if (delete_raw_post_emissive) + { + tex_emissive->destroyRawImage(); + } + + // Remove intermediary image references + mRawImagesBaseColor[i] = nullptr; + mRawImagesEmissive[i] = nullptr; } st_data[i] = mRawImages[i]->getData(); st_data_size[i] = mRawImages[i]->getDataSize(); @@ -344,12 +794,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 +829,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,31 +920,38 @@ 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++) + // Un-boost detail textures (will get re-boosted if rendering in high detail) + 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); - mDetailTextures[i]->setMinDiscardLevel(MAX_DISCARD_LEVEL + 1); + unboost_minimap_texture(mDetailTextures[i]); + } + + // Un-boost textures for each detail material (will get re-boosted if rendering in high detail) + for (S32 i = 0; i < ASSET_COUNT; i++) + { + unboost_minimap_material(mDetailMaterials[i]); } 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; + mRawImagesBaseColor[asset] = NULL; + mRawImagesEmissive[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 bab0e0043a..cd5104d5a5 100644 --- a/indra/newview/llvlcomposition.h +++ b/indra/newview/llvlcomposition.h @@ -28,13 +28,68 @@ #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(); + + void boost(); + + virtual LLUUID getDetailAssetID(S32 asset); + virtual void setDetailAssetID(S32 asset, const LLUUID& id); + Type getMaterialType(); + bool texturesReady(bool boost, bool strict); + // strict = true -> all materials must be sufficiently loaded + // strict = false -> at least one material must be loaded + bool materialsReady(bool boost, bool strict); + +protected: + void unboost(); + static bool textureReady(LLPointer& tex, bool boost); + // strict = true -> all materials must be sufficiently loaded + // strict = false -> at least one material must be loaded + static bool materialReady(LLPointer& mat, bool& textures_set, bool boost, bool strict); + 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: + // 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; + static const LLUUID (&getDefaultTextures())[ASSET_COUNT]; + LLVLComposition(LLSurface *surfacep, const U32 width, const F32 scale); /*virtual*/ ~LLVLComposition(); @@ -44,7 +99,7 @@ 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); // Use these as indeces ito the get/setters below that use 'corner' enum ECorner @@ -55,12 +110,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 +122,26 @@ 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; + + // Final minimap raw images + LLPointer mRawImages[LLTerrainMaterials::ASSET_COUNT]; + + // Only non-null during minimap tile generation + LLPointer mRawImagesBaseColor[LLTerrainMaterials::ASSET_COUNT]; + LLPointer mRawImagesEmissive[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/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 36af4614f2..6725d8b6ec 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -5412,7 +5412,7 @@ bool LLVOAvatar::updateCharacter(LLAgent &agent) mSpeed = speed; // update animations - if (!visible) + if (!visible && !isSelf()) // NOTE: never do a "hidden update" for self avatar as it interrupts controller processing { updateMotions(LLCharacter::HIDDEN_UPDATE); } @@ -5973,9 +5973,6 @@ U32 LLVOAvatar::renderRigid() return 0; } - bool should_alpha_mask = shouldAlphaMask(); - LLGLState test(GL_ALPHA_TEST, should_alpha_mask); - if (isTextureVisible(TEX_EYES_BAKED) || (getOverallAppearance() == AOA_JELLYDOLL && !isControlAvatar()) || isUIAvatar()) { LLViewerJoint* eyeball_left = getViewerJoint(MESH_ID_EYEBALL_LEFT); diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index d67046ee1e..80d40bdcb6 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -1485,7 +1485,7 @@ void LLVOAvatarSelf::updateAttachmentVisibility(U32 camera_mode) switch (camera_mode) { case CAMERA_MODE_MOUSELOOK: - if (LLVOAvatar::sVisibleInFirstPerson && attachment->getVisibleInFirstPerson()) + if ((LLVOAvatar::sVisibleInFirstPerson && attachment->getVisibleInFirstPerson()) || gPipeline.mHeroProbeManager.isMirrorPass()) { // [RLVa:KB] - Checked: RLVa-2.0.2 attachment->setAttachmentVisibility(fRlvCanShowAttachment); diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 9ef8beca36..b068f4dea9 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -34,7 +34,7 @@ #include "llagentcamera.h" #include "llsdserialize.h" #include "llagent.h" // For gAgent -#include "llworld.h" // For LLWorld::getInstance() +#include "llworld.h" // For LLWorld::getInstance() //static variables U32 LLVOCacheEntry::sMinFrameRange = 0; @@ -56,10 +56,10 @@ bool check_write(LLAPRFile* apr_file, void* src, S32 n_bytes) { return apr_file->write(src, n_bytes) == n_bytes ; } -// FIRE-33808 - Material Override Cache causes long delays + +// Material Override Cache needs a version label, so we can upgrade this later. const std::string LLGLTFOverrideCacheEntry::VERSION_LABEL = {"GLTFCacheVer"}; const int LLGLTFOverrideCacheEntry::VERSION = 1; -// bool LLGLTFOverrideCacheEntry::fromLLSD(const LLSD& data) { @@ -241,7 +241,7 @@ LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file) } else { - // improve logging around vocache + // Improve logging around vocache LL_WARNS() << "Error loading cache entry for " << mLocalID << ", size " << size << " aborting!" << LL_ENDL; delete[] mBuffer ; mBuffer = NULL ; @@ -1296,11 +1296,10 @@ void LLVOCache::removeEntry(HeaderEntryInfo* entry) { return; } - // FIRE-33808 - Material Override Cache causes long delays + // Bit more tracking of cache creation/destruction. std::string filename; getObjectCacheFilename(entry->mHandle, filename); LL_INFOS() << "Removing entry for region with filename" << filename << LL_ENDL; - // // make sure corresponding LLViewerRegion also clears its in-memory cache LLViewerRegion* regionp = LLWorld::instance().getRegionFromHandle(entry->mHandle); @@ -1379,13 +1378,13 @@ void LLVOCache::removeFromCache(HeaderEntryInfo* entry) getObjectCacheFilename(entry->mHandle, filename); LL_WARNS("GLTF", "VOCache") << "Removing object cache for handle " << entry->mHandle << "Filename: " << filename << LL_ENDL; LLAPRFile::remove(filename, mLocalAPRFilePoolp); - // FIRE-33808 - Material Override Cache causes long delays - // Note that removeFromCache should take responsibility for cleaning up all cache artefactgs specfic to the handle/entry. + + // Note: `removeFromCache` should take responsibility for cleaning up all cache artefacts specfic to the handle/entry. // as such this now includes the generic extras filename = getObjectCacheExtrasFilename(entry->mHandle); LL_WARNS("GLTF", "VOCache") << "Removing generic extras for handle " << entry->mHandle << "Filename: " << filename << LL_ENDL; LLFile::remove(filename); - // + entry->mTime = INVALID_TIME ; updateEntry(entry) ; //update the head file. } @@ -1534,18 +1533,16 @@ bool LLVOCache::updateEntry(const HeaderEntryInfo* entry) return check_write(&apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ; } -// FIRE-33808 - Material Override Cache causes long delays -// void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) + // we now return bool to trigger dirty cache -// and force a rewrite after a partial read due to corruption. +// this in turn forces a rewrite after a partial read due to corruption. bool LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) -// { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; if(!mEnabled) { LL_WARNS() << "Not reading cache for handle " << handle << "): Cache is currently disabled." << LL_ENDL; - return true; // FIRE-33808 - Material Override Cache causes long delays + return true; // no problem we're just read only } llassert_always(mInitialized); @@ -1553,12 +1550,12 @@ bool LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca if(iter == mHandleEntryMap.end()) //no cache { LL_WARNS() << "No handle map entry for " << handle << LL_ENDL; - return false; // FIRE-33808 - Material Override Cache causes long delays + return false; // arguably no a problem, but we'll mark this as dirty anyway. } bool success = true ; - S32 num_entries=0; // FIRE-33808 - Material Override Cache causes long delays - std::string filename; + S32 num_entries = 0 ; // lifted out of inner loop. + std::string filename; // lifted out of loop { LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("VOCache:loadRegionObjectCache"); LLUUID cache_id; @@ -1578,7 +1575,6 @@ bool LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca if(success) { - // S32 num_entries; // if removal was enabled during write num_entries might be wrong success = check_read(&apr_file, &num_entries, sizeof(S32)) ; if(success) @@ -1589,7 +1585,7 @@ bool LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca if (!entry->getLocalID()) { LL_WARNS() << "Aborting cache file load for " << filename << ", cache file corruption!" << LL_ENDL; - success = false ; + success = false ; break ; } cache_entry_map[entry->getLocalID()] = entry; @@ -1605,17 +1601,13 @@ bool LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca { removeEntry(iter->second) ; } - } - // FIRE-33808 - Material Override Cache causes long delays - // return ; + LL_DEBUGS("GLTF", "VOCache") << "Read " << cache_entry_map.size() << " entries from object cache " << filename << ", expected " << num_entries << ", success=" << (success?"True":"False") << LL_ENDL; return success; - // } -// FIRE-33808 - Material Override Cache causes long delays -// void LLVOCache::readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map) +// We now pass in the cache entry map, so that we can remove entries from extras that are no longer in the primary cache. void LLVOCache::readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; @@ -1623,7 +1615,6 @@ void LLVOCache::readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCac int discarded = 0; // get ViewerRegion pointer from handle LLViewerRegion* pRegion = LLWorld::getInstance()->getRegionFromHandle(handle); -// if(!mEnabled) { LL_WARNS() << "Not reading cache for handle " << handle << "): Cache is currently disabled." << LL_ENDL; @@ -1650,78 +1641,72 @@ void LLVOCache::readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCac std::string line; std::getline(in, line); - if(!in.good()) { + if(!in.good()) + { LL_WARNS() << "Failed reading extras cache for handle " << handle << LL_ENDL; - // FIRE-33808 - Material Override Cache causes long delays in.close(); removeGenericExtrasForHandle(handle); - // return; } - - // FIRE-33808 - Material Override Cache causes long delays // file formats need versions, let's add one. legacy cache files will be considered version 0 + // This will make it easier to upgrade/revise later. int versionNumber=0; if (line.compare(0, LLGLTFOverrideCacheEntry::VERSION_LABEL.length(), LLGLTFOverrideCacheEntry::VERSION_LABEL) == 0) { std::string versionStr = line.substr(LLGLTFOverrideCacheEntry::VERSION_LABEL.length()+1); // skip the version label and ':' versionNumber = std::stol(versionStr); - std::getline(in, line); // read the next line for the region UUID check } // For future versions we may call a legacy handler here, but realistically we'll just consider this cache out of date. // The important thing is to make sure it gets removed. - if(versionNumber != LLGLTFOverrideCacheEntry::VERSION && versionNumber != 0) + if(versionNumber != LLGLTFOverrideCacheEntry::VERSION) { LL_WARNS() << "Unexpected version number " << versionNumber << " for extras cache for handle " << handle << LL_ENDL; in.close(); + removeGenericExtrasForHandle(handle); + return; } - // + + LL_DEBUGS("VOCache") << "Reading extras cache for handle " << handle << ", version " << versionNumber << LL_ENDL; + std::getline(in, line); if(!LLUUID::validate(line)) { LL_WARNS() << "Failed reading extras cache for handle" << handle << ". invalid uuid line: '" << line << "'" << LL_ENDL; - // FIRE-33808 - Material Override Cache causes long delays in.close(); removeGenericExtrasForHandle(handle); - // return; } LLUUID cache_id(line); if(cache_id != id) { - // FIRE-33808 - Material Override Cache causes long delays // if the cache id doesn't match the expected region we should just kill the file. LL_WARNS() << "Cache ID doesn't match for this region, deleting it" << LL_ENDL; in.close(); removeGenericExtrasForHandle(handle); - // return; } U32 num_entries; // if removal was enabled during write num_entries might be wrong std::getline(in, line); - if(!in.good()) { + if(!in.good()) + { LL_WARNS() << "Failed reading extras cache for handle " << handle << LL_ENDL; - // FIRE-33808 - Material Override Cache causes long delays in.close(); removeGenericExtrasForHandle(handle); - // return; } - try { + try + { num_entries = std::stol(line); } catch(std::logic_error&) // either invalid_argument or out_of_range { LL_WARNS() << "Failed reading extras cache for handle " << handle << ". unreadable num_entries" << LL_ENDL; - // FIRE-33808 - Material Override Cache causes long delays in.close(); removeGenericExtrasForHandle(handle); - // return; } - // FIRE-33808 - Material Override Cache causes long delays LL_DEBUGS("GLTF") << "Beginning reading extras cache for handle " << handle << " from " << getObjectCacheExtrasFilename(handle) << LL_ENDL; LLSD entry_llsd; @@ -1732,22 +1717,19 @@ void LLVOCache::readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCac static const U32 max_size = 4096; bool success = LLSDSerialize::deserialize(entry_llsd, in, max_size); // check bool(in) this time since eof is not a failure condition here - if(!success || !in) { - // FIRE-33808 - Material Override Cache causes long delays + if(!success || !in) + { LL_WARNS() << "Failed reading extras cache for handle " << handle << ", entry number " << i << " cache patrtial load only." << LL_ENDL; in.close(); removeGenericExtrasForHandle(handle); break; - // } LLGLTFOverrideCacheEntry entry; entry.fromLLSD(entry_llsd); U32 local_id = entry_llsd["local_id"].asInteger(); - // FIRE-33808 - Material Override Cache causes long delays - // cache_extras_entry_map[local_id] = entry; // only add entries that exist in the primary cache - // this is a self-healing test that avoids us polluting the cache with entries that are no longer valid. + // this is a self-healing test that avoids us polluting the cache with entries that are no longer valid based on the main cache. if(cache_entry_map.find(local_id)!= cache_entry_map.end()) { // attempt to backfill a null objectId, though these shouldn't be in the persisted cache really @@ -1764,25 +1746,20 @@ void LLVOCache::readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCac } } LL_DEBUGS("GLTF") << "Completed reading extras cache for handle " << handle << ", " << loaded << " loaded, " << discarded << " discarded" << LL_ENDL; - // } void LLVOCache::purgeEntries(U32 size) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - // FIRE-33808 - Material Override Cache causes long delays LL_DEBUGS("VOCache","GLTF") << "Purging " << size << " entries from cache" << LL_ENDL; while(mHeaderEntryQueue.size() > size) { header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; HeaderEntryInfo* entry = *iter ; - mHandleEntryMap.erase(entry->mHandle); - // FIRE-33808 - Material Override Cache causes long delays - mHeaderEntryQueue.erase(iter); - removeFromCache(entry); - // + mHandleEntryMap.erase(entry->mHandle) ; + mHeaderEntryQueue.erase(iter) ; + removeFromCache(entry) ; // This now handles removing extras cache where appropriate. delete entry; - } mNumEntries = static_cast(mHandleEntryMap.size()); } @@ -1790,13 +1767,10 @@ void LLVOCache::purgeEntries(U32 size) void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, bool dirty_cache, bool removal_enabled) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - // FIRE-33808 - Material Override Cache causes long delays std::string filename; getObjectCacheFilename(handle, filename); - // if(!mEnabled) { - // FIRE-33808 - Material Override Cache causes long delays LL_WARNS() << "Not writing cache for " << filename << " (handle:" << handle << "): Cache is currently disabled." << LL_ENDL; return ; } @@ -1804,7 +1778,6 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: if(mReadOnly) { - // FIRE-33808 - Material Override Cache causes long delays LL_WARNS() << "Not writing cache for " << filename << " (handle:" << handle << "): Cache is currently in read-only mode." << LL_ENDL; return ; } @@ -1840,14 +1813,12 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: //update cache header if(!updateEntry(entry)) { - // FIRE-33808 - Material Override Cache causes long delays LL_WARNS() << "Failed to update cache header index " << entry->mIndex << ". " << filename << " handle = " << handle << LL_ENDL; return ; //update failed. } if(!dirty_cache) { - // FIRE-33808 - Material Override Cache causes long delays LL_WARNS() << "Skipping write to cache for " << filename << " (handle:" << handle << "): cache not dirty" << LL_ENDL; return ; //nothing changed, no need to update. } @@ -1884,7 +1855,6 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: } else { - // FIRE-33808 - Material Override Cache causes long delays LL_WARNS() << "Failed to write cache entry to buffer for " << filename << ", entry number " << iter->second->getLocalID() << LL_ENDL; success = false; break; @@ -1897,7 +1867,6 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: size_in_buffer = 0; if (!success) { - // FIRE-33808 - Material Override Cache causes long delays LL_WARNS() << "Failed to write cache to disk " << filename << LL_ENDL; break; } @@ -1909,15 +1878,12 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: { // final write success = check_write(&apr_file, (void*)data_buffer, size_in_buffer); - // FIRE-33808 - Material Override Cache causes long delays if(!success) { LL_WARNS() << "Failed to write cache entry to disk " << filename << LL_ENDL; } - // size_in_buffer = 0; } - // FIRE-33808 - Material Override Cache causes long delays LL_DEBUGS("VOCache") << "Wrote " << num_entries << " entries to the primary VOCache file " << filename << ". success = " << (success ? "True":"False") << LL_ENDL; } } @@ -1930,7 +1896,7 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: return ; } -// FIRE-33808 - Material Override Cache causes long delays + void LLVOCache::removeGenericExtrasForHandle(U64 handle) { if(mReadOnly) @@ -1938,7 +1904,6 @@ void LLVOCache::removeGenericExtrasForHandle(U64 handle) LL_WARNS() << "Not removing cache for handle " << handle << ": Cache is currently in read-only mode." << LL_ENDL; return ; } - LL_WARNS("GLTF", "VOCache") << "Removing generic extras for handle " << handle << "Filename: " << getObjectCacheExtrasFilename(handle) << LL_ENDL; // NOTE: when removing the extras, we must also remove the objects so the simulator will send us a full upddate with the valid overrides auto* entry = mHandleEntryMap[handle]; @@ -1953,7 +1918,6 @@ void LLVOCache::removeGenericExtrasForHandle(U64 handle) LLFile::remove(getObjectCacheExtrasFilename(handle)); } } -// void LLVOCache::writeGenericExtrasToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map, bool dirty_cache, bool removal_enabled) { @@ -1978,27 +1942,6 @@ void LLVOCache::writeGenericExtrasToCache(U64 handle, const LLUUID& id, const LL if(!out.good()) { LL_WARNS() << "Failed writing extras cache for handle " << handle << LL_ENDL; - // FIRE-33808 - Material Override Cache causes long delays - // return; - // // TODO - clean up broken cache file - // } - - // out << id << '\n'; - // if(!out.good()) - // { - // LL_WARNS() << "Failed writing extras cache for handle " << handle << LL_ENDL; - // return; - // // TODO - clean up broken cache file - // } - - // auto num_entries = cache_extras_entry_map.size(); - // out << num_entries << '\n'; - // if(!out.good()) - // { - // LL_WARNS() << "Failed writing extras cache for handle " << handle << LL_ENDL; - // return; - // // TODO - clean up broken cache file - // } removeGenericExtrasForHandle(handle); return; } @@ -2010,10 +1953,10 @@ void LLVOCache::writeGenericExtrasToCache(U64 handle, const LLUUID& id, const LL if(!out.good()) { LL_WARNS() << "Failed writing extras cache for handle " << handle << LL_ENDL; - removeGenericExtrasForHandle(handle); // FIRE-33808 - Material Override Cache causes long delays + removeGenericExtrasForHandle(handle); return; } - + // Because we don't write out all the entries we need to record a placeholder and rewrite this later auto num_entries_placeholder = out.tellp(); out << std::setw(10) << std::setfill('0') << 0 << '\n'; if(!out.good()) @@ -2034,17 +1977,17 @@ void LLVOCache::writeGenericExtrasToCache(U64 handle, const LLUUID& id, const LL { // Only write out GLTFOverrides that we can actually apply again on import. // worst case we have an extra cache miss. - // Note: mObjectId is valid in memory as we might have a data race between GLTF of the object itself. + // Note: A null mObjectId is valid when in memory as we might have a data race between GLTF of the object itself. // This remains a valid state to persist as it is consistent with the localid checks on import with the main cache. + // the mObjectId will be updated if/when the local object is updated from the gObject list (due to full update) if(entry.mObjectId.isNull() && pRegion) { gObjectList.getUUIDFromLocal( entry.mObjectId, local_id, pRegion->getHost().getAddress(), pRegion->getHost().getPort() ); } - if( /*entry.mObjectId.notNull() &&*/ - entry.mSides.size() > 0 && + if( entry.mSides.size() > 0 && entry.mSides.size() == entry.mGLTFMaterial.size() - ) + ) { LLSD entry_llsd = entry.toLLSD(); entry_llsd["local_id"] = (S32)local_id; @@ -2064,6 +2007,7 @@ void LLVOCache::writeGenericExtrasToCache(U64 handle, const LLUUID& id, const LL skipped++; } } + // Rewrite the placeholder out.seekp(num_entries_placeholder); out << std::setw(10) << std::setfill('0') << num_entries << '\n'; if(!out.good()) diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h index 5bcf7ce587..0daefc42e8 100644 --- a/indra/newview/llvocache.h +++ b/indra/newview/llvocache.h @@ -291,17 +291,14 @@ public: // We need this init to be separate from constructor, since we might construct cache, purge it, then init. void initCache(ELLPath location, U32 size, U32 cache_version); void removeCache(ELLPath location, bool started = false) ; - // FIRE-33808 - Material Override Cache causes long delays - // void readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) ; - // void readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map); + bool readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) ; void readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map); - // void writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, bool dirty_cache, bool removal_enabled); void writeGenericExtrasToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map, bool dirty_cache, bool removal_enabled); void removeEntry(U64 handle) ; - void removeGenericExtrasForHandle(U64 handle); // FIRE-33808 - Material Override Cache causes long delays + void removeGenericExtrasForHandle(U64 handle); U32 getCacheEntries() { return mNumEntries; } U32 getCacheEntriesMax() { return mCacheSize; } diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp index 58f890335f..46200539a3 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" @@ -213,6 +214,7 @@ bool LLVOSurfacePatch::updateGeometry(LLDrawable *drawable) void LLVOSurfacePatch::updateFaceSize(S32 idx) { + LL_PROFILE_ZONE_SCOPED; if (idx != 0) { LL_WARNS() << "Terrain partition requested invalid face!!!" << LL_ENDL; @@ -241,39 +243,41 @@ 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) + if (!facep) { - U32 index_offset = facep->getGeomIndex(); + return; + } - updateMainGeometry(facep, + 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); - updateNorthGeometry(facep, - verticesp, - normalsp, - texCoords0p, - texCoords1p, - indicesp, - index_offset); - updateEastGeometry(facep, - verticesp, - normalsp, - texCoords0p, - texCoords1p, - indicesp, - index_offset); - } } void LLVOSurfacePatch::updateMainGeometry(LLFace *facep, @@ -982,6 +986,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,34 +1036,56 @@ 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; - 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(); diff --git a/indra/newview/llvosurfacepatch.h b/indra/newview/llvosurfacepatch.h index 9e24c33774..2780b97a97 100644 --- a/indra/newview/llvosurfacepatch.h +++ b/indra/newview/llvosurfacepatch.h @@ -63,7 +63,7 @@ public: /*virtual*/ bool updateGeometry(LLDrawable *drawable); /*virtual*/ bool updateLOD(); /*virtual*/ void updateFaceSize(S32 idx); - void getGeometry(LLStrider &verticesp, + void getTerrainGeometry(LLStrider &verticesp, LLStrider &normalsp, LLStrider &texCoords0p, LLStrider &texCoords1p, diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 6358a794a4..0bdb250a1a 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -314,6 +314,11 @@ void LLVOVolume::markDead() { mLightTexture->removeVolume(LLRender::LIGHT_TEX, this); } + + if (mIsHeroProbe) + { + gPipeline.mHeroProbeManager.unregisterViewerObject(this); + } } LLViewerObject::markDead(); @@ -3606,6 +3611,29 @@ bool LLVOVolume::setReflectionProbeIsDynamic(bool is_dynamic) return false; } +bool LLVOVolume::setReflectionProbeIsMirror(bool is_mirror) +{ + LLReflectionProbeParams *param_block = (LLReflectionProbeParams *) getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE); + if (param_block) + { + if (param_block->getIsMirror() != is_mirror) + { + LL_INFOS() << "Setting reflection probe mirror to " << is_mirror << LL_ENDL; + param_block->setIsMirror(is_mirror); + parameterChanged(LLNetworkData::PARAMS_REFLECTION_PROBE, true); + + if (!is_mirror) + gPipeline.mHeroProbeManager.unregisterViewerObject(this); + else + gPipeline.mHeroProbeManager.registerViewerObject(this); + + return true; + } + } + + return false; +} + F32 LLVOVolume::getReflectionProbeAmbiance() const { const LLReflectionProbeParams* param_block = (const LLReflectionProbeParams*)getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE); @@ -3654,6 +3682,18 @@ bool LLVOVolume::getReflectionProbeIsDynamic() const return false; } +bool LLVOVolume::getReflectionProbeIsMirror() const +{ + const LLReflectionProbeParams *param_block = + (const LLReflectionProbeParams *) getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE); + if (param_block) + { + return param_block->getIsMirror(); + } + + return false; +} + U32 LLVOVolume::getVolumeInterfaceID() const { if (mVolumeImpl) @@ -4614,14 +4654,30 @@ void LLVOVolume::updateReflectionProbePtr() { if (isReflectionProbe()) { - if (mReflectionProbe.isNull()) + if (mReflectionProbe.isNull() && !getReflectionProbeIsMirror()) { mReflectionProbe = gPipeline.mReflectionMapManager.registerViewerObject(this); } + else if (mReflectionProbe.isNull() && getReflectionProbeIsMirror()) + { + // Geenz: This is a special case - what we want here is a hero probe. + // What we want to do here is instantiate a hero probe from the hero probe manager. + + if (!mIsHeroProbe) + mIsHeroProbe = gPipeline.mHeroProbeManager.registerViewerObject(this); + } } - else if (mReflectionProbe.notNull()) + else if (mReflectionProbe.notNull() || getReflectionProbeIsMirror()) { - mReflectionProbe = nullptr; + if (mReflectionProbe.notNull()) + { + mReflectionProbe = nullptr; + } + + if (getReflectionProbeIsMirror()) + { + gPipeline.mHeroProbeManager.unregisterViewerObject(this); + } } } @@ -4796,7 +4852,7 @@ LLVector3 LLVOVolume::volumeDirectionToAgent(const LLVector3& dir) const bool LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, bool pick_transparent, bool pick_rigged, bool pick_unselectable, S32 *face_hitp, - LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent) + LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent) { if (!mbCanSelect || mDrawable->isDead() @@ -6515,19 +6571,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace LLViewerTexture* last_tex = NULL; - S32 texture_index_channels = 1; - - if (gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 30) - { - texture_index_channels = LLGLSLShader::sIndexedTextureChannels-1; //always reserve one for shiny for now just for simplicity; - } - - if (distance_sort) - { - texture_index_channels = gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels; - } - - texture_index_channels = LLGLSLShader::sIndexedTextureChannels; + S32 texture_index_channels = LLGLSLShader::sIndexedTextureChannels; bool flexi = false; diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 379ddfff0a..311dfc2dfc 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -306,12 +306,14 @@ public: bool setReflectionProbeNearClip(F32 near_clip); bool setReflectionProbeIsBox(bool is_box); bool setReflectionProbeIsDynamic(bool is_dynamic); + bool setReflectionProbeIsMirror(bool is_mirror); bool isReflectionProbe() const override; F32 getReflectionProbeAmbiance() const; F32 getReflectionProbeNearClip() const; bool getReflectionProbeIsBox() const; bool getReflectionProbeIsDynamic() const; + bool getReflectionProbeIsMirror() const; // Flexible Objects U32 getVolumeInterfaceID() const; diff --git a/indra/newview/llxmlrpclistener.cpp b/indra/newview/llxmlrpclistener.cpp index 0eabb8983e..1148e81fd5 100644 --- a/indra/newview/llxmlrpclistener.cpp +++ b/indra/newview/llxmlrpclistener.cpp @@ -411,6 +411,114 @@ private: return parseValues(status_string, "", param); } + LLSD parseValue(std::string& status_string, const std::string& key, const std::string& key_pfx, XMLRPC_VALUE param) + { + LLSD response; + + XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(param); + switch (type) + { + case xmlrpc_type_empty: + LL_INFOS("LLXMLRPCListener") << "Empty result for key " << key_pfx << key << LL_ENDL; + break; + case xmlrpc_type_base64: + { + S32 len = XMLRPC_GetValueStringLen(param); + const char* buf = XMLRPC_GetValueBase64(param); + if ((len > 0) && buf) + { + // During implementation this code was not tested + // If you encounter this, please make sure this is correct, + // then remove llassert + llassert(0); + + LLSD::Binary data; + data.resize(len); + memcpy((void*)&data[0], (void*)buf, len); + response = data; + } + else + { + LL_WARNS("LLXMLRPCListener") << "Potentially malformed xmlrpc_type_base64 for key " + << key_pfx << key << LL_ENDL; + } + break; + } + case xmlrpc_type_boolean: + { + response = LLSD::Boolean(XMLRPC_GetValueBoolean(param)); + LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL; + break; + } + case xmlrpc_type_datetime: + { + std::string iso8601_date(XMLRPC_GetValueDateTime_ISO8601(param)); + LL_DEBUGS("LLXMLRPCListener") << "val: " << iso8601_date << LL_ENDL; + response = LLSD::Date(iso8601_date); + break; + } + case xmlrpc_type_double: + { + response = LLSD::Real(XMLRPC_GetValueDouble(param)); + LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL; + break; + } + case xmlrpc_type_int: + { + response = LLSD::Integer(XMLRPC_GetValueInt(param)); + LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL; + break; + } + case xmlrpc_type_string: + { + response = LLSD::String(XMLRPC_GetValueString(param)); + LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL; + break; + } + case xmlrpc_type_mixed: + case xmlrpc_type_array: + { + // We expect this to be an array of submaps. Walk the array, + // recursively parsing each submap and collecting them. + LLSD array; + int i = 0; // for descriptive purposes + for (XMLRPC_VALUE row = XMLRPC_VectorRewind(param); row; + row = XMLRPC_VectorNext(param), ++i) + { + // Recursive call. For the lower-level key_pfx, if 'key' + // is "foo", pass "foo[0]:", then "foo[1]:", etc. In the + // nested call, a subkey "bar" will then be logged as + // "foo[0]:bar", and so forth. + // Parse the scalar subkey/value pairs from this array + // entry into a temp submap. Collect such submaps in 'array'. + + array.append(parseValue(status_string, "", + STRINGIZE(key_pfx << key << '[' << i << "]:"), + row)); + } + // Having collected an 'array' of 'submap's, insert that whole + // 'array' as the value of this 'key'. + response = array; + break; + } + case xmlrpc_type_struct: + { + response = parseValues(status_string, + STRINGIZE(key_pfx << key << ':'), + param); + break; + } + case xmlrpc_type_none: // Not expected + default: + // whoops - unrecognized type + LL_WARNS("LLXMLRPCListener") << "Unhandled xmlrpc type " << type << " for key " + << key_pfx << key << LL_ENDL; + response = STRINGIZE("'); + status_string = "BadType"; + } + return response; + } + /** * Parse key/value pairs from a given XMLRPC_VALUE into an LLSD map. * @param key_pfx Used to describe a given key in log messages. At top @@ -428,113 +536,7 @@ private: { std::string key(XMLRPC_GetValueID(current)); LL_DEBUGS("LLXMLRPCListener") << "key: " << key_pfx << key << LL_ENDL; - XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(current); - switch (type) - { - case xmlrpc_type_empty: - LL_INFOS("LLXMLRPCListener") << "Empty result for key " << key_pfx << key << LL_ENDL; - responses.insert(key, LLSD()); - break; - case xmlrpc_type_base64: - { - S32 len = XMLRPC_GetValueStringLen(current); - const char* buf = XMLRPC_GetValueBase64(current); - if ((len > 0) && buf) - { - // During implementation this code was not tested - // If you encounter this, please make sure this is correct, - // then remove llassert - llassert(0); - - LLSD::Binary data; - data.resize(len); - memcpy((void*)&data[0], (void*)buf, len); - responses.insert(key, data); - } - else - { - LL_WARNS("LLXMLRPCListener") << "Potentially malformed xmlrpc_type_base64 for key " - << key_pfx << key << LL_ENDL; - responses.insert(key, LLSD()); - } - break; - } - case xmlrpc_type_boolean: - { - LLSD::Boolean val(XMLRPC_GetValueBoolean(current)); - LL_DEBUGS("LLXMLRPCListener") << "val: " << val << LL_ENDL; - responses.insert(key, val); - break; - } - case xmlrpc_type_datetime: - { - std::string iso8601_date(XMLRPC_GetValueDateTime_ISO8601(current)); - LL_DEBUGS("LLXMLRPCListener") << "val: " << iso8601_date << LL_ENDL; - responses.insert(key, LLSD::Date(iso8601_date)); - break; - } - case xmlrpc_type_double: - { - LLSD::Real val(XMLRPC_GetValueDouble(current)); - LL_DEBUGS("LLXMLRPCListener") << "val: " << val << LL_ENDL; - responses.insert(key, val); - break; - } - case xmlrpc_type_int: - { - LLSD::Integer val(XMLRPC_GetValueInt(current)); - LL_DEBUGS("LLXMLRPCListener") << "val: " << val << LL_ENDL; - responses.insert(key, val); - break; - } - case xmlrpc_type_string: - { - LLSD::String val(XMLRPC_GetValueString(current)); - LL_DEBUGS("LLXMLRPCListener") << "val: " << val << LL_ENDL; - responses.insert(key, val); - break; - } - case xmlrpc_type_mixed: - case xmlrpc_type_array: - { - // We expect this to be an array of submaps. Walk the array, - // recursively parsing each submap and collecting them. - LLSD array; - int i = 0; // for descriptive purposes - for (XMLRPC_VALUE row = XMLRPC_VectorRewind(current); row; - row = XMLRPC_VectorNext(current), ++i) - { - // Recursive call. For the lower-level key_pfx, if 'key' - // is "foo", pass "foo[0]:", then "foo[1]:", etc. In the - // nested call, a subkey "bar" will then be logged as - // "foo[0]:bar", and so forth. - // Parse the scalar subkey/value pairs from this array - // entry into a temp submap. Collect such submaps in 'array'. - array.append(parseValues(status_string, - STRINGIZE(key_pfx << key << '[' << i << "]:"), - row)); - } - // Having collected an 'array' of 'submap's, insert that whole - // 'array' as the value of this 'key'. - responses.insert(key, array); - break; - } - case xmlrpc_type_struct: - { - LLSD submap = parseValues(status_string, - STRINGIZE(key_pfx << key << ':'), - current); - responses.insert(key, submap); - break; - } - case xmlrpc_type_none: // Not expected - default: - // whoops - unrecognized type - LL_WARNS("LLXMLRPCListener") << "Unhandled xmlrpc type " << type << " for key " - << key_pfx << key << LL_ENDL; - responses.insert(key, STRINGIZE("')); - status_string = "BadType"; - } + responses.insert(key, parseValue(status_string, key, key_pfx, current)); } return responses; } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index a49b6e25c2..bff62c744a 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -112,6 +112,7 @@ #include "llscenemonitor.h" #include "llprogressview.h" #include "llcleanup.h" +#include "gltfscenemanager.h" // [RLVa:KB] - Checked: RLVa-2.0.0 #include "llvisualeffect.h" #include "rlvactions.h" @@ -213,8 +214,13 @@ F32 LLPipeline::RenderScreenSpaceReflectionDepthRejectBias; F32 LLPipeline::RenderScreenSpaceReflectionAdaptiveStepMultiplier; S32 LLPipeline::RenderScreenSpaceReflectionGlossySamples; S32 LLPipeline::RenderBufferVisualization; +bool LLPipeline::RenderMirrors; +S32 LLPipeline::RenderHeroProbeUpdateRate; +S32 LLPipeline::RenderHeroProbeConservativeUpdateMultiplier; 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; @@ -347,8 +353,8 @@ bool addDeferredAttachments(LLRenderTarget& target, bool for_impostor = false) { bool valid = true && target.addColorAttachment(GL_RGBA) // frag-data[1] specular OR PBR ORM - && target.addColorAttachment(GL_RGBA16F) // frag_data[2] normal+z+fogmask, See: class1\deferred\materialF.glsl & softenlight - && target.addColorAttachment(GL_RGB16F); // frag_data[3] PBR emissive + && target.addColorAttachment(GL_RGBA16F) // frag_data[2] normal+fogmask, See: class1\deferred\materialF.glsl & softenlight + && target.addColorAttachment(GL_RGB16F); // frag_data[3] PBR emissive OR material env intensity return valid; } @@ -594,6 +600,9 @@ void LLPipeline::init() connectRefreshCachedSettingsSafe("RenderScreenSpaceReflectionAdaptiveStepMultiplier"); connectRefreshCachedSettingsSafe("RenderScreenSpaceReflectionGlossySamples"); connectRefreshCachedSettingsSafe("RenderBufferVisualization"); + connectRefreshCachedSettingsSafe("RenderMirrors"); + connectRefreshCachedSettingsSafe("RenderHeroProbeUpdateRate"); + connectRefreshCachedSettingsSafe("RenderHeroProbeConservativeUpdateMultiplier"); connectRefreshCachedSettingsSafe("RenderAutoHideSurfaceAreaLimit"); connectRefreshCachedSettingsSafe("FSRenderVignette"); // Import Vignette from Exodus // Make change to RenderAttachedLights & RenderAttachedParticles instant @@ -686,6 +695,7 @@ void LLPipeline::cleanup() mCubeVB = NULL; mReflectionMapManager.cleanup(); + mHeroProbeManager.cleanup(); } //============================================================================ @@ -830,13 +840,26 @@ 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); + + if (RenderMirrors) + { + mHeroProbeManager.initReflectionMaps(); + res = mHeroProbeManager.mProbeResolution; // We also scale the hero probe RT to the probe res since we don't super sample it. + mRT = &mHeroProbeRT; + allocateScreenBuffer(res, res, samples); + } + mRT = &mMainRT; gCubeSnapshot = false; } @@ -1145,6 +1168,15 @@ void LLPipeline::refreshCachedSettings() RenderScreenSpaceReflectionAdaptiveStepMultiplier = gSavedSettings.getF32("RenderScreenSpaceReflectionAdaptiveStepMultiplier"); RenderScreenSpaceReflectionGlossySamples = gSavedSettings.getS32("RenderScreenSpaceReflectionGlossySamples"); RenderBufferVisualization = gSavedSettings.getS32("RenderBufferVisualization"); + if (gSavedSettings.getBOOL("RenderMirrors") != RenderMirrors) + { + RenderMirrors = gSavedSettings.getBOOL("RenderMirrors"); + LLViewerShaderMgr::instance()->clearShaderCache(); + LLViewerShaderMgr::instance()->setShaders(); + } + RenderHeroProbeUpdateRate = gSavedSettings.getS32("RenderHeroProbeUpdateRate"); + RenderHeroProbeConservativeUpdateMultiplier = gSavedSettings.getS32("RenderHeroProbeConservativeUpdateMultiplier"); + sReflectionProbesEnabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderReflectionsEnabled") && gSavedSettings.getBOOL("RenderReflectionsEnabled"); RenderSpotLight = nullptr; @@ -1174,7 +1206,6 @@ void LLPipeline::releaseGLBuffers() releaseLUTBuffers(); mWaterDis.release(); - mBake.release(); mSceneMap.release(); @@ -1220,6 +1251,12 @@ void LLPipeline::releaseScreenBuffers() mRT->fxaaBuffer.release(); mRT->deferredScreen.release(); mRT->deferredLight.release(); + + mHeroProbeRT.uiScreen.release(); + mHeroProbeRT.screen.release(); + mHeroProbeRT.fxaaBuffer.release(); + mHeroProbeRT.deferredScreen.release(); + mHeroProbeRT.deferredLight.release(); } void LLPipeline::releaseSunShadowTarget(U32 index) @@ -1253,12 +1290,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(); @@ -2336,7 +2367,8 @@ static LLTrace::BlockTimerStatHandle FTM_CULL("Object Culling"); // static bool LLPipeline::isWaterClip() { - return (!sRenderTransparentWater || gCubeSnapshot) && !sRenderingHUDs; + // We always pretend that we're not clipping water when rendering mirrors. + return (gPipeline.mHeroProbeManager.isMirrorPass()) ? false : (!sRenderTransparentWater || gCubeSnapshot) && !sRenderingHUDs; } void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, bool hud_attachments) @@ -2509,6 +2541,26 @@ void LLPipeline::doOcclusion(LLCamera& camera) gGL.setColorMask(true, true); } + if (sReflectionProbesEnabled && sUseOcclusion > 1 && !LLPipeline::sShadowRender && !gCubeSnapshot) + { + gGL.setColorMask(false, false); + LLGLDepthTest depth(GL_TRUE, GL_FALSE); + LLGLDisable cull(GL_CULL_FACE); + + gOcclusionCubeProgram.bind(); + + if (mCubeVB.isNull()) + { //cube VB will be used for issuing occlusion queries + mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX); + } + mCubeVB->setBuffer(); + + mHeroProbeManager.doOcclusion(); + gOcclusionCubeProgram.unbind(); + + gGL.setColorMask(true, true); + } + if (LLPipeline::sUseOcclusion > 1 && (sCull->hasOcclusionGroups() || LLVOCachePartition::sNeedsOcclusionCheck)) { @@ -3913,6 +3965,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera, bool do_occlusion) { //update reflection probe uniform mReflectionMapManager.updateUniforms(); + mHeroProbeManager.updateUniforms(); } U32 cur_type = 0; @@ -4614,6 +4667,8 @@ void LLPipeline::renderDebug() } } + LL::GLTFSceneManager::instance().renderDebug(); + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION)) { //render visible selected group occlusion geometry gDebugProgram.bind(); @@ -6383,6 +6438,8 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector4a& start, bool pick_unselectable, bool pick_reflection_probe, S32* face_hit, + S32* gltf_node_hit, + S32* gltf_primitive_hit, LLVector4a* intersection, // return the intersection point LLVector2* tex_coord, // return the texture coordinates of the intersection point LLVector4a* normal, // return the surface normal at the intersection point @@ -6526,6 +6583,25 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector4a& start, } } + S32 node_hit = -1; + S32 primitive_hit = -1; + LLDrawable* hit = LL::GLTFSceneManager::instance().lineSegmentIntersect(start, local_end, pick_transparent, pick_rigged, pick_unselectable, pick_reflection_probe, &node_hit, &primitive_hit, &position, tex_coord, normal, tangent); + if (hit) + { + drawable = hit; + local_end = position; + } + + if (gltf_node_hit) + { + *gltf_node_hit = node_hit; + } + + if (gltf_primitive_hit) + { + *gltf_primitive_hit = primitive_hit; + } + if (intersection) { *intersection = position; @@ -6641,6 +6717,15 @@ void LLPipeline::renderGLTFObjects(U32 type, bool texture, bool rigged) gGL.loadMatrix(gGLModelView); gGLLastMatrix = NULL; + + if (!rigged) + { + LL::GLTFSceneManager::instance().renderOpaque(); + } + else + { + LL::GLTFSceneManager::instance().render(true, true); + } } // Currently only used for shadows -Cosmic,2023-04-19 @@ -6678,7 +6763,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 +6789,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 { @@ -6849,6 +6934,8 @@ void LLPipeline::generateLuminance(LLRenderTarget* src, LLRenderTarget* dst) gLuminanceProgram.bind(); + static LLCachedControl diffuse_luminance_scale(gSavedSettings, "RenderDiffuseLuminanceScale", 1.0f); + S32 channel = 0; channel = gLuminanceProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE); if (channel > -1) @@ -6862,6 +6949,16 @@ void LLPipeline::generateLuminance(LLRenderTarget* src, LLRenderTarget* dst) mGlow[1].bindTexture(0, channel); } + channel = gLuminanceProgram.enableTexture(LLShaderMgr::DEFERRED_NORMAL); + if (channel > -1) + { + // bind the normal map to get the environment mask + mRT->deferredScreen.bindTexture(2, channel, LLTexUnit::TFO_POINT); + } + + static LLStaticHashedString diffuse_luminance_scale_s("diffuse_luminance_scale"); + gLuminanceProgram.uniform1f(diffuse_luminance_scale_s, diffuse_luminance_scale); + mScreenTriangleVB->setBuffer(); mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); dst->flush(); @@ -6872,11 +6969,12 @@ void LLPipeline::generateLuminance(LLRenderTarget* src, LLRenderTarget* dst) } } -void LLPipeline::generateExposure(LLRenderTarget* src, LLRenderTarget* dst) { +void LLPipeline::generateExposure(LLRenderTarget* src, LLRenderTarget* dst, bool use_history) { // exposure sample { LL_PROFILE_GPU_ZONE("exposure sample"); + if (use_history) { // copy last frame's exposure into mLastExposure mLastExposure.bindTarget(); @@ -6893,18 +6991,31 @@ void LLPipeline::generateExposure(LLRenderTarget* src, LLRenderTarget* dst) { LLGLDepthTest depth(GL_FALSE, GL_FALSE); - gExposureProgram.bind(); - - S32 channel = gExposureProgram.enableTexture(LLShaderMgr::DEFERRED_EMISSIVE); - if (channel > -1) + LLGLSLShader* shader; + if (use_history) { - mLuminanceMap.bindTexture(0, channel, LLTexUnit::TFO_TRILINEAR); + shader = &gExposureProgram; + } + else + { + shader = &gExposureProgramNoFade; } - channel = gExposureProgram.enableTexture(LLShaderMgr::EXPOSURE_MAP); + shader->bind(); + + S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_EMISSIVE); if (channel > -1) { - mLastExposure.bindTexture(0, channel); + src->bindTexture(0, channel, LLTexUnit::TFO_TRILINEAR); + } + + if (use_history) + { + channel = shader->enableTexture(LLShaderMgr::EXPOSURE_MAP); + if (channel > -1) + { + mLastExposure.bindTexture(0, channel); + } } static LLStaticHashedString dt("dt"); @@ -6921,7 +7032,7 @@ void LLPipeline::generateExposure(LLRenderTarget* src, LLRenderTarget* dst) { if (probe_ambiance > 0.f) { - F32 hdr_scale = sqrtf(LLEnvironment::instance().getCurrentSky()->getGamma())*2.f; + F32 hdr_scale = sqrtf(LLEnvironment::instance().getCurrentSky()->getGamma()) * 2.f; if (hdr_scale > 1.f) { @@ -6929,19 +7040,24 @@ void LLPipeline::generateExposure(LLRenderTarget* src, LLRenderTarget* dst) { exp_max = hdr_scale; } } - gExposureProgram.uniform1f(dt, gFrameIntervalSeconds); - gExposureProgram.uniform2f(noiseVec, ll_frand() * 2.0 - 1.0, ll_frand() * 2.0 - 1.0); - gExposureProgram.uniform3f(dynamic_exposure_params, dynamic_exposure_coefficient, exp_min, exp_max); + shader->uniform1f(dt, gFrameIntervalSeconds); + shader->uniform2f(noiseVec, ll_frand() * 2.0 - 1.0, ll_frand() * 2.0 - 1.0); + shader->uniform3f(dynamic_exposure_params, dynamic_exposure_coefficient, exp_min, exp_max); mScreenTriangleVB->setBuffer(); mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); - gGL.getTexUnit(channel)->unbind(mLastExposure.getUsage()); - gExposureProgram.unbind(); + if (use_history) + { + gGL.getTexUnit(channel)->unbind(mLastExposure.getUsage()); + } + shader->unbind(); dst->flush(); } } +extern LLPointer gEXRImage; + void LLPipeline::gammaCorrect(LLRenderTarget* src, LLRenderTarget* dst) { dst->bindTarget(); // gamma correct lighting @@ -6978,8 +7094,10 @@ void LLPipeline::gammaCorrect(LLRenderTarget* src, LLRenderTarget* dst) { F32 e = llclamp(exposure(), 0.5f, 4.f); static LLStaticHashedString s_exposure("exposure"); + static LLStaticHashedString aces_mix("aces_mix"); shader.uniform1f(s_exposure, e); + shader.uniform1f(aces_mix, gEXRImage.notNull() ? 0.f : 0.3f); mScreenTriangleVB->setBuffer(); mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); @@ -7351,7 +7469,7 @@ void LLPipeline::renderDoF(LLRenderTarget* src, LLRenderTarget* dst) LLVector4a result; result.clear(); - gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, false, false, true, true, NULL, &result); + gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, false, false, true, true, nullptr, nullptr, nullptr, &result); focus_point.set(result.getF32ptr()); } @@ -8430,6 +8548,7 @@ void LLPipeline::renderDeferredLighting() LLPipeline::RENDER_TYPE_CONTROL_AV, LLPipeline::RENDER_TYPE_ALPHA_MASK, LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK, + LLPipeline::RENDER_TYPE_TERRAIN, LLPipeline::RENDER_TYPE_WATER, END_RENDER_TYPES); @@ -8834,6 +8953,17 @@ void LLPipeline::bindReflectionProbes(LLGLSLShader& shader) bound = true; } + if (RenderMirrors) + { + channel = shader.enableTexture(LLShaderMgr::HERO_PROBE, LLTexUnit::TT_CUBE_MAP_ARRAY); + if (channel > -1 && mHeroProbeManager.mTexture.notNull()) + { + mHeroProbeManager.mTexture->bind(channel); + bound = true; + } + } + + if (bound) { mReflectionMapManager.setUniforms(); @@ -11102,6 +11232,16 @@ void LLPipeline::rebuildDrawInfo() } } +void LLPipeline::rebuildTerrain() +{ + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + region->dirtyAllPatches(); + } +} + // Reset VB during TP void LLPipeline::initDeferredVB() { diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 65b9eda7e2..49705e1d7d 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -39,6 +39,7 @@ #include "lldrawable.h" #include "llrendertarget.h" #include "llreflectionmapmanager.h" +#include "llheroprobemanager.h" #include @@ -133,6 +134,8 @@ public: // rebuild all LLVOVolume render batches void rebuildDrawInfo(); + // Rebuild all terrain + void rebuildTerrain(); // Clear LLFace mVertexBuffer pointers void resetVertexBuffers(LLDrawable* drawable); @@ -151,7 +154,7 @@ public: void renderFinalize(); void copyScreenSpaceReflections(LLRenderTarget* src, LLRenderTarget* dst); void generateLuminance(LLRenderTarget* src, LLRenderTarget* dst); - void generateExposure(LLRenderTarget* src, LLRenderTarget* dst); + void generateExposure(LLRenderTarget* src, LLRenderTarget* dst, bool use_history = true); void gammaCorrect(LLRenderTarget* src, LLRenderTarget* dst); void generateGlow(LLRenderTarget* src); void applyFXAA(LLRenderTarget* src, LLRenderTarget* dst); @@ -207,6 +210,8 @@ public: bool pick_unselectable, bool pick_reflection_probe, S32* face_hit, // return the face hit + S32* gltf_node_hit = nullptr, // return the gltf node hit + S32* gltf_primitive_hit = nullptr, // return the gltf primitive hit LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point LLVector4a* normal = NULL, // return the surface normal at the intersection point @@ -459,6 +464,7 @@ public: void handleShadowDetailChanged(); LLReflectionMapManager mReflectionMapManager; + LLHeroProbeManager mHeroProbeManager; private: void unloadShaders(); @@ -616,7 +622,7 @@ public: RENDER_DEBUG_PHYSICS_SHAPES = 0x02000000, RENDER_DEBUG_NORMALS = 0x04000000, RENDER_DEBUG_LOD_INFO = 0x08000000, - RENDER_DEBUG_ATTACHMENT_BYTES = 0x20000000, // not used + RENDER_DEBUG_NODES = 0x20000000, RENDER_DEBUG_TEXEL_DENSITY = 0x40000000, RENDER_DEBUG_TRIANGLE_COUNT = 0x80000000, RENDER_DEBUG_IMPOSTORS = 0x100000000, @@ -707,8 +713,12 @@ public: RenderTargetPack mMainRT; // auxillary 512x512 render target pack + // used by reflection probes and dynamic texture bakes RenderTargetPack mAuxillaryRT; + // Auxillary render target pack scaled to the hero probe's per-face size. + RenderTargetPack mHeroProbeRT; + // currently used render target pack RenderTargetPack* mRT; @@ -767,7 +777,7 @@ public: //water distortion texture (refraction) LLRenderTarget mWaterDis; - LLRenderTarget mBake; + static const U32 MAX_BAKE_WIDTH; //texture for making the glow LLRenderTarget mGlow[3]; @@ -1074,6 +1084,9 @@ public: static F32 RenderScreenSpaceReflectionAdaptiveStepMultiplier; static S32 RenderScreenSpaceReflectionGlossySamples; static S32 RenderBufferVisualization; + static bool RenderMirrors; + static S32 RenderHeroProbeUpdateRate; + static S32 RenderHeroProbeConservativeUpdateMultiplier; }; void render_bbox(const LLVector3 &min, const LLVector3 &max); diff --git a/indra/newview/skins/default/xui/az/menu_inventory_add.xml b/indra/newview/skins/default/xui/az/menu_inventory_add.xml index 2a475a3b5d..29eb61d7c8 100644 --- a/indra/newview/skins/default/xui/az/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/az/menu_inventory_add.xml @@ -1,7 +1,7 @@ - + diff --git a/indra/newview/skins/default/xui/az/menu_viewer.xml b/indra/newview/skins/default/xui/az/menu_viewer.xml index 935398402a..0fe6ef5532 100644 --- a/indra/newview/skins/default/xui/az/menu_viewer.xml +++ b/indra/newview/skins/default/xui/az/menu_viewer.xml @@ -255,7 +255,7 @@ - + diff --git a/indra/newview/skins/default/xui/da/menu_inventory_add.xml b/indra/newview/skins/default/xui/da/menu_inventory_add.xml index 9419e4ea3c..be3f121608 100644 --- a/indra/newview/skins/default/xui/da/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/da/menu_inventory_add.xml @@ -1,7 +1,7 @@ - + diff --git a/indra/newview/skins/default/xui/da/menu_viewer.xml b/indra/newview/skins/default/xui/da/menu_viewer.xml index 9131289568..995f4ab3e8 100644 --- a/indra/newview/skins/default/xui/da/menu_viewer.xml +++ b/indra/newview/skins/default/xui/da/menu_viewer.xml @@ -114,7 +114,7 @@ - + diff --git a/indra/newview/skins/default/xui/de/floater_tools.xml b/indra/newview/skins/default/xui/de/floater_tools.xml index c91dc6d437..4fbabd899a 100644 --- a/indra/newview/skins/default/xui/de/floater_tools.xml +++ b/indra/newview/skins/default/xui/de/floater_tools.xml @@ -482,7 +482,7 @@ Ndrg ↔ Nst - + @@ -491,13 +491,20 @@ Ndrg ↔ Nst - + + Test-Update: + + + + + + diff --git a/indra/newview/skins/default/xui/de/menu_inventory_add.xml b/indra/newview/skins/default/xui/de/menu_inventory_add.xml index 8acb4bd8f9..634fae4519 100644 --- a/indra/newview/skins/default/xui/de/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/de/menu_inventory_add.xml @@ -1,7 +1,7 @@ - + diff --git a/indra/newview/skins/default/xui/de/menu_viewer.xml b/indra/newview/skins/default/xui/de/menu_viewer.xml index d9dcd63a70..25f6b65867 100644 --- a/indra/newview/skins/default/xui/de/menu_viewer.xml +++ b/indra/newview/skins/default/xui/de/menu_viewer.xml @@ -251,7 +251,7 @@ - + @@ -343,6 +343,11 @@ + + + + + @@ -473,6 +478,8 @@ + + @@ -530,6 +537,7 @@ + diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml index 6daece3ba0..dc05cf3121 100644 --- a/indra/newview/skins/default/xui/de/notifications.xml +++ b/indra/newview/skins/default/xui/de/notifications.xml @@ -1645,13 +1645,62 @@ Wählen Sie ein einzelnes Objekt aus und versuchen Sie es erneut. Die Regionstexturen konnten nicht festgelegt werden: Die Terraintextur [TEXTURE_NUM] hat eine ungültige Bit-Tiefe [TEXTURE_BIT_DEPTH]. -Ersetzen Sie die Textur [TEXTURE_NUM] mit einer Bilddatei von maximal [MAX_SIZE]x[MAX_SIZE] und 24 Bit und klicken Sie dann erneut auf „Übernehmen“. +Ersetzen Sie die Textur [TEXTURE_NUM] mit einer PNG-Bilddatei von maximal [MAX_SIZE]x[MAX_SIZE] und klicken Sie dann erneut auf „Übernehmen“. + + + Die Regionstexturen konnten nicht festgelegt werden: +Die Terraintextur [TEXTURE_NUM] wurde nicht vollständig geladen, aber verwendet vermutlich Transparenz aufgrund einer Bit-Tiefe von [TEXTURE_BIT_DEPTH]. Transparenz wird derzeit nicht für Terraintexturen unterstützt. + +Falls Textur [TEXTURE_NUM] opak ist, warten Sie bitte, bis die Textur vollständig geladen ist und klicken dann erneut auf „Übernehmen“. + +Alpha wird aktuell nur für Terrain-Materialien (PBR metallische Unebenheit) unterstützt, wenn alphaMode="MASK" und doubleSided=false. + + + Die Regionstexturen konnten nicht festgelegt werden: +Die Terraintextur [TEXTURE_NUM] verwendet Transparenz. Transparenz wird derzeit nicht für Terraintexturen unterstützt. + +Ersetzen Sie die Textur [TEXTURE_NUM] mit einer opaken RGB-Bilddatei und klicken dann erneut auf „Übernehmen“. + +Falls Textur [TEXTURE_NUM] opak ist, warten Sie bitte, bis die Textur vollständig geladen ist und klicken dann erneut auf „Übernehmen“. + +Alpha wird aktuell nur für Terrain-Materialien (PBR metallische Unebenheit) unterstützt, wenn alphaMode="MASK" und doubleSided=false. + +Couldn't set region textures: +Terrain texture [TEXTURE_NUM] contains transparency. Transparency is not currently supported for terrain textures. + +Replace texture [TEXTURE_NUM] with an opaque RGB image, then click "Apply" again. + +Alpha is only supported for terrain materials (PBR Metallic Roughness), when alphaMode="MASK" and doubleSided=false. Die Regionstexturen konnten nicht festgelegt werden: Die Terraintextur [TEXTURE_NUM] ist mit [TEXTURE_SIZE_X]x[TEXTURE_SIZE_Y] zu groß. -Ersetzen Sie die Textur [TEXTURE_NUM] mit einer Bilddatei von maximal [MAX_SIZE]x[MAX_SIZE] und 24 Bit und klicken Sie dann erneut auf „Übernehmen“. +Ersetzen Sie die Textur [TEXTURE_NUM] mit einer PNG-Bilddatei von maximal [MAX_SIZE]x[MAX_SIZE] und klicken Sie dann erneut auf „Übernehmen“. + + + Die Regionsmaterialien konnten nicht festgelegt werden: +Terrain-Material [MATERIAL_NUM] ist nicht geladen. + +Warten Sie bitte, bis das Material geladen ist oder ersetzen Sie Material [MATERIAL_NUM] mit einem gültigen Material. + + + Die Regionsmaterialien konnten nicht festgelegt werden: +Terrain-Material [MATERIAL_NUM] konnte nicht geladen werden. + +Ersetzen Sie Material [MATERIAL_NUM] mit einem gültigen Material. + + + Die Regionsmaterialien konnten nicht festgelegt werden: +Terrain-Material [MATERIAL_NUM] ist doppelseitig. Doppelseitige Materialien werden derzeit für PBR-Terrain nicht unterstützt. + +Ersetzen Sie Material [MATERIAL_NUM] mit einem Material mit doubleSided=false. + + + Die Regionsmaterialien konnten nicht festgelegt werden: +Terrain-Material [MATERIAL_NUM] verwendeten den nicht-unterstützten alphaMode=„[MATERIAL_ALPHA_MODE]“. + +Ersetzen Sie Material [MATERIAL_NUM] mit einem Material mit alphaMode="OPAQUE" oder alphaMode="MASK". Hochladen gestartet. Je nach Verbindungsgeschwindigkeit kann der Vorgang bis zu 2 Minuten dauern. @@ -3826,6 +3875,10 @@ Sie haben lokal eine [RESOLUTION]-gebackene Textur für „[BODYREGION]“ nach Textur konnte nicht hochgeladen werden: „[NAME]“ +[REASON] + + + [WHAT] konnte nicht geladen werden. [REASON] @@ -5030,7 +5083,11 @@ Möchten Sie fortfahren? Sie bearbeiten einen Himmel, der automatisch zu HDR konvertiert wurde. Um HDR und Tone Mapping zu entfernen, setzen Sie „Umgebung Reflexionstest (HDR)“ auf 0. - + + + Sie müssen ein Objekt auswählen, das als Ankerpunkt für den GLTF-Gegenstand fungiert, den Sie vorschauen möchten. + + Keine gültige Einstellung für die Umgebung ausgewählt. diff --git a/indra/newview/skins/default/xui/de/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/de/panel_preferences_graphics1.xml index ab6e37bfea..ae6c77e741 100644 --- a/indra/newview/skins/default/xui/de/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/de/panel_preferences_graphics1.xml @@ -26,13 +26,13 @@ Ultra - Shader: + Schatten: @@ -61,7 +61,7 @@ Wasserreflexionen: - + @@ -78,6 +78,25 @@ + + Spiegelungsauflösung: + + + + + + + + + Aktualisierung Spiegelung: + + + + + + + + m @@ -133,10 +152,7 @@ - - - - + Erweiterte Einstellungen (Neustart erforderlich): diff --git a/indra/newview/skins/default/xui/de/panel_region_terrain.xml b/indra/newview/skins/default/xui/de/panel_region_terrain.xml index f101e55730..64c7472c97 100644 --- a/indra/newview/skins/default/xui/de/panel_region_terrain.xml +++ b/indra/newview/skins/default/xui/de/panel_region_terrain.xml @@ -10,8 +10,12 @@ - Terraintexturen (erfordert 24-Bit-.tga-Dateien mit einer Größe von 1024x1024) + Terrain-Texturen + + Terrain-Materialien + + 1 (niedrig) @@ -27,12 +31,21 @@ Texturhöhenbereich + + Materialhöhenbereich + Diese Werte geben den Mischungsgrad für die obigen Texturen an. + + Diese Werte geben den Mischungsgrad für die obigen Materialien an. + In Metern gemessen. Der Wert „Niedrig“ ist die maximale Höhe von Textur 1, der Wert „Hoch“ die Mindesthöhe von Textur 4. + + In Metern gemessen. Der Wert „Niedrig“ ist die maximale Höhe von Material 1, der Wert „Hoch“ die Mindesthöhe von Material 4. + Nordwest diff --git a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml index 78ce54993e..35d6623abc 100644 --- a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml @@ -387,42 +387,10 @@ name="FSAADisabled" value="0" /> - - - - - (requires restart) - - - Mesh + Mesh - Low + Low - Low + Low - Low + Low - Low + Low + + (requires restart) + + Shaders @@ -586,7 +573,7 @@ layout="topleft" left="420" name="TransparentWater" - top_delta="16" + top_delta="18" width="300"> @@ -607,7 +594,7 @@ max_val="128" name="SkyMeshDetail" show_text="false" - top_delta="16" + top_delta="22" width="260"> @@ -649,7 +636,7 @@ layout="topleft" left="420" name="UseDoF" - top_delta="16" + top_delta="20" width="240"> @@ -664,7 +651,7 @@ left="420" name="RenderShadowDetailText" text_readonly_color="LabelDisabledColor" - top_delta="16" + top_delta="22" width="128"> Shadows: @@ -698,7 +685,7 @@ layout="topleft" left="420" name="ScreenSpaceReflections" - top_delta="16" + top_delta="24" width="240"> @@ -713,7 +700,7 @@ left="420" name="ReflectionDetailText" text_readonly_color="LabelDisabledColor" - top_delta="16" + top_delta="22" width="128"> Reflection Detail: @@ -749,7 +736,7 @@ left="420" name="ReflectionProbeText" text_readonly_color="LabelDisabledColor" - top_delta="16" + top_delta="22" width="128"> Reflection Coverage: @@ -795,10 +782,106 @@ max_val="1.5" name="RenderExposure" show_text="true" - top_delta="20" + top_delta="24" width="260"> + + + + + + + Mirror Resolution: + + + + + + + + + + + Mirror Update Rate: + + + + + + + + + + + width="140"> + + Probe Update + + + + + + + diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index f179661bde..031900ca61 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2243,7 +2243,7 @@ name="Upload" tear_off="true"> @@ -3157,7 +3157,57 @@ function="Advanced.ToggleRenderType" parameter="simple" /> - + + + + + + + + + + + + + + + + + + + + @@ -4124,6 +4174,18 @@ + + + + + + + + + + @@ -4619,6 +4691,13 @@ + + + -Could not set region textures: + +Couldn't 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 + + + + +Couldn't set region textures: +Terrain texture [TEXTURE_NUM] is not fully loaded, but is assumed to contain transparency due to a bit depth of [TEXTURE_BIT_DEPTH]. Transparency is not currently supported for terrain textures. + +If texture [TEXTURE_NUM] is opaque, wait for the texture to fully load and then click "Apply" again. + +Alpha is only supported for terrain materials (PBR Metallic Roughness), when alphaMode="MASK" and doubleSided=false. + fail + + + + +Couldn't set region textures: +Terrain texture [TEXTURE_NUM] contains transparency. Transparency is not currently supported for terrain textures. + +Replace texture [TEXTURE_NUM] with an opaque RGB image, then click "Apply" again. + +Alpha is only supported for terrain materials (PBR Metallic Roughness), when alphaMode="MASK" and doubleSided=false. fail @@ -4156,10 +4185,55 @@ Replace texture [TEXTURE_NUM] with a 24-bit [MAX_SIZE]x[MAX_SIZE] or smaller ima icon="alertmodal.tga" name="InvalidTerrainSize" type="alertmodal"> -Could not set region textures: + +Couldn't 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. + + + + +Couldn't set region materials: +Terrain material [MATERIAL_NUM] is not loaded. + +Wait for the material to load, or replace material [MATERIAL_NUM] with a valid material. + + + + +Couldn't set region materials: +Terrain material [MATERIAL_NUM] failed to load. + +Replace material [MATERIAL_NUM] with a valid material. + + + + +Couldn't set region materials: +Terrain material [MATERIAL_NUM] is double-sided. Double-sided materials are not currently supported for PBR terrain. + +Replace material [MATERIAL_NUM] with a material with doubleSided=false. + + + + +Couldn't set region materials: +Terrain material [MATERIAL_NUM] is using the unsupported alphaMode="[MATERIAL_ALPHA_MODE]". + +Replace material [MATERIAL_NUM] with a material with alphaMode="OPAQUE" or alphaMode="MASK". fail + + Unable to load [WHAT]. + [REASON] + fail + + - + + + You must select an object to act as a handle to the GLTF asset you are previewing. + fail + + + Ultra - Shaders: @@ -283,6 +272,19 @@ + + + - - + + + + Mirror Resolution: + + + + + + + + + Mirror Update Rate: + + + + + + + + + + + - - - - Terrain Textures (1024x1024, 24 bit .tga files) + left="10" + top="105" + width="170"> + Terrain Textures + + Terrain Materials + + + + + + Texture Elevation Ranges + + Material Elevation Ranges + These values represent the blend range for the textures above. + + These values represent the blend range for the materials above. + Measured in meters, the LOW value is the MAXIMUM height of Texture #1, and the HIGH value is the MINIMUM height of Texture #4. + + Measured in meters, the LOW value is the MAXIMUM height of Material #1, and the HIGH value is the MINIMUM height of Material #4. + - + diff --git a/indra/newview/skins/default/xui/es/menu_viewer.xml b/indra/newview/skins/default/xui/es/menu_viewer.xml index e1d50a4b2d..502d789dea 100644 --- a/indra/newview/skins/default/xui/es/menu_viewer.xml +++ b/indra/newview/skins/default/xui/es/menu_viewer.xml @@ -40,7 +40,7 @@ - + diff --git a/indra/newview/skins/default/xui/es/panel_region_terrain.xml b/indra/newview/skins/default/xui/es/panel_region_terrain.xml index fc4a9b968c..7cb44a073e 100644 --- a/indra/newview/skins/default/xui/es/panel_region_terrain.xml +++ b/indra/newview/skins/default/xui/es/panel_region_terrain.xml @@ -10,10 +10,10 @@ - - Texturas del terreno (requiere archivos .tga de 1024x1024, 24 bits) - +terreno" name="terrain_lower_spin"/> + + Texturas del terreno + 1 (bajo) diff --git a/indra/newview/skins/default/xui/fr/menu_inventory_add.xml b/indra/newview/skins/default/xui/fr/menu_inventory_add.xml index 2f173a89da..56df11387e 100644 --- a/indra/newview/skins/default/xui/fr/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/fr/menu_inventory_add.xml @@ -1,7 +1,7 @@ - + diff --git a/indra/newview/skins/default/xui/fr/menu_viewer.xml b/indra/newview/skins/default/xui/fr/menu_viewer.xml index a5e07e3782..d7d18500aa 100644 --- a/indra/newview/skins/default/xui/fr/menu_viewer.xml +++ b/indra/newview/skins/default/xui/fr/menu_viewer.xml @@ -234,7 +234,7 @@ - + diff --git a/indra/newview/skins/default/xui/it/menu_inventory_add.xml b/indra/newview/skins/default/xui/it/menu_inventory_add.xml index 8229419347..29ec1b2dc5 100644 --- a/indra/newview/skins/default/xui/it/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/it/menu_inventory_add.xml @@ -1,7 +1,7 @@ - + diff --git a/indra/newview/skins/default/xui/it/menu_viewer.xml b/indra/newview/skins/default/xui/it/menu_viewer.xml index 5024160b88..d52b927bfb 100644 --- a/indra/newview/skins/default/xui/it/menu_viewer.xml +++ b/indra/newview/skins/default/xui/it/menu_viewer.xml @@ -254,7 +254,7 @@ - + diff --git a/indra/newview/skins/default/xui/it/panel_region_terrain.xml b/indra/newview/skins/default/xui/it/panel_region_terrain.xml index 0c21ef16b9..e571888832 100644 --- a/indra/newview/skins/default/xui/it/panel_region_terrain.xml +++ b/indra/newview/skins/default/xui/it/panel_region_terrain.xml @@ -10,8 +10,8 @@ - Texture terreno (richiede file 1024x1024 24 bit TGA) - + Texture terreno + 1 (basso) diff --git a/indra/newview/skins/default/xui/ja/menu_inventory_add.xml b/indra/newview/skins/default/xui/ja/menu_inventory_add.xml index 27ed912dfb..3bb5ab8b3f 100644 --- a/indra/newview/skins/default/xui/ja/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/ja/menu_inventory_add.xml @@ -1,7 +1,7 @@ - + diff --git a/indra/newview/skins/default/xui/ja/menu_viewer.xml b/indra/newview/skins/default/xui/ja/menu_viewer.xml index 503bca518f..b36a23fb89 100644 --- a/indra/newview/skins/default/xui/ja/menu_viewer.xml +++ b/indra/newview/skins/default/xui/ja/menu_viewer.xml @@ -261,7 +261,7 @@ - + diff --git a/indra/newview/skins/default/xui/ja/panel_region_terrain.xml b/indra/newview/skins/default/xui/ja/panel_region_terrain.xml index 29145ac7a1..94c8442dbd 100644 --- a/indra/newview/skins/default/xui/ja/panel_region_terrain.xml +++ b/indra/newview/skins/default/xui/ja/panel_region_terrain.xml @@ -10,7 +10,7 @@ - 地形テクスチャ(1024x1024 の 24 bit .tga ファイル) + 地形テクスチャ 1(低) diff --git a/indra/newview/skins/default/xui/pl/menu_inventory_add.xml b/indra/newview/skins/default/xui/pl/menu_inventory_add.xml index b8968c971d..8fb24ff49b 100644 --- a/indra/newview/skins/default/xui/pl/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/pl/menu_inventory_add.xml @@ -1,7 +1,7 @@ - + diff --git a/indra/newview/skins/default/xui/pl/menu_viewer.xml b/indra/newview/skins/default/xui/pl/menu_viewer.xml index 68e4ca8f8f..41445c29cf 100644 --- a/indra/newview/skins/default/xui/pl/menu_viewer.xml +++ b/indra/newview/skins/default/xui/pl/menu_viewer.xml @@ -254,7 +254,7 @@ - + diff --git a/indra/newview/skins/default/xui/pl/panel_region_terrain.xml b/indra/newview/skins/default/xui/pl/panel_region_terrain.xml index 62ce4d1965..1fc8c24a8e 100644 --- a/indra/newview/skins/default/xui/pl/panel_region_terrain.xml +++ b/indra/newview/skins/default/xui/pl/panel_region_terrain.xml @@ -7,7 +7,7 @@ - Tekstury terenu (1024x1024, 24 bitowy plik .tga) + Tekstury terenu 1 (Nisko) diff --git a/indra/newview/skins/default/xui/pt/menu_inventory_add.xml b/indra/newview/skins/default/xui/pt/menu_inventory_add.xml index 9d75132a03..10a8813606 100644 --- a/indra/newview/skins/default/xui/pt/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/pt/menu_inventory_add.xml @@ -1,7 +1,7 @@ - + diff --git a/indra/newview/skins/default/xui/pt/menu_viewer.xml b/indra/newview/skins/default/xui/pt/menu_viewer.xml index 67584e9adc..62f2c34f02 100644 --- a/indra/newview/skins/default/xui/pt/menu_viewer.xml +++ b/indra/newview/skins/default/xui/pt/menu_viewer.xml @@ -163,7 +163,7 @@ - + diff --git a/indra/newview/skins/default/xui/pt/panel_region_terrain.xml b/indra/newview/skins/default/xui/pt/panel_region_terrain.xml index c63dff8c9f..92d6859882 100644 --- a/indra/newview/skins/default/xui/pt/panel_region_terrain.xml +++ b/indra/newview/skins/default/xui/pt/panel_region_terrain.xml @@ -12,8 +12,8 @@ terreno" name="terrain_raise_spin"/> - Texturas de terreno (exige arquivos .tga 1024x1024, 24 bit) - + Texturas de terreno + 1 (Baixo) diff --git a/indra/newview/skins/default/xui/ru/menu_inventory_add.xml b/indra/newview/skins/default/xui/ru/menu_inventory_add.xml index 35ac72a8d0..9eb55f64b3 100644 --- a/indra/newview/skins/default/xui/ru/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/ru/menu_inventory_add.xml @@ -1,7 +1,7 @@ - + diff --git a/indra/newview/skins/default/xui/ru/menu_viewer.xml b/indra/newview/skins/default/xui/ru/menu_viewer.xml index c79f86a79e..4c50f74c68 100644 --- a/indra/newview/skins/default/xui/ru/menu_viewer.xml +++ b/indra/newview/skins/default/xui/ru/menu_viewer.xml @@ -288,7 +288,7 @@ - + diff --git a/indra/newview/skins/default/xui/ru/panel_region_terrain.xml b/indra/newview/skins/default/xui/ru/panel_region_terrain.xml index a2a2988da7..9d4f3c127c 100644 --- a/indra/newview/skins/default/xui/ru/panel_region_terrain.xml +++ b/indra/newview/skins/default/xui/ru/panel_region_terrain.xml @@ -10,8 +10,8 @@ - Текстуры ландшафта (требования: 1024x1024, 24-битные, TGA) - + Текстуры ландшафта + 1 (Низ) diff --git a/indra/newview/skins/default/xui/tr/menu_inventory_add.xml b/indra/newview/skins/default/xui/tr/menu_inventory_add.xml index f0a6d24018..57ff25ea0f 100644 --- a/indra/newview/skins/default/xui/tr/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/tr/menu_inventory_add.xml @@ -1,7 +1,7 @@ - + diff --git a/indra/newview/skins/default/xui/tr/menu_viewer.xml b/indra/newview/skins/default/xui/tr/menu_viewer.xml index ed7ea9e1e9..c889b0ccaa 100644 --- a/indra/newview/skins/default/xui/tr/menu_viewer.xml +++ b/indra/newview/skins/default/xui/tr/menu_viewer.xml @@ -145,7 +145,7 @@ - + diff --git a/indra/newview/skins/default/xui/tr/panel_region_terrain.xml b/indra/newview/skins/default/xui/tr/panel_region_terrain.xml index 92de4c7f54..00560d4c5b 100644 --- a/indra/newview/skins/default/xui/tr/panel_region_terrain.xml +++ b/indra/newview/skins/default/xui/tr/panel_region_terrain.xml @@ -10,8 +10,8 @@ - Yüzey Dokuları (1024x1024, 24 bit .tga dosyalar gerektirir) - + Yüzey Dokuları + 1 (Düşük) diff --git a/indra/newview/skins/default/xui/zh/menu_inventory_add.xml b/indra/newview/skins/default/xui/zh/menu_inventory_add.xml index 49be302e51..f22b76b9d5 100644 --- a/indra/newview/skins/default/xui/zh/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/zh/menu_inventory_add.xml @@ -1,7 +1,7 @@ - + diff --git a/indra/newview/skins/default/xui/zh/menu_viewer.xml b/indra/newview/skins/default/xui/zh/menu_viewer.xml index 3dde75ca62..28be6900b6 100644 --- a/indra/newview/skins/default/xui/zh/menu_viewer.xml +++ b/indra/newview/skins/default/xui/zh/menu_viewer.xml @@ -157,7 +157,7 @@ - + diff --git a/indra/newview/skins/default/xui/zh/panel_region_terrain.xml b/indra/newview/skins/default/xui/zh/panel_region_terrain.xml index 81bce46876..8490eeaafc 100644 --- a/indra/newview/skins/default/xui/zh/panel_region_terrain.xml +++ b/indra/newview/skins/default/xui/zh/panel_region_terrain.xml @@ -10,7 +10,7 @@ - 地形材質(須 1024x1024,24 位元 .tga 檔格式) + 地形材質 1(低) diff --git a/indra/newview/skins/starlight/xui/en/floater_tools.xml b/indra/newview/skins/starlight/xui/en/floater_tools.xml index 08cd9438e6..4b49074251 100644 --- a/indra/newview/skins/starlight/xui/en/floater_tools.xml +++ b/indra/newview/skins/starlight/xui/en/floater_tools.xml @@ -1,4 +1,4 @@ - + + follows="left|top" + name="Probe Volume Type" + tool_tip="Choose the probe influence volume" + width="140"> + + Probe Update + + + + + + + + + follows="left|top" + name="Probe Volume Type" + tool_tip="Choose the probe influence volume" + width="140"> + + Probe Update + + + + + + + + follows="left|top" + name="Probe Volume Type" + tool_tip="Choose the probe influence volume" + width="140"> + + Probe Update + + + + + + +