mirror of
https://github.com/overte-org/overte.git
synced 2025-04-07 17:52:26 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into head-puck
This commit is contained in:
commit
a0ba1a64b5
45 changed files with 1496 additions and 587 deletions
25
BUILD.md
25
BUILD.md
|
@ -1,4 +1,4 @@
|
|||
###Dependencies
|
||||
### Dependencies
|
||||
|
||||
* [cmake](https://cmake.org/download/) ~> 3.3.2
|
||||
* [Qt](https://www.qt.io/download-open-source) ~> 5.6.2
|
||||
|
@ -6,7 +6,7 @@
|
|||
* IMPORTANT: Use the latest available version of OpenSSL to avoid security vulnerabilities.
|
||||
* [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional)
|
||||
|
||||
####CMake External Project Dependencies
|
||||
#### CMake External Project Dependencies
|
||||
|
||||
* [boostconfig](https://github.com/boostorg/config) ~> 1.58
|
||||
* [Bullet Physics Engine](https://github.com/bulletphysics/bullet3/releases) ~> 2.83
|
||||
|
@ -30,16 +30,19 @@ These are not placed in your normal build tree when doing an out of source build
|
|||
|
||||
If you would like to use a specific install of a dependency instead of the version that would be grabbed as a CMake ExternalProject, you can pass -DUSE_LOCAL_$NAME=0 (where $NAME is the name of the subfolder in [cmake/externals](cmake/externals)) when you run CMake to tell it not to get that dependency as an external project.
|
||||
|
||||
###OS Specific Build Guides
|
||||
### OS Specific Build Guides
|
||||
|
||||
* [BUILD_OSX.md](BUILD_OSX.md) - additional instructions for OS X.
|
||||
* [BUILD_LINUX.md](BUILD_LINUX.md) - additional instructions for Linux.
|
||||
* [BUILD_WIN.md](BUILD_WIN.md) - additional instructions for Windows.
|
||||
* [BUILD_ANDROID.md](BUILD_ANDROID.md) - additional instructions for Android
|
||||
|
||||
###CMake
|
||||
### CMake
|
||||
|
||||
Hifi uses CMake to generate build files and project files for your platform.
|
||||
|
||||
####Qt
|
||||
#### Qt
|
||||
|
||||
In order for CMake to find the Qt5 find modules, you will need to set a QT_CMAKE_PREFIX_PATH environment variable pointing to your Qt installation.
|
||||
|
||||
This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment).
|
||||
|
@ -50,7 +53,8 @@ The path it needs to be set to will depend on where and how Qt5 was installed. e
|
|||
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.6.2/lib/cmake
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/opt/qt5/lib/cmake
|
||||
|
||||
####Generating build files
|
||||
#### Generating build files
|
||||
|
||||
Create a build directory in the root of your checkout and then run the CMake build from there. This will keep the rest of the directory clean.
|
||||
|
||||
mkdir build
|
||||
|
@ -59,14 +63,15 @@ Create a build directory in the root of your checkout and then run the CMake bui
|
|||
|
||||
If cmake gives you the same error message repeatedly after the build fails (e.g. you had a typo in the QT_CMAKE_PREFIX_PATH that you fixed but the `.cmake` files still cannot be found), try removing `CMakeCache.txt`.
|
||||
|
||||
####Variables
|
||||
#### Variables
|
||||
|
||||
Any variables that need to be set for CMake to find dependencies can be set as ENV variables in your shell profile, or passed directly to CMake with a `-D` flag appended to the `cmake ..` command.
|
||||
|
||||
For example, to pass the QT_CMAKE_PREFIX_PATH variable during build file generation:
|
||||
|
||||
cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.6.2/lib/cmake
|
||||
|
||||
####Finding Dependencies
|
||||
#### Finding Dependencies
|
||||
|
||||
The following applies for dependencies we do not grab via CMake ExternalProject (OpenSSL is an example), or for dependencies you have opted not to grab as a CMake ExternalProject (via -DUSE_LOCAL_$NAME=0). The list of dependencies we grab by default as external projects can be found in [the CMake External Project Dependencies section](#cmake-external-project-dependencies).
|
||||
|
||||
|
@ -78,8 +83,8 @@ In the examples below the variable $NAME would be replaced by the name of the de
|
|||
* $NAME_ROOT_DIR - set this variable in your ENV
|
||||
* HIFI_LIB_DIR - set this variable in your ENV to your High Fidelity lib folder, should contain a folder '$name'
|
||||
|
||||
###Optional Components
|
||||
### Optional Components
|
||||
|
||||
####Devices
|
||||
#### Devices
|
||||
|
||||
You can support external input/output devices such as Leap Motion, MIDI, and more by adding each individual SDK in the visible building path. Refer to the readme file available in each device folder in [interface/external/](interface/external) for the detailed explanation of the requirements to use the device.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only Android specific instructions are found in this file.
|
||||
|
||||
###Android Dependencies
|
||||
### Android Dependencies
|
||||
|
||||
You will need the following tools to build our Android targets.
|
||||
|
||||
|
@ -17,23 +17,23 @@ You will need the following tools to build our Android targets.
|
|||
|
||||
You will also need to cross-compile the dependencies required for all platforms for Android, and help CMake find these compiled libraries on your machine.
|
||||
|
||||
####Scribe
|
||||
#### Scribe
|
||||
|
||||
High Fidelity has a shader pre-processing tool called `scribe` that various libraries will call on during the build process. You must compile scribe using your native toolchain (following the build instructions for your platform) and then pass a CMake variable or set an ENV variable `SCRIBE_PATH` that is a path to the scribe executable.
|
||||
|
||||
CMake will fatally error if it does not find the scribe executable while using the android toolchain.
|
||||
|
||||
####Optional Components
|
||||
#### Optional Components
|
||||
|
||||
* [Oculus Mobile SDK](https://developer.oculus.com/downloads/#sdk=mobile) ~> 0.4.2
|
||||
|
||||
####ANDROID_LIB_DIR
|
||||
#### ANDROID_LIB_DIR
|
||||
|
||||
Since you won't be installing Android dependencies to system paths on your development machine, CMake will need a little help tracking down your Android dependencies.
|
||||
|
||||
This is most easily accomplished by installing all Android dependencies in the same folder. You can place this folder wherever you like on your machine. In this build guide and across our CMakeLists files this folder is referred to as `ANDROID_LIB_DIR`. You can set `ANDROID_LIB_DIR` in your environment or by passing when you run CMake.
|
||||
|
||||
####Qt
|
||||
#### Qt
|
||||
|
||||
Install Qt 5.5.1 for Android for your host environment from the [Qt downloads page](http://www.qt.io/download/). Install Qt to ``$ANDROID_LIB_DIR/Qt``. This is required so that our root CMakeLists file can help CMake find your Android Qt installation.
|
||||
|
||||
|
@ -41,7 +41,7 @@ The component required for the Android build is the `Android armv7` component.
|
|||
|
||||
If you would like to install Qt to a different location, or attempt to build with a different Qt version, you can pass `ANDROID_QT_CMAKE_PREFIX_PATH` to CMake. Point to the `cmake` folder inside `$VERSION_NUMBER/android_armv7/lib`. Otherwise, our root CMakeLists will set it to `$ANDROID_LIB_DIR/Qt/5.5/android_armv7/lib/cmake`.
|
||||
|
||||
####OpenSSL
|
||||
#### OpenSSL
|
||||
|
||||
Cross-compilation of OpenSSL has been tested from an OS X machine running 10.10 compiling OpenSSL 1.0.2. It is likely that the steps below will work for other OpenSSL versions than 1.0.2.
|
||||
|
||||
|
@ -76,7 +76,7 @@ This should generate libcrypto and libssl in the root of the OpenSSL directory.
|
|||
|
||||
If you have been building other components it is possible that the OpenSSL compile will fail based on the values other cross-compilations (tbb, bullet) have set. Ensure that you are in a new terminal window to avoid compilation errors from previously set environment variables.
|
||||
|
||||
####Oculus Mobile SDK
|
||||
#### Oculus Mobile SDK
|
||||
|
||||
The Oculus Mobile SDK is optional, for Gear VR support. It is not required to compile gvr-interface.
|
||||
|
||||
|
@ -91,7 +91,7 @@ ndk-build
|
|||
|
||||
This will create the liboculus.a archive that our FindLibOVR module will look for when cmake is run.
|
||||
|
||||
#####Hybrid testing
|
||||
##### Hybrid testing
|
||||
|
||||
Currently the 'vr_dual' mode that would allow us to run a hybrid app has limited support in the Oculus Mobile SDK. The best way to have an application we can launch without having to connect to the GearVR is to put the Gear VR Service into developer mode. This stops Oculus Home from taking over the device when it is plugged into the Gear VR headset, and allows the application to be launched from the Applications page.
|
||||
|
||||
|
@ -99,7 +99,7 @@ To put the Gear VR Service into developer mode you need an application with an O
|
|||
|
||||
Once the application is on your device, go to `Settings->Application Manager->Gear VR Service->Manage Storage`. Tap on `VR Service Version` six times. It will scan your device to verify that you have an osig file in an application on your device, and then it will let you enable Developer mode.
|
||||
|
||||
###CMake
|
||||
### CMake
|
||||
|
||||
We use CMake to generate the makefiles that compile and deploy the Android APKs to your device. In order to create Makefiles for the Android targets, CMake requires that some environment variables are set, and that other variables are passed to it when it is run.
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only Linux specific instructions are found in this file.
|
||||
|
||||
###Qt5 Dependencies
|
||||
### Qt5 Dependencies
|
||||
|
||||
Should you choose not to install Qt5 via a package manager that handles dependencies for you, you may be missing some Qt5 dependencies. On Ubuntu, for example, the following additional packages are required:
|
||||
|
||||
libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack0 libjack-dev libxrandr-dev libudev-dev libssl-dev
|
||||
|
|
11
BUILD_OSX.md
11
BUILD_OSX.md
|
@ -1,12 +1,13 @@
|
|||
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only OS X specific instructions are found in this file.
|
||||
|
||||
###Homebrew
|
||||
### Homebrew
|
||||
|
||||
[Homebrew](https://brew.sh/) is an excellent package manager for OS X. It makes install of some High Fidelity dependencies very simple.
|
||||
|
||||
brew tap homebrew/versions
|
||||
brew install cmake openssl
|
||||
|
||||
###OpenSSL
|
||||
### OpenSSL
|
||||
|
||||
Assuming you've installed OpenSSL using the homebrew instructions above, you'll need to set OPENSSL_ROOT_DIR so CMake can find your installations.
|
||||
For OpenSSL installed via homebrew, set OPENSSL_ROOT_DIR:
|
||||
|
@ -15,7 +16,8 @@ For OpenSSL installed via homebrew, set OPENSSL_ROOT_DIR:
|
|||
|
||||
Note that this uses the version from the homebrew formula at the time of this writing, and the version in the path will likely change.
|
||||
|
||||
###Qt
|
||||
### Qt
|
||||
|
||||
Download and install the [Qt 5.6.2 for macOS](http://download.qt.io/official_releases/qt/5.6/5.6.2/qt-opensource-mac-x64-clang-5.6.2.dmg).
|
||||
|
||||
Keep the default components checked when going through the installer.
|
||||
|
@ -23,7 +25,8 @@ Keep the default components checked when going through the installer.
|
|||
Once Qt is installed, you need to manually configure the following:
|
||||
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt5.6.2/5.6/clang_64/lib/cmake/` directory.
|
||||
|
||||
###Xcode
|
||||
### Xcode
|
||||
|
||||
If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles.
|
||||
|
||||
cmake .. -GXcode
|
||||
|
|
26
BUILD_WIN.md
26
BUILD_WIN.md
|
@ -1,32 +1,32 @@
|
|||
This is a stand-alone guide for creating your first High Fidelity build for Windows 64-bit.
|
||||
|
||||
###Step 1. Installing Visual Studio 2013
|
||||
### Step 1. Installing Visual Studio 2013
|
||||
|
||||
If you don't already have the Community or Professional edition of Visual Studio 2013, download and install [Visual Studio Community 2013](https://www.visualstudio.com/en-us/news/releasenotes/vs2013-community-vs). You do not need to install any of the optional components when going through the installer.
|
||||
|
||||
Note: Newer versions of Visual Studio are not yet compatible.
|
||||
|
||||
###Step 2. Installing CMake
|
||||
### Step 2. Installing CMake
|
||||
|
||||
Download and install the [CMake 3.8.0 win64-x64 Installer](https://cmake.org/files/v3.8/cmake-3.8.0-win64-x64.msi). Make sure "Add CMake to system PATH for all users" is checked when going through the installer.
|
||||
|
||||
###Step 3. Installing Qt
|
||||
### Step 3. Installing Qt
|
||||
|
||||
Download and install the [Qt 5.6.2 for Windows 64-bit (VS 2013)](http://download.qt.io/official_releases/qt/5.6/5.6.2/qt-opensource-windows-x86-msvc2013_64-5.6.2.exe).
|
||||
|
||||
Keep the default components checked when going through the installer.
|
||||
|
||||
###Step 4. Setting Qt Environment Variable
|
||||
### Step 4. Setting Qt Environment Variable
|
||||
|
||||
Go to "Control Panel > System > Advanced System Settings > Environment Variables > New..." (or search “Environment Variables” in Start Search).
|
||||
* Set "Variable name": QT_CMAKE_PREFIX_PATH
|
||||
* Set "Variable value": `%QT_DIR%\5.6\msvc2013_64\lib\cmake`
|
||||
|
||||
###Step 5. Installing OpenSSL
|
||||
### Step 5. Installing OpenSSL
|
||||
|
||||
Download and install the [Win64 OpenSSL v1.0.2k Installer](https://slproweb.com/download/Win64OpenSSL-1_0_2k.exe).
|
||||
Download and install the [Win64 OpenSSL v1.0.2L Installer](https://slproweb.com/download/Win64OpenSSL-1_0_2L.exe).
|
||||
|
||||
###Step 6. Running CMake to Generate Build Files
|
||||
### Step 6. Running CMake to Generate Build Files
|
||||
|
||||
Run Command Prompt from Start and run the following commands:
|
||||
cd "%HIFI_DIR%"
|
||||
|
@ -36,7 +36,7 @@ Run Command Prompt from Start and run the following commands:
|
|||
|
||||
Where %HIFI_DIR% is the directory for the highfidelity repository.
|
||||
|
||||
###Step 7. Making a Build
|
||||
### Step 7. Making a Build
|
||||
|
||||
Open '%HIFI_DIR%\build\hifi.sln' using Visual Studio.
|
||||
|
||||
|
@ -44,7 +44,7 @@ Change the Solution Configuration (next to the green play button) from "Debug" t
|
|||
|
||||
Run Build > Build Solution.
|
||||
|
||||
###Step 8. Testing Interface
|
||||
### Step 8. Testing Interface
|
||||
|
||||
Create another environment variable (see Step #4)
|
||||
* Set "Variable name": _NO_DEBUG_HEAP
|
||||
|
@ -56,7 +56,7 @@ Now, you should have a full build of High Fidelity and be able to run the Interf
|
|||
|
||||
Note: You can also run Interface by launching it from command line or File Explorer from %HIFI_DIR%\build\interface\Release\interface.exe
|
||||
|
||||
###Troubleshooting
|
||||
### Troubleshooting
|
||||
|
||||
For any problems after Step #6, first try this:
|
||||
* Delete your locally cloned copy of the highfidelity repository
|
||||
|
@ -64,18 +64,18 @@ For any problems after Step #6, first try this:
|
|||
* Redownload the [repository](https://github.com/highfidelity/hifi)
|
||||
* Restart directions from Step #6
|
||||
|
||||
####CMake gives you the same error message repeatedly after the build fails
|
||||
#### CMake gives you the same error message repeatedly after the build fails
|
||||
|
||||
Remove `CMakeCache.txt` found in the '%HIFI_DIR%\build' directory
|
||||
|
||||
####nmake cannot be found
|
||||
#### nmake cannot be found
|
||||
|
||||
Make sure nmake.exe is located at the following path:
|
||||
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin
|
||||
|
||||
If not, add the directory where nmake is located to the PATH environment variable.
|
||||
|
||||
####Qt is throwing an error
|
||||
#### Qt is throwing an error
|
||||
|
||||
Make sure you have the correct version (5.6.2) installed and 'QT_CMAKE_PREFIX_PATH' environment variable is set correctly.
|
||||
|
||||
|
|
|
@ -2,15 +2,15 @@ Follow the [build guide](BUILD.md) to figure out how to build High Fidelity for
|
|||
|
||||
During generation, CMake should produce an `install` target and a `package` target.
|
||||
|
||||
###Install
|
||||
### Install
|
||||
|
||||
The `install` target will copy the High Fidelity targets and their dependencies to your `CMAKE_INSTALL_PREFIX`.
|
||||
|
||||
###Packaging
|
||||
### Packaging
|
||||
|
||||
To produce an installer, run the `package` target.
|
||||
|
||||
####Windows
|
||||
#### Windows
|
||||
|
||||
To produce an executable installer on Windows, the following are required:
|
||||
|
||||
|
@ -20,6 +20,6 @@ To produce an executable installer on Windows, the following are required:
|
|||
|
||||
Run the `package` target to create an executable installer using the Nullsoft Scriptable Install System.
|
||||
|
||||
####OS X
|
||||
#### OS X
|
||||
|
||||
Run the `package` target to create an Apple Disk Image (.dmg).
|
||||
|
|
|
@ -436,6 +436,10 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
const char* portStr = getCmdOption(argc, constArgv, "--listenPort");
|
||||
const int listenPort = portStr ? atoi(portStr) : INVALID_PORT;
|
||||
|
||||
static const auto SUPPRESS_SETTINGS_RESET = "--suppress-settings-reset";
|
||||
bool suppressPrompt = cmdOptionExists(argc, const_cast<const char**>(argv), SUPPRESS_SETTINGS_RESET);
|
||||
bool previousSessionCrashed = CrashHandler::checkForResetSettings(runningMarkerExisted, suppressPrompt);
|
||||
|
||||
Setting::init();
|
||||
|
||||
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
|
||||
|
@ -456,10 +460,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
QCoreApplication::addLibraryPath(audioDLLPath);
|
||||
#endif
|
||||
|
||||
static const auto SUPPRESS_SETTINGS_RESET = "--suppress-settings-reset";
|
||||
bool suppressPrompt = cmdOptionExists(argc, const_cast<const char**>(argv), SUPPRESS_SETTINGS_RESET);
|
||||
bool previousSessionCrashed = CrashHandler::checkForResetSettings(runningMarkerExisted, suppressPrompt);
|
||||
|
||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||
DependencyManager::registerInheritance<AvatarHashMap, AvatarManager>();
|
||||
DependencyManager::registerInheritance<EntityDynamicFactoryInterface, InterfaceDynamicFactory>();
|
||||
|
@ -4881,12 +4881,6 @@ QRect Application::getDesirableApplicationGeometry() const {
|
|||
return applicationGeometry;
|
||||
}
|
||||
|
||||
glm::vec3 Application::getSunDirection() const {
|
||||
// Sun direction is in fact just the location of the sun relative to the origin
|
||||
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
||||
return skyStage->getSunLight()->getDirection();
|
||||
}
|
||||
|
||||
// FIXME, preprocessor guard this check to occur only in DEBUG builds
|
||||
static QThread * activeRenderingThread = nullptr;
|
||||
|
||||
|
@ -4953,90 +4947,6 @@ namespace render {
|
|||
}
|
||||
}
|
||||
|
||||
// Background Render Data & rendering functions
|
||||
class BackgroundRenderData {
|
||||
public:
|
||||
typedef render::Payload<BackgroundRenderData> Payload;
|
||||
typedef Payload::DataPointer Pointer;
|
||||
|
||||
static render::ItemID _item; // unique WorldBoxRenderData
|
||||
};
|
||||
|
||||
render::ItemID BackgroundRenderData::_item = 0;
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const BackgroundRenderData::Pointer& stuff) {
|
||||
return ItemKey::Builder::background();
|
||||
}
|
||||
|
||||
template <> const Item::Bound payloadGetBound(const BackgroundRenderData::Pointer& stuff) {
|
||||
return Item::Bound();
|
||||
}
|
||||
|
||||
template <> void payloadRender(const BackgroundRenderData::Pointer& background, RenderArgs* args) {
|
||||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
|
||||
// Background rendering decision
|
||||
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
||||
auto backgroundMode = skyStage->getBackgroundMode();
|
||||
|
||||
switch (backgroundMode) {
|
||||
case model::SunSkyStage::SKY_DEFAULT: {
|
||||
auto scene = DependencyManager::get<SceneScriptingInterface>()->getStage();
|
||||
auto sceneKeyLight = scene->getKeyLight();
|
||||
|
||||
scene->setSunModelEnable(false);
|
||||
sceneKeyLight->setColor(ColorUtils::toVec3(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_COLOR));
|
||||
sceneKeyLight->setIntensity(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_INTENSITY);
|
||||
sceneKeyLight->setAmbientIntensity(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_AMBIENT_INTENSITY);
|
||||
sceneKeyLight->setDirection(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_DIRECTION);
|
||||
// fall through: render a skybox (if available), or the defaults (if requested)
|
||||
}
|
||||
|
||||
case model::SunSkyStage::SKY_BOX: {
|
||||
auto skybox = skyStage->getSkybox();
|
||||
if (!skybox->empty()) {
|
||||
PerformanceTimer perfTimer("skybox");
|
||||
skybox->render(batch, args->getViewFrustum());
|
||||
break;
|
||||
}
|
||||
// fall through: render defaults (if requested)
|
||||
}
|
||||
|
||||
case model::SunSkyStage::SKY_DEFAULT_AMBIENT_TEXTURE: {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::DefaultSkybox)) {
|
||||
auto scene = DependencyManager::get<SceneScriptingInterface>()->getStage();
|
||||
auto sceneKeyLight = scene->getKeyLight();
|
||||
auto defaultSkyboxAmbientTexture = qApp->getDefaultSkyboxAmbientTexture();
|
||||
if (defaultSkyboxAmbientTexture) {
|
||||
sceneKeyLight->setAmbientSphere(defaultSkyboxAmbientTexture->getIrradiance());
|
||||
sceneKeyLight->setAmbientMap(defaultSkyboxAmbientTexture);
|
||||
} else {
|
||||
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(
|
||||
"Failed to get a valid Default Skybox Ambient Texture ? probably because it couldn't be find during initialization step");
|
||||
}
|
||||
// fall through: render defaults skybox
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case model::SunSkyStage::SKY_DEFAULT_TEXTURE:
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::DefaultSkybox)) {
|
||||
qApp->getDefaultSkybox()->render(batch, args->getViewFrustum());
|
||||
}
|
||||
break;
|
||||
|
||||
// Any other cases require no extra rendering
|
||||
case model::SunSkyStage::NO_BACKGROUND:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool selfAvatarOnly) {
|
||||
|
||||
// FIXME: This preDisplayRender call is temporary until we create a separate render::scene for the mirror rendering.
|
||||
|
@ -5060,15 +4970,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
|
|||
// The pending changes collecting the changes here
|
||||
render::Transaction transaction;
|
||||
|
||||
// FIXME: Move this out of here!, Background / skybox should be driven by the enityt content just like the other entities
|
||||
// Background rendering decision
|
||||
if (!render::Item::isValidID(BackgroundRenderData::_item)) {
|
||||
auto backgroundRenderData = make_shared<BackgroundRenderData>();
|
||||
auto backgroundRenderPayload = make_shared<BackgroundRenderData::Payload>(backgroundRenderData);
|
||||
BackgroundRenderData::_item = _main3DScene->allocateID();
|
||||
transaction.resetItem(BackgroundRenderData::_item, backgroundRenderPayload);
|
||||
}
|
||||
|
||||
// Assuming nothing gets rendered through that
|
||||
if (!selfAvatarOnly) {
|
||||
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
|
||||
|
@ -5104,12 +5005,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
|
|||
});
|
||||
}
|
||||
|
||||
// Setup the current Zone Entity lighting
|
||||
{
|
||||
auto stage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
||||
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(stage->getSunLight());
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("SceneProcessTransaction");
|
||||
_main3DScene->enqueueTransaction(transaction);
|
||||
|
|
|
@ -460,8 +460,6 @@ private:
|
|||
|
||||
void queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions, bool forceResend = false);
|
||||
|
||||
glm::vec3 getSunDirection() const;
|
||||
|
||||
void renderRearViewMirror(RenderArgs* renderArgs, const QRect& region, bool isZoomed);
|
||||
|
||||
int sendNackPackets();
|
||||
|
|
|
@ -24,12 +24,15 @@
|
|||
|
||||
#include "Application.h"
|
||||
#include "Menu.h"
|
||||
#include <SettingHandle.h>
|
||||
|
||||
#include <RunningMarker.h>
|
||||
#include <SettingHandle.h>
|
||||
#include <SettingHelpers.h>
|
||||
|
||||
|
||||
bool CrashHandler::checkForResetSettings(bool wasLikelyCrash, bool suppressPrompt) {
|
||||
Settings settings;
|
||||
QSettings::setDefaultFormat(JSON_FORMAT);
|
||||
QSettings settings;
|
||||
settings.beginGroup("Developer");
|
||||
QVariant displayCrashOptions = settings.value(MenuOption::DisplayCrashOptions);
|
||||
QVariant askToResetSettingsOption = settings.value(MenuOption::AskToResetSettings);
|
||||
|
@ -106,7 +109,7 @@ void CrashHandler::handleCrash(CrashHandler::Action action) {
|
|||
return;
|
||||
}
|
||||
|
||||
Settings settings;
|
||||
QSettings settings;
|
||||
const QString ADDRESS_MANAGER_GROUP = "AddressManager";
|
||||
const QString ADDRESS_KEY = "address";
|
||||
const QString AVATAR_GROUP = "Avatar";
|
||||
|
|
|
@ -444,6 +444,9 @@ void Web3DOverlay::handlePointerEventAsTouch(const PointerEvent& event) {
|
|||
|
||||
QCoreApplication::postEvent(_webSurface->getWindow(), touchEvent);
|
||||
|
||||
if (this->_pressed && event.getType() == PointerEvent::Move) {
|
||||
return;
|
||||
}
|
||||
// Send mouse events to the Web surface so that HTML dialog elements work with mouse press and hover.
|
||||
// FIXME: Scroll bar dragging is a bit unstable in the tablet (content can jump up and down at times).
|
||||
// This may be improved in Qt 5.8. Release notes: "Cleaned up touch and mouse event delivery".
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <QRunnable>
|
||||
#include <QThreadPool>
|
||||
#include <QDataStream>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
|
@ -49,13 +51,43 @@ Sound::Sound(const QUrl& url, bool isStereo, bool isAmbisonic) :
|
|||
_isAmbisonic(isAmbisonic),
|
||||
_isReady(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Sound::downloadFinished(const QByteArray& data) {
|
||||
// this is a QRunnable, will delete itself after it has finished running
|
||||
SoundProcessor* soundProcessor = new SoundProcessor(_url, data, _isStereo, _isAmbisonic);
|
||||
connect(soundProcessor, &SoundProcessor::onSuccess, this, &Sound::soundProcessSuccess);
|
||||
connect(soundProcessor, &SoundProcessor::onError, this, &Sound::soundProcessError);
|
||||
QThreadPool::globalInstance()->start(soundProcessor);
|
||||
}
|
||||
|
||||
void Sound::soundProcessSuccess(QByteArray data, bool stereo, bool ambisonic, float duration) {
|
||||
|
||||
qCDebug(audio) << "Setting ready state for sound file" << _url.toDisplayString();
|
||||
|
||||
_byteArray = data;
|
||||
_isStereo = stereo;
|
||||
_isAmbisonic = ambisonic;
|
||||
_duration = duration;
|
||||
_isReady = true;
|
||||
finishedLoading(true);
|
||||
|
||||
emit ready();
|
||||
}
|
||||
|
||||
void Sound::soundProcessError(int error, QString str) {
|
||||
qCCritical(audio) << "Failed to process sound file" << _url.toDisplayString() << "code =" << error << str;
|
||||
emit failed(QNetworkReply::UnknownContentError);
|
||||
finishedLoading(false);
|
||||
}
|
||||
|
||||
void SoundProcessor::run() {
|
||||
|
||||
qCDebug(audio) << "Processing sound file" << _url.toDisplayString();
|
||||
|
||||
// replace our byte array with the downloaded data
|
||||
QByteArray rawAudioByteArray = QByteArray(data);
|
||||
QString fileName = getURL().fileName().toLower();
|
||||
QByteArray rawAudioByteArray = QByteArray(_data);
|
||||
QString fileName = _url.fileName().toLower();
|
||||
|
||||
static const QString WAV_EXTENSION = ".wav";
|
||||
static const QString RAW_EXTENSION = ".raw";
|
||||
|
@ -72,31 +104,28 @@ void Sound::downloadFinished(const QByteArray& data) {
|
|||
// since it's raw the only way for us to know that is if the file was called .stereo.raw
|
||||
if (fileName.toLower().endsWith("stereo.raw")) {
|
||||
_isStereo = true;
|
||||
qCDebug(audio) << "Processing sound of" << rawAudioByteArray.size() << "bytes from" << getURL() << "as stereo audio file.";
|
||||
qCDebug(audio) << "Processing sound of" << rawAudioByteArray.size() << "bytes from" << _url << "as stereo audio file.";
|
||||
}
|
||||
|
||||
// Process as 48khz RAW file
|
||||
downSample(rawAudioByteArray, 48000);
|
||||
} else {
|
||||
qCDebug(audio) << "Unknown sound file type";
|
||||
emit onError(300, "Failed to load sound file, reason: unknown sound file type");
|
||||
return;
|
||||
}
|
||||
|
||||
finishedLoading(true);
|
||||
|
||||
_isReady = true;
|
||||
emit ready();
|
||||
emit onSuccess(_data, _isStereo, _isAmbisonic, _duration);
|
||||
}
|
||||
|
||||
void Sound::downSample(const QByteArray& rawAudioByteArray, int sampleRate) {
|
||||
void SoundProcessor::downSample(const QByteArray& rawAudioByteArray, int sampleRate) {
|
||||
|
||||
// we want to convert it to the format that the audio-mixer wants
|
||||
// which is signed, 16-bit, 24Khz
|
||||
|
||||
if (sampleRate == AudioConstants::SAMPLE_RATE) {
|
||||
|
||||
// no resampling needed
|
||||
_byteArray = rawAudioByteArray;
|
||||
|
||||
_data = rawAudioByteArray;
|
||||
} else {
|
||||
|
||||
int numChannels = _isAmbisonic ? AudioConstants::AMBISONIC : (_isStereo ? AudioConstants::STEREO : AudioConstants::MONO);
|
||||
|
@ -106,15 +135,15 @@ void Sound::downSample(const QByteArray& rawAudioByteArray, int sampleRate) {
|
|||
int numSourceFrames = rawAudioByteArray.size() / (numChannels * sizeof(AudioConstants::AudioSample));
|
||||
int maxDestinationFrames = resampler.getMaxOutput(numSourceFrames);
|
||||
int maxDestinationBytes = maxDestinationFrames * numChannels * sizeof(AudioConstants::AudioSample);
|
||||
_byteArray.resize(maxDestinationBytes);
|
||||
_data.resize(maxDestinationBytes);
|
||||
|
||||
int numDestinationFrames = resampler.render((int16_t*)rawAudioByteArray.data(),
|
||||
(int16_t*)_byteArray.data(),
|
||||
(int16_t*)_data.data(),
|
||||
numSourceFrames);
|
||||
|
||||
// truncate to actual output
|
||||
int numDestinationBytes = numDestinationFrames * numChannels * sizeof(AudioConstants::AudioSample);
|
||||
_byteArray.resize(numDestinationBytes);
|
||||
_data.resize(numDestinationBytes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,7 +192,7 @@ struct WAVEFormat {
|
|||
};
|
||||
|
||||
// returns wavfile sample rate, used for resampling
|
||||
int Sound::interpretAsWav(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray) {
|
||||
int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray) {
|
||||
|
||||
// Create a data stream to analyze the data
|
||||
QDataStream waveStream(const_cast<QByteArray *>(&inputAudioByteArray), QIODevice::ReadOnly);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#ifndef hifi_Sound_h
|
||||
#define hifi_Sound_h
|
||||
|
||||
#include <QRunnable>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QtScript/qscriptengine.h>
|
||||
|
@ -28,12 +29,15 @@ public:
|
|||
bool isAmbisonic() const { return _isAmbisonic; }
|
||||
bool isReady() const { return _isReady; }
|
||||
float getDuration() const { return _duration; }
|
||||
|
||||
|
||||
const QByteArray& getByteArray() const { return _byteArray; }
|
||||
|
||||
signals:
|
||||
void ready();
|
||||
|
||||
protected slots:
|
||||
void soundProcessSuccess(QByteArray data, bool stereo, bool ambisonic, float duration);
|
||||
void soundProcessError(int error, QString str);
|
||||
|
||||
private:
|
||||
QByteArray _byteArray;
|
||||
|
@ -42,10 +46,33 @@ private:
|
|||
bool _isReady;
|
||||
float _duration; // In seconds
|
||||
|
||||
virtual void downloadFinished(const QByteArray& data) override;
|
||||
};
|
||||
|
||||
class SoundProcessor : public QObject, public QRunnable {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SoundProcessor(const QUrl& url, const QByteArray& data, bool stereo, bool ambisonic)
|
||||
: _url(url), _data(data), _isStereo(stereo), _isAmbisonic(ambisonic)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void run() override;
|
||||
|
||||
void downSample(const QByteArray& rawAudioByteArray, int sampleRate);
|
||||
int interpretAsWav(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray);
|
||||
|
||||
virtual void downloadFinished(const QByteArray& data) override;
|
||||
|
||||
signals:
|
||||
void onSuccess(QByteArray data, bool stereo, bool ambisonic, float duration);
|
||||
void onError(int error, QString str);
|
||||
|
||||
private:
|
||||
QUrl _url;
|
||||
QByteArray _data;
|
||||
bool _isStereo;
|
||||
bool _isAmbisonic;
|
||||
float _duration;
|
||||
};
|
||||
|
||||
typedef QSharedPointer<Sound> SharedSoundPointer;
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <PerfStat.h>
|
||||
#include <SceneScriptingInterface.h>
|
||||
#include <ScriptEngine.h>
|
||||
#include <procedural/ProceduralSkybox.h>
|
||||
|
||||
#include "EntityTreeRenderer.h"
|
||||
|
||||
|
@ -141,7 +140,6 @@ void EntityTreeRenderer::clear() {
|
|||
|
||||
// reset the zone to the default (while we load the next scene)
|
||||
_layeredZones.clear();
|
||||
applyZoneAndHasSkybox(nullptr);
|
||||
|
||||
OctreeRenderer::clear();
|
||||
}
|
||||
|
@ -196,14 +194,6 @@ void EntityTreeRenderer::update() {
|
|||
// Handle enter/leave entity logic
|
||||
bool updated = checkEnterLeaveEntities();
|
||||
|
||||
// If we haven't already updated and previously attempted to load a texture,
|
||||
// check if the texture loaded and apply it
|
||||
if (!updated &&
|
||||
((_pendingAmbientTexture && (!_ambientTexture || _ambientTexture->isLoaded())) ||
|
||||
(_pendingSkyboxTexture && (!_skyboxTexture || _skyboxTexture->isLoaded())))) {
|
||||
applySkyboxAndHasAmbient();
|
||||
}
|
||||
|
||||
// Even if we're not moving the mouse, if we started clicking on an entity and we have
|
||||
// not yet released the hold then this is still considered a holdingClickOnEntity event
|
||||
// and we want to simulate this message here as well as in mouse move
|
||||
|
@ -371,176 +361,6 @@ bool EntityTreeRenderer::applyLayeredZones() {
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool EntityTreeRenderer::applyZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone) {
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
auto scene = DependencyManager::get<SceneScriptingInterface>();
|
||||
auto sceneStage = scene->getStage();
|
||||
auto skyStage = scene->getSkyStage();
|
||||
auto sceneKeyLight = sceneStage->getKeyLight();
|
||||
|
||||
// If there is no zone, use the default background
|
||||
if (!zone) {
|
||||
_zoneUserData = QString();
|
||||
skyStage->getSkybox()->clear();
|
||||
|
||||
_pendingSkyboxTexture = false;
|
||||
_skyboxTexture.clear();
|
||||
|
||||
_pendingAmbientTexture = false;
|
||||
_ambientTexture.clear();
|
||||
|
||||
sceneKeyLight->resetAmbientSphere();
|
||||
sceneKeyLight->setAmbientMap(nullptr);
|
||||
|
||||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the keylight
|
||||
sceneKeyLight->setColor(ColorUtils::toVec3(zone->getKeyLightProperties().getColor()));
|
||||
sceneKeyLight->setIntensity(zone->getKeyLightProperties().getIntensity());
|
||||
sceneKeyLight->setAmbientIntensity(zone->getKeyLightProperties().getAmbientIntensity());
|
||||
sceneKeyLight->setDirection(zone->getKeyLightProperties().getDirection());
|
||||
|
||||
// Set the stage
|
||||
bool isSunModelEnabled = zone->getStageProperties().getSunModelEnabled();
|
||||
sceneStage->setSunModelEnable(isSunModelEnabled);
|
||||
if (isSunModelEnabled) {
|
||||
sceneStage->setLocation(zone->getStageProperties().getLongitude(),
|
||||
zone->getStageProperties().getLatitude(),
|
||||
zone->getStageProperties().getAltitude());
|
||||
|
||||
auto sceneTime = sceneStage->getTime();
|
||||
sceneTime->setHour(zone->getStageProperties().calculateHour());
|
||||
sceneTime->setDay(zone->getStageProperties().calculateDay());
|
||||
}
|
||||
|
||||
// Set the ambient texture
|
||||
_ambientTextureURL = zone->getKeyLightProperties().getAmbientURL();
|
||||
if (_ambientTextureURL.isEmpty()) {
|
||||
_pendingAmbientTexture = false;
|
||||
_ambientTexture.clear();
|
||||
} else {
|
||||
_pendingAmbientTexture = true;
|
||||
}
|
||||
|
||||
// Set the skybox texture
|
||||
return layerZoneAndHasSkybox(zone);
|
||||
}
|
||||
|
||||
bool EntityTreeRenderer::layerZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone) {
|
||||
assert(zone);
|
||||
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
auto scene = DependencyManager::get<SceneScriptingInterface>();
|
||||
auto skyStage = scene->getSkyStage();
|
||||
auto skybox = skyStage->getSkybox();
|
||||
|
||||
bool hasSkybox = false;
|
||||
|
||||
switch (zone->getBackgroundMode()) {
|
||||
case BACKGROUND_MODE_SKYBOX:
|
||||
hasSkybox = true;
|
||||
|
||||
skybox->setColor(zone->getSkyboxProperties().getColorVec3());
|
||||
|
||||
if (_zoneUserData != zone->getUserData()) {
|
||||
_zoneUserData = zone->getUserData();
|
||||
std::dynamic_pointer_cast<ProceduralSkybox>(skybox)->parse(_zoneUserData);
|
||||
}
|
||||
|
||||
_skyboxTextureURL = zone->getSkyboxProperties().getURL();
|
||||
if (_skyboxTextureURL.isEmpty()) {
|
||||
_pendingSkyboxTexture = false;
|
||||
_skyboxTexture.clear();
|
||||
} else {
|
||||
_pendingSkyboxTexture = true;
|
||||
}
|
||||
|
||||
applySkyboxAndHasAmbient();
|
||||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_BOX);
|
||||
|
||||
break;
|
||||
|
||||
case BACKGROUND_MODE_INHERIT:
|
||||
default:
|
||||
// Clear the skybox to release its textures
|
||||
skybox->clear();
|
||||
_zoneUserData = QString();
|
||||
|
||||
_pendingSkyboxTexture = false;
|
||||
_skyboxTexture.clear();
|
||||
|
||||
// Let the application background through
|
||||
if (applySkyboxAndHasAmbient()) {
|
||||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT_TEXTURE);
|
||||
} else {
|
||||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT_AMBIENT_TEXTURE);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return hasSkybox;
|
||||
}
|
||||
|
||||
bool EntityTreeRenderer::applySkyboxAndHasAmbient() {
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
auto scene = DependencyManager::get<SceneScriptingInterface>();
|
||||
auto sceneStage = scene->getStage();
|
||||
auto skyStage = scene->getSkyStage();
|
||||
auto sceneKeyLight = sceneStage->getKeyLight();
|
||||
auto skybox = skyStage->getSkybox();
|
||||
|
||||
bool isAmbientSet = false;
|
||||
if (_pendingAmbientTexture && !_ambientTexture) {
|
||||
_ambientTexture = textureCache->getTexture(_ambientTextureURL, image::TextureUsage::CUBE_TEXTURE);
|
||||
}
|
||||
if (_ambientTexture && _ambientTexture->isLoaded()) {
|
||||
_pendingAmbientTexture = false;
|
||||
|
||||
auto texture = _ambientTexture->getGPUTexture();
|
||||
if (texture) {
|
||||
isAmbientSet = true;
|
||||
sceneKeyLight->setAmbientSphere(texture->getIrradiance());
|
||||
sceneKeyLight->setAmbientMap(texture);
|
||||
} else {
|
||||
qCDebug(entitiesrenderer) << "Failed to load ambient texture:" << _ambientTexture->getURL();
|
||||
}
|
||||
}
|
||||
|
||||
if (_pendingSkyboxTexture &&
|
||||
(!_skyboxTexture || (_skyboxTexture->getURL() != _skyboxTextureURL))) {
|
||||
_skyboxTexture = textureCache->getTexture(_skyboxTextureURL, image::TextureUsage::CUBE_TEXTURE);
|
||||
}
|
||||
if (_skyboxTexture && _skyboxTexture->isLoaded()) {
|
||||
_pendingSkyboxTexture = false;
|
||||
|
||||
auto texture = _skyboxTexture->getGPUTexture();
|
||||
if (texture) {
|
||||
skybox->setCubemap(texture);
|
||||
if (!isAmbientSet) {
|
||||
sceneKeyLight->setAmbientSphere(texture->getIrradiance());
|
||||
sceneKeyLight->setAmbientMap(texture);
|
||||
isAmbientSet = true;
|
||||
}
|
||||
} else {
|
||||
qCDebug(entitiesrenderer) << "Failed to load skybox texture:" << _skyboxTexture->getURL();
|
||||
skybox->setCubemap(nullptr);
|
||||
}
|
||||
} else {
|
||||
skybox->setCubemap(nullptr);
|
||||
}
|
||||
|
||||
if (!isAmbientSet) {
|
||||
sceneKeyLight->resetAmbientSphere();
|
||||
sceneKeyLight->setAmbientMap(nullptr);
|
||||
}
|
||||
|
||||
return isAmbientSet;
|
||||
}
|
||||
|
||||
const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(EntityItemPointer entityItem) {
|
||||
const FBXGeometry* result = NULL;
|
||||
|
||||
|
@ -1186,8 +1006,6 @@ std::pair<EntityTreeRenderer::LayeredZones::iterator, bool> EntityTreeRenderer::
|
|||
|
||||
void EntityTreeRenderer::LayeredZones::apply() {
|
||||
assert(_entityTreeRenderer);
|
||||
|
||||
applyPartial(begin());
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::LayeredZones::update(std::shared_ptr<ZoneEntityItem> zone) {
|
||||
|
@ -1202,12 +1020,6 @@ void EntityTreeRenderer::LayeredZones::update(std::shared_ptr<ZoneEntityItem> zo
|
|||
} else {
|
||||
LayeredZone zoneLayer(zone);
|
||||
|
||||
// should we update? only if this zone is tighter than the current skybox zone
|
||||
bool shouldUpdate = false;
|
||||
if (_skyboxLayer == end() || zoneLayer <= *_skyboxLayer) {
|
||||
shouldUpdate = true;
|
||||
}
|
||||
|
||||
// find this zone's layer, if it exists
|
||||
iterator layer = end();
|
||||
auto it = _map.find(zoneLayer.id);
|
||||
|
@ -1227,41 +1039,9 @@ void EntityTreeRenderer::LayeredZones::update(std::shared_ptr<ZoneEntityItem> zo
|
|||
std::tie(layer, std::ignore) = insert(zoneLayer);
|
||||
_map.emplace(layer->id, layer);
|
||||
}
|
||||
|
||||
if (shouldUpdate) {
|
||||
applyPartial(layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::LayeredZones::applyPartial(iterator layer) {
|
||||
bool hasSkybox = false;
|
||||
_skyboxLayer = end();
|
||||
|
||||
if (layer == end()) {
|
||||
if (empty()) {
|
||||
_entityTreeRenderer->applyZoneAndHasSkybox(nullptr);
|
||||
return;
|
||||
} else { // a layer was removed - reapply from beginning
|
||||
layer = begin();
|
||||
}
|
||||
}
|
||||
|
||||
if (layer == begin()) {
|
||||
hasSkybox = _entityTreeRenderer->applyZoneAndHasSkybox(layer->zone);
|
||||
} else {
|
||||
hasSkybox = _entityTreeRenderer->layerZoneAndHasSkybox(layer->zone);
|
||||
}
|
||||
|
||||
if (layer != end()) {
|
||||
while (!hasSkybox && ++layer != end()) {
|
||||
hasSkybox = _entityTreeRenderer->layerZoneAndHasSkybox(layer->zone);
|
||||
}
|
||||
}
|
||||
|
||||
_skyboxLayer = layer;
|
||||
}
|
||||
|
||||
bool EntityTreeRenderer::LayeredZones::contains(const LayeredZones& other) {
|
||||
bool result = std::equal(other.begin(), other._skyboxLayer, begin());
|
||||
if (result) {
|
||||
|
|
|
@ -147,9 +147,6 @@ private:
|
|||
void addEntityToScene(EntityItemPointer entity);
|
||||
bool findBestZoneAndMaybeContainingEntities(QVector<EntityItemID>* entitiesContainingAvatar = nullptr);
|
||||
|
||||
bool applyZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone);
|
||||
bool layerZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone);
|
||||
bool applySkyboxAndHasAmbient();
|
||||
bool applyLayeredZones();
|
||||
|
||||
void checkAndCallPreload(const EntityItemID& entityID, bool reload = false, bool unloadFirst = false);
|
||||
|
|
|
@ -13,14 +13,90 @@
|
|||
|
||||
#include <gpu/Batch.h>
|
||||
|
||||
#include <model/Stage.h>
|
||||
|
||||
#include <AbstractViewStateInterface.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <PerfStat.h>
|
||||
#include <procedural/ProceduralSkybox.h>
|
||||
|
||||
#include "EntityTreeRenderer.h"
|
||||
#include "RenderableEntityItem.h"
|
||||
|
||||
#include <LightPayload.h>
|
||||
#include "DeferredLightingEffect.h"
|
||||
|
||||
|
||||
class RenderableZoneEntityItemMeta {
|
||||
public:
|
||||
RenderableZoneEntityItemMeta(EntityItemPointer entity);
|
||||
~RenderableZoneEntityItemMeta();
|
||||
|
||||
typedef render::Payload<RenderableZoneEntityItemMeta> Payload;
|
||||
typedef Payload::DataPointer Pointer;
|
||||
|
||||
EntityItemPointer entity;
|
||||
|
||||
void render(RenderArgs* args);
|
||||
|
||||
void setVisible(bool visible) { _isVisible = visible; }
|
||||
bool isVisible() const { return _isVisible; }
|
||||
|
||||
render::Item::Bound& editBound() { _needUpdate = true; return _bound; }
|
||||
|
||||
model::LightPointer editSunLight() { _needSunUpdate = true; return _sunLight; }
|
||||
model::LightPointer editAmbientLight() { _needAmbientUpdate = true; return _ambientLight; }
|
||||
model::SunSkyStagePointer editBackground() { _needBackgroundUpdate = true; return _background; }
|
||||
model::SkyboxPointer editSkybox() { return editBackground()->getSkybox(); }
|
||||
|
||||
void setAmbientURL(const QString& ambientUrl);
|
||||
|
||||
void setSkyboxURL(const QString& skyboxUrl);
|
||||
|
||||
void setBackgroundMode(BackgroundMode mode);
|
||||
void setSkyboxColor(const glm::vec3& color);
|
||||
void setProceduralUserData(QString userData);
|
||||
|
||||
protected:
|
||||
render::Item::Bound _bound;
|
||||
|
||||
model::LightPointer _sunLight;
|
||||
model::LightPointer _ambientLight;
|
||||
model::SunSkyStagePointer _background;
|
||||
BackgroundMode _backgroundMode { BACKGROUND_MODE_INHERIT };
|
||||
|
||||
LightStagePointer _stage;
|
||||
LightStage::Index _sunIndex { LightStage::INVALID_INDEX };
|
||||
LightStage::Index _ambientIndex { LightStage::INVALID_INDEX };
|
||||
|
||||
BackgroundStagePointer _backgroundStage;
|
||||
BackgroundStage::Index _backgroundIndex { BackgroundStage::INVALID_INDEX };
|
||||
|
||||
bool _needUpdate { true };
|
||||
bool _needSunUpdate { true };
|
||||
bool _needAmbientUpdate { true };
|
||||
bool _needBackgroundUpdate { true };
|
||||
bool _isVisible { true };
|
||||
|
||||
|
||||
void updateAmbientMap();
|
||||
void updateSkyboxMap();
|
||||
|
||||
// More attributes used for rendering:
|
||||
QString _ambientTextureURL;
|
||||
NetworkTexturePointer _ambientTexture;
|
||||
bool _pendingAmbientTexture { false };
|
||||
bool _validAmbientTexture { false };
|
||||
|
||||
QString _skyboxTextureURL;
|
||||
NetworkTexturePointer _skyboxTexture;
|
||||
bool _pendingSkyboxTexture { false };
|
||||
bool _validSkyboxTexture { false };
|
||||
|
||||
QString _proceduralUserData;
|
||||
};
|
||||
|
||||
// Sphere entities should fit inside a cube entity of the same size, so a sphere that has dimensions 1x1x1
|
||||
// is a half unit sphere. However, the geometry cache renders a UNIT sphere, so we need to scale down.
|
||||
static const float SPHERE_ENTITY_SCALE = 0.5f;
|
||||
|
@ -67,8 +143,15 @@ bool RenderableZoneEntityItem::setProperties(const EntityItemProperties& propert
|
|||
|
||||
void RenderableZoneEntityItem::somethingChangedNotification() {
|
||||
DependencyManager::get<EntityTreeRenderer>()->updateZone(_id);
|
||||
|
||||
// If graphics elements are changed, we need to update the render items
|
||||
notifyChangedRenderItem();
|
||||
|
||||
// Poopagate back to parent
|
||||
ZoneEntityItem::somethingChangedNotification();
|
||||
}
|
||||
|
||||
|
||||
int RenderableZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||
ReadBitstreamToTreeParams& args,
|
||||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
|
||||
|
@ -174,18 +257,158 @@ bool RenderableZoneEntityItem::contains(const glm::vec3& point) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
class RenderableZoneEntityItemMeta {
|
||||
public:
|
||||
RenderableZoneEntityItemMeta(EntityItemPointer entity) : entity(entity){ }
|
||||
typedef render::Payload<RenderableZoneEntityItemMeta> Payload;
|
||||
typedef Payload::DataPointer Pointer;
|
||||
bool RenderableZoneEntityItem::addToScene(EntityItemPointer self, const render::ScenePointer& scene,
|
||||
render::Transaction& transaction) {
|
||||
_myMetaItem = scene->allocateID();
|
||||
|
||||
auto renderData = std::make_shared<RenderableZoneEntityItemMeta>(self);
|
||||
auto renderPayload = std::make_shared<RenderableZoneEntityItemMeta::Payload>(renderData);
|
||||
updateKeyZoneItemFromEntity((*renderData));
|
||||
updateKeySunFromEntity((*renderData));
|
||||
updateKeyAmbientFromEntity((*renderData));
|
||||
updateKeyBackgroundFromEntity((*renderData));
|
||||
|
||||
render::Item::Status::Getters statusGetters;
|
||||
makeEntityItemStatusGetters(getThisPointer(), statusGetters);
|
||||
renderPayload->addStatusGetters(statusGetters);
|
||||
|
||||
transaction.resetItem(_myMetaItem, renderPayload);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderableZoneEntityItem::removeFromScene(EntityItemPointer self, const render::ScenePointer& scene,
|
||||
render::Transaction& transaction) {
|
||||
transaction.removeItem(_myMetaItem);
|
||||
render::Item::clearID(_myMetaItem);
|
||||
if (_model) {
|
||||
_model->removeFromScene(scene, transaction);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderableZoneEntityItem::notifyBoundChanged() {
|
||||
notifyChangedRenderItem();
|
||||
}
|
||||
|
||||
void RenderableZoneEntityItem::updateKeySunFromEntity(RenderableZoneEntityItemMeta& keyZonePayload) {
|
||||
auto sunLight = keyZonePayload.editSunLight();
|
||||
sunLight->setType(model::Light::SUN);
|
||||
|
||||
sunLight->setPosition(this->getPosition());
|
||||
sunLight->setOrientation(this->getRotation());
|
||||
|
||||
// Set the keylight
|
||||
sunLight->setColor(ColorUtils::toVec3(this->getKeyLightProperties().getColor()));
|
||||
sunLight->setIntensity(this->getKeyLightProperties().getIntensity());
|
||||
sunLight->setDirection(this->getKeyLightProperties().getDirection());
|
||||
}
|
||||
|
||||
void RenderableZoneEntityItem::updateKeyAmbientFromEntity(RenderableZoneEntityItemMeta& keyZonePayload) {
|
||||
auto ambientLight = keyZonePayload.editAmbientLight();
|
||||
ambientLight->setType(model::Light::AMBIENT);
|
||||
|
||||
ambientLight->setPosition(this->getPosition());
|
||||
ambientLight->setOrientation(this->getRotation());
|
||||
|
||||
|
||||
// Set the keylight
|
||||
ambientLight->setAmbientIntensity(this->getKeyLightProperties().getAmbientIntensity());
|
||||
|
||||
if (this->getKeyLightProperties().getAmbientURL().isEmpty()) {
|
||||
keyZonePayload.setAmbientURL(this->getSkyboxProperties().getURL());
|
||||
} else {
|
||||
keyZonePayload.setAmbientURL(this->getKeyLightProperties().getAmbientURL());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RenderableZoneEntityItem::updateKeyBackgroundFromEntity(RenderableZoneEntityItemMeta& keyZonePayload) {
|
||||
auto background = keyZonePayload.editBackground();
|
||||
|
||||
keyZonePayload.setBackgroundMode(this->getBackgroundMode());
|
||||
keyZonePayload.setSkyboxColor(this->getSkyboxProperties().getColorVec3());
|
||||
keyZonePayload.setProceduralUserData(this->getUserData());
|
||||
keyZonePayload.setSkyboxURL(this->getSkyboxProperties().getURL());
|
||||
}
|
||||
|
||||
|
||||
void RenderableZoneEntityItem::updateKeyZoneItemFromEntity(RenderableZoneEntityItemMeta& keyZonePayload) {
|
||||
|
||||
keyZonePayload.setVisible(this->getVisible());
|
||||
|
||||
bool success;
|
||||
keyZonePayload.editBound() = this->getAABox(success);
|
||||
if (!success) {
|
||||
keyZonePayload.editBound() = render::Item::Bound();
|
||||
}
|
||||
|
||||
/* TODO: Implement the sun model behavior / Keep this code here for reference, this is how we
|
||||
{
|
||||
// Set the stage
|
||||
bool isSunModelEnabled = this->getStageProperties().getSunModelEnabled();
|
||||
sceneStage->setSunModelEnable(isSunModelEnabled);
|
||||
if (isSunModelEnabled) {
|
||||
sceneStage->setLocation(this->getStageProperties().getLongitude(),
|
||||
this->getStageProperties().getLatitude(),
|
||||
this->getStageProperties().getAltitude());
|
||||
|
||||
auto sceneTime = sceneStage->getTime();
|
||||
sceneTime->setHour(this->getStageProperties().calculateHour());
|
||||
sceneTime->setDay(this->getStageProperties().calculateDay());
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
void RenderableZoneEntityItem::sceneUpdateRenderItemFromEntity(render::Transaction& transaction) {
|
||||
if (!render::Item::isValidID(_myMetaItem)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool sunChanged = _keyLightPropertiesChanged;
|
||||
bool backgroundChanged = _backgroundPropertiesChanged;
|
||||
bool stageChanged = _stagePropertiesChanged;
|
||||
bool skyboxChanged = _skyboxPropertiesChanged;
|
||||
|
||||
transaction.updateItem<RenderableZoneEntityItemMeta>(_myMetaItem, [=](RenderableZoneEntityItemMeta& data) {
|
||||
|
||||
updateKeyZoneItemFromEntity(data);
|
||||
|
||||
if (sunChanged) {
|
||||
updateKeySunFromEntity(data);
|
||||
}
|
||||
|
||||
if (sunChanged || skyboxChanged) {
|
||||
updateKeyAmbientFromEntity(data);
|
||||
}
|
||||
if (backgroundChanged || skyboxChanged) {
|
||||
updateKeyBackgroundFromEntity(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void RenderableZoneEntityItem::notifyChangedRenderItem() {
|
||||
if (!render::Item::isValidID(_myMetaItem)) {
|
||||
return;
|
||||
}
|
||||
|
||||
render::Transaction transaction;
|
||||
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||
sceneUpdateRenderItemFromEntity(transaction);
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
EntityItemPointer entity;
|
||||
};
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const RenderableZoneEntityItemMeta::Pointer& payload) {
|
||||
return ItemKey::Builder::opaqueShape();
|
||||
return ItemKey::Builder().withTypeMeta().build();
|
||||
}
|
||||
|
||||
template <> const Item::Bound payloadGetBound(const RenderableZoneEntityItemMeta::Pointer& payload) {
|
||||
|
@ -200,51 +423,199 @@ namespace render {
|
|||
return render::Item::Bound();
|
||||
}
|
||||
template <> void payloadRender(const RenderableZoneEntityItemMeta::Pointer& payload, RenderArgs* args) {
|
||||
if (args) {
|
||||
if (payload && payload->entity) {
|
||||
payload->entity->render(args);
|
||||
payload->render(args);
|
||||
}
|
||||
}
|
||||
|
||||
RenderableZoneEntityItemMeta::RenderableZoneEntityItemMeta(EntityItemPointer entity) :
|
||||
entity(entity),
|
||||
_sunLight(std::make_shared<model::Light>()),
|
||||
_ambientLight(std::make_shared<model::Light>()),
|
||||
_background(std::make_shared<model::SunSkyStage>())
|
||||
{
|
||||
_background->setSkybox(std::make_shared<ProceduralSkybox>());
|
||||
}
|
||||
|
||||
|
||||
RenderableZoneEntityItemMeta::~RenderableZoneEntityItemMeta() {
|
||||
if (_stage) {
|
||||
if (!LightStage::isIndexInvalid(_sunIndex)) {
|
||||
_stage->removeLight(_sunIndex);
|
||||
}
|
||||
if (!LightStage::isIndexInvalid(_ambientIndex)) {
|
||||
_stage->removeLight(_ambientIndex);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (_backgroundStage) {
|
||||
if (!BackgroundStage::isIndexInvalid(_backgroundIndex)) {
|
||||
_backgroundStage->removeBackground(_backgroundIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderableZoneEntityItemMeta::setAmbientURL(const QString& ambientUrl) {
|
||||
// nothing change if nothing change
|
||||
if (_ambientTextureURL == ambientUrl) {
|
||||
return;
|
||||
}
|
||||
_ambientTextureURL = ambientUrl;
|
||||
|
||||
if (_ambientTextureURL.isEmpty()) {
|
||||
_validAmbientTexture = false;
|
||||
_pendingAmbientTexture = false;
|
||||
_ambientTexture.clear();
|
||||
|
||||
_ambientLight->setAmbientMap(nullptr);
|
||||
_ambientLight->setAmbientSpherePreset(gpu::SphericalHarmonics::BREEZEWAY);
|
||||
} else {
|
||||
_pendingAmbientTexture = true;
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
_ambientTexture = textureCache->getTexture(_ambientTextureURL, image::TextureUsage::CUBE_TEXTURE);
|
||||
|
||||
// keep whatever is assigned on the ambient map/sphere until texture is loaded
|
||||
}
|
||||
}
|
||||
|
||||
void RenderableZoneEntityItemMeta::updateAmbientMap() {
|
||||
if (_pendingAmbientTexture) {
|
||||
if (_ambientTexture && _ambientTexture->isLoaded()) {
|
||||
_pendingAmbientTexture = false;
|
||||
|
||||
auto texture = _ambientTexture->getGPUTexture();
|
||||
if (texture) {
|
||||
if (texture->getIrradiance()) {
|
||||
_ambientLight->setAmbientSphere(*texture->getIrradiance());
|
||||
} else {
|
||||
_ambientLight->setAmbientSpherePreset(gpu::SphericalHarmonics::BREEZEWAY);
|
||||
}
|
||||
editAmbientLight()->setAmbientMap(texture);
|
||||
_validAmbientTexture = true;
|
||||
} else {
|
||||
qCDebug(entitiesrenderer) << "Failed to load ambient texture:" << _ambientTexture->getURL();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderableZoneEntityItem::addToScene(EntityItemPointer self, const render::ScenePointer& scene,
|
||||
render::Transaction& transaction) {
|
||||
_myMetaItem = scene->allocateID();
|
||||
|
||||
auto renderData = std::make_shared<RenderableZoneEntityItemMeta>(self);
|
||||
auto renderPayload = std::make_shared<RenderableZoneEntityItemMeta::Payload>(renderData);
|
||||
|
||||
render::Item::Status::Getters statusGetters;
|
||||
makeEntityItemStatusGetters(getThisPointer(), statusGetters);
|
||||
renderPayload->addStatusGetters(statusGetters);
|
||||
|
||||
transaction.resetItem(_myMetaItem, renderPayload);
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderableZoneEntityItem::removeFromScene(EntityItemPointer self, const render::ScenePointer& scene,
|
||||
render::Transaction& transaction) {
|
||||
transaction.removeItem(_myMetaItem);
|
||||
render::Item::clearID(_myMetaItem);
|
||||
if (_model) {
|
||||
_model->removeFromScene(scene, transaction);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RenderableZoneEntityItem::notifyBoundChanged() {
|
||||
if (!render::Item::isValidID(_myMetaItem)) {
|
||||
void RenderableZoneEntityItemMeta::setSkyboxURL(const QString& skyboxUrl) {
|
||||
// nothing change if nothing change
|
||||
if (_skyboxTextureURL == skyboxUrl) {
|
||||
return;
|
||||
}
|
||||
render::Transaction transaction;
|
||||
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||
if (scene) {
|
||||
transaction.updateItem<RenderableZoneEntityItemMeta>(_myMetaItem, [](RenderableZoneEntityItemMeta& data) {
|
||||
});
|
||||
_skyboxTextureURL = skyboxUrl;
|
||||
|
||||
scene->enqueueTransaction(transaction);
|
||||
if (_skyboxTextureURL.isEmpty()) {
|
||||
_validSkyboxTexture = false;
|
||||
_pendingSkyboxTexture = false;
|
||||
_skyboxTexture.clear();
|
||||
|
||||
editSkybox()->setCubemap(nullptr);
|
||||
} else {
|
||||
qCWarning(entitiesrenderer) << "RenderableZoneEntityItem::notifyBoundChanged(), Unexpected null scene, possibly during application shutdown";
|
||||
_pendingSkyboxTexture = true;
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
_skyboxTexture = textureCache->getTexture(_skyboxTextureURL, image::TextureUsage::CUBE_TEXTURE);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderableZoneEntityItemMeta::updateSkyboxMap() {
|
||||
if (_pendingSkyboxTexture) {
|
||||
if (_skyboxTexture && _skyboxTexture->isLoaded()) {
|
||||
_pendingSkyboxTexture = false;
|
||||
|
||||
auto texture = _skyboxTexture->getGPUTexture();
|
||||
if (texture) {
|
||||
editSkybox()->setCubemap(texture);
|
||||
_validSkyboxTexture = true;
|
||||
} else {
|
||||
qCDebug(entitiesrenderer) << "Failed to load Skybox texture:" << _skyboxTexture->getURL();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderableZoneEntityItemMeta::setBackgroundMode(BackgroundMode mode) {
|
||||
_backgroundMode = mode;
|
||||
}
|
||||
|
||||
void RenderableZoneEntityItemMeta::setSkyboxColor(const glm::vec3& color) {
|
||||
editSkybox()->setColor(color);
|
||||
}
|
||||
|
||||
void RenderableZoneEntityItemMeta::setProceduralUserData(QString userData) {
|
||||
if (_proceduralUserData != userData) {
|
||||
_proceduralUserData = userData;
|
||||
std::dynamic_pointer_cast<ProceduralSkybox>(editSkybox())->parse(_proceduralUserData);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RenderableZoneEntityItemMeta::render(RenderArgs* args) {
|
||||
if (!_stage) {
|
||||
_stage = DependencyManager::get<DeferredLightingEffect>()->getLightStage();
|
||||
}
|
||||
|
||||
if (!_backgroundStage) {
|
||||
_backgroundStage = DependencyManager::get<DeferredLightingEffect>()->getBackgroundStage();
|
||||
}
|
||||
|
||||
{ // Sun
|
||||
// Need an update ?
|
||||
if (_needSunUpdate) {
|
||||
// Do we need to allocate the light in the stage ?
|
||||
if (LightStage::isIndexInvalid(_sunIndex)) {
|
||||
_sunIndex = _stage->addLight(_sunLight);
|
||||
} else {
|
||||
_stage->updateLightArrayBuffer(_sunIndex);
|
||||
}
|
||||
_needSunUpdate = false;
|
||||
}
|
||||
}
|
||||
|
||||
{ // Ambient
|
||||
updateAmbientMap();
|
||||
|
||||
// Need an update ?
|
||||
if (_needAmbientUpdate) {
|
||||
// Do we need to allocate the light in the stage ?
|
||||
if (LightStage::isIndexInvalid(_ambientIndex)) {
|
||||
_ambientIndex = _stage->addLight(_ambientLight);
|
||||
} else {
|
||||
_stage->updateLightArrayBuffer(_ambientIndex);
|
||||
}
|
||||
_needAmbientUpdate = false;
|
||||
}
|
||||
}
|
||||
|
||||
{ // Skybox
|
||||
updateSkyboxMap();
|
||||
|
||||
if (_needBackgroundUpdate) {
|
||||
if (BackgroundStage::isIndexInvalid(_backgroundIndex)) {
|
||||
_backgroundIndex = _backgroundStage->addBackground(_background);
|
||||
} else {
|
||||
|
||||
}
|
||||
_needBackgroundUpdate = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isVisible()) {
|
||||
// FInally, push the light visible in the frame
|
||||
// THe directional key light for sure
|
||||
_stage->_currentFrame.pushSunLight(_sunIndex);
|
||||
|
||||
// The ambient light only if it has a valid texture to render with
|
||||
if (_validAmbientTexture || _validSkyboxTexture) {
|
||||
_stage->_currentFrame.pushAmbientLight(_ambientIndex);
|
||||
}
|
||||
|
||||
// The background only if the mode is not inherit
|
||||
if (_backgroundMode != BACKGROUND_MODE_INHERIT) {
|
||||
_backgroundStage->_currentFrame.pushBackground(_backgroundIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
#include <ZoneEntityItem.h>
|
||||
|
||||
class NetworkGeometry;
|
||||
class KeyLightPayload;
|
||||
|
||||
class RenderableZoneEntityItemMeta;
|
||||
|
||||
class RenderableZoneEntityItem : public ZoneEntityItem {
|
||||
public:
|
||||
|
@ -42,7 +45,7 @@ public:
|
|||
virtual void removeFromScene(EntityItemPointer self, const render::ScenePointer& scene, render::Transaction& transaction) override;
|
||||
|
||||
render::ItemID getRenderItemID() const { return _myMetaItem; }
|
||||
|
||||
|
||||
private:
|
||||
virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); notifyBoundChanged(); }
|
||||
virtual void dimensionsChanged() override { EntityItem::dimensionsChanged(); notifyBoundChanged(); }
|
||||
|
@ -52,10 +55,18 @@ private:
|
|||
|
||||
template<typename Lambda>
|
||||
void changeProperties(Lambda functor);
|
||||
|
||||
|
||||
void notifyChangedRenderItem();
|
||||
void sceneUpdateRenderItemFromEntity(render::Transaction& transaction);
|
||||
void updateKeyZoneItemFromEntity(RenderableZoneEntityItemMeta& keyZonePayload);
|
||||
|
||||
void updateKeySunFromEntity(RenderableZoneEntityItemMeta& keyZonePayload);
|
||||
void updateKeyAmbientFromEntity(RenderableZoneEntityItemMeta& keyZonePayload);
|
||||
void updateKeyBackgroundFromEntity(RenderableZoneEntityItemMeta& keyZonePayload);
|
||||
|
||||
ModelPointer _model;
|
||||
bool _needsInitialSimulation;
|
||||
|
||||
|
||||
render::ItemID _myMetaItem{ render::Item::INVALID_ITEM_ID };
|
||||
};
|
||||
|
||||
|
|
|
@ -71,22 +71,6 @@ bool ZoneEntityItem::setProperties(const EntityItemProperties& properties) {
|
|||
bool somethingChanged = false;
|
||||
somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class
|
||||
|
||||
bool somethingChangedInKeyLight = _keyLightProperties.setProperties(properties);
|
||||
|
||||
bool somethingChangedInStage = _stageProperties.setProperties(properties);
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, setShapeType);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(backgroundMode, setBackgroundMode);
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(flyingAllowed, setFlyingAllowed);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(ghostingAllowed, setGhostingAllowed);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(filterURL, setFilterURL);
|
||||
|
||||
bool somethingChangedInSkybox = _skyboxProperties.setProperties(properties);
|
||||
|
||||
somethingChanged = somethingChanged || somethingChangedInKeyLight || somethingChangedInStage || somethingChangedInSkybox;
|
||||
|
||||
if (somethingChanged) {
|
||||
bool wantDebug = false;
|
||||
if (wantDebug) {
|
||||
|
@ -101,6 +85,30 @@ bool ZoneEntityItem::setProperties(const EntityItemProperties& properties) {
|
|||
return somethingChanged;
|
||||
}
|
||||
|
||||
bool ZoneEntityItem::setSubClassProperties(const EntityItemProperties& properties) {
|
||||
bool somethingChanged = EntityItem::setSubClassProperties(properties); // set the properties in our base class
|
||||
|
||||
|
||||
_keyLightPropertiesChanged = _keyLightProperties.setProperties(properties);
|
||||
|
||||
_stagePropertiesChanged = _stageProperties.setProperties(properties);
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, setShapeType);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(backgroundMode, setBackgroundMode);
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(flyingAllowed, setFlyingAllowed);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(ghostingAllowed, setGhostingAllowed);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(filterURL, setFilterURL);
|
||||
|
||||
_skyboxPropertiesChanged = _skyboxProperties.setProperties(properties);
|
||||
|
||||
somethingChanged = somethingChanged || _keyLightPropertiesChanged || _stagePropertiesChanged || _skyboxPropertiesChanged;
|
||||
|
||||
|
||||
return somethingChanged;
|
||||
}
|
||||
|
||||
int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||
ReadBitstreamToTreeParams& args,
|
||||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
|
||||
|
@ -109,14 +117,14 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
|
|||
const unsigned char* dataAt = data;
|
||||
|
||||
int bytesFromKeylight = _keyLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
|
||||
propertyFlags, overwriteLocalData, somethingChanged);
|
||||
|
||||
propertyFlags, overwriteLocalData, _keyLightPropertiesChanged);
|
||||
somethingChanged = somethingChanged || _keyLightPropertiesChanged;
|
||||
bytesRead += bytesFromKeylight;
|
||||
dataAt += bytesFromKeylight;
|
||||
|
||||
int bytesFromStage = _stageProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
|
||||
propertyFlags, overwriteLocalData, somethingChanged);
|
||||
|
||||
propertyFlags, overwriteLocalData, _stagePropertiesChanged);
|
||||
somethingChanged = somethingChanged || _stagePropertiesChanged;
|
||||
bytesRead += bytesFromStage;
|
||||
dataAt += bytesFromStage;
|
||||
|
||||
|
@ -125,7 +133,8 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
|
|||
READ_ENTITY_PROPERTY(PROP_BACKGROUND_MODE, BackgroundMode, setBackgroundMode);
|
||||
|
||||
int bytesFromSkybox = _skyboxProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
|
||||
propertyFlags, overwriteLocalData, somethingChanged);
|
||||
propertyFlags, overwriteLocalData, _skyboxPropertiesChanged);
|
||||
somethingChanged = somethingChanged || _skyboxPropertiesChanged;
|
||||
bytesRead += bytesFromSkybox;
|
||||
dataAt += bytesFromSkybox;
|
||||
|
||||
|
@ -185,6 +194,16 @@ void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
|
|||
APPEND_ENTITY_PROPERTY(PROP_FILTER_URL, getFilterURL());
|
||||
}
|
||||
|
||||
void ZoneEntityItem::somethingChangedNotification() {
|
||||
EntityItem::somethingChangedNotification();
|
||||
withWriteLock([&] {
|
||||
_keyLightPropertiesChanged = false;
|
||||
_backgroundPropertiesChanged = false;
|
||||
_stagePropertiesChanged = false;
|
||||
_skyboxPropertiesChanged = false;
|
||||
});
|
||||
}
|
||||
|
||||
void ZoneEntityItem::debugDump() const {
|
||||
quint64 now = usecTimestampNow();
|
||||
qCDebug(entities) << " ZoneEntityItem id:" << getEntityItemID() << "---------------------------------------------";
|
||||
|
|
|
@ -29,10 +29,16 @@ public:
|
|||
// methods for getting/setting all properties of an entity
|
||||
virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override;
|
||||
virtual bool setProperties(const EntityItemProperties& properties) override;
|
||||
virtual bool setSubClassProperties(const EntityItemProperties& properties) override;
|
||||
|
||||
// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time
|
||||
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override;
|
||||
|
||||
/// Override this in your derived class if you'd like to be informed when something about the state of the entity
|
||||
/// has changed. This will be called with properties change or when new data is loaded from a stream
|
||||
/// Overriding this function to capture the information that a keylight / Ambient / skybox properties has changed
|
||||
virtual void somethingChangedNotification() override;
|
||||
|
||||
virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
|
||||
EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData,
|
||||
EntityPropertyFlags& requestedProperties,
|
||||
|
@ -64,7 +70,7 @@ public:
|
|||
|
||||
const KeyLightPropertyGroup& getKeyLightProperties() const { return _keyLightProperties; }
|
||||
|
||||
void setBackgroundMode(BackgroundMode value) { _backgroundMode = value; }
|
||||
void setBackgroundMode(BackgroundMode value) { _backgroundMode = value; _backgroundPropertiesChanged = true; }
|
||||
BackgroundMode getBackgroundMode() const { return _backgroundMode; }
|
||||
|
||||
const SkyboxPropertyGroup& getSkyboxProperties() const { return _skyboxProperties; }
|
||||
|
@ -106,6 +112,14 @@ protected:
|
|||
bool _ghostingAllowed { DEFAULT_GHOSTING_ALLOWED };
|
||||
QString _filterURL { DEFAULT_FILTER_URL };
|
||||
|
||||
// Dirty flags turn true when either keylight properties is changing values.
|
||||
// This gets back to false in the somethingChangedNotification() call
|
||||
// Which is called after a setProperties() or a readEntitySubClassFromBUfferCall on the entity.
|
||||
bool _keyLightPropertiesChanged { false };
|
||||
bool _backgroundPropertiesChanged { false };
|
||||
bool _skyboxPropertiesChanged { false };
|
||||
bool _stagePropertiesChanged { false };
|
||||
|
||||
static bool _drawZoneBoundaries;
|
||||
static bool _zonesArePickable;
|
||||
};
|
||||
|
|
|
@ -493,10 +493,6 @@ gpu::TexturePointer TextureUsage::process2DTextureColorFromImage(const QImage& s
|
|||
|
||||
if (validAlpha) {
|
||||
processTextureAlpha(image, validAlpha, alphaAsMask);
|
||||
|
||||
// NOTE: This disables BC1a compression because it was producing odd artifacts on text textures
|
||||
// for the tutorial. Instead we use BC3 (which is larger) but doesn't produce the same artifacts).
|
||||
alphaAsMask = false;
|
||||
}
|
||||
|
||||
gpu::TexturePointer theTexture = nullptr;
|
||||
|
@ -506,7 +502,9 @@ gpu::TexturePointer TextureUsage::process2DTextureColorFromImage(const QImage& s
|
|||
gpu::Element formatGPU;
|
||||
if (isColorTexturesCompressionEnabled()) {
|
||||
if (validAlpha) {
|
||||
formatGPU = alphaAsMask ? gpu::Element::COLOR_COMPRESSED_SRGBA_MASK : gpu::Element::COLOR_COMPRESSED_SRGBA;
|
||||
// NOTE: This disables BC1a compression because it was producing odd artifacts on text textures
|
||||
// for the tutorial. Instead we use BC3 (which is larger) but doesn't produce the same artifacts).
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_SRGBA;
|
||||
} else {
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_SRGB;
|
||||
}
|
||||
|
|
|
@ -212,10 +212,11 @@ namespace khronos {
|
|||
template <uint32_t ALIGNMENT>
|
||||
inline uint32_t evalAlignedCompressedBlockCount(uint32_t value) {
|
||||
// FIXME add static assert that ALIGNMENT is a power of 2
|
||||
return (value + (ALIGNMENT - 1) / ALIGNMENT);
|
||||
static uint32_t ALIGNMENT_REMAINDER = ALIGNMENT - 1;
|
||||
return (value + ALIGNMENT_REMAINDER) / ALIGNMENT;
|
||||
}
|
||||
|
||||
inline uint8_t evalBlockAlignemnt(InternalFormat format, uint32_t value) {
|
||||
inline uint32_t evalCompressedBlockCount(InternalFormat format, uint32_t value) {
|
||||
switch (format) {
|
||||
case InternalFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT: // BC1
|
||||
case InternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: // BC1A
|
||||
|
|
|
@ -30,7 +30,7 @@ uint32_t Header::evalMaxDimension() const {
|
|||
|
||||
uint32_t Header::evalPixelOrBlockDimension(uint32_t pixelDimension) const {
|
||||
if (isCompressed()) {
|
||||
return khronos::gl::texture::evalBlockAlignemnt(getGLInternaFormat(), pixelDimension);
|
||||
return khronos::gl::texture::evalCompressedBlockCount(getGLInternaFormat(), pixelDimension);
|
||||
}
|
||||
return pixelDimension;
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ void Light::setAmbientSpherePreset(gpu::SphericalHarmonics::Preset preset) {
|
|||
_ambientSchemaBuffer.edit().ambientSphere.assignPreset(preset);
|
||||
}
|
||||
|
||||
void Light::setAmbientMap(gpu::TexturePointer ambientMap) {
|
||||
void Light::setAmbientMap(const gpu::TexturePointer& ambientMap) {
|
||||
_ambientMap = ambientMap;
|
||||
if (ambientMap) {
|
||||
setAmbientMapNumMips(_ambientMap->getNumMips());
|
||||
|
|
|
@ -68,7 +68,8 @@ public:
|
|||
|
||||
|
||||
enum Type {
|
||||
SUN = 0,
|
||||
AMBIENT = 0,
|
||||
SUN,
|
||||
POINT,
|
||||
SPOT,
|
||||
|
||||
|
@ -112,7 +113,6 @@ public:
|
|||
void setIntensity(float intensity);
|
||||
|
||||
bool isRanged() const { return (getType() == POINT) || (getType() == SPOT); }
|
||||
bool hasAmbient() const { return (getType() == SUN); }
|
||||
|
||||
// FalloffRradius is the physical radius of the light sphere through which energy shines,
|
||||
// expressed in meters. It is used only to calculate the falloff curve of the light.
|
||||
|
@ -143,7 +143,7 @@ public:
|
|||
const gpu::SphericalHarmonics& getAmbientSphere() const { return _ambientSchemaBuffer->ambientSphere; }
|
||||
void setAmbientSpherePreset(gpu::SphericalHarmonics::Preset preset);
|
||||
|
||||
void setAmbientMap(gpu::TexturePointer ambientMap);
|
||||
void setAmbientMap(const gpu::TexturePointer& ambientMap);
|
||||
gpu::TexturePointer getAmbientMap() const { return _ambientMap; }
|
||||
|
||||
void setAmbientMapNumMips(uint16_t numMips);
|
||||
|
|
|
@ -25,6 +25,8 @@ typedef glm::vec3 Color;
|
|||
|
||||
class Skybox {
|
||||
public:
|
||||
typedef gpu::BufferView UniformBufferView;
|
||||
|
||||
Skybox();
|
||||
Skybox& operator= (const Skybox& skybox);
|
||||
virtual ~Skybox() {};
|
||||
|
@ -43,6 +45,8 @@ public:
|
|||
|
||||
static void render(gpu::Batch& batch, const ViewFrustum& frustum, const Skybox& skybox);
|
||||
|
||||
const UniformBufferView& getSchemaBuffer() const { return _schemaBuffer; }
|
||||
|
||||
protected:
|
||||
static const int SKYBOX_SKYMAP_SLOT { 0 };
|
||||
static const int SKYBOX_CONSTANTS_SLOT { 0 };
|
||||
|
|
|
@ -241,6 +241,9 @@ void SendQueue::handshakeACK(SequenceNumber initialSequenceNumber) {
|
|||
std::lock_guard<std::mutex> locker { _handshakeMutex };
|
||||
_hasReceivedHandshakeACK = true;
|
||||
}
|
||||
|
||||
_lastReceiverResponse = QDateTime::currentMSecsSinceEpoch();
|
||||
|
||||
// Notify on the handshake ACK condition
|
||||
_handshakeACKCondition.notify_one();
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ AUTOSCRIBE_SHADER_LIB(gpu model render)
|
|||
# pull in the resources.qrc file
|
||||
qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc")
|
||||
setup_hifi_library(Widgets OpenGL Network Qml Quick Script)
|
||||
link_hifi_libraries(shared ktx gpu model model-networking render animation fbx entities image)
|
||||
link_hifi_libraries(shared ktx gpu model model-networking render animation fbx entities image procedural)
|
||||
|
||||
if (NOT ANDROID)
|
||||
target_nsight()
|
||||
|
|
141
libraries/render-utils/src/BackgroundStage.cpp
Normal file
141
libraries/render-utils/src/BackgroundStage.cpp
Normal file
|
@ -0,0 +1,141 @@
|
|||
//
|
||||
// BackgroundStage.cpp
|
||||
//
|
||||
// Created by Sam Gateau on 5/9/2017.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "BackgroundStage.h"
|
||||
|
||||
#include "DeferredLightingEffect.h"
|
||||
|
||||
#include <gpu/Context.h>
|
||||
|
||||
BackgroundStage::Index BackgroundStage::findBackground(const BackgroundPointer& background) const {
|
||||
auto found = _backgroundMap.find(background);
|
||||
if (found != _backgroundMap.end()) {
|
||||
return INVALID_INDEX;
|
||||
} else {
|
||||
return (*found).second;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BackgroundStage::Index BackgroundStage::addBackground(const BackgroundPointer& background) {
|
||||
|
||||
auto found = _backgroundMap.find(background);
|
||||
if (found == _backgroundMap.end()) {
|
||||
auto backgroundId = _backgrounds.newElement(background);
|
||||
// Avoid failing to allocate a background, just pass
|
||||
if (backgroundId != INVALID_INDEX) {
|
||||
|
||||
// Insert the background and its index in the reverse map
|
||||
_backgroundMap.insert(BackgroundMap::value_type(background, backgroundId));
|
||||
}
|
||||
return backgroundId;
|
||||
} else {
|
||||
return (*found).second;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BackgroundStage::BackgroundPointer BackgroundStage::removeBackground(Index index) {
|
||||
BackgroundPointer removed = _backgrounds.freeElement(index);
|
||||
|
||||
if (removed) {
|
||||
_backgroundMap.erase(removed);
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
|
||||
void DrawBackgroundStage::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) {
|
||||
|
||||
const auto& lightingModel = inputs;
|
||||
if (!lightingModel->isBackgroundEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Background rendering decision
|
||||
auto backgroundStage = DependencyManager::get<DeferredLightingEffect>()->getBackgroundStage();
|
||||
model::SunSkyStagePointer background;
|
||||
model::SkyboxPointer skybox;
|
||||
if (backgroundStage->_currentFrame._backgrounds.size()) {
|
||||
auto backgroundId = backgroundStage->_currentFrame._backgrounds.front();
|
||||
auto background = backgroundStage->getBackground(backgroundId);
|
||||
if (background) {
|
||||
skybox = background->getSkybox();
|
||||
}
|
||||
} else {
|
||||
skybox = DependencyManager::get<DeferredLightingEffect>()->getDefaultSkybox();
|
||||
}
|
||||
|
||||
/* auto backgroundMode = skyStage->getBackgroundMode();
|
||||
|
||||
switch (backgroundMode) {
|
||||
case model::SunSkyStage::SKY_DEFAULT: {
|
||||
auto scene = DependencyManager::get<SceneScriptingInterface>()->getStage();
|
||||
auto sceneKeyLight = scene->getKeyLight();
|
||||
|
||||
scene->setSunModelEnable(false);
|
||||
sceneKeyLight->setColor(ColorUtils::toVec3(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_COLOR));
|
||||
sceneKeyLight->setIntensity(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_INTENSITY);
|
||||
sceneKeyLight->setAmbientIntensity(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_AMBIENT_INTENSITY);
|
||||
sceneKeyLight->setDirection(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_DIRECTION);
|
||||
// fall through: render a skybox (if available), or the defaults (if requested)
|
||||
}
|
||||
|
||||
case model::SunSkyStage::SKY_BOX: {*/
|
||||
if (skybox && !skybox->empty()) {
|
||||
PerformanceTimer perfTimer("skybox");
|
||||
auto args = renderContext->args;
|
||||
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
args->_batch = &batch;
|
||||
|
||||
batch.enableSkybox(true);
|
||||
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
batch.setStateScissorRect(args->_viewport);
|
||||
|
||||
glm::mat4 projMat;
|
||||
Transform viewMat;
|
||||
args->getViewFrustum().evalProjectionMatrix(projMat);
|
||||
args->getViewFrustum().evalViewTransform(viewMat);
|
||||
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewMat);
|
||||
|
||||
skybox->render(batch, args->getViewFrustum());
|
||||
});
|
||||
args->_batch = nullptr;
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
|
||||
// break;
|
||||
}
|
||||
// fall through: render defaults (if requested)
|
||||
// }
|
||||
/*
|
||||
case model::SunSkyStage::SKY_DEFAULT_AMBIENT_TEXTURE: {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::DefaultSkybox)) {
|
||||
auto scene = DependencyManager::get<SceneScriptingInterface>()->getStage();
|
||||
auto sceneKeyLight = scene->getKeyLight();
|
||||
auto defaultSkyboxAmbientTexture = qApp->getDefaultSkyboxAmbientTexture();
|
||||
if (defaultSkyboxAmbientTexture) {
|
||||
sceneKeyLight->setAmbientSphere(defaultSkyboxAmbientTexture->getIrradiance());
|
||||
sceneKeyLight->setAmbientMap(defaultSkyboxAmbientTexture);
|
||||
} else {
|
||||
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(
|
||||
"Failed to get a valid Default Skybox Ambient Texture ? probably because it couldn't be find during initialization step");
|
||||
}
|
||||
// fall through: render defaults skybox
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
80
libraries/render-utils/src/BackgroundStage.h
Normal file
80
libraries/render-utils/src/BackgroundStage.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
//
|
||||
// BackgroundStage.h
|
||||
|
||||
// Created by Sam Gateau on 5/9/2017.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_render_utils_BackgroundStage_h
|
||||
#define hifi_render_utils_BackgroundStage_h
|
||||
|
||||
#include <model/Stage.h>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <render/IndexedContainer.h>
|
||||
|
||||
#include "LightingModel.h"
|
||||
|
||||
|
||||
// Background stage to set up background-related rendering tasks
|
||||
class BackgroundStage {
|
||||
public:
|
||||
using Index = render::indexed_container::Index;
|
||||
static const Index INVALID_INDEX { render::indexed_container::INVALID_INDEX };
|
||||
static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; }
|
||||
|
||||
using BackgroundPointer = model::SunSkyStagePointer;
|
||||
using Backgrounds = render::indexed_container::IndexedPointerVector<model::SunSkyStage>;
|
||||
using BackgroundMap = std::unordered_map<BackgroundPointer, Index>;
|
||||
|
||||
using BackgroundIndices = std::vector<Index>;
|
||||
|
||||
|
||||
Index findBackground(const BackgroundPointer& background) const;
|
||||
Index addBackground(const BackgroundPointer& background);
|
||||
|
||||
BackgroundPointer removeBackground(Index index);
|
||||
|
||||
bool checkBackgroundId(Index index) const { return _backgrounds.checkIndex(index); }
|
||||
|
||||
Index getNumBackgrounds() const { return _backgrounds.getNumElements(); }
|
||||
Index getNumFreeBackgrounds() const { return _backgrounds.getNumFreeIndices(); }
|
||||
Index getNumAllocatedBackgrounds() const { return _backgrounds.getNumAllocatedIndices(); }
|
||||
|
||||
BackgroundPointer getBackground(Index backgroundId) const {
|
||||
return _backgrounds.get(backgroundId);
|
||||
}
|
||||
|
||||
Backgrounds _backgrounds;
|
||||
BackgroundMap _backgroundMap;
|
||||
|
||||
class Frame {
|
||||
public:
|
||||
Frame() {}
|
||||
|
||||
void clear() { _backgrounds.clear(); }
|
||||
|
||||
void pushBackground(BackgroundStage::Index index) { _backgrounds.emplace_back(index); }
|
||||
|
||||
BackgroundStage::BackgroundIndices _backgrounds;
|
||||
};
|
||||
|
||||
Frame _currentFrame;
|
||||
};
|
||||
using BackgroundStagePointer = std::shared_ptr<BackgroundStage>;
|
||||
|
||||
|
||||
class DrawBackgroundStage {
|
||||
public:
|
||||
using Inputs = LightingModelPointer;
|
||||
using JobModel = render::Job::ModelI<DrawBackgroundStage, Inputs>;
|
||||
|
||||
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs);
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
#endif
|
|
@ -141,79 +141,69 @@ void DeferredLightingEffect::init() {
|
|||
_globalLights.push_back(_lightStage->addLight(lp));
|
||||
_lightStage->addShadow(_globalLights[0]);
|
||||
|
||||
}
|
||||
|
||||
void DeferredLightingEffect::addLight(const model::LightPointer& light) {
|
||||
assert(light);
|
||||
auto lightID = _lightStage->addLight(light);
|
||||
if (light->getType() == model::Light::POINT) {
|
||||
_pointLights.push_back(lightID);
|
||||
} else {
|
||||
_spotLights.push_back(lightID);
|
||||
_backgroundStage = std::make_shared<BackgroundStage>();
|
||||
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
|
||||
{
|
||||
PROFILE_RANGE(render, "Process Default Skybox");
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
|
||||
auto skyboxUrl = PathUtils::resourcesPath().toStdString() + "images/Default-Sky-9-cubemap.ktx";
|
||||
|
||||
_defaultSkyboxTexture = gpu::Texture::unserialize(skyboxUrl);
|
||||
_defaultSkyboxAmbientTexture = _defaultSkyboxTexture;
|
||||
|
||||
_defaultSkybox->setCubemap(_defaultSkyboxTexture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DeferredLightingEffect::addPointLight(const glm::vec3& position, float radius, const glm::vec3& color,
|
||||
float intensity, float falloffRadius) {
|
||||
addSpotLight(position, radius, color, intensity, falloffRadius);
|
||||
}
|
||||
|
||||
void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color,
|
||||
float intensity, float falloffRadius, const glm::quat& orientation, float exponent, float cutoff) {
|
||||
|
||||
unsigned int lightID = (unsigned int)(_pointLights.size() + _spotLights.size() + _globalLights.size());
|
||||
if (lightID >= _allocatedLights.size()) {
|
||||
_allocatedLights.push_back(std::make_shared<model::Light>());
|
||||
}
|
||||
model::LightPointer lp = _allocatedLights[lightID];
|
||||
|
||||
lp->setPosition(position);
|
||||
lp->setMaximumRadius(radius);
|
||||
lp->setColor(color);
|
||||
lp->setIntensity(intensity);
|
||||
lp->setFalloffRadius(falloffRadius);
|
||||
|
||||
if (exponent == 0.0f && cutoff == PI) {
|
||||
lp->setType(model::Light::POINT);
|
||||
_pointLights.push_back(lightID);
|
||||
|
||||
} else {
|
||||
lp->setOrientation(orientation);
|
||||
lp->setSpotAngle(cutoff);
|
||||
lp->setSpotExponent(exponent);
|
||||
lp->setType(model::Light::SPOT);
|
||||
_spotLights.push_back(lightID);
|
||||
}
|
||||
lp->setAmbientIntensity(0.5f);
|
||||
lp->setAmbientMap(_defaultSkyboxAmbientTexture);
|
||||
auto irradianceSH = _defaultSkyboxAmbientTexture->getIrradiance();
|
||||
if (irradianceSH) {
|
||||
lp->setAmbientSphere((*irradianceSH));
|
||||
}
|
||||
}
|
||||
|
||||
void DeferredLightingEffect::setupKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit) {
|
||||
PerformanceTimer perfTimer("DLE->setupBatch()");
|
||||
auto keyLight = _allocatedLights[_globalLights.front()];
|
||||
model::LightPointer keySunLight;
|
||||
if (_lightStage && _lightStage->_currentFrame._sunLights.size()) {
|
||||
keySunLight = _lightStage->getLight(_lightStage->_currentFrame._sunLights.front());
|
||||
} else {
|
||||
keySunLight = _allocatedLights[_globalLights.front()];
|
||||
}
|
||||
|
||||
model::LightPointer keyAmbiLight;
|
||||
if (_lightStage && _lightStage->_currentFrame._ambientLights.size()) {
|
||||
keyAmbiLight = _lightStage->getLight(_lightStage->_currentFrame._ambientLights.front());
|
||||
} else {
|
||||
keyAmbiLight = _allocatedLights[_globalLights.front()];
|
||||
}
|
||||
|
||||
if (lightBufferUnit >= 0) {
|
||||
batch.setUniformBuffer(lightBufferUnit, keyLight->getLightSchemaBuffer());
|
||||
batch.setUniformBuffer(lightBufferUnit, keySunLight->getLightSchemaBuffer());
|
||||
}
|
||||
if (keyLight->hasAmbient() && (ambientBufferUnit >= 0)) {
|
||||
batch.setUniformBuffer(ambientBufferUnit, keyLight->getAmbientSchemaBuffer());
|
||||
if (ambientBufferUnit >= 0) {
|
||||
batch.setUniformBuffer(ambientBufferUnit, keyAmbiLight->getAmbientSchemaBuffer());
|
||||
}
|
||||
|
||||
if (keyLight->getAmbientMap() && (skyboxCubemapUnit >= 0)) {
|
||||
batch.setResourceTexture(skyboxCubemapUnit, keyLight->getAmbientMap());
|
||||
if (keyAmbiLight->getAmbientMap() && (skyboxCubemapUnit >= 0)) {
|
||||
batch.setResourceTexture(skyboxCubemapUnit, keyAmbiLight->getAmbientMap());
|
||||
}
|
||||
}
|
||||
|
||||
void DeferredLightingEffect::unsetKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit) {
|
||||
auto keyLight = _allocatedLights[_globalLights.front()];
|
||||
|
||||
if (lightBufferUnit >= 0) {
|
||||
batch.setUniformBuffer(lightBufferUnit, nullptr);
|
||||
}
|
||||
if (keyLight->hasAmbient() && (ambientBufferUnit >= 0)) {
|
||||
if ((ambientBufferUnit >= 0)) {
|
||||
batch.setUniformBuffer(ambientBufferUnit, nullptr);
|
||||
}
|
||||
|
||||
if (keyLight->getAmbientMap() && (skyboxCubemapUnit >= 0)) {
|
||||
if ((skyboxCubemapUnit >= 0)) {
|
||||
batch.setResourceTexture(skyboxCubemapUnit, nullptr);
|
||||
}
|
||||
}
|
||||
|
@ -334,15 +324,20 @@ static void loadLightVolumeProgram(const char* vertSource, const char* fragSourc
|
|||
}
|
||||
|
||||
void DeferredLightingEffect::setGlobalLight(const model::LightPointer& light) {
|
||||
auto globalLight = _allocatedLights.front();
|
||||
/* auto globalLight = _allocatedLights.front();
|
||||
globalLight->setDirection(light->getDirection());
|
||||
globalLight->setColor(light->getColor());
|
||||
globalLight->setIntensity(light->getIntensity());
|
||||
globalLight->setAmbientIntensity(light->getAmbientIntensity());
|
||||
globalLight->setAmbientSphere(light->getAmbientSphere());
|
||||
globalLight->setAmbientMap(light->getAmbientMap());
|
||||
globalLight->setAmbientMap(light->getAmbientMap());*/
|
||||
}
|
||||
|
||||
const model::LightPointer& DeferredLightingEffect::getGlobalLight() const {
|
||||
return _allocatedLights.front();
|
||||
}
|
||||
|
||||
|
||||
#include <shared/Shapes.h>
|
||||
|
||||
model::MeshPointer DeferredLightingEffect::getPointLightMesh() {
|
||||
|
@ -772,16 +767,6 @@ void RenderDeferredCleanup::run(const render::RenderContextPointer& renderContex
|
|||
batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, nullptr);
|
||||
|
||||
}
|
||||
|
||||
auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>();
|
||||
|
||||
// End of the Lighting pass
|
||||
if (!deferredLightingEffect->_pointLights.empty()) {
|
||||
deferredLightingEffect->_pointLights.clear();
|
||||
}
|
||||
if (!deferredLightingEffect->_spotLights.empty()) {
|
||||
deferredLightingEffect->_spotLights.clear();
|
||||
}
|
||||
}
|
||||
|
||||
RenderDeferred::RenderDeferred() {
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include "model/Light.h"
|
||||
#include "model/Geometry.h"
|
||||
|
||||
#include <procedural/ProceduralSkybox.h>
|
||||
|
||||
#include <render/CullTask.h>
|
||||
|
||||
#include "DeferredFrameTransform.h"
|
||||
|
@ -28,11 +30,13 @@
|
|||
|
||||
#include "LightStage.h"
|
||||
#include "LightClusters.h"
|
||||
#include "BackgroundStage.h"
|
||||
|
||||
#include "SurfaceGeometryPass.h"
|
||||
#include "SubsurfaceScattering.h"
|
||||
#include "AmbientOcclusionEffect.h"
|
||||
|
||||
|
||||
class RenderArgs;
|
||||
struct LightLocations;
|
||||
using LightLocationsPtr = std::shared_ptr<LightLocations>;
|
||||
|
@ -43,34 +47,30 @@ class DeferredLightingEffect : public Dependency {
|
|||
|
||||
public:
|
||||
void init();
|
||||
|
||||
void addLight(const model::LightPointer& light);
|
||||
|
||||
/// Adds a point light to render for the current frame.
|
||||
void addPointLight(const glm::vec3& position, float radius, const glm::vec3& color = glm::vec3(0.0f, 0.0f, 0.0f),
|
||||
float intensity = 0.5f, float falloffRadius = 0.01f);
|
||||
|
||||
/// Adds a spot light to render for the current frame.
|
||||
void addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color = glm::vec3(1.0f, 1.0f, 1.0f),
|
||||
float intensity = 0.5f, float falloffRadius = 0.01f,
|
||||
const glm::quat& orientation = glm::quat(), float exponent = 0.0f, float cutoff = PI);
|
||||
|
||||
|
||||
void setupKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit);
|
||||
void unsetKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit);
|
||||
|
||||
// update global lighting
|
||||
void setGlobalLight(const model::LightPointer& light);
|
||||
const model::LightPointer& getGlobalLight() const;
|
||||
|
||||
const LightStagePointer getLightStage() { return _lightStage; }
|
||||
const LightStagePointer& getLightStage() { return _lightStage; }
|
||||
const BackgroundStagePointer& getBackgroundStage() { return _backgroundStage; }
|
||||
|
||||
void setShadowMapEnabled(bool enable) { _shadowMapEnabled = enable; };
|
||||
void setAmbientOcclusionEnabled(bool enable) { _ambientOcclusionEnabled = enable; }
|
||||
bool isAmbientOcclusionEnabled() const { return _ambientOcclusionEnabled; }
|
||||
|
||||
model::SkyboxPointer getDefaultSkybox() const { return _defaultSkybox; }
|
||||
gpu::TexturePointer getDefaultSkyboxTexture() const { return _defaultSkyboxTexture; }
|
||||
gpu::TexturePointer getDefaultSkyboxAmbientTexture() const { return _defaultSkyboxAmbientTexture; }
|
||||
|
||||
private:
|
||||
DeferredLightingEffect() = default;
|
||||
|
||||
LightStagePointer _lightStage;
|
||||
BackgroundStagePointer _backgroundStage;
|
||||
|
||||
bool _shadowMapEnabled{ false };
|
||||
bool _ambientOcclusionEnabled{ false };
|
||||
|
@ -113,8 +113,10 @@ private:
|
|||
|
||||
Lights _allocatedLights;
|
||||
std::vector<int> _globalLights;
|
||||
std::vector<int> _pointLights;
|
||||
std::vector<int> _spotLights;
|
||||
|
||||
model::SkyboxPointer _defaultSkybox { new ProceduralSkybox() };
|
||||
gpu::TexturePointer _defaultSkyboxTexture;
|
||||
gpu::TexturePointer _defaultSkyboxAmbientTexture;
|
||||
|
||||
friend class LightClusteringPass;
|
||||
friend class RenderDeferredSetup;
|
||||
|
|
|
@ -81,3 +81,71 @@ void LightPayload::render(RenderArgs* args) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const KeyLightPayload::Pointer& payload) {
|
||||
ItemKey::Builder builder;
|
||||
builder.withTypeLight();
|
||||
if (!payload || !payload->isVisible()) {
|
||||
builder.withInvisible();
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
template <> const Item::Bound payloadGetBound(const KeyLightPayload::Pointer& payload) {
|
||||
if (payload) {
|
||||
return payload->editBound();
|
||||
}
|
||||
return render::Item::Bound();
|
||||
}
|
||||
template <> void payloadRender(const KeyLightPayload::Pointer& payload, RenderArgs* args) {
|
||||
if (args) {
|
||||
if (payload) {
|
||||
payload->render(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KeyLightPayload::KeyLightPayload() :
|
||||
_light(std::make_shared<model::Light>())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
KeyLightPayload::~KeyLightPayload() {
|
||||
if (!LightStage::isIndexInvalid(_index)) {
|
||||
if (_stage) {
|
||||
_stage->removeLight(_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyLightPayload::render(RenderArgs* args) {
|
||||
if (!_stage) {
|
||||
_stage = DependencyManager::get<DeferredLightingEffect>()->getLightStage();
|
||||
}
|
||||
// Do we need to allocate the light in the stage ?
|
||||
if (LightStage::isIndexInvalid(_index)) {
|
||||
_index = _stage->addLight(_light);
|
||||
_needUpdate = false;
|
||||
}
|
||||
// Need an update ?
|
||||
if (_needUpdate) {
|
||||
_stage->updateLightArrayBuffer(_index);
|
||||
_needUpdate = false;
|
||||
}
|
||||
|
||||
if (isVisible()) {
|
||||
// FInally, push the light visible in the frame
|
||||
_stage->_currentFrame.pushLight(_index, _light->getType());
|
||||
|
||||
#ifdef WANT_DEBUG
|
||||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
batch.setModelTransform(getTransformToCenter());
|
||||
DependencyManager::get<GeometryCache>()->renderWireSphere(batch, 0.5f, 15, 15, glm::vec4(color, 1.0f));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <model/Light.h>
|
||||
#include <render/Item.h>
|
||||
#include "LightStage.h"
|
||||
#include "TextureCache.h"
|
||||
|
||||
class LightPayload {
|
||||
public:
|
||||
|
@ -46,4 +47,41 @@ namespace render {
|
|||
template <> void payloadRender(const LightPayload::Pointer& payload, RenderArgs* args);
|
||||
}
|
||||
|
||||
class KeyLightPayload {
|
||||
public:
|
||||
using Payload = render::Payload<KeyLightPayload>;
|
||||
using Pointer = Payload::DataPointer;
|
||||
|
||||
KeyLightPayload();
|
||||
~KeyLightPayload();
|
||||
void render(RenderArgs* args);
|
||||
|
||||
model::LightPointer editLight() { _needUpdate = true; return _light; }
|
||||
render::Item::Bound& editBound() { _needUpdate = true; return _bound; }
|
||||
|
||||
void setVisible(bool visible) { _isVisible = visible; }
|
||||
bool isVisible() const { return _isVisible; }
|
||||
|
||||
|
||||
// More attributes used for rendering:
|
||||
NetworkTexturePointer _ambientTexture;
|
||||
QString _ambientTextureURL;
|
||||
bool _pendingAmbientTexture { false };
|
||||
bool _validAmbientTextureURL { false };
|
||||
|
||||
protected:
|
||||
model::LightPointer _light;
|
||||
render::Item::Bound _bound;
|
||||
LightStagePointer _stage;
|
||||
LightStage::Index _index { LightStage::INVALID_INDEX };
|
||||
bool _needUpdate { true };
|
||||
bool _isVisible { true };
|
||||
};
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const KeyLightPayload::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const KeyLightPayload::Pointer& payload);
|
||||
template <> void payloadRender(const KeyLightPayload::Pointer& payload, RenderArgs* args);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -77,7 +77,6 @@ public:
|
|||
};
|
||||
using Descs = std::vector<Desc>;
|
||||
|
||||
|
||||
Index findLight(const LightPointer& light) const;
|
||||
Index addLight(const LightPointer& light);
|
||||
|
||||
|
@ -118,19 +117,25 @@ public:
|
|||
public:
|
||||
Frame() {}
|
||||
|
||||
void clear() { _pointLights.clear(); _spotLights.clear(); }
|
||||
void clear() { _pointLights.clear(); _spotLights.clear(); _sunLights.clear(); _ambientLights.clear(); }
|
||||
void pushLight(LightStage::Index index, model::Light::Type type) {
|
||||
switch (type) {
|
||||
case model::Light::POINT: { pushPointLight(index); break; }
|
||||
case model::Light::SPOT: { pushSpotLight(index); break; }
|
||||
case model::Light::SUN: { pushSunLight(index); break; }
|
||||
case model::Light::AMBIENT: { pushAmbientLight(index); break; }
|
||||
default: { break; }
|
||||
}
|
||||
}
|
||||
void pushPointLight(LightStage::Index index) { _pointLights.emplace_back(index); }
|
||||
void pushSpotLight(LightStage::Index index) { _spotLights.emplace_back(index); }
|
||||
|
||||
void pushSunLight(LightStage::Index index) { _sunLights.emplace_back(index); }
|
||||
void pushAmbientLight(LightStage::Index index) { _ambientLights.emplace_back(index); }
|
||||
|
||||
LightStage::LightIndices _pointLights;
|
||||
LightStage::LightIndices _spotLights;
|
||||
LightStage::LightIndices _sunLights;
|
||||
LightStage::LightIndices _ambientLights;
|
||||
};
|
||||
|
||||
Frame _currentFrame;
|
||||
|
|
|
@ -75,7 +75,6 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
|||
const auto deferredFrameTransform = task.addJob<GenerateDeferredFrameTransform>("DeferredFrameTransform");
|
||||
const auto lightingModel = task.addJob<MakeLightingModel>("LightingModel");
|
||||
|
||||
|
||||
// GPU jobs: Start preparing the primary, deferred and lighting buffer
|
||||
const auto primaryFramebuffer = task.addJob<PreparePrimaryFramebuffer>("PreparePrimaryBuffer");
|
||||
|
||||
|
@ -124,6 +123,9 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
|||
// Draw Lights just add the lights to the current list of lights to deal with. NOt really gpu job for now.
|
||||
task.addJob<DrawLight>("DrawLight", lights);
|
||||
|
||||
// Filter zones from the general metas bucket
|
||||
const auto zones = task.addJob<ZoneRendererTask>("ZoneRenderer", metas);
|
||||
|
||||
// Light Clustering
|
||||
// Create the cluster grid of lights, cpu job for now
|
||||
const auto lightClusteringPassInputs = LightClusteringPass::Inputs(deferredFrameTransform, lightingModel, linearDepthTarget).hasVarying();
|
||||
|
@ -136,11 +138,9 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
|||
|
||||
task.addJob<RenderDeferred>("RenderDeferred", deferredLightingInputs);
|
||||
|
||||
// Use Stencil and draw background in Lighting buffer to complete filling in the opaque
|
||||
const auto backgroundInputs = DrawBackgroundDeferred::Inputs(background, lightingModel).hasVarying();
|
||||
task.addJob<DrawBackgroundDeferred>("DrawBackgroundDeferred", backgroundInputs);
|
||||
|
||||
|
||||
// Similar to light stage, background stage has been filled by several potential render items and resolved for the frame in this job
|
||||
task.addJob<DrawBackgroundStage>("DrawBackgroundDeferred", lightingModel);
|
||||
|
||||
// Render transparent objects forward in LightingBuffer
|
||||
const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).hasVarying();
|
||||
task.addJob<DrawDeferred>("DrawTransparentDeferred", transparentsInputs, shapePlumber);
|
||||
|
@ -162,7 +162,8 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
|||
task.addJob<DrawBounds>("DrawOpaqueBounds", opaques);
|
||||
task.addJob<DrawBounds>("DrawTransparentBounds", transparents);
|
||||
|
||||
task.addJob<ZoneRendererTask>("ZoneRenderer", opaques);
|
||||
task.addJob<DrawBounds>("DrawLightBounds", lights);
|
||||
task.addJob<DrawBounds>("DrawZones", zones);
|
||||
}
|
||||
|
||||
// Overlays
|
||||
|
@ -202,6 +203,8 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
|||
auto statusIconMap = DependencyManager::get<TextureCache>()->getImageTexture(iconMapPath, image::TextureUsage::STRICT_TEXTURE);
|
||||
task.addJob<DrawStatus>("DrawStatus", opaques, DrawStatus(statusIconMap));
|
||||
}
|
||||
|
||||
task.addJob<DebugZoneLighting>("DrawZoneStack", deferredFrameTransform);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -10,18 +10,199 @@
|
|||
//
|
||||
#include "ZoneRenderer.h"
|
||||
|
||||
|
||||
#include <gpu/Context.h>
|
||||
#include <gpu/StandardShaderLib.h>
|
||||
|
||||
#include <render/FilterTask.h>
|
||||
#include <render/DrawTask.h>
|
||||
|
||||
#include "DeferredLightingEffect.h"
|
||||
|
||||
#include "zone_drawKeyLight_frag.h"
|
||||
#include "zone_drawAmbient_frag.h"
|
||||
#include "zone_drawSkybox_frag.h"
|
||||
|
||||
|
||||
using namespace render;
|
||||
|
||||
class SetupZones {
|
||||
public:
|
||||
using Inputs = render::ItemBounds;
|
||||
using JobModel = render::Job::ModelI<SetupZones, Inputs>;
|
||||
|
||||
SetupZones() {}
|
||||
|
||||
void run(const RenderContextPointer& context, const Inputs& inputs);
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
const Selection::Name ZoneRendererTask::ZONES_SELECTION { "RankedZones" };
|
||||
|
||||
void ZoneRendererTask::build(JobModel& task, const Varying& input, Varying& ouput) {
|
||||
|
||||
// Filter out the sorted list of zones
|
||||
const auto zoneItems = task.addJob<render::SelectSortItems>("FilterZones", input, ZONES_SELECTION.c_str());
|
||||
|
||||
// just draw them...
|
||||
task.addJob<DrawBounds>("DrawZones", zoneItems);
|
||||
// just setup the current zone env
|
||||
task.addJob<SetupZones>("SetupZones", zoneItems);
|
||||
|
||||
ouput = zoneItems;
|
||||
}
|
||||
|
||||
void SetupZones::run(const RenderContextPointer& context, const Inputs& inputs) {
|
||||
|
||||
auto backgroundStage = DependencyManager::get<DeferredLightingEffect>()->getBackgroundStage();
|
||||
backgroundStage->_currentFrame.clear();
|
||||
|
||||
// call render in the correct order first...
|
||||
render::renderItems(context, inputs);
|
||||
|
||||
}
|
||||
|
||||
const gpu::PipelinePointer& DebugZoneLighting::getKeyLightPipeline() {
|
||||
if (!_keyLightPipeline) {
|
||||
auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS();
|
||||
auto ps = gpu::Shader::createPixel(std::string(zone_drawKeyLight_frag));
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), ZONE_DEFERRED_TRANSFORM_BUFFER));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), ZONE_KEYLIGHT_BUFFER));
|
||||
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
|
||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||
_keyLightPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
return _keyLightPipeline;
|
||||
}
|
||||
|
||||
const gpu::PipelinePointer& DebugZoneLighting::getAmbientPipeline() {
|
||||
if (!_ambientPipeline) {
|
||||
auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS();
|
||||
auto ps = gpu::Shader::createPixel(std::string(zone_drawAmbient_frag));
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), ZONE_DEFERRED_TRANSFORM_BUFFER));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("lightAmbientBuffer"), ZONE_AMBIENT_BUFFER));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), ZONE_AMBIENT_MAP));
|
||||
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
|
||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||
_ambientPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
return _ambientPipeline;
|
||||
}
|
||||
const gpu::PipelinePointer& DebugZoneLighting::getBackgroundPipeline() {
|
||||
if (!_backgroundPipeline) {
|
||||
auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS();
|
||||
auto ps = gpu::Shader::createPixel(std::string(zone_drawSkybox_frag));
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), ZONE_DEFERRED_TRANSFORM_BUFFER));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), ZONE_SKYBOX_MAP));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("skyboxBuffer"), ZONE_SKYBOX_BUFFER));
|
||||
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
|
||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||
_backgroundPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
return _backgroundPipeline;
|
||||
}
|
||||
|
||||
void DebugZoneLighting::run(const render::RenderContextPointer& context, const Inputs& inputs) {
|
||||
RenderArgs* args = context->args;
|
||||
|
||||
auto deferredTransform = inputs;
|
||||
|
||||
auto lightStage = DependencyManager::get<DeferredLightingEffect>()->getLightStage();
|
||||
std::vector<model::LightPointer> keyLightStack;
|
||||
if (lightStage && lightStage->_currentFrame._sunLights.size()) {
|
||||
for (auto index : lightStage->_currentFrame._sunLights) {
|
||||
keyLightStack.push_back(lightStage->getLight(index));
|
||||
}
|
||||
}
|
||||
keyLightStack.push_back(DependencyManager::get<DeferredLightingEffect>()->getGlobalLight());
|
||||
|
||||
std::vector<model::LightPointer> ambientLightStack;
|
||||
if (lightStage && lightStage->_currentFrame._ambientLights.size()) {
|
||||
for (auto index : lightStage->_currentFrame._ambientLights) {
|
||||
ambientLightStack.push_back(lightStage->getLight(index));
|
||||
}
|
||||
}
|
||||
ambientLightStack.push_back(DependencyManager::get<DeferredLightingEffect>()->getGlobalLight());
|
||||
|
||||
|
||||
auto backgroundStage = DependencyManager::get<DeferredLightingEffect>()->getBackgroundStage();
|
||||
std::vector<model::SkyboxPointer> skyboxStack;
|
||||
if (backgroundStage && backgroundStage->_currentFrame._backgrounds.size()) {
|
||||
for (auto index : backgroundStage->_currentFrame._backgrounds) {
|
||||
auto background = backgroundStage->getBackground(index);
|
||||
if (background) {
|
||||
skyboxStack.push_back(background->getSkybox());
|
||||
}
|
||||
}
|
||||
}
|
||||
skyboxStack.push_back(DependencyManager::get<DeferredLightingEffect>()->getDefaultSkybox());
|
||||
|
||||
|
||||
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
|
||||
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
auto viewFrustum = args->getViewFrustum();
|
||||
batch.setProjectionTransform(viewFrustum.getProjection());
|
||||
batch.resetViewTransform();
|
||||
|
||||
Transform model;
|
||||
|
||||
batch.setUniformBuffer(ZONE_DEFERRED_TRANSFORM_BUFFER, deferredTransform->getFrameTransformBuffer());
|
||||
|
||||
batch.setPipeline(getKeyLightPipeline());
|
||||
auto numKeys = keyLightStack.size();
|
||||
for (int i = numKeys - 1; i >= 0; i--) {
|
||||
model.setTranslation(glm::vec3(-4.0, -3.0 + (i * 1.0), -10.0 - (i * 3.0)));
|
||||
batch.setModelTransform(model);
|
||||
if (keyLightStack[i]) {
|
||||
batch.setUniformBuffer(ZONE_KEYLIGHT_BUFFER, keyLightStack[i]->getLightSchemaBuffer());
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
}
|
||||
}
|
||||
|
||||
batch.setPipeline(getAmbientPipeline());
|
||||
auto numAmbients = ambientLightStack.size();
|
||||
for (int i = numAmbients - 1; i >= 0; i--) {
|
||||
model.setTranslation(glm::vec3(0.0, -3.0 + (i * 1.0), -10.0 - (i * 3.0)));
|
||||
batch.setModelTransform(model);
|
||||
if (ambientLightStack[i]) {
|
||||
batch.setUniformBuffer(ZONE_AMBIENT_BUFFER, ambientLightStack[i]->getAmbientSchemaBuffer());
|
||||
if (ambientLightStack[i]->getAmbientMap()) {
|
||||
batch.setResourceTexture(ZONE_AMBIENT_MAP, ambientLightStack[i]->getAmbientMap());
|
||||
}
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
}
|
||||
}
|
||||
|
||||
batch.setPipeline(getBackgroundPipeline());
|
||||
auto numBackgrounds = skyboxStack.size();
|
||||
for (int i = numBackgrounds - 1; i >= 0; i--) {
|
||||
model.setTranslation(glm::vec3(4.0, -3.0 + (i * 1.0), -10.0 - (i * 3.0)));
|
||||
batch.setModelTransform(model);
|
||||
if (skyboxStack[i]) {
|
||||
batch.setResourceTexture(ZONE_SKYBOX_MAP, skyboxStack[i]->getCubemap());
|
||||
batch.setUniformBuffer(ZONE_SKYBOX_BUFFER, skyboxStack[i]->getSchemaBuffer());
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -14,12 +14,15 @@
|
|||
|
||||
#include "render/Engine.h"
|
||||
|
||||
#include "DeferredFrameTransform.h"
|
||||
|
||||
class ZoneRendererConfig : public render::Task::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty)
|
||||
public:
|
||||
|
||||
ZoneRendererConfig() : render::Task::Config(false) {}
|
||||
ZoneRendererConfig() : render::Task::Config(
|
||||
) {}
|
||||
|
||||
int maxDrawn { -1 };
|
||||
|
||||
|
@ -49,4 +52,40 @@ protected:
|
|||
int _maxDrawn; // initialized by Config
|
||||
};
|
||||
|
||||
class DebugZoneLighting {
|
||||
public:
|
||||
class Config : public render::JobConfig {
|
||||
public:
|
||||
Config(bool enabled = false) : JobConfig(enabled) {}
|
||||
};
|
||||
|
||||
using Inputs = DeferredFrameTransformPointer;
|
||||
using JobModel = render::Job::ModelI<DebugZoneLighting, Inputs, Config>;
|
||||
|
||||
DebugZoneLighting() {}
|
||||
|
||||
void configure(const Config& configuration) {}
|
||||
void run(const render::RenderContextPointer& context, const Inputs& inputs);
|
||||
|
||||
protected:
|
||||
|
||||
enum Slots {
|
||||
ZONE_DEFERRED_TRANSFORM_BUFFER = 0,
|
||||
ZONE_KEYLIGHT_BUFFER,
|
||||
ZONE_AMBIENT_BUFFER,
|
||||
ZONE_AMBIENT_MAP,
|
||||
ZONE_SKYBOX_BUFFER,
|
||||
ZONE_SKYBOX_MAP,
|
||||
};
|
||||
|
||||
gpu::PipelinePointer _keyLightPipeline;
|
||||
gpu::PipelinePointer _ambientPipeline;
|
||||
gpu::PipelinePointer _backgroundPipeline;
|
||||
|
||||
const gpu::PipelinePointer& getKeyLightPipeline();
|
||||
const gpu::PipelinePointer& getAmbientPipeline();
|
||||
const gpu::PipelinePointer& getBackgroundPipeline();
|
||||
};
|
||||
|
||||
|
||||
#endif
|
37
libraries/render-utils/src/zone_draw.slh
Normal file
37
libraries/render-utils/src/zone_draw.slh
Normal file
|
@ -0,0 +1,37 @@
|
|||
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// Created by Sam Gateau on 5/17/17.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include DeferredTransform.slh@>
|
||||
<$declareDeferredFrameTransform()$>
|
||||
|
||||
<@func evalGlobeWidget()@>
|
||||
const float SCOPE_RADIUS = 1.0;
|
||||
const float SCOPE_RADIUS2 = SCOPE_RADIUS * SCOPE_RADIUS;
|
||||
const float EDGE_HALFWIDTH = 0.025;
|
||||
const float EDGE_HALFWIDTH2 = EDGE_HALFWIDTH * EDGE_HALFWIDTH;
|
||||
const float OUT_RADIUS = SCOPE_RADIUS + EDGE_HALFWIDTH;
|
||||
|
||||
vec2 sphereUV = (varTexCoord0.xy * 2.0 - vec2(1.0)) * OUT_RADIUS;
|
||||
float sphereR2 = dot(sphereUV.xy, sphereUV.xy);
|
||||
if (sphereR2 > OUT_RADIUS * OUT_RADIUS) {
|
||||
discard;
|
||||
}
|
||||
float sphereR = sqrt(sphereR2);
|
||||
|
||||
float edgeFalloff = (SCOPE_RADIUS - sphereR) / (EDGE_HALFWIDTH);
|
||||
float edgeFalloff2 = min(1.0, edgeFalloff * edgeFalloff);
|
||||
|
||||
vec4 base = vec4(0.0, 0.0, 0.0, 1.0 - edgeFalloff2);
|
||||
if (sphereR2 > SCOPE_RADIUS2) {
|
||||
_fragColor = base;
|
||||
return;
|
||||
}
|
||||
<@endfunc@>
|
||||
|
54
libraries/render-utils/src/zone_drawAmbient.slf
Normal file
54
libraries/render-utils/src/zone_drawAmbient.slf
Normal file
|
@ -0,0 +1,54 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// Created by Sam Gateau on 5/16/17.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
<@include zone_draw.slh@>
|
||||
|
||||
<@include model/Light.slh@>
|
||||
|
||||
<@include LightingModel.slh@>
|
||||
<$declareLightAmbientBuffer()$>
|
||||
|
||||
<@include LightAmbient.slh@>
|
||||
|
||||
<$declareLightingAmbient(_SCRIBE_NULL, 1, _SCRIBE_NULL, _SCRIBE_NULL)$>
|
||||
|
||||
in vec2 varTexCoord0;
|
||||
out vec4 _fragColor;
|
||||
|
||||
void main(void) {
|
||||
|
||||
<$evalGlobeWidget()$>
|
||||
|
||||
vec3 spherePos = normalize(vec3(sphereUV, sqrt(1.0 - sphereR2)));
|
||||
|
||||
|
||||
vec3 fragNormal = vec3(getViewInverse() * vec4(spherePos, 0.0));
|
||||
|
||||
|
||||
LightAmbient lightAmbient = getLightAmbient();
|
||||
|
||||
|
||||
float roughness = 0.1;
|
||||
float levels = getLightAmbientMapNumMips(lightAmbient);
|
||||
float lod = min(((roughness)* levels), levels);
|
||||
vec3 ambientMap = evalSkyboxLight(fragNormal, lod).xyz;
|
||||
vec3 ambientSH = sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(lightAmbient), fragNormal).xyz;
|
||||
|
||||
// vec3 ambient = sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(lightAmbient), fragNormal).xyz;
|
||||
// _fragColor = vec4( 0.5 * (fragNormal + vec3(1.0)), 1.0);
|
||||
|
||||
vec3 color = (sphereUV.x > 0 ? ambientMap : ambientSH);
|
||||
|
||||
color = color * 1.0 - base.w + base.xyz * base.w;
|
||||
const float INV_GAMMA_22 = 1.0 / 2.2;
|
||||
_fragColor = vec4(pow(color, vec3(INV_GAMMA_22)), 1.0);
|
||||
}
|
||||
|
||||
|
57
libraries/render-utils/src/zone_drawKeyLight.slf
Normal file
57
libraries/render-utils/src/zone_drawKeyLight.slf
Normal file
|
@ -0,0 +1,57 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// Created by Sam Gateau on 5/16/17.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
<@include zone_draw.slh@>
|
||||
|
||||
<@include model/Light.slh@>
|
||||
|
||||
<@include LightingModel.slh@>
|
||||
<$declareLightBuffer()$>
|
||||
|
||||
<@include LightDirectional.slh@>
|
||||
<$declareLightingDirectional(_SCRIBE_NULL)$>
|
||||
|
||||
in vec2 varTexCoord0;
|
||||
out vec4 _fragColor;
|
||||
|
||||
void main(void) {
|
||||
|
||||
<$evalGlobeWidget()$>
|
||||
|
||||
Light light = getLight();
|
||||
vec3 lightDirection = normalize(getLightDirection(light));
|
||||
vec3 lightIrradiance = getLightIrradiance(light);
|
||||
vec3 color = vec3(0.0);
|
||||
|
||||
const float INOUT_RATIO = 0.4;
|
||||
const float SUN_THRESHOLD = 0.99;
|
||||
|
||||
vec3 outSpherePos = normalize(vec3(sphereUV, -sqrt(1.0 - sphereR2)));
|
||||
vec3 outNormal = vec3(getViewInverse() * vec4(outSpherePos, 0.0));
|
||||
|
||||
float val = step(SUN_THRESHOLD, dot(-lightDirection, outNormal));
|
||||
|
||||
color = lightIrradiance * vec3(val);
|
||||
|
||||
if (sphereR2 < INOUT_RATIO * INOUT_RATIO * SCOPE_RADIUS2) {
|
||||
vec2 inSphereUV = sphereUV / INOUT_RATIO;
|
||||
vec3 inSpherePos = normalize(vec3(inSphereUV, sqrt(1.0 - dot(inSphereUV.xy, inSphereUV.xy))));
|
||||
vec3 inNormal = vec3(getViewInverse() * vec4(inSpherePos, 0.0));
|
||||
|
||||
vec3 marbleColor = max(lightIrradiance * vec3(dot(-lightDirection, inNormal)), vec3(0.01));
|
||||
color += marbleColor;
|
||||
}
|
||||
|
||||
color = color * 1.0 - base.w + base.xyz * base.w;
|
||||
const float INV_GAMMA_22 = 1.0 / 2.2;
|
||||
_fragColor = vec4(pow(color, vec3(INV_GAMMA_22)), 1.0);
|
||||
}
|
||||
|
||||
|
48
libraries/render-utils/src/zone_drawSkybox.slf
Normal file
48
libraries/render-utils/src/zone_drawSkybox.slf
Normal file
|
@ -0,0 +1,48 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// Created by Sam Gateau on 5/16/17.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
<@include zone_draw.slh@>
|
||||
|
||||
uniform samplerCube skyboxMap;
|
||||
|
||||
struct Skybox {
|
||||
vec4 color;
|
||||
};
|
||||
|
||||
uniform skyboxBuffer {
|
||||
Skybox skybox;
|
||||
};
|
||||
|
||||
in vec2 varTexCoord0;
|
||||
out vec4 _fragColor;
|
||||
|
||||
void main(void) {
|
||||
<$evalGlobeWidget()$>
|
||||
|
||||
vec3 spherePos = normalize(vec3(sphereUV, -sqrt(1.0 - sphereR2)));
|
||||
|
||||
vec3 direction = vec3(getViewInverse() * vec4(spherePos, 0.0));
|
||||
|
||||
vec3 color = skybox.color.rgb;
|
||||
|
||||
// blend is only set if there is a cubemap
|
||||
if (skybox.color.a > 0.0) {
|
||||
color = texture(skyboxMap, direction).rgb;
|
||||
if (skybox.color.a < 1.0) {
|
||||
color *= skybox.color.rgb;
|
||||
}
|
||||
}
|
||||
|
||||
color = color * 1.0 - base.w + base.xyz * base.w;
|
||||
const float INV_GAMMA_22 = 1.0 / 2.2;
|
||||
_fragColor = vec4(pow(color, vec3(INV_GAMMA_22)), 1.0);
|
||||
}
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ if (WIN32)
|
|||
setup_hifi_plugin(OpenGL Script Qml Widgets)
|
||||
link_hifi_libraries(shared gl networking controllers ui
|
||||
plugins display-plugins ui-plugins input-plugins script-engine
|
||||
render-utils model gpu gpu-gl render model-networking fbx ktx image)
|
||||
render-utils model gpu gpu-gl render model-networking fbx ktx image procedural)
|
||||
|
||||
include_hifi_library_headers(octree)
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ Column {
|
|||
"Point:LightingModel:enablePointLight",
|
||||
"Spot:LightingModel:enableSpotLight",
|
||||
"Light Contour:LightingModel:showLightContour",
|
||||
"Zone Stack:DrawZoneStack:enabled",
|
||||
"Shadow:RenderShadowTask:enabled"
|
||||
]
|
||||
CheckBox {
|
||||
|
@ -162,13 +163,9 @@ Column {
|
|||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
Column {
|
||||
id: metas
|
||||
CheckBox {
|
||||
text: "Metas"
|
||||
checked: Render.getConfig("DrawMetaBounds")["enabled"]
|
||||
onCheckedChanged: { Render.getConfig("DrawMetaBounds")["enabled"] = checked }
|
||||
}
|
||||
|
||||
CheckBox {
|
||||
text: "Opaques"
|
||||
checked: Render.getConfig("DrawOpaqueBounds")["enabled"]
|
||||
|
@ -189,11 +186,24 @@ Column {
|
|||
checked: Render.getConfig("DrawOverlayTransparentBounds")["enabled"]
|
||||
onCheckedChanged: { Render.getConfig("DrawOverlayTransparentBounds")["enabled"] = checked }
|
||||
}
|
||||
}
|
||||
Column {
|
||||
CheckBox {
|
||||
text: "Metas"
|
||||
checked: Render.getConfig("DrawMetaBounds")["enabled"]
|
||||
onCheckedChanged: { Render.getConfig("DrawMetaBounds")["enabled"] = checked }
|
||||
}
|
||||
CheckBox {
|
||||
text: "Lights"
|
||||
checked: Render.getConfig("DrawLightBounds")["enabled"]
|
||||
onCheckedChanged: { Render.getConfig("DrawLightBounds")["enabled"] = checked; }
|
||||
}
|
||||
CheckBox {
|
||||
text: "Zones"
|
||||
checked: Render.getConfig("DrawZones")["enabled"]
|
||||
onCheckedChanged: { Render.getConfig("ZoneRenderer")["enabled"] = checked; Render.getConfig("DrawZones")["enabled"] = checked; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,9 +20,9 @@ Item {
|
|||
id: stats
|
||||
spacing: 8
|
||||
anchors.fill:parent
|
||||
|
||||
|
||||
property var config: Render.getConfig("Stats")
|
||||
|
||||
|
||||
function evalEvenHeight() {
|
||||
// Why do we have to do that manually ? cannot seem to find a qml / anchor / layout mode that does that ?
|
||||
return (height - spacing * (children.length - 1)) / children.length
|
||||
|
@ -81,7 +81,7 @@ Item {
|
|||
color: "#1AC567"
|
||||
},
|
||||
{
|
||||
prop: "textureGPUTransferCount",
|
||||
prop: "texturePendingGPUTransferCount",
|
||||
label: "Transfer",
|
||||
color: "#9495FF"
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ Item {
|
|||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
PlotPerf {
|
||||
title: "State Changes"
|
||||
height: parent.evalEvenHeight()
|
||||
|
@ -180,7 +180,7 @@ Item {
|
|||
color: "#1AC567"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
property var drawOpaqueConfig: Render.getConfig("DrawOpaqueDeferred")
|
||||
property var drawTransparentConfig: Render.getConfig("DrawTransparentDeferred")
|
||||
|
@ -211,7 +211,7 @@ Item {
|
|||
color: "#FED959"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
PlotPerf {
|
||||
title: "Timing"
|
||||
|
@ -250,4 +250,3 @@ Item {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -261,7 +261,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
gpuTextures = Render.getConfig("Stats").textureGPUTransferCount;
|
||||
gpuTextures = Render.getConfig("Stats").texturePendingGPUTransferCount;
|
||||
|
||||
// Update state
|
||||
if (!visible) { // Not visible because no recent downloads
|
||||
|
@ -290,7 +290,7 @@
|
|||
}, FADE_OUT_WAIT);
|
||||
}
|
||||
} else {
|
||||
if (displayProgress < 100 || gpuTextures > 0) { // Was finished and waiting to fade out but have resumed so
|
||||
if (displayProgress < 100 || gpuTextures > 0) { // Was finished and waiting to fade out but have resumed so
|
||||
// don't fade out
|
||||
Script.clearInterval(fadeWaitTimer);
|
||||
fadeWaitTimer = null;
|
||||
|
|
|
@ -10,7 +10,7 @@ setup_hifi_project(Quick Gui OpenGL)
|
|||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(shared octree ktx gl gpu gpu-gl render model model-networking networking render-utils fbx entities entities-renderer animation audio avatars script-engine physics image)
|
||||
link_hifi_libraries(shared octree ktx gl gpu gpu-gl render model model-networking networking render-utils fbx entities entities-renderer animation audio avatars script-engine physics image procedural)
|
||||
|
||||
package_libraries_for_deployment()
|
||||
|
||||
|
|
Loading…
Reference in a new issue