diff --git a/streaming-pointcloud/.gitattributes b/streaming-pointcloud/.gitattributes new file mode 100644 index 00000000..1ff0c423 --- /dev/null +++ b/streaming-pointcloud/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/streaming-pointcloud/.gitignore b/streaming-pointcloud/.gitignore new file mode 100644 index 00000000..c74b9154 --- /dev/null +++ b/streaming-pointcloud/.gitignore @@ -0,0 +1,271 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +!*.csproj +!*.sln + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + + +*.ply +point\ cloud\ opencv/settings.toml + +*.toe + +*.dmp diff --git a/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer.sln b/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer.sln new file mode 100644 index 00000000..f0ad6afe --- /dev/null +++ b/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29424.173 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mqtt visualizer", "Mqtt visualizer\Mqtt visualizer.vcxproj", "{1E099D9A-F130-47F5-9B67-86EF5BFC546F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1E099D9A-F130-47F5-9B67-86EF5BFC546F}.Debug|x64.ActiveCfg = Debug|x64 + {1E099D9A-F130-47F5-9B67-86EF5BFC546F}.Debug|x64.Build.0 = Debug|x64 + {1E099D9A-F130-47F5-9B67-86EF5BFC546F}.Debug|x86.ActiveCfg = Debug|Win32 + {1E099D9A-F130-47F5-9B67-86EF5BFC546F}.Debug|x86.Build.0 = Debug|Win32 + {1E099D9A-F130-47F5-9B67-86EF5BFC546F}.Release|x64.ActiveCfg = Release|x64 + {1E099D9A-F130-47F5-9B67-86EF5BFC546F}.Release|x64.Build.0 = Release|x64 + {1E099D9A-F130-47F5-9B67-86EF5BFC546F}.Release|x86.ActiveCfg = Release|Win32 + {1E099D9A-F130-47F5-9B67-86EF5BFC546F}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {AFA77A22-E596-41B9-852B-DEF2DC67BF70} + EndGlobalSection +EndGlobal diff --git a/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/Mqtt visualizer.cpp b/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/Mqtt visualizer.cpp new file mode 100644 index 00000000..c9ba7a7d --- /dev/null +++ b/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/Mqtt visualizer.cpp @@ -0,0 +1,290 @@ +#include +#include "windowWrapper.h" +#include "mqtt.h" +#include +#include +#include +#include +#include + +float translationIncrement = 0; +float rotationIncrement = 0; +int adjustmentDetailLevel = 1; +float adjustmentDetailLevels[4] = { 0.1f, 1.0f, 10.0f, 100.0f }; + +uint16_t index = 0; +std::vector topics; + +//Window instance +openCvWrapper window("Pointcloud Renderer"); +mqtt mosquittoWrapper; +bool displayHelpText = true; + +std::string helptTextWidgetName("helptext"); +std::string helpTextString("\ +n, N : Help menu\n\ +m, M : Restart capture\n\ +Tab : Switch cameras\n\ +l,L : Save cameras\n\n\ +Cloud Movement\n\ +Directions relative to camera\n\ + Up : move positive y-axis\n\ + Down : move negative y-axis\n\ + Right : move positive x-axis\n\ + Left : move negative x-axis\n\ + Home : move positive z-axis\n\ + End : move negative z-axis\n\ + 2 : rotate positive x-axis\n\ + 8 : rotate negative x-axis\n\ + 6 : rotate positive y-axis\n\ + 4 : rotate negative y-axis\n\ + 9 : rotate positive z-axis\n\ + 7 : rotate negative z-axis\n\ +"); + + +void sendCalibrationAdjustment(float tx, float ty, float tz, float rx, float ry, float rz, std::string topic) { + float arr[6] = { tx, ty, tz, rx, ry, rz }; + mosquittoWrapper.sendMessage(sizeof(float) * 6, arr, (char*)topic.c_str()); +} + +//Keyboard events for the cv::viz window created +void KeyboardViz3d(const cv::viz::KeyboardEvent& w, void* t) { + //There was a key pressed + //Go through and look at which key was pressed and act accordingly by which key does what. + if (w.action) { + //Debug to get viz name in order to bind keys to proper instructions + //std::cout << "you pressed " << w.code << " = " << w.symbol << " in viz window " << "\n"; + std::string topicString; + std::string lastCommand("Last Command Entered: "); + std::string command; + + float translateAmount = translationIncrement * adjustmentDetailLevels[adjustmentDetailLevel]; + float rotateAmount = rotationIncrement * adjustmentDetailLevels[adjustmentDetailLevel]; + + if (topics.size() > index) { + topicString.append(topics[index]); + } + topicString.append("/calibrate"); + + if (w.symbol == "Up") { + sendCalibrationAdjustment(0, translateAmount, 0, 0, 0, 0, topicString); + } + else if (w.symbol == "Down") { + sendCalibrationAdjustment(0, -translateAmount, 0, 0, 0, 0, topicString); + } + else if (w.symbol == "Right") { + sendCalibrationAdjustment(-translateAmount, 0, 0, 0, 0, 0, topicString); + } + else if (w.symbol == "Left") { + sendCalibrationAdjustment(translateAmount, 0, 0, 0, 0, 0, topicString); + } + else if (w.symbol == "End") { + sendCalibrationAdjustment(0, 0, translateAmount, 0, 0, 0, topicString); + } + else if (w.symbol == "Home") { + sendCalibrationAdjustment(0, 0, -translateAmount, 0, 0, 0, topicString); + } + //Rotate the point cloud that is currently in focus, everything is relative to the global coordinates + else if (w.symbol == "2") { + sendCalibrationAdjustment(0, 0, 0, rotateAmount, 0, 0, topicString); + } + else if (w.symbol == "8") { + sendCalibrationAdjustment(0, 0, 0, -rotateAmount, 0, 0, topicString); + } + else if (w.symbol == "6") { + sendCalibrationAdjustment(0, 0, 0, 0, rotateAmount, 0, topicString); + } + else if (w.symbol == "4") { + sendCalibrationAdjustment(0, 0, 0, 0, -rotateAmount, 0, topicString); + } + else if (w.symbol == "7") { + sendCalibrationAdjustment(0, 0, 0, 0, 0, -rotateAmount, topicString); + } + else if (w.symbol == "9") { + sendCalibrationAdjustment(0, 0, 0, 0, 0, rotateAmount, topicString); + } + else if (w.symbol == "l" || w.symbol == "L") { + mosquittoWrapper.sendMessage(4, (char*)COMMAND_SAVE, (char*)TOPIC_CONTROL); + } + else if (w.symbol == "Prior") { + // page up + adjustmentDetailLevel++; + if (adjustmentDetailLevel > 3) { + adjustmentDetailLevel = 3; + } + } + else if (w.symbol == "Next") { + // page down + adjustmentDetailLevel--; + if (adjustmentDetailLevel < 0) { + adjustmentDetailLevel = 0; + } + } + else if (w.symbol == "n" || w.symbol == "N") { + displayHelpText = !displayHelpText; + if (displayHelpText) { + window.drawText(helpTextString, helptTextWidgetName, 100, 0); + } + else { + window.clearWidgetByName(helptTextWidgetName); + } + } + else if (w.symbol == "m" || w.symbol == "M") { + mosquittoWrapper.sendMessage(7, (char*)COMMAND_RESTART, (char*)TOPIC_CONTROL); + } + else if (w.symbol == "Tab") { + index = (index + 1) % (topics.size()); + std::cout << "\33[2KCamera: " << topics[index] <<"\r"; + } + //Display the extra options onto the help message + else if (w.symbol == "H" || w.symbol == "h") { + std::cout<< helpTextString << std::endl; + } + else if (w.symbol == "q" || w.symbol == "Q" || w.symbol == "e" || w.symbol == "E") { + window.setDone(true); + } + + if (topics.size() != 0) { + lastCommand.append(w.symbol); + lastCommand.append(" on source "); + lastCommand.append(topics[index]); + + window.drawText(lastCommand, std::string("lastCommand")); + } + } +} + +int main() { + //Set the window's background and keyboard callbacks + window.setBackgroundColor(cv::viz::Color::black()); + window.registerKeyboardCallback(KeyboardViz3d); + + //Parse the toml file + std::ifstream file("settings.toml"); + if (!file.good()) { + fprintf(stderr, "Error opening the settings.toml file"); + exit(1); + } + toml::Data data = toml::parse(file); + mosquittoWrapper.initMqttLib(); + + translationIncrement = (float)toml::get(data.at("translation_increment")); + rotationIncrement = (float)toml::get(data.at("rotation_increment")); + + bool merged = toml::get(data.at("merged")); + + mosquittoWrapper.ParseArgs(toml::get(data.at("MqttInfo"))); + //Set up the mosquitto client + mosquittoWrapper.callbacks(); + mosquittoWrapper.connect(); + + mosquittoWrapper.subscribe((char*)TOPIC_MERGER); + mosquittoWrapper.subscribe((char*)TOPIC_CONTROL); + mosquitto_loop_start(mosquittoWrapper.giveMosquitto()); + + window.parseArgs(toml::get(data.at("Threshold"))); + + std::string commandGetCameraTopics(COMMAND_GET_CAMERA_TOPICS); + std::string commandGetMergedTopic(COMMAND_GET_MERGED_TOPIC); + bool stopped = false; + std::string state("Cameras:\n"); + std::string stats("Stats:\n"); + int pointCount = 0; + + while (!stopped && !window.isDone()) { + window.drawThreshold(); + window.sphere(10); + + while (topics.size() == 0 && !window.isDone() && !stopped) { + std::string temp = state; + temp.append("Waiting for topics from merger\n"); + window.drawText(temp, state, 0, 0.70); + temp = stats; + temp.append("Points: 0"); + window.drawText(temp, stats, 0, 0.90); + if (displayHelpText) { + window.drawText(helpTextString, helptTextWidgetName); + } + window.showWindow(1, false); + mosquittoWrapper.sendMessage((int)commandGetCameraTopics.size(), commandGetCameraTopics.c_str(), (char*)TOPIC_VIEWER); + std::this_thread::sleep_for(std::chrono::seconds(1)); + topics = window.getIndexNames(); + stopped = window.wasStopped(); + } + std::string displayTopics = state; + for (auto iter : topics) { + displayTopics.append(iter); + displayTopics.append("\n"); + } + if (merged) { + window.unsubscribeTopics(); + mosquittoWrapper.sendMessage((int)commandGetMergedTopic.size(), commandGetMergedTopic.c_str(), (char*)TOPIC_VIEWER); + } + while (!stopped && !window.isRestart() && !window.isDone()) { + int newPoints = window.createWidgets(); + if (newPoints != 0) { + pointCount = newPoints; + } + std::string displayStats("Points: "); + displayStats.append(std::to_string(pointCount)); + displayStats.append("\n\nSelected Camera: "); + displayStats.append(topics[index]); + + if (!merged) { + displayStats.append(" - "); + switch (index) { + case 0: + displayStats.append("red"); + break; + case 1: + displayStats.append("green"); + break; + case 2: + displayStats.append("blue"); + break; + default: + displayStats.append("white"); + } + } + displayStats.append("\n"); + displayStats.append("Rotation increment: "); + + std::stringstream currentRotationValue; + currentRotationValue << std::fixed << std::setprecision(2) << (rotationIncrement * adjustmentDetailLevels[adjustmentDetailLevel]); + std::stringstream currentTranslationValue; + currentTranslationValue << std::fixed << std::setprecision(2) << (translationIncrement * adjustmentDetailLevels[adjustmentDetailLevel]); + + displayStats.append(currentRotationValue.str()); + displayStats.append(" degrees\n"); + + displayStats.append("Translation increment: "); + displayStats.append(currentTranslationValue.str()); + displayStats.append(" mm"); + + + window.drawText(displayStats, stats, 0.0, 0.85); + window.drawText(displayTopics, state, 0, 0.65); + if (displayHelpText) { + window.drawText(helpTextString, helptTextWidgetName); + } + window.showWindow(1, false); + stopped = window.wasStopped(); + } + window.setRestart(false); + window.unsubscribeTopics(); + window.clearAllWidgets(); + topics.clear(); + index = 0; + if (!stopped) { + std::this_thread::sleep_for(std::chrono::seconds(3)); + } + } + + //Disconnect the mosquitto client from the broker + //Clean up the library + mosquittoWrapper.disconnect(); + mosquittoWrapper.finishMosquitto(); + + return 0; +} \ No newline at end of file diff --git a/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/Mqtt visualizer.vcxproj b/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/Mqtt visualizer.vcxproj new file mode 100644 index 00000000..b7012bf1 --- /dev/null +++ b/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/Mqtt visualizer.vcxproj @@ -0,0 +1,183 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + {1E099D9A-F130-47F5-9B67-86EF5BFC546F} + Win32Proj + Mqttvisualizer + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + Disabled + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + + + Level3 + + + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + AnySuitable + Speed + true + + + Console + true + + + + + + + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + Level3 + MaxSpeed + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + AnySuitable + Speed + true + true + true + true + true + AdvancedVectorExtensions2 + Fast + + + Console + true + true + true + + + + + + + + + + + + + + Document + + + + + + \ No newline at end of file diff --git a/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/Mqtt visualizer.vcxproj.filters b/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/Mqtt visualizer.vcxproj.filters new file mode 100644 index 00000000..d84a9bb8 --- /dev/null +++ b/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/Mqtt visualizer.vcxproj.filters @@ -0,0 +1,41 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/mqtt.cpp b/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/mqtt.cpp new file mode 100644 index 00000000..9baf9f15 --- /dev/null +++ b/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/mqtt.cpp @@ -0,0 +1,329 @@ +#include "mqtt.h" +#include "windowWrapper.h" +#include + +extern mqtt mosquittoWrapper; +extern openCvWrapper window; +extern bool merged; + + +//Converts an std::string into an array of chars, syntax is very similar to how strcpy works +//Used for getting std::/toml::string into a char* +void stringToChar(char*& dest, std::string source) { + if (strlen(source.c_str())) { + size_t len = strlen(source.c_str()) + 1; + dest = new char[len]; + strcpy_s(dest, len, source.c_str()); + dest[len - 1] = '\0'; + } +} + +/* +The constructor sets all pointers to null and sets the non pointer variables to the default by mosquitto's standards +port = 1883 +keepalive = 60 +clean_session = true +*/ +mqtt::mqtt() { + this->host = nullptr; + this->topic = nullptr; + this->port = 1883; + this->keepalive = 60; + this->clean_session = true; + this->mosq = nullptr; + this->id = nullptr; + this->userdata = nullptr; +} + +/* +The constructor frees up all of the pointer's memory and then set them to point at 0 +All other non-pointer data variables are set to 0. +*/ +mqtt::~mqtt() { + delete[] this->host; + this->host = 0; + delete[] this->topic; + this->topic = 0; + this->port = 0; + this->keepalive = 0; + this->clean_session = false; + delete this->userdata; + this->userdata = nullptr; + mosquitto_destroy(this->mosq); + this->mosq = 0; +} + +/* +Frees up all memory for the pointer fields before allocating the data onto host, topic, and id +Sets all the other non pointer variables to their respective fields. +It will then go through and call init_mosquitto() which will initialize the mosq variable, +allowing it to connect() right after create() +*/ +bool mqtt::create(char* host, char* topic, int port, char* id, void* userdata, int keep_alive, bool clean_session, int num_cameras) { + delete[]this->host; + delete[]this->topic; + delete[]this->id; + this->host = new char[strlen(host) + 1]; + strcpy_s(this->host, (strlen(host) + 1), host); + this->topic = new char[strlen(topic) + 1]; + strcpy_s(this->topic, (strlen(topic) + 1), topic); + this->port = port; + this->keepalive = keepalive; + this->clean_session = clean_session; + this->id = new char[strlen(id) + 1]; + strcpy_s(this->id, (strlen(id) + 1), id); + + return initMosquitto(); +} + +/* +connect() is a wrapper that will check to make sure that the connection succeeded, if it didn't it will return 1 +succeeding will return 0 +*/ +bool mqtt::connect(void) { + if (mosquitto_connect(this->mosq, this->host, this->port, this->keepalive)) { + fprintf(stderr, "Unable to connect.\n"); + return false; + } + return true; +} + +/* +The my_function_callback are functions that will help in the debug process. They are the functions that are called as if there +were on_event() type syntax. These are added to the callback function when calling the mosquitto_log_function_set(). The +mosquitto_log_function_set() takes the mosquitto structure and these my_function_callback() as the arguments. +*/ +void mqtt::callbacks(void) { + //mosquitto_log_callback_set(this->mosq, my_log_callback); + //mosquitto_connect_callback_set(this->mosq, my_connect_callback); + mosquitto_message_callback_set(this->mosq, my_message_callback); + //mosquitto_subscribe_callback_set(this->mosq, my_subscribe_callback); +} + +/* +Send message is just a simple wrapper to publish/send a message over the mqtt stream with the +topic that the varible was initialized with. +The required arguments are: +payload_len: size of payload to be sent over +payload: the actual payload to be sent over +qos: 0, 1 or 2 indicating the quality of service to be used for the message +Optional arguments are: +retain: if message is desired to be kept +mid: number for the message id specifically sent over, can be NULL and the library will increment its own. +*/ +void mqtt::sendMessage(int payload_len, const void* payload, char* topic, int qos, bool retain, int* mid) { + if(topic != nullptr){ + mosquitto_publish(this->mosq, mid, topic, payload_len, payload, qos, retain); + } + else { + mosquitto_publish(this->mosq, mid, this->topic, payload_len, payload, qos, retain); + } +} + +/* +Finish mosquitto is a wrapper that calls the mosquitto_lib_cleanup() function +Only do this at the end of the program. +*/ +void mqtt::finishMosquitto(void) { + mosquitto_lib_cleanup(); +} + +/* +Wrapper that is used to initialize the mosquitto library. Only needs to be called once. +*/ +void mqtt::initMqttLib(void) { + mosquitto_lib_init(); +} + +/* +Wrapper to help create a new mosquitto instance. +There are no required parameters for this function as it already assumes that the values for the class +has been populated in some fashion prior to calling this. +*/ +int mqtt::initMosquitto(void) { + this->mosq = mosquitto_new(this->id, this->clean_session, this->userdata); + if (!mosq) { + fprintf(stderr, "Unable to connect.\n"); + return 0; + } + return 1; +} + +/* +ParseArgs takes in the section of toml that is relevant for mqtt info. +It will create the variables right from the file and then initialize the values to those provided from the +config.toml file. +Returns the success or failure of init_mosquitto() +*/ +bool mqtt::ParseArgs(toml::Table table) { + stringToChar(this->host, toml::get(table.at("host"))); + stringToChar(this->id, toml::get(table.at("id"))); + std::string topicString(toml::get(table.at("topic"))); + topicString.append("/"); + topicString.append(id); + stringToChar(this->topic, topicString); + this->port = (int)toml::get(table.at("port")); + try { + this->keepalive = (int)toml::get(table.at("keepalive")); + } + catch (std::exception & e) { + e; //Removes unreferenced local veriable warning + this->keepalive = 60; + } + try { + this->clean_session = toml::get(table.at("clean_session")); + } + catch (std::exception & e) { + e; //Removes unreferenced local veriable warning + this->clean_session = true; + } + + return initMosquitto(); +} + +/* +Give the current mosquitto instance back, useful for: +mosquitto_loop_start(); +*/ +mosquitto* mqtt::giveMosquitto() { + return this->mosq; +} + +/* +Subscribe to the topic that is stored in the class +*/ +void mqtt::subscribe() { + mosquitto_subscribe(this->mosq, NULL, this->topic, 0); +} + +/* +Subscribe to a topic that is not stored in the class +Can do either to be '(this->topic)/newtopic' in terms of appending +or its own topic to something that is not tied to this->topic +*/ +void mqtt::subscribe(char* topic, bool append) { + std::string subTopic; + if (append) { + subTopic = std::string(this->topic); + subTopic.append("/"); + subTopic.append(topic); + } + else { + subTopic = std::string(topic); + } + mosquitto_subscribe(this->mosq, NULL, subTopic.c_str(), 0); +} + +/* +Disconnect the mosquitto client from the broker +*/ +void mqtt::disconnect() { + mosquitto_disconnect(this->mosq); +} + + /* + Return the stored topic in the class + */ +std::string mqtt::giveTopic() { + return this->topic; +} + +bool mqtt::unsubscribe(char* topic) { + if (topic == nullptr) { + return false; + } + + mosquitto_unsubscribe(this->mosq, NULL, topic); + + return true; +} + +/* +Function is provided by the mosquitto.org documentation +*/ +void my_message_callback(struct mosquitto* mosq, void* userdata, const struct mosquitto_message* message) +{ + if (message->payloadlen) { + + if (strcmp((char*)message->topic, TOPIC_CONTROL) == 0 ) { + + if (strcmp((char*)message->payload, COMMAND_SHUTDOWN) == 0) { + printf("Closing down the application..\n"); + window.setDone(true); + } + else if (strcmp((char*)message->payload, COMMAND_RESTART) == 0) { + printf("Restarting the application.. \n"); + window.setRestart(true); + } + } + else if (strcmp((char*)message->topic, TOPIC_MERGER) == 0) { + + // Merger is responding with a list of 1 or more topics from which + // point frames will be broadcast (either the list of individual + // cameras, or the merged frames) + + std::string messagePayload((char*)message->payload); + std::vector messageVector; + //String split using boost 'Solution 2': https://www.fluentcpp.com/2017/04/21/how-to-split-a-string-in-c/ + boost::split(messageVector, messagePayload, [](char c) {return c == ' '; }); + if (messageVector.size() != 0) { + window.setTopicNames(messageVector); + } + } + else if ( window.isActiveTopic(message->topic) ) { + //For Debugging purposes + //printf("%s %d bytes\n", (char*)message->topic, message->payloadlen); + std::string topicString((char*)message->topic); + msg newPoints; + char* buffer = (char*)message->payload; + int totalBuffer = message->payloadlen - 13; + int totalPoints = 0; + memcpy(&totalPoints, &buffer[8], 4); + totalPoints *= 3; + int depthSize = totalPoints * 2; + newPoints.message = new int16_t[totalPoints]; + newPoints.size = totalPoints; + memcpy(&newPoints.message[0], &buffer[13], depthSize); + window.importPoints(topicString, newPoints); + delete[]newPoints.message; + newPoints.message = nullptr; + } + } +} + +/* +Function is provided by the mosquitto.org documentation +*/ +void my_connect_callback(struct mosquitto* mosq, void* userdata, int result) +{ + if (!result) { + /* Subscribe to broker information topics on successful connect. */ + mosquitto_subscribe(mosq, NULL, "$SYS/#", 2); + } + else { + fprintf(stderr, "Connect failed\n"); + } +} + +/* +Function is provided by the mosquitto.org documentation +*/ +void my_subscribe_callback(struct mosquitto* mosq, void* userdata, int mid, int qos_count, const int* granted_qos) +{ + int i; + + printf("Subscribed (mid: %d): %d", mid, granted_qos[0]); + for (i = 1; i < qos_count; i++) { + printf(", %d", granted_qos[i]); + } + printf("\n"); +} + +/* +Function is provided by the mosquitto.org documentation +*/ +void my_log_callback(struct mosquitto* mosq, void* userdata, int level, const char* str) +{ + /* Pring all log messages regardless of level. */ + printf("%s\n", str); +} \ No newline at end of file diff --git a/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/mqtt.h b/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/mqtt.h new file mode 100644 index 00000000..c62566f3 --- /dev/null +++ b/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/mqtt.h @@ -0,0 +1,92 @@ +#pragma once +#pragma once +#include +#include +#include "..//packages/TOMLParser-master/toml.hpp" +#include + +#define TOPIC_CAMERA_AVAILBLE "cameras/available" +#define TOPIC_CAMERA_CONFIGURE "cameras/configure" +#define TOPIC_CONTROL "cameras/control" + +#define TOPIC_VIEWER "viewer" +#define TOPIC_MERGER "merger" + +// Commands for the TOPIC_CAMERA_CONTROL messages +#define COMMAND_SHUTDOWN "done" +#define COMMAND_SAVE "save" +#define COMMAND_RESTART "restart" + +#define COMMAND_GET_CAMERA_TOPICS "get_camera_topics" +#define COMMAND_GET_MERGED_TOPIC "get_merged_topic" + +//Wrapper to store all of the mqtt information +//Only can take in one source of information one camera vs. one merged point cloud +struct msg { + int16_t* message = nullptr; + size_t size = 0; + std::mutex mut; + bool changed = false; + + msg() { + this->message = nullptr; + this->size = 0; + this->changed = false; + } + + ~msg() { + if (message) { + delete[]this->message; + this->message = nullptr; + this->size = 0; + this->changed = false; + } + } +}; + + +/* +These callback functions are not included within the class as they are used to be passed as pointers to the functions +for mosquitto to use them properly +*/ +void my_message_callback(struct mosquitto* mosq, void* userdata, const struct mosquitto_message* message); +void my_connect_callback(struct mosquitto* mosq, void* userdata, int result); +void my_subscribe_callback(struct mosquitto* mosq, void* userdata, int mid, int qos_count, const int* granted_qos); +void my_log_callback(struct mosquitto* mosq, void* userdata, int level, const char* str); + +/* +mqtt class is a wrapper for the mosquitto library +It holds just about all the information to be able to send data with the exception of some sort of message +variable. +Once the class has been created, the next steps to send a message are connect(), then send_message() +With send_message(), be sure to include the payload length, the payload, and the quality of service that would be desired. +*/ +class mqtt { +public: + mqtt(); + ~mqtt(); + bool create(char* host, char* topic, int port, char* id, void* userdata, int keep_alive, bool clean_session, int num_cameras); + bool connect(void); + void disconnect(); + void callbacks(void); + void sendMessage(int payload_len, const void* payload, char* topic = nullptr, int qos = 0, bool retain = false, int* mid = NULL); + void finishMosquitto(void); + void initMqttLib(void); + int initMosquitto(void); + bool ParseArgs(toml::Table table); + void subscribe(void); + void subscribe(char* topic, bool append = false); + std::string giveTopic(); + mosquitto* giveMosquitto(); + bool unsubscribe(char* topic); + +private: + char* host; + char* topic; + int port; + int keepalive; + bool clean_session; + char* id; + void* userdata; + struct mosquitto* mosq; +}; \ No newline at end of file diff --git a/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/settings.toml b/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/settings.toml new file mode 100644 index 00000000..9486aa3a --- /dev/null +++ b/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/settings.toml @@ -0,0 +1,13 @@ +translation_increment = 10.0 +rotation_increment = 1.0 +merged = false + +[MqttInfo] +host = 'localhost' +id = 'windowViewer' +topic = 'points' +port = 1883 + +[Threshold] +min = [-2000, 0, -1500] +max = [2000, 2000, 2000] \ No newline at end of file diff --git a/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/windowWrapper.cpp b/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/windowWrapper.cpp new file mode 100644 index 00000000..43491315 --- /dev/null +++ b/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/windowWrapper.cpp @@ -0,0 +1,405 @@ +#pragma once +#include "windowWrapper.h" +#include "mqtt.h" + +extern mqtt mosquittoWrapper; + +//-------------------------------public functions-------------------------------// + + +//-----Default constructor------// +/* +Sets all of the data types to their zero respective or empty values +*/ +openCvWrapper::openCvWrapper() { + this->window; + this->windowName.clear(); + this->topicNames.clear(); + this->threshold = std::vector(2); + this->done = false; + this->restart = false; +} + +//-----Name constructor------// +/* +Sets all of the data types to their zero respective or empty values. +Gets the window all set up and ready to go in order to display +*/ +openCvWrapper::openCvWrapper(std::string windowName) { + this->openCvWrapper::openCvWrapper(); + this->windowName = windowName; + this->window = cv::viz::Viz3d(this->windowName); +} + +//-----Deconstructor------// +/* +Sets all of the data types to their zero respective or empty values in order to be cleared +*/ +openCvWrapper::~openCvWrapper() { + this->windowName.clear(); + this->threshold.clear(); + + this->done = false; + this->restart = false; + + this->unsubscribeTopics(); + this->cameraSources.clear(); + this->topicNames.clear(); + +} + +//-----SetName------// +/* +Set name will set the WindowName variable +Also sets this->window with the windowName, so its ready to go when showing. +*/ +bool openCvWrapper::setName(std::string windowName) { + if (windowName.size() == 0) { + return false; + } + this->windowName.clear(); + this->windowName = windowName; + this->window = cv::viz::Viz3d(this->windowName); + return true; +} + +bool openCvWrapper::isActiveTopic(std::string topic) { + return std::find(this->topicNames.begin(), this->topicNames.end(), topic) != this->topicNames.end(); +} + +//-----getWindowByName------// +/* +This will take a windowName that is not 0 in length and set that as the new window focus. +Will also reset the camera so everything should be visable if the camera is not in the correct +position to see the new window's object. +*/ +bool openCvWrapper::getWindowByName(std::string windowName) { + if (windowName.size() == 0) { + return false; + } + + this->windowName.clear(); + this->windowName = windowName; + this->window = cv::viz::getWindowByName(this->windowName); + this->window.resetCamera(); + + return true; +} + +//-----showWindow------// +/* +This will display the window indefinately, until the user hits q,Q,e, or E in order to +have it exit the window. Will only show the window if this->windowName is already set +*/ +bool openCvWrapper::showWindow() { + if (this->windowName.size() == 0) { + return false; + } + this->window.spin(); + return true; +} + +//-----showWindow------// +/* +This is an overloaded function that will take 1-2 inputs. +int ms = the number of milliseconds to show the screen +bool redraw = force to redraw the image every time its shown +*/ +bool openCvWrapper::showWindow(int ms, bool redraw) { + if (this->windowName.size() == 0) { + return false; + } + this->window.spinOnce(ms, redraw); + return true; +} + +//-----importPoints------// +/* +Check to make sure that the index exists and its possible to lock the mutex + +Go ahead and copy the message over into the buffer class and unlock the mutex +*/ +bool openCvWrapper::importPoints(std::string index, msg& message) { + if (this->cameraSources.find(index) != this->cameraSources.end() && !this->cameraSources[index]->mut.try_lock()) { + return false; + } + + this->cameraSources[index]->size = message.size; + delete[]this->cameraSources[index]->message; + this->cameraSources[index]->message = new int16_t[message.size]; + memcpy(&this->cameraSources[index]->message[0], &message.message[0], message.size*2); + this->cameraSources[index]->changed = true; + + this->cameraSources[index]->mut.unlock(); + + return true; +} + +//-----createWidget------// +/* +This function will create a widget object and put it into the window that has already +been set in place. Will fail if either the points field or windowName are empty +fields. Will succeed if both of those values are populated prior to calling this function. +*/ +int openCvWrapper::createWidgets() { + if (this->topicNames.size() == 0) { + return 0; + } + + int pointCount = 0; + int count = 0; + //Set the color depending on how many point clouds there are. + for (auto iter : this->cameraSources) { + cv::viz::Color color; + switch (count) { + case 0: + color = color.red(); + break; + case 1: + color = color.green(); + break; + case 2: + color = color.blue(); + break; + default: + color = color.white(); + } + //If the lock can be obtained, update the point cloud and unlock + if (iter.second->mut.try_lock()) { + if (iter.second->changed && iter.second->message != nullptr) { + this->currentPoints[count].clear(); + int16_t* points = iter.second->message; + int size = (int)iter.second->size / 3; + for (int i = 0; i < size; ++i) { + this->currentPoints[count].emplace_back(cv::Point3d(points[i * 3 + 0], points[i * 3 + 1], points[i * 3 + 2])); + } + pointCount += size; + iter.second->changed = false; + this->makeWidget(this->currentPoints[count], iter.first, color); + + } + iter.second->mut.unlock(); + } + + ++count; + } + + return pointCount; +} + +//-----clearAllWidgets------// +/* +This function is a simple wrapper to get rid of all the widgets on the window. +*/ +void openCvWrapper::clearAllWidgets() { + this->window.removeAllWidgets(); + +} + +//-----clearAllWidgets------// +/* +This function is a simple wrapper to get rid of the matching widget name on the window. +*/ +void openCvWrapper::clearWidgetByName(std::string widgetName) { + this->window.removeWidget(widgetName); +} + +//-----wasStopped------// +/* +This function is a simple wrapper for the wasStopped function on the window, which +checks to see if the user wanted to try and get close out of the window. If the value +is true, then the user did want to exit the window. +*/ +bool openCvWrapper::wasStopped() { + return this->window.wasStopped(); +} +//-----setBackgroundColor------// +/* +This function will set the color if the window has already been set up +*/ +bool openCvWrapper::setBackgroundColor(cv::viz::Color color) { + if (this->windowName.size() == 0) { + return false; + } + this->window.setBackgroundColor(color); + return true; +} + +//-----setBackgroundColor------// +/* +This function is a wrapper to reset the camera for the window. +*/ +void openCvWrapper::resetCamera() { + this->window.resetCamera(); +} + +//-----setBackgroundColor------// +/* +This function is a wrapper to pass in more keyboard events. +*/ +void openCvWrapper::registerKeyboardCallback(cv::viz::Viz3d::KeyboardCallback callback) { + this->window.registerKeyboardCallback(callback, &this->window); +} + +//-----sphere------// +/* +Show a blue sphere that is larger than the normal points + +The intent of this sphere is to show the origin and move the point cloud over to have the same origin +*/ +void openCvWrapper::sphere(double size) { + std::vector p(1, cv::Point3d(0,0,0)); + cv::viz::WCloud sphere(p, cv::viz::Color::yellow()); + sphere.setRenderingProperty(cv::viz::POINT_SIZE, size); + this->window.showWidget("sphere", sphere); +} + +//-----parseArgs------// +/* +Get the min and max vectors to be used for a threshold cube, used in drawThreshold +*/ +bool openCvWrapper::parseArgs(toml::Table table) { + + std::vector temp = toml::get>(table.at("min")); + threshold[0] = cv::Point3d((int)temp[0], (int)temp[1], (int)temp[2]); + temp = toml::get>(table.at("max")); + threshold[1] = cv::Point3d((int)temp[0], (int)temp[1], (int)temp[2]); + + return true; +} + +//-----drawThreshold------// +/* +Show the bounding box that the current threshold values are within the world origin. + +Move point clouds around within the box in order to get it set to the spot it would like to be. + +Uses the cv::viz::WCylinder to get the 'pipes' or the edges of the cube that threshold makes +*/ +void openCvWrapper::drawThreshold(cv::viz::Color color) { + cv::Point3d allmin = this->threshold[0]; + cv::Point3d allmax = this->threshold[1]; + + + this->window.showWidget("side1", cv::viz::WCylinder(cv::Point3d(allmin.x, allmin.y, allmin.z), cv::Point3d(allmax.x, allmin.y, allmin.z), 10, 30, color)); + this->window.showWidget("side2", cv::viz::WCylinder(cv::Point3d(allmin.x, allmin.y, allmin.z), cv::Point3d(allmin.x, allmax.y, allmin.z), 10, 30, color)); + this->window.showWidget("side3", cv::viz::WCylinder(cv::Point3d(allmin.x, allmin.y, allmin.z), cv::Point3d(allmin.x, allmin.y, allmax.z), 10, 30, color)); + this->window.showWidget("side4", cv::viz::WCylinder(cv::Point3d(allmin.x, allmax.y, allmin.z), cv::Point3d(allmin.x, allmax.y, allmax.z), 10, 30, color)); + this->window.showWidget("side5", cv::viz::WCylinder(cv::Point3d(allmin.x, allmax.y, allmin.z), cv::Point3d(allmax.x, allmax.y, allmin.z), 10, 30, color)); + this->window.showWidget("side6", cv::viz::WCylinder(cv::Point3d(allmin.x, allmax.y, allmax.z), cv::Point3d(allmin.x, allmin.y, allmax.z), 10, 30, color)); + this->window.showWidget("side7", cv::viz::WCylinder(cv::Point3d(allmin.x, allmax.y, allmax.z), cv::Point3d(allmax.x, allmax.y, allmax.z), 10, 30, color)); + this->window.showWidget("side8", cv::viz::WCylinder(cv::Point3d(allmax.x, allmax.y, allmax.z), cv::Point3d(allmax.x, allmax.y, allmin.z), 10, 30, color)); + this->window.showWidget("side9", cv::viz::WCylinder(cv::Point3d(allmax.x, allmax.y, allmax.z), cv::Point3d(allmax.x, allmin.y, allmax.z), 10, 30, color)); + this->window.showWidget("side10", cv::viz::WCylinder(cv::Point3d(allmax.x, allmin.y, allmax.z), cv::Point3d(allmin.x, allmin.y, allmax.z), 10, 30, color)); + this->window.showWidget("side11", cv::viz::WCylinder(cv::Point3d(allmax.x, allmin.y, allmax.z), cv::Point3d(allmax.x, allmin.y, allmin.z), 10, 30, color)); + this->window.showWidget("side12", cv::viz::WCylinder(cv::Point3d(allmax.x, allmax.y, allmin.z), cv::Point3d(allmax.x, allmin.y, allmin.z), 10, 30, color)); +} + +//-----setTopicNames------// +/* +Make sure that newTopicNames is a size of nonZero, if it is size zero, return false, bad list + +Unsubscribe to all topics before doing anything to the new ones. + +Set class member vector to the newTopics, if its greater than 1 there will be an extra 'blank' at the end from parsing the space separated string + +Make the unordered_map entry first before subscribing + +Set currentPoints to fit the new amount of topics +*/ +bool openCvWrapper::setTopicNames(std::vector newTopicNames) { + if (newTopicNames.size() == 0) { + return false; + } + + this->unsubscribeTopics(); + + this->topicNames = newTopicNames; + + this->currentPoints = std::vector>(this->topicNames.size()); + + for (auto iter: this->topicNames) { + this->cameraSources[iter] = new msg; + mosquittoWrapper.subscribe((char*)iter.c_str()); + //Debugging to ensure which topics the visualizer has subscribed to + //std::cout <<"|" < openCvWrapper::getIndexNames() { + return this->topicNames; +} + +//-----unsubscribeTopics------// +/* +Checks that there are topic names (must have been subscribed already), error out if zero + +Go through the list and unsubscribe from them all, obtain the lock and delete everything. This is a blocking lock to ensure no thread is accessing the current message. + +Clear out the rest of the vectors +*/ +bool openCvWrapper::unsubscribeTopics() { + if (this->topicNames.size() == 0) { + return false; + } + + for (auto iter : this->topicNames) { + mosquittoWrapper.unsubscribe((char*)iter.c_str()); + this->cameraSources[iter]->mut.lock(); + this->cameraSources[iter]->mut.unlock(); + delete this->cameraSources[iter]; + } + + this->topicNames.clear(); + this->cameraSources.clear(); + this->currentPoints.clear(); + + return true; +} + +void openCvWrapper::drawText(std::string text, std::string widgetName, float widthPercent, float heightPercent, int textSize) { + cv::Size s = this->window.getWindowSize(); + cv::Point point((int)(s.width * widthPercent), (int)(s.height * heightPercent)); + cv::viz::WText textWidget(text, point, textSize); + this->window.showWidget(widgetName, textWidget); +} + +//-----isDone, setDone, isRestart, setRestart------// +/* +Simple getters and setters that manage program state +*/ +bool openCvWrapper::isDone() { + return this->done; +} + +bool openCvWrapper::setDone(bool toSet) { + return this->done = toSet; +} + +bool openCvWrapper::isRestart() { + return this->restart; +} + +bool openCvWrapper::setRestart(bool toSet) { + return this->restart = toSet; +} + +//-------------------------------private functions-------------------------------// + +//-----makeWidget------// +/* +Put the point cloud up into the viz window with the color decided from createWidgets +*/ +void openCvWrapper::makeWidget(std::vector& points, std::string widgetName, cv::viz::Color color) { + if (points.size() == 0) { + return; + } + cv::viz::WCloud cloudWidget(points, color); + this->window.showWidget(widgetName, cloudWidget); +} diff --git a/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/windowWrapper.h b/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/windowWrapper.h new file mode 100644 index 00000000..cb4e13e3 --- /dev/null +++ b/streaming-pointcloud/Mqtt visualizer/Mqtt visualizer/windowWrapper.h @@ -0,0 +1,61 @@ +#pragma once +#include +#include +#include +#include +#include "../packages/TOMLParser-master/toml.hpp" +#include "mqtt.h" +#include + +//-----openCvWrapper------// +/* +This class is used in order to wrap the cv::viz library into an easier to use API. +Just has the basic functionality of taking a couple different vectors of data types +and converting them into the cv::Point3d type so it can be used with the cv::viz::WCloud +*/ +class openCvWrapper { +public: + openCvWrapper(); + openCvWrapper(std::string windowName); + ~openCvWrapper(); + bool setName(std::string windowName); + bool getWindowByName(std::string windowName); + bool showWindow(); + bool showWindow(int ms, bool redraw = false); + bool importPoints(std::string index, msg& message); + int createWidgets(); + void clearAllWidgets(); + void clearWidgetByName(std::string widgetName); + bool wasStopped(); + bool setBackgroundColor(cv::viz::Color color = cv::viz::Color::white()); + void resetCamera(); + void registerKeyboardCallback(cv::viz::Viz3d::KeyboardCallback callback); + void sphere(double size); + bool parseArgs(toml::Table table); + void drawThreshold(cv::viz::Color color = cv::viz::Color::amethyst()); + bool setTopicNames(std::vector newTopicNames); + std::vector getIndexNames(); + bool unsubscribeTopics(); + void drawText(std::string text, std::string widgetName, float widthPercent = 0.0, float heightPercent = 0.0, int textSize = 16); + void drawHelpText(std::string widgetName); + bool isActiveTopic(std::string topic); + bool isDone(); + bool setDone(bool toSet); + bool isRestart(); + bool setRestart(bool toSet); + + +private: //functions + void makeWidget(std::vector& points, std::string widgetName, cv::viz::Color color = cv::viz::Color::white()); + +private: //variables + cv::viz::Viz3d window; //Window holds the cv::viz::Viz3d window instance + std::string windowName; //Window name stores the window's name + std::vector threshold; + std::vector topicNames; + std::unordered_map cameraSources; + std::vector> currentPoints; + //Program state variables + bool done; + bool restart; +}; \ No newline at end of file diff --git a/streaming-pointcloud/Mqtt visualizer/README.md b/streaming-pointcloud/Mqtt visualizer/README.md new file mode 100644 index 00000000..69705e0b --- /dev/null +++ b/streaming-pointcloud/Mqtt visualizer/README.md @@ -0,0 +1,119 @@ +# Point Cloud Visualizer + +## Introduction + +The Point Cloud Visualizer will display multiple kinect capture sources and show the depth data. The visualizer will also adjust/calibrate the camera's coordinate system into the real world coordinate system by keypresses. + +**Note:** This application provides a visualizer for the depth data source(s) and does not do much by itself. It's meant to be used as a calibration and debugging tool. + +# Prerequisites + +In order to use this application, you will need the following: + +1. An MQTT broker such as [Mosquitto](https://mosquitto.org/download) +1. The executable `'Mqtt visualizer.exe'` which is available in this repository or can be compiled from the source. +1. The executable `'merger.exe'` which is also available in this repository or can be combiled from the source. + + +# Usage +This is a command line application that also has a GUI visualization window. The program does not take any command line arguments. +``` +'Mqtt visualizer.exe' +``` + + +# Configuration +For configuration, the application will look for a file named `settings.toml`. + +## Settings TOML +The contents of the TOML file are as follows: + +| Property | Description | Values | +| -------- | ----------- | ------ | +|`unit`| amount to shift the point cloud by a single keypress (in millimeter) | Any whole integer| +|`merged`| Choose between viewing cameras individually or the merged point cloud | `true` or `false`| + + +## [MqttInfo] Section + +Connection settings for the MQTT client are stored in the `[MqttInfo]` section. + +| Property | Description | +| -------- | ----------- | +| `host` | the IP address of the MQTT broker | +| `port` | the port for the MQTT broker (typically this is 1883) | +| `id` | the MQTT client ID for this application (this must be unique among clients). | +| `topic` | the MQTT topic upon which the depth frames will be published. | +| `keepalive` | The MQTT keepalive interval, in seconds | +| `clean_session` | The `clean_session` value to use when connecting to the broker (see MQTT spec) + +### [Threshold] Section + +Threshold settings are used to visualize the bounding box that the `kinect Capture` software uses for the culling points. This is not the actual bounding box for culling points, it is a debugging representation on the thresholding for the sources. + +| Property | Description | +| -------- | ----------- | +| `min` | The minimum X, Y, and Z boundary, in millimeters, for bounding box. | +| `max` | The maximum X, Y, and Z boundary, in millimeters, for bounding box. | + + +# Point cloud manipulation + +![Coordinate system for the Microsoft Kinect for Azure](https://docs.microsoft.com/en-us/azure/kinect-dk/media/concepts/concepts-coordinate-systems/coordinate-systems-camera-features.png) + +| Key | Description of command | +| --- | ---------------------- | +| ↑ | Move the point cloud up | +| ↓ | Move the point cloud down | +| → | Move the point cloud right | +| ← | Move the point cloud left | +| Home | Move the point cloud away (positive z) | +| End | Move the point cloud closer (negative z) | +| 8 | Move the point cloud counter clockwise along the x axis | +| 2 | Move the point cloud clockwise along the x axis | +| 4 | Move the point cloud counter clockwise along the y axis | +| 6 | Move the point cloud clockwise along the y axis | +| 7 | Move the point cloud counter clockwise along the z axis | +| 9 | Move the point cloud clockwise along the z axis | + +If viewing the camera sources individually, they will show the following color (not the actual color of the rgb points) for their assigned ordering: +| Device Number | Color | +| ------------- | ----- | +| 1 | red | +| 2 | green | +| 3 | blue | +| 4+ | white | + +**Note:** If there is only one color present, but multiple cameras going, the viewer is set to look at the merged point cloud + +# Keybindings +In addition to the point cloud manipulation commands, the visualizer has some other helpful commands present. + +| Key | Description of command | +| :---: | ---------------------- | +| Q | Exit out of the program | +| L | Have `kinect Capture` applications save their transformations | +| N | Toggle onscreen help text | +| M | Restart the programs without closing | +| TAB | Cycle active selected camera | +| H | Display the help text in the terminal | + + # Compiling from Source +To compile this application from source, you will need the following: + ++ Visual Studio 2019 with MSVC v142 or greater + ++ Install the following packages via [Vcpkg](https://github.com/microsoft/vcpkg) + + boost:x64-windows + + mosquitto:x64-windows + + opencv[contrib,core,vtk]:x64-windows + ++ If you experience problems compiling the projects related to the Kinect SDK or libraries, it may be that you need to manually add the Microsoft Azure Kinect Sensor package. You can do this from within Visual Studio via the Nuget Package Manager. + + In Visual Studio, open the `Tools` menu and select `NuGet Package Manager > Manage NuGet Packages for Solution...` + + Search for `Microsoft.Azure.Kinect.Sensor` and install it. + ++ [TomlParser](https://github.com/ToruNiina/TOMLParser) Library + + Download or clone the repository and copy the contents to ```packages/``` + + Insert ```#pragma warning(disable : 4996) //_CRT_SECURE_NO_WARNINGS``` to the top of ```src/toml_parser.hpp``` + +Once you have all of these prerequisites, open `Mqtt visualizer.sln` in Visual Studio to build the application. \ No newline at end of file diff --git a/streaming-pointcloud/Mqtt visualizer/Release.zip b/streaming-pointcloud/Mqtt visualizer/Release.zip new file mode 100644 index 00000000..f237bc48 Binary files /dev/null and b/streaming-pointcloud/Mqtt visualizer/Release.zip differ diff --git a/streaming-pointcloud/README.md b/streaming-pointcloud/README.md new file mode 100644 index 00000000..d849e6de --- /dev/null +++ b/streaming-pointcloud/README.md @@ -0,0 +1,50 @@ +# Azure Kinect Multicamera Streaming + +This example project consists of a set of applications to align multiple Azure Kinect cameras, capture depth data (point cloud frames), merge the frames from multiple cameras together, and forward them on to be consumed and rendered by third party applications like Touch Designer, Unity, or even via webGL. + +![Webgl Screenshot](./docs/visualizer-screenshot.jpg) + +## Overview of Components + +This project made up of from three separate executables which communicate via the MQTT protocol. + +![Timeline for Mqtt events](./docs/kinect-streaming-diagram.png) + +### Kinect Capture +A console application which acquires frames from an Azure Kinect camera, performs translation/rotation of the points (to alignin multiple camers in world space) and sends the frames to the Merger to be combined with data from any other cameras in the system. + +### Merger +A console application which receives frames from one or more `Kinect Capture` instances and combines them into a single frame which is broadcast to 3rd party applications for rendering. + +### Visualizer +This application is used for debugging and calibration of the system. It will display the active depth frames and provides keyboard controls to adjust the alignment of the individual `Kinect Capture` sources. This application is only used for debugging and calibration and is not typically needed once the system is set up and running. + + +## Usage Examples + +There are three examples in this project whic render the output from this system (the merged frames). + +### Unity + +An example Unity project which renders the frames as dynamic particle systems using the new Visual Effects graph. + + +### TouchDesigner + +A custom Touch Designer plugin and example network to render frames as particles. + + +### WebGL (THREE.js) + +A simple node.js application which creates a bridge between MQTT and websockets to send frames to a web browser and render them via THREE.js. + + + +## Documentation + +You will find a README file in each project and example within this repository. Additionally, the following documents are available: + + * [Setting Up](./docs/setup.md) + * [Networking and Binary Message Structure](./docs/networking.md) + * [Building and Development Environment](./docs/building.md) + * [Troubleshooting](./docs/troubleshooting.md) \ No newline at end of file diff --git a/streaming-pointcloud/TOMLParser-master.zip b/streaming-pointcloud/TOMLParser-master.zip new file mode 100644 index 00000000..5b07777a Binary files /dev/null and b/streaming-pointcloud/TOMLParser-master.zip differ diff --git a/streaming-pointcloud/docs/AzureKinectDiagram.png b/streaming-pointcloud/docs/AzureKinectDiagram.png new file mode 100644 index 00000000..8b3cde35 Binary files /dev/null and b/streaming-pointcloud/docs/AzureKinectDiagram.png differ diff --git a/streaming-pointcloud/docs/building.md b/streaming-pointcloud/docs/building.md new file mode 100644 index 00000000..3da3ab3a --- /dev/null +++ b/streaming-pointcloud/docs/building.md @@ -0,0 +1,76 @@ +# Building + +You can find detailed documentation for each of the specific components in their respective README files, however there are several commonalities and shared requirements among the projects which are described here. + +## Vcpkg + +You may install and build the required libraries manually but it is simpler to use the [Vcpkg](https://github.com/microsoft/vcpkg) package management tool provided by Microsoft. + +### Installing and Setting up Vcpkg + +You can install Vcpkg via the command line using the following steps: + +| Powershell command | Description | +|--------------------|-------------| +|`'git clone git@github.com:microsoft/vcpkg.git'` | Clone the repo | +|`'cd vcpkg'` | Change to the vcpkg directory | +|`'.\bootstrap-vcpkg.bat'` | Run the bootstrapper | +|`'.\vcpkg.exe integrate install'` | Set the PATH for visual studio | + +After running `vcpkg.exe integrate install` you should see the following: +``` +PS C:\vcpkg> .\vcpkg.exe integrate install +Applied user-wide integration for this vcpkg root. + +All MSBuild C++ projects can now #include any installed libraries. +Linking will be handled automatically. +Installing new libraries will make them instantly available. + +CMake projects should use: "-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake" +``` + + +### Installing the libraries + +Once you have installed Vcpkg, you can install the dependencies for building the various C++ projects. + +| Powershell command | Description | +|--------------------|-------------| +| `.\vcpkg.exe install boost:x64-windows` | Install 64-bit version of Boost | +| `.\vcpkg.exe install eigen3:x64-windows` | Install 64-bit version of Eigen3 | +| `.\vcpkg.exe install mosquitto:x64-windows` | Install 64-bit version of mosquitto | +| `.\vcpkg.exe install opencv[contrib,core,vtk]:x64-windows` | Install 64-bit version of Opencv (May take time) | + +After installing these libraries, run the following command prior to opening Visual Studio: + +`vcpky.exe integrate install` + +## Visual Studio 2019 + +This respository includes the source code and Visual Studio solutions to be used with Visual Studio 2019. You must ensure that you have the + +### MSCV v142 + +To ensure that MSCV v142 is installed on the machine, open `Visual Studio Installer` and click `modify` within `Visual Studio 2019` + +Go to the `Individual components` tab located at the top and search for `MSVC v142 - VS 2019 C++ x64/x86 build tools (v14.20)` + +Click `Modify` at the bottom right of the screen and wait for the installer to finish + +### NuGet - Install the Azure Kinect Package + +If you experience problems compiling the projects related to the Kinect SDK or libraries, it may be that you need to manually add the Microsoft Azure Kinect Sensor package. You can do this from within Visual Studio via the Nuget Package Manager. + +To get there open the `Tools` menu and select `NuGet Package Manager > Manage NuGet Packages for Solution... > Search` + +Search for `Microsoft.Azure.Kinect.Sensor` and install it. + +## Toml Parser + +This project uses Toml files to store configuration, to build the project you will need to place the [TomlParser](https://github.com/ToruNiina/TOMLParser) source in the `packages` folder of each project you wish to build. In order to avoid warnings when building the project, you will need to modify the Toml source code as follows: + +Edit `src/toml_parser.hpp` and add the following line to the top of the file: + +```#pragma warning(disable : 4996) //_CRT_SECURE_NO_WARNINGS``` + +There is a zipped up version of the github repo used for the [TomlParser](https://github.com/ToruNiina/TOMLParser) availble at the root directory which already contains this modification. diff --git a/streaming-pointcloud/docs/kinect-streaming-diagram.png b/streaming-pointcloud/docs/kinect-streaming-diagram.png new file mode 100644 index 00000000..49a11f97 Binary files /dev/null and b/streaming-pointcloud/docs/kinect-streaming-diagram.png differ diff --git a/streaming-pointcloud/docs/networking.md b/streaming-pointcloud/docs/networking.md new file mode 100644 index 00000000..b221f18b --- /dev/null +++ b/streaming-pointcloud/docs/networking.md @@ -0,0 +1,49 @@ +# Networking + +This system communicates via MQTT. This includes the stream of depth frames as well as control signals for camera calibration. Each application must be configured with the address and port of an available MQTT broker (such as [mosquitto](https://mosquitto.org/)). + +**NOTE:** Due to the high bandwith requirements it is strongly recommended that you run an MQTT broker on your local network and use wired connections rather than WIFI. + + +# Startup Sequence + +When starting up the different components of the system, some configuration data needs to be exchanged between the `merger` and `Kinect Capture` applications (such as the MQTT topic upon which frames will be broadcast, and the camera settings like resolution and frame rate). + + Once this startup sequence is complete, frames will be sent from the `Kinect Capture` application (or applications, if there are multiple instances running). These frames will be combined by the `merger` and broadcast to other applications to be rendered. + +The following diagram illustrates this startup sequence with a single `Kinect Capture` instance, but this same sequence follows for multiple cameras as well. + +![Startup sequence and frame loop](./startup-sequence.png) + + +# Point Cloud Message Structure + +Each camera frame consists of a small header followed by the 3D points, then the optional RGB color data. + +![Packet Structure](./packet-structure.png) + + +## Message Header + +The first 13 bytes of each frame are the header + +| Bytes | Data Type | Description | +| --------- | --------- | ----------- | +| 0 - 7 | unsigned 64 bit integer | Frame time stamp | +| 8 - 11 | unsigned 32 bit integer | The number of points in the frame | +| 12 | unsigned 8 bit integer | Treated as a boolean, indicates if color data is present | + + +## Message Body + +After the header, the remaining contents in the message will be the 3D position of each point, optionally followed by the RGB color of each point (byte 12 of the header indicates if color data is present or not). + +Each point position consists of three 16 bit signed integers (the X, Y, and Z coordinates, in millimeters). Therefore each point will occupy 6 bytes of space in the message body. + +If color data is present, each point will include 3 bytes of color data representing the red, green, and blue values for the point. As illustrated in the message structure diagram, the message body will contain _ALL_ of the 3D position data in one contiguous block, optionally followed by _ALL_ of the RGB color data. + +If color data is present, you can compute the byte offset where color data begins in the message by the following formula: + +```color data byte offset = 13 + (point count * 6)``` + +Once you have computed the byte offset you can begin reading the RGB color values from that point in the message. \ No newline at end of file diff --git a/streaming-pointcloud/docs/packet-structure.png b/streaming-pointcloud/docs/packet-structure.png new file mode 100644 index 00000000..f196c90c Binary files /dev/null and b/streaming-pointcloud/docs/packet-structure.png differ diff --git a/streaming-pointcloud/docs/setup.md b/streaming-pointcloud/docs/setup.md new file mode 100644 index 00000000..39752210 --- /dev/null +++ b/streaming-pointcloud/docs/setup.md @@ -0,0 +1,71 @@ +# Azure Kinect Point Cloud Streaming + +This project will capture and merge 3D points (including RGB color for each point) from multiple Azure Kinect cameras and broadcast the resulting point cloud via MQTT for use in other applications. + +## MQTT Broker + +The components in this system communicate via MQTT so they will need to connect to an MQTT broker such as [Mosquitto](https://mosquitto.org/download/). The bandwidth required may be quite high so it is recommended to run a dedicated broker on a local wired network. + +## Applications + +The system is comprised of three applications which work in concert to capture, configure, merge, and transmit depth data (point cloud frames) to be rendered in 3rd-party applications. The three applications are as follows: + +### Kinect capture +This application connects to the Azure Kinect to read the depth data, applies translation, rotation, and min/max thresholding, then sends the point data to the Merger. There should be one instance of this app for each Azure Kinect. + +`kinect capture\kinect capture.exe` + +### Merger +The merger application receives depth data from one or more capture instances and combines the points into single frames, then broadcasts the resulting merged set of points out over MQTT to be used in 3rd party applications. + +`merger\merger.exe` + +### Visualizer +This application is used to preview the merged point cloud and adjust the relative alignment of data from multiple cameras. The viewer application is only needed for debugging and configuration/calibration. Once the system is set up correctly this application is not needed for normal use. + +`viewer\Mqtt visualizer.exe` + + +# Physical Setup and Launch + +## 1. Prepare MQTT Broker + +Verify that your MQTT broker is running, this can be on the local computer or a remote computer so long as the network can handle a high volume of traffic (a dedicated wired network is recommended). + + +## 2.a Using a Single Azure Kinect + +With a single Azure Kinect, you only need to connect the device normally (via a USB 3.0 port, and the power cable). + + +## 2.b Using Multiple Azure Kinects + +If you are using multiple Azure Kinects it's recommended that you arrange them radially and aimed inward at a central point. This will give good coverage from multiple points of view around your subject. + +For the best performance, connect all of the cameras to the same computer if possible, and run all of the applications on that same computer. If multiple computers are used, a wired gigabit network is recommended. When using multiple Azure Kinects, you must first determine the master/subordinate configuration and connect the sync cables accordingly. + + +1. To access the sync in and sync out ports, remove the white plastic housings using the torx wrench that was included with the Azure Kinect. The sync ports are located on the back of the device on either side of the USB and power ports. + +1. Decide which Azure Kinect will be designated as the **master** and daisy chain the devices (using standard 3.5mm audio cables) so the sync-out port of the master connects to the next Azure Kinect sync-in port. + +1. Connect the sync-out port of each Azure Kinect to the sync-in port of the next device until all the devices are connected. + + +### 3. Run the `Merger` application + +The merger application should be running before any of the kinect capture applications are launched. + + +### 4. Run the `Kinect Capture` application(s) + +Run the `kinect capture` application. + +**NOTE:** If you are using multiple Azure Kinects, start the `kinect capture` instances of all **subordinate** devices first, and the **master** device last. This will ensure that frame synchronization is enabled. + + + + +### 5. Run the `visualizer` application + +You should see a 3D preview of the points in the Visualizer window. If you do, the system is working and the point cloud data is being broadcast correctly on the MQTT topic `points/pointmerger`. \ No newline at end of file diff --git a/streaming-pointcloud/docs/startup-sequence.png b/streaming-pointcloud/docs/startup-sequence.png new file mode 100644 index 00000000..12783a3b Binary files /dev/null and b/streaming-pointcloud/docs/startup-sequence.png differ diff --git a/streaming-pointcloud/docs/troubleshooting.md b/streaming-pointcloud/docs/troubleshooting.md new file mode 100644 index 00000000..e3866dcd --- /dev/null +++ b/streaming-pointcloud/docs/troubleshooting.md @@ -0,0 +1,49 @@ +# Troubleshooting Tips + +## The programs are saying they can't connect: + +Ensure that the MQTT broker is actively running. + +## Can't connect to a camera: + +Ensure that the camera is properly connected and try viewing the camera(s) through the [Microsoft Kinect for Azure SDK](https://docs.microsoft.com/en-us/azure/kinect-dk/sensor-sdk-download) + +You can run multiple instances of the Azure Kinect Viewer to verify that multiple Azure Kinect cameras can be run at the same time on your system (not all USB controllers work well with more than a single camera). + +## Camera and merger are sending 0 points: + +The camera may be configured such that all of the 3D points fall outside of the culling boundaries, try adjusting the camera position in the visualizer to see if this is the case. + +Alternatively, you can increase the size of the bounding box (via `min` and `max` in the cameraposition.toml file). Make sure to change the threshold back to a reasonable size (if desired) once you have adjusted the camera to center the content correctly. + +## No points present in the visualizer: + +Look at the top left of the screen to see if the pointCount is zero and it is showing cameras connected, try moving a camera source around in space. + +If there are no camera sources shown on the left side, pressing `M` will restart the system in the event that the viewer did not recieve the proper camera source(s). + +Using the default settings, _usually_ the camera is too far forward, pressing `End` will bring the camera into frame if that is the case. + +## Visualizer is not seeing all cameras: + +Restart the system by pressing `M` to restart the system and allow for the visualizer to recieve the required startup messages from all of the cameras which may have been missed previously due to start up timing/sequencing. + +## Visualizer wireframe thresholding box is not accurate + +The thresholding box on the visualizer is simply a visual guide to align the cameras to a level space (i.e, the ground). The size of this wireframe box is not guaranteed to be the same as the min/max boundaries of each camera. If the min/max values of the visualizer and camera are not the same, they will not be aligned in the viewport. + +## Merger isn't sending points while some cameras are running: + +The Merger will only send points when it recieves a frame from each camera it has subscribed to. If one of the cameras stops sending points for some reason, the merger will stop sending frames since it will be waiting for the unresponsive camera. + +If a camera has become unresponsive, try restarting the system (the `M` key in the the visualizer window). + +## Visual studio says it can't find the libraries installed from Vcpkg: + +Ensure that the target architecture is set to x64. + +Ensure that you have run `vcpkg integrate install` after installing the dependencies, then restart Visual Studio. + +## The program is running slowly + +These applications rely heavily on compiler optimization to perform well, ensure that Visual Studio build configuration is set to `release` and not `debug`. \ No newline at end of file diff --git a/streaming-pointcloud/docs/visualizer-screenshot.jpg b/streaming-pointcloud/docs/visualizer-screenshot.jpg new file mode 100644 index 00000000..376874df Binary files /dev/null and b/streaming-pointcloud/docs/visualizer-screenshot.jpg differ diff --git a/streaming-pointcloud/examples/README.md b/streaming-pointcloud/examples/README.md new file mode 100644 index 00000000..e6ab7f7b --- /dev/null +++ b/streaming-pointcloud/examples/README.md @@ -0,0 +1,7 @@ +# Usage Examples + +These are example applications which make use of the merged output. + +* [Touch Designer](./td) +* [Unity VFXGraph](./Unity) +* [WebGL via THREE.js](./threejs) \ No newline at end of file diff --git a/streaming-pointcloud/examples/Unity/.gitignore b/streaming-pointcloud/examples/Unity/.gitignore new file mode 100644 index 00000000..bf638eb9 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/.gitignore @@ -0,0 +1,38 @@ +[Ll]ibrary/ +[Tt]emp/ +[Oo]bj/ +[Bb]uild/ +[Bb]uilds/ +Assets/AssetStoreTools* + +!*.meta + +# Visual Studio cache directory +.vs/ + +# Autogenerated VS/MD/Consulo solution and project files +ExportedObj/ +.consulo/ +*.csproj +*.unityproj +*.sln +*.suo +*.tmp +*.user +*.userprefs +*.pidb +*.booproj +*.svd +*.pdb +*.opendb + +# Unity3D generated meta files +*.pidb.meta +*.pdb.meta + +# Unity3D Generated File On Crash Reports +sysinfo.txt + +# Builds +*.apk +*.unitypackage diff --git a/streaming-pointcloud/examples/Unity/Assets/Plugins.meta b/streaming-pointcloud/examples/Unity/Assets/Plugins.meta new file mode 100644 index 00000000..97c18c77 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cef722e20ff808d4790c07ea0593a1b9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/streaming-pointcloud/examples/Unity/Assets/Plugins/MQTTnet.dll b/streaming-pointcloud/examples/Unity/Assets/Plugins/MQTTnet.dll new file mode 100644 index 00000000..ef1c4a15 Binary files /dev/null and b/streaming-pointcloud/examples/Unity/Assets/Plugins/MQTTnet.dll differ diff --git a/streaming-pointcloud/examples/Unity/Assets/Plugins/MQTTnet.dll.meta b/streaming-pointcloud/examples/Unity/Assets/Plugins/MQTTnet.dll.meta new file mode 100644 index 00000000..82691763 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/Plugins/MQTTnet.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 03cbf7de17fdc41428931fbc14af54cd +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/streaming-pointcloud/examples/Unity/Assets/Plugins/System.Buffers.dll b/streaming-pointcloud/examples/Unity/Assets/Plugins/System.Buffers.dll new file mode 100644 index 00000000..c517a3b6 Binary files /dev/null and b/streaming-pointcloud/examples/Unity/Assets/Plugins/System.Buffers.dll differ diff --git a/streaming-pointcloud/examples/Unity/Assets/Plugins/System.Buffers.dll.meta b/streaming-pointcloud/examples/Unity/Assets/Plugins/System.Buffers.dll.meta new file mode 100644 index 00000000..1d762273 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/Plugins/System.Buffers.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: cb0bd3d59b01e5849b2251f3e7205570 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/streaming-pointcloud/examples/Unity/Assets/Prefabs.meta b/streaming-pointcloud/examples/Unity/Assets/Prefabs.meta new file mode 100644 index 00000000..2452dfaa --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dc6da43b7b21254478c3b1132c947285 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/streaming-pointcloud/examples/Unity/Assets/Prefabs/StreamingPoints.prefab b/streaming-pointcloud/examples/Unity/Assets/Prefabs/StreamingPoints.prefab new file mode 100644 index 00000000..dd47fdb5 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/Prefabs/StreamingPoints.prefab @@ -0,0 +1,147 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1013343643317854087 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1013343643317854089} + - component: {fileID: 1013343643317854092} + - component: {fileID: 1013343643317854088} + - component: {fileID: 1013343643317854091} + - component: {fileID: 1013343643317854090} + m_Layer: 0 + m_Name: StreamingPoints + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1013343643317854089 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1013343643317854087} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1013343643317854092 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1013343643317854087} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f77e166531485294aaa58e17e5385ce9, type: 3} + m_Name: + m_EditorClassIdentifier: + Broker: 127.0.0.1 + Port: 1883 + Topic: points/pointmerger + pointLoader: {fileID: 1013343643317854088} +--- !u!114 &1013343643317854088 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1013343643317854087} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 65e26582ff8e9c04a95446fef4f6cacb, type: 3} + m_Name: + m_EditorClassIdentifier: + debugImage: {fileID: 0} + PointCount: 0 + effect: {fileID: 1013343643317854090} + PositionTextureName: PositionMap + ColorTextureName: ColorMap +--- !u!73398921 &1013343643317854091 +VFXRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1013343643317854087} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 0 + m_LightProbeUsage: 0 + m_ReflectionProbeUsage: 0 + m_RayTracingMode: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!2083052967 &1013343643317854090 +VisualEffect: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1013343643317854087} + m_Enabled: 1 + m_Asset: {fileID: 8926484042661614526, guid: cf9ac41df9d70eb4e864b63085235543, type: 3} + m_InitialEventName: OnPlay + m_InitialEventNameOverriden: 0 + m_StartSeed: 0 + m_ResetSeedOnPlay: 1 + m_PropertySheet: + m_Float: + m_Array: [] + m_Vector2f: + m_Array: [] + m_Vector3f: + m_Array: [] + m_Vector4f: + m_Array: [] + m_Uint: + m_Array: [] + m_Int: + m_Array: [] + m_Matrix4x4f: + m_Array: [] + m_AnimationCurve: + m_Array: [] + m_Gradient: + m_Array: [] + m_NamedObject: + m_Array: + - m_Value: {fileID: 2800000, guid: 276d9e395ae18fe40a9b4988549f2349, type: 3} + m_Name: PositionMap + m_Overridden: 0 + m_Bool: + m_Array: [] diff --git a/streaming-pointcloud/examples/Unity/Assets/Prefabs/StreamingPoints.prefab.meta b/streaming-pointcloud/examples/Unity/Assets/Prefabs/StreamingPoints.prefab.meta new file mode 100644 index 00000000..470ef210 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/Prefabs/StreamingPoints.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 39908e4cb384bb547b5e94c2118b6bbd +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/streaming-pointcloud/examples/Unity/Assets/Scenes.meta b/streaming-pointcloud/examples/Unity/Assets/Scenes.meta new file mode 100644 index 00000000..310eefa8 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dd5489dbf35266640abcdee82adb1847 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/streaming-pointcloud/examples/Unity/Assets/Scenes/SampleScene.unity b/streaming-pointcloud/examples/Unity/Assets/Scenes/SampleScene.unity new file mode 100644 index 00000000..8d6bf2f9 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/Scenes/SampleScene.unity @@ -0,0 +1,652 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 705507994} + m_IndirectSpecularColor: {r: 0.44657874, g: 0.49641258, b: 0.5748172, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &89383192 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 89383193} + - component: {fileID: 89383195} + - component: {fileID: 89383194} + m_Layer: 5 + m_Name: RawImage + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &89383193 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 89383192} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1988735297} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 300, y: 300} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &89383194 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 89383192} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Texture: {fileID: 0} + m_UVRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 +--- !u!222 &89383195 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 89383192} + m_CullTransparentMesh: 0 +--- !u!1 &705507993 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 705507995} + - component: {fileID: 705507994} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &705507994 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 705507993} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 1 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &705507995 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 705507993} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &947975261 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 947975262} + - component: {fileID: 947975263} + m_Layer: 0 + m_Name: Orbit + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &947975262 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 947975261} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 963194228} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &947975263 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 947975261} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7755da38630b1db4998af21f1ebafa90, type: 3} + m_Name: + m_EditorClassIdentifier: + speed: 5 +--- !u!1 &963194225 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 963194228} + - component: {fileID: 963194227} + - component: {fileID: 963194226} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &963194226 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 +--- !u!20 &963194227 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0, g: 0, b: 0, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.01 + far clip plane: 1000 + field of view: 65 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &963194228 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_LocalRotation: {x: 0, y: 1, z: 0, w: 0} + m_LocalPosition: {x: 0, y: 1, z: 5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 947975262} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0} +--- !u!1 &1600005066 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1600005069} + - component: {fileID: 1600005068} + - component: {fileID: 1600005067} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1600005067 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1600005066} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &1600005068 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1600005066} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &1600005069 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1600005066} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1988735293 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1988735297} + - component: {fileID: 1988735296} + - component: {fileID: 1988735295} + - component: {fileID: 1988735294} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!114 &1988735294 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1988735293} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &1988735295 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1988735293} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!223 &1988735296 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1988735293} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &1988735297 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1988735293} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 89383193} + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!1001 &1013343644018545264 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 1013343643317854087, guid: 39908e4cb384bb547b5e94c2118b6bbd, + type: 3} + propertyPath: m_Name + value: StreamingPoints + objectReference: {fileID: 0} + - target: {fileID: 1013343643317854089, guid: 39908e4cb384bb547b5e94c2118b6bbd, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1013343643317854089, guid: 39908e4cb384bb547b5e94c2118b6bbd, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1013343643317854089, guid: 39908e4cb384bb547b5e94c2118b6bbd, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1013343643317854089, guid: 39908e4cb384bb547b5e94c2118b6bbd, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1013343643317854089, guid: 39908e4cb384bb547b5e94c2118b6bbd, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1013343643317854089, guid: 39908e4cb384bb547b5e94c2118b6bbd, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1013343643317854089, guid: 39908e4cb384bb547b5e94c2118b6bbd, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 1013343643317854089, guid: 39908e4cb384bb547b5e94c2118b6bbd, + type: 3} + propertyPath: m_RootOrder + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 1013343643317854089, guid: 39908e4cb384bb547b5e94c2118b6bbd, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1013343643317854089, guid: 39908e4cb384bb547b5e94c2118b6bbd, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1013343643317854089, guid: 39908e4cb384bb547b5e94c2118b6bbd, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1013343643317854091, guid: 39908e4cb384bb547b5e94c2118b6bbd, + type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 39908e4cb384bb547b5e94c2118b6bbd, type: 3} diff --git a/streaming-pointcloud/examples/Unity/Assets/Scenes/SampleScene.unity.meta b/streaming-pointcloud/examples/Unity/Assets/Scenes/SampleScene.unity.meta new file mode 100644 index 00000000..8f2c693c --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/Scenes/SampleScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 5464a1b7442fcea408eb5a025cdddff9 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/streaming-pointcloud/examples/Unity/Assets/Scripts.meta b/streaming-pointcloud/examples/Unity/Assets/Scripts.meta new file mode 100644 index 00000000..daf4c48e --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 17aef43f4730c854c8d1549c0cb4511c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet.meta b/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet.meta new file mode 100644 index 00000000..4781675b --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0a8a3c13bd194bf40a684b707b98bfcc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetClient.cs b/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetClient.cs new file mode 100644 index 00000000..7cd831ce --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetClient.cs @@ -0,0 +1,187 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; +using MQTTnet.Client; +using MQTTnet; +using MQTTnet.Diagnostics; +using System.Threading.Tasks; +using MQTTnet.Client.Options; +using System; +using System.Threading; +using System.Text; +using MQTTnet.Client.Publishing; +using MQTTnet.Client.Receiving; +using System.Collections.Concurrent; + +public class MQTTNetClient : MonoBehaviour +{ + public string Broker; + public int Port; + public string Topic; + private IMqttClient _client; + public PointCloudLoader pointLoader; + + + public class MqttMessage + { + public string path; + public byte[] payload; + } + + //public ConcurrentQueue queue = new ConcurrentQueue(); + + public BlockingCollection queue = new BlockingCollection(new ConcurrentQueue()); + + public bool IsConnected() + { + if (_client == null) return false; + + return _client.IsConnected; + } + + public async void Publish(string topic, string message) + { + try + { + await PublishAsync(topic, message); + } + catch (Exception e) + { + Debug.LogError("[MQTTNetClient] publish error " + e.Message); + } + } + + private async Task PublishAsync(string topic, string message) + { + if (_client != null && _client.IsConnected) + { + + var mqttmsg = new MqttApplicationMessageBuilder() + .WithTopic(topic) + .WithPayload(message) + .Build(); + + MqttClientPublishResult result = await _client.PublishAsync(mqttmsg); + return result; + }else + { + return null; + } + } + + private Thread receiveEventThread; + private bool isRunning; + + public async void Connect() + { + await StartClientAsync().ConfigureAwait(false); + } + + private void ReceiveEventThread() + { + Connect(); + } + + private void Start() + { + // start thread for raising received message event from broker + this.receiveEventThread = new Thread(this.ReceiveEventThread); + this.receiveEventThread.Start(); + + } + + bool aborting; + private void OnDisable() + { + Debug.Log("disconnect"); + aborting = true; + this.receiveEventThread.Abort(); + _client.DisconnectAsync().ConfigureAwait(false); + _client.Dispose(); + } + + private void Update() + { + + bool latest = false; + + MqttMessage message = new MqttMessage(); + while(queue.TryTake(out message, TimeSpan.FromMilliseconds(1))) + { + latest = (queue.Count == 0); + if (latest) + { + pointLoader.LoadPoints(message.payload, message.payload.Length); + } + } + } + + public async Task StartClientAsync() + { + var options = new MqttClientOptionsBuilder() + .WithTcpServer(Broker, Port) + .WithCommunicationTimeout(System.TimeSpan.FromSeconds(5)) + .Build(); + + ((MqttClientTcpOptions)(options.ChannelOptions)).NoDelay = true; + ((MqttClientTcpOptions)(options.ChannelOptions)).BufferSize = 4096 * 1000; + + var adapterFactory = new MQTTnet.Implementations.MQTTNetCustomAdapterFactory(); + + var factory = new MqttFactory(); + _client = factory.CreateMqttClient(adapterFactory); + + /* + _client.UseDisconnectedHandler(async e => + { + if (aborting) return; + + Debug.Log("[MQTTNetClient] Disconnected, reconnect"); + await Task.Delay(TimeSpan.FromSeconds(.5)); + + try + { + await _client.ConnectAsync(options, CancellationToken.None); + } + catch + { + Debug.Log("[MQTTNetClient] reconnect failed"); + } + }); + */ + + _client.UseApplicationMessageReceivedHandler( e => + { + if (aborting) return; + + if (e.ApplicationMessage.Topic == Topic) + { + //Debug.Log($"+ Topic = {e.ApplicationMessage.Topic} {queue.Count}"); + MqttMessage message = new MqttMessage(); + message.path = e.ApplicationMessage.Topic; + message.payload = new byte[e.ApplicationMessage.Payload.Length]; + Array.Copy(e.ApplicationMessage.Payload, 0, message.payload, 0, e.ApplicationMessage.Payload.Length); + + queue.Add(message); + + //pointLoader.LoadPoints(e.ApplicationMessage.Payload); + } + }); + + _client.UseConnectedHandler(async e => + { + if (aborting) return; + + Debug.Log("[MQTTNetClient] connected"); + + await _client.SubscribeAsync(new TopicFilterBuilder().WithTopic( Topic).WithAtMostOnceQoS().Build()); + + Debug.Log("[MQTTNetClient] subscribed"); + }); + + + await _client.ConnectAsync(options, CancellationToken.None).ConfigureAwait(false); + return _client; + } +} diff --git a/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetClient.cs.meta b/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetClient.cs.meta new file mode 100644 index 00000000..4a246f39 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f77e166531485294aaa58e17e5385ce9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetCustomAdapter.cs b/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetCustomAdapter.cs new file mode 100644 index 00000000..b7eb022a --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetCustomAdapter.cs @@ -0,0 +1,338 @@ + +using System; +using System.IO; +using System.Net.Sockets; +using System.Runtime.InteropServices; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; +using MQTTnet.Channel; +using MQTTnet.Diagnostics; +using MQTTnet.Exceptions; +using MQTTnet.Formatter; +using MQTTnet.Internal; +using MQTTnet.Packets; + +namespace MQTTnet.Adapter +{ + public class MQTTNetCustomAdapter : IMqttChannelAdapter + { + private const uint ErrorOperationAborted = 0x800703E3; + //private const int ReadBufferSize = 4096; // TODO: Move buffer size to config + + private readonly SemaphoreSlim _writerSemaphore = new SemaphoreSlim(1, 1); + + private readonly IMqttNetChildLogger _logger; + private readonly IMqttChannel _channel; + private readonly MqttPacketReader _packetReader; + + private readonly byte[] _fixedHeaderBuffer = new byte[2]; + + private bool _isDisposed; + + private long _bytesReceived; + private long _bytesSent; + + public MQTTNetCustomAdapter(IMqttChannel channel, MqttPacketFormatterAdapter packetFormatterAdapter, IMqttNetChildLogger logger) + { + if (logger == null) throw new ArgumentNullException(nameof(logger)); + + _channel = channel ?? throw new ArgumentNullException(nameof(channel)); + PacketFormatterAdapter = packetFormatterAdapter ?? throw new ArgumentNullException(nameof(packetFormatterAdapter)); + + _packetReader = new MqttPacketReader(_channel); + + _logger = logger.CreateChildLogger(nameof(MqttChannelAdapter)); + } + + public int ReadBufferSize = 4096; + + public string Endpoint => _channel.Endpoint; + + public bool IsSecureConnection => _channel.IsSecureConnection; + + public X509Certificate2 ClientCertificate => _channel.ClientCertificate; + + public MqttPacketFormatterAdapter PacketFormatterAdapter { get; } + + public long BytesSent => Interlocked.Read(ref _bytesSent); + public long BytesReceived => Interlocked.Read(ref _bytesReceived); + + public Action ReadingPacketStartedCallback { get; set; } + public Action ReadingPacketCompletedCallback { get; set; } + + public async Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken) + { + ThrowIfDisposed(); + + try + { + if (timeout == TimeSpan.Zero) + { + await _channel.ConnectAsync(cancellationToken).ConfigureAwait(false); + } + else + { + await MqttTaskTimeout.WaitAsync(t => _channel.ConnectAsync(t), timeout, cancellationToken).ConfigureAwait(false); + } + } + catch (Exception exception) + { + if (IsWrappedException(exception)) + { + throw; + } + + WrapException(exception); + } + } + + public async Task DisconnectAsync(TimeSpan timeout, CancellationToken cancellationToken) + { + ThrowIfDisposed(); + + try + { + if (timeout == TimeSpan.Zero) + { + await _channel.DisconnectAsync(cancellationToken).ConfigureAwait(false); + } + else + { + await MqttTaskTimeout.WaitAsync( + t => _channel.DisconnectAsync(t), timeout, cancellationToken).ConfigureAwait(false); + } + } + catch (Exception exception) + { + if (IsWrappedException(exception)) + { + throw; + } + + WrapException(exception); + } + } + + public async Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout, CancellationToken cancellationToken) + { + await _writerSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + try + { + var packetData = PacketFormatterAdapter.Encode(packet); + + if (timeout == TimeSpan.Zero) + { + await _channel.WriteAsync(packetData.Array, packetData.Offset, packetData.Count, cancellationToken).ConfigureAwait(false); + } + else + { + await MqttTaskTimeout.WaitAsync( + t => _channel.WriteAsync(packetData.Array, packetData.Offset, packetData.Count, t), timeout, cancellationToken).ConfigureAwait(false); + } + + Interlocked.Add(ref _bytesReceived, packetData.Count); + + PacketFormatterAdapter.FreeBuffer(); + + _logger.Verbose("TX ({0} bytes) >>> {1}", packetData.Count, packet); + } + catch (Exception exception) + { + if (IsWrappedException(exception)) + { + throw; + } + + WrapException(exception); + } + finally + { + _writerSemaphore.Release(); + } + } + + public async Task ReceivePacketAsync(TimeSpan timeout, CancellationToken cancellationToken) + { + ThrowIfDisposed(); + + try + { + ReceivedMqttPacket receivedMqttPacket; + if (timeout == TimeSpan.Zero) + { + receivedMqttPacket = await ReceiveAsync(cancellationToken).ConfigureAwait(false); + } + else + { + receivedMqttPacket = await MqttTaskTimeout.WaitAsync(ReceiveAsync, timeout, cancellationToken).ConfigureAwait(false); + } + + if (receivedMqttPacket == null || cancellationToken.IsCancellationRequested) + { + return null; + } + + Interlocked.Add(ref _bytesSent, receivedMqttPacket.TotalLength); + + if (PacketFormatterAdapter.ProtocolVersion == MqttProtocolVersion.Unknown) + { + PacketFormatterAdapter.DetectProtocolVersion(receivedMqttPacket); + } + + var packet = PacketFormatterAdapter.Decode(receivedMqttPacket); + if (packet == null) + { + throw new MqttProtocolViolationException("Received malformed packet."); + } + + _logger.Verbose("RX ({0} bytes) <<< {1}", receivedMqttPacket.TotalLength, packet); + + return packet; + } + catch (OperationCanceledException) + { + } + catch (Exception exception) + { + if (IsWrappedException(exception)) + { + throw; + } + + WrapException(exception); + } + + return null; + } + + public void ResetStatistics() + { + Interlocked.Exchange(ref _bytesReceived, 0L); + Interlocked.Exchange(ref _bytesSent, 0L); + } + + private async Task ReceiveAsync(CancellationToken cancellationToken) + { + var readFixedHeaderResult = await _packetReader.ReadFixedHeaderAsync(_fixedHeaderBuffer, cancellationToken).ConfigureAwait(false); + + if (cancellationToken.IsCancellationRequested) + { + return null; + } + + try + { + if (readFixedHeaderResult.ConnectionClosed) + { + return null; + } + + ReadingPacketStartedCallback?.Invoke(); + + var fixedHeader = readFixedHeaderResult.FixedHeader; + if (fixedHeader.RemainingLength == 0) + { + return new ReceivedMqttPacket(fixedHeader.Flags, null, 2); + } + + var body = new byte[fixedHeader.RemainingLength]; + var bodyOffset = 0; + var chunkSize = Math.Min(ReadBufferSize, fixedHeader.RemainingLength); + + if( chunkSize >= ReadBufferSize) + { + UnityEngine.Debug.LogWarning("readbuffer smaller than packet: "+chunkSize); + } + + int count = 0; + do + { + var bytesLeft = body.Length - bodyOffset; + if (chunkSize > bytesLeft) + { + chunkSize = bytesLeft; + } + + var readBytes = await _channel.ReadAsync(body, bodyOffset, chunkSize, cancellationToken).ConfigureAwait(false); + + if (cancellationToken.IsCancellationRequested) + { + return null; + } + + if (readBytes == 0) + { + return null; + } + + bodyOffset += readBytes; + count++; + } while (bodyOffset < body.Length); + + /* + if( count > 1) + { + UnityEngine.Debug.LogWarning($"{body.Length} {count} {body.Length/count}"); + } + */ + + var bodyReader = new MqttPacketBodyReader(body, 0, body.Length); + return new ReceivedMqttPacket(fixedHeader.Flags, bodyReader, fixedHeader.TotalLength); + } + finally + { + ReadingPacketCompletedCallback?.Invoke(); + } + } + + public void Dispose() + { + _isDisposed = true; + + _channel?.Dispose(); + } + + private void ThrowIfDisposed() + { + if (_isDisposed) + { + throw new ObjectDisposedException(nameof(MqttChannelAdapter)); + } + } + + private static bool IsWrappedException(Exception exception) + { + return exception is OperationCanceledException || + exception is MqttCommunicationTimedOutException || + exception is MqttCommunicationException; + } + + private static void WrapException(Exception exception) + { + if (exception is IOException && exception.InnerException is SocketException innerException) + { + exception = innerException; + } + + if (exception is SocketException socketException) + { + if (socketException.SocketErrorCode == SocketError.ConnectionAborted || + socketException.SocketErrorCode == SocketError.OperationAborted) + { + throw new OperationCanceledException(); + } + } + + if (exception is COMException comException) + { + if ((uint)comException.HResult == ErrorOperationAborted) + { + throw new OperationCanceledException(); + } + } + + throw new MqttCommunicationException(exception); + } + } +} diff --git a/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetCustomAdapter.cs.meta b/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetCustomAdapter.cs.meta new file mode 100644 index 00000000..5868ee74 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetCustomAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b78f5eca1f19e27418600a46d55fa3d1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetCustomAdapterFactory.cs b/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetCustomAdapterFactory.cs new file mode 100644 index 00000000..3e800b83 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetCustomAdapterFactory.cs @@ -0,0 +1,38 @@ +using System; +using MQTTnet.Adapter; +using MQTTnet.Client.Options; +using MQTTnet.Diagnostics; +using MQTTnet.Formatter; + +namespace MQTTnet.Implementations +{ + public class MQTTNetCustomAdapterFactory : IMqttClientAdapterFactory + { + public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetChildLogger logger) + { + if (options == null) throw new ArgumentNullException(nameof(options)); + + switch (options.ChannelOptions) + { + case MqttClientTcpOptions _: + { + var adapter = new MQTTnet.Adapter.MQTTNetCustomAdapter(new MQTTnet.Implementations.MqttTcpChannel(options), new MQTTnet.Formatter.MqttPacketFormatterAdapter(options.ProtocolVersion), logger) + { + ReadBufferSize = ((MqttClientTcpOptions)(options.ChannelOptions)).BufferSize + }; + return adapter; + } + + case MqttClientWebSocketOptions webSocketOptions: + { + return new MQTTnet.Adapter.MQTTNetCustomAdapter(new MqttWebSocketChannel(webSocketOptions), new MqttPacketFormatterAdapter(options.ProtocolVersion), logger); + } + + default: + { + throw new NotSupportedException(); + } + } + } + } +} diff --git a/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetCustomAdapterFactory.cs.meta b/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetCustomAdapterFactory.cs.meta new file mode 100644 index 00000000..cf31b5d8 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetCustomAdapterFactory.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e1aa957518447fb41b0435e34e244415 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetServer.cs b/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetServer.cs new file mode 100644 index 00000000..9aa3d601 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetServer.cs @@ -0,0 +1,51 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using MQTTnet.Server; +using MQTTnet; +using MQTTnet.Diagnostics; +using System.Threading.Tasks; + +public class MQTTNetServer : MonoBehaviour +{ + public int Port = 1883; + IMqttServer server; + + private readonly IMqttNetLogger _serverLogger = new MqttNetLogger("server"); + + // Start is called before the first frame update + void Start() + { + + var _ = StartServerAsync(); + } + + public async Task StartServerAsync() + { + MqttFactory mqttFactory = new MqttFactory(); + + MqttServerOptionsBuilder options = new MqttServerOptionsBuilder() + .WithDefaultEndpointPort(Port); + + server = mqttFactory.CreateMqttServer(); + server.StartedHandler = new MqttServerStartedHandlerDelegate(e => { + Debug.Log($"[MQTTNetServer] server started " + Port); + }); + + /* + server.ClientSubscribedTopicHandler = new MqttServerClientSubscribedHandlerDelegate(e => + { + Debug.Log($"{e.TopicFilter.Topic} {e.ClientId}"); + }); + */ + + await server.StartAsync(options.Build()); + return server; + } + + // Update is called once per frame + void Update() + { + + } +} diff --git a/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetServer.cs.meta b/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetServer.cs.meta new file mode 100644 index 00000000..06891347 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/Scripts/MQTTNet/MQTTNetServer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 915b939850f218c488dc4f03d0877d76 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/streaming-pointcloud/examples/Unity/Assets/Scripts/PointCloudLoader.cs b/streaming-pointcloud/examples/Unity/Assets/Scripts/PointCloudLoader.cs new file mode 100644 index 00000000..eb1ae55c --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/Scripts/PointCloudLoader.cs @@ -0,0 +1,170 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.VFX; +using UnityEngine.UI; +using System.Runtime.InteropServices; + +public class PointCloudLoader : MonoBehaviour +{ + const int TextureDimensionX = 1024; + const int TextureDimensionY = 1024; + + public RawImage debugImage; + + [SerializeField] + private int PointCount; + + public VisualEffect effect; + public string PositionTextureName = "PositionMap"; + public string ColorTextureName = "ColorMap"; + + Texture2D positionMap; + Texture2D colorMap; + + int messasgeSize; + byte[] message; + + + short[] intArray = new short[TextureDimensionX * TextureDimensionY * 3]; + float[] positionArray = new float[TextureDimensionX * TextureDimensionY * 4]; + + byte[] positionBytes = new byte[TextureDimensionX * TextureDimensionY * 4 * 4]; + byte[] colorBytes = new byte[TextureDimensionX * TextureDimensionY * 3]; + + volatile bool textureNeedsUpdate = false; + int currentPointCount = 0; + + public void LoadPoints(byte[] data, int length) + { + int header = 13; + + ulong timestamp = BitConverter.ToUInt64(data, 0); + int pointCount = (int)BitConverter.ToUInt32(data, 8); + bool hasColor = BitConverter.ToBoolean(data, 12); + + //Debug.Log("Loading points:: " + pointCount); + PointCount = pointCount; + Buffer.BlockCopy(data, header, intArray, 0, pointCount * 6); + + int srcIndex = 0; + int destIndex = 0; + + //convert from int16 to float + for (int i = 0; i < pointCount; i++) + { + positionArray[destIndex] = (intArray[srcIndex] * 0.001f); + positionArray[destIndex + 1] = (intArray[srcIndex + 1] * 0.001f); + positionArray[destIndex + 2] = (intArray[srcIndex + 2] * 0.001f); + positionArray[destIndex + 3] = 1; + + srcIndex += 3; + destIndex += 4; + } + + //fill texture using float positions array + try + { + unsafe + { + //rgba positionArray + int positionChunk = (pointCount * 4) * 4; + int index = 0; + fixed (float* p = &positionArray[0]) + { + //fill the whole texture as vfx graphic is randomly sampling + while (index < (positionBytes.Length - positionChunk)) + { + Marshal.Copy(new IntPtr(p), positionBytes, index, positionChunk); + index += positionChunk; + } + + //fill the remaining texture + Marshal.Copy(new IntPtr(p), positionBytes, index, (positionBytes.Length - index)); + } + } + } + catch (Exception e) + { + Debug.LogError("Exception creating point texture:" + e.Message); + } + + //fill color texture directly from payload + if(hasColor) + { + try + { + unsafe + { + //rbg raw data + int colorChunck = pointCount * 3; + + int index = 0; + fixed (byte* b = &data[header + ((pointCount * 3) * 2)]) + { + while (index < (colorBytes.Length - colorChunck)) + { + Marshal.Copy(new IntPtr(b), colorBytes, index, colorChunck); + index += colorChunck; + } + } + } + } + catch (Exception e) + { + Debug.LogError("Exception creating color texture:" + e.Message); + } + } + + currentPointCount = pointCount; + textureNeedsUpdate = true; + } + + + void Start() + { + positionMap = new Texture2D(TextureDimensionX, TextureDimensionY, TextureFormat.RGBAFloat, false); + positionMap.filterMode = FilterMode.Point; + + + colorMap = new Texture2D(TextureDimensionX, TextureDimensionY, TextureFormat.RGB24, false); + colorMap.filterMode = FilterMode.Point; + + if (debugImage) + { + debugImage.texture = positionMap; + } + + if (effect) + { + effect.SetTexture("PositionMap", positionMap); + effect.SetTexture("ColorMap", colorMap); + } + } + + public void UpdateEffect(VisualEffectAsset newEffect) + { + Debug.Log("Update Effect"); + + effect.visualEffectAsset = newEffect; + effect.SetTexture("PositionMap", positionMap); + effect.SetTexture("ColorMap", colorMap); + effect.Reinit(); + } + + + void Update() + { + if (textureNeedsUpdate) + { + positionMap.LoadRawTextureData(positionBytes); + positionMap.Apply(); + + colorMap.LoadRawTextureData(colorBytes); + colorMap.Apply(); + + textureNeedsUpdate = false; + } + } +} diff --git a/streaming-pointcloud/examples/Unity/Assets/Scripts/PointCloudLoader.cs.meta b/streaming-pointcloud/examples/Unity/Assets/Scripts/PointCloudLoader.cs.meta new file mode 100644 index 00000000..56729a95 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/Scripts/PointCloudLoader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 65e26582ff8e9c04a95446fef4f6cacb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/streaming-pointcloud/examples/Unity/Assets/Scripts/RotateObject.cs b/streaming-pointcloud/examples/Unity/Assets/Scripts/RotateObject.cs new file mode 100644 index 00000000..3de477c6 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/Scripts/RotateObject.cs @@ -0,0 +1,20 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class RotateObject : MonoBehaviour +{ + //degrees per second + public int speed = 5; + // Start is called before the first frame update + void Start() + { + + } + + // Update is called once per frame + void Update() + { + transform.Rotate(new Vector3(0, 1 * (Time.deltaTime * speed), 0), Space.World); + } +} diff --git a/streaming-pointcloud/examples/Unity/Assets/Scripts/RotateObject.cs.meta b/streaming-pointcloud/examples/Unity/Assets/Scripts/RotateObject.cs.meta new file mode 100644 index 00000000..cd4a83b3 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/Scripts/RotateObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7755da38630b1db4998af21f1ebafa90 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/streaming-pointcloud/examples/Unity/Assets/SimplePointsViz.vfx b/streaming-pointcloud/examples/Unity/Assets/SimplePointsViz.vfx new file mode 100644 index 00000000..cd04e9a0 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/SimplePointsViz.vfx @@ -0,0 +1,4172 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &114307113894698210 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1b605c022ee79394a8a776c0869b3f9a, type: 3} + m_Name: VFXSlot + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: + - {fileID: 114986932069951040} + - {fileID: 114963171269329408} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 114307113894698210} + m_MasterData: + m_Owner: {fileID: 114946465509916290} + m_Value: + m_Type: + m_SerializableType: UnityEditor.VFX.AABox, Unity.VisualEffectGraph.Editor, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"center":{"x":0.0,"y":1.0,"z":0.0},"size":{"x":50.0,"y":50.0,"z":50.0}}' + m_Space: 0 + m_Property: + name: bounds + m_serializedType: + m_SerializableType: UnityEditor.VFX.AABox, Unity.VisualEffectGraph.Editor, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: The culling bounds of this system. The Visual Effect is only visible + if the bounding box specified here is visible to the camera. + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &114340500867371532 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d01270efd3285ea4a9d6c555cb0a8027, type: 3} + m_Name: VFXUI + m_EditorClassIdentifier: + groupInfos: [] + stickyNoteInfos: [] + systemInfos: [] + categories: [] + uiBounds: + serializedVersion: 2 + x: -259 + y: -641 + width: 1609 + height: 3083 +--- !u!114 &114350483966674976 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7d4c867f6b72b714dbb5fd1780afe208, type: 3} + m_Name: SimplePointsViz + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: + - {fileID: 114946465509916290} + - {fileID: 114780028408030698} + - {fileID: 8926484042661614573} + - {fileID: 8926484042661614552} + - {fileID: 8926484042661614568} + - {fileID: 8926484042661614617} + - {fileID: 8926484042661614618} + - {fileID: 8926484042661614652} + - {fileID: 8926484042661614760} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_UIInfos: {fileID: 114340500867371532} + m_ParameterInfo: + - name: PositionMap + path: PositionMap + tooltip: + sheetType: m_NamedObject + realType: Texture2D + defaultValue: + m_Type: + m_SerializableType: UnityEngine.Texture2D, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"obj":{"fileID":2800000,"guid":"276d9e395ae18fe40a9b4988549f2349","type":3}}' + min: -Infinity + max: Infinity + descendantCount: 0 + - name: ColorMap + path: ColorMap + tooltip: + sheetType: m_NamedObject + realType: Texture2D + defaultValue: + m_Type: + m_SerializableType: UnityEngine.Texture2D, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"obj":{"fileID":2800000,"guid":"276d9e395ae18fe40a9b4988549f2349","type":3}}' + min: -Infinity + max: Infinity + descendantCount: 0 + m_GraphVersion: 4 + m_saved: 1 + m_SubgraphDependencies: [] + m_CategoryPath: +--- !u!114 &114380859405582094 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: VFXSlotFloat + m_EditorClassIdentifier: + m_Parent: {fileID: 114963171269329408} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 114307113894698210} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: z + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &114428730288789306 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d78581a96eae8bf4398c282eb0b098bd, type: 3} + m_Name: VFXDataParticle + m_EditorClassIdentifier: + m_Parent: {fileID: 114350483966674976} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + title: + m_Owners: + - {fileID: 114946465509916290} + - {fileID: 114780028408030698} + - {fileID: 8926484042661614760} + - {fileID: 8926484042661614573} + dataType: 0 + capacity: 500000 + stripCapacity: 16 + particlePerStripCount: 16 + m_Space: 0 +--- !u!114 &114512514798047786 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: VFXSlotFloat + m_EditorClassIdentifier: + m_Parent: {fileID: 114963171269329408} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 114307113894698210} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: x + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &114538391275492396 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: VFXSlotFloat + m_EditorClassIdentifier: + m_Parent: {fileID: 114986932069951040} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 114307113894698210} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: z + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &114739294351936256 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: VFXSlotFloat + m_EditorClassIdentifier: + m_Parent: {fileID: 114986932069951040} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 114307113894698210} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: x + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &114780028408030698 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2dc095764ededfa4bb32fa602511ea4b, type: 3} + m_Name: VFXBasicUpdate + m_EditorClassIdentifier: + m_Parent: {fileID: 114350483966674976} + m_Children: + - {fileID: 8926484042661614624} + - {fileID: 8926484042661614655} + - {fileID: 8926484042661614666} + m_UIPosition: {x: 707, y: 1054} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: [] + m_OutputSlots: [] + m_Label: + m_Data: {fileID: 114428730288789306} + m_InputFlowSlot: + - link: + - context: {fileID: 114946465509916290} + slotIndex: 0 + m_OutputFlowSlot: + - link: + - context: {fileID: 8926484042661614760} + slotIndex: 0 + integration: 0 + angularIntegration: 0 + ageParticles: 1 + reapParticles: 1 +--- !u!114 &114920711487922656 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: VFXSlotFloat + m_EditorClassIdentifier: + m_Parent: {fileID: 114963171269329408} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 114307113894698210} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: y + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &114935892456706286 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: VFXSlotFloat + m_EditorClassIdentifier: + m_Parent: {fileID: 114986932069951040} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 114307113894698210} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: y + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &114946465509916290 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9dfea48843f53fc438eabc12a3a30abc, type: 3} + m_Name: VFXBasicInitialize + m_EditorClassIdentifier: + m_Parent: {fileID: 114350483966674976} + m_Children: + - {fileID: 8926484042661614555} + - {fileID: 8926484042661614612} + - {fileID: 8926484042661614591} + - {fileID: 8926484042661614541} + - {fileID: 8926484042661614557} + m_UIPosition: {x: 711, y: 57} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 114307113894698210} + m_OutputSlots: [] + m_Label: + m_Data: {fileID: 114428730288789306} + m_InputFlowSlot: + - link: + - context: {fileID: 8926484042661614652} + slotIndex: 0 + m_OutputFlowSlot: + - link: + - context: {fileID: 114780028408030698} + slotIndex: 0 +--- !u!114 &114963171269329408 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} + m_Name: VFXSlotFloat3 + m_EditorClassIdentifier: + m_Parent: {fileID: 114307113894698210} + m_Children: + - {fileID: 114512514798047786} + - {fileID: 114920711487922656} + - {fileID: 114380859405582094} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 114307113894698210} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: size + m_serializedType: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: Sets the size of the box along each axis. + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &114986932069951040 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} + m_Name: VFXSlotFloat3 + m_EditorClassIdentifier: + m_Parent: {fileID: 114307113894698210} + m_Children: + - {fileID: 114739294351936256} + - {fileID: 114935892456706286} + - {fileID: 114538391275492396} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 114307113894698210} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: center + m_serializedType: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: Sets the center of the box. + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!2058629511 &8926484042661614527 +VisualEffectResource: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: SimplePointsViz + m_Graph: {fileID: 114350483966674976} + m_ShaderSources: + - compute: 1 + name: '[System 1]Initialize Particle' + source: "#pragma kernel CSMain\r\n#define NB_THREADS_PER_GROUP 64\n#define HAS_ATTRIBUTES + 1\n#define VFX_PASSDEPTH_ACTUAL (0)\n#define VFX_PASSDEPTH_MOTION_VECTOR (1)\n#define + VFX_PASSDEPTH_SELECTION (2)\n#define VFX_USE_SIZE_CURRENT 1\n#define VFX_USE_AGE_CURRENT + 1\n#define VFX_USE_LIFETIME_CURRENT 1\n#define VFX_USE_POSITION_CURRENT 1\n#define + VFX_USE_PARTICLEID_CURRENT 1\n#define VFX_USE_COLOR_CURRENT 1\n#define VFX_USE_ALIVE_CURRENT + 1\n#define VFX_LOCAL_SPACE 1\n#include \"Packages/com.unity.visualeffectgraph/Shaders/RenderPipeline/Legacy/VFXDefines.hlsl\"\n\n\r\n\nstruct + Attributes\n{\n float size;\n float age;\n float lifetime;\n float3 + position;\n uint particleId;\n float3 color;\n bool alive;\n};\n\nstruct + SourceAttributes\n{\n};\n\nTexture2D attributeMap_d;\nSamplerState samplerattributeMap_d;\nfloat4 + attributeMap_d_TexelSize;\nTexture2D attributeMap_e;\nSamplerState samplerattributeMap_e;\nfloat4 + attributeMap_e_TexelSize;\n\n\r\n\r\n#define USE_DEAD_LIST (VFX_USE_ALIVE_CURRENT + && !HAS_STRIPS)\r\n\r\nRWByteAddressBuffer attributeBuffer;\r\nByteAddressBuffer + sourceAttributeBuffer;\r\n\r\nCBUFFER_START(initParams)\r\n#if !VFX_USE_SPAWNER_FROM_GPU\r\n + uint nbSpawned;\t\t\t\t\t// Numbers of particle spawned\r\n uint spawnIndex;\t\t\t\t// + Index of the first particle spawned\r\n uint dispatchWidth;\r\n#else\r\n + uint offsetInAdditionalOutput;\r\n\tuint nbMax;\r\n#endif\r\n\tuint systemSeed;\r\nCBUFFER_END\r\n\r\n#if + USE_DEAD_LIST\r\nRWStructuredBuffer deadListIn;\r\nByteAddressBuffer + deadListCount; // This is bad to use a SRV to fetch deadList count but Unity + API currently prevent from copying to CB\r\n#endif\r\n\r\n#if VFX_USE_SPAWNER_FROM_GPU\r\nStructuredBuffer + eventList;\r\nByteAddressBuffer inputAdditional;\r\n#endif\r\n\r\n#if HAS_STRIPS\r\nRWBuffer + stripDataBuffer;\r\n#endif\r\n\r\n#include \"Packages/com.unity.visualeffectgraph/Shaders/Common/VFXCommonCompute.hlsl\"\n#include + \"Packages/com.unity.visualeffectgraph/Shaders/VFXCommon.hlsl\"\n\n\r\n\r\nvoid + SetAttribute_2EBDF112(inout float size, float Size) /*attribute:size Composition:Add + Source:Slot Random:Off channels:XYZ */\n{\n size += Size;\n}\nvoid SetAttribute_9631F7C0(inout + float age, float Age) /*attribute:age Composition:Add Source:Slot Random:Off + channels:XYZ */\n{\n age += Age;\n}\nvoid SetAttribute_EC596BAC(inout float + lifetime, float Lifetime) /*attribute:lifetime Composition:Add Source:Slot + Random:Off channels:XYZ */\n{\n lifetime += Lifetime;\n}\nvoid AttributeFromMap_6F6C36D5(inout + float3 position, uint particleId, VFXSampler2D attributeMap, uint Seed, float3 + valueBias, float3 valueScale) /*attribute:position Composition:Overwrite SampleMode:RandomConstantPerParticle + channels:XYZ */\n{\n \n uint width, height;\n attributeMap.t.GetDimensions(width, + height);\n uint count = width * height;\n uint id = FIXED_RAND(Seed) + * count;\n uint y = id / width;\n uint x = id - y * width;\n float3 + value = (float3)attributeMap.t.Load(int3(x, y, 0));\n value = (value + + valueBias) * valueScale;\n position = value;\n}\nvoid AttributeFromMap_9AACC55(inout + float3 color, uint particleId, VFXSampler2D attributeMap, uint Seed, float3 + valueBias, float3 valueScale) /*attribute:color Composition:Overwrite SampleMode:RandomConstantPerParticle + channels:XYZ */\n{\n \n uint width, height;\n attributeMap.t.GetDimensions(width, + height);\n uint count = width * height;\n uint id = FIXED_RAND(Seed) + * count;\n uint y = id / width;\n uint x = id - y * width;\n float3 + value = (float3)attributeMap.t.Load(int3(x, y, 0));\n value = (value + + valueBias) * valueScale;\n color = value;\n}\n\n\r\n\r\n#if HAS_STRIPS\r\nbool + GetParticleIndex(inout uint particleIndex, uint stripIndex)\r\n{\r\n\tuint + relativeIndex;\r\n\tInterlockedAdd(STRIP_DATA(STRIP_NEXT_INDEX, stripIndex), + 1, relativeIndex);\r\n\tif (relativeIndex >= PARTICLE_PER_STRIP_COUNT) // strip + is full\r\n\t{\r\n\t\tInterlockedAdd(STRIP_DATA(STRIP_NEXT_INDEX, stripIndex), + -1); // Remove previous increment\r\n\t\treturn false;\r\n\t}\r\n\r\n\tparticleIndex + = stripIndex * PARTICLE_PER_STRIP_COUNT + ((STRIP_DATA(STRIP_FIRST_INDEX, stripIndex) + + relativeIndex) % PARTICLE_PER_STRIP_COUNT);\r\n return true;\r\n}\r\n#endif\r\n\r\n[numthreads(NB_THREADS_PER_GROUP,1,1)]\r\nvoid + CSMain(uint3 groupId : SV_GroupID,\r\n uint3 groupThreadId + : SV_GroupThreadID)\r\n{\r\n uint id = groupThreadId.x + groupId.x * NB_THREADS_PER_GROUP;\r\n#if + !VFX_USE_SPAWNER_FROM_GPU\r\n id += groupId.y * dispatchWidth * NB_THREADS_PER_GROUP;\r\n#endif\r\n\r\n#if + VFX_USE_SPAWNER_FROM_GPU\r\n uint maxThreadId = inputAdditional.Load((offsetInAdditionalOutput + * 2 + 0) << 2);\r\n uint currentSpawnIndex = inputAdditional.Load((offsetInAdditionalOutput + * 2 + 1) << 2) - maxThreadId;\r\n#else\r\n uint maxThreadId = nbSpawned;\r\n + uint currentSpawnIndex = spawnIndex;\r\n#endif\r\n\r\n#if USE_DEAD_LIST\r\n + maxThreadId = min(maxThreadId, deadListCount.Load(0x0));\r\n#elif VFX_USE_SPAWNER_FROM_GPU\r\n + maxThreadId = min(maxThreadId, nbMax); //otherwise, nbSpawned already clamped + on CPU\r\n#endif\r\n\r\n if (id < maxThreadId)\r\n {\r\n#if VFX_USE_SPAWNER_FROM_GPU\r\n + int sourceIndex = eventList[id];\r\n#endif\r\n\t\tuint particleIndex = id + + currentSpawnIndex;\r\n\t\t\r\n#if !VFX_USE_SPAWNER_FROM_GPU\r\n int + sourceIndex = 0;\n /*//Loop with 1 iteration generate a wrong IL Assembly + (and actually, useless code)\n uint currentSumSpawnCount = 0u;\n + for (sourceIndex=0; sourceIndex<1; sourceIndex++)\n {\n currentSumSpawnCount + += uint(asfloat(sourceAttributeBuffer.Load((sourceIndex * 0x1 + 0x0) << 2)));\n + if (id < currentSumSpawnCount)\n {\n break;\n + }\n }\n */\n \n\r\n#endif\r\n\r\n\t\tAttributes attributes + = (Attributes)0;\r\n\t\tSourceAttributes sourceAttributes = (SourceAttributes)0;\r\n\t\t\r\n + attributes.size = (float)0.100000001;\n attributes.age = (float)0;\n + attributes.lifetime = (float)1;\n attributes.position = float3(0, 0, + 0);\n attributes.particleId = (uint)0;\n attributes.color = float3(1, + 1, 1);\n attributes.alive = (bool)true;\n \n\r\n#if VFX_USE_PARTICLEID_CURRENT\r\n + attributes.particleId = particleIndex;\r\n#endif\r\n#if VFX_USE_SEED_CURRENT\r\n + attributes.seed = WangHash(particleIndex ^ systemSeed);\r\n#endif\r\n#if VFX_USE_SPAWNINDEX_CURRENT\r\n + attributes.spawnIndex = id;\r\n#endif\r\n#if HAS_STRIPS\r\n#if !VFX_USE_SPAWNER_FROM_GPU\r\n\t\t\r\n#else\r\n + uint stripIndex = sourceIndex;\r\n#endif\r\n\t\tstripIndex = min(stripIndex, + STRIP_COUNT);\r\n\r\n if (!GetParticleIndex(particleIndex, stripIndex))\r\n + return;\r\n\r\n const StripData stripData = GetStripDataFromStripIndex(stripIndex, + PARTICLE_PER_STRIP_COUNT);\r\n\t\tInitStripAttributes(particleIndex, attributes, + stripData);\r\n\t\t// TODO Change seed to be sure we're deterministic on random + with strip\r\n#endif\r\n \r\n {\n SetAttribute_2EBDF112( + /*inout */attributes.size, (float)1);\n }\n {\n SetAttribute_9631F7C0( + /*inout */attributes.age, (float)0);\n }\n {\n SetAttribute_EC596BAC( + /*inout */attributes.lifetime, (float)1);\n }\n {\n + AttributeFromMap_6F6C36D5( /*inout */attributes.position, attributes.particleId, + GetVFXSampler(attributeMap_d, samplerattributeMap_d), (uint)0, float3(0, 0, + 0), float3(1, 1, 1));\n }\n {\n AttributeFromMap_9AACC55( + /*inout */attributes.color, attributes.particleId, GetVFXSampler(attributeMap_e, + samplerattributeMap_e), (uint)0, float3(0, 0, 0), float3(1, 1, 1));\n + }\n \n\r\n\t\t\r\n#if VFX_USE_ALIVE_CURRENT\r\n if (attributes.alive)\r\n#endif + \r\n {\r\n#if USE_DEAD_LIST\r\n\t uint deadIndex = deadListIn.DecrementCounter();\r\n + uint index = deadListIn[deadIndex];\r\n#else\r\n uint index = particleIndex;\r\n#endif\r\n + attributeBuffer.Store((index * 0x4 + 0x3) << 2,asuint(attributes.size));\n + attributeBuffer.Store((index * 0x1 + 0x1E8500) << 2,asuint(attributes.age));\n + attributeBuffer.Store((index * 0x1 + 0x262640) << 2,asuint(attributes.lifetime));\n + attributeBuffer.Store3((index * 0x4 + 0x2DC780) << 2,asuint(attributes.position));\n + attributeBuffer.Store((index * 0x1 + 0x4C4C80) << 2,asuint(attributes.particleId));\n + attributeBuffer.Store3((index * 0x4 + 0x0) << 2,asuint(attributes.color));\n + attributeBuffer.Store((index * 0x1 + 0x53EDC0) << 2,uint(attributes.alive));\n + \n\r\n }\r\n }\r\n}\r\n" + - compute: 1 + name: '[System 1]A Update Particle' + source: "#pragma kernel CSMain\r\n#define NB_THREADS_PER_GROUP 64\n#define HAS_ATTRIBUTES + 1\n#define VFX_PASSDEPTH_ACTUAL (0)\n#define VFX_PASSDEPTH_MOTION_VECTOR (1)\n#define + VFX_PASSDEPTH_SELECTION (2)\n#define VFX_USE_SIZE_CURRENT 1\n#define VFX_USE_AGE_CURRENT + 1\n#define VFX_USE_LIFETIME_CURRENT 1\n#define VFX_USE_POSITION_CURRENT 1\n#define + VFX_USE_PARTICLEID_CURRENT 1\n#define VFX_USE_COLOR_CURRENT 1\n#define VFX_USE_ALIVE_CURRENT + 1\n#define VFX_HAS_INDIRECT_DRAW 1\n#define VFX_LOCAL_SPACE 1\n#include \"Packages/com.unity.visualeffectgraph/Shaders/RenderPipeline/Legacy/VFXDefines.hlsl\"\n\n\r\nCBUFFER_START(parameters)\n + float deltaTime_d;\n uint3 PADDING_0;\nCBUFFER_END\n\nstruct Attributes\n{\n + float size;\n float age;\n float lifetime;\n float3 position;\n + uint particleId;\n float3 color;\n bool alive;\n};\n\nstruct SourceAttributes\n{\n};\n\nTexture2D + attributeMap_b;\nSamplerState samplerattributeMap_b;\nfloat4 attributeMap_b_TexelSize;\nTexture2D + attributeMap_c;\nSamplerState samplerattributeMap_c;\nfloat4 attributeMap_c_TexelSize;\n\n\r\n\r\n#define + USE_DEAD_LIST (VFX_USE_ALIVE_CURRENT && !HAS_STRIPS)\r\n\r\nRWByteAddressBuffer + attributeBuffer;\r\n\r\n#if USE_DEAD_LIST\r\nRWStructuredBuffer deadListOut;\r\n#endif\r\n\r\n#if + VFX_HAS_INDIRECT_DRAW\r\nRWStructuredBuffer indirectBuffer;\r\n#endif\r\n\r\n#if + HAS_STRIPS\r\nRWBuffer stripDataBuffer;\r\n#endif\r\n\r\n#if VFX_USE_STRIPALIVE_CURRENT\r\nBuffer + attachedStripDataBuffer;\r\n#endif\r\n\r\nCBUFFER_START(updateParams)\r\n + uint nbMax;\r\n\tuint dispatchWidth;\r\n\tuint systemSeed;\r\nCBUFFER_END\r\n\r\n#include + \"Packages/com.unity.visualeffectgraph/Shaders/Common/VFXCommonCompute.hlsl\"\n#include + \"Packages/com.unity.visualeffectgraph/Shaders/VFXCommon.hlsl\"\n\n\r\n\r\nvoid + SetAttribute_3278B22F(inout float size, float Size) /*attribute:size Composition:Overwrite + Source:Slot Random:Off channels:XYZ */\n{\n size = Size;\n}\nvoid AttributeFromMap_6F6C36D5(inout + float3 position, uint particleId, VFXSampler2D attributeMap, uint Seed, float3 + valueBias, float3 valueScale) /*attribute:position Composition:Overwrite SampleMode:RandomConstantPerParticle + channels:XYZ */\n{\n \n uint width, height;\n attributeMap.t.GetDimensions(width, + height);\n uint count = width * height;\n uint id = FIXED_RAND(Seed) + * count;\n uint y = id / width;\n uint x = id - y * width;\n float3 + value = (float3)attributeMap.t.Load(int3(x, y, 0));\n value = (value + + valueBias) * valueScale;\n position = value;\n}\nvoid AttributeFromMap_9AACC55(inout + float3 color, uint particleId, VFXSampler2D attributeMap, uint Seed, float3 + valueBias, float3 valueScale) /*attribute:color Composition:Overwrite SampleMode:RandomConstantPerParticle + channels:XYZ */\n{\n \n uint width, height;\n attributeMap.t.GetDimensions(width, + height);\n uint count = width * height;\n uint id = FIXED_RAND(Seed) + * count;\n uint y = id / width;\n uint x = id - y * width;\n float3 + value = (float3)attributeMap.t.Load(int3(x, y, 0));\n value = (value + + valueBias) * valueScale;\n color = value;\n}\nvoid Age(inout float age, + float deltaTime)\n{\n age += deltaTime;\n}\nvoid Reap(float age, float lifetime, + inout bool alive)\n{\n if(age > lifetime) { alive = false; }\n}\n\n\r\n\r\n[numthreads(NB_THREADS_PER_GROUP,1,1)]\r\nvoid + CSMain(uint3 groupId : SV_GroupID,\r\n uint3 groupThreadId + : SV_GroupThreadID)\r\n{\r\n\tuint id = groupThreadId.x + groupId.x * NB_THREADS_PER_GROUP + + groupId.y * dispatchWidth * NB_THREADS_PER_GROUP;\r\n\tuint index = id;\r\n\tif + (id < nbMax)\r\n\t{\r\n Attributes attributes = (Attributes)0;\r\n\t\tSourceAttributes + sourceAttributes = (SourceAttributes)0;\r\n\r\n#if VFX_USE_ALIVE_CURRENT\r\n\t\tattributes.alive + = (attributeBuffer.Load((index * 0x1 + 0x53EDC0) << 2));\n\t\t\n\r\n\t\tif + (attributes.alive)\r\n\t\t{\r\n\t\t\tattributes.size = asfloat(attributeBuffer.Load((index + * 0x4 + 0x3) << 2));\n\t\t\tattributes.age = asfloat(attributeBuffer.Load((index + * 0x1 + 0x1E8500) << 2));\n\t\t\tattributes.lifetime = asfloat(attributeBuffer.Load((index + * 0x1 + 0x262640) << 2));\n\t\t\tattributes.position = asfloat(attributeBuffer.Load3((index + * 0x4 + 0x2DC780) << 2));\n\t\t\tattributes.particleId = (attributeBuffer.Load((index + * 0x1 + 0x4C4C80) << 2));\n\t\t\tattributes.color = asfloat(attributeBuffer.Load3((index + * 0x4 + 0x0) << 2));\n\t\t\t\n\r\n\r\n// Initialize built-in needed attributes\r\n#if + VFX_USE_OLDPOSITION_CURRENT\r\n\t\t\tattributes.oldPosition = attributes.position;\r\n#endif\r\n#if + HAS_STRIPS\r\n const StripData stripData = GetStripDataFromParticleIndex(index, + PARTICLE_PER_STRIP_COUNT);\r\n InitStripAttributes(index, attributes, + stripData);\r\n#endif\r\n\t\t\t\r\n\t\t\t{\n\t\t\t SetAttribute_3278B22F( + /*inout */attributes.size, (float)0.0399999991);\n\t\t\t}\n\t\t\t{\n\t\t\t + AttributeFromMap_6F6C36D5( /*inout */attributes.position, attributes.particleId, + GetVFXSampler(attributeMap_b, samplerattributeMap_b), (uint)0, float3(0, 0, + 0), float3(1, 1, 1));\n\t\t\t}\n\t\t\t{\n\t\t\t AttributeFromMap_9AACC55( + /*inout */attributes.color, attributes.particleId, GetVFXSampler(attributeMap_c, + samplerattributeMap_c), (uint)0, float3(0, 0, 0), float3(1, 1, 1));\n\t\t\t}\n\t\t\tAge( + /*inout */attributes.age, deltaTime_d);\n\t\t\tReap(attributes.age, attributes.lifetime, + /*inout */attributes.alive);\n\t\t\t\n\r\n\r\n\t\t\tif (attributes.alive)\r\n\t\t\t{\r\n\t\t\t\tattributeBuffer.Store((index + * 0x4 + 0x3) << 2,asuint(attributes.size));\n\t\t\t\tattributeBuffer.Store((index + * 0x1 + 0x1E8500) << 2,asuint(attributes.age));\n\t\t\t\tattributeBuffer.Store3((index + * 0x4 + 0x2DC780) << 2,asuint(attributes.position));\n\t\t\t\tattributeBuffer.Store3((index + * 0x4 + 0x0) << 2,asuint(attributes.color));\n\t\t\t\t\n\r\n#if VFX_HAS_INDIRECT_DRAW\r\n + uint indirectIndex = indirectBuffer.IncrementCounter();\r\n\t\t\t\tindirectBuffer[indirectIndex] + = index;\r\n#endif\r\n\r\n#if HAS_STRIPS\t\t\t\r\n\t\t\t\tuint relativeIndexInStrip + = GetRelativeIndex(index, stripData);\r\n\t\t\t\tInterlockedMin(STRIP_DATA(STRIP_MIN_ALIVE, + stripData.stripIndex), relativeIndexInStrip);\r\n\t\t\t\tInterlockedMax(STRIP_DATA(STRIP_MAX_ALIVE, + stripData.stripIndex), relativeIndexInStrip);\r\n#endif\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tattributeBuffer.Store((index + * 0x1 + 0x53EDC0) << 2,uint(attributes.alive));\n\t\t\t\t\n\r\n#if USE_DEAD_LIST + && !VFX_USE_STRIPALIVE_CURRENT\r\n\t\t\t\tuint deadIndex = deadListOut.IncrementCounter();\r\n\t\t\t\tdeadListOut[deadIndex] + = index;\r\n#endif\r\n\t\t\t}\r\n\t\t}\r\n#if USE_DEAD_LIST && VFX_USE_STRIPALIVE_CURRENT\r\n + else if (attributes.stripAlive)\r\n {\r\n if (STRIP_DATA_X(attachedStripDataBuffer, + STRIP_MIN_ALIVE, index) == ~1) // Attached strip is no longer alive, recycle + the particle \r\n {\r\n uint deadIndex = deadListOut.IncrementCounter();\r\n\t\t\t\tdeadListOut[deadIndex] + = index;\r\n attributes.stripAlive = false;\r\n + \r\n } \r\n }\r\n#endif\r\n#else\r\n\t\tattributes.size + = asfloat(attributeBuffer.Load((index * 0x4 + 0x3) << 2));\n\t\tattributes.age + = asfloat(attributeBuffer.Load((index * 0x1 + 0x1E8500) << 2));\n\t\tattributes.lifetime + = asfloat(attributeBuffer.Load((index * 0x1 + 0x262640) << 2));\n\t\tattributes.position + = asfloat(attributeBuffer.Load3((index * 0x4 + 0x2DC780) << 2));\n\t\tattributes.particleId + = (attributeBuffer.Load((index * 0x1 + 0x4C4C80) << 2));\n\t\tattributes.color + = asfloat(attributeBuffer.Load3((index * 0x4 + 0x0) << 2));\n\t\tattributes.alive + = (attributeBuffer.Load((index * 0x1 + 0x53EDC0) << 2));\n\t\t\n\r\n\t\t\r\n#if + VFX_USE_OLDPOSITION_CURRENT\r\n\t\tattributes.oldPosition = attributes.position;\r\n#endif\r\n#if + HAS_STRIPS\r\n const StripData stripData = GetStripDataFromParticleIndex(index, + PARTICLE_PER_STRIP_COUNT);\r\n InitStripAttributes(index, attributes, + stripData);\r\n#endif\r\n\t\t\r\n\t\t{\n\t\t SetAttribute_3278B22F( /*inout + */attributes.size, (float)0.0399999991);\n\t\t}\n\t\t{\n\t\t AttributeFromMap_6F6C36D5( + /*inout */attributes.position, attributes.particleId, GetVFXSampler(attributeMap_b, + samplerattributeMap_b), (uint)0, float3(0, 0, 0), float3(1, 1, 1));\n\t\t}\n\t\t{\n\t\t + AttributeFromMap_9AACC55( /*inout */attributes.color, attributes.particleId, + GetVFXSampler(attributeMap_c, samplerattributeMap_c), (uint)0, float3(0, 0, + 0), float3(1, 1, 1));\n\t\t}\n\t\tAge( /*inout */attributes.age, deltaTime_d);\n\t\tReap(attributes.age, + attributes.lifetime, /*inout */attributes.alive);\n\t\t\n\r\n\t\tattributeBuffer.Store((index + * 0x4 + 0x3) << 2,asuint(attributes.size));\n\t\tattributeBuffer.Store((index + * 0x1 + 0x1E8500) << 2,asuint(attributes.age));\n\t\tattributeBuffer.Store3((index + * 0x4 + 0x2DC780) << 2,asuint(attributes.position));\n\t\tattributeBuffer.Store3((index + * 0x4 + 0x0) << 2,asuint(attributes.color));\n\t\tattributeBuffer.Store((index + * 0x1 + 0x53EDC0) << 2,uint(attributes.alive));\n\t\t\n\r\n#if VFX_HAS_INDIRECT_DRAW\r\n + uint indirectIndex = indirectBuffer.IncrementCounter();\r\n\t\tindirectBuffer[indirectIndex] + = index;\r\n#endif\r\n#endif\r\n\t}\r\n}\r\n" + - compute: 0 + name: '[System 1]Output Particle Quad' + source: "Shader \"Hidden/VFX/SimplePointsViz/System 1/Output Particle Quad\"\n{\r\n\tSubShader\r\n\t{\t\r\n\t\tCull + Off\r\n\t\t\r\n\t\tTags { \"Queue\"=\"Transparent\" \"IgnoreProjector\"=\"True\" + \"RenderType\"=\"Transparent\" }\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\tBlend + One OneMinusSrcAlpha\n\t\tZTest LEqual\n\t\tZWrite Off\n\t\tCull Off\n\t\t\n\t\n\t\t\t\n\t\tHLSLINCLUDE\n\t\t\n\t\t#define + NB_THREADS_PER_GROUP 64\n\t\t#define HAS_ATTRIBUTES 1\n\t\t#define VFX_PASSDEPTH_ACTUAL + (0)\n\t\t#define VFX_PASSDEPTH_MOTION_VECTOR (1)\n\t\t#define VFX_PASSDEPTH_SELECTION + (2)\n\t\t#define VFX_USE_SIZE_CURRENT 1\n\t\t#define VFX_USE_POSITION_CURRENT + 1\n\t\t#define VFX_USE_COLOR_CURRENT 1\n\t\t#define VFX_USE_ALPHA_CURRENT 1\n\t\t#define + VFX_USE_ALIVE_CURRENT 1\n\t\t#define VFX_USE_AXISX_CURRENT 1\n\t\t#define VFX_USE_AXISY_CURRENT + 1\n\t\t#define VFX_USE_AXISZ_CURRENT 1\n\t\t#define VFX_USE_ANGLEX_CURRENT + 1\n\t\t#define VFX_USE_ANGLEY_CURRENT 1\n\t\t#define VFX_USE_ANGLEZ_CURRENT + 1\n\t\t#define VFX_USE_PIVOTX_CURRENT 1\n\t\t#define VFX_USE_PIVOTY_CURRENT + 1\n\t\t#define VFX_USE_PIVOTZ_CURRENT 1\n\t\t#define VFX_USE_SCALEX_CURRENT + 1\n\t\t#define VFX_USE_SCALEY_CURRENT 1\n\t\t#define VFX_USE_SCALEZ_CURRENT + 1\n\t\t#define VFX_COLORMAPPING_DEFAULT 1\n\t\t#define IS_TRANSPARENT_PARTICLE + 1\n\t\t#define VFX_BLENDMODE_PREMULTIPLY 1\n\t\t#define VFX_HAS_INDIRECT_DRAW + 1\n\t\t#define USE_DEAD_LIST_COUNT 1\n\t\t#define VFX_PRIMITIVE_QUAD 1\n\t\t\n\t\t\n\t\t#define + VFX_LOCAL_SPACE 1\n\t\t#include \"Packages/com.unity.visualeffectgraph/Shaders/RenderPipeline/Legacy/VFXDefines.hlsl\"\n\t\t\n\n\t\t\n\t\tstruct + Attributes\n\t\t{\n\t\t float size;\n\t\t float3 position;\n\t\t float3 + color;\n\t\t float alpha;\n\t\t bool alive;\n\t\t float3 axisX;\n\t\t + float3 axisY;\n\t\t float3 axisZ;\n\t\t float angleX;\n\t\t float + angleY;\n\t\t float angleZ;\n\t\t float pivotX;\n\t\t float pivotY;\n\t\t + float pivotZ;\n\t\t float scaleX;\n\t\t float scaleY;\n\t\t float + scaleZ;\n\t\t};\n\t\t\n\t\tstruct SourceAttributes\n\t\t{\n\t\t};\n\t\t\n\t\tTexture2D + mainTexture;\n\t\tSamplerState samplermainTexture;\n\t\tfloat4 mainTexture_TexelSize;\n\t\t\n\n\t\t\n\t\t#define + VFX_NEEDS_COLOR_INTERPOLATOR (VFX_USE_COLOR_CURRENT || VFX_USE_ALPHA_CURRENT)\n\t\t#if + HAS_STRIPS\n\t\t#define VFX_OPTIONAL_INTERPOLATION \n\t\t#else\n\t\t#define + VFX_OPTIONAL_INTERPOLATION nointerpolation\n\t\t#endif\n\t\t\n\t\tByteAddressBuffer + attributeBuffer;\t\n\t\t\n\t\t#if VFX_HAS_INDIRECT_DRAW\n\t\tStructuredBuffer + indirectBuffer;\t\n\t\t#endif\t\n\t\t\n\t\t#if USE_DEAD_LIST_COUNT\n\t\tByteAddressBuffer + deadListCount;\n\t\t#endif\n\t\t\n\t\t#if HAS_STRIPS\n\t\tBuffer stripDataBuffer;\n\t\t#endif\n\t\t\n\t\t#if + WRITE_MOTION_VECTOR_IN_FORWARD || USE_MOTION_VECTORS_PASS\n\t\tByteAddressBuffer + elementToVFXBufferPrevious;\n\t\t#endif\n\t\t\n\t\tCBUFFER_START(outputParams)\n\t\t\tfloat + nbMax;\n\t\t\tfloat systemSeed;\n\t\tCBUFFER_END\n\t\t\n\t\t// Helper macros + to always use a valid instanceID\n\t\t#if defined(UNITY_STEREO_INSTANCING_ENABLED)\n\t\t\t#define + VFX_DECLARE_INSTANCE_ID UNITY_VERTEX_INPUT_INSTANCE_ID\n\t\t\t#define VFX_GET_INSTANCE_ID(i) + unity_InstanceID\n\t\t#else\n\t\t\t#define VFX_DECLARE_INSTANCE_ID uint + instanceID : SV_InstanceID;\n\t\t\t#define VFX_GET_INSTANCE_ID(i) i.instanceID\n\t\t#endif\n\t\t\n\t\tENDHLSL\n\t\t\n\r\n\t\t// + Forward pass\n\t\tPass\n\t\t{\t\t\n\t\t\tTags { \"LightMode\"=\"ForwardBase\" + }\n\t\t\t\n\t\t\tHLSLPROGRAM\n\t\t\t#pragma target 4.5\n\t\t\t\n\t\t\n\t\t\tstruct + ps_input\n\t\t\t{\n\t\t\t\tfloat4 pos : SV_POSITION;\n\t\t\t\t#if USE_FLIPBOOK_INTERPOLATION\n\t\t\t\tfloat4 + uv : TEXCOORD0;\n\t\t\t\t#else\n\t\t\t\tfloat2 uv : TEXCOORD0;\t\n\t\t\t\t#endif\n\t\t\t\t#if + VFX_NEEDS_COLOR_INTERPOLATOR\n\t\t\t\tVFX_OPTIONAL_INTERPOLATION float4 color + : COLOR0;\n\t\t\t\t#endif\n\t\t\t\t#if USE_SOFT_PARTICLE || USE_ALPHA_TEST + || USE_FLIPBOOK_INTERPOLATION || USE_EXPOSURE_WEIGHT || WRITE_MOTION_VECTOR_IN_FORWARD\n\t\t\t\t// + x: inverse soft particles fade distance\n\t\t\t\t// y: alpha threshold\n\t\t\t\t// + z: frame blending factor\n\t\t\t\t// w: exposure weight\n\t\t\t\tVFX_OPTIONAL_INTERPOLATION + float4 builtInInterpolants : TEXCOORD1;\n\t\t\t\t#endif\n\t\t\t\t#if USE_FLIPBOOK_MOTIONVECTORS\n\t\t\t\t// + x: motion vectors scale X\n\t\t\t\t// y: motion vectors scale Y\n\t\t\t\tVFX_OPTIONAL_INTERPOLATION + float2 builtInInterpolants2 : TEXCOORD2;\n\t\t\t\t#endif\n\t\t\t\t#if VFX_NEEDS_POSWS_INTERPOLATOR\n\t\t\t\tfloat3 + posWS : TEXCOORD3;\n\t\t\t\t#endif\n\t\t\t\t\n\t\t\t\t#if WRITE_MOTION_VECTOR_IN_FORWARD\n\t\t\t\tfloat4 + cPosPrevious : TEXCOORD4;\n\t\t\t\tfloat4 cPosNonJiterred : TEXCOORD5;\n\t\t\t\t#endif\n\t\t\t\t\n\t\t\t\t#if + SHADERGRAPH_NEEDS_NORMAL_FORWARD\n\t\t\t\tfloat3 normal : TEXCOORD6;\n\t\t\t\t#endif\n\t\t\t\t#if + SHADERGRAPH_NEEDS_TANGENT_FORWARD\n\t\t\t\tfloat3 tangent : TEXCOORD7;\n\t\t\t\t#endif\n\t\t\t\t\n\t\t + \n\t\t\t\t\n\t\t\t\tUNITY_VERTEX_OUTPUT_STEREO\n\t\t\t};\n\t\t\t\n\t\t\tstruct + ps_output\n\t\t\t{\n\t\t\t\tfloat4 color : SV_Target0;\n\t\t#if WRITE_MOTION_VECTOR_IN_FORWARD\n\t\t\t\tfloat4 + outMotionVector : SV_Target1;\n\t\t#endif\n\t\t\t};\n\t\t\n\t\t#define VFX_VARYING_PS_INPUTS + ps_input\n\t\t#define VFX_VARYING_POSCS pos\n\t\t#define VFX_VARYING_COLOR + color.rgb\n\t\t#define VFX_VARYING_ALPHA color.a\n\t\t#define VFX_VARYING_INVSOFTPARTICLEFADEDISTANCE + builtInInterpolants.x\n\t\t#define VFX_VARYING_ALPHATHRESHOLD builtInInterpolants.y\n\t\t#define + VFX_VARYING_FRAMEBLEND builtInInterpolants.z\n\t\t#define VFX_VARYING_MOTIONVECTORSCALE + builtInInterpolants2.xy\n\t\t#define VFX_VARYING_UV uv\n\t\t#if VFX_NEEDS_POSWS_INTERPOLATOR\n\t\t#define + VFX_VARYING_POSWS posWS\n\t\t#endif\n\t\t#if USE_EXPOSURE_WEIGHT\n\t\t#define + VFX_VARYING_EXPOSUREWEIGHT builtInInterpolants.w\n\t\t#endif\n\t\t#if WRITE_MOTION_VECTOR_IN_FORWARD\n\t\t#define + VFX_VARYING_VELOCITY_CPOS cPosNonJiterred\n\t\t#define VFX_VARYING_VELOCITY_CPOS_PREVIOUS + cPosPrevious\n\t\t#endif\n\t\t\n\t\t\n\t\t\t\n\t\t#if SHADERGRAPH_NEEDS_NORMAL_FORWARD\n\t\t#define + VFX_VARYING_NORMAL normal\n\t\t#endif\n\t\t#if SHADERGRAPH_NEEDS_TANGENT_FORWARD\n\t\t#define + VFX_VARYING_TANGENT tangent\n\t\t#endif\n\t\t\t\t\n\t\t\t#if !(defined(VFX_VARYING_PS_INPUTS) + && defined(VFX_VARYING_POSCS))\n\t\t\t#error VFX_VARYING_PS_INPUTS, VFX_VARYING_POSCS + and VFX_VARYING_UV must be defined.\n\t\t\t#endif\n\t\t\t\n\t\t\t#include \"Packages/com.unity.visualeffectgraph/Shaders/RenderPipeline/Legacy/VFXCommon.hlsl\"\n\t\t\t#include + \"Packages/com.unity.visualeffectgraph/Shaders/VFXCommon.hlsl\"\n\t\t\t\n\n\t\t\tvoid + Orient_4(inout float3 axisX, inout float3 axisY, inout float3 axisZ) /*mode:FaceCameraPlane + axes:ZY */\n\t\t\t{\n\t\t\t \n\t\t\t float3x3 viewRot = GetVFXToViewRotMatrix();\n\t\t\t + axisX = viewRot[0].xyz;\n\t\t\t axisY = viewRot[1].xyz;\n\t\t\t #if VFX_LOCAL_SPACE + // Need to remove potential scale in local transform\n\t\t\t axisX = normalize(axisX);\n\t\t\t + axisY = normalize(axisY);\n\t\t\t axisZ = cross(axisX,axisY);\n\t\t\t + #else\n\t\t\t axisZ = -viewRot[2].xyz;\n\t\t\t #endif\n\t\t\t \n\t\t\t}\n\t\t\t\n\n\t\t\t\n\t\t\t#if + defined(HAS_STRIPS) && !defined(VFX_PRIMITIVE_QUAD)\n\t\t\t#error VFX_PRIMITIVE_QUAD + must be defined when HAS_STRIPS is.\n\t\t\t#endif\n\t\t\t\n\t\t\tstruct vs_input\n\t\t\t{\n\t\t\t\tVFX_DECLARE_INSTANCE_ID\n\t\t\t};\n\t\t\t\n\t\t\t#if + HAS_STRIPS\n\t\t\t#define PARTICLE_IN_EDGE (id & 1)\n\t\t\t\n\t\t\tfloat3 GetParticlePosition(uint + index)\n\t\t\t{\n\t\t\t\tstruct Attributes attributes = (Attributes)0;\n\t\t\t\tattributes.position + = asfloat(attributeBuffer.Load3((index * 0x4 + 0x2DC780) << 2));\n\t\t\t\t\n\n\t\t\t\treturn + attributes.position;\n\t\t\t}\n\t\t\t\n\t\t\tfloat3 GetStripTangent(float3 + currentPos, uint relativeIndex, const StripData stripData)\n\t\t\t{\n\t\t\t\tfloat3 + prevTangent = (float3)0.0f;\n\t\t\t\tif (relativeIndex > 0)\n\t\t\t\t{\n\t\t\t\t\tuint + prevIndex = GetParticleIndex(relativeIndex - 1,stripData);\n\t\t\t\t\tprevTangent + = normalize(currentPos - GetParticlePosition(prevIndex));\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfloat3 + nextTangent = (float3)0.0f;\n\t\t\t\tif (relativeIndex < stripData.nextIndex + - 1)\n\t\t\t\t{\n\t\t\t\t\tuint nextIndex = GetParticleIndex(relativeIndex + + 1,stripData);\n\t\t\t\t\tnextTangent = normalize(GetParticlePosition(nextIndex) + - currentPos);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn normalize(prevTangent + + nextTangent);\n\t\t\t}\n\t\t\t#endif\n\t\t\t\n\t\t\t#pragma vertex vert\n\t\t\tVFX_VARYING_PS_INPUTS + vert(uint id : SV_VertexID, vs_input i)\n\t\t\t{\n\t\t\t\tVFX_VARYING_PS_INPUTS + o = (VFX_VARYING_PS_INPUTS)0;\n\t\t\t\n\t\t\t\tUNITY_SETUP_INSTANCE_ID(i);\n\t\t\t\tUNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);\n\t\t\t\n\t\t\t#if + VFX_PRIMITIVE_TRIANGLE\n\t\t\t\tuint index = id / 3;\n\t\t\t#elif VFX_PRIMITIVE_QUAD\n\t\t\t#if + HAS_STRIPS\n\t\t\t\tid += VFX_GET_INSTANCE_ID(i) * 8192;\n\t\t\t\tconst uint + vertexPerStripCount = (PARTICLE_PER_STRIP_COUNT - 1) << 2;\n\t\t\t\tconst StripData + stripData = GetStripDataFromStripIndex(id / vertexPerStripCount, PARTICLE_PER_STRIP_COUNT);\n\t\t\t\tuint + currentIndex = ((id % vertexPerStripCount) >> 2) + (id & 1); // relative index + of particle\n\t\t\t\t\n\t\t\t\tuint maxEdgeIndex = currentIndex - PARTICLE_IN_EDGE + + 1;\n\t\t\t\tif (maxEdgeIndex >= stripData.nextIndex)\n\t\t\t\t\treturn o;\n\t\t\t\t\n\t\t\t\tuint + index = GetParticleIndex(currentIndex, stripData);\n\t\t\t#else\n\t\t\t\tuint + index = (id >> 2) + VFX_GET_INSTANCE_ID(i) * 2048;\n\t\t\t#endif\n\t\t\t#elif + VFX_PRIMITIVE_OCTAGON\n\t\t\t\tuint index = (id >> 3) + VFX_GET_INSTANCE_ID(i) + * 1024;\n\t\t\t#endif\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\tuint deadCount = 0;\n\t\t\t\t\t\t#if + USE_DEAD_LIST_COUNT\n\t\t\t\t\t\tdeadCount = deadListCount.Load(0);\n\t\t\t\t\t\t#endif\t\n\t\t\t\t\t\tif + (index >= asuint(nbMax) - deadCount)\n\t\t\t\t\t\t#if USE_GEOMETRY_SHADER\n\t\t\t\t\t\t\treturn; + // cull\n\t\t\t\t\t\t#else\n\t\t\t\t\t\t\treturn o; // cull\n\t\t\t\t\t\t#endif\n\t\t\t\t\t\t\n\t\t\t\t\t\tAttributes + attributes = (Attributes)0;\n\t\t\t\t\t\tSourceAttributes sourceAttributes + = (SourceAttributes)0;\n\t\t\t\t\t\t\n\t\t\t\t\t\t#if VFX_HAS_INDIRECT_DRAW\n\t\t\t\t\t\tindex + = indirectBuffer[index];\n\t\t\t\t\t\tattributes.size = asfloat(attributeBuffer.Load((index + * 0x4 + 0x3) << 2));\n\t\t\t\t\t\tattributes.position = asfloat(attributeBuffer.Load3((index + * 0x4 + 0x2DC780) << 2));\n\t\t\t\t\t\tattributes.color = asfloat(attributeBuffer.Load3((index + * 0x4 + 0x0) << 2));\n\t\t\t\t\t\tattributes.alpha = (float)1;\n\t\t\t\t\t\tattributes.alive + = (attributeBuffer.Load((index * 0x1 + 0x53EDC0) << 2));\n\t\t\t\t\t\tattributes.axisX + = float3(1, 0, 0);\n\t\t\t\t\t\tattributes.axisY = float3(0, 1, 0);\n\t\t\t\t\t\tattributes.axisZ + = float3(0, 0, 1);\n\t\t\t\t\t\tattributes.angleX = (float)0;\n\t\t\t\t\t\tattributes.angleY + = (float)0;\n\t\t\t\t\t\tattributes.angleZ = (float)0;\n\t\t\t\t\t\tattributes.pivotX + = (float)0;\n\t\t\t\t\t\tattributes.pivotY = (float)0;\n\t\t\t\t\t\tattributes.pivotZ + = (float)0;\n\t\t\t\t\t\tattributes.scaleX = (float)1;\n\t\t\t\t\t\tattributes.scaleY + = (float)1;\n\t\t\t\t\t\tattributes.scaleZ = (float)1;\n\t\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\t#else\n\t\t\t\t\t\tattributes.alive + = (attributeBuffer.Load((index * 0x1 + 0x53EDC0) << 2));\n\t\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\t#if + !HAS_STRIPS\n\t\t\t\t\t\tif (!attributes.alive)\n\t\t\t\t\t\t\treturn o;\n\t\t\t\t\t\t#endif\n\t\t\t\t\t\t\t\n\t\t\t\t\t\tattributes.size + = asfloat(attributeBuffer.Load((index * 0x4 + 0x3) << 2));\n\t\t\t\t\t\tattributes.position + = asfloat(attributeBuffer.Load3((index * 0x4 + 0x2DC780) << 2));\n\t\t\t\t\t\tattributes.color + = asfloat(attributeBuffer.Load3((index * 0x4 + 0x0) << 2));\n\t\t\t\t\t\tattributes.alpha + = (float)1;\n\t\t\t\t\t\tattributes.axisX = float3(1, 0, 0);\n\t\t\t\t\t\tattributes.axisY + = float3(0, 1, 0);\n\t\t\t\t\t\tattributes.axisZ = float3(0, 0, 1);\n\t\t\t\t\t\tattributes.angleX + = (float)0;\n\t\t\t\t\t\tattributes.angleY = (float)0;\n\t\t\t\t\t\tattributes.angleZ + = (float)0;\n\t\t\t\t\t\tattributes.pivotX = (float)0;\n\t\t\t\t\t\tattributes.pivotY + = (float)0;\n\t\t\t\t\t\tattributes.pivotZ = (float)0;\n\t\t\t\t\t\tattributes.scaleX + = (float)1;\n\t\t\t\t\t\tattributes.scaleY = (float)1;\n\t\t\t\t\t\tattributes.scaleZ + = (float)1;\n\t\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\t#endif\n\t\t\t\t\t\t\n\t\t\t\t\t\t// + Initialize built-in needed attributes\n\t\t\t\t\t\t#if HAS_STRIPS\n\t\t\t\t\t\tInitStripAttributes(index, + attributes, stripData);\n\t\t\t\t\t\t#endif\n\t\t\t\t\t\t\t\n\t\t\t\tOrient_4( + /*inout */attributes.axisX, /*inout */attributes.axisY, /*inout */attributes.axisZ);\n\t\t\t\t\n\n\t\t\t\t\n\t\t\t#if + !HAS_STRIPS\n\t\t\t\tif (!attributes.alive)\n\t\t\t\t\treturn o;\n\t\t\t#endif\n\t\t\t\t\n\t\t\t#if + VFX_PRIMITIVE_QUAD\n\t\t\t\n\t\t\t#if HAS_STRIPS\n\t\t\t#if VFX_STRIPS_UV_STRECHED\n\t\t\t\to.VFX_VARYING_UV.x + = (float)(currentIndex) / (stripData.nextIndex - 1);\n\t\t\t#elif VFX_STRIPS_UV_PER_SEGMENT\n\t\t\t\to.VFX_VARYING_UV.x + = PARTICLE_IN_EDGE;\n\t\t\t#else\n\t\t\t\t\n\t\t\t o.VFX_VARYING_UV.x = + texCoord;\n\t\t\t#endif\n\t\t\t\n\t\t\t\to.VFX_VARYING_UV.y = float((id & 2) + >> 1);\n\t\t\t\tconst float2 vOffsets = float2(0.0f,o.VFX_VARYING_UV.y - 0.5f);\n\t\t\t\t\n\t\t\t#if + VFX_STRIPS_SWAP_UV\n\t\t\t\to.VFX_VARYING_UV.xy = float2(1.0f - o.VFX_VARYING_UV.y, + o.VFX_VARYING_UV.x);\n\t\t\t#endif\n\t\t\t\t\n\t\t\t\t// Orient strips along + their tangents\n\t\t\t\tattributes.axisX = GetStripTangent(attributes.position, + currentIndex, stripData);\n\t\t\t#if !VFX_STRIPS_ORIENT_CUSTOM\n\t\t\t\tattributes.axisZ + = attributes.position - GetViewVFXPosition();\n\t\t\t#endif\n\t\t\t\tattributes.axisY + = normalize(cross(attributes.axisZ, attributes.axisX));\n\t\t\t\tattributes.axisZ + = normalize(cross(attributes.axisX, attributes.axisY));\n\t\t\t\t\n\t\t\t#else\n\t\t\t\to.VFX_VARYING_UV.x + = float(id & 1);\n\t\t\t\to.VFX_VARYING_UV.y = float((id & 2) >> 1);\n\t\t\t\tconst + float2 vOffsets = o.VFX_VARYING_UV.xy - 0.5f;\n\t\t\t#endif\n\t\t\t\t\n\t\t\t#elif + VFX_PRIMITIVE_TRIANGLE\n\t\t\t\n\t\t\t\tconst float2 kOffsets[] = {\n\t\t\t\t\tfloat2(-0.5f, + \t-0.288675129413604736328125f),\n\t\t\t\t\tfloat2(0.0f, \t0.57735025882720947265625f),\n\t\t\t\t\tfloat2(0.5f,\t-0.288675129413604736328125f),\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\tconst + float kUVScale = 0.866025388240814208984375f;\n\t\t\t\t\n\t\t\t\tconst float2 + vOffsets = kOffsets[id % 3];\n\t\t\t\to.VFX_VARYING_UV.xy = (vOffsets * kUVScale) + + 0.5f;\n\t\t\t\t\n\t\t\t#elif VFX_PRIMITIVE_OCTAGON\t\n\t\t\t\t\n\t\t\t\tconst + float2 kUvs[8] = \n\t\t\t\t{\n\t\t\t\t\tfloat2(-0.5f,\t0.0f),\n\t\t\t\t\tfloat2(-0.5f,\t0.5f),\n\t\t\t\t\tfloat2(0.0f,\t0.5f),\n\t\t\t\t\tfloat2(0.5f,\t0.5f),\n\t\t\t\t\tfloat2(0.5f,\t0.0f),\n\t\t\t\t\tfloat2(0.5f,\t-0.5f),\n\t\t\t\t\tfloat2(0.0f,\t-0.5f),\n\t\t\t\t\tfloat2(-0.5f,\t-0.5f),\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\t\n\t\t\t\tcropFactor + = id & 1 ? 1.0f - cropFactor : 1.0f;\n\t\t\t\tconst float2 vOffsets = kUvs[id + & 7] * cropFactor;\n\t\t\t\to.VFX_VARYING_UV.xy = vOffsets + 0.5f;\n\t\t\t\t\n\t\t\t#endif\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\tfloat3 + size3 = float3(attributes.size,attributes.size,attributes.size);\n\t\t\t\t\t\t#if + VFX_USE_SCALEX_CURRENT\n\t\t\t\t\t\tsize3.x *= attributes.scaleX;\n\t\t\t\t\t\t#endif\n\t\t\t\t\t\t#if + VFX_USE_SCALEY_CURRENT\n\t\t\t\t\t\tsize3.y *= attributes.scaleY;\n\t\t\t\t\t\t#endif\n\t\t\t\t\t\t#if + VFX_USE_SCALEZ_CURRENT\n\t\t\t\t\t\tsize3.z *= attributes.scaleZ;\n\t\t\t\t\t\t#endif\n\t\t\t\t\t\t\n\t\t\t#if + HAS_STRIPS\n\t\t\t\tsize3 += size3 < 0.0f ? -VFX_EPSILON : VFX_EPSILON; // + Add an epsilon so that size is never 0 for strips\n\t\t\t#endif\n\t\t\t\t\n\t\t\t\tconst + float4x4 elementToVFX = GetElementToVFXMatrix(\n\t\t\t\t\tattributes.axisX,\n\t\t\t\t\tattributes.axisY,\n\t\t\t\t\tattributes.axisZ,\n\t\t\t\t\tfloat3(attributes.angleX,attributes.angleY,attributes.angleZ),\n\t\t\t\t\tfloat3(attributes.pivotX,attributes.pivotY,attributes.pivotZ),\n\t\t\t\t\tsize3,\n\t\t\t\t\tattributes.position);\n\t\t\t\t\t\n\t\t\t\tfloat3 + inputVertexPosition = float3(vOffsets, 0.0f);\n\t\t\t\tfloat3 vPos = mul(elementToVFX,float4(inputVertexPosition, + 1.0f)).xyz;\n\t\t\t\n\t\t\t\to.VFX_VARYING_POSCS = TransformPositionVFXToClip(vPos);\n\t\t\t + \n\t\t\t float3 vPosWS = TransformPositionVFXToWorld(vPos);\n\t\t\t\t\n\t\t\t + #ifdef VFX_VARYING_POSWS\n\t\t\t o.VFX_VARYING_POSWS = vPosWS;\n\t\t\t + #endif\n\t\t\t\n\t\t\t\tfloat3 normalWS = normalize(TransformDirectionVFXToWorld(normalize(-transpose(elementToVFX)[2].xyz)));\n\t\t\t\t#ifdef + VFX_VARYING_NORMAL\n\t\t\t\tfloat normalFlip = (size3.x * size3.y * size3.z) + < 0 ? -1 : 1;\n\t\t\t\to.VFX_VARYING_NORMAL = normalFlip * normalWS;\n\t\t\t\t#endif\n\t\t\t\t#ifdef + VFX_VARYING_TANGENT\n\t\t\t\to.VFX_VARYING_TANGENT = normalize(TransformDirectionVFXToWorld(normalize(transpose(elementToVFX)[0].xyz)));\n\t\t\t\t#endif\n\t\t\t\t#ifdef + VFX_VARYING_BENTFACTORS\n\t\t\t\t\n\t\t\t\t#if HAS_STRIPS\n\t\t\t\t#define + BENT_FACTOR_MULTIPLIER 2.0f\n\t\t\t\t#else\n\t\t\t\t#define BENT_FACTOR_MULTIPLIER + 1.41421353816986083984375f\n\t\t\t\t#endif\n\t\t\t\to.VFX_VARYING_BENTFACTORS + = vOffsets * normalBendingFactor * BENT_FACTOR_MULTIPLIER;\n\t\t\t\t#endif\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\t#if + defined(VFX_VARYING_VELOCITY_CPOS) && defined(VFX_VARYING_VELOCITY_CPOS_PREVIOUS)\n\t\t\t\t\t\tfloat4x4 + previousElementToVFX = (float4x4)0;\n\t\t\t\t\t\tpreviousElementToVFX[3] = + float4(0,0,0,1);\n\t\t\t\t\t\t\n\t\t\t\t\t\tUNITY_UNROLL\n\t\t\t\t\t\tfor (int + itIndexMatrixRow = 0; itIndexMatrixRow < 3; ++itIndexMatrixRow)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tUNITY_UNROLL\n\t\t\t\t\t\t\tfor + (int itIndexMatrixCol = 0; itIndexMatrixCol < 4; ++itIndexMatrixCol)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tuint + itIndexMatrix = itIndexMatrixCol * 4 + itIndexMatrixRow;\n\t\t\t\t\t\t\t\tuint + read = elementToVFXBufferPrevious.Load((index * 16 + itIndexMatrix) << 2);\n\t\t\t\t\t\t\t\tpreviousElementToVFX[itIndexMatrixRow][itIndexMatrixCol] + = asfloat(read);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tuint + previousFrameIndex = elementToVFXBufferPrevious.Load((index * 16 + 15) << 2);\n\t\t\t\t\t\to.VFX_VARYING_VELOCITY_CPOS + = o.VFX_VARYING_VELOCITY_CPOS_PREVIOUS = float4(0.0f, 0.0f, 0.0f, 1.0f);\n\t\t\t\t\t\tif + (asuint(currentFrameIndex) - previousFrameIndex == 1u)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfloat3 + oldvPos = mul(previousElementToVFX,float4(inputVertexPosition, 1.0f)).xyz;\n\t\t\t\t\t\t\to.VFX_VARYING_VELOCITY_CPOS_PREVIOUS + = TransformPositionVFXToPreviousClip(oldvPos);\n\t\t\t\t\t\t\to.VFX_VARYING_VELOCITY_CPOS + = TransformPositionVFXToNonJitteredClip(vPos);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t#endif\n\t\t\t\t\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\t#if + VFX_USE_COLOR_CURRENT && defined(VFX_VARYING_COLOR)\n\t\t\t\t\t\to.VFX_VARYING_COLOR + = attributes.color;\n\t\t\t\t\t\t#endif\n\t\t\t\t\t\t#if VFX_USE_ALPHA_CURRENT + && defined(VFX_VARYING_ALPHA) \n\t\t\t\t\t\to.VFX_VARYING_ALPHA = attributes.alpha;\n\t\t\t\t\t\t#endif\n\t\t\t\t\t\t\n\t\t\t\t\t\t#ifdef + VFX_VARYING_EXPOSUREWEIGHT\n\t\t\t\t\t\t\n\t\t\t\t\t\to.VFX_VARYING_EXPOSUREWEIGHT + = exposureWeight;\n\t\t\t\t\t\t#endif\n\t\t\t\t\t\t\n\t\t\t\t\t\t#if USE_SOFT_PARTICLE + && defined(VFX_VARYING_INVSOFTPARTICLEFADEDISTANCE)\n\t\t\t\t\t\t\n\t\t\t\t\t\to.VFX_VARYING_INVSOFTPARTICLEFADEDISTANCE + = invSoftParticlesFadeDistance;\n\t\t\t\t\t\t#endif\n\t\t\t\t\t\t\n\t\t\t\t\t\t#if + (USE_ALPHA_TEST || WRITE_MOTION_VECTOR_IN_FORWARD) && (!VFX_SHADERGRAPH || + !HAS_SHADERGRAPH_PARAM_ALPHATHRESHOLD) && defined(VFX_VARYING_ALPHATHRESHOLD)\n\t\t\t\t\t\t\n\t\t\t\t\t\to.VFX_VARYING_ALPHATHRESHOLD + = alphaThreshold;\n\t\t\t\t\t\t#endif\n\t\t\t\t\t\t\n\t\t\t\t\t\t#if USE_UV_SCALE_BIAS\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t#if + defined (VFX_VARYING_UV)\n\t\t\t\t\t\to.VFX_VARYING_UV.xy = o.VFX_VARYING_UV.xy + * uvScale + uvBias;\n\t\t\t\t\t\t#endif\n\t\t\t\t\t\t#endif\n\t\t\t\t\t\t\n\t\t\t\t\t\t#if + defined(VFX_VARYING_POSWS)\n\t\t\t\t\t\to.VFX_VARYING_POSWS = TransformPositionVFXToWorld(vPos);\n\t\t\t\t\t\t#endif\n\t\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\t#if + USE_FLIPBOOK && defined(VFX_VARYING_UV)\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\tVFXUVData + uvData = GetUVData(flipBookSize, invFlipBookSize, o.VFX_VARYING_UV.xy, attributes.texIndex);\n\t\t\t\t\t\to.VFX_VARYING_UV.xy + = uvData.uvs.xy;\n\t\t\t\t\t\t#if USE_FLIPBOOK_INTERPOLATION && defined(VFX_VARYING_UV) + && defined (VFX_VARYING_FRAMEBLEND)\n\t\t\t\t\t\to.VFX_VARYING_UV.zw = uvData.uvs.zw;\n\t\t\t\t\t\to.VFX_VARYING_FRAMEBLEND + = uvData.blend;\n\t\t\t\t\t\t#if USE_FLIPBOOK_MOTIONVECTORS && defined(VFX_VARYING_MOTIONVECTORSCALE)\n\t\t\t\t\t\t\n\t\t\t\t\t\to.VFX_VARYING_MOTIONVECTORSCALE + = motionVectorScale * invFlipBookSize;\n\t\t\t\t\t\t#endif\n\t\t\t\t\t\t#endif\n\t\t\t\t\t\t#endif\n\t\t\t\t\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t + \n\t\t\t \n\t\t\t\n\t\t\t\treturn o;\n\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t#include + \"Packages/com.unity.visualeffectgraph/Shaders/VFXCommonOutput.hlsl\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t#if + VFX_SHADERGRAPH\n\t\t\t\n\t\t#endif\n\t\t\t\t\n\t\t\t#pragma fragment frag\n\t\t\tps_output + frag(ps_input i)\n\t\t\t{\n\t\t\t\tUNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);\n\t\t\t\tps_output + o = (ps_output)0;\n\t\t\t\tVFXTransformPSInputs(i);\n\t\t\t\t\n\t\t\t\t\t\t\t#ifdef + VFX_VARYING_NORMAL\n\t\t\t\t\t\t\t#if USE_DOUBLE_SIDED\n\t\t\t\t\t\t\tconst + float faceMul = frontFace ? 1.0f : -1.0f;\n\t\t\t\t\t\t\t#else\n\t\t\t\t\t\t\tconst + float faceMul = 1.0f;\n\t\t\t\t\t\t\t#endif\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfloat3 + normalWS = i.VFX_VARYING_NORMAL * faceMul;\n\t\t\t\t\t\t\tconst VFXUVData uvData + = GetUVData(i);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t#ifdef VFX_VARYING_TANGENT\n\t\t\t\t\t\t\tfloat3 + tangentWS = i.VFX_VARYING_TANGENT;\n\t\t\t\t\t\t\tfloat3 bitangentWS = cross(i.VFX_VARYING_TANGENT,i.VFX_VARYING_NORMAL);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t#if + defined(VFX_VARYING_BENTFACTORS) && USE_NORMAL_BENDING\t\n\t\t\t\t\t\t\tfloat3 + bentFactors = float3(i.VFX_VARYING_BENTFACTORS.xy,sqrt(1.0f - dot(i.VFX_VARYING_BENTFACTORS,i.VFX_VARYING_BENTFACTORS)));\n\t\t\t\t\t\t\tnormalWS + = tangentWS * bentFactors.x + bitangentWS * bentFactors.y + normalWS * bentFactors.z;\n\t\t\t\t\t\t\ttangentWS + = normalize(cross(normalWS,bitangentWS));\n\t\t\t\t\t\t\tbitangentWS = cross(tangentWS,normalWS);\n\t\t\t\t\t\t\ttangentWS + *= faceMul;\n\t\t\t\t\t\t\t#endif\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfloat3x3 tbn + = float3x3(tangentWS,bitangentWS,normalWS);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t#if + USE_NORMAL_MAP\n\t\t\t\t\t\t\tfloat3 n = SampleNormalMap(VFX_SAMPLER(normalMap),uvData);\n\t\t\t\t\t\t\tfloat + normalScale = 1.0f;\n\t\t\t\t\t\t\t#ifdef VFX_VARYING_NORMALSCALE\n\t\t\t\t\t\t\tnormalScale + = i.VFX_VARYING_NORMALSCALE;\n\t\t\t\t\t\t\t#endif\n\t\t\t\t\t\t\tnormalWS + = normalize(lerp(normalWS,mul(n,tbn),normalScale));\n\t\t\t\t\t\t\t#endif\n\t\t\t\t\t\t\t#endif\n\t\t\t\t\t\t\t#endif\n\t\t\t\t\t\t\t\n\t\t\t\t\n\t\t#if + VFX_SHADERGRAPH\n\t\t \n\t\t \n\t\t \n\t\t \n\t\t + #if HAS_SHADERGRAPH_PARAM_COLOR\n\t\t o.color.rgb = OUTSG..rgb;\n\t\t + #endif\n\t\t \n\t\t #if HAS_SHADERGRAPH_PARAM_ALPHA \n\t\t + o.color.a = OUTSG.;\n\t\t #endif\n\t\t#else\n\t\t\t\n\t\t\t\t#define + VFX_TEXTURE_COLOR VFXGetTextureColor(VFX_SAMPLER(mainTexture),i)\n\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\tfloat4 + color = VFXGetFragmentColor(i);\n\t\t\t\t\t\t\n\t\t\t\t\t\t#ifndef VFX_TEXTURE_COLOR\n\t\t\t\t\t\t\t#define + VFX_TEXTURE_COLOR float4(1.0,1.0,1.0,1.0)\n\t\t\t\t\t\t#endif\n\t\t\t\t\t\t\n\t\t\t\t\t\t#if + VFX_COLORMAPPING_DEFAULT\n\t\t\t\t\t\t\to.color = color * VFX_TEXTURE_COLOR;\n\t\t\t\t\t\t#endif\n\t\t\t\t\t\t\n\t\t\t\t\t\t#if + VFX_COLORMAPPING_GRADIENTMAPPED\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\to.color = SampleGradient(gradient, + VFX_TEXTURE_COLOR.a * color.a) * float4(color.rgb,1.0);\n\t\t\t\t\t\t#endif\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\to.color + = VFXApplyPreExposure(o.color, i);\n\t\t#endif\n\t\t\n\t\t\t\to.color = VFXApplyFog(o.color,i);\n\t\t\t\tVFXClipFragmentColor(o.color.a,i);\n\t\t\t\to.color.a + = saturate(o.color.a);\n\t\t\t\to.color = VFXTransformFinalColor(o.color);\n\t\t\t\t\n\t\t#if + WRITE_MOTION_VECTOR_IN_FORWARD\n\t\t\t\t\n\t\t\t\t\t\tfloat2 velocity = (i.VFX_VARYING_VELOCITY_CPOS.xy/i.VFX_VARYING_VELOCITY_CPOS.w) + - (i.VFX_VARYING_VELOCITY_CPOS_PREVIOUS.xy/i.VFX_VARYING_VELOCITY_CPOS_PREVIOUS.w);\n\t\t\t\t\t\t#if + UNITY_UV_STARTS_AT_TOP\n\t\t\t\t\t\t\tvelocity.y = -velocity.y;\n\t\t\t\t\t\t#endif\n\t\t\t\t\t\tfloat4 + encodedMotionVector = 0.0f;\n\t\t\t\t\t\tVFXEncodeMotionVector(velocity * 0.5f, + encodedMotionVector);\n\t\t\t\t\t\t\n\t\t\t\to.outMotionVector = encodedMotionVector;\n\t\t + o.outMotionVector.a = o.color.a < i.VFX_VARYING_ALPHATHRESHOLD ? 0.0f : 1.0f; + //Independant clipping for motion vector pass\n\t\t#endif\n\t\t\t\treturn o;\n\t\t\t}\n\t\t\tENDHLSL\n\t\t}\n\t\t\n\r\n\t\t\r\n\t}\r\n}\r\n" + - compute: 1 + name: '[System 1]B Update Particle' + source: "#pragma kernel CSMain\r\n#define NB_THREADS_PER_GROUP 64\n#define HAS_ATTRIBUTES + 1\n#define VFX_PASSDEPTH_ACTUAL (0)\n#define VFX_PASSDEPTH_MOTION_VECTOR (1)\n#define + VFX_PASSDEPTH_SELECTION (2)\n#define VFX_USE_AGE_CURRENT 1\n#define VFX_USE_LIFETIME_CURRENT + 1\n#define VFX_USE_ALIVE_CURRENT 1\n#define VFX_HAS_INDIRECT_DRAW 1\n#define + VFX_LOCAL_SPACE 1\n#include \"Packages/com.unity.visualeffectgraph/Shaders/RenderPipeline/Legacy/VFXDefines.hlsl\"\n\n\r\nCBUFFER_START(parameters)\n + float deltaTime_a;\n uint3 PADDING_0;\nCBUFFER_END\n\nstruct Attributes\n{\n + float age;\n float lifetime;\n bool alive;\n};\n\nstruct SourceAttributes\n{\n};\n\n\n\r\n\r\n#define + USE_DEAD_LIST (VFX_USE_ALIVE_CURRENT && !HAS_STRIPS)\r\n\r\nRWByteAddressBuffer + attributeBuffer;\r\n\r\n#if USE_DEAD_LIST\r\nRWStructuredBuffer deadListOut;\r\n#endif\r\n\r\n#if + VFX_HAS_INDIRECT_DRAW\r\nRWStructuredBuffer indirectBuffer;\r\n#endif\r\n\r\n#if + HAS_STRIPS\r\nRWBuffer stripDataBuffer;\r\n#endif\r\n\r\n#if VFX_USE_STRIPALIVE_CURRENT\r\nBuffer + attachedStripDataBuffer;\r\n#endif\r\n\r\nCBUFFER_START(updateParams)\r\n + uint nbMax;\r\n\tuint dispatchWidth;\r\n\tuint systemSeed;\r\nCBUFFER_END\r\n\r\n#include + \"Packages/com.unity.visualeffectgraph/Shaders/Common/VFXCommonCompute.hlsl\"\n#include + \"Packages/com.unity.visualeffectgraph/Shaders/VFXCommon.hlsl\"\n\n\r\n\r\nvoid + Age(inout float age, float deltaTime)\n{\n age += deltaTime;\n}\nvoid Reap(float + age, float lifetime, inout bool alive)\n{\n if(age > lifetime) { alive = + false; }\n}\n\n\r\n\r\n[numthreads(NB_THREADS_PER_GROUP,1,1)]\r\nvoid CSMain(uint3 + groupId : SV_GroupID,\r\n uint3 groupThreadId : SV_GroupThreadID)\r\n{\r\n\tuint + id = groupThreadId.x + groupId.x * NB_THREADS_PER_GROUP + groupId.y * dispatchWidth + * NB_THREADS_PER_GROUP;\r\n\tuint index = id;\r\n\tif (id < nbMax)\r\n\t{\r\n + Attributes attributes = (Attributes)0;\r\n\t\tSourceAttributes sourceAttributes + = (SourceAttributes)0;\r\n\r\n#if VFX_USE_ALIVE_CURRENT\r\n\t\tattributes.alive + = (attributeBuffer.Load((index * 0x1 + 0x53EDC0) << 2));\n\t\t\n\r\n\t\tif + (attributes.alive)\r\n\t\t{\r\n\t\t\tattributes.age = asfloat(attributeBuffer.Load((index + * 0x1 + 0x1E8500) << 2));\n\t\t\tattributes.lifetime = asfloat(attributeBuffer.Load((index + * 0x1 + 0x262640) << 2));\n\t\t\t\n\r\n\r\n// Initialize built-in needed attributes\r\n#if + VFX_USE_OLDPOSITION_CURRENT\r\n\t\t\tattributes.oldPosition = attributes.position;\r\n#endif\r\n#if + HAS_STRIPS\r\n const StripData stripData = GetStripDataFromParticleIndex(index, + PARTICLE_PER_STRIP_COUNT);\r\n InitStripAttributes(index, attributes, + stripData);\r\n#endif\r\n\t\t\t\r\n\t\t\tAge( /*inout */attributes.age, deltaTime_a);\n\t\t\tReap(attributes.age, + attributes.lifetime, /*inout */attributes.alive);\n\t\t\t\n\r\n\r\n\t\t\tif + (attributes.alive)\r\n\t\t\t{\r\n\t\t\t\tattributeBuffer.Store((index * 0x1 + + 0x1E8500) << 2,asuint(attributes.age));\n\t\t\t\t\n\r\n#if VFX_HAS_INDIRECT_DRAW\r\n + uint indirectIndex = indirectBuffer.IncrementCounter();\r\n\t\t\t\tindirectBuffer[indirectIndex] + = index;\r\n#endif\r\n\r\n#if HAS_STRIPS\t\t\t\r\n\t\t\t\tuint relativeIndexInStrip + = GetRelativeIndex(index, stripData);\r\n\t\t\t\tInterlockedMin(STRIP_DATA(STRIP_MIN_ALIVE, + stripData.stripIndex), relativeIndexInStrip);\r\n\t\t\t\tInterlockedMax(STRIP_DATA(STRIP_MAX_ALIVE, + stripData.stripIndex), relativeIndexInStrip);\r\n#endif\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tattributeBuffer.Store((index + * 0x1 + 0x53EDC0) << 2,uint(attributes.alive));\n\t\t\t\t\n\r\n#if USE_DEAD_LIST + && !VFX_USE_STRIPALIVE_CURRENT\r\n\t\t\t\tuint deadIndex = deadListOut.IncrementCounter();\r\n\t\t\t\tdeadListOut[deadIndex] + = index;\r\n#endif\r\n\t\t\t}\r\n\t\t}\r\n#if USE_DEAD_LIST && VFX_USE_STRIPALIVE_CURRENT\r\n + else if (attributes.stripAlive)\r\n {\r\n if (STRIP_DATA_X(attachedStripDataBuffer, + STRIP_MIN_ALIVE, index) == ~1) // Attached strip is no longer alive, recycle + the particle \r\n {\r\n uint deadIndex = deadListOut.IncrementCounter();\r\n\t\t\t\tdeadListOut[deadIndex] + = index;\r\n attributes.stripAlive = false;\r\n + \r\n } \r\n }\r\n#endif\r\n#else\r\n\t\tattributes.age + = asfloat(attributeBuffer.Load((index * 0x1 + 0x1E8500) << 2));\n\t\tattributes.lifetime + = asfloat(attributeBuffer.Load((index * 0x1 + 0x262640) << 2));\n\t\tattributes.alive + = (attributeBuffer.Load((index * 0x1 + 0x53EDC0) << 2));\n\t\t\n\r\n\t\t\r\n#if + VFX_USE_OLDPOSITION_CURRENT\r\n\t\tattributes.oldPosition = attributes.position;\r\n#endif\r\n#if + HAS_STRIPS\r\n const StripData stripData = GetStripDataFromParticleIndex(index, + PARTICLE_PER_STRIP_COUNT);\r\n InitStripAttributes(index, attributes, + stripData);\r\n#endif\r\n\t\t\r\n\t\tAge( /*inout */attributes.age, deltaTime_a);\n\t\tReap(attributes.age, + attributes.lifetime, /*inout */attributes.alive);\n\t\t\n\r\n\t\tattributeBuffer.Store((index + * 0x1 + 0x1E8500) << 2,asuint(attributes.age));\n\t\tattributeBuffer.Store((index + * 0x1 + 0x53EDC0) << 2,uint(attributes.alive));\n\t\t\n\r\n#if VFX_HAS_INDIRECT_DRAW\r\n + uint indirectIndex = indirectBuffer.IncrementCounter();\r\n\t\tindirectBuffer[indirectIndex] + = index;\r\n#endif\r\n#endif\r\n\t}\r\n}\r\n" + - compute: 1 + name: '[System 1]CameraSort' + source: "#pragma kernel CSMain\r\n#define NB_THREADS_PER_GROUP 64\n#define HAS_ATTRIBUTES + 1\n#define VFX_PASSDEPTH_ACTUAL (0)\n#define VFX_PASSDEPTH_MOTION_VECTOR (1)\n#define + VFX_PASSDEPTH_SELECTION (2)\n#define VFX_USE_POSITION_CURRENT 1\n#define USE_DEAD_LIST_COUNT + 1\n#define VFX_LOCAL_SPACE 1\n#include \"Packages/com.unity.visualeffectgraph/Shaders/RenderPipeline/Legacy/VFXDefines.hlsl\"\n\n\r\nCBUFFER_START(parameters)\n + float4x4 localToWorld;\nCBUFFER_END\n\nstruct Attributes\n{\n float3 position;\n};\n\nstruct + SourceAttributes\n{\n};\n\n\n\r\n#include \"Packages/com.unity.visualeffectgraph/Shaders/Common/VFXCommonCompute.hlsl\"\n#include + \"Packages/com.unity.visualeffectgraph/Shaders/VFXCommon.hlsl\"\n\n\r\n\r\nCBUFFER_START(params)\r\n + uint nbMax;\r\n uint dispatchWidth;\r\nCBUFFER_END\r\n\r\nCBUFFER_START(cameraParams)\r\n + float3 cameraPosition;\r\nCBUFFER_END\r\n\r\nByteAddressBuffer attributeBuffer;\r\nStructuredBuffer + inputBuffer;\r\n\r\n#if USE_DEAD_LIST_COUNT\r\nByteAddressBuffer deadListCount;\r\n#endif\r\n\r\nstruct + Kvp\r\n{\r\n\tfloat sortKey;\r\n\tuint index;\r\n};\r\n\r\nRWStructuredBuffer + outputBuffer;\r\n\r\n[numthreads(NB_THREADS_PER_GROUP,1,1)]\r\nvoid CSMain(uint3 + groupId : SV_GroupID,\r\n uint3 groupThreadId : SV_GroupThreadID)\r\n{\r\n\tuint + threshold = nbMax;\r\n#if USE_DEAD_LIST_COUNT\r\n\tthreshold -= deadListCount.Load(0);\r\n#endif\r\n\tuint + id = groupThreadId.x + groupId.x * NB_THREADS_PER_GROUP + groupId.y * dispatchWidth + * NB_THREADS_PER_GROUP;\r\n\tif (id < threshold)\r\n\t{\r\n\t\tuint index = + inputBuffer[id];\r\n\t\t\r\n\t\tAttributes attributes = (Attributes)0;\r\n\t\tattributes.position + = asfloat(attributeBuffer.Load3((index * 0x4 + 0x2DC780) << 2));\n\t\t\n\r\n\t\t\r\n#if + VFX_LOCAL_SPACE\r\n\t\tfloat3 wPos = mul(localToWorld,float4(attributes.position,1.0f)).xyz;\r\n#else\r\n\t\tfloat3 + wPos = attributes.position;\r\n#endif\r\n\t\tfloat3 camToPos = wPos - cameraPosition;\r\n\t\t\r\n\t\tKvp + kvp;\r\n\t\tkvp.sortKey = dot(camToPos,camToPos); // sqr distance to the camera\r\n\t\tkvp.index + = index;\r\n\r\n\t\toutputBuffer[id] = kvp;\r\n\t}\r\n}\r\n" + m_Infos: + m_Expressions: + m_Expressions: + - op: 1 + valueIndex: 0 + data[0]: -1 + data[1]: -1 + data[2]: -1 + data[3]: 3 + - op: 1 + valueIndex: 3 + data[0]: -1 + data[1]: -1 + data[2]: -1 + data[3]: 3 + - op: 1 + valueIndex: 6 + data[0]: -1 + data[1]: -1 + data[2]: -1 + data[3]: 1 + - op: 1 + valueIndex: 7 + data[0]: -1 + data[1]: -1 + data[2]: -1 + data[3]: 7 + - op: 1 + valueIndex: 8 + data[0]: -1 + data[1]: -1 + data[2]: -1 + data[3]: 7 + - op: 1 + valueIndex: 9 + data[0]: -1 + data[1]: -1 + data[2]: -1 + data[3]: 1 + - op: 1 + valueIndex: 10 + data[0]: -1 + data[1]: -1 + data[2]: -1 + data[3]: 1 + - op: 1 + valueIndex: 11 + data[0]: -1 + data[1]: -1 + data[2]: -1 + data[3]: 6 + - op: 1 + valueIndex: 12 + data[0]: -1 + data[1]: -1 + data[2]: -1 + data[3]: 3 + - op: 1 + valueIndex: 15 + data[0]: -1 + data[1]: -1 + data[2]: -1 + data[3]: 3 + - op: 1 + valueIndex: 18 + data[0]: -1 + data[1]: -1 + data[2]: -1 + data[3]: 1 + - op: 6 + valueIndex: 19 + data[0]: -1 + data[1]: -1 + data[2]: -1 + data[3]: -1 + - op: 1 + valueIndex: 20 + data[0]: -1 + data[1]: -1 + data[2]: -1 + data[3]: 7 + - op: 9 + valueIndex: 21 + data[0]: -1 + data[1]: -1 + data[2]: -1 + data[3]: -1 + m_NeedsLocalToWorld: 1 + m_NeedsWorldToLocal: 0 + m_NeededMainCameraBuffers: 0 + m_PropertySheet: + m_Float: + m_Array: + - m_ExpressionIndex: 2 + m_Value: 25000 + - m_ExpressionIndex: 5 + m_Value: 1 + - m_ExpressionIndex: 6 + m_Value: 0 + - m_ExpressionIndex: 10 + m_Value: 0.04 + m_Vector2f: + m_Array: [] + m_Vector3f: + m_Array: + - m_ExpressionIndex: 0 + m_Value: {x: 0, y: 1, z: 0} + - m_ExpressionIndex: 1 + m_Value: {x: 50, y: 50, z: 50} + - m_ExpressionIndex: 8 + m_Value: {x: 0, y: 0, z: 0} + - m_ExpressionIndex: 9 + m_Value: {x: 1, y: 1, z: 1} + m_Vector4f: + m_Array: [] + m_Uint: + m_Array: + - m_ExpressionIndex: 7 + m_Value: 0 + m_Int: + m_Array: [] + m_Matrix4x4f: + m_Array: [] + m_AnimationCurve: + m_Array: [] + m_Gradient: + m_Array: [] + m_NamedObject: + m_Array: + - m_ExpressionIndex: 3 + m_Value: {fileID: 2800000, guid: 276d9e395ae18fe40a9b4988549f2349, type: 3} + - m_ExpressionIndex: 4 + m_Value: {fileID: 2800000, guid: 276d9e395ae18fe40a9b4988549f2349, type: 3} + - m_ExpressionIndex: 12 + m_Value: {fileID: 10300, guid: 0000000000000000f000000000000000, type: 0} + m_Bool: + m_Array: [] + m_ExposedExpressions: + - nameId: ColorMap + index: 4 + - nameId: PositionMap + index: 3 + m_Buffers: + - type: 1 + size: 6000384 + layout: + - name: color + type: 3 + offset: + bucket: 0 + structure: 4 + element: 0 + - name: size + type: 1 + offset: + bucket: 0 + structure: 4 + element: 3 + - name: age + type: 1 + offset: + bucket: 2000128 + structure: 1 + element: 0 + - name: lifetime + type: 1 + offset: + bucket: 2500160 + structure: 1 + element: 0 + - name: position + type: 3 + offset: + bucket: 3000192 + structure: 4 + element: 0 + - name: particleId + type: 6 + offset: + bucket: 5000320 + structure: 1 + element: 0 + - name: alive + type: 17 + offset: + bucket: 5500352 + structure: 1 + element: 0 + capacity: 500032 + stride: 4 + - type: 1 + size: 1 + layout: + - name: spawnCount + type: 1 + offset: + bucket: 0 + structure: 1 + element: 0 + capacity: 1 + stride: 4 + - type: 4 + size: 500000 + layout: [] + capacity: 0 + stride: 4 + - type: 1 + size: 1 + layout: [] + capacity: 0 + stride: 4 + - type: 4 + size: 500000 + layout: [] + capacity: 0 + stride: 4 + - type: 0 + size: 500000 + layout: [] + capacity: 0 + stride: 8 + - type: 0 + size: 500000 + layout: [] + capacity: 0 + stride: 8 + m_TemporaryBuffers: [] + m_CPUBuffers: + - capacity: 1 + stride: 1 + layout: + - name: spawnCount + type: 1 + offset: + bucket: 0 + structure: 1 + element: 0 + initialData: + data: 00000000 + - capacity: 1 + stride: 1 + layout: + - name: spawnCount + type: 1 + offset: + bucket: 0 + structure: 1 + element: 0 + initialData: + data: 00000000 + m_Events: + - name: OnPlay + playSystems: 00000000 + stopSystems: + - name: OnStop + playSystems: + stopSystems: 00000000 + m_RuntimeVersion: 10 + m_RendererSettings: + motionVectorGenerationMode: 0 + shadowCastingMode: 0 + receiveShadows: 0 + reflectionProbeUsage: 0 + lightProbeUsage: 0 + m_CullingFlags: 3 + m_UpdateMode: 0 + m_PreWarmDeltaTime: 0.05 + m_PreWarmStepCount: 0 + m_InitialEventName: OnPlay + m_Systems: + - type: 0 + flags: 0 + capacity: 0 + layer: 4294967295 + buffers: + - nameId: spawner_output + index: 1 + values: [] + tasks: + - type: 268435456 + buffers: [] + temporaryBuffers: [] + values: + - nameId: Rate + index: 2 + params: [] + processor: {fileID: 0} + shaderSourceIndex: -1 + - type: 1 + flags: 3 + capacity: 500000 + layer: 4294967295 + buffers: + - nameId: attributeBuffer + index: 0 + - nameId: sourceAttributeBuffer + index: 1 + - nameId: deadList + index: 2 + - nameId: deadListCount + index: 3 + - nameId: spawner_input + index: 1 + - nameId: indirectBuffer + index: 4 + - nameId: sortBufferA + index: 5 + - nameId: sortBufferB + index: 6 + values: + - nameId: bounds_center + index: 0 + - nameId: bounds_size + index: 1 + tasks: + - type: 536870912 + buffers: + - nameId: attributeBuffer + index: 0 + - nameId: deadListIn + index: 2 + - nameId: deadListCount + index: 3 + - nameId: sourceAttributeBuffer + index: 1 + temporaryBuffers: [] + values: + - nameId: attributeMap_d + index: 3 + - nameId: attributeMap_e + index: 4 + params: + - nameId: bounds_center + index: 0 + - nameId: bounds_size + index: 1 + processor: {fileID: 0} + shaderSourceIndex: 0 + - type: 805306368 + buffers: + - nameId: attributeBuffer + index: 0 + - nameId: deadListOut + index: 2 + - nameId: indirectBuffer + index: 4 + temporaryBuffers: [] + values: + - nameId: deltaTime_d + index: 11 + - nameId: attributeMap_b + index: 3 + - nameId: attributeMap_c + index: 4 + params: [] + processor: {fileID: 0} + shaderSourceIndex: 1 + - type: 805306368 + buffers: + - nameId: attributeBuffer + index: 0 + - nameId: deadListOut + index: 2 + - nameId: indirectBuffer + index: 4 + temporaryBuffers: [] + values: + - nameId: deltaTime_a + index: 11 + params: [] + processor: {fileID: 0} + shaderSourceIndex: 3 + - type: 805306369 + buffers: + - nameId: attributeBuffer + index: 0 + - nameId: inputBuffer + index: 4 + - nameId: outputBuffer + index: 5 + - nameId: deadListCount + index: 3 + temporaryBuffers: [] + values: + - nameId: localToWorld + index: 13 + params: [] + processor: {fileID: 0} + shaderSourceIndex: 4 + - type: 1073741826 + buffers: + - nameId: attributeBuffer + index: 0 + - nameId: indirectBuffer + index: 4 + - nameId: deadListCount + index: 3 + temporaryBuffers: [] + values: + - nameId: mainTexture + index: 12 + params: + - nameId: sortPriority + index: 0 + - nameId: indirectDraw + index: 1 + processor: {fileID: 0} + shaderSourceIndex: 2 +--- !u!114 &8926484042661614541 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 60fff265f139e2a4194a44c2bac41757, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 114946465509916290} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 8926484042661614542} + - {fileID: 8926484042661614603} + - {fileID: 8926484042661614544} + - {fileID: 8926484042661614548} + m_OutputSlots: [] + m_Disabled: 0 + attribute: position + Composition: 0 + SampleMode: 6 + channels: 6 +--- !u!114 &8926484042661614542 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 70a331b1d86cc8d4aa106ccbe0da5852, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614542} + m_MasterData: + m_Owner: {fileID: 8926484042661614541} + m_Value: + m_Type: + m_SerializableType: UnityEngine.Texture2D, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"obj":{"fileID":2800000,"guid":"1d8481de16af723418a688958c41224b","type":3}}' + m_Space: 2147483647 + m_Property: + name: attributeMap + m_serializedType: + m_SerializableType: UnityEngine.Texture2D, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: AttributeMap texture to read attributes from + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: + - {fileID: 8926484042661614553} +--- !u!114 &8926484042661614544 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: + - {fileID: 8926484042661614545} + - {fileID: 8926484042661614546} + - {fileID: 8926484042661614547} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614544} + m_MasterData: + m_Owner: {fileID: 8926484042661614541} + m_Value: + m_Type: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"x":0.0,"y":0.0,"z":0.0}' + m_Space: 2147483647 + m_Property: + name: valueBias + m_serializedType: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: Bias Applied to the read Vector3 value + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614545 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614544} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614544} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: x + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614546 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614544} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614544} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: y + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614547 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614544} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614544} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: z + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614548 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: + - {fileID: 8926484042661614549} + - {fileID: 8926484042661614550} + - {fileID: 8926484042661614551} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614548} + m_MasterData: + m_Owner: {fileID: 8926484042661614541} + m_Value: + m_Type: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"x":1.0,"y":1.0,"z":1.0}' + m_Space: 2147483647 + m_Property: + name: valueScale + m_serializedType: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: Scale Applied to the read Vector3 value + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614549 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614548} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614548} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: x + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614550 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614548} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614548} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: y + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614551 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614548} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614548} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: z + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614552 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 330e0fca1717dde4aaa144f48232aa64, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 114350483966674976} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: [] + m_OutputSlots: + - {fileID: 8926484042661614553} + m_ExposedName: PositionMap + m_Exposed: 1 + m_Order: 0 + m_Category: + m_Min: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Max: + m_Type: + m_SerializableType: + m_SerializableObject: + m_IsOutput: 0 + m_Tooltip: + m_Nodes: + - m_Id: 0 + linkedSlots: + - outputSlot: {fileID: 8926484042661614553} + inputSlot: {fileID: 8926484042661614542} + - outputSlot: {fileID: 8926484042661614553} + inputSlot: {fileID: 8926484042661614656} + position: {x: 158, y: 912} + expandedSlots: [] + expanded: 0 +--- !u!114 &8926484042661614553 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 70a331b1d86cc8d4aa106ccbe0da5852, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614553} + m_MasterData: + m_Owner: {fileID: 8926484042661614552} + m_Value: + m_Type: + m_SerializableType: UnityEngine.Texture2D, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"obj":{"fileID":2800000,"guid":"276d9e395ae18fe40a9b4988549f2349","type":3}}' + m_Space: 2147483647 + m_Property: + name: o + m_serializedType: + m_SerializableType: UnityEngine.Texture2D, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + attributes: [] + m_Direction: 1 + m_LinkedSlots: + - {fileID: 8926484042661614542} + - {fileID: 8926484042661614656} +--- !u!114 &8926484042661614555 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a971fa2e110a0ac42ac1d8dae408704b, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 114946465509916290} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 8926484042661614556} + m_OutputSlots: [] + m_Disabled: 0 + attribute: size + Composition: 1 + Source: 0 + Random: 0 + channels: 6 +--- !u!114 &8926484042661614556 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614556} + m_MasterData: + m_Owner: {fileID: 8926484042661614555} + m_Value: + m_Type: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: 1 + m_Space: 2147483647 + m_Property: + name: Size + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: The uniform size of the particle. + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614557 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 60fff265f139e2a4194a44c2bac41757, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 114946465509916290} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 8926484042661614558} + - {fileID: 8926484042661614602} + - {fileID: 8926484042661614560} + - {fileID: 8926484042661614564} + m_OutputSlots: [] + m_Disabled: 0 + attribute: color + Composition: 0 + SampleMode: 6 + channels: 6 +--- !u!114 &8926484042661614558 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 70a331b1d86cc8d4aa106ccbe0da5852, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614558} + m_MasterData: + m_Owner: {fileID: 8926484042661614557} + m_Value: + m_Type: + m_SerializableType: UnityEngine.Texture2D, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"obj":{"fileID":2800000,"guid":"1d8481de16af723418a688958c41224b","type":3}}' + m_Space: 2147483647 + m_Property: + name: attributeMap + m_serializedType: + m_SerializableType: UnityEngine.Texture2D, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: AttributeMap texture to read attributes from + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: + - {fileID: 8926484042661614569} +--- !u!114 &8926484042661614560 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: + - {fileID: 8926484042661614561} + - {fileID: 8926484042661614562} + - {fileID: 8926484042661614563} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614560} + m_MasterData: + m_Owner: {fileID: 8926484042661614557} + m_Value: + m_Type: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"x":0.0,"y":0.0,"z":0.0}' + m_Space: 2147483647 + m_Property: + name: valueBias + m_serializedType: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: Bias Applied to the read Vector3 value + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614561 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614560} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614560} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: x + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614562 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614560} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614560} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: y + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614563 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614560} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614560} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: z + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614564 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: + - {fileID: 8926484042661614565} + - {fileID: 8926484042661614566} + - {fileID: 8926484042661614567} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614564} + m_MasterData: + m_Owner: {fileID: 8926484042661614557} + m_Value: + m_Type: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"x":1.0,"y":1.0,"z":1.0}' + m_Space: 2147483647 + m_Property: + name: valueScale + m_serializedType: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: Scale Applied to the read Vector3 value + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614565 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614564} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614564} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: x + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614566 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614564} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614564} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: y + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614567 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614564} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614564} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: z + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614568 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 330e0fca1717dde4aaa144f48232aa64, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 114350483966674976} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: [] + m_OutputSlots: + - {fileID: 8926484042661614569} + m_ExposedName: ColorMap + m_Exposed: 1 + m_Order: 1 + m_Category: + m_Min: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Max: + m_Type: + m_SerializableType: + m_SerializableObject: + m_IsOutput: 0 + m_Tooltip: + m_Nodes: + - m_Id: 0 + linkedSlots: + - outputSlot: {fileID: 8926484042661614569} + inputSlot: {fileID: 8926484042661614558} + - outputSlot: {fileID: 8926484042661614569} + inputSlot: {fileID: 8926484042661614667} + position: {x: 181, y: 1073} + expandedSlots: [] + expanded: 0 +--- !u!114 &8926484042661614569 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 70a331b1d86cc8d4aa106ccbe0da5852, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614569} + m_MasterData: + m_Owner: {fileID: 8926484042661614568} + m_Value: + m_Type: + m_SerializableType: UnityEngine.Texture2D, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"obj":{"fileID":2800000,"guid":"276d9e395ae18fe40a9b4988549f2349","type":3}}' + m_Space: 2147483647 + m_Property: + name: o + m_serializedType: + m_SerializableType: UnityEngine.Texture2D, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + attributes: [] + m_Direction: 1 + m_LinkedSlots: + - {fileID: 8926484042661614558} + - {fileID: 8926484042661614667} +--- !u!114 &8926484042661614573 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a0b9e6b9139e58d4c957ec54595da7d3, type: 3} + m_Name: VFXQuadOutput + m_EditorClassIdentifier: + m_Parent: {fileID: 114350483966674976} + m_Children: + - {fileID: 8926484042661614583} + - {fileID: 8926484042661614574} + m_UIPosition: {x: 707, y: 2062} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 8926484042661614579} + m_OutputSlots: [] + m_Label: + m_Data: {fileID: 114428730288789306} + m_InputFlowSlot: + - link: + - context: {fileID: 8926484042661614760} + slotIndex: 0 + m_OutputFlowSlot: + - link: [] + blendMode: 2 + useAlphaClipping: 0 + generateMotionVector: 0 + m_SubOutputs: + - {fileID: 0} + cullMode: 0 + zWriteMode: 0 + zTestMode: 0 + colorMapping: 0 + uvMode: 0 + useSoftParticle: 0 + sortPriority: 0 + sort: 0 + indirectDraw: 0 + castShadows: 0 + useExposureWeight: 0 + shaderGraph: {fileID: 0} + shadergraphGUID: + primitiveType: 1 + useGeometryShader: 0 +--- !u!114 &8926484042661614574 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d16c6aeaef944094b9a1633041804207, type: 3} + m_Name: Orient + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614573} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: [] + m_OutputSlots: [] + m_Disabled: 0 + mode: 0 + axes: 4 +--- !u!114 &8926484042661614579 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 70a331b1d86cc8d4aa106ccbe0da5852, type: 3} + m_Name: VFXSlotTexture2D + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614579} + m_MasterData: + m_Owner: {fileID: 8926484042661614573} + m_Value: + m_Type: + m_SerializableType: UnityEngine.Texture2D, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"obj":{"fileID":10300,"guid":"0000000000000000f000000000000000","type":0}}' + m_Space: 2147483647 + m_Property: + name: mainTexture + m_serializedType: + m_SerializableType: UnityEngine.Texture2D, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: Specifies the base color (RGB) and opacity (A) of the particle. + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614583 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a971fa2e110a0ac42ac1d8dae408704b, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614573} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 8926484042661614584} + m_OutputSlots: [] + m_Disabled: 1 + attribute: size + Composition: 0 + Source: 0 + Random: 0 + channels: 6 +--- !u!114 &8926484042661614584 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614584} + m_MasterData: + m_Owner: {fileID: 8926484042661614583} + m_Value: + m_Type: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: 0.05 + m_Space: 2147483647 + m_Property: + name: Size + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: The uniform size of the particle. + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614591 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a971fa2e110a0ac42ac1d8dae408704b, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 114946465509916290} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 8926484042661614592} + m_OutputSlots: [] + m_Disabled: 0 + attribute: lifetime + Composition: 1 + Source: 0 + Random: 0 + channels: 6 +--- !u!114 &8926484042661614592 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614592} + m_MasterData: + m_Owner: {fileID: 8926484042661614591} + m_Value: + m_Type: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: 1 + m_Space: 2147483647 + m_Property: + name: Lifetime + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: "Indicates how long the particle can stay alive. If the particle\u2019s + age exceeds its lifetime, the particle is destroyed." + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614602 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c52d920e7fff73b498050a6b3c4404ca, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614602} + m_MasterData: + m_Owner: {fileID: 8926484042661614557} + m_Value: + m_Type: + m_SerializableType: System.UInt32, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: 0 + m_Space: 2147483647 + m_Property: + name: Seed + m_serializedType: + m_SerializableType: System.UInt32, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: Seed to compute the constant random + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614603 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c52d920e7fff73b498050a6b3c4404ca, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614603} + m_MasterData: + m_Owner: {fileID: 8926484042661614541} + m_Value: + m_Type: + m_SerializableType: System.UInt32, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: 0 + m_Space: 2147483647 + m_Property: + name: Seed + m_serializedType: + m_SerializableType: System.UInt32, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: Seed to compute the constant random + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614612 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a971fa2e110a0ac42ac1d8dae408704b, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 114946465509916290} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 8926484042661614613} + m_OutputSlots: [] + m_Disabled: 0 + attribute: age + Composition: 1 + Source: 0 + Random: 0 + channels: 6 +--- !u!114 &8926484042661614613 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614613} + m_MasterData: + m_Owner: {fileID: 8926484042661614612} + m_Value: + m_Type: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: 0 + m_Space: 2147483647 + m_Property: + name: Age + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: "The age of the particle. If a particle\u2019s age exceeds its lifetime, + it gets destroyed." + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614617 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2461f61b3c026d54db1951a4e17ab20e, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 114350483966674976} + m_Children: [] + m_UIPosition: {x: 384, y: -641} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: [] + m_OutputSlots: [] + m_Label: + m_Data: {fileID: 0} + m_InputFlowSlot: + - link: [] + m_OutputFlowSlot: + - link: + - context: {fileID: 8926484042661614618} + slotIndex: 0 + eventName: OnNewFrame +--- !u!114 &8926484042661614618 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 73a13919d81fb7444849bae8b5c812a2, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 114350483966674976} + m_Children: + - {fileID: 8926484042661614619} + m_UIPosition: {x: 445, y: -342} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: [] + m_OutputSlots: [] + m_Label: + m_Data: {fileID: 0} + m_InputFlowSlot: + - link: + - context: {fileID: 8926484042661614617} + slotIndex: 0 + - link: [] + m_OutputFlowSlot: + - link: [] + loopDuration: 0 + loopCount: 0 + delayBeforeLoop: 0 + delayAfterLoop: 0 +--- !u!114 &8926484042661614619 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5e382412bb691334bb79457a6c127924, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614618} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 8926484042661614620} + - {fileID: 8926484042661614621} + m_OutputSlots: [] + m_Disabled: 0 + repeat: 0 + spawnMode: 0 + delayMode: 0 +--- !u!114 &8926484042661614620 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614620} + m_MasterData: + m_Owner: {fileID: 8926484042661614619} + m_Value: + m_Type: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: 25000 + m_Space: 2147483647 + m_Property: + name: Count + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: Sets the number of particles to be spawned with each burst. + m_Regex: + m_RegexMaxLength: 0 + - m_Type: 1 + m_Min: 0 + m_Max: Infinity + m_Tooltip: + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614621 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614621} + m_MasterData: + m_Owner: {fileID: 8926484042661614619} + m_Value: + m_Type: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: 0 + m_Space: 2147483647 + m_Property: + name: Delay + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: Sets the delay in seconds between each burst. + m_Regex: + m_RegexMaxLength: 0 + - m_Type: 1 + m_Min: 0 + m_Max: Infinity + m_Tooltip: + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614624 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a971fa2e110a0ac42ac1d8dae408704b, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 114780028408030698} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 8926484042661614625} + m_OutputSlots: [] + m_Disabled: 0 + attribute: size + Composition: 0 + Source: 0 + Random: 0 + channels: 6 +--- !u!114 &8926484042661614625 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614625} + m_MasterData: + m_Owner: {fileID: 8926484042661614624} + m_Value: + m_Type: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: 0.04 + m_Space: 2147483647 + m_Property: + name: Size + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: The uniform size of the particle. + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614652 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 73a13919d81fb7444849bae8b5c812a2, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 114350483966674976} + m_Children: + - {fileID: 8926484042661614653} + m_UIPosition: {x: 958, y: -611} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: [] + m_OutputSlots: [] + m_Label: + m_Data: {fileID: 0} + m_InputFlowSlot: + - link: [] + - link: [] + m_OutputFlowSlot: + - link: + - context: {fileID: 114946465509916290} + slotIndex: 0 + loopDuration: 0 + loopCount: 0 + delayBeforeLoop: 0 + delayAfterLoop: 0 +--- !u!114 &8926484042661614653 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f05c6884b705ce14d82ae720f0ec209f, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614652} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 8926484042661614654} + m_OutputSlots: [] + m_Disabled: 0 +--- !u!114 &8926484042661614654 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614654} + m_MasterData: + m_Owner: {fileID: 8926484042661614653} + m_Value: + m_Type: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: 25000 + m_Space: 2147483647 + m_Property: + name: Rate + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: + - m_Type: 1 + m_Min: 0 + m_Max: Infinity + m_Tooltip: + m_Regex: + m_RegexMaxLength: 0 + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: Sets the number of particles to be spawned per second. + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614655 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 60fff265f139e2a4194a44c2bac41757, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 114780028408030698} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 8926484042661614656} + - {fileID: 8926484042661614657} + - {fileID: 8926484042661614658} + - {fileID: 8926484042661614662} + m_OutputSlots: [] + m_Disabled: 0 + attribute: position + Composition: 0 + SampleMode: 6 + channels: 6 +--- !u!114 &8926484042661614656 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 70a331b1d86cc8d4aa106ccbe0da5852, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614656} + m_MasterData: + m_Owner: {fileID: 8926484042661614655} + m_Value: + m_Type: + m_SerializableType: UnityEngine.Texture2D, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"obj":{"fileID":2800000,"guid":"1d8481de16af723418a688958c41224b","type":3}}' + m_Space: 2147483647 + m_Property: + name: attributeMap + m_serializedType: + m_SerializableType: UnityEngine.Texture2D, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: AttributeMap texture to read attributes from + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: + - {fileID: 8926484042661614553} +--- !u!114 &8926484042661614657 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c52d920e7fff73b498050a6b3c4404ca, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614657} + m_MasterData: + m_Owner: {fileID: 8926484042661614655} + m_Value: + m_Type: + m_SerializableType: System.UInt32, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: 0 + m_Space: 2147483647 + m_Property: + name: Seed + m_serializedType: + m_SerializableType: System.UInt32, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: Seed to compute the constant random + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614658 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: + - {fileID: 8926484042661614659} + - {fileID: 8926484042661614660} + - {fileID: 8926484042661614661} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614658} + m_MasterData: + m_Owner: {fileID: 8926484042661614655} + m_Value: + m_Type: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"x":0.0,"y":0.0,"z":0.0}' + m_Space: 2147483647 + m_Property: + name: valueBias + m_serializedType: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: Bias Applied to the read Vector3 value + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614659 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614658} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614658} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: x + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614660 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614658} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614658} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: y + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614661 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614658} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614658} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: z + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614662 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: + - {fileID: 8926484042661614663} + - {fileID: 8926484042661614664} + - {fileID: 8926484042661614665} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614662} + m_MasterData: + m_Owner: {fileID: 8926484042661614655} + m_Value: + m_Type: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"x":1.0,"y":1.0,"z":1.0}' + m_Space: 2147483647 + m_Property: + name: valueScale + m_serializedType: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: Scale Applied to the read Vector3 value + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614663 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614662} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614662} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: x + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614664 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614662} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614662} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: y + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614665 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614662} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614662} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: z + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614666 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 60fff265f139e2a4194a44c2bac41757, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 114780028408030698} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 8926484042661614667} + - {fileID: 8926484042661614668} + - {fileID: 8926484042661614669} + - {fileID: 8926484042661614673} + m_OutputSlots: [] + m_Disabled: 0 + attribute: color + Composition: 0 + SampleMode: 6 + channels: 6 +--- !u!114 &8926484042661614667 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 70a331b1d86cc8d4aa106ccbe0da5852, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614667} + m_MasterData: + m_Owner: {fileID: 8926484042661614666} + m_Value: + m_Type: + m_SerializableType: UnityEngine.Texture2D, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"obj":{"fileID":2800000,"guid":"1d8481de16af723418a688958c41224b","type":3}}' + m_Space: 2147483647 + m_Property: + name: attributeMap + m_serializedType: + m_SerializableType: UnityEngine.Texture2D, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: AttributeMap texture to read attributes from + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: + - {fileID: 8926484042661614569} +--- !u!114 &8926484042661614668 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c52d920e7fff73b498050a6b3c4404ca, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614668} + m_MasterData: + m_Owner: {fileID: 8926484042661614666} + m_Value: + m_Type: + m_SerializableType: System.UInt32, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: 0 + m_Space: 2147483647 + m_Property: + name: Seed + m_serializedType: + m_SerializableType: System.UInt32, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: Seed to compute the constant random + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614669 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: + - {fileID: 8926484042661614670} + - {fileID: 8926484042661614671} + - {fileID: 8926484042661614672} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614669} + m_MasterData: + m_Owner: {fileID: 8926484042661614666} + m_Value: + m_Type: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"x":0.0,"y":0.0,"z":0.0}' + m_Space: 2147483647 + m_Property: + name: valueBias + m_serializedType: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: Bias Applied to the read Vector3 value + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614670 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614669} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614669} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: x + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614671 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614669} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614669} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: y + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614672 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614669} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614669} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: z + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614673 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: + - {fileID: 8926484042661614674} + - {fileID: 8926484042661614675} + - {fileID: 8926484042661614676} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614673} + m_MasterData: + m_Owner: {fileID: 8926484042661614666} + m_Value: + m_Type: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"x":1.0,"y":1.0,"z":1.0}' + m_Space: 2147483647 + m_Property: + name: valueScale + m_serializedType: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + attributes: + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: Scale Applied to the read Vector3 value + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614674 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614673} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614673} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: x + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614675 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614673} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614673} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: y + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614676 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614673} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614673} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: z + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614760 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2dc095764ededfa4bb32fa602511ea4b, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 114350483966674976} + m_Children: + - {fileID: 8926484042661614762} + m_UIPosition: {x: 705, y: 1633} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: [] + m_OutputSlots: [] + m_Label: + m_Data: {fileID: 114428730288789306} + m_InputFlowSlot: + - link: + - context: {fileID: 114780028408030698} + slotIndex: 0 + m_OutputFlowSlot: + - link: + - context: {fileID: 8926484042661614573} + slotIndex: 0 + integration: 0 + angularIntegration: 0 + ageParticles: 1 + reapParticles: 1 +--- !u!114 &8926484042661614762 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a971fa2e110a0ac42ac1d8dae408704b, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614760} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 8926484042661614763} + - {fileID: 8926484042661614767} + m_OutputSlots: [] + m_Disabled: 1 + attribute: color + Composition: 3 + Source: 0 + Random: 0 + channels: 6 +--- !u!114 &8926484042661614763 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: + - {fileID: 8926484042661614764} + - {fileID: 8926484042661614765} + - {fileID: 8926484042661614766} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614763} + m_MasterData: + m_Owner: {fileID: 8926484042661614762} + m_Value: + m_Type: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"x":1.0,"y":1.0,"z":1.0}' + m_Space: 2147483647 + m_Property: + name: Color + m_serializedType: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + attributes: + - m_Type: 5 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: + m_Regex: + m_RegexMaxLength: 0 + - m_Type: 3 + m_Min: -Infinity + m_Max: Infinity + m_Tooltip: The color of the particle. + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614764 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614763} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614763} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: x + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614765 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614763} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614763} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: y + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614766 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 8926484042661614763} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614763} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: z + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: [] + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614767 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614767} + m_MasterData: + m_Owner: {fileID: 8926484042661614762} + m_Value: + m_Type: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: + m_Space: 2147483647 + m_Property: + name: Blend + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + attributes: + - m_Type: 0 + m_Min: 0 + m_Max: 1 + m_Tooltip: + m_Regex: + m_RegexMaxLength: 0 + m_Direction: 0 + m_LinkedSlots: [] diff --git a/streaming-pointcloud/examples/Unity/Assets/SimplePointsViz.vfx.meta b/streaming-pointcloud/examples/Unity/Assets/SimplePointsViz.vfx.meta new file mode 100644 index 00000000..4ad117e3 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/SimplePointsViz.vfx.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: cf9ac41df9d70eb4e864b63085235543 +VisualEffectImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/streaming-pointcloud/examples/Unity/Assets/VFXDefaultResources.asset b/streaming-pointcloud/examples/Unity/Assets/VFXDefaultResources.asset new file mode 100644 index 00000000..9e63d918 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/VFXDefaultResources.asset @@ -0,0 +1,112 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: cd0a560c562a33e4b94f515804e2bd27, type: 3} + m_Name: VFXDefaultResources + m_EditorClassIdentifier: + particleTexture: {fileID: 2800000, guid: 276d9e395ae18fe40a9b4988549f2349, type: 3} + noiseTexture: {fileID: 2800000, guid: 1d8481de16af723418a688958c41224b, type: 3} + vectorField: {fileID: 11700000, guid: 08937e3134903c5488be506a2dac71e9, type: 2} + signedDistanceField: {fileID: 11700000, guid: 5c2949c31aafddd4e8011ffdebb8fdf7, + type: 2} + mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} + animationCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.25 + value: 0.25 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + gradient: + serializedVersion: 2 + key0: {r: 1, g: 1, b: 1, a: 0} + key1: {r: 0.5, g: 0.5, b: 0.5, a: 1} + key2: {r: 0, g: 0, b: 0, a: 0.8} + key3: {r: 0, g: 0, b: 0, a: 0} + key4: {r: 0, g: 0, b: 0, a: 0} + key5: {r: 0, g: 0, b: 0, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 65535 + ctime2: 0 + ctime3: 0 + ctime4: 0 + ctime5: 0 + ctime6: 0 + ctime7: 0 + atime0: 0 + atime1: 6554 + atime2: 52428 + atime3: 65535 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 0 + m_NumColorKeys: 2 + m_NumAlphaKeys: 4 + gradientMapRamp: + serializedVersion: 2 + key0: {r: 0, g: 0, b: 0, a: 0} + key1: {r: 0.75, g: 0.15, b: 0, a: 1} + key2: {r: 1.25, g: 0.56, b: 0.12, a: 0} + key3: {r: 3.5, g: 2, b: 0.5, a: 0} + key4: {r: 4, g: 3.5, b: 1.2, a: 0} + key5: {r: 12, g: 10, b: 2.5, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 19661 + ctime2: 32768 + ctime3: 45875 + ctime4: 58982 + ctime5: 65535 + ctime6: 0 + ctime7: 0 + atime0: 0 + atime1: 65535 + atime2: 0 + atime3: 0 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 0 + m_NumColorKeys: 6 + m_NumAlphaKeys: 2 + shader: {fileID: 4800000, guid: cd270bc83dc0ce644bf351c3f5b7f30f, type: 3} diff --git a/streaming-pointcloud/examples/Unity/Assets/VFXDefaultResources.asset.meta b/streaming-pointcloud/examples/Unity/Assets/VFXDefaultResources.asset.meta new file mode 100644 index 00000000..2f40e501 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/Assets/VFXDefaultResources.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f9b51df7f582a46458c32bc184cfc877 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/streaming-pointcloud/examples/Unity/ProjectSettings/AudioManager.asset b/streaming-pointcloud/examples/Unity/ProjectSettings/AudioManager.asset new file mode 100644 index 00000000..07ebfb05 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/ProjectSettings/AudioManager.asset @@ -0,0 +1,19 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!11 &1 +AudioManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Volume: 1 + Rolloff Scale: 1 + Doppler Factor: 1 + Default Speaker Mode: 2 + m_SampleRate: 0 + m_DSPBufferSize: 1024 + m_VirtualVoiceCount: 512 + m_RealVoiceCount: 32 + m_SpatializerPlugin: + m_AmbisonicDecoderPlugin: + m_DisableAudio: 0 + m_VirtualizeEffects: 1 + m_RequestedDSPBufferSize: 1024 diff --git a/streaming-pointcloud/examples/Unity/ProjectSettings/ClusterInputManager.asset b/streaming-pointcloud/examples/Unity/ProjectSettings/ClusterInputManager.asset new file mode 100644 index 00000000..e7886b26 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/ProjectSettings/ClusterInputManager.asset @@ -0,0 +1,6 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!236 &1 +ClusterInputManager: + m_ObjectHideFlags: 0 + m_Inputs: [] diff --git a/streaming-pointcloud/examples/Unity/ProjectSettings/DynamicsManager.asset b/streaming-pointcloud/examples/Unity/ProjectSettings/DynamicsManager.asset new file mode 100644 index 00000000..cdc1f3ea --- /dev/null +++ b/streaming-pointcloud/examples/Unity/ProjectSettings/DynamicsManager.asset @@ -0,0 +1,34 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!55 &1 +PhysicsManager: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_Gravity: {x: 0, y: -9.81, z: 0} + m_DefaultMaterial: {fileID: 0} + m_BounceThreshold: 2 + m_SleepThreshold: 0.005 + m_DefaultContactOffset: 0.01 + m_DefaultSolverIterations: 6 + m_DefaultSolverVelocityIterations: 1 + m_QueriesHitBackfaces: 0 + m_QueriesHitTriggers: 1 + m_EnableAdaptiveForce: 0 + m_ClothInterCollisionDistance: 0 + m_ClothInterCollisionStiffness: 0 + m_ContactsGeneration: 1 + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + m_AutoSimulation: 1 + m_AutoSyncTransforms: 0 + m_ReuseCollisionCallbacks: 1 + m_ClothInterCollisionSettingsToggle: 0 + m_ContactPairsMode: 0 + m_BroadphaseType: 0 + m_WorldBounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 250, y: 250, z: 250} + m_WorldSubdivisions: 8 + m_FrictionType: 0 + m_EnableEnhancedDeterminism: 0 + m_EnableUnifiedHeightmaps: 1 + m_DefaultMaxAngluarSpeed: 7 diff --git a/streaming-pointcloud/examples/Unity/ProjectSettings/EditorBuildSettings.asset b/streaming-pointcloud/examples/Unity/ProjectSettings/EditorBuildSettings.asset new file mode 100644 index 00000000..ae5d6f7b --- /dev/null +++ b/streaming-pointcloud/examples/Unity/ProjectSettings/EditorBuildSettings.asset @@ -0,0 +1,11 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1045 &1 +EditorBuildSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Scenes: + - enabled: 1 + path: Assets/Scenes/SampleScene.unity + guid: 5464a1b7442fcea408eb5a025cdddff9 + m_configObjects: {} diff --git a/streaming-pointcloud/examples/Unity/ProjectSettings/EditorSettings.asset b/streaming-pointcloud/examples/Unity/ProjectSettings/EditorSettings.asset new file mode 100644 index 00000000..1a44c3d3 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/ProjectSettings/EditorSettings.asset @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!159 &1 +EditorSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_ExternalVersionControlSupport: Visible Meta Files + m_SerializationMode: 2 + m_LineEndingsForNewScripts: 2 + m_DefaultBehaviorMode: 0 + m_PrefabRegularEnvironment: {fileID: 0} + m_PrefabUIEnvironment: {fileID: 0} + m_SpritePackerMode: 0 + m_SpritePackerPaddingPower: 1 + m_EtcTextureCompressorBehavior: 1 + m_EtcTextureFastCompressor: 1 + m_EtcTextureNormalCompressor: 2 + m_EtcTextureBestCompressor: 4 + m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;rsp;asmref + m_ProjectGenerationRootNamespace: + m_CollabEditorSettings: + inProgressEnabled: 1 + m_EnableTextureStreamingInEditMode: 1 + m_EnableTextureStreamingInPlayMode: 1 + m_AsyncShaderCompilation: 1 + m_EnterPlayModeOptionsEnabled: 0 + m_EnterPlayModeOptions: 3 + m_ShowLightmapResolutionOverlay: 1 + m_UseLegacyProbeSampleCount: 1 + m_AssetPipelineMode: 1 + m_CacheServerMode: 0 + m_CacheServerEndpoint: + m_CacheServerNamespacePrefix: default + m_CacheServerEnableDownload: 1 + m_CacheServerEnableUpload: 1 diff --git a/streaming-pointcloud/examples/Unity/ProjectSettings/GraphicsSettings.asset b/streaming-pointcloud/examples/Unity/ProjectSettings/GraphicsSettings.asset new file mode 100644 index 00000000..4706883c --- /dev/null +++ b/streaming-pointcloud/examples/Unity/ProjectSettings/GraphicsSettings.asset @@ -0,0 +1,66 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!30 &1 +GraphicsSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_Deferred: + m_Mode: 1 + m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} + m_DeferredReflections: + m_Mode: 1 + m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} + m_ScreenSpaceShadows: + m_Mode: 1 + m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} + m_LegacyDeferred: + m_Mode: 1 + m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} + m_DepthNormals: + m_Mode: 1 + m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} + m_MotionVectors: + m_Mode: 1 + m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} + m_LightHalo: + m_Mode: 1 + m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} + m_LensFlare: + m_Mode: 1 + m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} + m_AlwaysIncludedShaders: + - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 16000, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 16001, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 17000, guid: 0000000000000000f000000000000000, type: 0} + m_PreloadedShaders: [] + m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, + type: 0} + m_CustomRenderPipeline: {fileID: 0} + m_TransparencySortMode: 0 + m_TransparencySortAxis: {x: 0, y: 0, z: 1} + m_DefaultRenderingPath: 1 + m_DefaultMobileRenderingPath: 1 + m_TierSettings: [] + m_LightmapStripping: 0 + m_FogStripping: 0 + m_InstancingStripping: 0 + m_LightmapKeepPlain: 1 + m_LightmapKeepDirCombined: 1 + m_LightmapKeepDynamicPlain: 1 + m_LightmapKeepDynamicDirCombined: 1 + m_LightmapKeepShadowMask: 1 + m_LightmapKeepSubtractive: 1 + m_FogKeepLinear: 1 + m_FogKeepExp: 1 + m_FogKeepExp2: 1 + m_AlbedoSwatchInfos: [] + m_LightsUseLinearIntensity: 0 + m_LightsUseColorTemperature: 0 + m_LogWhenShaderIsCompiled: 0 + m_AllowEnlightenSupportForUpgradedProject: 0 diff --git a/streaming-pointcloud/examples/Unity/ProjectSettings/InputManager.asset b/streaming-pointcloud/examples/Unity/ProjectSettings/InputManager.asset new file mode 100644 index 00000000..b16147e9 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/ProjectSettings/InputManager.asset @@ -0,0 +1,487 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!13 &1 +InputManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Axes: + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: a + altPositiveButton: d + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: s + altPositiveButton: w + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left ctrl + altNegativeButton: + altPositiveButton: mouse 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left alt + altNegativeButton: + altPositiveButton: mouse 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left shift + altNegativeButton: + altPositiveButton: mouse 2 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: space + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse X + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse Y + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse ScrollWheel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 2 + joyNum: 0 + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 1 + type: 2 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 0 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 1 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 2 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 3 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: return + altNegativeButton: + altPositiveButton: joystick button 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: enter + altNegativeButton: + altPositiveButton: space + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Cancel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: escape + altNegativeButton: + altPositiveButton: joystick button 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Enable Debug Button 1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left ctrl + altNegativeButton: + altPositiveButton: joystick button 8 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Enable Debug Button 2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: backspace + altNegativeButton: + altPositiveButton: joystick button 9 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Reset + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left alt + altNegativeButton: + altPositiveButton: joystick button 1 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Next + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: page down + altNegativeButton: + altPositiveButton: joystick button 5 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Previous + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: page up + altNegativeButton: + altPositiveButton: joystick button 4 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Validate + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: return + altNegativeButton: + altPositiveButton: joystick button 0 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Persistent + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: right shift + altNegativeButton: + altPositiveButton: joystick button 2 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Multiplier + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left shift + altNegativeButton: + altPositiveButton: joystick button 3 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 2 + axis: 6 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 2 + axis: 5 + joyNum: 0 diff --git a/streaming-pointcloud/examples/Unity/ProjectSettings/NavMeshAreas.asset b/streaming-pointcloud/examples/Unity/ProjectSettings/NavMeshAreas.asset new file mode 100644 index 00000000..3b0b7c3d --- /dev/null +++ b/streaming-pointcloud/examples/Unity/ProjectSettings/NavMeshAreas.asset @@ -0,0 +1,91 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!126 &1 +NavMeshProjectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + areas: + - name: Walkable + cost: 1 + - name: Not Walkable + cost: 1 + - name: Jump + cost: 2 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + m_LastAgentTypeID: -887442657 + m_Settings: + - serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.75 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_SettingNames: + - Humanoid diff --git a/streaming-pointcloud/examples/Unity/ProjectSettings/Physics2DSettings.asset b/streaming-pointcloud/examples/Unity/ProjectSettings/Physics2DSettings.asset new file mode 100644 index 00000000..47880b1c --- /dev/null +++ b/streaming-pointcloud/examples/Unity/ProjectSettings/Physics2DSettings.asset @@ -0,0 +1,56 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!19 &1 +Physics2DSettings: + m_ObjectHideFlags: 0 + serializedVersion: 4 + m_Gravity: {x: 0, y: -9.81} + m_DefaultMaterial: {fileID: 0} + m_VelocityIterations: 8 + m_PositionIterations: 3 + m_VelocityThreshold: 1 + m_MaxLinearCorrection: 0.2 + m_MaxAngularCorrection: 8 + m_MaxTranslationSpeed: 100 + m_MaxRotationSpeed: 360 + m_BaumgarteScale: 0.2 + m_BaumgarteTimeOfImpactScale: 0.75 + m_TimeToSleep: 0.5 + m_LinearSleepTolerance: 0.01 + m_AngularSleepTolerance: 2 + m_DefaultContactOffset: 0.01 + m_JobOptions: + serializedVersion: 2 + useMultithreading: 0 + useConsistencySorting: 0 + m_InterpolationPosesPerJob: 100 + m_NewContactsPerJob: 30 + m_CollideContactsPerJob: 100 + m_ClearFlagsPerJob: 200 + m_ClearBodyForcesPerJob: 200 + m_SyncDiscreteFixturesPerJob: 50 + m_SyncContinuousFixturesPerJob: 50 + m_FindNearestContactsPerJob: 100 + m_UpdateTriggerContactsPerJob: 100 + m_IslandSolverCostThreshold: 100 + m_IslandSolverBodyCostScale: 1 + m_IslandSolverContactCostScale: 10 + m_IslandSolverJointCostScale: 10 + m_IslandSolverBodiesPerJob: 50 + m_IslandSolverContactsPerJob: 50 + m_AutoSimulation: 1 + m_QueriesHitTriggers: 1 + m_QueriesStartInColliders: 1 + m_CallbacksOnDisable: 1 + m_ReuseCollisionCallbacks: 1 + m_AutoSyncTransforms: 0 + m_AlwaysShowColliders: 0 + m_ShowColliderSleep: 1 + m_ShowColliderContacts: 0 + m_ShowColliderAABB: 0 + m_ContactArrowScale: 0.2 + m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} + m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} + m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} + m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/streaming-pointcloud/examples/Unity/ProjectSettings/PresetManager.asset b/streaming-pointcloud/examples/Unity/ProjectSettings/PresetManager.asset new file mode 100644 index 00000000..67a94dae --- /dev/null +++ b/streaming-pointcloud/examples/Unity/ProjectSettings/PresetManager.asset @@ -0,0 +1,7 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1386491679 &1 +PresetManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_DefaultPresets: {} diff --git a/streaming-pointcloud/examples/Unity/ProjectSettings/ProjectSettings.asset b/streaming-pointcloud/examples/Unity/ProjectSettings/ProjectSettings.asset new file mode 100644 index 00000000..8716141d --- /dev/null +++ b/streaming-pointcloud/examples/Unity/ProjectSettings/ProjectSettings.asset @@ -0,0 +1,674 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!129 &1 +PlayerSettings: + m_ObjectHideFlags: 0 + serializedVersion: 20 + productGUID: dd8efffa2cedf234ca0478e8ef16e712 + AndroidProfiler: 0 + AndroidFilterTouchesWhenObscured: 0 + AndroidEnableSustainedPerformanceMode: 0 + defaultScreenOrientation: 4 + targetDevice: 2 + useOnDemandResources: 0 + accelerometerFrequency: 60 + companyName: DefaultCompany + productName: Unity Client Test + defaultCursor: {fileID: 0} + cursorHotspot: {x: 0, y: 0} + m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1} + m_ShowUnitySplashScreen: 1 + m_ShowUnitySplashLogo: 1 + m_SplashScreenOverlayOpacity: 1 + m_SplashScreenAnimation: 1 + m_SplashScreenLogoStyle: 1 + m_SplashScreenDrawMode: 0 + m_SplashScreenBackgroundAnimationZoom: 1 + m_SplashScreenLogoAnimationZoom: 1 + m_SplashScreenBackgroundLandscapeAspect: 1 + m_SplashScreenBackgroundPortraitAspect: 1 + m_SplashScreenBackgroundLandscapeUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenBackgroundPortraitUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenLogos: [] + m_VirtualRealitySplashScreen: {fileID: 0} + m_HolographicTrackingLossScreen: {fileID: 0} + defaultScreenWidth: 1024 + defaultScreenHeight: 768 + defaultScreenWidthWeb: 960 + defaultScreenHeightWeb: 600 + m_StereoRenderingPath: 0 + m_ActiveColorSpace: 0 + m_MTRendering: 1 + m_StackTraceTypes: 010000000100000001000000010000000100000001000000 + iosShowActivityIndicatorOnLoading: -1 + androidShowActivityIndicatorOnLoading: -1 + iosUseCustomAppBackgroundBehavior: 0 + iosAllowHTTPDownload: 1 + allowedAutorotateToPortrait: 1 + allowedAutorotateToPortraitUpsideDown: 1 + allowedAutorotateToLandscapeRight: 1 + allowedAutorotateToLandscapeLeft: 1 + useOSAutorotation: 1 + use32BitDisplayBuffer: 1 + preserveFramebufferAlpha: 0 + disableDepthAndStencilBuffers: 0 + androidStartInFullscreen: 1 + androidRenderOutsideSafeArea: 1 + androidUseSwappy: 0 + androidBlitType: 0 + defaultIsNativeResolution: 1 + macRetinaSupport: 1 + runInBackground: 1 + captureSingleScreen: 0 + muteOtherAudioSources: 0 + Prepare IOS For Recording: 0 + Force IOS Speakers When Recording: 0 + deferSystemGesturesMode: 0 + hideHomeButton: 0 + submitAnalytics: 1 + usePlayerLog: 1 + bakeCollisionMeshes: 0 + forceSingleInstance: 0 + useFlipModelSwapchain: 1 + resizableWindow: 0 + useMacAppStoreValidation: 0 + macAppStoreCategory: public.app-category.games + gpuSkinning: 1 + xboxPIXTextureCapture: 0 + xboxEnableAvatar: 0 + xboxEnableKinect: 0 + xboxEnableKinectAutoTracking: 0 + xboxEnableFitness: 0 + visibleInBackground: 1 + allowFullscreenSwitch: 1 + fullscreenMode: 1 + xboxSpeechDB: 0 + xboxEnableHeadOrientation: 0 + xboxEnableGuest: 0 + xboxEnablePIXSampling: 0 + metalFramebufferOnly: 0 + xboxOneResolution: 0 + xboxOneSResolution: 0 + xboxOneXResolution: 3 + xboxOneMonoLoggingLevel: 0 + xboxOneLoggingLevel: 1 + xboxOneDisableEsram: 0 + xboxOnePresentImmediateThreshold: 0 + switchQueueCommandMemory: 0 + switchQueueControlMemory: 16384 + switchQueueComputeMemory: 262144 + switchNVNShaderPoolsGranularity: 33554432 + switchNVNDefaultPoolsGranularity: 16777216 + switchNVNOtherPoolsGranularity: 16777216 + vulkanNumSwapchainBuffers: 3 + vulkanEnableSetSRGBWrite: 0 + m_SupportedAspectRatios: + 4:3: 1 + 5:4: 1 + 16:10: 1 + 16:9: 1 + Others: 1 + bundleVersion: 0.1 + preloadedAssets: [] + metroInputSource: 0 + wsaTransparentSwapchain: 0 + m_HolographicPauseOnTrackingLoss: 1 + xboxOneDisableKinectGpuReservation: 1 + xboxOneEnable7thCore: 1 + vrSettings: + cardboard: + depthFormat: 0 + enableTransitionView: 0 + daydream: + depthFormat: 0 + useSustainedPerformanceMode: 0 + enableVideoLayer: 0 + useProtectedVideoMemory: 0 + minimumSupportedHeadTracking: 0 + maximumSupportedHeadTracking: 1 + hololens: + depthFormat: 1 + depthBufferSharingEnabled: 1 + lumin: + depthFormat: 0 + frameTiming: 2 + enableGLCache: 0 + glCacheMaxBlobSize: 524288 + glCacheMaxFileSize: 8388608 + oculus: + sharedDepthBuffer: 1 + dashSupport: 1 + lowOverheadMode: 0 + protectedContext: 0 + v2Signing: 1 + enable360StereoCapture: 0 + isWsaHolographicRemotingEnabled: 0 + enableFrameTimingStats: 0 + useHDRDisplay: 0 + D3DHDRBitDepth: 0 + m_ColorGamuts: 00000000 + targetPixelDensity: 30 + resolutionScalingMode: 0 + androidSupportedAspectRatio: 1 + androidMaxAspectRatio: 2.1 + applicationIdentifier: {} + buildNumber: {} + AndroidBundleVersionCode: 1 + AndroidMinSdkVersion: 19 + AndroidTargetSdkVersion: 0 + AndroidPreferredInstallLocation: 1 + aotOptions: + stripEngineCode: 1 + iPhoneStrippingLevel: 0 + iPhoneScriptCallOptimization: 0 + ForceInternetPermission: 0 + ForceSDCardPermission: 0 + CreateWallpaper: 0 + APKExpansionFiles: 0 + keepLoadedShadersAlive: 0 + StripUnusedMeshComponents: 1 + VertexChannelCompressionMask: 4054 + iPhoneSdkVersion: 988 + iOSTargetOSVersionString: 10.0 + tvOSSdkVersion: 0 + tvOSRequireExtendedGameController: 0 + tvOSTargetOSVersionString: 10.0 + uIPrerenderedIcon: 0 + uIRequiresPersistentWiFi: 0 + uIRequiresFullScreen: 1 + uIStatusBarHidden: 1 + uIExitOnSuspend: 0 + uIStatusBarStyle: 0 + iPhoneSplashScreen: {fileID: 0} + iPhoneHighResSplashScreen: {fileID: 0} + iPhoneTallHighResSplashScreen: {fileID: 0} + iPhone47inSplashScreen: {fileID: 0} + iPhone55inPortraitSplashScreen: {fileID: 0} + iPhone55inLandscapeSplashScreen: {fileID: 0} + iPhone58inPortraitSplashScreen: {fileID: 0} + iPhone58inLandscapeSplashScreen: {fileID: 0} + iPadPortraitSplashScreen: {fileID: 0} + iPadHighResPortraitSplashScreen: {fileID: 0} + iPadLandscapeSplashScreen: {fileID: 0} + iPadHighResLandscapeSplashScreen: {fileID: 0} + iPhone65inPortraitSplashScreen: {fileID: 0} + iPhone65inLandscapeSplashScreen: {fileID: 0} + iPhone61inPortraitSplashScreen: {fileID: 0} + iPhone61inLandscapeSplashScreen: {fileID: 0} + appleTVSplashScreen: {fileID: 0} + appleTVSplashScreen2x: {fileID: 0} + tvOSSmallIconLayers: [] + tvOSSmallIconLayers2x: [] + tvOSLargeIconLayers: [] + tvOSLargeIconLayers2x: [] + tvOSTopShelfImageLayers: [] + tvOSTopShelfImageLayers2x: [] + tvOSTopShelfImageWideLayers: [] + tvOSTopShelfImageWideLayers2x: [] + iOSLaunchScreenType: 0 + iOSLaunchScreenPortrait: {fileID: 0} + iOSLaunchScreenLandscape: {fileID: 0} + iOSLaunchScreenBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreenFillPct: 100 + iOSLaunchScreenSize: 100 + iOSLaunchScreenCustomXibPath: + iOSLaunchScreeniPadType: 0 + iOSLaunchScreeniPadImage: {fileID: 0} + iOSLaunchScreeniPadBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreeniPadFillPct: 100 + iOSLaunchScreeniPadSize: 100 + iOSLaunchScreeniPadCustomXibPath: + iOSUseLaunchScreenStoryboard: 0 + iOSLaunchScreenCustomStoryboardPath: + iOSDeviceRequirements: [] + iOSURLSchemes: [] + iOSBackgroundModes: 0 + iOSMetalForceHardShadows: 0 + metalEditorSupport: 1 + metalAPIValidation: 1 + iOSRenderExtraFrameOnPause: 0 + appleDeveloperTeamID: + iOSManualSigningProvisioningProfileID: + tvOSManualSigningProvisioningProfileID: + iOSManualSigningProvisioningProfileType: 0 + tvOSManualSigningProvisioningProfileType: 0 + appleEnableAutomaticSigning: 0 + iOSRequireARKit: 0 + iOSAutomaticallyDetectAndAddCapabilities: 1 + appleEnableProMotion: 0 + clonedFromGUID: c0afd0d1d80e3634a9dac47e8a0426ea + templatePackageId: com.unity.template.3d@4.2.5 + templateDefaultScene: Assets/Scenes/SampleScene.unity + AndroidTargetArchitectures: 1 + AndroidSplashScreenScale: 0 + androidSplashScreen: {fileID: 0} + AndroidKeystoreName: + AndroidKeyaliasName: + AndroidBuildApkPerCpuArchitecture: 0 + AndroidTVCompatibility: 0 + AndroidIsGame: 1 + AndroidEnableTango: 0 + androidEnableBanner: 1 + androidUseLowAccuracyLocation: 0 + androidUseCustomKeystore: 0 + m_AndroidBanners: + - width: 320 + height: 180 + banner: {fileID: 0} + androidGamepadSupportLevel: 0 + AndroidValidateAppBundleSize: 1 + AndroidAppBundleSizeToValidate: 150 + m_BuildTargetIcons: [] + m_BuildTargetPlatformIcons: [] + m_BuildTargetBatching: + - m_BuildTarget: Standalone + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: tvOS + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: Android + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: iPhone + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: WebGL + m_StaticBatching: 0 + m_DynamicBatching: 0 + m_BuildTargetGraphicsJobs: + - m_BuildTarget: MacStandaloneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: Switch + m_GraphicsJobs: 1 + - m_BuildTarget: MetroSupport + m_GraphicsJobs: 1 + - m_BuildTarget: AppleTVSupport + m_GraphicsJobs: 0 + - m_BuildTarget: BJMSupport + m_GraphicsJobs: 1 + - m_BuildTarget: LinuxStandaloneSupport + m_GraphicsJobs: 1 + - m_BuildTarget: PS4Player + m_GraphicsJobs: 1 + - m_BuildTarget: iOSSupport + m_GraphicsJobs: 0 + - m_BuildTarget: WindowsStandaloneSupport + m_GraphicsJobs: 1 + - m_BuildTarget: XboxOnePlayer + m_GraphicsJobs: 1 + - m_BuildTarget: LuminSupport + m_GraphicsJobs: 0 + - m_BuildTarget: AndroidPlayer + m_GraphicsJobs: 0 + - m_BuildTarget: WebGLSupport + m_GraphicsJobs: 0 + m_BuildTargetGraphicsJobMode: + - m_BuildTarget: PS4Player + m_GraphicsJobMode: 0 + - m_BuildTarget: XboxOnePlayer + m_GraphicsJobMode: 0 + m_BuildTargetGraphicsAPIs: + - m_BuildTarget: AndroidPlayer + m_APIs: 150000000b000000 + m_Automatic: 0 + - m_BuildTarget: iOSSupport + m_APIs: 10000000 + m_Automatic: 1 + - m_BuildTarget: AppleTVSupport + m_APIs: 10000000 + m_Automatic: 0 + - m_BuildTarget: WebGLSupport + m_APIs: 0b000000 + m_Automatic: 1 + m_BuildTargetVRSettings: + - m_BuildTarget: Standalone + m_Enabled: 0 + m_Devices: + - Oculus + - OpenVR + openGLRequireES31: 0 + openGLRequireES31AEP: 0 + openGLRequireES32: 0 + m_TemplateCustomTags: {} + mobileMTRendering: + Android: 1 + iPhone: 1 + tvOS: 1 + m_BuildTargetGroupLightmapEncodingQuality: [] + m_BuildTargetGroupLightmapSettings: [] + playModeTestRunnerEnabled: 0 + runPlayModeTestAsEditModeTest: 0 + actionOnDotNetUnhandledException: 1 + enableInternalProfiler: 0 + logObjCUncaughtExceptions: 1 + enableCrashReportAPI: 0 + cameraUsageDescription: + locationUsageDescription: + microphoneUsageDescription: + switchNetLibKey: + switchSocketMemoryPoolSize: 6144 + switchSocketAllocatorPoolSize: 128 + switchSocketConcurrencyLimit: 14 + switchScreenResolutionBehavior: 2 + switchUseCPUProfiler: 0 + switchApplicationID: 0x01004b9000490000 + switchNSODependencies: + switchTitleNames_0: + switchTitleNames_1: + switchTitleNames_2: + switchTitleNames_3: + switchTitleNames_4: + switchTitleNames_5: + switchTitleNames_6: + switchTitleNames_7: + switchTitleNames_8: + switchTitleNames_9: + switchTitleNames_10: + switchTitleNames_11: + switchTitleNames_12: + switchTitleNames_13: + switchTitleNames_14: + switchPublisherNames_0: + switchPublisherNames_1: + switchPublisherNames_2: + switchPublisherNames_3: + switchPublisherNames_4: + switchPublisherNames_5: + switchPublisherNames_6: + switchPublisherNames_7: + switchPublisherNames_8: + switchPublisherNames_9: + switchPublisherNames_10: + switchPublisherNames_11: + switchPublisherNames_12: + switchPublisherNames_13: + switchPublisherNames_14: + switchIcons_0: {fileID: 0} + switchIcons_1: {fileID: 0} + switchIcons_2: {fileID: 0} + switchIcons_3: {fileID: 0} + switchIcons_4: {fileID: 0} + switchIcons_5: {fileID: 0} + switchIcons_6: {fileID: 0} + switchIcons_7: {fileID: 0} + switchIcons_8: {fileID: 0} + switchIcons_9: {fileID: 0} + switchIcons_10: {fileID: 0} + switchIcons_11: {fileID: 0} + switchIcons_12: {fileID: 0} + switchIcons_13: {fileID: 0} + switchIcons_14: {fileID: 0} + switchSmallIcons_0: {fileID: 0} + switchSmallIcons_1: {fileID: 0} + switchSmallIcons_2: {fileID: 0} + switchSmallIcons_3: {fileID: 0} + switchSmallIcons_4: {fileID: 0} + switchSmallIcons_5: {fileID: 0} + switchSmallIcons_6: {fileID: 0} + switchSmallIcons_7: {fileID: 0} + switchSmallIcons_8: {fileID: 0} + switchSmallIcons_9: {fileID: 0} + switchSmallIcons_10: {fileID: 0} + switchSmallIcons_11: {fileID: 0} + switchSmallIcons_12: {fileID: 0} + switchSmallIcons_13: {fileID: 0} + switchSmallIcons_14: {fileID: 0} + switchManualHTML: + switchAccessibleURLs: + switchLegalInformation: + switchMainThreadStackSize: 1048576 + switchPresenceGroupId: + switchLogoHandling: 0 + switchReleaseVersion: 0 + switchDisplayVersion: 1.0.0 + switchStartupUserAccount: 0 + switchTouchScreenUsage: 0 + switchSupportedLanguagesMask: 0 + switchLogoType: 0 + switchApplicationErrorCodeCategory: + switchUserAccountSaveDataSize: 0 + switchUserAccountSaveDataJournalSize: 0 + switchApplicationAttribute: 0 + switchCardSpecSize: -1 + switchCardSpecClock: -1 + switchRatingsMask: 0 + switchRatingsInt_0: 0 + switchRatingsInt_1: 0 + switchRatingsInt_2: 0 + switchRatingsInt_3: 0 + switchRatingsInt_4: 0 + switchRatingsInt_5: 0 + switchRatingsInt_6: 0 + switchRatingsInt_7: 0 + switchRatingsInt_8: 0 + switchRatingsInt_9: 0 + switchRatingsInt_10: 0 + switchRatingsInt_11: 0 + switchRatingsInt_12: 0 + switchLocalCommunicationIds_0: + switchLocalCommunicationIds_1: + switchLocalCommunicationIds_2: + switchLocalCommunicationIds_3: + switchLocalCommunicationIds_4: + switchLocalCommunicationIds_5: + switchLocalCommunicationIds_6: + switchLocalCommunicationIds_7: + switchParentalControl: 0 + switchAllowsScreenshot: 1 + switchAllowsVideoCapturing: 1 + switchAllowsRuntimeAddOnContentInstall: 0 + switchDataLossConfirmation: 0 + switchUserAccountLockEnabled: 0 + switchSystemResourceMemory: 16777216 + switchSupportedNpadStyles: 22 + switchNativeFsCacheSize: 32 + switchIsHoldTypeHorizontal: 0 + switchSupportedNpadCount: 8 + switchSocketConfigEnabled: 0 + switchTcpInitialSendBufferSize: 32 + switchTcpInitialReceiveBufferSize: 64 + switchTcpAutoSendBufferSizeMax: 256 + switchTcpAutoReceiveBufferSizeMax: 256 + switchUdpSendBufferSize: 9 + switchUdpReceiveBufferSize: 42 + switchSocketBufferEfficiency: 4 + switchSocketInitializeEnabled: 1 + switchNetworkInterfaceManagerInitializeEnabled: 1 + switchPlayerConnectionEnabled: 1 + ps4NPAgeRating: 12 + ps4NPTitleSecret: + ps4NPTrophyPackPath: + ps4ParentalLevel: 11 + ps4ContentID: ED1633-NPXX51362_00-0000000000000000 + ps4Category: 0 + ps4MasterVersion: 01.00 + ps4AppVersion: 01.00 + ps4AppType: 0 + ps4ParamSfxPath: + ps4VideoOutPixelFormat: 0 + ps4VideoOutInitialWidth: 1920 + ps4VideoOutBaseModeInitialWidth: 1920 + ps4VideoOutReprojectionRate: 60 + ps4PronunciationXMLPath: + ps4PronunciationSIGPath: + ps4BackgroundImagePath: + ps4StartupImagePath: + ps4StartupImagesFolder: + ps4IconImagesFolder: + ps4SaveDataImagePath: + ps4SdkOverride: + ps4BGMPath: + ps4ShareFilePath: + ps4ShareOverlayImagePath: + ps4PrivacyGuardImagePath: + ps4NPtitleDatPath: + ps4RemotePlayKeyAssignment: -1 + ps4RemotePlayKeyMappingDir: + ps4PlayTogetherPlayerCount: 0 + ps4EnterButtonAssignment: 1 + ps4ApplicationParam1: 0 + ps4ApplicationParam2: 0 + ps4ApplicationParam3: 0 + ps4ApplicationParam4: 0 + ps4DownloadDataSize: 0 + ps4GarlicHeapSize: 2048 + ps4ProGarlicHeapSize: 2560 + playerPrefsMaxSize: 32768 + ps4Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ + ps4pnSessions: 1 + ps4pnPresence: 1 + ps4pnFriends: 1 + ps4pnGameCustomData: 1 + playerPrefsSupport: 0 + enableApplicationExit: 0 + resetTempFolder: 1 + restrictedAudioUsageRights: 0 + ps4UseResolutionFallback: 0 + ps4ReprojectionSupport: 0 + ps4UseAudio3dBackend: 0 + ps4SocialScreenEnabled: 0 + ps4ScriptOptimizationLevel: 0 + ps4Audio3dVirtualSpeakerCount: 14 + ps4attribCpuUsage: 0 + ps4PatchPkgPath: + ps4PatchLatestPkgPath: + ps4PatchChangeinfoPath: + ps4PatchDayOne: 0 + ps4attribUserManagement: 0 + ps4attribMoveSupport: 0 + ps4attrib3DSupport: 0 + ps4attribShareSupport: 0 + ps4attribExclusiveVR: 0 + ps4disableAutoHideSplash: 0 + ps4videoRecordingFeaturesUsed: 0 + ps4contentSearchFeaturesUsed: 0 + ps4attribEyeToEyeDistanceSettingVR: 0 + ps4IncludedModules: [] + ps4attribVROutputEnabled: 0 + monoEnv: + splashScreenBackgroundSourceLandscape: {fileID: 0} + splashScreenBackgroundSourcePortrait: {fileID: 0} + blurSplashScreenBackground: 1 + spritePackerPolicy: + webGLMemorySize: 16 + webGLExceptionSupport: 1 + webGLNameFilesAsHashes: 0 + webGLDataCaching: 1 + webGLDebugSymbols: 0 + webGLEmscriptenArgs: + webGLModulesDirectory: + webGLTemplate: APPLICATION:Default + webGLAnalyzeBuildSize: 0 + webGLUseEmbeddedResources: 0 + webGLCompressionFormat: 1 + webGLLinkerTarget: 1 + webGLThreadsSupport: 0 + webGLWasmStreaming: 0 + scriptingDefineSymbols: {} + platformArchitecture: {} + scriptingBackend: + Standalone: 0 + il2cppCompilerConfiguration: {} + managedStrippingLevel: {} + incrementalIl2cppBuild: {} + allowUnsafeCode: 1 + additionalIl2CppArgs: + scriptingRuntimeVersion: 1 + gcIncremental: 0 + gcWBarrierValidation: 0 + apiCompatibilityLevelPerPlatform: {} + m_RenderingPath: 1 + m_MobileRenderingPath: 1 + metroPackageName: Template_3D + metroPackageVersion: + metroCertificatePath: + metroCertificatePassword: + metroCertificateSubject: + metroCertificateIssuer: + metroCertificateNotAfter: 0000000000000000 + metroApplicationDescription: Template_3D + wsaImages: {} + metroTileShortName: + metroTileShowName: 0 + metroMediumTileShowName: 0 + metroLargeTileShowName: 0 + metroWideTileShowName: 0 + metroSupportStreamingInstall: 0 + metroLastRequiredScene: 0 + metroDefaultTileSize: 1 + metroTileForegroundText: 2 + metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0} + metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628, + a: 1} + metroSplashScreenUseBackgroundColor: 0 + platformCapabilities: {} + metroTargetDeviceFamilies: {} + metroFTAName: + metroFTAFileTypes: [] + metroProtocolName: + XboxOneProductId: + XboxOneUpdateKey: + XboxOneSandboxId: + XboxOneContentId: + XboxOneTitleId: + XboxOneSCId: + XboxOneGameOsOverridePath: + XboxOnePackagingOverridePath: + XboxOneAppManifestOverridePath: + XboxOneVersion: 1.0.0.0 + XboxOnePackageEncryption: 0 + XboxOnePackageUpdateGranularity: 2 + XboxOneDescription: + XboxOneLanguage: + - enus + XboxOneCapability: [] + XboxOneGameRating: {} + XboxOneIsContentPackage: 0 + XboxOneEnableGPUVariability: 1 + XboxOneSockets: {} + XboxOneSplashScreen: {fileID: 0} + XboxOneAllowedProductIds: [] + XboxOnePersistentLocalStorageSize: 0 + XboxOneXTitleMemory: 8 + XboxOneOverrideIdentityName: + vrEditorSettings: + daydream: + daydreamIconForeground: {fileID: 0} + daydreamIconBackground: {fileID: 0} + cloudServicesEnabled: + UNet: 1 + luminIcon: + m_Name: + m_ModelFolderPath: + m_PortalFolderPath: + luminCert: + m_CertPath: + m_SignPackage: 1 + luminIsChannelApp: 0 + luminVersion: + m_VersionCode: 1 + m_VersionName: + apiCompatibilityLevel: 6 + cloudProjectId: + framebufferDepthMemorylessMode: 0 + projectName: + organizationId: + cloudEnabled: 0 + enableNativePlatformBackendsForNewInputSystem: 0 + disableOldInputManagerSupport: 0 + legacyClampBlendShapeWeights: 0 diff --git a/streaming-pointcloud/examples/Unity/ProjectSettings/ProjectVersion.txt b/streaming-pointcloud/examples/Unity/ProjectSettings/ProjectVersion.txt new file mode 100644 index 00000000..a8d67257 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/ProjectSettings/ProjectVersion.txt @@ -0,0 +1,2 @@ +m_EditorVersion: 2019.3.3f1 +m_EditorVersionWithRevision: 2019.3.3f1 (7ceaae5f7503) diff --git a/streaming-pointcloud/examples/Unity/ProjectSettings/QualitySettings.asset b/streaming-pointcloud/examples/Unity/ProjectSettings/QualitySettings.asset new file mode 100644 index 00000000..7b7658d6 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/ProjectSettings/QualitySettings.asset @@ -0,0 +1,232 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!47 &1 +QualitySettings: + m_ObjectHideFlags: 0 + serializedVersion: 5 + m_CurrentQuality: 5 + m_QualitySettings: + - serializedVersion: 2 + name: Very Low + pixelLightCount: 0 + shadows: 0 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 15 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + blendWeights: 1 + textureQuality: 1 + anisotropicTextures: 0 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 0 + lodBias: 0.3 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 4 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Low + pixelLightCount: 0 + shadows: 0 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 20 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + blendWeights: 2 + textureQuality: 0 + anisotropicTextures: 0 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 0 + lodBias: 0.4 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 16 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Medium + pixelLightCount: 1 + shadows: 1 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 20 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + blendWeights: 2 + textureQuality: 0 + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 1 + lodBias: 0.7 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 64 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: High + pixelLightCount: 2 + shadows: 2 + shadowResolution: 1 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 40 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + blendWeights: 2 + textureQuality: 0 + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 1 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 256 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Very High + pixelLightCount: 3 + shadows: 2 + shadowResolution: 2 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 70 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + blendWeights: 4 + textureQuality: 0 + anisotropicTextures: 2 + antiAliasing: 2 + softParticles: 1 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 1.5 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 1024 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Ultra + pixelLightCount: 4 + shadows: 2 + shadowResolution: 2 + shadowProjection: 1 + shadowCascades: 4 + shadowDistance: 150 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + blendWeights: 4 + textureQuality: 0 + anisotropicTextures: 2 + antiAliasing: 2 + softParticles: 1 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 2 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 4096 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + m_PerPlatformDefaultQuality: + Android: 2 + Lumin: 5 + Nintendo 3DS: 5 + Nintendo Switch: 5 + PS4: 5 + PSP2: 2 + Stadia: 5 + Standalone: 5 + WebGL: 3 + Windows Store Apps: 5 + XboxOne: 5 + iPhone: 2 + tvOS: 2 diff --git a/streaming-pointcloud/examples/Unity/ProjectSettings/TagManager.asset b/streaming-pointcloud/examples/Unity/ProjectSettings/TagManager.asset new file mode 100644 index 00000000..1c92a784 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/ProjectSettings/TagManager.asset @@ -0,0 +1,43 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!78 &1 +TagManager: + serializedVersion: 2 + tags: [] + layers: + - Default + - TransparentFX + - Ignore Raycast + - + - Water + - UI + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + m_SortingLayers: + - name: Default + uniqueID: 0 + locked: 0 diff --git a/streaming-pointcloud/examples/Unity/ProjectSettings/TimeManager.asset b/streaming-pointcloud/examples/Unity/ProjectSettings/TimeManager.asset new file mode 100644 index 00000000..558a017e --- /dev/null +++ b/streaming-pointcloud/examples/Unity/ProjectSettings/TimeManager.asset @@ -0,0 +1,9 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!5 &1 +TimeManager: + m_ObjectHideFlags: 0 + Fixed Timestep: 0.02 + Maximum Allowed Timestep: 0.33333334 + m_TimeScale: 1 + Maximum Particle Timestep: 0.03 diff --git a/streaming-pointcloud/examples/Unity/ProjectSettings/UnityConnectSettings.asset b/streaming-pointcloud/examples/Unity/ProjectSettings/UnityConnectSettings.asset new file mode 100644 index 00000000..fa0b1465 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/ProjectSettings/UnityConnectSettings.asset @@ -0,0 +1,34 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!310 &1 +UnityConnectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 1 + m_Enabled: 0 + m_TestMode: 0 + m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events + m_EventUrl: https://cdp.cloud.unity3d.com/v1/events + m_ConfigUrl: https://config.uca.cloud.unity3d.com + m_TestInitMode: 0 + CrashReportingSettings: + m_EventUrl: https://perf-events.cloud.unity3d.com + m_Enabled: 0 + m_LogBufferSize: 10 + m_CaptureEditorExceptions: 1 + UnityPurchasingSettings: + m_Enabled: 0 + m_TestMode: 0 + UnityAnalyticsSettings: + m_Enabled: 0 + m_TestMode: 0 + m_InitializeOnStartup: 1 + UnityAdsSettings: + m_Enabled: 0 + m_InitializeOnStartup: 1 + m_TestMode: 0 + m_IosGameId: + m_AndroidGameId: + m_GameIds: {} + m_GameId: + PerformanceReportingSettings: + m_Enabled: 0 diff --git a/streaming-pointcloud/examples/Unity/ProjectSettings/VFXManager.asset b/streaming-pointcloud/examples/Unity/ProjectSettings/VFXManager.asset new file mode 100644 index 00000000..57825677 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/ProjectSettings/VFXManager.asset @@ -0,0 +1,12 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!937362698 &1 +VFXManager: + m_ObjectHideFlags: 0 + m_IndirectShader: {fileID: 7200000, guid: 84a17cfa13e40ae4082ef42714f0a81c, type: 3} + m_CopyBufferShader: {fileID: 7200000, guid: 23c51f21a3503f6428b527b01f8a2f4e, type: 3} + m_SortShader: {fileID: 7200000, guid: ea257ca3cfb12a642a5025e612af6b2a, type: 3} + m_StripUpdateShader: {fileID: 7200000, guid: 8fa6c4009fe2a4d4486c62736fc30ad8, type: 3} + m_RenderPipeSettingsPath: + m_FixedTimeStep: 0.016666668 + m_MaxDeltaTime: 0.05 diff --git a/streaming-pointcloud/examples/Unity/ProjectSettings/XRSettings.asset b/streaming-pointcloud/examples/Unity/ProjectSettings/XRSettings.asset new file mode 100644 index 00000000..482590c1 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/ProjectSettings/XRSettings.asset @@ -0,0 +1,10 @@ +{ + "m_SettingKeys": [ + "VR Device Disabled", + "VR Device User Alert" + ], + "m_SettingValues": [ + "False", + "False" + ] +} \ No newline at end of file diff --git a/streaming-pointcloud/examples/Unity/README.md b/streaming-pointcloud/examples/Unity/README.md new file mode 100644 index 00000000..4c723979 --- /dev/null +++ b/streaming-pointcloud/examples/Unity/README.md @@ -0,0 +1,41 @@ +# Unity Visualizer + +![Unity Screenshot](./unity-screenshot.jpg) + +This is an example of consuming live point cloud frames for use with Unity. This example will receive point cloud frames and will update a VFX Graph. + +## Prerequisites + +* The Kinect Capture and Merger applications +* An MQTT broker such as [Mosquitto](https://mosquitto.org) +* Unity 2019.3 with Visual Effects Graph package + +Please note, this has only been tested on Windows 10 64bit + +## Installation + +1. Configure and run the Kinect Capture and Merger apps with at least one camera attached +1. Open Unity and load the project in this folder +1. Update project settings to have "allow unsafe" checked (https://docs.unity3d.com/Manual/class-PlayerSettingsStandalone.html#Other) + + +## Configuration +The example includes a prefab called StreamingPoints. This prefab has all the components needed to display a streaming point cloud. + +![StreamingPoints Parameters](./streamingpoints-params.png) + +| Component | Property | Description | +| -------- | -------- | ----------- | +| MQTT Net Client | Broker | IP address of mqtt broker | +| | Port | Network port the mqtt broker listens on | +| | Topic | MQTT topic the Merger broadcasts on | +| | Point Loader | Reference to PointCloudLoader script | +| Point Cloud Loader | Debug Image | (Optional) Reference to Raw Image | +| | Point Count | Amount of points in most recent package | +| | Effect | Reference to Visual Effect Graph | +| | Postion Texture Name | Name of the VFX graph input param for P data | +| | Effect | Name of the VFX graph input param for color data | + +# License +This example uses the MQTTnet library which is release under the MIT Library +https://github.com/chkr1011/MQTTnet#license \ No newline at end of file diff --git a/streaming-pointcloud/examples/Unity/packages.config b/streaming-pointcloud/examples/Unity/packages.config new file mode 100644 index 00000000..9698e44c --- /dev/null +++ b/streaming-pointcloud/examples/Unity/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/streaming-pointcloud/examples/Unity/streamingpoints-params.png b/streaming-pointcloud/examples/Unity/streamingpoints-params.png new file mode 100644 index 00000000..bd7592d2 Binary files /dev/null and b/streaming-pointcloud/examples/Unity/streamingpoints-params.png differ diff --git a/streaming-pointcloud/examples/Unity/unity-screenshot.jpg b/streaming-pointcloud/examples/Unity/unity-screenshot.jpg new file mode 100644 index 00000000..9ad046ed Binary files /dev/null and b/streaming-pointcloud/examples/Unity/unity-screenshot.jpg differ diff --git a/streaming-pointcloud/examples/Unity/unity-screenshot.png b/streaming-pointcloud/examples/Unity/unity-screenshot.png new file mode 100644 index 00000000..29857111 Binary files /dev/null and b/streaming-pointcloud/examples/Unity/unity-screenshot.png differ diff --git a/streaming-pointcloud/examples/td/README.md b/streaming-pointcloud/examples/td/README.md new file mode 100644 index 00000000..3cbb6184 --- /dev/null +++ b/streaming-pointcloud/examples/td/README.md @@ -0,0 +1,60 @@ +# TouchDesigner Example + +![Touch Designer Screenshot](./td-screenshot.jpg) + +This is an example of consuming live point cloud frames for in TouchDesigner. The example consists of a sample project that demonstrates using a custom c++ TOP plugin to consume the merged MQTT data stream as well as the TOP source code. + + +A custom c++ TOP processes the mqtt data into a texture TouchDesigner can use to visualize the pointcloud. The example comes with a comp. + + +## Prerequisites + +1. The Kinect Capture and Merger applications +1. An MQTT broker such as [Mosquitto](https://mosquitto.org) +1. TouchDesigner latst version 2020.20020 + +## Installation + +1. Configure and run the Kinect Capture and Merger apps with at least one camera attached +1. Open td-pointcloud-visualizer/td-pointcloud-visualizer.toe in TouchDesigner + +if you want to use the TOP in your own TouchDesigner project, copy over the precompiled dll td-pointcloud-visualizer/resources/MqttToTex.dll + + +## Configuration + +![MqttToTex plugin parameters](./td-cpptop-params.png) + +| Property | Description | +| -------- | ----------- | +|Broker|Url to broker, usig this format tcp://[ip]:[port]| +|Client|Mqtt client id, this should be unique, if you run more than one TD instance be sure that each instance has its own unique id| +|Topic|Mqtt topic to subscribe to, this match what the merger publishes on| +|Color Fill|Color to use when there is no color data in the mqtt packet| +|Texture Resolution|Output resolution of the texture. The more points in a packet the larger this needs to be. The plugin packs color and depth into one texture. A 512 x 512 texture has a max of 131072 points. (512*512)/2.| + +## Compiling from Source + +The TOP plugin has the following dependencies: +1. Visual Studio 2019 with toolset v142 +1. vcpkg +1. paho-mqttpp3 c++ libarry +1. Ws2_32.Lib + +Note: TouchDesigner has a native mqtt library based on paho-mqtt, the same we are using in the TOP. The built in mqtt functionality does not perform for large binary packets which is one of the reasons we need a custom cpp TOP. The paho-mqtt lib TD includes is not compiled for shared multi-threaded use. The work around is to build our "own" library as a static linked library, it gets compiled into the mqtttotex.dll. + +To build from source: +1. Install/Verify Visual Studio 2019 with c++ toolset v142 +1. Install and configure vcpkg, see [../../docs/building.md] for instructions +1. Build paho-mqttpp3 + 1. copy `x64-windows-static-md.cmake` to `vcpkg\triplets` + 1. ```.\vcpkg.exe install paho-mqttpp3:x64-windows-static-md``` + 1. ```.\vcpkg integrate install``` +1. Open solution in Visual Studio and build + +Be sure to point your TouchDesigner project at the MqttToTex.dll you just built. The example project comes with a precompiled dll you need to manually overwrite. + +# License +The Paho MQTT library is released under the Ecplipse Public License. +https://github.com/eclipse/paho.mqtt.cpp \ No newline at end of file diff --git a/streaming-pointcloud/examples/td/td-cpptop-params.png b/streaming-pointcloud/examples/td/td-cpptop-params.png new file mode 100644 index 00000000..6d686b2d Binary files /dev/null and b/streaming-pointcloud/examples/td/td-cpptop-params.png differ diff --git a/streaming-pointcloud/examples/td/td-pointcloud-visualizer/.gitignore b/streaming-pointcloud/examples/td/td-pointcloud-visualizer/.gitignore new file mode 100644 index 00000000..b0b041dc --- /dev/null +++ b/streaming-pointcloud/examples/td/td-pointcloud-visualizer/.gitignore @@ -0,0 +1 @@ +!td-pointcloud-visualizer.toe \ No newline at end of file diff --git a/streaming-pointcloud/examples/td/td-pointcloud-visualizer/resources/MqttToTex.dll b/streaming-pointcloud/examples/td/td-pointcloud-visualizer/resources/MqttToTex.dll new file mode 100644 index 00000000..544a47aa Binary files /dev/null and b/streaming-pointcloud/examples/td/td-pointcloud-visualizer/resources/MqttToTex.dll differ diff --git a/streaming-pointcloud/examples/td/td-pointcloud-visualizer/td-pointcloud-visualizer.toe b/streaming-pointcloud/examples/td/td-pointcloud-visualizer/td-pointcloud-visualizer.toe new file mode 100644 index 00000000..e54a41eb Binary files /dev/null and b/streaming-pointcloud/examples/td/td-pointcloud-visualizer/td-pointcloud-visualizer.toe differ diff --git a/streaming-pointcloud/examples/td/td-screenshot.jpg b/streaming-pointcloud/examples/td/td-screenshot.jpg new file mode 100644 index 00000000..3da6d60a Binary files /dev/null and b/streaming-pointcloud/examples/td/td-screenshot.jpg differ diff --git a/streaming-pointcloud/examples/td/top-plugin/CPlusPlus_Common.h b/streaming-pointcloud/examples/td/top-plugin/CPlusPlus_Common.h new file mode 100644 index 00000000..4dfbb4b1 --- /dev/null +++ b/streaming-pointcloud/examples/td/top-plugin/CPlusPlus_Common.h @@ -0,0 +1,1492 @@ +/* Shared Use License: This file is owned by Derivative Inc. (Derivative) +* and can only be used, and/or modified for use, in conjunction with +* Derivative's TouchDesigner software, and only if you are a licensee who has +* accepted Derivative's TouchDesigner license or assignment agreement +* (which also govern the use of this file). You may share or redistribute +* a modified version of this file provided the following conditions are met: +* +* 1. The shared file or redistribution must retain the information set out +* above and this list of conditions. +* 2. Derivative's name (Derivative Inc.) or its trademarks may not be used +* to endorse or promote products derived from this file without specific +* prior written permission from Derivative. +*/ + +/******* +Derivative Developers: Make sure the virtual function order +stays the same, otherwise changes won't be backwards compatible +********/ + + +#ifndef __CPlusPlus_Common +#define __CPlusPlus_Common + + +#ifdef _WIN32 + #define NOMINMAX + #include + #include + #include "GL_Extensions.h" + #define DLLEXPORT __declspec (dllexport) +#else + #include + #define DLLEXPORT +#endif + +#include +#include +#include + +#ifndef PyObject_HEAD + struct _object; + typedef _object PyObject; +#endif + +struct cudaArray; + +enum class OP_CPUMemPixelType : int32_t +{ + // 8-bit per color, BGRA pixels. This is preferred for 4 channel 8-bit data + BGRA8Fixed = 0, + // 8-bit per color, RGBA pixels. Only use this one if absolutely nesseary. + RGBA8Fixed, + // 32-bit float per color, RGBA pixels + RGBA32Float, + + // A few single and two channel versions of the above + R8Fixed, + RG8Fixed, + R32Float, + RG32Float, + + R16Fixed = 100, + RG16Fixed, + RGBA16Fixed, + + R16Float = 200, + RG16Float, + RGBA16Float, +}; + +class OP_String; + +// Used to describe this Plugin so it can be used as a custom OP. +// Can be filled in as part of the Fill*PluginInfo() callback +class OP_CustomOPInfo +{ +public: + // For this plugin to be treated as a Custom OP, all of the below fields + // must be filled in correctly. Otherwise the .dll can only be used + // when manually loaded into the C++ TOP + + // The type name of the node, this needs to be unique from all the other + // TOP plugins loaded on the system. The name must start with an upper case + // character (A-Z), and the rest should be lower case + // Only the characters a-z and 0-9 are allowed in the opType. + // Spaces are not allowed + OP_String* opType; + + // The english readable label for the node. This is what is shown in the + // OP Create Menu dialog. + // Spaces and other special characters are allowed. + // This can be a UTF-8 encoded string for non-english langauge label + OP_String* opLabel; + + // This should be three letters (upper or lower case), or numbers, which + // are used to create an icon for this Custom OP. + OP_String* opIcon; + + // The minimum number of wired inputs required for this OP to function. + int32_t minInputs = 0; + + // The maximum number of connected inputs allowed for this OP. If this plugin + // always requires 1 input, then set both min and max to 1. + int32_t maxInputs = 0; + + // The name of the author + OP_String* authorName; + + // The email of the author + OP_String* authorEmail; + + // Major version should be used to differentiate between drastically different + // versions of this Custom OP. In particular changes that arn't backwards + // compatible. + // A project file will compare the major version of OPs saved in it with the + // major version of the plugin installed on the system, and expect them to be + // the same. + int32_t majorVersion = 0; + + // Minor version is used to denote upgrades to a plugin. It should be increased + // when new features are added to a plugin that would cause loading up a project + // with an older version of the plguin to behavior incorrectly. For example + // if new parameters are added to the plugin. + // A project file will expect the plugin installed on the system to be greater than + // or equal to the plugin version the project was created with. Assuming + // the majorVersion is the same. + int32_t minorVersion = 1; + + // If this Custom OP is using CPython objects (PyObject* etc.) obtained via + // getParPython() calls, this needs to be set to the Python + // version this plugin is compiled against. + // + // This ensures when TD's Python version is upgraded the plugins will + // error cleanly. This should be set to PY_VERSION as defined in + // patchlevel.h from the Python include folder. (E.g, "3.5.1") + // It should be left unchanged if CPython isn't being used in this plugin. + OP_String* pythonVersion; + + int32_t reserved[98]; +}; + + +class OP_NodeInfo +{ +public: + + // The full path to the operator + const char* opPath; + + // A unique ID representing the operator, no two operators will ever + // have the same ID in a single TouchDesigner instance. + uint32_t opId; + + // This is the handle to the main TouchDesigner window. + // It's possible this will be 0 the first few times the operator cooks, + // incase it cooks while TouchDesigner is still loading up +#ifdef _WIN32 + HWND mainWindowHandle; +#endif + + // The path to where the plugin's binary is located on this machine. + // UTF8-8 encoded. + const char* pluginPath; + + int32_t reserved[17]; +}; + + +class OP_DATInput +{ +public: + const char* opPath; + uint32_t opId; + + int32_t numRows; + int32_t numCols; + bool isTable; + + // data, referenced by (row,col), which will be a const char* for the + // contents of the cell + // E.g getCell(1,2) will be the contents of the cell located at (1,2) + // The string will be in UTF-8 encoding. + const char* + getCell(int32_t row, int32_t col) const + { + return cellData[row * numCols + col]; + } + + const char** cellData; + + // The number of times this node has cooked + int64_t totalCooks; + + int32_t reserved[18]; +}; + + +class OP_TOPInput +{ +public: + const char* opPath; + uint32_t opId; + + int32_t width; + int32_t height; + + // You can use OP_Inputs::getTOPDataInCPUMemory() to download the + // data from a TOP input into CPU memory easily. + + // The OpenGL Texture index for this TOP. + // This is only valid when accessed from C++ TOPs. + // Other C++ OPs will have this value set to 0 (invalid). + GLuint textureIndex; + + // The OpenGL Texture target for this TOP. + // E.g GL_TEXTURE_2D, GL_TEXTURE_CUBE, + // GL_TEXTURE_2D_ARRAY + GLenum textureType; + + // Depth for 3D and 2D_ARRAY textures, undefined + // for other texture types + uint32_t depth; + + // contains the internalFormat for the texture + // such as GL_RGBA8, GL_RGBA32F, GL_R16 + GLint pixelFormat; + + int32_t reserved1; + + // When the TOP_ExecuteMode is CUDA, this will be filled in + cudaArray* cudaInput; + + // The number of times this node has cooked + int64_t totalCooks; + + int32_t reserved[14]; +}; + +class OP_String +{ +protected: + OP_String() + { + } + + virtual ~OP_String() + { + } + +public: + + // val is expected to be UTF-8 encoded + virtual void setString(const char* val) = 0; + + + int32_t reserved[20]; + +}; + + +class OP_CHOPInput +{ +public: + + const char* opPath; + uint32_t opId; + + int32_t numChannels; + int32_t numSamples; + double sampleRate; + double startIndex; + + + + // Retrieve a float array for a specific channel. + // 'i' ranges from 0 to numChannels-1 + // The returned arrray contains 'numSamples' samples. + // e.g: getChannelData(1)[10] will refer to the 11th sample in the 2nd channel + + const float* + getChannelData(int32_t i) const + { + return channelData[i]; + } + + + // Retrieve the name of a specific channel. + // 'i' ranges from 0 to numChannels-1 + // For example getChannelName(1) is the name of the 2nd channel + + const char* + getChannelName(int32_t i) const + { + return nameData[i]; + } + + const float** channelData; + const char** nameData; + + // The number of times this node has cooked + int64_t totalCooks; + + int32_t reserved[18]; +}; + + +class OP_ObjectInput +{ +public: + + const char* opPath; + uint32_t opId; + + // Use these methods to calculate object transforms + double worldTransform[4][4]; + double localTransform[4][4]; + + // The number of times this node has cooked + int64_t totalCooks; + + int32_t reserved[18]; +}; + + +// The type of data the attribute holds +enum class AttribType : int32_t +{ + // One or more floats + Float = 0, + + // One or more integers + Int, +}; + +// Right now we only support point attributes. +enum class AttribSet : int32_t +{ + Invalid, + Point = 0, +}; + +// The type of the primitives, currently only Polygon type +// is supported +enum class PrimitiveType : int32_t +{ + Invalid, + Polygon = 0, +}; + + +class Vector +{ +public: + Vector() + { + x = 0.0f; + y = 0.0f; + z = 0.0f; + } + + Vector(float xx, float yy, float zz) + { + x = xx; + y = yy; + z = zz; + } + + // inplace operators + inline Vector& + operator*=(const float scalar) + { + x *= scalar; + y *= scalar; + z *= scalar; + return *this; + } + + inline Vector& + operator/=(const float scalar) + { + x /= scalar; + y /= scalar; + z /= scalar; + return *this; + } + + inline Vector& + operator-=(const Vector& trans) + { + x -= trans.x; + y -= trans.y; + z -= trans.z; + return *this; + } + + inline Vector& + operator+=(const Vector& trans) + { + x += trans.x; + y += trans.y; + z += trans.z; + return *this; + } + + // non-inplace operations: + inline Vector + operator*(const float scalar) + { + Vector temp(*this); + temp.x *= scalar; + temp.y *= scalar; + temp.z *= scalar; + return temp; + } + + inline Vector + operator/(const float scalar) + { + Vector temp(*this); + temp.x /= scalar; + temp.y /= scalar; + temp.z /= scalar; + return temp; + } + + inline Vector + operator-(const Vector& trans) + { + Vector temp(*this); + temp.x -= trans.x; + temp.y -= trans.y; + temp.z -= trans.z; + return temp; + } + + inline Vector + operator+(const Vector& trans) + { + Vector temp(*this); + temp.x += trans.x; + temp.y += trans.y; + temp.z += trans.z; + return temp; + } + + //------ + float + dot(const Vector &v) const + { + return x * v.x + y * v.y + z * v.z; + } + + inline float + length() + { + return sqrtf(dot(*this)); + } + + inline float + normalize() + { + float dn = x * x + y * y + z * z; + if (dn > FLT_MIN && dn != 1.0F) + { + dn = sqrtf(dn); + (*this) /= dn; + } + return dn; + } + + float x; + float y; + float z; +}; + +class Position +{ +public: + Position() + { + x = 0.0f; + y = 0.0f; + z = 0.0f; + } + + Position(float xx, float yy, float zz) + { + x = xx; + y = yy; + z = zz; + } + + // in-place operators + inline Position& operator*=(const float scalar) + { + x *= scalar; + y *= scalar; + z *= scalar; + return *this; + } + + inline Position& operator/=(const float scalar) + { + x /= scalar; + y /= scalar; + z /= scalar; + return *this; + } + + inline Position& operator-=(const Vector& trans) + { + x -= trans.x; + y -= trans.y; + z -= trans.z; + return *this; + } + + inline Position& operator+=(const Vector& trans) + { + x += trans.x; + y += trans.y; + z += trans.z; + return *this; + } + + // non-inplace operators + inline Position operator*(const float scalar) + { + Position temp(*this); + temp.x *= scalar; + temp.y *= scalar; + temp.z *= scalar; + return temp; + } + + inline Position operator/(const float scalar) + { + Position temp(*this); + temp.x /= scalar; + temp.y /= scalar; + temp.z /= scalar; + return temp; + } + + inline Position operator+(const Vector& trans) + { + Position temp(*this); + temp.x += trans.x; + temp.y += trans.y; + temp.z += trans.z; + return temp; + } + + inline Position operator-(const Vector& trans) + { + Position temp(*this); + temp.x -= trans.x; + temp.y -= trans.y; + temp.z -= trans.z; + return temp; + } + + float x; + float y; + float z; +}; + + +class Color +{ +public: + Color () + { + r = 1.0f; + g = 1.0f; + b = 1.0f; + a = 1.0f; + } + + Color (float rr, float gg, float bb, float aa) + { + r = rr; + g = gg; + b = bb; + a = aa; + } + + float r; + float g; + float b; + float a; +}; + + +class TexCoord +{ +public: + TexCoord() + { + u = 0.0f; + v = 0.0f; + w = 0.0f; + } + + TexCoord(float uu, float vv, float ww) + { + u = uu; + v = vv; + w = ww; + } + + float u; + float v; + float w; +}; + +class BoundingBox +{ +public: + BoundingBox(float minx, float miny, float minz, + float maxx, float maxy, float maxz) : + minX(minx), minY(miny), minZ(minz), maxX(maxx), maxY(maxy), maxZ(maxz) + { + } + + BoundingBox(const Position& min, const Position& max) + { + minX = min.x; + maxX = max.x; + minY = min.y; + maxY = max.y; + minZ = min.z; + maxZ = max.z; + } + + BoundingBox(const Position& center, float x, float y, float z) + { + minX = center.x - x; + maxX = center.x + x; + minY = center.y - y; + maxY = center.y + y; + minZ = center.z - z; + maxZ = center.z + z; + } + + // enlarge the bounding box by the input point Position + void + enlargeBounds(const Position& pos) + { + if (pos.x < minX) + minX = pos.x; + if (pos.x > maxX) + maxX = pos.x; + if (pos.y < minY) + minY = pos.y; + if (pos.y > maxY) + maxY = pos.y; + if (pos.z < minZ) + minZ = pos.z; + if (pos.z > maxZ) + maxZ = pos.z; + } + + // enlarge the bounding box by the input bounding box: + void + enlargeBounds(const BoundingBox &box) + { + if (box.minX < minX) + minX = box.minX; + if (box.maxX > maxX) + maxX = box.maxX; + if (box.minY < minY) + minY = box.minY; + if (box.maxY > maxY) + maxY = box.maxY; + if (box.minZ < minZ) + minZ = box.minZ; + if (box.maxZ > maxZ) + maxZ = box.maxZ; + } + + // returns the bounding box length in x axis: + float + sizeX() + { + return maxX - minX; + } + + // returns the bounding box length in y axis: + float + sizeY() + { + return maxY - minY; + } + + // returns the bounding box length in z axis: + float + sizeZ() + { + return maxZ - minZ; + } + + bool + getCenter(Position* pos) + { + if (!pos) + return false; + pos->x = (minX + maxX) / 2.0f; + pos->y = (minY + maxY) / 2.0f; + pos->z = (minZ + maxZ) / 2.0f; + return true; + } + + // verifies if the input position (pos) is inside the current bounding box or not: + bool + isInside(const Position& pos) + { + if (pos.x >= minX && pos.x <= maxX && + pos.y >= minY && pos.y <= maxY && + pos.z >= minZ && pos.z <= maxZ) + return true; + else + return false; + } + + + float minX; + float minY; + float minZ; + + float maxX; + float maxY; + float maxZ; + +}; + + +class SOP_NormalInfo +{ +public: + + SOP_NormalInfo() + { + numNormals = 0; + attribSet = AttribSet::Point; + normals = nullptr; + } + + int32_t numNormals; + AttribSet attribSet; + const Vector* normals; +}; + +class SOP_ColorInfo +{ +public: + + SOP_ColorInfo() + { + numColors = 0; + attribSet = AttribSet::Point; + colors = nullptr; + } + + int32_t numColors; + AttribSet attribSet; + const Color* colors; +}; + +class SOP_TextureInfo +{ +public: + + SOP_TextureInfo() + { + numTextures = 0; + attribSet = AttribSet::Point; + textures = nullptr; + numTextureLayers = 0; + } + + int32_t numTextures; + AttribSet attribSet; + const TexCoord* textures; + int32_t numTextureLayers; +}; + + + +// CustomAttribInfo, all the required data for each custom attribute +// this info can be queried by calling getCustomAttribute() which accepts +// two types of argument: +// 1) a valid index of a custom attribute +// 2) a valid name of a custom attribute +class SOP_CustomAttribInfo +{ +public: + + SOP_CustomAttribInfo() + { + name = nullptr; + numComponents = 0; + attribType = AttribType::Float; + } + + SOP_CustomAttribInfo(const char* n, int32_t numComp, const AttribType& type) + { + name = n; + numComponents = numComp; + attribType = type; + } + + const char* name; + int32_t numComponents; + AttribType attribType; +}; + +// SOP_CustomAttribData, all the required data for each custom attribute +// this info can be queried by calling getCustomAttribute() which accepts +// a valid name of a custom attribute +class SOP_CustomAttribData : public SOP_CustomAttribInfo +{ +public: + + SOP_CustomAttribData() + { + name = nullptr; + numComponents = 0; + attribType = AttribType::Float; + floatData = nullptr; + intData = nullptr; + } + + SOP_CustomAttribData(const char* n, int32_t numComp, const AttribType& type) + { + name = n; + numComponents = numComp; + attribType = type; + floatData = nullptr; + intData = nullptr; + } + + const float* floatData; + const int32_t* intData; + +}; + +// SOP_PrimitiveInfo, all the required data for each primitive +// this info can be queried by calling getPrimitive() which accepts +// a valid index of a primitive as an input argument +class SOP_PrimitiveInfo +{ +public: + + SOP_PrimitiveInfo() + { + pointIndices = nullptr; + numVertices = 0; + type = PrimitiveType::Invalid; + pointIndicesOffset = 0; + } + + // number of vertices of this prim + int32_t numVertices; + + // all the indices of the vertices of the primitive. This array has + // numVertices entries in it + const int32_t* pointIndices; + + // The type of this primitive + PrimitiveType type; + + // the offset of the this primitive's point indices in the index array + // returned from getAllPrimPointIndices() + int32_t pointIndicesOffset; + +}; + + + + +class OP_SOPInput +{ +public: + + virtual ~OP_SOPInput() + { + } + + + + const char* opPath; + uint32_t opId; + + + // Returns the total number of points + virtual int32_t getNumPoints() const = 0; + + // The total number of vertices, across all primitives. + virtual int32_t getNumVertices() const = 0; + + // The total number of primitives + virtual int32_t getNumPrimitives() const = 0; + + // The total number of custom attributes + virtual int32_t getNumCustomAttributes() const = 0; + + // Returns an array of point positions. This array is getNumPoints() long. + virtual const Position* getPointPositions() const = 0; + + // Returns an array of normals. + // + // Returns nullptr if no normals are present + virtual const SOP_NormalInfo* getNormals() const = 0; + + // Returns an array of colors. + // Returns nullptr if no colors are present + virtual const SOP_ColorInfo* getColors() const = 0; + + // Returns an array of texture coordinates. + // If multiple texture coordinate layers are present, they will be placed + // interleaved back-to-back. + // E.g layer0 followed by layer1 followed by layer0 etc. + // + // Returns nullptr if no texture layers are present + virtual const SOP_TextureInfo* getTextures() const = 0; + + // Returns the custom attribute data with an input index + virtual const SOP_CustomAttribData* getCustomAttribute(int32_t customAttribIndex) const = 0; + + // Returns the custom attribute data with its name + virtual const SOP_CustomAttribData* getCustomAttribute(const char* customAttribName) const = 0; + + // Returns true if the SOP has a normal attribute of the given source + // attribute 'N' + virtual bool hasNormals() const = 0; + + // Returns true if the SOP has a color the given source + // attribute 'Cd' + virtual bool hasColors() const = 0; + + // Returns the SOP_PrimitiveInfo with primIndex + const SOP_PrimitiveInfo + getPrimitive(int32_t primIndex) const + { + return myPrimsInfo[primIndex]; + } + + // Returns the full list of all the point indices for all primitives. + // The primitives are stored back to back in this array. + // This is a faster but harder way to work with primitives than + // getPrimPointIndices() + const int32_t* + getAllPrimPointIndices() + { + return myPrimPointIndices; + } + + SOP_PrimitiveInfo* myPrimsInfo; + const int32_t* myPrimPointIndices; + + // The number of times this node has cooked + int64_t totalCooks; + + int32_t reserved[98]; +}; + + + +enum class OP_TOPInputDownloadType : int32_t +{ + // The texture data will be downloaded and and available on the next frame. + // Except for the first time this is used, getTOPDataInCPUMemory() + // will return the texture data on the CPU from the previous frame. + // The first getTOPDataInCPUMemory() is called it will be nullptr. + // ** This mode should be used is most cases for performance reasons ** + Delayed = 0, + + // The texture data will be downloaded immediately and be available + // this frame. This can cause a large stall though and should be avoided + // in most cases + Instant, +}; + +class OP_TOPInputDownloadOptions +{ +public: + OP_TOPInputDownloadOptions() + { + downloadType = OP_TOPInputDownloadType::Delayed; + verticalFlip = false; + cpuMemPixelType = OP_CPUMemPixelType::BGRA8Fixed; + } + + OP_TOPInputDownloadType downloadType; + + // Set this to true if you want the image vertically flipped in the + // downloaded data + bool verticalFlip; + + // Set this to how you want the pixel data to be give to you in CPU + // memory. BGRA8Fixed should be used for 4 channel 8-bit data if possible + OP_CPUMemPixelType cpuMemPixelType; + +}; + +class OP_TimeInfo +{ +public: + + // same as global Python value absTime.frame. Counts up forever + // since the application started. In rootFPS units. + int64_t absFrame; + + // The timeline frame number for this cook + double frame; + + // The timeline FPS/rate this node is cooking at. + // If the component this node is located in has Component Time, it's FPS + // may be different than the Root FPS + double rate; + + // The frame number for the root timeline. Different than frame + // if the node is in a component that has component time. + double rootFrame; + + // The Root FPS/Rate the file is running at. + double rootRate; + + // The number of frames that have elapsed since the last cook occured. + // This can be more than one if frames were dropped. + // If this is the first time this node is cooking, this will be 0.0 + // This is in 'rate' units, not 'rootRate' units. + double deltaFrames; + + // The number of milliseconds that have elapsed since the last cook. + // Note that this isn't done via CPU timers, but is instead + // simply deltaFrames * milliSecondsPerFrame + double deltaMS; + + + + int32_t reserved[40]; +}; + + +class OP_Inputs +{ +public: + // NOTE: When writting a TOP, none of these functions should + // be called inside a beginGLCommands()/endGLCommands() section + // as they may require GL themselves to complete execution. + + // Inputs that are wired into the node. Note that since some inputs + // may not be connected this number doesn't mean that that the first N + // inputs are connected. For example on a 3 input node if the 3rd input + // is only one connected, this will return 1, and getInput*(0) and (1) + // will return nullptr. + virtual int32_t getNumInputs() const = 0; + + // Will return nullptr when the input has nothing connected to it. + // only valid for C++ TOP operators + virtual const OP_TOPInput* getInputTOP(int32_t index) const = 0; + // Only valid for C++ CHOP operators + virtual const OP_CHOPInput* getInputCHOP(int32_t index) const = 0; + // getInputSOP() declared later on in the class + // getInputDAT() declared later on in the class + + // these are defined by parameters. + // may return nullptr when invalid input + // this value is valid until the parameters are rebuilt or it is called with the same parameter name. + virtual const OP_DATInput* getParDAT(const char *name) const = 0; + virtual const OP_TOPInput* getParTOP(const char *name) const = 0; + virtual const OP_CHOPInput* getParCHOP(const char *name) const = 0; + virtual const OP_ObjectInput* getParObject(const char *name) const = 0; + // getParSOP() declared later on in the class + + // these work on any type of parameter and can be interchanged + // for menu types, int returns the menu selection index, string returns the item + + // returns the requested value, index may be 0 to 4. + virtual double getParDouble(const char* name, int32_t index = 0) const = 0; + + // for multiple values: returns True on success/false otherwise + virtual bool getParDouble2(const char* name, double &v0, double &v1) const = 0; + virtual bool getParDouble3(const char* name, double &v0, double &v1, double &v2) const = 0; + virtual bool getParDouble4(const char* name, double &v0, double &v1, double &v2, double &v3) const = 0; + + + // returns the requested value + virtual int32_t getParInt(const char* name, int32_t index = 0) const = 0; + + // for multiple values: returns True on success/false otherwise + virtual bool getParInt2(const char* name, int32_t &v0, int32_t &v1) const = 0; + virtual bool getParInt3(const char* name, int32_t &v0, int32_t &v1, int32_t &v2) const = 0; + virtual bool getParInt4(const char* name, int32_t &v0, int32_t &v1, int32_t &v2, int32_t &v3) const = 0; + + // returns the requested value + // this value is valid until the parameters are rebuilt or it is called with the same parameter name. + // return value usable for life of parameter + // The returned string will be in UTF-8 encoding. + virtual const char* getParString(const char* name) const = 0; + + + // this is similar to getParString, but will return an absolute path if it exists, with + // slash direction consistent with O/S requirements. + // to get the original parameter value, use getParString + // return value usable for life of parameter + // The returned string will be in UTF-8 encoding. + virtual const char* getParFilePath(const char* name) const = 0; + + // returns true on success + // from_name and to_name must be Object parameters + virtual bool getRelativeTransform(const char* from_name, const char* to_name, double matrix[4][4]) const = 0; + + + // disable or enable updating of the parameter + virtual void enablePar(const char* name, bool onoff) const = 0; + + + // these are defined by paths. + // may return nullptr when invalid input + // this value is valid until the parameters are rebuilt or it is called with the same parameter name. + virtual const OP_DATInput* getDAT(const char *path) const = 0; + virtual const OP_TOPInput* getTOP(const char *path) const = 0; + virtual const OP_CHOPInput* getCHOP(const char *path) const = 0; + virtual const OP_ObjectInput* getObject(const char *path) const = 0; + + + // This function can be used to retrieve the TOPs texture data in CPU + // memory. You must pass the OP_TOPInput object you get from + // getParTOP/getInputTOP into this, not a copy you've made + // + // Fill in a OP_TOPIputDownloadOptions class with the desired options set + // + // Returns the data, which will be valid until the end of execute() + // Returned value may be nullptr in some cases, such as the first call + // to this with options->downloadType == OP_TOP_DOWNLOAD_DELAYED. + virtual void* getTOPDataInCPUMemory(const OP_TOPInput *top, + const OP_TOPInputDownloadOptions *options) const = 0; + + + virtual const OP_SOPInput* getParSOP(const char *name) const = 0; + // only valid for C++ SOP operators + virtual const OP_SOPInput* getInputSOP(int32_t index) const = 0; + virtual const OP_SOPInput* getSOP(const char *path) const = 0; + + // only valid for C++ DAT operators + virtual const OP_DATInput* getInputDAT(int32_t index) const = 0; + + // To use Python in your Plugin you need to fill the + // customOPInfo.pythonVersion member in Fill*PluginInfo. + // + // The returned object does NOT have it's reference count incremented. + // So increment it if you want to hold onto the object, and only + // decement it if you've incremented it. + virtual PyObject* getParPython(const char* name) const = 0; + + + // Returns a class whose members gives you information about timing + // such as FPS and delta-time since the last cook. + // See OP_TimeInfo for more information + virtual const OP_TimeInfo* getTimeInfo() const = 0; + +}; + +class OP_InfoCHOPChan +{ +public: + OP_String* name; + float value; + + int32_t reserved[10]; +}; + + +class OP_InfoDATSize +{ +public: + + // Set this to the size you want the table to be + + int32_t rows; + int32_t cols; + + // Set this to true if you want to return DAT entries on a column + // by column basis. + // Otherwise set to false, and you'll be expected to set them on + // a row by row basis. + // DEFAULT : false + + bool byColumn; + + int32_t reserved[10]; +}; + + +class OP_InfoDATEntries +{ +public: + + // This is an array of OP_String* pointers which you are expected to assign + // values to. + // e.g values[1]->setString("myColumnName"); + // The string should be in UTF-8 encoding. + OP_String** values; + + int32_t reserved[10]; +}; + + +class OP_NumericParameter +{ +public: + + OP_NumericParameter(const char* iname = nullptr) + { + name = iname; + label = page = nullptr; + + for (int i = 0; i<4; i++) + { + defaultValues[i] = 0.0; + + minSliders[i] = 0.0; + maxSliders[i] = 1.0; + + minValues[i] = 0.0; + maxValues[i] = 1.0; + + clampMins[i] = false; + clampMaxes[i] = false; + } + } + + // Any char* values passed are copied immediately by the append parameter functions, + // and do not need to be retained by the calling function. + // Must begin with capital letter, and contain no spaces + const char* name; + const char* label; + const char* page; + + double defaultValues[4]; + double minValues[4]; + double maxValues[4]; + + bool clampMins[4]; + bool clampMaxes[4]; + + double minSliders[4]; + double maxSliders[4]; + + int32_t reserved[20]; + +}; + + +class OP_StringParameter +{ +public: + + OP_StringParameter(const char* iname = nullptr) + { + name = iname; + label = page = nullptr; + defaultValue = nullptr; + } + + // Any char* values passed are copied immediately by the append parameter functions, + // and do not need to be retained by the calling function. + + // Must begin with capital letter, and contain no spaces + const char* name; + const char* label; + const char* page; + + // This should be in UTF-8 encoding. + const char* defaultValue; + + int32_t reserved[20]; +}; + + +enum class OP_ParAppendResult : int32_t +{ + Success = 0, + InvalidName, // invalid or duplicate name + InvalidSize, // size out of range +}; + + +class OP_ParameterManager +{ + +public: + + // Returns PARAMETER_APPEND_SUCCESS on succesful + + virtual OP_ParAppendResult appendFloat(const OP_NumericParameter &np, int32_t size = 1) = 0; + virtual OP_ParAppendResult appendInt(const OP_NumericParameter &np, int32_t size = 1) = 0; + + virtual OP_ParAppendResult appendXY(const OP_NumericParameter &np) = 0; + virtual OP_ParAppendResult appendXYZ(const OP_NumericParameter &np) = 0; + + virtual OP_ParAppendResult appendUV(const OP_NumericParameter &np) = 0; + virtual OP_ParAppendResult appendUVW(const OP_NumericParameter &np) = 0; + + virtual OP_ParAppendResult appendRGB(const OP_NumericParameter &np) = 0; + virtual OP_ParAppendResult appendRGBA(const OP_NumericParameter &np) = 0; + + virtual OP_ParAppendResult appendToggle(const OP_NumericParameter &np) = 0; + virtual OP_ParAppendResult appendPulse(const OP_NumericParameter &np) = 0; + + virtual OP_ParAppendResult appendString(const OP_StringParameter &sp) = 0; + virtual OP_ParAppendResult appendFile(const OP_StringParameter &sp) = 0; + virtual OP_ParAppendResult appendFolder(const OP_StringParameter &sp) = 0; + + virtual OP_ParAppendResult appendDAT(const OP_StringParameter &sp) = 0; + virtual OP_ParAppendResult appendCHOP(const OP_StringParameter &sp) = 0; + virtual OP_ParAppendResult appendTOP(const OP_StringParameter &sp) = 0; + virtual OP_ParAppendResult appendObject(const OP_StringParameter &sp) = 0; + // appendSOP() located further down in the class + + + // Any char* values passed are copied immediately by the append parameter functions, + // and do not need to be retained by the calling function. + virtual OP_ParAppendResult appendMenu(const OP_StringParameter &sp, + int32_t nitems, const char **names, + const char **labels) = 0; + + // Any char* values passed are copied immediately by the append parameter functions, + // and do not need to be retained by the calling function. + virtual OP_ParAppendResult appendStringMenu(const OP_StringParameter &sp, + int32_t nitems, const char **names, + const char **labels) = 0; + + virtual OP_ParAppendResult appendSOP(const OP_StringParameter &sp) = 0; + + // To use Python in your Plugin you need to fill the + // customOPInfo.pythonVersion member in Fill*PluginInfo. + virtual OP_ParAppendResult appendPython(const OP_StringParameter &sp) = 0; + + +}; + +static_assert(offsetof(OP_CustomOPInfo, opType) == 0, "Incorrect Alignment"); +static_assert(offsetof(OP_CustomOPInfo, opLabel) == 8, "Incorrect Alignment"); +static_assert(offsetof(OP_CustomOPInfo, opIcon) == 16, "Incorrect Alignment"); +static_assert(offsetof(OP_CustomOPInfo, minInputs) == 24, "Incorrect Alignment"); +static_assert(offsetof(OP_CustomOPInfo, maxInputs) == 28, "Incorrect Alignment"); +static_assert(offsetof(OP_CustomOPInfo, authorName) == 32, "Incorrect Alignment"); +static_assert(offsetof(OP_CustomOPInfo, authorEmail) == 40, "Incorrect Alignment"); +static_assert(offsetof(OP_CustomOPInfo, majorVersion) == 48, "Incorrect Alignment"); +static_assert(offsetof(OP_CustomOPInfo, minorVersion) == 52, "Incorrect Alignment"); +static_assert(sizeof(OP_CustomOPInfo) == 456, "Incorrect Size"); + +static_assert(offsetof(OP_NodeInfo, opPath) == 0, "Incorrect Alignment"); +static_assert(offsetof(OP_NodeInfo, opId) == 8, "Incorrect Alignment"); +#ifdef _WIN32 + static_assert(offsetof(OP_NodeInfo, mainWindowHandle) == 16, "Incorrect Alignment"); + static_assert(sizeof(OP_NodeInfo) == 104, "Incorrect Size"); +#else + static_assert(sizeof(OP_NodeInfo) == 96, "Incorrect Size"); +#endif + +static_assert(offsetof(OP_DATInput, opPath) == 0, "Incorrect Alignment"); +static_assert(offsetof(OP_DATInput, opId) == 8, "Incorrect Alignment"); +static_assert(offsetof(OP_DATInput, numRows) == 12, "Incorrect Alignment"); +static_assert(offsetof(OP_DATInput, numCols) == 16, "Incorrect Alignment"); +static_assert(offsetof(OP_DATInput, isTable) == 20, "Incorrect Alignment"); +static_assert(offsetof(OP_DATInput, cellData) == 24, "Incorrect Alignment"); +static_assert(offsetof(OP_DATInput, totalCooks) == 32, "Incorrect Alignment"); +static_assert(sizeof(OP_DATInput) == 112, "Incorrect Size"); + +static_assert(offsetof(OP_TOPInput, opPath) == 0, "Incorrect Alignment"); +static_assert(offsetof(OP_TOPInput, opId) == 8, "Incorrect Alignment"); +static_assert(offsetof(OP_TOPInput, width) == 12, "Incorrect Alignment"); +static_assert(offsetof(OP_TOPInput, height) == 16, "Incorrect Alignment"); +static_assert(offsetof(OP_TOPInput, textureIndex) == 20, "Incorrect Alignment"); +static_assert(offsetof(OP_TOPInput, textureType) == 24, "Incorrect Alignment"); +static_assert(offsetof(OP_TOPInput, depth) == 28, "Incorrect Alignment"); +static_assert(offsetof(OP_TOPInput, pixelFormat) == 32, "Incorrect Alignment"); +static_assert(offsetof(OP_TOPInput, cudaInput) == 40, "Incorrect Alignment"); +static_assert(offsetof(OP_TOPInput, totalCooks) == 48, "Incorrect Alignment"); +static_assert(sizeof(OP_TOPInput) == 112, "Incorrect Size"); + +static_assert(offsetof(OP_CHOPInput, opPath) == 0, "Incorrect Alignment"); +static_assert(offsetof(OP_CHOPInput, opId) == 8, "Incorrect Alignment"); +static_assert(offsetof(OP_CHOPInput, numChannels) == 12, "Incorrect Alignment"); +static_assert(offsetof(OP_CHOPInput, numSamples) == 16, "Incorrect Alignment"); +static_assert(offsetof(OP_CHOPInput, sampleRate) == 24, "Incorrect Alignment"); +static_assert(offsetof(OP_CHOPInput, startIndex) == 32, "Incorrect Alignment"); +static_assert(offsetof(OP_CHOPInput, channelData) == 40, "Incorrect Alignment"); +static_assert(offsetof(OP_CHOPInput, nameData) == 48, "Incorrect Alignment"); +static_assert(offsetof(OP_CHOPInput, totalCooks) == 56, "Incorrect Alignment"); +static_assert(sizeof(OP_CHOPInput) == 136, "Incorrect Size"); + +static_assert(offsetof(OP_ObjectInput, opPath) == 0, "Incorrect Alignment"); +static_assert(offsetof(OP_ObjectInput, opId) == 8, "Incorrect Alignment"); +static_assert(offsetof(OP_ObjectInput, worldTransform) == 16, "Incorrect Alignment"); +static_assert(offsetof(OP_ObjectInput, localTransform) == 144, "Incorrect Alignment"); +static_assert(offsetof(OP_ObjectInput, totalCooks) == 272, "Incorrect Alignment"); +static_assert(sizeof(OP_ObjectInput) == 352, "Incorrect Size"); + +static_assert(offsetof(Position, x) == 0, "Incorrect Alignment"); +static_assert(offsetof(Position, y) == 4, "Incorrect Alignment"); +static_assert(offsetof(Position, z) == 8, "Incorrect Alignment"); +static_assert(sizeof(Position) == 12, "Incorrect Size"); + +static_assert(offsetof(Vector, x) == 0, "Incorrect Alignment"); +static_assert(offsetof(Vector, y) == 4, "Incorrect Alignment"); +static_assert(offsetof(Vector, z) == 8, "Incorrect Alignment"); +static_assert(sizeof(Vector) == 12, "Incorrect Size"); + +static_assert(offsetof(Color, r) == 0, "Incorrect Alignment"); +static_assert(offsetof(Color, g) == 4, "Incorrect Alignment"); +static_assert(offsetof(Color, b) == 8, "Incorrect Alignment"); +static_assert(offsetof(Color, a) == 12, "Incorrect Alignment"); +static_assert(sizeof(Color) == 16, "Incorrect Size"); + +static_assert(offsetof(TexCoord, u) == 0, "Incorrect Alignment"); +static_assert(offsetof(TexCoord, v) == 4, "Incorrect Alignment"); +static_assert(offsetof(TexCoord, w) == 8, "Incorrect Alignment"); +static_assert(sizeof(TexCoord) == 12, "Incorrect Size"); + +static_assert(offsetof(SOP_NormalInfo, numNormals) == 0, "Incorrect Alignment"); +static_assert(offsetof(SOP_NormalInfo, attribSet) == 4, "Incorrect Alignment"); +static_assert(offsetof(SOP_NormalInfo, normals) == 8, "Incorrect Alignment"); +static_assert(sizeof(SOP_NormalInfo) == 16, "Incorrect Size"); + +static_assert(offsetof(SOP_ColorInfo, numColors) == 0, "Incorrect Alignment"); +static_assert(offsetof(SOP_ColorInfo, attribSet) == 4, "Incorrect Alignment"); +static_assert(offsetof(SOP_ColorInfo, colors) == 8, "Incorrect Alignment"); +static_assert(sizeof(SOP_ColorInfo) == 16, "Incorrect Size"); + +static_assert(offsetof(SOP_TextureInfo, numTextures) == 0, "Incorrect Alignment"); +static_assert(offsetof(SOP_TextureInfo, attribSet) == 4, "Incorrect Alignment"); +static_assert(offsetof(SOP_TextureInfo, textures) == 8, "Incorrect Alignment"); +static_assert(offsetof(SOP_TextureInfo, numTextureLayers) == 16, "Incorrect Alignment"); +static_assert(sizeof(SOP_TextureInfo) == 24, "Incorrect Size"); + +static_assert(offsetof(SOP_CustomAttribData, name) == 0, "Incorrect Alignment"); +static_assert(offsetof(SOP_CustomAttribData, numComponents) == 8, "Incorrect Alignment"); +static_assert(offsetof(SOP_CustomAttribData, attribType) == 12, "Incorrect Alignment"); +static_assert(offsetof(SOP_CustomAttribData, floatData) == 16, "Incorrect Alignment"); +static_assert(offsetof(SOP_CustomAttribData, intData) == 24, "Incorrect Alignment"); +static_assert(sizeof(SOP_CustomAttribData) == 32, "Incorrect Size"); + +static_assert(offsetof(SOP_PrimitiveInfo, numVertices) == 0, "Incorrect Alignment"); +static_assert(offsetof(SOP_PrimitiveInfo, pointIndices) == 8, "Incorrect Alignment"); +static_assert(offsetof(SOP_PrimitiveInfo, type) == 16, "Incorrect Alignment"); +static_assert(offsetof(SOP_PrimitiveInfo, pointIndicesOffset) == 20, "Incorrect Alignment"); +static_assert(sizeof(SOP_PrimitiveInfo) == 24, "Incorrect Size"); + +static_assert(sizeof(OP_SOPInput) == 440, "Incorrect Size"); + +static_assert(offsetof(OP_TOPInputDownloadOptions, downloadType) == 0, "Incorrect Alignment"); +static_assert(offsetof(OP_TOPInputDownloadOptions, verticalFlip) == 4, "Incorrect Alignment"); +static_assert(offsetof(OP_TOPInputDownloadOptions, cpuMemPixelType) == 8, "Incorrect Alignment"); +static_assert(sizeof(OP_TOPInputDownloadOptions) == 12, "Incorrect Size"); + +static_assert(offsetof(OP_InfoCHOPChan, name) == 0, "Incorrect Alignment"); +static_assert(offsetof(OP_InfoCHOPChan, value) == 8, "Incorrect Alignment"); +static_assert(sizeof(OP_InfoCHOPChan) == 56, "Incorrect Size"); + +static_assert(offsetof(OP_InfoDATSize, rows) == 0, "Incorrect Alignment"); +static_assert(offsetof(OP_InfoDATSize, cols) == 4, "Incorrect Alignment"); +static_assert(offsetof(OP_InfoDATSize, byColumn) == 8, "Incorrect Alignment"); +static_assert(sizeof(OP_InfoDATSize) == 52, "Incorrect Size"); + +static_assert(offsetof(OP_InfoDATEntries, values) == 0, "Incorrect Alignment"); +static_assert(sizeof(OP_InfoDATEntries) == 48, "Incorrect Size"); + +static_assert(offsetof(OP_NumericParameter, name) == 0, "Incorrect Alignment"); +static_assert(offsetof(OP_NumericParameter, label) == 8, "Incorrect Alignment"); +static_assert(offsetof(OP_NumericParameter, page) == 16, "Incorrect Alignment"); +static_assert(offsetof(OP_NumericParameter, defaultValues) == 24, "Incorrect Alignment"); +static_assert(offsetof(OP_NumericParameter, minValues) == 56, "Incorrect Alignment"); +static_assert(offsetof(OP_NumericParameter, maxValues) == 88, "Incorrect Alignment"); +static_assert(offsetof(OP_NumericParameter, clampMins) == 120, "Incorrect Alignment"); +static_assert(offsetof(OP_NumericParameter, clampMaxes) == 124, "Incorrect Alignment"); +static_assert(offsetof(OP_NumericParameter, minSliders) == 128, "Incorrect Alignment"); +static_assert(offsetof(OP_NumericParameter, maxSliders) == 160, "Incorrect Alignment"); +static_assert(sizeof(OP_NumericParameter) == 272, "Incorrect Size"); + +static_assert(offsetof(OP_StringParameter, name) == 0, "Incorrect Alignment"); +static_assert(offsetof(OP_StringParameter, label) == 8, "Incorrect Alignment"); +static_assert(offsetof(OP_StringParameter, page) == 16, "Incorrect Alignment"); +static_assert(offsetof(OP_StringParameter, defaultValue) == 24, "Incorrect Alignment"); +static_assert(sizeof(OP_StringParameter) == 112, "Incorrect Size"); +static_assert(sizeof(OP_TimeInfo) == 216, "Incorrect Size"); +#endif diff --git a/streaming-pointcloud/examples/td/top-plugin/FrameQueue.cpp b/streaming-pointcloud/examples/td/top-plugin/FrameQueue.cpp new file mode 100644 index 00000000..da53d817 --- /dev/null +++ b/streaming-pointcloud/examples/td/top-plugin/FrameQueue.cpp @@ -0,0 +1,233 @@ +/* Shared Use License: This file is owned by Derivative Inc. (Derivative) +* and can only be used, and/or modified for use, in conjunction with +* Derivative's TouchDesigner software, and only if you are a licensee who has +* accepted Derivative's TouchDesigner license or assignment agreement +* (which also govern the use of this file). You may share or redistribute +* a modified version of this file provided the following conditions are met: +* +* 1. The shared file or redistribution must retain the information set out +* above and this list of conditions. +* 2. Derivative's name (Derivative Inc.) or its trademarks may not be used +* to endorse or promote products derived from this file without specific +* prior written permission from Derivative. +*/ + +#include "FrameQueue.h" +#include + +FrameQueue::FrameQueue() : + myUpdateBuffer(nullptr) +{ + +} + +FrameQueue::~FrameQueue() +{ + assert(!myUpdateBuffer); +} + +void +FrameQueue::sync(TOP_OutputFormatSpecs * output) +{ + myLock.lock(); + + // First clear out buffers that are no longer valid + for (auto itr = myUpdatedBuffers.begin(); itr != myUpdatedBuffers.end(); ) + { + bool found = false; + for (int j = 0; j < NumCPUPixelDatas; j++) + { + if (*itr == output->cpuPixelData[j]) + { + found = true; + break; + } + } + + if (!found) + { + itr = myUpdatedBuffers.erase(itr); + } + else + { + itr++; + } + } + + for (auto itr = myUnusedBuffers.begin(); itr != myUnusedBuffers.end(); ) + { + bool found = false; + for (int j = 0; j < NumCPUPixelDatas; j++) + { + if (*itr == output->cpuPixelData[j]) + { + found = true; + break; + } + } + + if (!found) + { + itr = myUnusedBuffers.erase(itr); + } + else + { + itr++; + } + } + + // Now if there are new buffers given to use, take hold of them + for (int i = 0; i < NumCPUPixelDatas; i++) + { + void *buf = output->cpuPixelData[i]; + + bool found = false; + // Look for buf somewhere in our current data + + if (buf == myUpdateBuffer) + found = true; + else + { + for (const auto e : myUnusedBuffers) + { + if (e == buf) + { + found = true; + break; + } + } + + if (!found) + { + for (const auto e : myUpdatedBuffers) + { + if (e == buf) + { + found = true; + break; + } + } + } + + // Not found in our buffers, so add it as an available buffer. + if (!found) + { + myUnusedBuffers.push_back(buf); + + } + } + } + // Finally, clear out the active update buffer it it's become invalid + if (myUpdateBuffer) + { + bool found = false; + + for (int i = 0; i < NumCPUPixelDatas; i++) + { + if (myUpdateBuffer == output->cpuPixelData[i]) + { + found = true; + break; + } + } + + if (!found) + { + myUpdateBufferLock.lock(); + + // Throw it away + myUpdateBuffer = nullptr; + + myUpdateBufferLock.unlock(); + } + } + + myWidth = output->width; + myHeight = output->height; + + myLock.unlock(); +} + +void* +FrameQueue::getBufferForUpdate(int *width, int *height) +{ + // If this occurs it means a updateComplete/updateCancelled call wasn't + // done to match the previous call to getFrameForUpdate + assert(!myUpdateBuffer); + myLock.lock(); + + void *buf = nullptr; + // Try to get an unused buffer first + if (!myUnusedBuffers.empty()) + { + buf = myUnusedBuffers.front(); + myUnusedBuffers.pop_front(); + } + + // If there wasn't an unused buffer, then replace the content of the oldest filled buffer + if (!buf && !myUpdatedBuffers.empty()) + { + buf = myUpdatedBuffers.front(); + myUpdatedBuffers.pop_front(); + } + if (buf) + { + myUpdateBufferLock.lock(); + myUpdateBuffer = buf; + } + *width = myWidth; + *height = myHeight; + myLock.unlock(); + return buf; +} + +void +FrameQueue::updateComplete() +{ + myUpdateBufferLock.unlock(); + + myLock.lock(); + if (myUpdateBuffer) + { + myUpdatedBuffers.push_back(myUpdateBuffer); + myUpdateBuffer = nullptr; + } + myLock.unlock(); +} + +void +FrameQueue::updateCancelled() +{ + myUpdateBufferLock.unlock(); + + myLock.lock(); + if (myUpdateBuffer) + { + myUnusedBuffers.push_back(myUpdateBuffer); + myUpdateBuffer = nullptr; + } + myLock.unlock(); +} + +void +FrameQueue::sendBufferForUpload(TOP_OutputFormatSpecs* output) +{ + myLock.lock(); + + if (!myUpdatedBuffers.empty()) + { + void *buf = myUpdatedBuffers.front(); + myUpdatedBuffers.pop_front(); + + for (int i = 0; i < NumCPUPixelDatas; i++) + { + if (output->cpuPixelData[i] == buf) + { + output->newCPUPixelDataLocation = i; + buf = nullptr; + break; + } + } + } + myLock.unlock(); +} diff --git a/streaming-pointcloud/examples/td/top-plugin/FrameQueue.h b/streaming-pointcloud/examples/td/top-plugin/FrameQueue.h new file mode 100644 index 00000000..aa0b866f --- /dev/null +++ b/streaming-pointcloud/examples/td/top-plugin/FrameQueue.h @@ -0,0 +1,64 @@ +/* Shared Use License: This file is owned by Derivative Inc. (Derivative) +* and can only be used, and/or modified for use, in conjunction with +* Derivative's TouchDesigner software, and only if you are a licensee who has +* accepted Derivative's TouchDesigner license or assignment agreement +* (which also govern the use of this file). You may share or redistribute +* a modified version of this file provided the following conditions are met: +* +* 1. The shared file or redistribution must retain the information set out +* above and this list of conditions. +* 2. Derivative's name (Derivative Inc.) or its trademarks may not be used +* to endorse or promote products derived from this file without specific +* prior written permission from Derivative. +*/ + +#pragma once + +#include +#include +#include + +#include "TOP_CPlusPlusBase.h" + +class FrameQueue +{ +public: + + FrameQueue(); + ~FrameQueue(); + + // This will fill the class with buffers that can be updated. It should + // be called every frame to ensure the buffers this class have is in + // sync with what the TOP_OutputFormatSpecs is providing as output buffers. + void sync(TOP_OutputFormatSpecs *output); + + // Call this to get a buffer to fill with new buffer data. + // You MUST call either updateComplete() or updateCancelled() when done with the buffer. + // This may return nullptr if there is no buffer available for update. + // width and height will be filled in with the width/height of the buffer + void* getBufferForUpdate(int *width, int *height); + + // Call this to tell the class that the data from the last getBufferForUpdate() + // is ready to be used by the TOP + void updateComplete(); + + // Call this to tell the class that the data from the last getBufferForUpdate() + // did not get filled so it should not be queued for upload to the TOP + void updateCancelled(); + + // Call this from execute() to send a new buffer (if available) to the TOP to output. + void sendBufferForUpload(TOP_OutputFormatSpecs *output); + + +private: + + std::mutex myLock; + std::mutex myUpdateBufferLock; + std::deque myUnusedBuffers; + std::deque myUpdatedBuffers; + + int myWidth; + int myHeight; + + void* myUpdateBuffer; +}; diff --git a/streaming-pointcloud/examples/td/top-plugin/GL_Extensions.h b/streaming-pointcloud/examples/td/top-plugin/GL_Extensions.h new file mode 100644 index 00000000..4cd44cfc --- /dev/null +++ b/streaming-pointcloud/examples/td/top-plugin/GL_Extensions.h @@ -0,0 +1,3 @@ +// Stub file for simpler CPU Memory TOP usage than an OpenGLTOP + +#include diff --git a/streaming-pointcloud/examples/td/top-plugin/Info.plist b/streaming-pointcloud/examples/td/top-plugin/Info.plist new file mode 100644 index 00000000..de15cb28 --- /dev/null +++ b/streaming-pointcloud/examples/td/top-plugin/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSHumanReadableCopyright + Copyright © 2016 Derivative. All rights reserved. + NSPrincipalClass + + + diff --git a/streaming-pointcloud/examples/td/top-plugin/MQTTClient.cpp b/streaming-pointcloud/examples/td/top-plugin/MQTTClient.cpp new file mode 100644 index 00000000..4770e292 --- /dev/null +++ b/streaming-pointcloud/examples/td/top-plugin/MQTTClient.cpp @@ -0,0 +1,342 @@ +// async_subscribe.cpp +// +// This is a Paho MQTT C++ client, sample application. +// +// This application is an MQTT subscriber using the C++ asynchronous client +// interface, employing callbacks to receive messages and status updates. +// +// The sample demonstrates: +// - Connecting to an MQTT server/broker. +// - Subscribing to a topic +// - Receiving messages through the callback API +// - Receiving network disconnect updates and attempting manual reconnects. +// - Using a "clean session" and manually re-subscribing to topics on +// reconnect. +// + +/******************************************************************************* + * Copyright (c) 2013-2017 Frank Pagliughi + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Frank Pagliughi - initial implementation and documentation + *******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include "mqtt/async_client.h" + +const int QOS = 0; + +///////////////////////////////////////////////////////////////////////////// + +// Callbacks for the success or failures of requested actions. +// This could be used to initiate further action, but here we just log the +// results to the console. + +class action_listener : public virtual mqtt::iaction_listener +{ + std::string name_; + + void on_failure(const mqtt::token& tok) override { + std::cout << name_ << " failure"; + if (tok.get_message_id() != 0) + std::cout << " for token: [" << tok.get_message_id() << "]" << std::endl; + std::cout << std::endl; + } + + void on_success(const mqtt::token& tok) override { + std::cout << name_ << " success"; + if (tok.get_message_id() != 0) + std::cout << " for token: [" << tok.get_message_id() << "]" << std::endl; + auto top = tok.get_topics(); + if (top && !top->empty()) + std::cout << "\ttoken topic: '" << (*top)[0] << "', ..." << std::endl; + std::cout << std::endl; + } + +public: + action_listener(const std::string& name) : name_(name) {} +}; + +///////////////////////////////////////////////////////////////////////////// + +/** + * Local callback & listener class for use with the client connection. + * This is primarily intended to receive messages, but it will also monitor + * the connection to the broker. If the connection is lost, it will attempt + * to restore the connection and re-subscribe to the topic. + */ +class callback : public virtual mqtt::callback, + public virtual mqtt::iaction_listener + +{ + // Counter for the number of connection retries + int nretry_; + std::chrono::time_point< std::chrono::steady_clock> lasttrytime; + + // The MQTT client + mqtt::async_client& cli_; + // Options to use if we need to reconnect + mqtt::connect_options& connOpts_; + // An action listener to display the result of actions. + action_listener subListener_; + + // This deomonstrates manually reconnecting to the broker by calling + // connect() again. This is a possibility for an application that keeps + // a copy of it's original connect_options, or if the app wants to + // reconnect with different options. + // Another way this can be done manually, if using the same options, is + // to just call the async_client::reconnect() method. + void reconnect() { + auto now= std::chrono::steady_clock::now(); + if (std::chrono::duration_cast(now - lasttrytime).count() > 2500) { + lasttrytime = now; + try { + bool connected = cli_.connect(connOpts_, nullptr, *this)->try_wait(); + } + catch (const mqtt::exception & exc) { + std::cerr << "Error: " << exc.what() << std::endl; + exit(1); + } + } + } + + // Re-connection failure + void on_failure(const mqtt::token& tok) override { + std::cout << "Connection attempt failed" << std::endl; + nretry_++; + reconnect(); + } + + // (Re)connection success + // Either this or connected() can be used for callbacks. + void on_success(const mqtt::token& tok) override {} + + // (Re)connection success + void connected(const std::string& cause) override { + std::cout << "\nConnection success" << std::endl; + std::cout << "\nSubscribing to topic '" << topic << std::endl; + + lasttrytime = std::chrono::steady_clock::now(); + + cli_.subscribe(topic, QOS, nullptr, subListener_); + cli_.start_consuming(); + } + + // Callback for when the connection is lost. + // This will initiate the attempt to manually reconnect. + void connection_lost(const std::string& cause) override { + std::cout << "\nConnection lost" << std::endl; + if (!cause.empty()) + std::cout << "\tcause: " << cause << std::endl; + + std::cout << "Reconnecting..." << std::endl; + nretry_ = 0; + reconnect(); + } + + // Callback for when a message arrives. + void message_arrived(mqtt::const_message_ptr msg) override { } + + void delivery_complete(mqtt::delivery_token_ptr token) override {} + +public: + callback(mqtt::async_client& cli, mqtt::connect_options& connOpts) + : nretry_(0), cli_(cli), connOpts_(connOpts), subListener_("Subscription") {} + + std::string topic = "frames"; +}; + +///////////////////////////////////////////////////////////////////////////// + + +//Buffer to receive "raw" mqtt data into +struct TextureData { + + uint64_t timestamp; + uint32_t pointcount; + bool hasColor; + + //position data + std::vector* depth_data; + + //rgb data + std::vector* color_data; + +}; + +//Wrap mqtt client and provide ability to parse mqtt packet +class MQTTClient { + + mqtt::async_client* client; + mqtt::connect_options* connOpts; + callback* cb; + int messagecount = 0; + + +public: + MQTTClient() { + MQTTAsync_nameValue* v = MQTTAsync_getVersionInfo(); + std::cout << v[0].value << " v:" << v[1].value << std::endl; + + //we start out wit nothing + client = NULL; + cb = NULL; + connOpts = NULL; + } + + ~MQTTClient() { + + } + + void Connect(const std::string& url, const std::string& clientid, const std::string& topic) { + if (client != NULL ){ + if (client->is_connected()) { + Disconnect(); + } + } + + //async client plumbing + connOpts = new mqtt::connect_options(); + connOpts->set_keep_alive_interval(5); + connOpts->set_clean_session(true); + connOpts->set_connect_timeout(5); + + client = new mqtt::async_client(url, clientid); + + cb = new callback(*client, *connOpts); + cb->topic = topic; + client->set_callback(*cb); + + // Start the connection. + // When completed, "callback" will subscribe to topic. + + try { + std::cout << "Connecting to the MQTT server..." << std::flush; + mqtt::token_ptr t = client->connect(*connOpts, nullptr, *cb); + } + catch (const mqtt::exception & exc) { + std::cerr << "\nERROR: Unable to connect to MQTT server: '" + << url << "' error:" << exc.what() << std::endl; + } + } + + void Disconnect() { + if (client != NULL) { + + //tear it down + if (client->is_connected()) { + client->disconnect()->wait(); + } + + delete cb; + delete client; + delete connOpts; + + client = NULL; + cb = NULL; + connOpts = NULL; + } + } + + //copy mqtt payload into a struct that is passed in, returns the pointcount + //clears out the struct if it has points from previous frames + int GetData( TextureData& data) + { + if (client == NULL) { + return -1; + } + + if (!this->client->is_connected()) + { + return -1; + } + + //try and get a package from the mqtt queue + mqtt::const_message_ptr ptr; + auto messageConsumed = this->client->try_consume_message(&ptr); + if (messageConsumed) { + + //work with the payload + mqtt::binary payload = ptr->get_payload(); + + //get timestamp + int header = 0; + memcpy(&data.timestamp, &payload[0], sizeof(uint64_t)); + header += sizeof(uint64_t); + + //get point count + uint32_t headerPointCount; + memcpy(&headerPointCount, &payload[header], sizeof(uint32_t)); + header += 4; + + //does the packet have depth and color + memcpy(&data.hasColor, &payload[header], sizeof(bool)); + header += 1; + + uint32_t payloadPointCount = (payload.size() - header) / 9; + //clear our buffers if we have less points + if (payloadPointCount < data.pointcount) { + std::fill(data.depth_data->begin(), data.depth_data->end(), 0); + std::fill(data.color_data->begin(), data.color_data->end(), 0); + } + + //payload count trumps the count in the header, just in case the header value is wrong + if (payloadPointCount != headerPointCount) { + headerPointCount = payloadPointCount; + } + + //play it safe, don't go larger than what fits in TD texture + if (headerPointCount > data.depth_data->size() / 3) { + headerPointCount = data.depth_data->size() / 3; + } + data.pointcount = headerPointCount; + + //copy over depth data + int positionssize = sizeof(int16_t) * ((__int64)data.pointcount* 3); + memcpy(data.depth_data->data(), &payload[header], positionssize); + + //if color is included, copy this too + if (data.hasColor) { + int colorsize = sizeof(uint8_t) * ((__int64)data.pointcount * 3); + int depthEnd = sizeof(int16_t)* ((__int64)payloadPointCount * 3); + memcpy(data.color_data->data(), &payload[(__int64)header + (__int64)depthEnd], colorsize); + } + + //clean up + ptr.reset(); + + //we need to clear out the queue to prevent a memory leak. + //we don't have a way to know the current queue size. + //so we only process the first message (oldest) above and clear the rest out below + //the chances that we will create a queue in runtime is small as touch runs faster than the network + int queuesize = 0; + while (this->client->try_consume_message(&ptr)) { + queuesize++; + ptr.reset(); + } + + return data.pointcount; + } + else { + ptr.reset(); + + return 0; + } + } + +}; \ No newline at end of file diff --git a/streaming-pointcloud/examples/td/top-plugin/MqttToTex.cpp b/streaming-pointcloud/examples/td/top-plugin/MqttToTex.cpp new file mode 100644 index 00000000..b46d379b --- /dev/null +++ b/streaming-pointcloud/examples/td/top-plugin/MqttToTex.cpp @@ -0,0 +1,502 @@ +/* Shared Use License: This file is owned by Derivative Inc. (Derivative) +* and can only be used, and/or modified for use, in conjunction with +* Derivative's TouchDesigner software, and only if you are a licensee who has +* accepted Derivative's TouchDesigner license or assignment agreement +* (which also govern the use of this file). You may share or redistribute +* a modified version of this file provided the following conditions are met: +* +* 1. The shared file or redistribution must retain the information set out +* above and this list of conditions. +* 2. Derivative's name (Derivative Inc.) or its trademarks may not be used +* to endorse or promote products derived from this file without specific +* prior written permission from Derivative. +*/ + +#include "MqttToTex.h" + +#include +#include +#include +#include +#include +#include + + +// These functions are basic C function, which the DLL loader can find +// much easier than finding a C++ Class. +// The DLLEXPORT prefix is needed so the compile exports these functions from the .dll +// you are creating +extern "C" +{ + + DLLEXPORT + void + FillTOPPluginInfo(TOP_PluginInfo* info) + { + // This must always be set to this constant + info->apiVersion = TOPCPlusPlusAPIVersion; + + // Change this to change the executeMode behavior of this plugin. + info->executeMode = TOP_ExecuteMode::CPUMemWriteOnly; + + // The opType is the unique name for this TOP. It must start with a + // capital A-Z character, and all the following characters must lower case + // or numbers (a-z, 0-9) + info->customOPInfo.opType->setString("Mqtt2tex"); + + // The opLabel is the text that will show up in the OP Create Dialog + info->customOPInfo.opLabel->setString("MQTT to TEX from Azure Kinect"); + + // Will be turned into a 3 letter icon on the nodes + info->customOPInfo.opIcon->setString("MQT"); + + // Information about the author of this OP + info->customOPInfo.authorName->setString("Thomas Wester"); + info->customOPInfo.authorEmail->setString("thomas@glowbox.io"); + + // This TOP works with 0 or 1 inputs connected + info->customOPInfo.minInputs = 0; + info->customOPInfo.maxInputs = 0; + } + + DLLEXPORT + TOP_CPlusPlusBase* + CreateTOPInstance(const OP_NodeInfo* info, TOP_Context* context) + { + // Return a new instance of your class every time this is called. + // It will be called once per TOP that is using the .dll + return new MqttToTex(info); + } + + DLLEXPORT + void + DestroyTOPInstance(TOP_CPlusPlusBase* instance, TOP_Context* context) + { + // Delete the instance here, this will be called when + // Touch is shutting down, when the TOP using that instance is deleted, or + // if the TOP loads a different DLL + delete (MqttToTex*)instance; + } + +}; + +MqttToTex::MqttToTex(const OP_NodeInfo* info) : + myNodeInfo(info) +{ + myExecuteCount = 0; + reconnect = false; + + textureMemoryLocation = 0; + databuffer.pointcount = -1; + + mqttClient = std::make_unique(); +} + +MqttToTex::~MqttToTex() +{ + mqttClient->Disconnect(); + mqttClient.release(); +} + +void +MqttToTex::getGeneralInfo(TOP_GeneralInfo* ginfo, const OP_Inputs* inputs, void* reserved1) +{ + // Set our pixel type here - important for different use cases, all pixel specification follows pixel type format + ginfo->cookEveryFrame = true; + ginfo->memPixelType = OP_CPUMemPixelType::RGBA32Float; + ginfo->clearBuffers = false; + +} + +bool +MqttToTex::getOutputFormat(TOP_OutputFormat* format, const OP_Inputs* inputs, void* reserved1) +{ + int32_t w; + int32_t h; + inputs->getParInt2("Resolution", w, h); + + if (w != outputWidth || h != outputHeight) { + outputWidth = w; + outputHeight = h; + size_t size = (w * h / 2) * 3; + + + if (myExecuteCount == 0) { + databuffer.color_data = new std::vector(size * 3, 0); + databuffer.depth_data = new std::vector(size * 3, 0); + } + else { + databuffer.depth_data->resize(size, 0); + databuffer.color_data->resize(size, 0); + } + } + + // Assign variable values to 'format' to specify the pixel format/resolution etc that we want to output + format->width = outputWidth; + format->height = outputHeight; + format->bitsPerChannel = 32; + + format->floatPrecision = true; + + // Return true to tell the TOP to use the settings specified + return true; +} + + +void +MqttToTex::execute(TOP_OutputFormatSpecs* output, + const OP_Inputs* inputs, + TOP_Context* context, + void* reserved1) +{ + + //check for reset pulse, often to reconnect to a different ip + if (reconnect || myExecuteCount == 0) { + std::cout << "Reset received..." << std::endl; + inputs->getParInt2("Resolution", outputWidth, outputHeight); + + //first time excute is count we initialze the buffer to receive mqtt data in + int size = (outputWidth * outputHeight) / 2; + + if (myExecuteCount == 0) { + databuffer.color_data = new std::vector(size * 3, 0); + databuffer.depth_data = new std::vector(size * 3, 0); + } + + databuffer.pointcount = 0; + databuffer.timestamp = 0; + myPointCount = 0; + + reconnect = false; + + const char* broker_in = inputs->getParString("Broker"); + broker.assign(broker_in); + + const char* client_in = inputs->getParString("Client"); + client.assign(client_in); + + const char* topic_in = inputs->getParString("Topic"); + topic.assign(topic_in); + + this->mqttClient->Connect(broker, client, topic); + } + + //read the color fill paramter + inputs->getParDouble4("Fill", this->fillR, this->fillG, this->fillB, this->fillA); + + //get a texture to write to + float* mem = (float*)output->cpuPixelData[textureMemoryLocation]; + + //get the latest mqtt data + if (mqttClient->GetData(databuffer) > 0) { + myPointCount = databuffer.pointcount; + + //fill the texture we got from TD + fillBuffer(mem, outputWidth, outputHeight); + + //let TD know there is a new texture + output->newCPUPixelDataLocation = textureMemoryLocation; + + textureMemoryLocation++; + if (textureMemoryLocation > 2) { + textureMemoryLocation = 0; + } + } + + myExecuteCount++; +} + +//fill mem with buffer from mqtt +void +MqttToTex::fillBuffer(float* mem, int width, int height) +{ + //clear td texturedata + memset(&mem[0], 0, width * height * 4 * sizeof(float_t)); + + //we use 1 texture of which the top half is color and the both half is depth + + //pointer for depth data + float* pospixel = &mem[0]; + + //pointer for color data + int colorstart = (width * (height / 2)) * 4; + float* colorpixel = &mem[colorstart]; + + uint32_t positiondataoffset = 0; + uint32_t colordatabyteoffset = 0; + + uint32_t maxPoints = databuffer.pointcount > (width * height) / 2 ? (width * height) / 2 : databuffer.pointcount; + + //populate the texture buffer + for (uint32_t i = 0; i < maxPoints; i++) + { + //mqtt data comes in as uint values, translate back to meters + pospixel[0] = databuffer.depth_data->at(positiondataoffset) * 0.001f; + pospixel[1] = databuffer.depth_data->at(positiondataoffset + 1) * 0.001f; + pospixel[2] = databuffer.depth_data->at(positiondataoffset + 2) * 0.001f; + pospixel[3] = 1; + + positiondataoffset += 3; + pospixel += 4; + + //fill in color if we are getting color, otherwise use the fill + if (this->databuffer.hasColor) { + colorpixel[0] = (databuffer.color_data->at(colordatabyteoffset) / 255.0f); + colorpixel[1] = (databuffer.color_data->at(colordatabyteoffset + 1) / 255.0f); + colorpixel[2] = (databuffer.color_data->at(colordatabyteoffset + 2) / 255.0f); + colorpixel[3] = 1; + } + else + { + //some form of memcpy / block copy might be fractionally faster + colorpixel[0] = this->fillR; + colorpixel[1] = this->fillG; + colorpixel[2] = this->fillB; + colorpixel[3] = this->fillA; + } + + colordatabyteoffset += 3; + colorpixel += 4; + } +} + +int32_t +MqttToTex::getNumInfoCHOPChans(void* reserved1) +{ + // We return the number of channel we want to output to any Info CHOP + // connected to the TOP. In this example we are just going to send one channel. + return 2; +} + +void +MqttToTex::getInfoCHOPChan(int32_t index, OP_InfoCHOPChan* chan, void* reserved1) +{ + // This function will be called once for each channel we said we'd want to return + // In this example it'll only be called once. + + if (index == 0) + { + chan->name->setString("executeCount"); + chan->value = (float)myExecuteCount; + } + + if (index == 1) + { + chan->name->setString("pointCount"); + chan->value = (float)myPointCount; + } + +} + +bool +MqttToTex::getInfoDATSize(OP_InfoDATSize* infoSize, void* reserved1) +{ + infoSize->rows = 5; + infoSize->cols = 2; + // Setting this to false means we'll be assigning values to the table + // one row at a time. True means we'll do it one column at a time. + infoSize->byColumn = false; + return true; +} + +void +MqttToTex::getInfoDATEntries(int32_t index, + int32_t nEntries, + OP_InfoDATEntries* entries, + void* reserved1) +{ + char tempBuffer[4096]; + + if (index == 0) + { + // Set the value for the first column +#ifdef _WIN32 + strcpy_s(tempBuffer, "executeCount"); +#else // macOS + strlcpy(tempBuffer, "executeCount", sizeof(tempBuffer)); +#endif + entries->values[0]->setString(tempBuffer); + + // Set the value for the second column +#ifdef _WIN32 + sprintf_s(tempBuffer, "%d", myExecuteCount); +#else // macOS + snprintf(tempBuffer, sizeof(tempBuffer), "%d", myExecuteCount); +#endif + entries->values[1]->setString(tempBuffer); + } + + if (index == 1) + { + // Set the value for the first column +#ifdef _WIN32 + strcpy_s(tempBuffer, "pointCount"); +#else // macOS + strlcpy(tempBuffer, "pointCount", sizeof(tempBuffer)); +#endif + entries->values[0]->setString(tempBuffer); + + // Set the value for the second column +#ifdef _WIN32 + sprintf_s(tempBuffer, "%d", myPointCount); +#else // macOS + snprintf(tempBuffer, sizeof(tempBuffer), "%d", myExecuteCount); +#endif + entries->values[1]->setString(tempBuffer); + } + + if (index == 2) + { + // Set the value for the first column +#ifdef _WIN32 + strcpy_s(tempBuffer, "broker"); +#else // macOS + strlcpy(tempBuffer, "broker", sizeof(tempBuffer)); +#endif + entries->values[0]->setString(tempBuffer); + + // Set the value for the second column +#ifdef _WIN32 + strcpy_s(tempBuffer, broker.c_str()); +#else // macOS + strlcpy(tempBuffer, "broker", sizeof(tempBuffer)); +#endif + entries->values[1]->setString(tempBuffer); + } + + if (index == 3) + { + // Set the value for the first column +#ifdef _WIN32 + strcpy_s(tempBuffer, "client"); +#else // macOS + strlcpy(tempBuffer, "client", sizeof(tempBuffer)); +#endif + entries->values[0]->setString(tempBuffer); + + // Set the value for the second column +#ifdef _WIN32 + strcpy_s(tempBuffer, client.c_str()); +#else // macOS + strlcpy(tempBuffer, "client", sizeof(tempBuffer)); +#endif + entries->values[1]->setString(tempBuffer); + } + + if (index == 4) + { + // Set the value for the first column +#ifdef _WIN32 + strcpy_s(tempBuffer, "topic"); +#else // macOS + strlcpy(tempBuffer, "topic", sizeof(tempBuffer)); +#endif + entries->values[0]->setString(tempBuffer); + + // Set the value for the second column +#ifdef _WIN32 + strcpy_s(tempBuffer, topic.c_str()); +#else // macOS + strlcpy(tempBuffer, "topic", sizeof(tempBuffer)); +#endif + entries->values[1]->setString(tempBuffer); + } + +} + +void +MqttToTex::setupParameters(OP_ParameterManager* manager, void* reserved1) +{ + + // pulse + { + OP_NumericParameter np; + + np.name = "Reset"; + np.label = "(Re)Connect"; + + OP_ParAppendResult res = manager->appendPulse(np); + assert(res == OP_ParAppendResult::Success); + } + + //broker + { + OP_StringParameter sp; + + sp.name = "Broker"; + sp.label = "Broker"; + sp.defaultValue = this->broker.data(); + OP_ParAppendResult res = manager->appendString(sp); + assert(res == OP_ParAppendResult::Success); + } + + //client + { + OP_StringParameter sp; + + sp.name = "Client"; + sp.label = "Client"; + + sp.defaultValue = this->client.data(); + + OP_ParAppendResult res = manager->appendString(sp); + assert(res == OP_ParAppendResult::Success); + } + + //topic + { + OP_StringParameter sp; + + sp.name = "Topic"; + sp.label = "Topic"; + + sp.defaultValue = this->topic.data(); + + OP_ParAppendResult res = manager->appendString(sp); + assert(res == OP_ParAppendResult::Success); + } + + //color + { + OP_NumericParameter np; + + np.name = "Fill"; + np.label = "Color Fill"; + + np.defaultValues[0] = 0.0f; + np.defaultValues[1] = 0.0f; + np.defaultValues[2] = 0.0f; + np.defaultValues[3] = 1.0f; + + OP_ParAppendResult res = manager->appendRGBA(np); + assert(res == OP_ParAppendResult::Success); + } + + //width + { + OP_NumericParameter np; + np.name = "Resolution"; + np.label = "Texture Resolution"; + + np.defaultValues[0] = 1024; + np.defaultValues[1] = 1024; + + + OP_ParAppendResult res = manager->appendXY(np); + assert(res == OP_ParAppendResult::Success); + + } + + //height +} + + +void +MqttToTex::pulsePressed(const char* name, void* reserved1) +{ + if (!strcmp(name, "Reset")) + { + reconnect = true; + } +} + diff --git a/streaming-pointcloud/examples/td/top-plugin/MqttToTex.h b/streaming-pointcloud/examples/td/top-plugin/MqttToTex.h new file mode 100644 index 00000000..8e8b7edd --- /dev/null +++ b/streaming-pointcloud/examples/td/top-plugin/MqttToTex.h @@ -0,0 +1,87 @@ +/* Shared Use License: This file is owned by Derivative Inc. (Derivative) +* and can only be used, and/or modified for use, in conjunction with +* Derivative's TouchDesigner software, and only if you are a licensee who has +* accepted Derivative's TouchDesigner license or assignment agreement +* (which also govern the use of this file). You may share or redistribute +* a modified version of this file provided the following conditions are met: +* +* 1. The shared file or redistribution must retain the information set out +* above and this list of conditions. +* 2. Derivative's name (Derivative Inc.) or its trademarks may not be used +* to endorse or promote products derived from this file without specific +* prior written permission from Derivative. +*/ + +#include "TOP_CPlusPlusBase.h" +#include "FrameQueue.h" +#include +#include +#include "MQTTClient.cpp" + +class MqttToTex : public TOP_CPlusPlusBase +{ +public: + MqttToTex(const OP_NodeInfo *info); + virtual ~MqttToTex(); + + virtual void getGeneralInfo(TOP_GeneralInfo *, const OP_Inputs*, void*) override; + virtual bool getOutputFormat(TOP_OutputFormat*, const OP_Inputs*, void*) override; + + + virtual void execute(TOP_OutputFormatSpecs*, + const OP_Inputs*, + TOP_Context* context, + void* reserved1) override; + + virtual void fillBuffer(float * mem, int width, int height); + + virtual int32_t getNumInfoCHOPChans(void *reserved1) override; + virtual void getInfoCHOPChan(int32_t index, + OP_InfoCHOPChan *chan, void* reserved1) override; + + virtual bool getInfoDATSize(OP_InfoDATSize *infoSize, void *reserved1) override; + virtual void getInfoDATEntries(int32_t index, + int32_t nEntries, + OP_InfoDATEntries *entries, + void *reserved1) override; + + virtual void setupParameters(OP_ParameterManager *manager, void *reserved1) override; + virtual void pulsePressed(const char *name, void *reserved1) override; + +private: + + // We don't need to store this pointer, but we do for the example. + // The OP_NodeInfo class store information about the node that's using + // this instance of the class (like its name). + const OP_NodeInfo* myNodeInfo; + + // In this example this value will be incremented each time the execute() + // function is called, then passes back to the TOP + int myExecuteCount; + int myPointCount; + + std::unique_ptr mqttClient; + + //mqtt broker ip address and port in this format: tcp://127.0.0.1:1883 + std::string broker; + //mqtt client id + std::string client; + //mqtt topic + std::string topic; + + //color fil; + double fillR; + double fillG; + double fillB; + double fillA; + + int32_t outputWidth; + int32_t outputHeight; + + //TD pulse + bool reconnect; + + //buffer to receive mqtt data in + TextureData databuffer; + int textureMemoryLocation; +}; diff --git a/streaming-pointcloud/examples/td/top-plugin/MqttToTex.sln b/streaming-pointcloud/examples/td/top-plugin/MqttToTex.sln new file mode 100644 index 00000000..838a579d --- /dev/null +++ b/streaming-pointcloud/examples/td/top-plugin/MqttToTex.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.960 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MqttToTex", "MqttToTex.vcxproj", "{35DC6386-39BD-4D59-B767-BB8ADC3096C1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {35DC6386-39BD-4D59-B767-BB8ADC3096C1}.Debug|x64.ActiveCfg = Debug|x64 + {35DC6386-39BD-4D59-B767-BB8ADC3096C1}.Debug|x64.Build.0 = Debug|x64 + {35DC6386-39BD-4D59-B767-BB8ADC3096C1}.Release|x64.ActiveCfg = Release|x64 + {35DC6386-39BD-4D59-B767-BB8ADC3096C1}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A4A127DF-5427-4DF9-9A8D-EAC07775043D} + EndGlobalSection +EndGlobal diff --git a/streaming-pointcloud/examples/td/top-plugin/MqttToTex.vcxproj b/streaming-pointcloud/examples/td/top-plugin/MqttToTex.vcxproj new file mode 100644 index 00000000..d35a5f98 --- /dev/null +++ b/streaming-pointcloud/examples/td/top-plugin/MqttToTex.vcxproj @@ -0,0 +1,121 @@ + + + + + Debug + x64 + + + Release + x64 + + + + {35DC6386-39BD-4D59-B767-BB8ADC3096C1} + CPUMemoryTOP + Win32Proj + 10.0 + MqttToTex + x86-windows-static-md + x64-windows-static-md + + + + DynamicLibrary + NotSet + v142 + + + DynamicLibrary + NotSet + v142 + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir) + + + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir) + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + $(ProjectDir) + + + + + OpenGL32.lib;ws2_32.lib;%(AdditionalDependencies) + true + Windows + + + + + WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + $(ProjectDir) + + + + + OpenGL32.lib;ws2_32.lib;%(AdditionalDependencies) + true + Windows + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/streaming-pointcloud/examples/td/top-plugin/TOP_CPlusPlusBase.h b/streaming-pointcloud/examples/td/top-plugin/TOP_CPlusPlusBase.h new file mode 100644 index 00000000..34241da5 --- /dev/null +++ b/streaming-pointcloud/examples/td/top-plugin/TOP_CPlusPlusBase.h @@ -0,0 +1,639 @@ +/* Shared Use License: This file is owned by Derivative Inc. (Derivative) +* and can only be used, and/or modified for use, in conjunction with +* Derivative's TouchDesigner software, and only if you are a licensee who has +* accepted Derivative's TouchDesigner license or assignment agreement +* (which also govern the use of this file). You may share or redistribute +* a modified version of this file provided the following conditions are met: +* +* 1. The shared file or redistribution must retain the information set out +* above and this list of conditions. +* 2. Derivative's name (Derivative Inc.) or its trademarks may not be used +* to endorse or promote products derived from this file without specific +* prior written permission from Derivative. +*/ + +/* + * Produced by: + * + * Derivative Inc + * 401 Richmond Street West, Unit 386 + * Toronto, Ontario + * Canada M5V 3A8 + * 416-591-3555 + * + * NAME: TOP_CPlusPlusBase.h + * + */ + +/******* + Do not edit this file directly! + Make a subclass of TOP_CPlusPlusBase instead, and add your own data/function + + Derivative Developers:: Make sure the virtual function order + stays the same, otherwise changes won't be backwards compatible +********/ + + +#ifndef __TOP_CPlusPlusBase__ +#define __TOP_CPlusPlusBase__ + +#include "assert.h" +#include "CPlusPlus_Common.h" + +class TOP_CPlusPlusBase; +class TOP_Context; + +#ifndef _WIN32 + #ifdef __OBJC__ + @class NSOpenGLContext; + #else + class NSOpenGLContext; + #endif +#endif + + +enum class TOP_ExecuteMode : int32_t +{ + // Rendering is done using OpenGL into a FBO/RenderBuffers + // that is provided for you. + OpenGL_FBO = 0, + + + // *NOTE* - Do not use OpenGL calls when using a CPUMem*/CUDA executeMode. + + + // CPU memory is filled with data directly. No OpenGL calls can be + // made when using this mode. Doing so will likely result in + // rendering issues within TD. + + // cpuPixelData[0] and cpupixelData[1] are width by height array of pixels. + // to access pixel (x,y) you would need to offset the memory location by bytesperpixel * ( y * width + x). + // all pixels should be set, pixels that was not set will have an undefined value. + + // "CPUMemWriteOnly" - cpuPixelData* will be provided that you fill in with pixel data. This will automatically be uploaded to the GPU as a texture for you. Reading from the memory will result in very poor performance. + CPUMemWriteOnly, + + // "CPUmemReadWrite - same as CPU_MEM_WRITEONLY but reading from the memory won't result in a large performance pentalty. The initial contents of the memory is undefined still. + CPUMemReadWrite, + + // Using CUDA. Textures will be given using cudaArray*, registered with + // cudaGraphicsRegisterFlagsSurfaceLoadStore flag set. The output + // texture will be written using a provided cudaArray* as well + CUDA, +}; + +// Define for the current API version that this sample code is made for. +// To upgrade to a newer version, replace the files +// TOP_CPlusPlusBase.h +// CPlusPlus_Common.h +// from the samples folder in a newer TouchDesigner installation. +// You may need to upgrade your plugin code in that case, to match +// the new API requirements +const int TOPCPlusPlusAPIVersion = 10; + +struct TOP_PluginInfo +{ +public: + // Must be set to TOPCPlusPlusAPIVersion in FillTOPPluginInfo + int32_t apiVersion = 0; + + // Set this to control the execution mode for this plugin + // See the documention for TOP_ExecuteMode for more information + TOP_ExecuteMode executeMode = TOP_ExecuteMode::OpenGL_FBO; + +private: + int32_t reserved[100]; + +public: + // Information used to describe this plugin as a custom OP. + OP_CustomOPInfo customOPInfo; + +private: + int32_t reserved2[20]; + +}; + +// These are the definitions for the C-functions that are used to +// load the library and create instances of the object you define +typedef void (__cdecl *FILLTOPPLUGININFO)(TOP_PluginInfo* info); +typedef TOP_CPlusPlusBase* (__cdecl *CREATETOPINSTANCE)(const OP_NodeInfo*, + TOP_Context*); +typedef void (__cdecl *DESTROYTOPINSTANCE)(TOP_CPlusPlusBase*, TOP_Context*); + +// These classes are used to pass data to/from the functions you will define + + + +// TouchDesigner will select the best pixel format based on the options you give +// Not all possible combinations of channels/bit depth are possible, +// so you get the best choice supported by your card + +class TOP_OutputFormat +{ +public: + int32_t width; + int32_t height; + + + // The aspect ratio of the TOP's output + + float aspectX; + float aspectY; + + + // The anti-alias level. + // 1 means no anti-alaising + // 2 means '2x', etc., up to 32 right now + // Only used when executeMode == TOP_ExecuteMode::OpenGL_FBO + + int32_t antiAlias; + + + // Set true if you want this channel, false otherwise + // The channel may still be present if the combination you select + // isn't supported by the card (blue only for example) + + bool redChannel; + bool greenChannel; + bool blueChannel; + bool alphaChannel; + + + // The number of bits per channel. + // TouchDesigner will select the closest supported number of bits based on + // your cards capabilities + + int32_t bitsPerChannel; + + // Set to true if you want a floating point format. + // Some bit precisions don't support floating point (8-bit for example) + // while others require it (32-bit) + + bool floatPrecision; + + + // If you want to use multiple render targets, you can set this + // greater than one + // Only used when executeMode == TOP_ExecuteMode::OpenGL_FBO + + int32_t numColorBuffers; + + + // The number of bits in the depth buffer. + // 0 for no depth buffer + // Only used when executeMode == TOP_ExecuteMode::OpenGL_FBO + + int32_t depthBits; + + + // The number of bits in the stencil buffer + // 0 for no stencil buffer, if this is > 0 then + // it will also cause a depth buffer to be created + // even if you have depthBits == 0 + // Only used when executeMode == TOP_ExecuteMode::OpenGL_FBO + + int32_t stencilBits; + + int32_t reserved[20]; +}; + +const int NumCPUPixelDatas = 3; + +// This class will tell you the actual output format +// that was chosen. +class TOP_OutputFormatSpecs +{ +public: + const int32_t width; + const int32_t height; + const float aspectX; + const float aspectY; + + const int32_t antiAlias; + + const int32_t redBits; + const int32_t blueBits; + const int32_t greenBits; + const int32_t alphaBits; + const bool floatPrecision; + + /*** BEGIN: TOP_ExcuteMode::OpenGL_FBO and CUDA executeMode specific ***/ + const int32_t numColorBuffers; + + const int32_t depthBits; + const int32_t stencilBits; + + + // The OpenGL internal format of the output texture. E.g GL_RGBA8, GL_RGBA32F + const GLint pixelFormat; + /*** END: TOP_ExecuteMode::OpenGL_FBO and CUDA executeMode specific ***/ + + + + + /*** BEGIN: CPU_MEM_* executeMode specific ***/ + + // if the 'executeMode' is set to CPU_MEM_* + // then cpuPixelData will point to three blocks of memory of size + // width * height * bytesPerPixel + // and one may be uploaded as a texture after the execute call. + // All of these pointers will stay valid until the next execute() call + // unless you set newCPUPixelDataLocation to 0, 1 or 2. In that case + // the location you specified will become invalid as soon as execute() + // returns. The pointers for the locations you don't specify stays + // valid though. + // This means you can hold onto these pointers by default and use them + // after execute() returns, such as filling them in another thread. + void* const cpuPixelData[NumCPUPixelDatas]; + + // setting this to 0 will upload memory from cpuPixelData[0], + // setting this to 1 will upload memory from cpuPixelData[1] + // setting this to 2 will upload memory from cpuPixelData[2] + // uploading from a memory location will invalidate it and a new memory location will be provided next execute call. + // setting this to -1 will not upload any memory and retain previously uploaded texture + // setting this to any other value will result in an error being displayed in the CPlusPlus TOP. + // defaults to -1 + int32_t newCPUPixelDataLocation; + + /*** END: CPU_MEM_* executeMode specific ***/ + + + + /*** BEGIN: New TOP_ExecuteMode::OpenGL_FBO execudeMode specific data ***/ + + // The first color can either be a GL_TEXTURE_2D or a GL_RENDERBUFFER + // depending on the settings. This will be set to either + // GL_TEXTURE_2D or GL_RENDERBUFFER accordingly + const GLenum colorBuffer0Type; + + // The indices for the renderBuffers for the color buffers that are attached to the FBO, except for possibly index 0 (see colorBuffer0Type) + // these are all GL_RENDERBUFFER GL objects, or 0 if not present + const GLuint colorBufferRB[32]; + + // The renderBuffer for the depth buffer that is attached to the FBO + // This is always a GL_RENDERBUFFER GL object + const GLuint depthBufferRB; + + /*** END: TOP_ExecuteMode::OpenGL_FBO executeMode specific ***/ + + /*** BEGIN: TOP_ExecuteMode::CUDA specific ***/ + // Write to this CUDA memory to fill the output textures + cudaArray* const cudaOutput[32]; + + /*** END: TOP_ExecuteMode::CUDA specific ***/ + const int32_t reserved[10]; +}; + + +class TOP_GeneralInfo +{ +public: + // Set this to true if you want the TOP to cook every frame, even + // if none of it's inputs/parameters are changing + + bool cookEveryFrame; + + + // TouchDesigner will clear the color/depth buffers before calling + // execute(), as an optimization you can disable this, if you know + // you'll be overwriting all the data or calling clear yourself + + bool clearBuffers; + + + // Set this to true if you want TouchDesigner to create mipmaps for all the + // TOPs that are passed into execute() function + + bool mipmapAllTOPs; + + // Set this to true if you want the CHOP to cook every frame, if asked + // (someone uses it's output) + // This is different from 'cookEveryFrame', which causes the node to cook + // every frame no matter what + + bool cookEveryFrameIfAsked; + + // When setting the output texture size using the node's common page + // if using 'Input' or 'Half' options for example, it uses the first input + // by default. You can use a different input by assigning a value + // to inputSizeIndex. + + int32_t inputSizeIndex; + + // Unused by current API Version, but remains for backwards compatibility + int32_t reservedForLegacy1; + + // determines the datatype of each pixel in CPU memory. This will determin + // the size of the CPU memory buffers that are given to you + // in TOP_OutputFormatSpecs + // "BGRA8Fixed" - each pixel will hold 4 fixed-point values of size 8 bits (use 'unsigned char' in the code). They will be ordered BGRA. This is the preferred ordering for better performance. + // "RGBA8Fixed" - each pixel will hold 4 fixed-point values of size 8 bits (use 'unsigned char' in the code). They will be ordered RGBA + // "RGBA32Float" - each pixel will hold 4 floating-point values of size 32 bits (use 'float' in the code). They will be ordered RGBA + // + // Other cases are listed in the CPUMemPixelType enumeration + OP_CPUMemPixelType memPixelType; + + int32_t reserved[18]; +}; + + +// This class is passed into the Create and Destroy methods as well +// as into execute() +// You should use it to signify when you want to do GL work and when you are +// done to avoid GL state conflicts with TouchDesigner's GL context. +class TOP_Context +{ +public: + virtual ~TOP_Context() {} + + /*** BEGIN: New TOP_ExecuteMode::OpenGL_FBO execudeMode specific functions ***/ + + // This function will make a GL context that is unique to this + // TOP active. Call this before issuing any GL commands. + // During execute() it will also bind a FBO to the GL_DRAW_FRAMEBUFFER + // target and attach textures/renderbuffers to the attachment points + // as required. It will also call glDrawBuffersARB() with the correct + // active draw buffers depending on the number of color buffers in use + // All other GL state will be left as it was from the previous time + // execute() was called for this TOP. + // + // NOTE: No functions on the OP_Inputs class should be called + // between a beginGLCommands() and endGLCommands() block, as they + // may require GL to complete properly due to node cooking + virtual void beginGLCommands() = 0; + + // Call this when you are done issuing GL commands and need to do other + virtual void endGLCommands() = 0; + + // Returns the index of the FBO that TouchDesigner has setup for you. + // Only valid during execute(), between beginGLCommands() and endGLCommands() + // calls. + virtual GLuint getFBOIndex() = 0; + + /*** END: New TOP_ExecuteMode::OpenGL_FBO execudeMode specific functions ***/ + +#ifdef _WIN32 + // This will return the device context used to create rendering contexts + // for this instance of TouchDesigner. In the case where GPU affinity + // is being used, using this to create extra contexts will ensure those + // contexts are affine to the correct GPU. + // If not null, pixelFormatOut will be filled with the pixel format + // index used for the DC. + virtual HDC getDC(int *pixelFormatOut) const = 0; + + // This will return the context that should be used if you are going to setup + // sharing between a context you are creating and the contexts TouchDesigner + // is using. + virtual HGLRC getShareRenderContext() const = 0; +#else + + // This will return the context that should be used if you are going to setup + // sharing between a context you are creating and the contexts TouchDesigner + // is using. + virtual NSOpenGLContext* getShareRenderContext() const = 0; +#endif +}; + + +/***** FUNCTION CALL ORDER DURING INITIALIZATION ******/ +/* + When the TOP loads the dll the functions will be called in this order + + setupParameters(OP_ParameterManager* m); + +*/ + + +/***** FUNCTION CALL ORDER DURING A COOK ******/ +/* + When the TOP cooks the functions will be called in this order + + getGeneralInfo() + getOutputFormat() + + execute() + getNumInfoCHOPChans() + for the number of chans returned getNumInfoCHOPChans() + { + getInfoCHOPChan() + } + getInfoDATSize() + for the number of rows/cols returned by getInfoDATSize() + { + getInfoDATEntries() + } + getWarningString() + getErrorString() + getInfoPopupString() + +*/ + + +/*** DO NOT EDIT THIS CLASS, MAKE A SUBCLASS OF IT INSTEAD ***/ +class TOP_CPlusPlusBase +{ +protected: + TOP_CPlusPlusBase() + { + } + + +public: + + virtual ~TOP_CPlusPlusBase() + { + } + + // BEGIN PUBLIC INTERFACE + + // Some general settings can be assigned here by setting memebers of + // the TOP_GeneralInfo class that is passed in + virtual void + getGeneralInfo(TOP_GeneralInfo*, const OP_Inputs*, void *reserved1) + { + } + + + // This function is called so the class can tell the TOP what + // kind of buffer it wants to output into. + // TouchDesigner will try to find the best match based on the specifications + // given. + // Return true if you specify the output here + // Return false if you want the output to be set by the TOP's parameters + // The TOP_OutputFormat class is pre-filled with what the TOP would + // output if you return false, so you can just tweak a few settings + // and return true if you want + virtual bool + getOutputFormat(TOP_OutputFormat*, const OP_Inputs*, void* reserved1) + { + return false; + } + + // In this function you do whatever you want to fill the framebuffer + // + // See the OP_Inputs class definition for more details on it's + // contents + + virtual void execute(TOP_OutputFormatSpecs*, + const OP_Inputs* , + TOP_Context* context, + void* reserved1) = 0; + + + // Override these methods if you want to output values to the Info CHOP/DAT + // returning 0 means you dont plan to output any Info CHOP channels + + virtual int32_t + getNumInfoCHOPChans(void* reserved1) + { + return 0; + } + + // Specify the name and value for Info CHOP channel 'index', + // by assigning something to 'name' and 'value' members of the + // OP_InfoCHOPChan class pointer that is passed in. + virtual void + getInfoCHOPChan(int32_t index, OP_InfoCHOPChan* chan, + void* reserved1) + { + } + + + // Return false if you arn't returning data for an Info DAT + // Return true if you are. + // Fill in members of the OP_InfoDATSize class to specify the size + virtual bool + getInfoDATSize(OP_InfoDATSize* infoSize, void* reserved1) + { + return false; + } + + // You are asked to assign values to the Info DAT 1 row or column at a time + // The 'byColumn' variable in 'getInfoDATSize' is how you specify + // if it is by column or by row. + // 'index' is the row/column index + // 'nEntries' is the number of entries in the row/column + // Strings should be UTF-8 encoded. + virtual void + getInfoDATEntries(int32_t index, int32_t nEntries, + OP_InfoDATEntries* entries, + void *reserved1) + { + } + + // You can use this function to put the node into a warning state + // with the returned string as the message. + virtual void + getWarningString(OP_String *warning, void *reserved1) + { + } + + // You can use this function to put the node into a error state + // with the returned string as the message. + virtual void + getErrorString(OP_String *error, void *reserved1) + { + } + + // Use this function to return some text that will show up in the + // info popup (when you middle click on a node) + virtual void + getInfoPopupString(OP_String *info, void *reserved1) + { + } + + + + // Override these methods if you want to define specfic parameters + virtual void + setupParameters(OP_ParameterManager* manager, void* reserved1) + { + } + + + // This is called whenever a pulse parameter is pressed + virtual void + pulsePressed(const char* name, void* reserved1) + { + } + + + // END PUBLIC INTERFACE + + + + // Reserved for future features + virtual int32_t reservedFunc6() { return 0; } + virtual int32_t reservedFunc7() { return 0; } + virtual int32_t reservedFunc8() { return 0; } + virtual int32_t reservedFunc9() { return 0; } + virtual int32_t reservedFunc10() { return 0; } + virtual int32_t reservedFunc11() { return 0; } + virtual int32_t reservedFunc12() { return 0; } + virtual int32_t reservedFunc13() { return 0; } + virtual int32_t reservedFunc14() { return 0; } + virtual int32_t reservedFunc15() { return 0; } + virtual int32_t reservedFunc16() { return 0; } + virtual int32_t reservedFunc17() { return 0; } + virtual int32_t reservedFunc18() { return 0; } + virtual int32_t reservedFunc19() { return 0; } + virtual int32_t reservedFunc20() { return 0; } + + int32_t reserved[400]; + +}; + +static_assert(offsetof(TOP_PluginInfo, apiVersion) == 0, "Incorrect Alignment"); +static_assert(offsetof(TOP_PluginInfo, executeMode) == 4, "Incorrect Alignment"); +static_assert(offsetof(TOP_PluginInfo, customOPInfo) == 408, "Incorrect Alignment"); +static_assert(sizeof(TOP_PluginInfo) == 944, "Incorrect Size"); + +static_assert(offsetof(TOP_OutputFormatSpecs, width) == 0, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormatSpecs, height) == 4, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormatSpecs, aspectX) == 8, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormatSpecs, aspectY) == 12, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormatSpecs, antiAlias) == 16, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormatSpecs, redBits) == 20, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormatSpecs, blueBits) == 24, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormatSpecs, greenBits) == 28, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormatSpecs, alphaBits) == 32, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormatSpecs, floatPrecision) == 36, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormatSpecs, numColorBuffers) == 40, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormatSpecs, depthBits) == 44, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormatSpecs, stencilBits) == 48, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormatSpecs, pixelFormat) == 52, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormatSpecs, cpuPixelData) == 56, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormatSpecs, newCPUPixelDataLocation) == 80, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormatSpecs, colorBuffer0Type) == 84, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormatSpecs, colorBufferRB) == 88, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormatSpecs, depthBufferRB) == 216, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormatSpecs, cudaOutput) == 224, "Incorrect Aligment"); +static_assert(sizeof(TOP_OutputFormatSpecs) == 520, "Incorrect Size"); + +static_assert(offsetof(TOP_GeneralInfo, cookEveryFrame) == 0, "Incorrect Aligment"); +static_assert(offsetof(TOP_GeneralInfo, clearBuffers) == 1, "Incorrect Aligment"); +static_assert(offsetof(TOP_GeneralInfo, mipmapAllTOPs) == 2, "Incorrect Aligment"); +static_assert(offsetof(TOP_GeneralInfo, cookEveryFrameIfAsked) == 3, "Incorrect Aligment"); +static_assert(offsetof(TOP_GeneralInfo, inputSizeIndex) == 4, "Incorrect Aligment"); +static_assert(offsetof(TOP_GeneralInfo, reservedForLegacy1) == 8, "Incorrect Aligment"); +static_assert(offsetof(TOP_GeneralInfo, memPixelType) == 12, "Incorrect Aligment"); +static_assert(sizeof(TOP_GeneralInfo) == 88, "Incorrect Aligment"); + + +static_assert(offsetof(TOP_OutputFormat, width) == 0, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormat, height) == 4, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormat, aspectX) == 8, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormat, aspectY) == 12, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormat, antiAlias) == 16, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormat, redChannel) == 20, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormat, greenChannel) == 21, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormat, blueChannel) == 22, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormat, alphaChannel) == 23, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormat, bitsPerChannel) == 24, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormat, floatPrecision) == 28, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormat, numColorBuffers) == 32, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormat, depthBits) == 36, "Incorrect Aligment"); +static_assert(offsetof(TOP_OutputFormat, stencilBits) == 40, "Incorrect Aligment"); +static_assert(sizeof(TOP_OutputFormat) == 124, "Incorrect Size"); + +#endif diff --git a/streaming-pointcloud/examples/td/top-plugin/cpp.hint b/streaming-pointcloud/examples/td/top-plugin/cpp.hint new file mode 100644 index 00000000..cca1bfa0 --- /dev/null +++ b/streaming-pointcloud/examples/td/top-plugin/cpp.hint @@ -0,0 +1,8 @@ +// Hint files help the Visual Studio IDE interpret Visual C++ identifiers +// such as names of functions and macros. +// For more information see https://go.microsoft.com/fwlink/?linkid=865984 +#define DLLEXPORT __declspec (dllexport) +// Hint files help the Visual Studio IDE interpret Visual C++ identifiers +// such as names of functions and macros. +// For more information see https://go.microsoft.com/fwlink/?linkid=865984 +#define DLLEXPORT __declspec (dllexport) diff --git a/streaming-pointcloud/examples/td/top-plugin/resource.h b/streaming-pointcloud/examples/td/top-plugin/resource.h new file mode 100644 index 00000000..0de7e577 --- /dev/null +++ b/streaming-pointcloud/examples/td/top-plugin/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by MqttToTex.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/streaming-pointcloud/examples/td/top-plugin/version.h b/streaming-pointcloud/examples/td/top-plugin/version.h new file mode 100644 index 00000000..85ce4fa5 --- /dev/null +++ b/streaming-pointcloud/examples/td/top-plugin/version.h @@ -0,0 +1,31 @@ +#define STRINGIZE2(s) #s +#define STRINGIZE(s) STRINGIZE2(s) + +#define VERSION_MAJOR 1 +#define VERSION_MINOR 0 +#define VERSION_REVISION 0 +#define VERSION_BUILD 15 + +#define VER_FILE_DESCRIPTION_STR "MQTT to TEX from Azure Kinect" +#define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD +#define VER_FILE_VERSION_STR STRINGIZE(VERSION_MAJOR) \ + "." STRINGIZE(VERSION_MINOR) \ + "." STRINGIZE(VERSION_REVISION) \ + "." STRINGIZE(VERSION_BUILD) \ + +#define VER_PRODUCTNAME_STR "MqttToTex" +#define VER_PRODUCT_VERSION VER_FILE_VERSION +#define VER_PRODUCT_VERSION_STR VER_FILE_VERSION_STR +#define VER_ORIGINAL_FILENAME_STR VER_PRODUCTNAME_STR ".dll" +#define VER_INTERNAL_NAME_STR VER_ORIGINAL_FILENAME_STR +#define VER_COPYRIGHT_STR "" + +#ifdef _DEBUG +#define VER_VER_DEBUG VS_FF_DEBUG +#else +#define VER_VER_DEBUG 0 +#endif + +#define VER_FILEOS VOS_NT_WINDOWS32 +#define VER_FILEFLAGS VER_VER_DEBUG +#define VER_FILETYPE VFT_DLL diff --git a/streaming-pointcloud/examples/td/top-plugin/version.rc b/streaming-pointcloud/examples/td/top-plugin/version.rc new file mode 100644 index 00000000..cd65dabd Binary files /dev/null and b/streaming-pointcloud/examples/td/top-plugin/version.rc differ diff --git a/streaming-pointcloud/examples/td/top-plugin/x64-windows-static-md.cmake b/streaming-pointcloud/examples/td/top-plugin/x64-windows-static-md.cmake new file mode 100644 index 00000000..eaa8c3b8 --- /dev/null +++ b/streaming-pointcloud/examples/td/top-plugin/x64-windows-static-md.cmake @@ -0,0 +1,3 @@ +set(VCPKG_TARGET_ARCHITECTURE x64) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE static) \ No newline at end of file diff --git a/streaming-pointcloud/examples/threejs/.gitignore b/streaming-pointcloud/examples/threejs/.gitignore new file mode 100644 index 00000000..3c3629e6 --- /dev/null +++ b/streaming-pointcloud/examples/threejs/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/streaming-pointcloud/examples/threejs/README.md b/streaming-pointcloud/examples/threejs/README.md new file mode 100644 index 00000000..188ecf46 --- /dev/null +++ b/streaming-pointcloud/examples/threejs/README.md @@ -0,0 +1,31 @@ +# THREE.js Visualizer + +![Webgl Screenshot](./webgl-screenshot.jpg) + +This is an example of consuming live point cloud frames for use with THREE.js. When run in a web browser, this example will receive point cloud frames and will update a THREE.BufferGeometry to be rendered via the THREE.PointsMaterial and THREE.Points object. + +In order to receive frames in the browser, an intermediary server is needed to translate the MQTT messages into websocket messages. If you use an MQTT broker with built-in websocket support you will not need to translate between MQTT and websockets. + + +## Prerequisites + +* The Kinect Capture and Merger applications +* An MQTT broker such as [Mosquitto](https://mosquitto.org) +* [Node.js](https://nodejs.org/) + + +## Installation + +1. Configure and run the Kinect Capture and Merger apps with at least one camera attached +1. Run `npm install` to install the required node modules + + +## Running the Example + +1. Run `node app.js` to start the local webserver with socket.io +1. Open `http://localhost:5500` in a webGL capable browser + + +## Configuration + +The node.js application will read `config.json` at startup to load the HTTP server and MQTT broker configuration. diff --git a/streaming-pointcloud/examples/threejs/app.js b/streaming-pointcloud/examples/threejs/app.js new file mode 100644 index 00000000..56eb426e --- /dev/null +++ b/streaming-pointcloud/examples/threejs/app.js @@ -0,0 +1,32 @@ +const config = require("./config.json"); +const mqtt = require("mqtt"); +const express = require("express"); +const socketio = require("socket.io"); + +// Start up the HTTP and websocket server + +const app = express(); + +app.use('/', express.static(__dirname + "/public")); + +const server = app.listen(config.http_server.port, "0.0.0.0", function() { + console.log("HTTP server running on port: ", server.address().port); +}); + +const io = socketio(server); + +// Connect to the MQTT broker and subscribe to the topic for point cloud frames. + +const mqttClient = mqtt.connect(config.mqtt); + +mqttClient.on("connect", function () { + console.log("Connected to MQTT broker."); + mqttClient.subscribe(config.points_topic); +}); + +mqttClient.on("message", function(topic, payload){ + // Forward point frames on as websocket messages. + if(topic == config.points_topic) { + io.emit("points", payload); + } +}); diff --git a/streaming-pointcloud/examples/threejs/config.json b/streaming-pointcloud/examples/threejs/config.json new file mode 100644 index 00000000..29da507c --- /dev/null +++ b/streaming-pointcloud/examples/threejs/config.json @@ -0,0 +1,12 @@ +{ + "mqtt" : { + "host" : "localhost", + "port" : 1883 + }, + + "http_server" : { + "port" : 8000 + }, + + "points_topic" : "points/pointmerger" +} \ No newline at end of file diff --git a/streaming-pointcloud/examples/threejs/package-lock.json b/streaming-pointcloud/examples/threejs/package-lock.json new file mode 100644 index 00000000..9de18f14 --- /dev/null +++ b/streaming-pointcloud/examples/threejs/package-lock.json @@ -0,0 +1,1294 @@ +{ + "name": "threejs-viewer", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + }, + "base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "requires": { + "callsite": "1.0.0" + } + }, + "bl": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "requires": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "callback-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/callback-stream/-/callback-stream-1.1.0.tgz", + "integrity": "sha1-RwGlEmbwbgbqpx/BcjOCLYdfSQg=", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "> 1.0.0 < 3.0.0" + } + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" + }, + "commist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/commist/-/commist-1.1.0.tgz", + "integrity": "sha512-rraC8NXWOEjhADbZe9QBNzLAN5Q3fsTPQtBV+fEVj6xKIgDgNiEVE6ZNfHpZOqfQ21YUzfVNUXLOEZquYvQPPg==", + "requires": { + "leven": "^2.1.0", + "minimist": "^1.1.0" + } + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "engine.io": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.4.0.tgz", + "integrity": "sha512-XCyYVWzcHnK5cMz7G4VTu2W7zJS7SM1QkcelghyIk/FmobWBtXE7fwhBusEKvCSqc3bMh8fNFMlUkCKTFRxH2w==", + "requires": { + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "0.3.1", + "debug": "~4.1.0", + "engine.io-parser": "~2.2.0", + "ws": "^7.1.2" + }, + "dependencies": { + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "engine.io-client": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.0.tgz", + "integrity": "sha512-a4J5QO2k99CM2a0b12IznnyQndoEvtA4UAldhGzKqnHf42I3Qs2W5SPnDvatZRcMaNZs4IevVicBPayxYt6FwA==", + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~4.1.0", + "engine.io-parser": "~2.2.0", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~6.1.0", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "ws": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz", + "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==", + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.0.tgz", + "integrity": "sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w==", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, + "es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", + "requires": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-set": "~0.1.5", + "es6-symbol": "~3.1.1", + "event-emitter": "~0.3.5" + } + }, + "es6-set": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", + "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", + "requires": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-symbol": "3.1.1", + "event-emitter": "~0.3.5" + }, + "dependencies": { + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + } + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "requires": { + "type": "^2.0.0" + }, + "dependencies": { + "type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", + "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==" + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "glob-stream": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", + "requires": { + "extend": "^3.0.0", + "glob": "^7.1.1", + "glob-parent": "^3.1.0", + "is-negated-glob": "^1.0.0", + "ordered-read-streams": "^1.0.0", + "pumpify": "^1.3.5", + "readable-stream": "^2.1.5", + "remove-trailing-separator": "^1.0.1", + "to-absolute-glob": "^2.0.0", + "unique-stream": "^2.0.2" + } + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "requires": { + "isarray": "2.0.1" + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "help-me": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-1.1.0.tgz", + "integrity": "sha1-jy1QjQYAtKRW2i8IZVbn5cBWo8Y=", + "requires": { + "callback-stream": "^1.0.2", + "glob-stream": "^6.1.0", + "through2": "^2.0.1", + "xtend": "^4.0.0" + } + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", + "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==" + }, + "is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "requires": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "requires": { + "is-extglob": "^2.1.0" + } + }, + "is-negated-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=" + }, + "is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "requires": { + "is-unc-path": "^1.0.0" + } + }, + "is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "requires": { + "unc-path-regex": "^0.1.2" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + }, + "leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" + }, + "mime-types": { + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", + "requires": { + "mime-db": "1.43.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "mqtt": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-3.0.0.tgz", + "integrity": "sha512-0nKV6MAc1ibKZwaZQUTb3iIdT4NVpj541BsYrqrGBcQdQ7Jd0MnZD1/6/nj1UFdGTboK9ZEUXvkCu2nPCugHFA==", + "requires": { + "base64-js": "^1.3.0", + "commist": "^1.0.0", + "concat-stream": "^1.6.2", + "end-of-stream": "^1.4.1", + "es6-map": "^0.1.5", + "help-me": "^1.0.1", + "inherits": "^2.0.3", + "minimist": "^1.2.0", + "mqtt-packet": "^6.0.0", + "pump": "^3.0.0", + "readable-stream": "^2.3.6", + "reinterval": "^1.1.0", + "split2": "^3.1.0", + "websocket-stream": "^5.1.2", + "xtend": "^4.0.1" + } + }, + "mqtt-packet": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-6.3.0.tgz", + "integrity": "sha512-TjusSKu8uFZCmGZU8K6r4C3Ic+er/4r8rva+Mp5GQgWg/KjSdAfLK/GTucBwkdATE2Z0Da8AssI2WHzs0M9W0w==", + "requires": { + "bl": "^1.2.2", + "inherits": "^2.0.3", + "process-nextick-args": "^2.0.0", + "safe-buffer": "^5.1.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "ordered-read-streams": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", + "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", + "requires": { + "readable-stream": "^2.0.1" + } + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "proxy-addr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", + "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.0" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + } + } + }, + "reinterval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz", + "integrity": "sha1-M2Hs+jymwYKDOA3Qu5VG85D17Oc=" + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "socket.io": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.3.0.tgz", + "integrity": "sha512-2A892lrj0GcgR/9Qk81EaY2gYhCBxurV0PfmmESO6p27QPrUK1J3zdns+5QPqvUYK2q657nSj0guoIil9+7eFg==", + "requires": { + "debug": "~4.1.0", + "engine.io": "~3.4.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.3.0", + "socket.io-parser": "~3.4.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "socket.io-adapter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz", + "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==" + }, + "socket.io-client": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.3.0.tgz", + "integrity": "sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==", + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~4.1.0", + "engine.io-client": "~3.4.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.3.0", + "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "socket.io-parser": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz", + "integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==", + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + } + } + }, + "socket.io-parser": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.0.tgz", + "integrity": "sha512-/G/VOI+3DBp0+DJKW4KesGnQkQPFmUCbA/oO2QGT6CWxU7hLGWqU3tyuzeSK/dqcyeHsQg1vTe9jiZI8GU9SCQ==", + "requires": { + "component-emitter": "1.2.1", + "debug": "~4.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "split2": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.1.1.tgz", + "integrity": "sha512-emNzr1s7ruq4N+1993yht631/JH+jaj0NYBosuKmLcq+JkGQ9MmTw1RB1fGaTCzUuseRIClrlSLHRNYGwWQ58Q==", + "requires": { + "readable-stream": "^3.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "through2-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", + "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", + "requires": { + "through2": "~2.0.0", + "xtend": "~4.0.0" + } + }, + "to-absolute-glob": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", + "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", + "requires": { + "is-absolute": "^1.0.0", + "is-negated-glob": "^1.0.0" + } + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, + "unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" + }, + "unique-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", + "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", + "requires": { + "json-stable-stringify-without-jsonify": "^1.0.1", + "through2-filter": "^3.0.0" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "websocket-stream": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/websocket-stream/-/websocket-stream-5.5.0.tgz", + "integrity": "sha512-EXy/zXb9kNHI07TIMz1oIUIrPZxQRA8aeJ5XYg5ihV8K4kD1DuA+FY6R96HfdIHzlSzS8HiISAfrm+vVQkZBug==", + "requires": { + "duplexify": "^3.5.1", + "inherits": "^2.0.1", + "readable-stream": "^2.3.3", + "safe-buffer": "^5.1.2", + "ws": "^3.2.0", + "xtend": "^4.0.0" + }, + "dependencies": { + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "ws": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.1.tgz", + "integrity": "sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A==" + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + } + } +} diff --git a/streaming-pointcloud/examples/threejs/package.json b/streaming-pointcloud/examples/threejs/package.json new file mode 100644 index 00000000..65f295de --- /dev/null +++ b/streaming-pointcloud/examples/threejs/package.json @@ -0,0 +1,11 @@ +{ + "name": "threejs-viewer", + "version": "1.0.0", + "description": "Consuming and displaying Azure Kinect point cloud frames using THREE.js", + "main": "app.js", + "dependencies": { + "express": "^4.17.1", + "mqtt": "^3.0.0", + "socket.io": "^2.3.0" + } +} diff --git a/streaming-pointcloud/examples/threejs/public/index.html b/streaming-pointcloud/examples/threejs/public/index.html new file mode 100644 index 00000000..ece8622c --- /dev/null +++ b/streaming-pointcloud/examples/threejs/public/index.html @@ -0,0 +1,45 @@ + + + + THREE.js Azure Kinect Streaming Example + + + + +
Waiting for data..
+ + + + + + + + + + \ No newline at end of file diff --git a/streaming-pointcloud/examples/threejs/public/three.min.js b/streaming-pointcloud/examples/threejs/public/three.min.js new file mode 100644 index 00000000..4f37bc9d --- /dev/null +++ b/streaming-pointcloud/examples/threejs/public/three.min.js @@ -0,0 +1,1036 @@ +// threejs.org/license +(function(h,Fa){"object"===typeof exports&&"undefined"!==typeof module?Fa(exports):"function"===typeof define&&define.amd?define(["exports"],Fa):(h=h||self,Fa(h.THREE={}))})(this,function(h){function Fa(){}function w(a,b){this.x=a||0;this.y=b||0}function za(){this.elements=[1,0,0,0,1,0,0,0,1];0k)return!1}return!0}function qb(a,b){this.center=void 0!==a?a:new n;this.radius=void 0!==b?b:0}function Wb(a,b){this.origin=void 0!==a?a:new n;this.direction=void 0!==b?b:new n(0,0,-1)}function Ua(a,b){this.normal=void 0!==a?a:new n(1, +0,0);this.constant=void 0!==b?b:0}function oa(a,b,c){this.a=void 0!==a?a:new n;this.b=void 0!==b?b:new n;this.c=void 0!==c?c:new n}function B(a,b,c){return void 0===b&&void 0===c?this.set(a):this.setRGB(a,b,c)}function cg(a,b,c){0>c&&(c+=1);1c?b:c<2/3?a+6*(b-a)*(2/3-c):a}function dg(a){return.04045>a?.0773993808*a:Math.pow(.9478672986*a+.0521327014,2.4)}function eg(a){return.0031308>a?12.92*a:1.055*Math.pow(a,.41666)-.055}function Bc(a,b,c,d,e,f){this.a=a;this.b= +b;this.c=c;this.normal=d&&d.isVector3?d:new n;this.vertexNormals=Array.isArray(d)?d:[];this.color=e&&e.isColor?e:new B;this.vertexColors=Array.isArray(e)?e:[];this.materialIndex=void 0!==f?f:0}function K(){Object.defineProperty(this,"id",{value:rj++});this.uuid=P.generateUUID();this.name="";this.type="Material";this.fog=!0;this.blending=1;this.side=0;this.vertexTangents=this.flatShading=!1;this.vertexColors=0;this.opacity=1;this.transparent=!1;this.blendSrc=204;this.blendDst=205;this.blendEquation= +100;this.blendEquationAlpha=this.blendDstAlpha=this.blendSrcAlpha=null;this.depthFunc=3;this.depthWrite=this.depthTest=!0;this.stencilWriteMask=255;this.stencilFunc=519;this.stencilRef=0;this.stencilFuncMask=255;this.stencilZPass=this.stencilZFail=this.stencilFail=7680;this.stencilWrite=!1;this.clippingPlanes=null;this.clipShadows=this.clipIntersection=!1;this.shadowSide=null;this.colorWrite=!0;this.precision=null;this.polygonOffset=!1;this.polygonOffsetUnits=this.polygonOffsetFactor=0;this.dithering= +!1;this.alphaTest=0;this.premultipliedAlpha=!1;this.toneMapped=this.visible=!0;this.userData={};this.version=0}function Pa(a){K.call(this);this.type="MeshBasicMaterial";this.color=new B(16777215);this.lightMap=this.map=null;this.lightMapIntensity=1;this.aoMap=null;this.aoMapIntensity=1;this.envMap=this.alphaMap=this.specularMap=null;this.combine=0;this.reflectivity=1;this.refractionRatio=.98;this.wireframe=!1;this.wireframeLinewidth=1;this.wireframeLinejoin=this.wireframeLinecap="round";this.morphTargets= +this.skinning=!1;this.setValues(a)}function M(a,b,c){if(Array.isArray(a))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.name="";this.array=a;this.itemSize=b;this.count=void 0!==a?a.length/b:0;this.normalized=!0===c;this.usage=35044;this.updateRange={offset:0,count:-1};this.version=0}function Cd(a,b,c){M.call(this,new Int8Array(a),b,c)}function Dd(a,b,c){M.call(this,new Uint8Array(a),b,c)}function Ed(a,b,c){M.call(this,new Uint8ClampedArray(a),b,c)}function Fd(a, +b,c){M.call(this,new Int16Array(a),b,c)}function Xb(a,b,c){M.call(this,new Uint16Array(a),b,c)}function Gd(a,b,c){M.call(this,new Int32Array(a),b,c)}function Yb(a,b,c){M.call(this,new Uint32Array(a),b,c)}function E(a,b,c){M.call(this,new Float32Array(a),b,c)}function Hd(a,b,c){M.call(this,new Float64Array(a),b,c)}function xh(){this.vertices=[];this.normals=[];this.colors=[];this.uvs=[];this.uvs2=[];this.groups=[];this.morphTargets={};this.skinWeights=[];this.skinIndices=[];this.boundingSphere=this.boundingBox= +null;this.groupsNeedUpdate=this.uvsNeedUpdate=this.colorsNeedUpdate=this.normalsNeedUpdate=this.verticesNeedUpdate=!1}function yh(a){if(0===a.length)return-Infinity;for(var b=a[0],c=1,d=a.length;cb&&(b=a[c]);return b}function A(){Object.defineProperty(this,"id",{value:sj+=2});this.uuid=P.generateUUID();this.name="";this.type="BufferGeometry";this.index=null;this.attributes={};this.morphAttributes={};this.morphTargetsRelative=!1;this.groups=[];this.boundingSphere=this.boundingBox=null; +this.drawRange={start:0,count:Infinity};this.userData={}}function ca(a,b){D.call(this);this.type="Mesh";this.geometry=void 0!==a?a:new A;this.material=void 0!==b?b:new Pa;this.updateMorphTargets()}function zh(a,b,c,d,e,f,g,k){if(null===(1===b.side?d.intersectTriangle(g,f,e,!0,k):d.intersectTriangle(e,f,g,2!==b.side,k)))return null;Ke.copy(k);Ke.applyMatrix4(a.matrixWorld);b=c.ray.origin.distanceTo(Ke);return bc.far?null:{distance:b,point:Ke.clone(),object:a}}function Le(a,b,c,d,e,f,g,k, +l,m,x,p){Zb.fromBufferAttribute(e,m);$b.fromBufferAttribute(e,x);ac.fromBufferAttribute(e,p);e=a.morphTargetInfluences;if(b.morphTargets&&f&&e){Me.set(0,0,0);Ne.set(0,0,0);Oe.set(0,0,0);for(var q=0,t=f.length;qg;g++)a.setRenderTarget(f,g),a.clear(b,c,d);a.setRenderTarget(e)}}function Eb(a,b,c){Number.isInteger(b)&&(console.warn("THREE.WebGLCubeRenderTarget: constructor signature is now WebGLCubeRenderTarget( size, options )"),b=c);wa.call(this,a,a,b)}function bc(a,b,c,d,e,f,g,k,l,m,x,p){Z.call(this,null,f,g,k,l,m,d,e,x,p);this.image={data:a||null,width:b||1,height:c||1};this.magFilter=void 0!==l?l:1003;this.minFilter=void 0!==m?m:1003;this.flipY=this.generateMipmaps=!1;this.unpackAlignment= +1;this.needsUpdate=!0}function Hc(a,b,c,d,e,f){this.planes=[void 0!==a?a:new Ua,void 0!==b?b:new Ua,void 0!==c?c:new Ua,void 0!==d?d:new Ua,void 0!==e?e:new Ua,void 0!==f?f:new Ua]}function Ah(){function a(e,f){!1!==c&&(d(e,f),b.requestAnimationFrame(a))}var b=null,c=!1,d=null;return{start:function(){!0!==c&&null!==d&&(b.requestAnimationFrame(a),c=!0)},stop:function(){c=!1},setAnimationLoop:function(a){d=a},setContext:function(a){b=a}}}function uj(a,b){function c(b,c){var d=b.array,e=b.usage,f=a.createBuffer(); +a.bindBuffer(c,f);a.bufferData(c,d,e);b.onUploadCallback();c=5126;d instanceof Float32Array?c=5126:d instanceof Float64Array?console.warn("THREE.WebGLAttributes: Unsupported data buffer format: Float64Array."):d instanceof Uint16Array?c=5123:d instanceof Int16Array?c=5122:d instanceof Uint32Array?c=5125:d instanceof Int32Array?c=5124:d instanceof Int8Array?c=5120:d instanceof Uint8Array&&(c=5121);return{buffer:f,type:c,bytesPerElement:d.BYTES_PER_ELEMENT,version:b.version}}var d=b.isWebGL2,e=new WeakMap; +return{get:function(a){a.isInterleavedBufferAttribute&&(a=a.data);return e.get(a)},remove:function(b){b.isInterleavedBufferAttribute&&(b=b.data);var c=e.get(b);c&&(a.deleteBuffer(c.buffer),e.delete(b))},update:function(b,g){b.isInterleavedBufferAttribute&&(b=b.data);var f=e.get(b);if(void 0===f)e.set(b,c(b,g));else if(f.versionm;m++){if(p=d[m])if(l=p[0],p=p[1]){x&&e.setAttribute("morphTarget"+m,x[l]); +f&&e.setAttribute("morphNormal"+m,f[l]);c[m]=p;k+=p;continue}c[m]=0}e=e.morphTargetsRelative?1:1-k;g.getUniforms().setValue(a,"morphTargetBaseInfluence",e);g.getUniforms().setValue(a,"morphTargetInfluences",c)}}}function Fj(a,b,c,d){var e={};return{update:function(a){var f=d.render.frame,k=a.geometry,l=b.get(a,k);e[l.id]!==f&&(k.isGeometry&&l.updateFromObject(a),b.update(l),e[l.id]=f);a.isInstancedMesh&&c.update(a.instanceMatrix,34962);return l},dispose:function(){e={}}}}function rb(a,b,c,d,e,f,g, +k,l,m){a=void 0!==a?a:[];Z.call(this,a,void 0!==b?b:301,c,d,e,f,void 0!==g?g:1022,k,l,m);this.flipY=!1}function Ic(a,b,c,d){Z.call(this,null);this.image={data:a||null,width:b||1,height:c||1,depth:d||1};this.minFilter=this.magFilter=1003;this.wrapR=1001;this.flipY=this.generateMipmaps=!1;this.needsUpdate=!0}function Jc(a,b,c,d){Z.call(this,null);this.image={data:a||null,width:b||1,height:c||1,depth:d||1};this.minFilter=this.magFilter=1003;this.wrapR=1001;this.flipY=this.generateMipmaps=!1;this.needsUpdate= +!0}function Kc(a,b,c){var d=a[0];if(0>=d||0");return a.replace(kg,jg)}function Qh(a,b,c,d){a="";for(b=parseInt(b);bc;c++)b.probe.push(new n);var d=new n,e=new O,f=new O;return{setup:function(c,k,l){for(var g=0,x=0,p=0,h=0;9>h;h++)b.probe[h].set(0,0,0);var t=k=0,r=0,u=0,n=0,v=0,C= +0,W=0;l=l.matrixWorldInverse;c.sort(Dk);h=0;for(var ja=c.length;hw;w++)b.probe[w].addScaledVector(z.sh.coefficients[w],fa);else if(z.isDirectionalLight){var G=a.get(z);G.color.copy(z.color).multiplyScalar(z.intensity);G.direction.setFromMatrixPosition(z.matrixWorld);d.setFromMatrixPosition(z.target.matrixWorld); +G.direction.sub(d);G.direction.transformDirection(l);if(G.shadow=z.castShadow)fa=z.shadow,G.shadowBias=fa.bias,G.shadowRadius=fa.radius,G.shadowMapSize=fa.mapSize,b.directionalShadowMap[k]=w,b.directionalShadowMatrix[k]=z.shadow.matrix,v++;b.directional[k]=G;k++}else if(z.isSpotLight){G=a.get(z);G.position.setFromMatrixPosition(z.matrixWorld);G.position.applyMatrix4(l);G.color.copy(ra).multiplyScalar(fa);G.distance=Ga;G.direction.setFromMatrixPosition(z.matrixWorld);d.setFromMatrixPosition(z.target.matrixWorld); +G.direction.sub(d);G.direction.transformDirection(l);G.coneCos=Math.cos(z.angle);G.penumbraCos=Math.cos(z.angle*(1-z.penumbra));G.decay=z.decay;if(G.shadow=z.castShadow)fa=z.shadow,G.shadowBias=fa.bias,G.shadowRadius=fa.radius,G.shadowMapSize=fa.mapSize,b.spotShadowMap[r]=w,b.spotShadowMatrix[r]=z.shadow.matrix,W++;b.spot[r]=G;r++}else if(z.isRectAreaLight)G=a.get(z),G.color.copy(ra).multiplyScalar(fa),G.position.setFromMatrixPosition(z.matrixWorld),G.position.applyMatrix4(l),f.identity(),e.copy(z.matrixWorld), +e.premultiply(l),f.extractRotation(e),G.halfWidth.set(.5*z.width,0,0),G.halfHeight.set(0,.5*z.height,0),G.halfWidth.applyMatrix4(f),G.halfHeight.applyMatrix4(f),b.rectArea[u]=G,u++;else if(z.isPointLight){G=a.get(z);G.position.setFromMatrixPosition(z.matrixWorld);G.position.applyMatrix4(l);G.color.copy(z.color).multiplyScalar(z.intensity);G.distance=z.distance;G.decay=z.decay;if(G.shadow=z.castShadow)fa=z.shadow,G.shadowBias=fa.bias,G.shadowRadius=fa.radius,G.shadowMapSize=fa.mapSize,G.shadowCameraNear= +fa.camera.near,G.shadowCameraFar=fa.camera.far,b.pointShadowMap[t]=w,b.pointShadowMatrix[t]=z.shadow.matrix,C++;b.point[t]=G;t++}else z.isHemisphereLight&&(G=a.get(z),G.direction.setFromMatrixPosition(z.matrixWorld),G.direction.transformDirection(l),G.direction.normalize(),G.skyColor.copy(z.color).multiplyScalar(fa),G.groundColor.copy(z.groundColor).multiplyScalar(fa),b.hemi[n]=G,n++)}b.ambient[0]=g;b.ambient[1]=x;b.ambient[2]=p;c=b.hash;if(c.directionalLength!==k||c.pointLength!==t||c.spotLength!== +r||c.rectAreaLength!==u||c.hemiLength!==n||c.numDirectionalShadows!==v||c.numPointShadows!==C||c.numSpotShadows!==W)b.directional.length=k,b.spot.length=r,b.rectArea.length=u,b.point.length=t,b.hemi.length=n,b.directionalShadowMap.length=v,b.pointShadowMap.length=C,b.spotShadowMap.length=W,b.directionalShadowMatrix.length=v,b.pointShadowMatrix.length=C,b.spotShadowMatrix.length=W,c.directionalLength=k,c.pointLength=t,c.spotLength=r,c.rectAreaLength=u,c.hemiLength=n,c.numDirectionalShadows=v,c.numPointShadows= +C,c.numSpotShadows=W,b.version=Fk++},state:b}}function Vh(){var a=new Ek,b=[],c=[];return{init:function(){b.length=0;c.length=0},state:{lightsArray:b,shadowsArray:c,lights:a},setupLights:function(d){a.setup(b,c,d)},pushLight:function(a){b.push(a)},pushShadow:function(a){c.push(a)}}}function Gk(){function a(c){c=c.target;c.removeEventListener("dispose",a);b.delete(c)}var b=new WeakMap;return{get:function(c,d){if(!1===b.has(c)){var e=new Vh;b.set(c,new WeakMap);b.get(c).set(d,e);c.addEventListener("dispose", +a)}else!1===b.get(c).has(d)?(e=new Vh,b.get(c).set(d,e)):e=b.get(c).get(d);return e},dispose:function(){b=new WeakMap}}}function Gb(a){K.call(this);this.type="MeshDepthMaterial";this.depthPacking=3200;this.morphTargets=this.skinning=!1;this.displacementMap=this.alphaMap=this.map=null;this.displacementScale=1;this.displacementBias=0;this.wireframe=!1;this.wireframeLinewidth=1;this.fog=!1;this.setValues(a)}function Hb(a){K.call(this);this.type="MeshDistanceMaterial";this.referencePosition=new n;this.nearDistance= +1;this.farDistance=1E3;this.morphTargets=this.skinning=!1;this.displacementMap=this.alphaMap=this.map=null;this.displacementScale=1;this.displacementBias=0;this.fog=!1;this.setValues(a)}function Wh(a,b,c){function d(a,b,c){c=a<<0|b<<1|c<<2;var d=p[c];void 0===d&&(d=new Gb({depthPacking:3201,morphTargets:a,skinning:b}),p[c]=d);return d}function e(a,b,c){c=a<<0|b<<1|c<<2;var d=h[c];void 0===d&&(d=new Hb({morphTargets:a,skinning:b}),h[c]=d);return d}function f(b,c,f,g,k,l){var m=b.geometry,p=d,x=b.customDepthMaterial; +!0===f.isPointLight&&(p=e,x=b.customDistanceMaterial);void 0===x?(x=!1,!0===c.morphTargets&&(!0===m.isBufferGeometry?x=m.morphAttributes&&m.morphAttributes.position&&0\nvoid main() {\n float mean = 0.0;\n float squared_mean = 0.0;\n\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy ) / resolution ) );\n for ( float i = -1.0; i < 1.0 ; i += SAMPLE_RATE) {\n #ifdef HORIZONAL_PASS\n vec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( i, 0.0 ) * radius ) / resolution ) );\n mean += distribution.x;\n squared_mean += distribution.y * distribution.y + distribution.x * distribution.x;\n #else\n float depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, i ) * radius ) / resolution ) );\n mean += depth;\n squared_mean += depth * depth;\n #endif\n }\n mean = mean * HALF_SAMPLE_RATE;\n squared_mean = squared_mean * HALF_SAMPLE_RATE;\n float std_dev = sqrt( squared_mean - mean * mean );\n gl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) );\n}"}), +n=u.clone();n.defines.HORIZONAL_PASS=1;var v=new A;v.setAttribute("position",new M(new Float32Array([-1,-1,.5,3,-1,.5,-1,3,.5]),3));var C=new ca(v,u),W=this;this.enabled=!1;this.autoUpdate=!0;this.needsUpdate=!1;this.type=1;this.render=function(d,e,f){if(!1!==W.enabled&&(!1!==W.autoUpdate||!1!==W.needsUpdate)&&0!==d.length){var p=a.getRenderTarget(),h=a.getActiveCubeFace(),r=a.getActiveMipmapLevel(),q=a.state;q.setBlending(0);q.buffers.color.setClear(1,1,1,1);q.buffers.depth.setTest(!0);q.setScissorTest(!1); +for(var t=0,y=d.length;tc||l.y>c)console.warn("THREE.WebGLShadowMap:",v,"has shadow exceeding max texture size, reducing"),l.x>c&&(m.x=Math.floor(c/w.x),l.x=m.x*w.x,z.mapSize.x=m.x),l.y>c&&(m.y=Math.floor(c/w.y),l.y=m.y*w.y,z.mapSize.y=m.y);null!==z.map||z.isPointLightShadow||3!==this.type||(w={minFilter:1006,magFilter:1006, +format:1023},z.map=new wa(l.x,l.y,w),z.map.texture.name=v.name+".shadowMap",z.mapPass=new wa(l.x,l.y,w),z.camera.updateProjectionMatrix());null===z.map&&(w={minFilter:1003,magFilter:1003,format:1023},z.map=new wa(l.x,l.y,w),z.map.texture.name=v.name+".shadowMap",z.camera.updateProjectionMatrix());a.setRenderTarget(z.map);a.clear();w=z.getViewportCount();for(var ja=0;jad||a.height>d)e=d/Math.max(a.width,a.height);if(1>e||!0===b){if("undefined"!==typeof HTMLImageElement&&a instanceof HTMLImageElement||"undefined"!==typeof HTMLCanvasElement&&a instanceof HTMLCanvasElement||"undefined"!==typeof ImageBitmap&&a instanceof ImageBitmap)return d=b?P.floorPowerOfTwo:Math.floor,b=d(e*a.width),e=d(e*a.height),void 0=== +B&&(B=k(b,e)),c=c?k(b,e):B,c.width=b,c.height=e,c.getContext("2d").drawImage(a,0,0,b,e),console.warn("THREE.WebGLRenderer: Texture has been resized from ("+a.width+"x"+a.height+") to ("+b+"x"+e+")."),c;"data"in a&&console.warn("THREE.WebGLRenderer: Image in DataTexture is too big ("+a.width+"x"+a.height+").")}return a}function m(a){return P.isPowerOfTwo(a.width)&&P.isPowerOfTwo(a.height)}function x(a,b){return a.generateMipmaps&&b&&1003!==a.minFilter&&1006!==a.minFilter}function p(b,c,e,f){a.generateMipmap(b); +d.get(c).__maxMipLevel=Math.log(Math.max(e,f))*Math.LOG2E}function h(c,d,e){if(!1===Ha)return d;if(null!==c){if(void 0!==a[c])return a[c];console.warn("THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format '"+c+"'")}c=d;6403===d&&(5126===e&&(c=33326),5131===e&&(c=33325),5121===e&&(c=33321));6407===d&&(5126===e&&(c=34837),5131===e&&(c=34843),5121===e&&(c=32849));6408===d&&(5126===e&&(c=34836),5131===e&&(c=34842),5121===e&&(c=32856));33325===c||33326===c||34842===c||34836===c?b.get("EXT_color_buffer_float"): +(34843===c||34837===c)&&console.warn("THREE.WebGLRenderer: Floating point textures with RGB format not supported. Please use RGBA instead.");return c}function t(a){return 1003===a||1004===a||1005===a?9728:9729}function r(b){b=b.target;b.removeEventListener("dispose",r);var c=d.get(b);void 0!==c.__webglInit&&(a.deleteTexture(c.__webglTexture),d.remove(b));b.isVideoTexture&&D.delete(b);g.memory.textures--}function u(b){b=b.target;b.removeEventListener("dispose",u);var c=d.get(b),e=d.get(b.texture); +if(b){void 0!==e.__webglTexture&&a.deleteTexture(e.__webglTexture);b.depthTexture&&b.depthTexture.dispose();if(b.isWebGLCubeRenderTarget)for(e=0;6>e;e++)a.deleteFramebuffer(c.__webglFramebuffer[e]),c.__webglDepthbuffer&&a.deleteRenderbuffer(c.__webglDepthbuffer[e]);else a.deleteFramebuffer(c.__webglFramebuffer),c.__webglDepthbuffer&&a.deleteRenderbuffer(c.__webglDepthbuffer);if(b.isWebGLMultiviewRenderTarget){a.deleteTexture(c.__webglColorTexture);a.deleteTexture(c.__webglDepthStencilTexture);g.memory.textures-= +2;e=0;for(var f=c.__webglViewFramebuffers.length;eq;q++)r[q]=k||e?e?b.image[q].image:b.image[q]:l(b.image[q],!1,!0,Nd);var t=r[0],u=m(t)||Ha,n=f.convert(b.format), +y=f.convert(b.type),v=h(b.internalFormat,n,y);W(34067,b,u);if(k){for(q=0;6>q;q++){var z=r[q].mipmaps;for(k=0;kq;q++)if(e)for(c.texImage2D(34069+q,0, +v,r[q].width,r[q].height,0,n,y,r[q].data),k=0;k=G&&console.warn("THREE.WebGLTextures: Trying to use "+a+" texture units while this GPU supports only "+G);I+=1;return a};this.resetTextureUnits=function(){I=0};this.setTexture2D=n;this.setTexture2DArray=function(a,b){var e= +d.get(a);0v;v++)k.__webglFramebuffer[v]=a.createFramebuffer()}else if(k.__webglFramebuffer=a.createFramebuffer(),q)if(Ha){k.__webglMultisampledFramebuffer=a.createFramebuffer();k.__webglColorRenderbuffer=a.createRenderbuffer();a.bindRenderbuffer(36161,k.__webglColorRenderbuffer);q=f.convert(e.texture.format);var z=f.convert(e.texture.type);q=h(e.texture.internalFormat,q,z);z= +Ga(e);a.renderbufferStorageMultisample(36161,z,q,e.width,e.height);a.bindFramebuffer(36160,k.__webglMultisampledFramebuffer);a.framebufferRenderbuffer(36160,36064,36161,k.__webglColorRenderbuffer);a.bindRenderbuffer(36161,null);e.depthBuffer&&(k.__webglDepthRenderbuffer=a.createRenderbuffer(),fa(k.__webglDepthRenderbuffer,e,!0));a.bindFramebuffer(36160,null)}else console.warn("THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.");else if(t){v=e.width;var C=e.height;q=e.numViews; +a.bindFramebuffer(36160,k.__webglFramebuffer);var G=b.get("OVR_multiview2");g.memory.textures+=2;z=a.createTexture();a.bindTexture(35866,z);a.texParameteri(35866,10240,9728);a.texParameteri(35866,10241,9728);a.texImage3D(35866,0,32856,v,C,q,0,6408,5121,null);G.framebufferTextureMultiviewOVR(36160,36064,z,0,0,q);var w=a.createTexture();a.bindTexture(35866,w);a.texParameteri(35866,10240,9728);a.texParameteri(35866,10241,9728);a.texImage3D(35866,0,35056,v,C,q,0,34041,34042,null);G.framebufferTextureMultiviewOVR(36160, +33306,w,0,0,q);C=Array(q);for(v=0;vv;v++)ra(k.__webglFramebuffer[v],e,36064,34069+v);x(e.texture,y)&&p(34067,e.texture,e.width,e.height);c.bindTexture(34067,null)}else t||(c.bindTexture(3553, +l.__webglTexture),W(3553,e.texture,y),ra(k.__webglFramebuffer,e,36064,3553),x(e.texture,y)&&p(3553,e.texture,e.width,e.height),c.bindTexture(3553,null));if(e.depthBuffer){k=d.get(e);l=!0===e.isWebGLCubeRenderTarget;if(e.depthTexture){if(l)throw Error("target.depthTexture not supported in Cube render targets");if(e&&e.isWebGLCubeRenderTarget)throw Error("Depth Texture with cube render targets is not supported");a.bindFramebuffer(36160,k.__webglFramebuffer);if(!e.depthTexture||!e.depthTexture.isDepthTexture)throw Error("renderTarget.depthTexture must be an instance of THREE.DepthTexture"); +d.get(e.depthTexture).__webglTexture&&e.depthTexture.image.width===e.width&&e.depthTexture.image.height===e.height||(e.depthTexture.image.width=e.width,e.depthTexture.image.height=e.height,e.depthTexture.needsUpdate=!0);n(e.depthTexture,0);k=d.get(e.depthTexture).__webglTexture;if(1026===e.depthTexture.format)a.framebufferTexture2D(36160,36096,3553,k,0);else if(1027===e.depthTexture.format)a.framebufferTexture2D(36160,33306,3553,k,0);else throw Error("Unknown depthTexture format");}else if(l)for(k.__webglDepthbuffer= +[],l=0;6>l;l++)a.bindFramebuffer(36160,k.__webglFramebuffer[l]),k.__webglDepthbuffer[l]=a.createRenderbuffer(),fa(k.__webglDepthbuffer[l],e);else a.bindFramebuffer(36160,k.__webglFramebuffer),k.__webglDepthbuffer=a.createRenderbuffer(),fa(k.__webglDepthbuffer,e);a.bindFramebuffer(36160,null)}};this.updateRenderTargetMipmap=function(a){var b=a.texture,e=m(a)||Ha;if(x(b,e)){e=a.isWebGLCubeRenderTarget?34067:3553;var f=d.get(b).__webglTexture;c.bindTexture(e,f);p(e,b,a.width,a.height);c.bindTexture(e, +null)}};this.updateMultisampleRenderTarget=function(b){if(b.isWebGLMultisampleRenderTarget)if(Ha){var c=d.get(b);a.bindFramebuffer(36008,c.__webglMultisampledFramebuffer);a.bindFramebuffer(36009,c.__webglFramebuffer);c=b.width;var e=b.height,f=16384;b.depthBuffer&&(f|=256);b.stencilBuffer&&(f|=1024);a.blitFramebuffer(0,0,c,e,0,0,c,e,f,9728)}else console.warn("THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.")};this.safeSetTexture2D=function(a,b){a&&a.isWebGLRenderTarget&& +(!1===M&&(console.warn("THREE.WebGLTextures.safeSetTexture2D: don't use render targets as textures. Use their .texture property instead."),M=!0),a=a.texture);n(a,b)};this.safeSetTextureCube=function(a,b){a&&a.isWebGLCubeRenderTarget&&(!1===O&&(console.warn("THREE.WebGLTextures.safeSetTextureCube: don't use cube render targets as textures. Use their .texture property instead."),O=!0),a=a.texture);a&&a.isCubeTexture||Array.isArray(a.image)&&6===a.image.length?v(a,b):C(a,b)}}function Yh(a,b,c){var d= +c.isWebGL2;return{convert:function(a){if(1009===a)return 5121;if(1017===a)return 32819;if(1018===a)return 32820;if(1019===a)return 33635;if(1010===a)return 5120;if(1011===a)return 5122;if(1012===a)return 5123;if(1013===a)return 5124;if(1014===a)return 5125;if(1015===a)return 5126;if(1016===a){if(d)return 5131;var c=b.get("OES_texture_half_float");return null!==c?c.HALF_FLOAT_OES:null}if(1021===a)return 6406;if(1022===a)return 6407;if(1023===a)return 6408;if(1024===a)return 6409;if(1025===a)return 6410; +if(1026===a)return 6402;if(1027===a)return 34041;if(1028===a)return 6403;if(1029===a)return 36244;if(1030===a)return 33319;if(1031===a)return 33320;if(1032===a)return 36248;if(1033===a)return 36249;if(33776===a||33777===a||33778===a||33779===a)if(c=b.get("WEBGL_compressed_texture_s3tc"),null!==c){if(33776===a)return c.COMPRESSED_RGB_S3TC_DXT1_EXT;if(33777===a)return c.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(33778===a)return c.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(33779===a)return c.COMPRESSED_RGBA_S3TC_DXT5_EXT}else return null; +if(35840===a||35841===a||35842===a||35843===a)if(c=b.get("WEBGL_compressed_texture_pvrtc"),null!==c){if(35840===a)return c.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;if(35841===a)return c.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(35842===a)return c.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;if(35843===a)return c.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}else return null;if(36196===a)return c=b.get("WEBGL_compressed_texture_etc1"),null!==c?c.COMPRESSED_RGB_ETC1_WEBGL:null;if(37808===a||37809===a||37810===a||37811===a||37812===a||37813=== +a||37814===a||37815===a||37816===a||37817===a||37818===a||37819===a||37820===a||37821===a)return c=b.get("WEBGL_compressed_texture_astc"),null!==c?a:null;if(1020===a){if(d)return 34042;c=b.get("WEBGL_depth_texture");return null!==c?c.UNSIGNED_INT_24_8_WEBGL:null}}}}function pg(a,b,c,d){wa.call(this,a,b,d);this.stencilBuffer=this.depthBuffer=!1;this.numViews=c}function Jk(a,b){function c(a){if(a.isArrayCamera)return a.cameras;x[0]=a;return x}function d(a){if(void 0===a.isArrayCamera)return!0;a=a.cameras; +if(a.length>t)return!1;for(var b=1,c=a.length;bf.matrixWorld.determinant(),l=h(a,c,e,f);aa.setMaterial(e,k);var m=!1;if(b!==d.id||ha!==l.id||xa!==(!0===e.wireframe))b=d.id,ha=l.id,xa=!0===e.wireframe,m=!0;if(e.morphTargets||e.morphNormals)Aa.update(f,d,e,l),m=!0;a=d.index;c=d.attributes.position; +if(null===a){if(void 0===c||0===c.count)return}else if(0===a.count)return;var p=1;!0===e.wireframe&&(a=za.getWireframeAttribute(d),p=2);k=Ba;if(null!==a){var x=oa.get(a);k=Da;k.setIndex(x)}if(m){if(!1!==Ia.isWebGL2||!f.isInstancedMesh&&!d.isInstancedBufferGeometry||null!==sa.get("ANGLE_instanced_arrays")){aa.initAttributes();m=d.attributes;l=l.getAttributes();var q=e.defaultAttributeValues;for(W in l){var r=l[W];if(0<=r){var t=m[W];if(void 0!==t){var n=t.normalized,u=t.itemSize,v=oa.get(t);if(void 0!== +v){var y=v.buffer,z=v.type;v=v.bytesPerElement;if(t.isInterleavedBufferAttribute){var C=t.data,w=C.stride;t=t.offset;C&&C.isInstancedInterleavedBuffer?(aa.enableAttributeAndDivisor(r,C.meshPerAttribute),void 0===d.maxInstancedCount&&(d.maxInstancedCount=C.meshPerAttribute*C.count)):aa.enableAttribute(r);H.bindBuffer(34962,y);H.vertexAttribPointer(r,u,z,n,w*v,t*v)}else t.isInstancedBufferAttribute?(aa.enableAttributeAndDivisor(r,t.meshPerAttribute),void 0===d.maxInstancedCount&&(d.maxInstancedCount= +t.meshPerAttribute*t.count)):aa.enableAttribute(r),H.bindBuffer(34962,y),H.vertexAttribPointer(r,u,z,n,0,0)}}else if("instanceMatrix"===W)v=oa.get(f.instanceMatrix),void 0!==v&&(y=v.buffer,z=v.type,aa.enableAttributeAndDivisor(r+0,1),aa.enableAttributeAndDivisor(r+1,1),aa.enableAttributeAndDivisor(r+2,1),aa.enableAttributeAndDivisor(r+3,1),H.bindBuffer(34962,y),H.vertexAttribPointer(r+0,4,z,!1,64,0),H.vertexAttribPointer(r+1,4,z,!1,64,16),H.vertexAttribPointer(r+2,4,z,!1,64,32),H.vertexAttribPointer(r+ +3,4,z,!1,64,48));else if(void 0!==q&&(n=q[W],void 0!==n))switch(n.length){case 2:H.vertexAttrib2fv(r,n);break;case 3:H.vertexAttrib3fv(r,n);break;case 4:H.vertexAttrib4fv(r,n);break;default:H.vertexAttrib1fv(r,n)}}}aa.disableUnusedAttributes()}null!==a&&H.bindBuffer(34963,x.buffer)}var W=d.drawRange.start*p;m=null!==g?g.start*p:0;x=Math.max(W,m);g=Math.max(0,Math.min(null!==a?a.count:c.count,W+d.drawRange.count*p,m+(null!==g?g.count*p:Infinity))-1-x+1);0!==g&&(f.isMesh?!0===e.wireframe?(aa.setLineWidth(e.wireframeLinewidth* +(null===N?Q:1)),k.setMode(1)):k.setMode(4):f.isLine?(e=e.linewidth,void 0===e&&(e=1),aa.setLineWidth(e*(null===N?Q:1)),f.isLineSegments?k.setMode(1):f.isLineLoop?k.setMode(2):k.setMode(3)):f.isPoints?k.setMode(0):f.isSprite&&k.setMode(4),f.isInstancedMesh?k.renderInstances(d,x,g,f.count):d.isInstancedBufferGeometry?k.renderInstances(d,x,g,d.maxInstancedCount):k.render(x,g))};this.compile=function(a,b){G=wa.get(a,b);G.init();a.traverse(function(a){a.isLight&&(G.pushLight(a),a.castShadow&&G.pushShadow(a))}); +G.setupLights(b);var c={};a.traverse(function(b){if(b.material)if(Array.isArray(b.material))for(var d=0;de.far||f.push({distance:a,distanceToRay:Math.sqrt(k),point:c,index:b,face:null,object:g}))}function ug(a,b,c,d,e,f,g,k,l){Z.call(this,a,b,c,d,e,f,g,k,l);this.format=void 0!==g?g:1022;this.minFilter=void 0!==f?f:1006;this.magFilter=void 0!==e?e:1006;this.generateMipmaps=!1}function Qc(a,b,c,d,e,f,g,k,l,m,h,p){Z.call(this,null,f,g,k,l,m,d,e,h,p);this.image={width:b,height:c};this.mipmaps=a;this.generateMipmaps= +this.flipY=!1}function Vd(a,b,c,d,e,f,g,k,l){Z.call(this,a,b,c,d,e,f,g,k,l);this.needsUpdate=!0}function Wd(a,b,c,d,e,f,g,k,l,m){m=void 0!==m?m:1026;if(1026!==m&&1027!==m)throw Error("DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat");void 0===c&&1026===m&&(c=1012);void 0===c&&1027===m&&(c=1020);Z.call(this,null,d,e,f,g,k,m,c,l);this.image={width:a,height:b};this.magFilter=void 0!==g?g:1003;this.minFilter=void 0!==k?k:1003;this.generateMipmaps=this.flipY=!1}function Rc(a){A.call(this); +this.type="WireframeGeometry";var b=[],c,d,e,f=[0,0],g={},k=["a","b","c"];if(a&&a.isGeometry){var l=a.faces;var m=0;for(d=l.length;mc;c++){var p=h[k[c]];var q=h[k[(c+1)%3]];f[0]=Math.min(p,q);f[1]=Math.max(p,q);p=f[0]+","+f[1];void 0===g[p]&&(g[p]={index1:f[0],index2:f[1]})}}for(p in g)m=g[p],k=a.vertices[m.index1],b.push(k.x,k.y,k.z),k=a.vertices[m.index2],b.push(k.x,k.y,k.z)}else if(a&&a.isBufferGeometry)if(k=new n,null!==a.index){l=a.attributes.position;h=a.index;var t= +a.groups;0===t.length&&(t=[{start:0,count:h.count,materialIndex:0}]);a=0;for(e=t.length;ac;c++)p=h.getX(m+c),q=h.getX(m+(c+1)%3),f[0]=Math.min(p,q),f[1]=Math.max(p,q),p=f[0]+","+f[1],void 0===g[p]&&(g[p]={index1:f[0],index2:f[1]});for(p in g)m=g[p],k.fromBufferAttribute(l,m.index1),b.push(k.x,k.y,k.z),k.fromBufferAttribute(l,m.index2),b.push(k.x,k.y,k.z)}else for(l=a.attributes.position,m=0,d=l.count/3;mc;c++)g=3* +m+c,k.fromBufferAttribute(l,g),b.push(k.x,k.y,k.z),g=3*m+(c+1)%3,k.fromBufferAttribute(l,g),b.push(k.x,k.y,k.z);this.setAttribute("position",new E(b,3))}function Xd(a,b,c){L.call(this);this.type="ParametricGeometry";this.parameters={func:a,slices:b,stacks:c};this.fromBufferGeometry(new Sc(a,b,c));this.mergeVertices()}function Sc(a,b,c){A.call(this);this.type="ParametricBufferGeometry";this.parameters={func:a,slices:b,stacks:c};var d=[],e=[],f=[],g=[],k=new n,l=new n,m=new n,h=new n,p=new n,q,t;3> +a.length&&console.error("THREE.ParametricGeometry: Function must now modify a Vector3 as third parameter.");var r=b+1;for(q=0;q<=c;q++){var u=q/c;for(t=0;t<=b;t++){var y=t/b;a(y,u,l);e.push(l.x,l.y,l.z);0<=y-1E-5?(a(y-1E-5,u,m),h.subVectors(l,m)):(a(y+1E-5,u,m),h.subVectors(m,l));0<=u-1E-5?(a(y,u-1E-5,m),p.subVectors(l,m)):(a(y,u+1E-5,m),p.subVectors(m,l));k.crossVectors(h,p).normalize();f.push(k.x,k.y,k.z);g.push(y,u)}}for(q=0;qd&&1===a.x&&(l[b]=a.x-1);0===c.x&& +0===c.z&&(l[b]=d/2/Math.PI+.5)}A.call(this);this.type="PolyhedronBufferGeometry";this.parameters={vertices:a,indices:b,radius:c,detail:d};c=c||1;d=d||0;var k=[],l=[];(function(a){for(var c=new n,d=new n,g=new n,k=0;ke&&(.2>b&&(l[a+0]+=1),.2>c&&(l[a+2]+=1),.2>d&&(l[a+4]+=1))})();this.setAttribute("position",new E(k,3));this.setAttribute("normal", +new E(k.slice(),3));this.setAttribute("uv",new E(l,2));0===d?this.computeVertexNormals():this.normalizeNormals()}function Zd(a,b){L.call(this);this.type="TetrahedronGeometry";this.parameters={radius:a,detail:b};this.fromBufferGeometry(new Tc(a,b));this.mergeVertices()}function Tc(a,b){Ja.call(this,[1,1,1,-1,-1,1,-1,1,-1,1,-1,-1],[2,1,0,0,3,2,1,3,0,2,3,1],a,b);this.type="TetrahedronBufferGeometry";this.parameters={radius:a,detail:b}}function $d(a,b){L.call(this);this.type="OctahedronGeometry";this.parameters= +{radius:a,detail:b};this.fromBufferGeometry(new dc(a,b));this.mergeVertices()}function dc(a,b){Ja.call(this,[1,0,0,-1,0,0,0,1,0,0,-1,0,0,0,1,0,0,-1],[0,2,4,0,4,3,0,3,5,0,5,2,1,2,5,1,5,3,1,3,4,1,4,2],a,b);this.type="OctahedronBufferGeometry";this.parameters={radius:a,detail:b}}function ae(a,b){L.call(this);this.type="IcosahedronGeometry";this.parameters={radius:a,detail:b};this.fromBufferGeometry(new Uc(a,b));this.mergeVertices()}function Uc(a,b){var c=(1+Math.sqrt(5))/2;Ja.call(this,[-1,c,0,1,c,0, +-1,-c,0,1,-c,0,0,-1,c,0,1,c,0,-1,-c,0,1,-c,c,0,-1,c,0,1,-c,0,-1,-c,0,1],[0,11,5,0,5,1,0,1,7,0,7,10,0,10,11,1,5,9,5,11,4,11,10,2,10,7,6,7,1,8,3,9,4,3,4,2,3,2,6,3,6,8,3,8,9,4,9,5,2,4,11,6,2,10,8,6,7,9,8,1],a,b);this.type="IcosahedronBufferGeometry";this.parameters={radius:a,detail:b}}function be(a,b){L.call(this);this.type="DodecahedronGeometry";this.parameters={radius:a,detail:b};this.fromBufferGeometry(new Vc(a,b));this.mergeVertices()}function Vc(a,b){var c=(1+Math.sqrt(5))/2,d=1/c;Ja.call(this, +[-1,-1,-1,-1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,1,-1,1,1,1,-1,1,1,1,0,-d,-c,0,-d,c,0,d,-c,0,d,c,-d,-c,0,-d,c,0,d,-c,0,d,c,0,-c,0,-d,c,0,-d,-c,0,d,c,0,d],[3,11,7,3,7,15,3,15,13,7,19,17,7,17,6,7,6,15,17,4,8,17,8,10,17,10,6,8,0,16,8,16,2,8,2,10,0,12,1,0,1,18,0,18,16,6,10,2,6,2,13,6,13,15,2,16,18,2,18,3,2,3,13,18,1,9,18,9,11,18,11,3,4,14,12,4,12,0,4,0,8,11,9,5,11,5,19,11,19,7,19,5,14,19,14,4,19,4,17,1,12,14,1,14,5,1,5,9],a,b);this.type="DodecahedronBufferGeometry";this.parameters={radius:a,detail:b}}function ce(a, +b,c,d,e,f){L.call(this);this.type="TubeGeometry";this.parameters={path:a,tubularSegments:b,radius:c,radialSegments:d,closed:e};void 0!==f&&console.warn("THREE.TubeGeometry: taper has been removed.");a=new ec(a,b,c,d,e);this.tangents=a.tangents;this.normals=a.normals;this.binormals=a.binormals;this.fromBufferGeometry(a);this.mergeVertices()}function ec(a,b,c,d,e){function f(e){h=a.getPointAt(e/b,h);var f=g.normals[e];e=g.binormals[e];for(q=0;q<=d;q++){var m=q/d*Math.PI*2,p=Math.sin(m);m=-Math.cos(m); +l.x=m*f.x+p*e.x;l.y=m*f.y+p*e.y;l.z=m*f.z+p*e.z;l.normalize();r.push(l.x,l.y,l.z);k.x=h.x+c*l.x;k.y=h.y+c*l.y;k.z=h.z+c*l.z;t.push(k.x,k.y,k.z)}}A.call(this);this.type="TubeBufferGeometry";this.parameters={path:a,tubularSegments:b,radius:c,radialSegments:d,closed:e};b=b||64;c=c||1;d=d||8;e=e||!1;var g=a.computeFrenetFrames(b,e);this.tangents=g.tangents;this.normals=g.normals;this.binormals=g.binormals;var k=new n,l=new n,m=new w,h=new n,p,q,t=[],r=[],u=[],y=[];for(p=0;p=b;e-=d)f=ci(e,a[e],a[e+1],f);f&&fc(f,f.next)&&(fe(f),f=f.next);return f}function ge(a,b){if(!a)return a;b||(b=a);do{var c=!1;if(a.steiner||!fc(a,a.next)&&0!==ta(a.prev,a,a.next))a=a.next;else{fe(a);a=b=a.prev; +if(a===a.next)break;c=!0}}while(c||a!==b);return b}function he(a,b,c,d,e,f,g){if(a){if(!g&&f){var k=a,l=k;do null===l.z&&(l.z=vg(l.x,l.y,d,e,f)),l.prevZ=l.prev,l=l.nextZ=l.next;while(l!==k);l.prevZ.nextZ=null;l.prevZ=null;k=l;var m,h,p,q,t=1;do{l=k;var r=k=null;for(h=0;l;){h++;var n=l;for(m=p=0;mn!==r.next.y>n&&r.next.y!==r.y&&p<(r.next.x-r.x)*(n-r.y)/(r.next.y-r.y)+r.x&&(h=!h),r=r.next;while(r!==l);r=h}l=r}if(l){a=ei(g,k);g=ge(g,g.next);a=ge(a, +a.next);he(g,b,c,d,e,f);he(a,b,c,d,e,f);break a}k=k.next}g=g.next}while(g!==a)}break}}}}function Kk(a,b,c,d){var e=a.prev,f=a.next;if(0<=ta(e,a,f))return!1;var g=e.x>a.x?e.x>f.x?e.x:f.x:a.x>f.x?a.x:f.x,k=e.y>a.y?e.y>f.y?e.y:f.y:a.y>f.y?a.y:f.y,l=vg(e.x=l&&d&&d.z<=b;){if(c!==a.prev&&c!==a.next&&Yc(e.x,e.y,a.x,a.y,f.x,f.y,c.x,c.y)&&0<=ta(c.prev,c,c.next))return!1;c=c.prevZ; +if(d!==a.prev&&d!==a.next&&Yc(e.x,e.y,a.x,a.y,f.x,f.y,d.x,d.y)&&0<=ta(d.prev,d,d.next))return!1;d=d.nextZ}for(;c&&c.z>=l;){if(c!==a.prev&&c!==a.next&&Yc(e.x,e.y,a.x,a.y,f.x,f.y,c.x,c.y)&&0<=ta(c.prev,c,c.next))return!1;c=c.prevZ}for(;d&&d.z<=b;){if(d!==a.prev&&d!==a.next&&Yc(e.x,e.y,a.x,a.y,f.x,f.y,d.x,d.y)&&0<=ta(d.prev,d,d.next))return!1;d=d.nextZ}return!0}function Lk(a,b){return a.x-b.x}function Mk(a,b){var c=b,d=a.x,e=a.y,f=-Infinity;do{if(e<=c.y&&e>=c.next.y&&c.next.y!==c.y){var g=c.x+(e-c.y)* +(c.next.x-c.x)/(c.next.y-c.y);if(g<=d&&g>f){f=g;if(g===d){if(e===c.y)return c;if(e===c.next.y)return c.next}var k=c.x=c.x&&c.x>=g&&d!==c.x&&Yc(ek.x)&&ie(c,a)&&(k=c,m=h)}c=c.next}return k}function vg(a,b,c,d,e){a=32767*(a-c)*e;b=32767*(b-d)*e;a=(a|a<<8)&16711935;a=(a|a<<4)&252645135; +a=(a|a<<2)&858993459;b=(b|b<<8)&16711935;b=(b|b<<4)&252645135;b=(b|b<<2)&858993459;return(a|a<<1)&1431655765|((b|b<<1)&1431655765)<<1}function Nk(a){var b=a,c=a;do{if(b.xta(a.prev,a,a.next)?0<=ta(a,b,a.next)&&0<=ta(a,a.prev,b):0>ta(a,b,a.prev)||0>ta(a,a.next,b)}function ei(a,b){var c=new wg(a.i,a.x,a.y),d=new wg(b.i,b.x,b.y),e=a.next,f=b.prev;a.next=b;b.prev=a;c.next=e;e.prev=c;d.next=c;c.prev=d;f.next=d;d.prev=f;return d}function ci(a,b,c,d){a=new wg(a,b,c);d?(a.next=d.next,a.prev=d,d.next.prev=a,d.next=a):(a.prev=a,a.next=a);return a}function fe(a){a.next.prev= +a.prev;a.prev.next=a.next;a.prevZ&&(a.prevZ.nextZ=a.nextZ);a.nextZ&&(a.nextZ.prevZ=a.prevZ)}function wg(a,b,c){this.i=a;this.x=b;this.y=c;this.nextZ=this.prevZ=this.z=this.next=this.prev=null;this.steiner=!1}function fi(a){var b=a.length;2Number.EPSILON){var l=Math.sqrt(k),m=Math.sqrt(f*f+g*g);k=b.x-e/l;b=b.y+d/l;g=((c.x-g/m-k)*g-(c.y+f/m-b)*f)/(d*g-e*f);f=k+d*g-a.x;d=b+e*g-a.y;e=f*f+d*d;if(2>=e)return new w(f,d);e=Math.sqrt(e/2)}else a=!1,d>Number.EPSILON?f>Number.EPSILON&&(a=!0):d<-Number.EPSILON? +f<-Number.EPSILON&&(a=!0):Math.sign(e)===Math.sign(g)&&(a=!0),a?(f=-e,e=Math.sqrt(k)):(f=d,d=e,e=Math.sqrt(k/2));return new w(f/e,d/e)}function k(a,b){for(J=a.length;0<=--J;){var c=J;var f=J-1;0>f&&(f=a.length-1);var g,k=C+2*E;for(g=0;gh;h++){var p=m[f[h]];var q=m[f[(h+1)%3]];d[0]=Math.min(p,q);d[1]=Math.max(p,q);p=d[0]+","+d[1];void 0===e[p]?e[p]={index1:d[0],index2:d[1],face1:k,face2:void 0}:e[p].face2=k}for(p in e)if(d=e[p],void 0===d.face2||g[d.face1].normal.dot(g[d.face2].normal)<=b)f=a[d.index1],c.push(f.x,f.y,f.z),f=a[d.index2],c.push(f.x,f.y,f.z);this.setAttribute("position",new E(c,3))}function kc(a,b,c,d, +e,f,g,k){L.call(this);this.type="CylinderGeometry";this.parameters={radiusTop:a,radiusBottom:b,height:c,radialSegments:d,heightSegments:e,openEnded:f,thetaStart:g,thetaLength:k};this.fromBufferGeometry(new ub(a,b,c,d,e,f,g,k));this.mergeVertices()}function ub(a,b,c,d,e,f,g,k){function l(c){var e,f=new w,l=new n,x=0,u=!0===c?a:b,C=!0===c?1:-1;var A=r;for(e=1;e<=d;e++)p.push(0,y*C,0),q.push(0,C,0),t.push(.5,.5),r++;var B=r;for(e=0;e<=d;e++){var E=e/d*k+g,D=Math.cos(E);E=Math.sin(E);l.x=u*E;l.y=y*C; +l.z=u*D;p.push(l.x,l.y,l.z);q.push(0,C,0);f.x=.5*D+.5;f.y=.5*E*C+.5;t.push(f.x,f.y);r++}for(e=0;ethis.duration&&this.resetDuration()}function Pk(a){switch(a.toLowerCase()){case "scalar":case "double":case "float":case "number":case "integer":return dd; +case "vector":case "vector2":case "vector3":case "vector4":return ed;case "color":return $e;case "quaternion":return re;case "bool":case "boolean":return Ze;case "string":return bf}throw Error("THREE.KeyframeTrack: Unsupported typeName: "+a);}function Qk(a){if(void 0===a.type)throw Error("THREE.KeyframeTrack: track type undefined, can not parse");var b=Pk(a.type);if(void 0===a.times){var c=[],d=[];ea.flattenJSON(a.keys,c,d,"value");a.times=c;a.values=d}return void 0!==b.parse?b.parse(a):new b(a.name, +a.times,a.values,a.interpolation)}function xg(a,b,c){var d=this,e=!1,f=0,g=0,k=void 0,l=[];this.onStart=void 0;this.onLoad=a;this.onProgress=b;this.onError=c;this.itemStart=function(a){g++;if(!1===e&&void 0!==d.onStart)d.onStart(a,f,g);e=!0};this.itemEnd=function(a){f++;if(void 0!==d.onProgress)d.onProgress(a,f,g);if(f===g&&(e=!1,void 0!==d.onLoad))d.onLoad()};this.itemError=function(a){if(void 0!==d.onError)d.onError(a)};this.resolveURL=function(a){return k?k(a):a};this.setURLModifier=function(a){k= +a;return this};this.addHandler=function(a,b){l.push(a,b);return this};this.removeHandler=function(a){a=l.indexOf(a);-1!==a&&l.splice(a,2);return this};this.getHandler=function(a){for(var b=0,c=l.length;ba;a++)this.coefficients.push(new n)}function bb(a,b){ba.call(this,void 0,b);this.sh=void 0!==a?a:new uf}function Gg(a,b,c){bb.call(this, +void 0,c);a=(new B).set(a);c=(new B).set(b);b=new n(a.r,a.g,a.b);a=new n(c.r,c.g,c.b);c=Math.sqrt(Math.PI);var d=c*Math.sqrt(.75);this.sh.coefficients[0].copy(b).add(a).multiplyScalar(c);this.sh.coefficients[1].copy(b).sub(a).multiplyScalar(d)}function Hg(a,b){bb.call(this,void 0,b);a=(new B).set(a);this.sh.coefficients[0].set(a.r,a.g,a.b).multiplyScalar(2*Math.sqrt(Math.PI))}function li(){this.type="StereoCamera";this.aspect=1;this.eyeSep=.064;this.cameraL=new da;this.cameraL.layers.enable(1);this.cameraL.matrixAutoUpdate= +!1;this.cameraR=new da;this.cameraR.layers.enable(2);this.cameraR.matrixAutoUpdate=!1;this._cache={focus:null,fov:null,aspect:null,near:null,far:null,zoom:null,eyeSep:null}}function Ig(a){this.autoStart=void 0!==a?a:!0;this.elapsedTime=this.oldTime=this.startTime=0;this.running=!1}function Jg(){D.call(this);this.type="AudioListener";this.context=Kg.getContext();this.gain=this.context.createGain();this.gain.connect(this.context.destination);this.filter=null;this.timeDelta=0;this._clock=new Ig}function id(a){D.call(this); +this.type="Audio";this.listener=a;this.context=a.context;this.gain=this.context.createGain();this.gain.connect(a.getInput());this.autoplay=!1;this.buffer=null;this.detune=0;this.loop=!1;this.offset=this.loopEnd=this.loopStart=0;this.duration=void 0;this.playbackRate=1;this.isPlaying=!1;this.hasPlaybackControl=!0;this.sourceType="empty";this._pausedAt=this._startedAt=0;this.filters=[]}function Lg(a){id.call(this,a);this.panner=this.context.createPanner();this.panner.panningModel="HRTF";this.panner.connect(this.gain)} +function Mg(a,b){this.analyser=a.context.createAnalyser();this.analyser.fftSize=void 0!==b?b:2048;this.data=new Uint8Array(this.analyser.frequencyBinCount);a.getOutput().connect(this.analyser)}function Ng(a,b,c){this.binding=a;this.valueSize=c;a=Float64Array;switch(b){case "quaternion":b=this._slerp;break;case "string":case "bool":a=Array;b=this._select;break;default:b=this._lerp}this.buffer=new a(4*c);this._mixBufferRegion=b;this.referenceCount=this.useCount=this.cumulativeWeight=0}function mi(a, +b,c){c=c||Ba.parseTrackName(b);this._targetGroup=a;this._bindings=a.subscribe_(b,c)}function Ba(a,b,c){this.path=b;this.parsedPath=c||Ba.parseTrackName(b);this.node=Ba.findNode(a,this.parsedPath.nodeName)||a;this.rootNode=a}function ni(){this.uuid=P.generateUUID();this._objects=Array.prototype.slice.call(arguments);this.nCachedObjects_=0;var a={};this._indicesByUUID=a;for(var b=0,c=arguments.length;b!==c;++b)a[arguments[b].uuid]=b;this._paths=[];this._parsedPaths=[];this._bindings=[];this._bindingsIndicesByPath= +{};var d=this;this.stats={objects:{get total(){return d._objects.length},get inUse(){return this.total-d.nCachedObjects_}},get bindingsPerObject(){return d._bindings.length}}}function oi(a,b,c){this._mixer=a;this._clip=b;this._localRoot=c||null;a=b.tracks;b=a.length;c=Array(b);for(var d={endingStart:2400,endingEnd:2400},e=0;e!==b;++e){var f=a[e].createInterpolant(null);c[e]=f;f.settings=d}this._interpolantSettings=d;this._interpolants=c;this._propertyBindings=Array(b);this._weightInterpolant=this._timeScaleInterpolant= +this._byClipCacheIndex=this._cacheIndex=null;this.loop=2201;this._loopCount=-1;this._startTime=null;this.time=0;this._effectiveWeight=this.weight=this._effectiveTimeScale=this.timeScale=1;this.repetitions=Infinity;this.paused=!1;this.enabled=!0;this.clampWhenFinished=!1;this.zeroSlopeAtEnd=this.zeroSlopeAtStart=!0}function Og(a){this._root=a;this._initMemoryManager();this.time=this._accuIndex=0;this.timeScale=1}function vf(a,b){"string"===typeof a&&(console.warn("THREE.Uniform: Type parameter is no longer needed."), +a=b);this.value=a}function Pg(a,b,c){sb.call(this,a,b);this.meshPerAttribute=c||1}function pi(a,b,c,d){this.ray=new Wb(a,b);this.near=c||0;this.far=d||Infinity;this.camera=null;this.params={Mesh:{},Line:{},LOD:{},Points:{threshold:1},Sprite:{}};Object.defineProperties(this.params,{PointCloud:{get:function(){console.warn("THREE.Raycaster: params.PointCloud has been renamed to params.Points.");return this.Points}}})}function qi(a,b){return a.distance-b.distance}function Qg(a,b,c,d){if(!1!==a.visible&& +(a.raycast(b,c),!0===d)){a=a.children;d=0;for(var e=a.length;dc;c++,d++){var e=c/32*Math.PI*2,f=d/32*Math.PI*2;b.push(Math.cos(e),Math.sin(e),1,Math.cos(f),Math.sin(f),1)}a.setAttribute("position",new E(b,3));b=new ka({fog:!1});this.cone=new ma(a,b);this.add(this.cone);this.update()}function ti(a){var b= +[];a&&a.isBone&&b.push(a);for(var c=0;cn;++n){var r=n/h;r=Math.exp(-r*r/2);e.push(r);0==n?q+=r:n\n\nvec4 inputTexelToLinear(vec4 value){\n\tif(inputEncoding == 0){\n\t\treturn value;\n\t}else if(inputEncoding == 1){\n\t\treturn sRGBToLinear(value);\n\t}else if(inputEncoding == 2){\n\t\treturn RGBEToLinear(value);\n\t}else if(inputEncoding == 3){\n\t\treturn RGBMToLinear(value, 7.0);\n\t}else if(inputEncoding == 4){\n\t\treturn RGBMToLinear(value, 16.0);\n\t}else if(inputEncoding == 5){\n\t\treturn RGBDToLinear(value, 256.0);\n\t}else{\n\t\treturn GammaToLinear(value, 2.2);\n\t}\n}\n\nvec4 linearToOutputTexel(vec4 value){\n\tif(outputEncoding == 0){\n\t\treturn value;\n\t}else if(outputEncoding == 1){\n\t\treturn LinearTosRGB(value);\n\t}else if(outputEncoding == 2){\n\t\treturn LinearToRGBE(value);\n\t}else if(outputEncoding == 3){\n\t\treturn LinearToRGBM(value, 7.0);\n\t}else if(outputEncoding == 4){\n\t\treturn LinearToRGBM(value, 16.0);\n\t}else if(outputEncoding == 5){\n\t\treturn LinearToRGBD(value, 256.0);\n\t}else{\n\t\treturn LinearToGamma(value, 2.2);\n\t}\n}\n\nvec4 envMapTexelToLinear(vec4 color) {\n\treturn inputTexelToLinear(color);\n}\n\t"} +function Fi(a){console.warn("THREE.ClosedSplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.");Aa.call(this,a);this.type="catmullrom";this.closed=!0}function Gi(a){console.warn("THREE.SplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.");Aa.call(this,a);this.type="catmullrom"}function ah(a){console.warn("THREE.Spline has been removed. Use THREE.CatmullRomCurve3 instead.");Aa.call(this,a);this.type="catmullrom"}void 0===Number.EPSILON&&(Number.EPSILON=Math.pow(2, +-52));void 0===Number.isInteger&&(Number.isInteger=function(a){return"number"===typeof a&&isFinite(a)&&Math.floor(a)===a});void 0===Math.sign&&(Math.sign=function(a){return 0>a?-1:0Ae;Ae++)ya[Ae]=(16>Ae?"0":"")+Ae.toString(16);var P={DEG2RAD:Math.PI/180,RAD2DEG:180/Math.PI,generateUUID:function(){var a=4294967295*Math.random()|0,b=4294967295*Math.random()|0,c=4294967295*Math.random()| +0,d=4294967295*Math.random()|0;return(ya[a&255]+ya[a>>8&255]+ya[a>>16&255]+ya[a>>24&255]+"-"+ya[b&255]+ya[b>>8&255]+"-"+ya[b>>16&15|64]+ya[b>>24&255]+"-"+ya[c&63|128]+ya[c>>8&255]+"-"+ya[c>>16&255]+ya[c>>24&255]+ya[d&255]+ya[d>>8&255]+ya[d>>16&255]+ya[d>>24&255]).toUpperCase()},clamp:function(a,b,c){return Math.max(b,Math.min(c,a))},euclideanModulo:function(a,b){return(a%b+b)%b},mapLinear:function(a,b,c,d,e){return d+(a-b)*(e-d)/(c-b)},lerp:function(a,b,c){return(1-c)*a+c*b},smoothstep:function(a, +b,c){if(a<=b)return 0;if(a>=c)return 1;a=(a-b)/(c-b);return a*a*(3-2*a)},smootherstep:function(a,b,c){if(a<=b)return 0;if(a>=c)return 1;a=(a-b)/(c-b);return a*a*a*(a*(6*a-15)+10)},randInt:function(a,b){return a+Math.floor(Math.random()*(b-a+1))},randFloat:function(a,b){return a+Math.random()*(b-a)},randFloatSpread:function(a){return a*(.5-Math.random())},degToRad:function(a){return a*P.DEG2RAD},radToDeg:function(a){return a*P.RAD2DEG},isPowerOfTwo:function(a){return 0===(a&a-1)&&0!==a},ceilPowerOfTwo:function(a){return Math.pow(2, +Math.ceil(Math.log(a)/Math.LN2))},floorPowerOfTwo:function(a){return Math.pow(2,Math.floor(Math.log(a)/Math.LN2))},setQuaternionFromProperEuler:function(a,b,c,d,e){var f=Math.cos,g=Math.sin,k=f(c/2);c=g(c/2);var l=f((b+d)/2),m=g((b+d)/2),h=f((b-d)/2),p=g((b-d)/2);f=f((d-b)/2);b=g((d-b)/2);"XYX"===e?a.set(k*m,c*h,c*p,k*l):"YZY"===e?a.set(c*p,k*m,c*h,k*l):"ZXZ"===e?a.set(c*h,c*p,k*m,k*l):"XZX"===e?a.set(k*m,c*b,c*f,k*l):"YXY"===e?a.set(c*f,k*m,c*b,k*l):"ZYZ"===e?a.set(c*b,c*f,k*m,k*l):console.warn("THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order.")}}; +Object.defineProperties(w.prototype,{width:{get:function(){return this.x},set:function(a){this.x=a}},height:{get:function(){return this.y},set:function(a){this.y=a}}});Object.assign(w.prototype,{isVector2:!0,set:function(a,b){this.x=a;this.y=b;return this},setScalar:function(a){this.y=this.x=a;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;default:throw Error("index is out of range: "+ +a);}return this},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;default:throw Error("index is out of range: "+a);}},clone:function(){return new this.constructor(this.x,this.y)},copy:function(a){this.x=a.x;this.y=a.y;return this},add:function(a,b){if(void 0!==b)return console.warn("THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;return this},addScalar:function(a){this.x+=a;this.y+=a;return this}, +addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this},addScaledVector:function(a,b){this.x+=a.x*b;this.y+=a.y*b;return this},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;return this},subScalar:function(a){this.x-=a;this.y-=a;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this},multiply:function(a){this.x*=a.x;this.y*= +a.y;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;return this},divide:function(a){this.x/=a.x;this.y/=a.y;return this},divideScalar:function(a){return this.multiplyScalar(1/a)},applyMatrix3:function(a){var b=this.x,c=this.y;a=a.elements;this.x=a[0]*b+a[3]*c+a[6];this.y=a[1]*b+a[4]*c+a[7];return this},min:function(a){this.x=Math.min(this.x,a.x);this.y=Math.min(this.y,a.y);return this},max:function(a){this.x=Math.max(this.x,a.x);this.y=Math.max(this.y,a.y);return this},clamp:function(a, +b){this.x=Math.max(a.x,Math.min(b.x,this.x));this.y=Math.max(a.y,Math.min(b.y,this.y));return this},clampScalar:function(a,b){this.x=Math.max(a,Math.min(b,this.x));this.y=Math.max(a,Math.min(b,this.y));return this},clampLength:function(a,b){var c=this.length();return this.divideScalar(c||1).multiplyScalar(Math.max(a,Math.min(b,c)))},floor:function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);return this},ceil:function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);return this},round:function(){this.x= +Math.round(this.x);this.y=Math.round(this.y);return this},roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);return this},negate:function(){this.x=-this.x;this.y=-this.y;return this},dot:function(a){return this.x*a.x+this.y*a.y},cross:function(a){return this.x*a.y-this.y*a.x},lengthSq:function(){return this.x*this.x+this.y*this.y},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y)},manhattanLength:function(){return Math.abs(this.x)+ +Math.abs(this.y)},normalize:function(){return this.divideScalar(this.length()||1)},angle:function(){var a=Math.atan2(this.y,this.x);0>a&&(a+=2*Math.PI);return a},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x;a=this.y-a.y;return b*b+a*a},manhattanDistanceTo:function(a){return Math.abs(this.x-a.x)+Math.abs(this.y-a.y)},setLength:function(a){return this.normalize().multiplyScalar(a)},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+= +(a.y-this.y)*b;return this},lerpVectors:function(a,b,c){return this.subVectors(b,a).multiplyScalar(c).add(a)},equals:function(a){return a.x===this.x&&a.y===this.y},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;return a},fromBufferAttribute:function(a,b,c){void 0!==c&&console.warn("THREE.Vector2: offset has been removed from .fromBufferAttribute().");this.x=a.getX(b);this.y=a.getY(b); +return this},rotateAround:function(a,b){var c=Math.cos(b);b=Math.sin(b);var d=this.x-a.x,e=this.y-a.y;this.x=d*c-e*b+a.x;this.y=d*b+e*c+a.y;return this}});Object.assign(za.prototype,{isMatrix3:!0,set:function(a,b,c,d,e,f,g,k,l){var m=this.elements;m[0]=a;m[1]=d;m[2]=g;m[3]=b;m[4]=e;m[5]=k;m[6]=c;m[7]=f;m[8]=l;return this},identity:function(){this.set(1,0,0,0,1,0,0,0,1);return this},clone:function(){return(new this.constructor).fromArray(this.elements)},copy:function(a){var b=this.elements;a=a.elements; +b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];return this},setFromMatrix4:function(a){a=a.elements;this.set(a[0],a[4],a[8],a[1],a[5],a[9],a[2],a[6],a[10]);return this},multiply:function(a){return this.multiplyMatrices(this,a)},premultiply:function(a){return this.multiplyMatrices(a,this)},multiplyMatrices:function(a,b){var c=a.elements,d=b.elements;b=this.elements;a=c[0];var e=c[3],f=c[6],g=c[1],k=c[4],l=c[7],m=c[2],h=c[5];c=c[8];var p=d[0],q=d[3],n=d[6], +r=d[1],u=d[4],y=d[7],v=d[2],w=d[5];d=d[8];b[0]=a*p+e*r+f*v;b[3]=a*q+e*u+f*w;b[6]=a*n+e*y+f*d;b[1]=g*p+k*r+l*v;b[4]=g*q+k*u+l*w;b[7]=g*n+k*y+l*d;b[2]=m*p+h*r+c*v;b[5]=m*q+h*u+c*w;b[8]=m*n+h*y+c*d;return this},multiplyScalar:function(a){var b=this.elements;b[0]*=a;b[3]*=a;b[6]*=a;b[1]*=a;b[4]*=a;b[7]*=a;b[2]*=a;b[5]*=a;b[8]*=a;return this},determinant:function(){var a=this.elements,b=a[0],c=a[1],d=a[2],e=a[3],f=a[4],g=a[5],k=a[6],l=a[7];a=a[8];return b*f*a-b*g*l-c*e*a+c*g*k+d*e*l-d*f*k},getInverse:function(a, +b){a&&a.isMatrix4&&console.error("THREE.Matrix3: .getInverse() no longer takes a Matrix4 argument.");var c=a.elements;a=this.elements;var d=c[0],e=c[1],f=c[2],g=c[3],k=c[4],l=c[5],m=c[6],h=c[7];c=c[8];var p=c*k-l*h,q=l*m-c*g,n=h*g-k*m,r=d*p+e*q+f*n;if(0===r){if(!0===b)throw Error("THREE.Matrix3: .getInverse() can't invert matrix, determinant is 0");console.warn("THREE.Matrix3: .getInverse() can't invert matrix, determinant is 0");return this.identity()}b=1/r;a[0]=p*b;a[1]=(f*h-c*e)*b;a[2]=(l*e-f* +k)*b;a[3]=q*b;a[4]=(c*d-f*m)*b;a[5]=(f*g-l*d)*b;a[6]=n*b;a[7]=(e*m-h*d)*b;a[8]=(k*d-e*g)*b;return this},transpose:function(){var a=this.elements;var b=a[1];a[1]=a[3];a[3]=b;b=a[2];a[2]=a[6];a[6]=b;b=a[5];a[5]=a[7];a[7]=b;return this},getNormalMatrix:function(a){return this.setFromMatrix4(a).getInverse(this).transpose()},transposeIntoArray:function(a){var b=this.elements;a[0]=b[0];a[1]=b[3];a[2]=b[6];a[3]=b[1];a[4]=b[4];a[5]=b[7];a[6]=b[2];a[7]=b[5];a[8]=b[8];return this},setUvTransform:function(a, +b,c,d,e,f,g){var k=Math.cos(e);e=Math.sin(e);this.set(c*k,c*e,-c*(k*f+e*g)+f+a,-d*e,d*k,-d*(-e*f+k*g)+g+b,0,0,1)},scale:function(a,b){var c=this.elements;c[0]*=a;c[3]*=a;c[6]*=a;c[1]*=b;c[4]*=b;c[7]*=b;return this},rotate:function(a){var b=Math.cos(a);a=Math.sin(a);var c=this.elements,d=c[0],e=c[3],f=c[6],g=c[1],k=c[4],l=c[7];c[0]=b*d+a*g;c[3]=b*e+a*k;c[6]=b*f+a*l;c[1]=-a*d+b*g;c[4]=-a*e+b*k;c[7]=-a*f+b*l;return this},translate:function(a,b){var c=this.elements;c[0]+=a*c[2];c[3]+=a*c[5];c[6]+=a*c[8]; +c[1]+=b*c[2];c[4]+=b*c[5];c[7]+=b*c[8];return this},equals:function(a){var b=this.elements;a=a.elements;for(var c=0;9>c;c++)if(b[c]!==a[c])return!1;return!0},fromArray:function(a,b){void 0===b&&(b=0);for(var c=0;9>c;c++)this.elements[c]=a[c+b];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);var c=this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[5];a[b+6]=c[6];a[b+7]=c[7];a[b+8]=c[8];return a}});var od,Mb={getDataURL:function(a){if("undefined"== +typeof HTMLCanvasElement)return a.src;if(!(a instanceof HTMLCanvasElement)){void 0===od&&(od=document.createElementNS("http://www.w3.org/1999/xhtml","canvas"));od.width=a.width;od.height=a.height;var b=od.getContext("2d");a instanceof ImageData?b.putImageData(a,0,0):b.drawImage(a,0,0,a.width,a.height);a=od}return 2048a.x||1a.x?0:1;break;case 1002:a.x=1===Math.abs(Math.floor(a.x)%2)?Math.ceil(a.x)-a.x:a.x-Math.floor(a.x)}if(0>a.y||1a.y?0:1;break;case 1002:a.y=1===Math.abs(Math.floor(a.y)%2)?Math.ceil(a.y)-a.y:a.y-Math.floor(a.y)}this.flipY&&(a.y=1-a.y);return a}});Object.defineProperty(Z.prototype,"needsUpdate",{set:function(a){!0===a&&this.version++}});Object.defineProperties(ia.prototype,{width:{get:function(){return this.z}, +set:function(a){this.z=a}},height:{get:function(){return this.w},set:function(a){this.w=a}}});Object.assign(ia.prototype,{isVector4:!0,set:function(a,b,c,d){this.x=a;this.y=b;this.z=c;this.w=d;return this},setScalar:function(a){this.w=this.z=this.y=this.x=a;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},setW:function(a){this.w=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b; +break;case 2:this.z=b;break;case 3:this.w=b;break;default:throw Error("index is out of range: "+a);}return this},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw Error("index is out of range: "+a);}},clone:function(){return new this.constructor(this.x,this.y,this.z,this.w)},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=void 0!==a.w?a.w:1;return this},add:function(a,b){if(void 0!==b)return console.warn("THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead."), +this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;this.w+=a.w;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;this.w+=a;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;this.w=a.w+b.w;return this},addScaledVector:function(a,b){this.x+=a.x*b;this.y+=a.y*b;this.z+=a.z*b;this.w+=a.w*b;return this},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a, +b);this.x-=a.x;this.y-=a.y;this.z-=a.z;this.w-=a.w;return this},subScalar:function(a){this.x-=a;this.y-=a;this.z-=a;this.w-=a;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;this.w=a.w-b.w;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;this.w*=a;return this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z,e=this.w;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12]*e;this.y=a[1]*b+a[5]*c+a[9]*d+a[13]*e;this.z=a[2]*b+a[6]*c+a[10]*d+a[14]* +e;this.w=a[3]*b+a[7]*c+a[11]*d+a[15]*e;return this},divideScalar:function(a){return this.multiplyScalar(1/a)},setAxisAngleFromQuaternion:function(a){this.w=2*Math.acos(a.w);var b=Math.sqrt(1-a.w*a.w);1E-4>b?(this.x=1,this.z=this.y=0):(this.x=a.x/b,this.y=a.y/b,this.z=a.z/b);return this},setAxisAngleFromRotationMatrix:function(a){a=a.elements;var b=a[0];var c=a[4];var d=a[8],e=a[1],f=a[5],g=a[9];var k=a[2];var l=a[6];var m=a[10];if(.01>Math.abs(c-e)&&.01>Math.abs(d-k)&&.01>Math.abs(g-l)){if(.1>Math.abs(c+ +e)&&.1>Math.abs(d+k)&&.1>Math.abs(g+l)&&.1>Math.abs(b+f+m-3))return this.set(1,0,0,0),this;a=Math.PI;b=(b+1)/2;f=(f+1)/2;m=(m+1)/2;c=(c+e)/4;d=(d+k)/4;g=(g+l)/4;b>f&&b>m?.01>b?(l=0,c=k=.707106781):(l=Math.sqrt(b),k=c/l,c=d/l):f>m?.01>f?(l=.707106781,k=0,c=.707106781):(k=Math.sqrt(f),l=c/k,c=g/k):.01>m?(k=l=.707106781,c=0):(c=Math.sqrt(m),l=d/c,k=g/c);this.set(l,k,c,a);return this}a=Math.sqrt((l-g)*(l-g)+(d-k)*(d-k)+(e-c)*(e-c));.001>Math.abs(a)&&(a=1);this.x=(l-g)/a;this.y=(d-k)/a;this.z=(e-c)/a; +this.w=Math.acos((b+f+m-1)/2);return this},min:function(a){this.x=Math.min(this.x,a.x);this.y=Math.min(this.y,a.y);this.z=Math.min(this.z,a.z);this.w=Math.min(this.w,a.w);return this},max:function(a){this.x=Math.max(this.x,a.x);this.y=Math.max(this.y,a.y);this.z=Math.max(this.z,a.z);this.w=Math.max(this.w,a.w);return this},clamp:function(a,b){this.x=Math.max(a.x,Math.min(b.x,this.x));this.y=Math.max(a.y,Math.min(b.y,this.y));this.z=Math.max(a.z,Math.min(b.z,this.z));this.w=Math.max(a.w,Math.min(b.w, +this.w));return this},clampScalar:function(a,b){this.x=Math.max(a,Math.min(b,this.x));this.y=Math.max(a,Math.min(b,this.y));this.z=Math.max(a,Math.min(b,this.z));this.w=Math.max(a,Math.min(b,this.w));return this},clampLength:function(a,b){var c=this.length();return this.divideScalar(c||1).multiplyScalar(Math.max(a,Math.min(b,c)))},floor:function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);this.z=Math.floor(this.z);this.w=Math.floor(this.w);return this},ceil:function(){this.x=Math.ceil(this.x); +this.y=Math.ceil(this.y);this.z=Math.ceil(this.z);this.w=Math.ceil(this.w);return this},round:function(){this.x=Math.round(this.x);this.y=Math.round(this.y);this.z=Math.round(this.z);this.w=Math.round(this.w);return this},roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);this.z=0>this.z?Math.ceil(this.z):Math.floor(this.z);this.w=0>this.w?Math.ceil(this.w):Math.floor(this.w);return this},negate:function(){this.x=-this.x; +this.y=-this.y;this.z=-this.z;this.w=-this.w;return this},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z+this.w*a.w},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)},manhattanLength:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)},normalize:function(){return this.divideScalar(this.length()||1)},setLength:function(a){return this.normalize().multiplyScalar(a)}, +lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;this.w+=(a.w-this.w)*b;return this},lerpVectors:function(a,b,c){return this.subVectors(b,a).multiplyScalar(c).add(a)},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z&&a.w===this.w},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];this.z=a[b+2];this.w=a[b+3];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;a[b+2]=this.z;a[b+3]= +this.w;return a},fromBufferAttribute:function(a,b,c){void 0!==c&&console.warn("THREE.Vector4: offset has been removed from .fromBufferAttribute().");this.x=a.getX(b);this.y=a.getY(b);this.z=a.getZ(b);this.w=a.getW(b);return this}});wa.prototype=Object.assign(Object.create(Fa.prototype),{constructor:wa,isWebGLRenderTarget:!0,setSize:function(a,b){if(this.width!==a||this.height!==b)this.width=a,this.height=b,this.texture.image.width=a,this.texture.image.height=b,this.dispose();this.viewport.set(0,0, +a,b);this.scissor.set(0,0,a,b)},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.width=a.width;this.height=a.height;this.viewport.copy(a.viewport);this.texture=a.texture.clone();this.depthBuffer=a.depthBuffer;this.stencilBuffer=a.stencilBuffer;this.depthTexture=a.depthTexture;return this},dispose:function(){this.dispatchEvent({type:"dispose"})}});$f.prototype=Object.assign(Object.create(wa.prototype),{constructor:$f,isWebGLMultisampleRenderTarget:!0,copy:function(a){wa.prototype.copy.call(this, +a);this.samples=a.samples;return this}});Object.assign(Da,{slerp:function(a,b,c,d){return c.copy(a).slerp(b,d)},slerpFlat:function(a,b,c,d,e,f,g){var k=c[d+0],l=c[d+1],m=c[d+2];c=c[d+3];d=e[f+0];var h=e[f+1],p=e[f+2];e=e[f+3];if(c!==e||k!==d||l!==h||m!==p){f=1-g;var q=k*d+l*h+m*p+c*e,n=0<=q?1:-1,r=1-q*q;r>Number.EPSILON&&(r=Math.sqrt(r),q=Math.atan2(r,q*n),f=Math.sin(f*q)/r,g=Math.sin(g*q)/r);n*=g;k=k*f+d*n;l=l*f+h*n;m=m*f+p*n;c=c*f+e*n;f===1-g&&(g=1/Math.sqrt(k*k+l*l+m*m+c*c),k*=g,l*=g,m*=g,c*=g)}a[b]= +k;a[b+1]=l;a[b+2]=m;a[b+3]=c}});Object.defineProperties(Da.prototype,{x:{get:function(){return this._x},set:function(a){this._x=a;this._onChangeCallback()}},y:{get:function(){return this._y},set:function(a){this._y=a;this._onChangeCallback()}},z:{get:function(){return this._z},set:function(a){this._z=a;this._onChangeCallback()}},w:{get:function(){return this._w},set:function(a){this._w=a;this._onChangeCallback()}}});Object.assign(Da.prototype,{isQuaternion:!0,set:function(a,b,c,d){this._x=a;this._y= +b;this._z=c;this._w=d;this._onChangeCallback();return this},clone:function(){return new this.constructor(this._x,this._y,this._z,this._w)},copy:function(a){this._x=a.x;this._y=a.y;this._z=a.z;this._w=a.w;this._onChangeCallback();return this},setFromEuler:function(a,b){if(!a||!a.isEuler)throw Error("THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.");var c=a._x,d=a._y,e=a._z;a=a.order;var f=Math.cos,g=Math.sin,k=f(c/2),l=f(d/2);f=f(e/2);c=g(c/2);d=g(d/ +2);e=g(e/2);"XYZ"===a?(this._x=c*l*f+k*d*e,this._y=k*d*f-c*l*e,this._z=k*l*e+c*d*f,this._w=k*l*f-c*d*e):"YXZ"===a?(this._x=c*l*f+k*d*e,this._y=k*d*f-c*l*e,this._z=k*l*e-c*d*f,this._w=k*l*f+c*d*e):"ZXY"===a?(this._x=c*l*f-k*d*e,this._y=k*d*f+c*l*e,this._z=k*l*e+c*d*f,this._w=k*l*f-c*d*e):"ZYX"===a?(this._x=c*l*f-k*d*e,this._y=k*d*f+c*l*e,this._z=k*l*e-c*d*f,this._w=k*l*f+c*d*e):"YZX"===a?(this._x=c*l*f+k*d*e,this._y=k*d*f+c*l*e,this._z=k*l*e-c*d*f,this._w=k*l*f-c*d*e):"XZY"===a&&(this._x=c*l*f-k*d* +e,this._y=k*d*f-c*l*e,this._z=k*l*e+c*d*f,this._w=k*l*f+c*d*e);!1!==b&&this._onChangeCallback();return this},setFromAxisAngle:function(a,b){b/=2;var c=Math.sin(b);this._x=a.x*c;this._y=a.y*c;this._z=a.z*c;this._w=Math.cos(b);this._onChangeCallback();return this},setFromRotationMatrix:function(a){var b=a.elements,c=b[0];a=b[4];var d=b[8],e=b[1],f=b[5],g=b[9],k=b[2],l=b[6];b=b[10];var m=c+f+b;0f&&c>b?(c=2*Math.sqrt(1+ +c-f-b),this._w=(l-g)/c,this._x=.25*c,this._y=(a+e)/c,this._z=(d+k)/c):f>b?(c=2*Math.sqrt(1+f-c-b),this._w=(d-k)/c,this._x=(a+e)/c,this._y=.25*c,this._z=(g+l)/c):(c=2*Math.sqrt(1+b-c-f),this._w=(e-a)/c,this._x=(d+k)/c,this._y=(g+l)/c,this._z=.25*c);this._onChangeCallback();return this},setFromUnitVectors:function(a,b){var c=a.dot(b)+1;1E-6>c?(c=0,Math.abs(a.x)>Math.abs(a.z)?(this._x=-a.y,this._y=a.x,this._z=0):(this._x=0,this._y=-a.z,this._z=a.y)):(this._x=a.y*b.z-a.z*b.y,this._y=a.z*b.x-a.x*b.z,this._z= +a.x*b.y-a.y*b.x);this._w=c;return this.normalize()},angleTo:function(a){return 2*Math.acos(Math.abs(P.clamp(this.dot(a),-1,1)))},rotateTowards:function(a,b){var c=this.angleTo(a);if(0===c)return this;this.slerp(a,Math.min(1,b/c));return this},inverse:function(){return this.conjugate()},conjugate:function(){this._x*=-1;this._y*=-1;this._z*=-1;this._onChangeCallback();return this},dot:function(a){return this._x*a._x+this._y*a._y+this._z*a._z+this._w*a._w},lengthSq:function(){return this._x*this._x+ +this._y*this._y+this._z*this._z+this._w*this._w},length:function(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)},normalize:function(){var a=this.length();0===a?(this._z=this._y=this._x=0,this._w=1):(a=1/a,this._x*=a,this._y*=a,this._z*=a,this._w*=a);this._onChangeCallback();return this},multiply:function(a,b){return void 0!==b?(console.warn("THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead."),this.multiplyQuaternions(a, +b)):this.multiplyQuaternions(this,a)},premultiply:function(a){return this.multiplyQuaternions(a,this)},multiplyQuaternions:function(a,b){var c=a._x,d=a._y,e=a._z;a=a._w;var f=b._x,g=b._y,k=b._z;b=b._w;this._x=c*b+a*f+d*k-e*g;this._y=d*b+a*g+e*f-c*k;this._z=e*b+a*k+c*g-d*f;this._w=a*b-c*f-d*g-e*k;this._onChangeCallback();return this},slerp:function(a,b){if(0===b)return this;if(1===b)return this.copy(a);var c=this._x,d=this._y,e=this._z,f=this._w,g=f*a._w+c*a._x+d*a._y+e*a._z;0>g?(this._w=-a._w,this._x= +-a._x,this._y=-a._y,this._z=-a._z,g=-g):this.copy(a);if(1<=g)return this._w=f,this._x=c,this._y=d,this._z=e,this;a=1-g*g;if(a<=Number.EPSILON)return g=1-b,this._w=g*f+b*this._w,this._x=g*c+b*this._x,this._y=g*d+b*this._y,this._z=g*e+b*this._z,this.normalize(),this._onChangeCallback(),this;a=Math.sqrt(a);var k=Math.atan2(a,g);g=Math.sin((1-b)*k)/a;b=Math.sin(b*k)/a;this._w=f*g+this._w*b;this._x=c*g+this._x*b;this._y=d*g+this._y*b;this._z=e*g+this._z*b;this._onChangeCallback();return this},equals:function(a){return a._x=== +this._x&&a._y===this._y&&a._z===this._z&&a._w===this._w},fromArray:function(a,b){void 0===b&&(b=0);this._x=a[b];this._y=a[b+1];this._z=a[b+2];this._w=a[b+3];this._onChangeCallback();return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this._x;a[b+1]=this._y;a[b+2]=this._z;a[b+3]=this._w;return a},_onChange:function(a){this._onChangeCallback=a;return this},_onChangeCallback:function(){}});var bh=new n,Hi=new Da;Object.assign(n.prototype,{isVector3:!0,set:function(a,b,c){this.x= +a;this.y=b;this.z=c;return this},setScalar:function(a){this.z=this.y=this.x=a;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;default:throw Error("index is out of range: "+a);}return this},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw Error("index is out of range: "+ +a);}},clone:function(){return new this.constructor(this.x,this.y,this.z)},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},add:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;return this},addScaledVector:function(a, +b){this.x+=a.x*b;this.y+=a.y*b;this.z+=a.z*b;return this},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;return this},subScalar:function(a){this.x-=a;this.y-=a;this.z-=a;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;return this},multiply:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead."), +this.multiplyVectors(a,b);this.x*=a.x;this.y*=a.y;this.z*=a.z;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;return this},multiplyVectors:function(a,b){this.x=a.x*b.x;this.y=a.y*b.y;this.z=a.z*b.z;return this},applyEuler:function(a){a&&a.isEuler||console.error("THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.");return this.applyQuaternion(Hi.setFromEuler(a))},applyAxisAngle:function(a,b){return this.applyQuaternion(Hi.setFromAxisAngle(a, +b))},applyMatrix3:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[3]*c+a[6]*d;this.y=a[1]*b+a[4]*c+a[7]*d;this.z=a[2]*b+a[5]*c+a[8]*d;return this},applyNormalMatrix:function(a){return this.applyMatrix3(a).normalize()},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;var e=1/(a[3]*b+a[7]*c+a[11]*d+a[15]);this.x=(a[0]*b+a[4]*c+a[8]*d+a[12])*e;this.y=(a[1]*b+a[5]*c+a[9]*d+a[13])*e;this.z=(a[2]*b+a[6]*c+a[10]*d+a[14])*e;return this},applyQuaternion:function(a){var b= +this.x,c=this.y,d=this.z,e=a.x,f=a.y,g=a.z;a=a.w;var k=a*b+f*d-g*c,l=a*c+g*b-e*d,m=a*d+e*c-f*b;b=-e*b-f*c-g*d;this.x=k*a+b*-e+l*-g-m*-f;this.y=l*a+b*-f+m*-e-k*-g;this.z=m*a+b*-g+k*-f-l*-e;return this},project:function(a){return this.applyMatrix4(a.matrixWorldInverse).applyMatrix4(a.projectionMatrix)},unproject:function(a){return this.applyMatrix4(a.projectionMatrixInverse).applyMatrix4(a.matrixWorld)},transformDirection:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[4]*c+ +a[8]*d;this.y=a[1]*b+a[5]*c+a[9]*d;this.z=a[2]*b+a[6]*c+a[10]*d;return this.normalize()},divide:function(a){this.x/=a.x;this.y/=a.y;this.z/=a.z;return this},divideScalar:function(a){return this.multiplyScalar(1/a)},min:function(a){this.x=Math.min(this.x,a.x);this.y=Math.min(this.y,a.y);this.z=Math.min(this.z,a.z);return this},max:function(a){this.x=Math.max(this.x,a.x);this.y=Math.max(this.y,a.y);this.z=Math.max(this.z,a.z);return this},clamp:function(a,b){this.x=Math.max(a.x,Math.min(b.x,this.x)); +this.y=Math.max(a.y,Math.min(b.y,this.y));this.z=Math.max(a.z,Math.min(b.z,this.z));return this},clampScalar:function(a,b){this.x=Math.max(a,Math.min(b,this.x));this.y=Math.max(a,Math.min(b,this.y));this.z=Math.max(a,Math.min(b,this.z));return this},clampLength:function(a,b){var c=this.length();return this.divideScalar(c||1).multiplyScalar(Math.max(a,Math.min(b,c)))},floor:function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);this.z=Math.floor(this.z);return this},ceil:function(){this.x= +Math.ceil(this.x);this.y=Math.ceil(this.y);this.z=Math.ceil(this.z);return this},round:function(){this.x=Math.round(this.x);this.y=Math.round(this.y);this.z=Math.round(this.z);return this},roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);this.z=0>this.z?Math.ceil(this.z):Math.floor(this.z);return this},negate:function(){this.x=-this.x;this.y=-this.y;this.z=-this.z;return this},dot:function(a){return this.x*a.x+this.y* +a.y+this.z*a.z},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)},manhattanLength:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)},normalize:function(){return this.divideScalar(this.length()||1)},setLength:function(a){return this.normalize().multiplyScalar(a)},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;return this},lerpVectors:function(a, +b,c){return this.subVectors(b,a).multiplyScalar(c).add(a)},cross:function(a,b){return void 0!==b?(console.warn("THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."),this.crossVectors(a,b)):this.crossVectors(this,a)},crossVectors:function(a,b){var c=a.x,d=a.y;a=a.z;var e=b.x,f=b.y;b=b.z;this.x=d*b-a*f;this.y=a*e-c*b;this.z=c*f-d*e;return this},projectOnVector:function(a){var b=a.lengthSq();if(0===b)return this.set(0,0,0);b=a.dot(this)/b;return this.copy(a).multiplyScalar(b)}, +projectOnPlane:function(a){bh.copy(this).projectOnVector(a);return this.sub(bh)},reflect:function(a){return this.sub(bh.copy(a).multiplyScalar(2*this.dot(a)))},angleTo:function(a){var b=Math.sqrt(this.lengthSq()*a.lengthSq());if(0===b)return Math.PI/2;a=this.dot(a)/b;return Math.acos(P.clamp(a,-1,1))},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,c=this.y-a.y;a=this.z-a.z;return b*b+c*c+a*a},manhattanDistanceTo:function(a){return Math.abs(this.x- +a.x)+Math.abs(this.y-a.y)+Math.abs(this.z-a.z)},setFromSpherical:function(a){return this.setFromSphericalCoords(a.radius,a.phi,a.theta)},setFromSphericalCoords:function(a,b,c){var d=Math.sin(b)*a;this.x=d*Math.sin(c);this.y=Math.cos(b)*a;this.z=d*Math.cos(c);return this},setFromCylindrical:function(a){return this.setFromCylindricalCoords(a.radius,a.theta,a.y)},setFromCylindricalCoords:function(a,b,c){this.x=a*Math.sin(b);this.y=c;this.z=a*Math.cos(b);return this},setFromMatrixPosition:function(a){a= +a.elements;this.x=a[12];this.y=a[13];this.z=a[14];return this},setFromMatrixScale:function(a){var b=this.setFromMatrixColumn(a,0).length(),c=this.setFromMatrixColumn(a,1).length();a=this.setFromMatrixColumn(a,2).length();this.x=b;this.y=c;this.z=a;return this},setFromMatrixColumn:function(a,b){return this.fromArray(a.elements,4*b)},setFromMatrix3Column:function(a,b){return this.fromArray(a.elements,3*b)},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z},fromArray:function(a,b){void 0=== +b&&(b=0);this.x=a[b];this.y=a[b+1];this.z=a[b+2];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;a[b+2]=this.z;return a},fromBufferAttribute:function(a,b,c){void 0!==c&&console.warn("THREE.Vector3: offset has been removed from .fromBufferAttribute().");this.x=a.getX(b);this.y=a.getY(b);this.z=a.getZ(b);return this}});var pd=new n,S=new O,Rk=new n(0,0,0),Sk=new n(1,1,1),Nb=new n,Df=new n,la=new n;Object.assign(O.prototype,{isMatrix4:!0,set:function(a, +b,c,d,e,f,g,k,l,m,h,p,q,n,r,u){var x=this.elements;x[0]=a;x[4]=b;x[8]=c;x[12]=d;x[1]=e;x[5]=f;x[9]=g;x[13]=k;x[2]=l;x[6]=m;x[10]=h;x[14]=p;x[3]=q;x[7]=n;x[11]=r;x[15]=u;return this},identity:function(){this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);return this},clone:function(){return(new O).fromArray(this.elements)},copy:function(a){var b=this.elements;a=a.elements;b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];b[9]=a[9];b[10]=a[10];b[11]=a[11];b[12]=a[12];b[13]= +a[13];b[14]=a[14];b[15]=a[15];return this},copyPosition:function(a){var b=this.elements;a=a.elements;b[12]=a[12];b[13]=a[13];b[14]=a[14];return this},extractBasis:function(a,b,c){a.setFromMatrixColumn(this,0);b.setFromMatrixColumn(this,1);c.setFromMatrixColumn(this,2);return this},makeBasis:function(a,b,c){this.set(a.x,b.x,c.x,0,a.y,b.y,c.y,0,a.z,b.z,c.z,0,0,0,0,1);return this},extractRotation:function(a){var b=this.elements,c=a.elements,d=1/pd.setFromMatrixColumn(a,0).length(),e=1/pd.setFromMatrixColumn(a, +1).length();a=1/pd.setFromMatrixColumn(a,2).length();b[0]=c[0]*d;b[1]=c[1]*d;b[2]=c[2]*d;b[3]=0;b[4]=c[4]*e;b[5]=c[5]*e;b[6]=c[6]*e;b[7]=0;b[8]=c[8]*a;b[9]=c[9]*a;b[10]=c[10]*a;b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return this},makeRotationFromEuler:function(a){a&&a.isEuler||console.error("THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.");var b=this.elements,c=a.x,d=a.y,e=a.z,f=Math.cos(c);c=Math.sin(c);var g=Math.cos(d);d=Math.sin(d);var k= +Math.cos(e);e=Math.sin(e);if("XYZ"===a.order){a=f*k;var l=f*e,m=c*k,h=c*e;b[0]=g*k;b[4]=-g*e;b[8]=d;b[1]=l+m*d;b[5]=a-h*d;b[9]=-c*g;b[2]=h-a*d;b[6]=m+l*d;b[10]=f*g}else"YXZ"===a.order?(a=g*k,l=g*e,m=d*k,h=d*e,b[0]=a+h*c,b[4]=m*c-l,b[8]=f*d,b[1]=f*e,b[5]=f*k,b[9]=-c,b[2]=l*c-m,b[6]=h+a*c,b[10]=f*g):"ZXY"===a.order?(a=g*k,l=g*e,m=d*k,h=d*e,b[0]=a-h*c,b[4]=-f*e,b[8]=m+l*c,b[1]=l+m*c,b[5]=f*k,b[9]=h-a*c,b[2]=-f*d,b[6]=c,b[10]=f*g):"ZYX"===a.order?(a=f*k,l=f*e,m=c*k,h=c*e,b[0]=g*k,b[4]=m*d-l,b[8]=a*d+ +h,b[1]=g*e,b[5]=h*d+a,b[9]=l*d-m,b[2]=-d,b[6]=c*g,b[10]=f*g):"YZX"===a.order?(a=f*g,l=f*d,m=c*g,h=c*d,b[0]=g*k,b[4]=h-a*e,b[8]=m*e+l,b[1]=e,b[5]=f*k,b[9]=-c*k,b[2]=-d*k,b[6]=l*e+m,b[10]=a-h*e):"XZY"===a.order&&(a=f*g,l=f*d,m=c*g,h=c*d,b[0]=g*k,b[4]=-e,b[8]=d*k,b[1]=a*e+h,b[5]=f*k,b[9]=l*e-m,b[2]=m*e-l,b[6]=c*k,b[10]=h*e+a);b[3]=0;b[7]=0;b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return this},makeRotationFromQuaternion:function(a){return this.compose(Rk,a,Sk)},lookAt:function(a,b,c){var d=this.elements; +la.subVectors(a,b);0===la.lengthSq()&&(la.z=1);la.normalize();Nb.crossVectors(c,la);0===Nb.lengthSq()&&(1===Math.abs(c.z)?la.x+=1E-4:la.z+=1E-4,la.normalize(),Nb.crossVectors(c,la));Nb.normalize();Df.crossVectors(la,Nb);d[0]=Nb.x;d[4]=Df.x;d[8]=la.x;d[1]=Nb.y;d[5]=Df.y;d[9]=la.y;d[2]=Nb.z;d[6]=Df.z;d[10]=la.z;return this},multiply:function(a,b){return void 0!==b?(console.warn("THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead."),this.multiplyMatrices(a, +b)):this.multiplyMatrices(this,a)},premultiply:function(a){return this.multiplyMatrices(a,this)},multiplyMatrices:function(a,b){var c=a.elements,d=b.elements;b=this.elements;a=c[0];var e=c[4],f=c[8],g=c[12],k=c[1],l=c[5],m=c[9],h=c[13],p=c[2],q=c[6],n=c[10],r=c[14],u=c[3],y=c[7],v=c[11];c=c[15];var w=d[0],A=d[4],B=d[8],z=d[12],E=d[1],D=d[5],F=d[9],I=d[13],G=d[2],K=d[6],L=d[10],M=d[14],N=d[3],O=d[7],P=d[11];d=d[15];b[0]=a*w+e*E+f*G+g*N;b[4]=a*A+e*D+f*K+g*O;b[8]=a*B+e*F+f*L+g*P;b[12]=a*z+e*I+f*M+g* +d;b[1]=k*w+l*E+m*G+h*N;b[5]=k*A+l*D+m*K+h*O;b[9]=k*B+l*F+m*L+h*P;b[13]=k*z+l*I+m*M+h*d;b[2]=p*w+q*E+n*G+r*N;b[6]=p*A+q*D+n*K+r*O;b[10]=p*B+q*F+n*L+r*P;b[14]=p*z+q*I+n*M+r*d;b[3]=u*w+y*E+v*G+c*N;b[7]=u*A+y*D+v*K+c*O;b[11]=u*B+y*F+v*L+c*P;b[15]=u*z+y*I+v*M+c*d;return this},multiplyScalar:function(a){var b=this.elements;b[0]*=a;b[4]*=a;b[8]*=a;b[12]*=a;b[1]*=a;b[5]*=a;b[9]*=a;b[13]*=a;b[2]*=a;b[6]*=a;b[10]*=a;b[14]*=a;b[3]*=a;b[7]*=a;b[11]*=a;b[15]*=a;return this},determinant:function(){var a=this.elements, +b=a[0],c=a[4],d=a[8],e=a[12],f=a[1],g=a[5],k=a[9],l=a[13],m=a[2],h=a[6],p=a[10],q=a[14];return a[3]*(+e*k*h-d*l*h-e*g*p+c*l*p+d*g*q-c*k*q)+a[7]*(+b*k*q-b*l*p+e*f*p-d*f*q+d*l*m-e*k*m)+a[11]*(+b*l*h-b*g*q-e*f*h+c*f*q+e*g*m-c*l*m)+a[15]*(-d*g*m-b*k*h+b*g*p+d*f*h-c*f*p+c*k*m)},transpose:function(){var a=this.elements;var b=a[1];a[1]=a[4];a[4]=b;b=a[2];a[2]=a[8];a[8]=b;b=a[6];a[6]=a[9];a[9]=b;b=a[3];a[3]=a[12];a[12]=b;b=a[7];a[7]=a[13];a[13]=b;b=a[11];a[11]=a[14];a[14]=b;return this},setPosition:function(a, +b,c){var d=this.elements;a.isVector3?(d[12]=a.x,d[13]=a.y,d[14]=a.z):(d[12]=a,d[13]=b,d[14]=c);return this},getInverse:function(a,b){var c=this.elements,d=a.elements;a=d[0];var e=d[1],f=d[2],g=d[3],k=d[4],l=d[5],m=d[6],h=d[7],p=d[8],q=d[9],n=d[10],r=d[11],u=d[12],y=d[13],v=d[14];d=d[15];var w=q*v*h-y*n*h+y*m*r-l*v*r-q*m*d+l*n*d,A=u*n*h-p*v*h-u*m*r+k*v*r+p*m*d-k*n*d,B=p*y*h-u*q*h+u*l*r-k*y*r-p*l*d+k*q*d,z=u*q*m-p*y*m-u*l*n+k*y*n+p*l*v-k*q*v,E=a*w+e*A+f*B+g*z;if(0===E){if(!0===b)throw Error("THREE.Matrix4: .getInverse() can't invert matrix, determinant is 0"); +console.warn("THREE.Matrix4: .getInverse() can't invert matrix, determinant is 0");return this.identity()}b=1/E;c[0]=w*b;c[1]=(y*n*g-q*v*g-y*f*r+e*v*r+q*f*d-e*n*d)*b;c[2]=(l*v*g-y*m*g+y*f*h-e*v*h-l*f*d+e*m*d)*b;c[3]=(q*m*g-l*n*g-q*f*h+e*n*h+l*f*r-e*m*r)*b;c[4]=A*b;c[5]=(p*v*g-u*n*g+u*f*r-a*v*r-p*f*d+a*n*d)*b;c[6]=(u*m*g-k*v*g-u*f*h+a*v*h+k*f*d-a*m*d)*b;c[7]=(k*n*g-p*m*g+p*f*h-a*n*h-k*f*r+a*m*r)*b;c[8]=B*b;c[9]=(u*q*g-p*y*g-u*e*r+a*y*r+p*e*d-a*q*d)*b;c[10]=(k*y*g-u*l*g+u*e*h-a*y*h-k*e*d+a*l*d)*b;c[11]= +(p*l*g-k*q*g-p*e*h+a*q*h+k*e*r-a*l*r)*b;c[12]=z*b;c[13]=(p*y*f-u*q*f+u*e*n-a*y*n-p*e*v+a*q*v)*b;c[14]=(u*l*f-k*y*f-u*e*m+a*y*m+k*e*v-a*l*v)*b;c[15]=(k*q*f-p*l*f+p*e*m-a*q*m-k*e*n+a*l*n)*b;return this},scale:function(a){var b=this.elements,c=a.x,d=a.y;a=a.z;b[0]*=c;b[4]*=d;b[8]*=a;b[1]*=c;b[5]*=d;b[9]*=a;b[2]*=c;b[6]*=d;b[10]*=a;b[3]*=c;b[7]*=d;b[11]*=a;return this},getMaxScaleOnAxis:function(){var a=this.elements;return Math.sqrt(Math.max(a[0]*a[0]+a[1]*a[1]+a[2]*a[2],a[4]*a[4]+a[5]*a[5]+a[6]*a[6], +a[8]*a[8]+a[9]*a[9]+a[10]*a[10]))},makeTranslation:function(a,b,c){this.set(1,0,0,a,0,1,0,b,0,0,1,c,0,0,0,1);return this},makeRotationX:function(a){var b=Math.cos(a);a=Math.sin(a);this.set(1,0,0,0,0,b,-a,0,0,a,b,0,0,0,0,1);return this},makeRotationY:function(a){var b=Math.cos(a);a=Math.sin(a);this.set(b,0,a,0,0,1,0,0,-a,0,b,0,0,0,0,1);return this},makeRotationZ:function(a){var b=Math.cos(a);a=Math.sin(a);this.set(b,-a,0,0,a,b,0,0,0,0,1,0,0,0,0,1);return this},makeRotationAxis:function(a,b){var c= +Math.cos(b);b=Math.sin(b);var d=1-c,e=a.x,f=a.y;a=a.z;var g=d*e,k=d*f;this.set(g*e+c,g*f-b*a,g*a+b*f,0,g*f+b*a,k*f+c,k*a-b*e,0,g*a-b*f,k*a+b*e,d*a*a+c,0,0,0,0,1);return this},makeScale:function(a,b,c){this.set(a,0,0,0,0,b,0,0,0,0,c,0,0,0,0,1);return this},makeShear:function(a,b,c){this.set(1,b,c,0,a,1,c,0,a,b,1,0,0,0,0,1);return this},compose:function(a,b,c){var d=this.elements,e=b._x,f=b._y,g=b._z,k=b._w,l=e+e,m=f+f,h=g+g;b=e*l;var p=e*m;e*=h;var n=f*m;f*=h;g*=h;l*=k;m*=k;k*=h;h=c.x;var t=c.y;c= +c.z;d[0]=(1-(n+g))*h;d[1]=(p+k)*h;d[2]=(e-m)*h;d[3]=0;d[4]=(p-k)*t;d[5]=(1-(b+g))*t;d[6]=(f+l)*t;d[7]=0;d[8]=(e+m)*c;d[9]=(f-l)*c;d[10]=(1-(b+n))*c;d[11]=0;d[12]=a.x;d[13]=a.y;d[14]=a.z;d[15]=1;return this},decompose:function(a,b,c){var d=this.elements,e=pd.set(d[0],d[1],d[2]).length(),f=pd.set(d[4],d[5],d[6]).length(),g=pd.set(d[8],d[9],d[10]).length();0>this.determinant()&&(e=-e);a.x=d[12];a.y=d[13];a.z=d[14];S.copy(this);a=1/e;d=1/f;var k=1/g;S.elements[0]*=a;S.elements[1]*=a;S.elements[2]*=a; +S.elements[4]*=d;S.elements[5]*=d;S.elements[6]*=d;S.elements[8]*=k;S.elements[9]*=k;S.elements[10]*=k;b.setFromRotationMatrix(S);c.x=e;c.y=f;c.z=g;return this},makePerspective:function(a,b,c,d,e,f){void 0===f&&console.warn("THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.");var g=this.elements;g[0]=2*e/(b-a);g[4]=0;g[8]=(b+a)/(b-a);g[12]=0;g[1]=0;g[5]=2*e/(c-d);g[9]=(c+d)/(c-d);g[13]=0;g[2]=0;g[6]=0;g[10]=-(f+e)/(f-e);g[14]=-2*f*e/(f-e);g[3]=0; +g[7]=0;g[11]=-1;g[15]=0;return this},makeOrthographic:function(a,b,c,d,e,f){var g=this.elements,k=1/(b-a),l=1/(c-d),m=1/(f-e);g[0]=2*k;g[4]=0;g[8]=0;g[12]=-((b+a)*k);g[1]=0;g[5]=2*l;g[9]=0;g[13]=-((c+d)*l);g[2]=0;g[6]=0;g[10]=-2*m;g[14]=-((f+e)*m);g[3]=0;g[7]=0;g[11]=0;g[15]=1;return this},equals:function(a){var b=this.elements;a=a.elements;for(var c=0;16>c;c++)if(b[c]!==a[c])return!1;return!0},fromArray:function(a,b){void 0===b&&(b=0);for(var c=0;16>c;c++)this.elements[c]=a[c+b];return this},toArray:function(a, +b){void 0===a&&(a=[]);void 0===b&&(b=0);var c=this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[5];a[b+6]=c[6];a[b+7]=c[7];a[b+8]=c[8];a[b+9]=c[9];a[b+10]=c[10];a[b+11]=c[11];a[b+12]=c[12];a[b+13]=c[13];a[b+14]=c[14];a[b+15]=c[15];return a}});var Ii=new O,Ji=new Da;Ub.RotationOrders="XYZ YZX ZXY XZY YXZ ZYX".split(" ");Ub.DefaultOrder="XYZ";Object.defineProperties(Ub.prototype,{x:{get:function(){return this._x},set:function(a){this._x=a;this._onChangeCallback()}},y:{get:function(){return this._y}, +set:function(a){this._y=a;this._onChangeCallback()}},z:{get:function(){return this._z},set:function(a){this._z=a;this._onChangeCallback()}},order:{get:function(){return this._order},set:function(a){this._order=a;this._onChangeCallback()}}});Object.assign(Ub.prototype,{isEuler:!0,set:function(a,b,c,d){this._x=a;this._y=b;this._z=c;this._order=d||this._order;this._onChangeCallback();return this},clone:function(){return new this.constructor(this._x,this._y,this._z,this._order)},copy:function(a){this._x= +a._x;this._y=a._y;this._z=a._z;this._order=a._order;this._onChangeCallback();return this},setFromRotationMatrix:function(a,b,c){var d=P.clamp,e=a.elements;a=e[0];var f=e[4],g=e[8],k=e[1],l=e[5],m=e[9],h=e[2],p=e[6];e=e[10];b=b||this._order;"XYZ"===b?(this._y=Math.asin(d(g,-1,1)),.9999999>Math.abs(g)?(this._x=Math.atan2(-m,e),this._z=Math.atan2(-f,a)):(this._x=Math.atan2(p,l),this._z=0)):"YXZ"===b?(this._x=Math.asin(-d(m,-1,1)),.9999999>Math.abs(m)?(this._y=Math.atan2(g,e),this._z=Math.atan2(k,l)): +(this._y=Math.atan2(-h,a),this._z=0)):"ZXY"===b?(this._x=Math.asin(d(p,-1,1)),.9999999>Math.abs(p)?(this._y=Math.atan2(-h,e),this._z=Math.atan2(-f,l)):(this._y=0,this._z=Math.atan2(k,a))):"ZYX"===b?(this._y=Math.asin(-d(h,-1,1)),.9999999>Math.abs(h)?(this._x=Math.atan2(p,e),this._z=Math.atan2(k,a)):(this._x=0,this._z=Math.atan2(-f,l))):"YZX"===b?(this._z=Math.asin(d(k,-1,1)),.9999999>Math.abs(k)?(this._x=Math.atan2(-m,l),this._y=Math.atan2(-h,a)):(this._x=0,this._y=Math.atan2(g,e))):"XZY"===b?(this._z= +Math.asin(-d(f,-1,1)),.9999999>Math.abs(f)?(this._x=Math.atan2(p,l),this._y=Math.atan2(g,a)):(this._x=Math.atan2(-m,e),this._y=0)):console.warn("THREE.Euler: .setFromRotationMatrix() given unsupported order: "+b);this._order=b;!1!==c&&this._onChangeCallback();return this},setFromQuaternion:function(a,b,c){Ii.makeRotationFromQuaternion(a);return this.setFromRotationMatrix(Ii,b,c)},setFromVector3:function(a,b){return this.set(a.x,a.y,a.z,b||this._order)},reorder:function(a){Ji.setFromEuler(this);return this.setFromQuaternion(Ji, +a)},equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._order===this._order},fromArray:function(a){this._x=a[0];this._y=a[1];this._z=a[2];void 0!==a[3]&&(this._order=a[3]);this._onChangeCallback();return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this._x;a[b+1]=this._y;a[b+2]=this._z;a[b+3]=this._order;return a},toVector3:function(a){return a?a.set(this._x,this._y,this._z):new n(this._x,this._y,this._z)},_onChange:function(a){this._onChangeCallback= +a;return this},_onChangeCallback:function(){}});Object.assign(ag.prototype,{set:function(a){this.mask=1<e&&(e=h);n>f&&(f=n);p>g&&(g=p)}this.min.set(b,c,d);this.max.set(e,f,g);return this},setFromBufferAttribute:function(a){for(var b=Infinity,c=Infinity,d=Infinity,e=-Infinity,f=-Infinity,g=-Infinity,k=0,l=a.count;ke&&(e=h);n>f&&(f=n);p>g&&(g=p)}this.min.set(b,c,d);this.max.set(e,f,g);return this},setFromPoints:function(a){this.makeEmpty();for(var b=0,c=a.length;bthis.max.x||a.y< +this.min.y||a.y>this.max.y||a.zthis.max.z?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y&&this.min.z<=a.min.z&&a.max.z<=this.max.z},getParameter:function(a,b){void 0===b&&(console.warn("THREE.Box3: .getParameter() target is now required"),b=new n);return b.set((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y),(a.z-this.min.z)/(this.max.z-this.min.z))},intersectsBox:function(a){return a.max.x< +this.min.x||a.min.x>this.max.x||a.max.ythis.max.y||a.max.zthis.max.z?!1:!0},intersectsSphere:function(a){this.clampPoint(a.center,Ce);return Ce.distanceToSquared(a.center)<=a.radius*a.radius},intersectsPlane:function(a){if(0=-a.constant},intersectsTriangle:function(a){if(this.isEmpty())return!1;this.getCenter(De);Gf.subVectors(this.max,De);rd.subVectors(a.a,De);sd.subVectors(a.b,De);td.subVectors(a.c,De);Ob.subVectors(sd,rd);Pb.subVectors(td,sd);sc.subVectors(rd,td);a=[0,-Ob.z,Ob.y,0,-Pb.z,Pb.y,0,-sc.z,sc.y,Ob.z,0,-Ob.x,Pb.z,0,-Pb.x,sc.z,0,-sc.x,-Ob.y,Ob.x,0,-Pb.y,Pb.x,0,-sc.y, +sc.x,0];if(!bg(a,rd,sd,td,Gf))return!1;a=[1,0,0,0,1,0,0,0,1];if(!bg(a,rd,sd,td,Gf))return!1;Hf.crossVectors(Ob,Pb);a=[Hf.x,Hf.y,Hf.z];return bg(a,rd,sd,td,Gf)},clampPoint:function(a,b){void 0===b&&(console.warn("THREE.Box3: .clampPoint() target is now required"),b=new n);return b.copy(a).clamp(this.min,this.max)},distanceToPoint:function(a){return Ce.copy(a).clamp(this.min,this.max).sub(a).length()},getBoundingSphere:function(a){void 0===a&&console.error("THREE.Box3: .getBoundingSphere() target is now required"); +this.getCenter(a.center);a.radius=.5*this.getSize(Ce).length();return a},intersect:function(a){this.min.max(a.min);this.max.min(a.max);this.isEmpty()&&this.makeEmpty();return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},applyMatrix4:function(a){if(this.isEmpty())return this;Ab[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(a);Ab[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(a);Ab[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(a);Ab[3].set(this.min.x, +this.max.y,this.max.z).applyMatrix4(a);Ab[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(a);Ab[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(a);Ab[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(a);Ab[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(a);this.setFromPoints(Ab);return this},translate:function(a){this.min.add(a);this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)}});var Xk=new Ta;Object.assign(qb.prototype,{set:function(a, +b){this.center.copy(a);this.radius=b;return this},setFromPoints:function(a,b){var c=this.center;void 0!==b?c.copy(b):Xk.setFromPoints(a).getCenter(c);for(var d=b=0,e=a.length;d=this.radius},containsPoint:function(a){return a.distanceToSquared(this.center)<= +this.radius*this.radius},distanceToPoint:function(a){return a.distanceTo(this.center)-this.radius},intersectsSphere:function(a){var b=this.radius+a.radius;return a.center.distanceToSquared(this.center)<=b*b},intersectsBox:function(a){return a.intersectsSphere(this)},intersectsPlane:function(a){return Math.abs(a.distanceToPoint(this.center))<=this.radius},clampPoint:function(a,b){var c=this.center.distanceToSquared(a);void 0===b&&(console.warn("THREE.Sphere: .clampPoint() target is now required"), +b=new n);b.copy(a);c>this.radius*this.radius&&(b.sub(this.center).normalize(),b.multiplyScalar(this.radius).add(this.center));return b},getBoundingBox:function(a){void 0===a&&(console.warn("THREE.Sphere: .getBoundingBox() target is now required"),a=new Ta);a.set(this.center,this.center);a.expandByScalar(this.radius);return a},applyMatrix4:function(a){this.center.applyMatrix4(a);this.radius*=a.getMaxScaleOnAxis();return this},translate:function(a){this.center.add(a);return this},equals:function(a){return a.center.equals(this.center)&& +a.radius===this.radius}});var Bb=new n,ch=new n,If=new n,Qb=new n,dh=new n,Jf=new n,eh=new n;Object.assign(Wb.prototype,{set:function(a,b){this.origin.copy(a);this.direction.copy(b);return this},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.origin.copy(a.origin);this.direction.copy(a.direction);return this},at:function(a,b){void 0===b&&(console.warn("THREE.Ray: .at() target is now required"),b=new n);return b.copy(this.direction).multiplyScalar(a).add(this.origin)}, +lookAt:function(a){this.direction.copy(a).sub(this.origin).normalize();return this},recast:function(a){this.origin.copy(this.at(a,Bb));return this},closestPointToPoint:function(a,b){void 0===b&&(console.warn("THREE.Ray: .closestPointToPoint() target is now required"),b=new n);b.subVectors(a,this.origin);a=b.dot(this.direction);return 0>a?b.copy(this.origin):b.copy(this.direction).multiplyScalar(a).add(this.origin)},distanceToPoint:function(a){return Math.sqrt(this.distanceSqToPoint(a))},distanceSqToPoint:function(a){var b= +Bb.subVectors(a,this.origin).dot(this.direction);if(0>b)return this.origin.distanceToSquared(a);Bb.copy(this.direction).multiplyScalar(b).add(this.origin);return Bb.distanceToSquared(a)},distanceSqToSegment:function(a,b,c,d){ch.copy(a).add(b).multiplyScalar(.5);If.copy(b).sub(a).normalize();Qb.copy(this.origin).sub(ch);var e=.5*a.distanceTo(b),f=-this.direction.dot(If),g=Qb.dot(this.direction),k=-Qb.dot(If),l=Qb.lengthSq(),h=Math.abs(1-f*f);if(0=-n?b<=n?(e=1/h, +a*=e,b*=e,f=a*(a+f*b+2*g)+b*(f*a+b+2*k)+l):(b=e,a=Math.max(0,-(f*b+g)),f=-a*a+b*(b+2*k)+l):(b=-e,a=Math.max(0,-(f*b+g)),f=-a*a+b*(b+2*k)+l):b<=-n?(a=Math.max(0,-(-f*e+g)),b=0a)return null;a=Math.sqrt(a-d);d=c-a;c+=a;return 0>d&&0>c?null:0>d?this.at(c,b):this.at(d,b)},intersectsSphere:function(a){return this.distanceSqToPoint(a.center)<=a.radius*a.radius},distanceToPlane:function(a){var b=a.normal.dot(this.direction);if(0===b)return 0===a.distanceToPoint(this.origin)?0:null;a=-(this.origin.dot(a.normal)+a.constant)/b;return 0<= +a?a:null},intersectPlane:function(a,b){a=this.distanceToPlane(a);return null===a?null:this.at(a,b)},intersectsPlane:function(a){var b=a.distanceToPoint(this.origin);return 0===b||0>a.normal.dot(this.direction)*b?!0:!1},intersectBox:function(a,b){var c=1/this.direction.x;var d=1/this.direction.y;var e=1/this.direction.z,f=this.origin;if(0<=c){var g=(a.min.x-f.x)*c;c*=a.max.x-f.x}else g=(a.max.x-f.x)*c,c*=a.min.x-f.x;if(0<=d){var k=(a.min.y-f.y)*d;d*=a.max.y-f.y}else k=(a.max.y-f.y)*d,d*=a.min.y-f.y; +if(g>d||k>c)return null;if(k>g||g!==g)g=k;if(da||k>c)return null;if(k>g||g!==g)g=k;if(ac?null:this.at(0<=g?g:c,b)},intersectsBox:function(a){return null!==this.intersectBox(a,Bb)},intersectTriangle:function(a,b,c,d,e){dh.subVectors(b,a);Jf.subVectors(c,a);eh.crossVectors(dh,Jf);b=this.direction.dot(eh);if(0b)d=-1,b=-b;else return null;Qb.subVectors(this.origin, +a);a=d*this.direction.dot(Jf.crossVectors(Qb,Jf));if(0>a)return null;c=d*this.direction.dot(dh.cross(Qb));if(0>c||a+c>b)return null;a=-d*Qb.dot(eh);return 0>a?null:this.at(a/b,e)},applyMatrix4:function(a){this.origin.applyMatrix4(a);this.direction.transformDirection(a);return this},equals:function(a){return a.origin.equals(this.origin)&&a.direction.equals(this.direction)}});var fh=new n,Yk=new n,Zk=new za;Object.assign(Ua.prototype,{isPlane:!0,set:function(a,b){this.normal.copy(a);this.constant=b; +return this},setComponents:function(a,b,c,d){this.normal.set(a,b,c);this.constant=d;return this},setFromNormalAndCoplanarPoint:function(a,b){this.normal.copy(a);this.constant=-b.dot(this.normal);return this},setFromCoplanarPoints:function(a,b,c){b=fh.subVectors(c,b).cross(Yk.subVectors(a,b)).normalize();this.setFromNormalAndCoplanarPoint(b,a);return this},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.normal.copy(a.normal);this.constant=a.constant;return this},normalize:function(){var a= +1/this.normal.length();this.normal.multiplyScalar(a);this.constant*=a;return this},negate:function(){this.constant*=-1;this.normal.negate();return this},distanceToPoint:function(a){return this.normal.dot(a)+this.constant},distanceToSphere:function(a){return this.distanceToPoint(a.center)-a.radius},projectPoint:function(a,b){void 0===b&&(console.warn("THREE.Plane: .projectPoint() target is now required"),b=new n);return b.copy(this.normal).multiplyScalar(-this.distanceToPoint(a)).add(a)},intersectLine:function(a, +b){void 0===b&&(console.warn("THREE.Plane: .intersectLine() target is now required"),b=new n);var c=a.delta(fh),d=this.normal.dot(c);if(0===d){if(0===this.distanceToPoint(a.start))return b.copy(a.start)}else if(d=-(a.start.dot(this.normal)+this.constant)/d,!(0>d||1b&&0a&&0=Db.x+Db.y},getUV:function(a,b,c,d,e,f,g,k){this.getBarycoord(a,b,c,d,Db);k.set(0,0);k.addScaledVector(e,Db.x);k.addScaledVector(f,Db.y);k.addScaledVector(g,Db.z);return k},isFrontFacing:function(a,b,c,d){cb.subVectors(c, +b);Cb.subVectors(a,b);return 0>cb.cross(Cb).dot(d)?!0:!1}});Object.assign(oa.prototype,{set:function(a,b,c){this.a.copy(a);this.b.copy(b);this.c.copy(c);return this},setFromPointsAndIndices:function(a,b,c,d){this.a.copy(a[b]);this.b.copy(a[c]);this.c.copy(a[d]);return this},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.a.copy(a.a);this.b.copy(a.b);this.c.copy(a.c);return this},getArea:function(){cb.subVectors(this.c,this.b);Cb.subVectors(this.a,this.b);return.5*cb.cross(Cb).length()}, +getMidpoint:function(a){void 0===a&&(console.warn("THREE.Triangle: .getMidpoint() target is now required"),a=new n);return a.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)},getNormal:function(a){return oa.getNormal(this.a,this.b,this.c,a)},getPlane:function(a){void 0===a&&(console.warn("THREE.Triangle: .getPlane() target is now required"),a=new Ua);return a.setFromCoplanarPoints(this.a,this.b,this.c)},getBarycoord:function(a,b){return oa.getBarycoord(a,this.a,this.b,this.c,b)},getUV:function(a, +b,c,d,e){return oa.getUV(a,this.a,this.b,this.c,b,c,d,e)},containsPoint:function(a){return oa.containsPoint(a,this.a,this.b,this.c)},isFrontFacing:function(a){return oa.isFrontFacing(this.a,this.b,this.c,a)},intersectsBox:function(a){return a.intersectsTriangle(this)},closestPointToPoint:function(a,b){void 0===b&&(console.warn("THREE.Triangle: .closestPointToPoint() target is now required"),b=new n);var c=this.a,d=this.b,e=this.c;ud.subVectors(d,c);vd.subVectors(e,c);hh.subVectors(a,c);var f=ud.dot(hh), +g=vd.dot(hh);if(0>=f&&0>=g)return b.copy(c);ih.subVectors(a,d);var k=ud.dot(ih),l=vd.dot(ih);if(0<=k&&l<=k)return b.copy(d);var h=f*l-k*g;if(0>=h&&0<=f&&0>=k)return d=f/(f-k),b.copy(c).addScaledVector(ud,d);jh.subVectors(a,e);a=ud.dot(jh);var x=vd.dot(jh);if(0<=x&&a<=x)return b.copy(e);f=a*g-f*x;if(0>=f&&0<=g&&0>=x)return h=g/(g-x),b.copy(c).addScaledVector(vd,h);g=k*x-a*l;if(0>=g&&0<=l-k&&0<=a-x)return Oi.subVectors(e,d),h=(l-k)/(l-k+(a-x)),b.copy(d).addScaledVector(Oi,h);e=1/(g+f+h);d=f*e;h*=e; +return b.copy(c).addScaledVector(ud,d).addScaledVector(vd,h)},equals:function(a){return a.a.equals(this.a)&&a.b.equals(this.b)&&a.c.equals(this.c)}});var Pi={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535, +darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842, +fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762, +lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685, +navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256, +skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074},Ca={h:0,s:0,l:0},Kf={h:0,s:0,l:0};Object.assign(B.prototype,{isColor:!0,r:1,g:1,b:1,set:function(a){a&&a.isColor?this.copy(a):"number"===typeof a?this.setHex(a):"string"===typeof a&&this.setStyle(a);return this}, +setScalar:function(a){this.b=this.g=this.r=a;return this},setHex:function(a){a=Math.floor(a);this.r=(a>>16&255)/255;this.g=(a>>8&255)/255;this.b=(a&255)/255;return this},setRGB:function(a,b,c){this.r=a;this.g=b;this.b=c;return this},setHSL:function(a,b,c){a=P.euclideanModulo(a,1);b=P.clamp(b,0,1);c=P.clamp(c,0,1);0===b?this.r=this.g=this.b=c:(b=.5>=c?c*(1+b):c+b-c*b,c=2*c-b,this.r=cg(c,b,a+1/3),this.g=cg(c,b,a),this.b=cg(c,b,a-1/3));return this},setStyle:function(a){function b(b){void 0!==b&&1>parseFloat(b)&& +console.warn("THREE.Color: Alpha component of "+a+" will be ignored.")}var c;if(c=/^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec(a)){var d=c[2];switch(c[1]){case "rgb":case "rgba":if(c=/^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(d))return this.r=Math.min(255,parseInt(c[1],10))/255,this.g=Math.min(255,parseInt(c[2],10))/255,this.b=Math.min(255,parseInt(c[3],10))/255,b(c[5]),this;if(c=/^(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(d))return this.r=Math.min(100, +parseInt(c[1],10))/100,this.g=Math.min(100,parseInt(c[2],10))/100,this.b=Math.min(100,parseInt(c[3],10))/100,b(c[5]),this;break;case "hsl":case "hsla":if(c=/^([0-9]*\.?[0-9]+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(d)){d=parseFloat(c[1])/360;var e=parseInt(c[2],10)/100,f=parseInt(c[3],10)/100;b(c[5]);return this.setHSL(d,e,f)}}}else if(c=/^#([A-Fa-f0-9]+)$/.exec(a)){c=c[1];d=c.length;if(3===d)return this.r=parseInt(c.charAt(0)+c.charAt(0),16)/255,this.g=parseInt(c.charAt(1)+ +c.charAt(1),16)/255,this.b=parseInt(c.charAt(2)+c.charAt(2),16)/255,this;if(6===d)return this.r=parseInt(c.charAt(0)+c.charAt(1),16)/255,this.g=parseInt(c.charAt(2)+c.charAt(3),16)/255,this.b=parseInt(c.charAt(4)+c.charAt(5),16)/255,this}return a&&0=k?l/(e+f):l/(2-e-f);switch(e){case b:g=(c-d)/l+(cthis.opacity&&(d.opacity=this.opacity);!0===this.transparent&&(d.transparent=this.transparent);d.depthFunc=this.depthFunc;d.depthTest=this.depthTest;d.depthWrite=this.depthWrite;d.stencilWrite=this.stencilWrite;d.stencilWriteMask=this.stencilWriteMask;d.stencilFunc=this.stencilFunc;d.stencilRef=this.stencilRef;d.stencilFuncMask=this.stencilFuncMask;d.stencilFail=this.stencilFail;d.stencilZFail=this.stencilZFail;d.stencilZPass=this.stencilZPass;this.rotation&&0!==this.rotation&& +(d.rotation=this.rotation);!0===this.polygonOffset&&(d.polygonOffset=!0);0!==this.polygonOffsetFactor&&(d.polygonOffsetFactor=this.polygonOffsetFactor);0!==this.polygonOffsetUnits&&(d.polygonOffsetUnits=this.polygonOffsetUnits);this.linewidth&&1!==this.linewidth&&(d.linewidth=this.linewidth);void 0!==this.dashSize&&(d.dashSize=this.dashSize);void 0!==this.gapSize&&(d.gapSize=this.gapSize);void 0!==this.scale&&(d.scale=this.scale);!0===this.dithering&&(d.dithering=!0);0g;g++)if(d[g]===d[(g+1)%3]){a.push(f);break}for(f=a.length-1;0<=f;f--)for(d=a[f],this.faces.splice(d,1),c=0,e=this.faceVertexUvs.length;c\n\t#include \n}",fragmentShader:"uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#define RECIPROCAL_PI 0.31830988618\n#define RECIPROCAL_PI2 0.15915494\nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV;\n\tsampleUV.y = asin( clamp( direction.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n}", +side:1,blending:0});d.uniforms.tEquirect.value=b;b=new ca(new Kd(5,5,5),d);c.add(b);d=new Gc(1,10,1);d.renderTarget=this;d.renderTarget.texture.name="CubeCameraTexture";d.update(a,c);b.geometry.dispose();b.material.dispose();return this};bc.prototype=Object.create(Z.prototype);bc.prototype.constructor=bc;bc.prototype.isDataTexture=!0;var xd=new qb,Mf=new n;Object.assign(Hc.prototype,{set:function(a,b,c,d,e,f){var g=this.planes;g[0].copy(a);g[1].copy(b);g[2].copy(c);g[3].copy(d);g[4].copy(e);g[5].copy(f); +return this},clone:function(){return(new this.constructor).copy(this)},copy:function(a){for(var b=this.planes,c=0;6>c;c++)b[c].copy(a.planes[c]);return this},setFromProjectionMatrix:function(a){var b=this.planes,c=a.elements;a=c[0];var d=c[1],e=c[2],f=c[3],g=c[4],k=c[5],h=c[6],m=c[7],n=c[8],p=c[9],q=c[10],t=c[11],r=c[12],u=c[13],y=c[14];c=c[15];b[0].setComponents(f-a,m-g,t-n,c-r).normalize();b[1].setComponents(f+a,m+g,t+n,c+r).normalize();b[2].setComponents(f+d,m+k,t+p,c+u).normalize();b[3].setComponents(f- +d,m-k,t-p,c-u).normalize();b[4].setComponents(f-e,m-h,t-q,c-y).normalize();b[5].setComponents(f+e,m+h,t+q,c+y).normalize();return this},intersectsObject:function(a){var b=a.geometry;null===b.boundingSphere&&b.computeBoundingSphere();xd.copy(b.boundingSphere).applyMatrix4(a.matrixWorld);return this.intersectsSphere(xd)},intersectsSprite:function(a){xd.center.set(0,0,0);xd.radius=.7071067811865476;xd.applyMatrix4(a.matrixWorld);return this.intersectsSphere(xd)},intersectsSphere:function(a){var b=this.planes, +c=a.center;a=-a.radius;for(var d=0;6>d;d++)if(b[d].distanceToPoint(c)c;c++){var d=b[c];Mf.x=0d.distanceToPoint(Mf))return!1}return!0},containsPoint:function(a){for(var b=this.planes,c=0;6>c;c++)if(0>b[c].distanceToPoint(a))return!1;return!0}});var F={common:{diffuse:{value:new B(15658734)},opacity:{value:1},map:{value:null}, +uvTransform:{value:new za},uv2Transform:{value:new za},alphaMap:{value:null}},specularmap:{specularMap:{value:null}},envmap:{envMap:{value:null},flipEnvMap:{value:-1},reflectivity:{value:1},refractionRatio:{value:.98},maxMipLevel:{value:0}},aomap:{aoMap:{value:null},aoMapIntensity:{value:1}},lightmap:{lightMap:{value:null},lightMapIntensity:{value:1}},emissivemap:{emissiveMap:{value:null}},bumpmap:{bumpMap:{value:null},bumpScale:{value:1}},normalmap:{normalMap:{value:null},normalScale:{value:new w(1, +1)}},displacementmap:{displacementMap:{value:null},displacementScale:{value:1},displacementBias:{value:0}},roughnessmap:{roughnessMap:{value:null}},metalnessmap:{metalnessMap:{value:null}},gradientmap:{gradientMap:{value:null}},fog:{fogDensity:{value:2.5E-4},fogNear:{value:1},fogFar:{value:2E3},fogColor:{value:new B(16777215)}},lights:{ambientLightColor:{value:[]},lightProbe:{value:[]},directionalLights:{value:[],properties:{direction:{},color:{},shadow:{},shadowBias:{},shadowRadius:{},shadowMapSize:{}}}, +directionalShadowMap:{value:[]},directionalShadowMatrix:{value:[]},spotLights:{value:[],properties:{color:{},position:{},direction:{},distance:{},coneCos:{},penumbraCos:{},decay:{},shadow:{},shadowBias:{},shadowRadius:{},shadowMapSize:{}}},spotShadowMap:{value:[]},spotShadowMatrix:{value:[]},pointLights:{value:[],properties:{color:{},position:{},decay:{},distance:{},shadow:{},shadowBias:{},shadowRadius:{},shadowMapSize:{},shadowCameraNear:{},shadowCameraFar:{}}},pointShadowMap:{value:[]},pointShadowMatrix:{value:[]}, +hemisphereLights:{value:[],properties:{direction:{},skyColor:{},groundColor:{}}},rectAreaLights:{value:[],properties:{color:{},position:{},width:{},height:{}}}},points:{diffuse:{value:new B(15658734)},opacity:{value:1},size:{value:1},scale:{value:1},map:{value:null},alphaMap:{value:null},uvTransform:{value:new za}},sprite:{diffuse:{value:new B(15658734)},opacity:{value:1},center:{value:new w(.5,.5)},rotation:{value:0},map:{value:null},alphaMap:{value:null},uvTransform:{value:new za}}};Jd.prototype= +Object.create(L.prototype);Jd.prototype.constructor=Jd;cc.prototype=Object.create(A.prototype);cc.prototype.constructor=cc;var N={alphamap_fragment:"#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif",alphamap_pars_fragment:"#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif",alphatest_fragment:"#ifdef ALPHATEST\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n#endif",aomap_fragment:"#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( STANDARD )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.specularRoughness );\n\t#endif\n#endif", +aomap_pars_fragment:"#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif",begin_vertex:"vec3 transformed = vec3( position );",beginnormal_vertex:"vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif",bsdfs:"vec2 integrateSpecularBRDF( const in float dotNV, const in float roughness ) {\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\treturn vec2( -1.04, 1.04 ) * a004 + r.zw;\n}\nfloat punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\tif( cutoffDistance > 0.0 ) {\n\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t}\n\treturn distanceFalloff;\n#else\n\tif( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t}\n\treturn 1.0;\n#endif\n}\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\n}\nvec3 F_Schlick_RoughnessDependent( const in vec3 F0, const in float dotNV, const in float roughness ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotNV - 6.98316 ) * dotNV );\n\tvec3 Fr = max( vec3( 1.0 - roughness ), F0 ) - F0;\n\treturn Fr * fresnel + F0;\n}\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\treturn 1.0 / ( gl * gv );\n}\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + viewDir );\n\tfloat dotNL = saturate( dot( normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( G * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\nvec3 BRDF_Specular_GGX_Environment( const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tvec2 brdf = integrateSpecularBRDF( dotNV, roughness );\n\treturn specularColor * brdf.x + brdf.y;\n}\nvoid BRDF_Specular_Multiscattering_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tvec3 F = F_Schlick_RoughnessDependent( specularColor, dotNV, roughness );\n\tvec2 brdf = integrateSpecularBRDF( dotNV, roughness );\n\tvec3 FssEss = F * brdf.x + brdf.y;\n\tfloat Ess = brdf.x + brdf.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = specularColor + ( 1.0 - specularColor ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\n}\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie(float roughness, float NoH) {\n\tfloat invAlpha = 1.0 / roughness;\n\tfloat cos2h = NoH * NoH;\n\tfloat sin2h = max(1.0 - cos2h, 0.0078125);\treturn (2.0 + invAlpha) * pow(sin2h, invAlpha * 0.5) / (2.0 * PI);\n}\nfloat V_Neubelt(float NoV, float NoL) {\n\treturn saturate(1.0 / (4.0 * (NoL + NoV - NoL * NoV)));\n}\nvec3 BRDF_Specular_Sheen( const in float roughness, const in vec3 L, const in GeometricContext geometry, vec3 specularColor ) {\n\tvec3 N = geometry.normal;\n\tvec3 V = geometry.viewDir;\n\tvec3 H = normalize( V + L );\n\tfloat dotNH = saturate( dot( N, H ) );\n\treturn specularColor * D_Charlie( roughness, dotNH ) * V_Neubelt( dot(N, V), dot(N, L) );\n}\n#endif", +bumpmap_pars_fragment:"#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\t\tvec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) );\n\t\tvec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\t\tfDet *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif", +clipping_planes_fragment:"#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\tplane = clippingPlanes[ i ];\n\t\tif ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\t#pragma unroll_loop\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\tif ( clipped ) discard;\n\t#endif\n#endif", +clipping_planes_pars_fragment:"#if NUM_CLIPPING_PLANES > 0\n\t#if ! defined( STANDARD ) && ! defined( PHONG ) && ! defined( MATCAP )\n\t\tvarying vec3 vViewPosition;\n\t#endif\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif",clipping_planes_pars_vertex:"#if NUM_CLIPPING_PLANES > 0 && ! defined( STANDARD ) && ! defined( PHONG ) && ! defined( MATCAP )\n\tvarying vec3 vViewPosition;\n#endif",clipping_planes_vertex:"#if NUM_CLIPPING_PLANES > 0 && ! defined( STANDARD ) && ! defined( PHONG ) && ! defined( MATCAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif", +color_fragment:"#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif",color_pars_fragment:"#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif",color_pars_vertex:"#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif",color_vertex:"#ifdef USE_COLOR\n\tvColor.xyz = color.xyz;\n#endif",common:"#define PI 3.14159265359\n#define PI2 6.28318530718\n#define PI_HALF 1.5707963267949\n#define RECIPROCAL_PI 0.31830988618\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement(a) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract(sin(sn) * c);\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat max3( vec3 v ) { return max( max( v.x, v.y ), v.z ); }\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n#ifdef CLEARCOAT\n\tvec3 clearcoatNormal;\n#endif\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\tfloat distance = dot( planeNormal, point - pointOnPlane );\n\treturn - distance * planeNormal + point;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat linearToRelativeLuminance( const in vec3 color ) {\n\tvec3 weights = vec3( 0.2126, 0.7152, 0.0722 );\n\treturn dot( weights, color.rgb );\n}\nbool isPerspectiveMatrix( mat4 m ) {\n return m[ 2 ][ 3 ] == - 1.0;\n}", +cube_uv_reflection_fragment:"#ifdef ENVMAP_TYPE_CUBE_UV\n#define cubeUV_maxMipLevel 8.0\n#define cubeUV_minMipLevel 4.0\n#define cubeUV_maxTileSize 256.0\n#define cubeUV_minTileSize 16.0\nfloat getFace(vec3 direction) {\n vec3 absDirection = abs(direction);\n float face = -1.0;\n if (absDirection.x > absDirection.z) {\n if (absDirection.x > absDirection.y)\n face = direction.x > 0.0 ? 0.0 : 3.0;\n else\n face = direction.y > 0.0 ? 1.0 : 4.0;\n } else {\n if (absDirection.z > absDirection.y)\n face = direction.z > 0.0 ? 2.0 : 5.0;\n else\n face = direction.y > 0.0 ? 1.0 : 4.0;\n }\n return face;\n}\nvec2 getUV(vec3 direction, float face) {\n vec2 uv;\n if (face == 0.0) {\n uv = vec2(-direction.z, direction.y) / abs(direction.x);\n } else if (face == 1.0) {\n uv = vec2(direction.x, -direction.z) / abs(direction.y);\n } else if (face == 2.0) {\n uv = direction.xy / abs(direction.z);\n } else if (face == 3.0) {\n uv = vec2(direction.z, direction.y) / abs(direction.x);\n } else if (face == 4.0) {\n uv = direction.xz / abs(direction.y);\n } else {\n uv = vec2(-direction.x, direction.y) / abs(direction.z);\n }\n return 0.5 * (uv + 1.0);\n}\nvec3 bilinearCubeUV(sampler2D envMap, vec3 direction, float mipInt) {\n float face = getFace(direction);\n float filterInt = max(cubeUV_minMipLevel - mipInt, 0.0);\n mipInt = max(mipInt, cubeUV_minMipLevel);\n float faceSize = exp2(mipInt);\n float texelSize = 1.0 / (3.0 * cubeUV_maxTileSize);\n vec2 uv = getUV(direction, face) * (faceSize - 1.0);\n vec2 f = fract(uv);\n uv += 0.5 - f;\n if (face > 2.0) {\n uv.y += faceSize;\n face -= 3.0;\n }\n uv.x += face * faceSize;\n if(mipInt < cubeUV_maxMipLevel){\n uv.y += 2.0 * cubeUV_maxTileSize;\n }\n uv.y += filterInt * 2.0 * cubeUV_minTileSize;\n uv.x += 3.0 * max(0.0, cubeUV_maxTileSize - 2.0 * faceSize);\n uv *= texelSize;\n vec3 tl = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n uv.x += texelSize;\n vec3 tr = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n uv.y += texelSize;\n vec3 br = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n uv.x -= texelSize;\n vec3 bl = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n vec3 tm = mix(tl, tr, f.x);\n vec3 bm = mix(bl, br, f.x);\n return mix(tm, bm, f.y);\n}\n#define r0 1.0\n#define v0 0.339\n#define m0 -2.0\n#define r1 0.8\n#define v1 0.276\n#define m1 -1.0\n#define r4 0.4\n#define v4 0.046\n#define m4 2.0\n#define r5 0.305\n#define v5 0.016\n#define m5 3.0\n#define r6 0.21\n#define v6 0.0038\n#define m6 4.0\nfloat roughnessToMip(float roughness) {\n float mip = 0.0;\n if (roughness >= r1) {\n mip = (r0 - roughness) * (m1 - m0) / (r0 - r1) + m0;\n } else if (roughness >= r4) {\n mip = (r1 - roughness) * (m4 - m1) / (r1 - r4) + m1;\n } else if (roughness >= r5) {\n mip = (r4 - roughness) * (m5 - m4) / (r4 - r5) + m4;\n } else if (roughness >= r6) {\n mip = (r5 - roughness) * (m6 - m5) / (r5 - r6) + m5;\n } else {\n mip = -2.0 * log2(1.16 * roughness); }\n return mip;\n}\nvec4 textureCubeUV(sampler2D envMap, vec3 sampleDir, float roughness) {\n float mip = clamp(roughnessToMip(roughness), m0, cubeUV_maxMipLevel);\n float mipF = fract(mip);\n float mipInt = floor(mip);\n vec3 color0 = bilinearCubeUV(envMap, sampleDir, mipInt);\n if (mipF == 0.0) {\n return vec4(color0, 1.0);\n } else {\n vec3 color1 = bilinearCubeUV(envMap, sampleDir, mipInt + 1.0);\n return vec4(mix(color0, color1, mipF), 1.0);\n }\n}\n#endif", +defaultnormal_vertex:"vec3 transformedNormal = objectNormal;\n#ifdef USE_INSTANCING\n\ttransformedNormal = mat3( instanceMatrix ) * transformedNormal;\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = ( modelViewMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif",displacementmap_pars_vertex:"#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif", +displacementmap_vertex:"#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vUv ).x * displacementScale + displacementBias );\n#endif",emissivemap_fragment:"#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif",emissivemap_pars_fragment:"#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif", +encodings_fragment:"gl_FragColor = linearToOutputTexel( gl_FragColor );",encodings_pars_fragment:"\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.rgb, vec3( gammaFactor ) ), value.a );\n}\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.rgb, vec3( 1.0 / gammaFactor ) ), value.a );\n}\nvec4 sRGBToLinear( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.a );\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}\nvec4 RGBEToLinear( in vec4 value ) {\n\treturn vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\n}\nvec4 LinearToRGBE( in vec4 value ) {\n\tfloat maxComponent = max( max( value.r, value.g ), value.b );\n\tfloat fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\n\treturn vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\n}\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * value.a * maxRange, 1.0 );\n}\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.r, max( value.g, value.b ) );\n\tfloat M = clamp( maxRGB / maxRange, 0.0, 1.0 );\n\tM = ceil( M * 255.0 ) / 255.0;\n\treturn vec4( value.rgb / ( M * maxRange ), M );\n}\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\n}\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.r, max( value.g, value.b ) );\n\tfloat D = max( maxRange / maxRGB, 1.0 );\n\tD = clamp( floor( D ) / 255.0, 0.0, 1.0 );\n\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\n}\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\nvec4 LinearToLogLuv( in vec4 value ) {\n\tvec3 Xp_Y_XYZp = cLogLuvM * value.rgb;\n\tXp_Y_XYZp = max( Xp_Y_XYZp, vec3( 1e-6, 1e-6, 1e-6 ) );\n\tvec4 vResult;\n\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\n\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\n\tvResult.w = fract( Le );\n\tvResult.z = ( Le - ( floor( vResult.w * 255.0 ) ) / 255.0 ) / 255.0;\n\treturn vResult;\n}\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\nvec4 LogLuvToLinear( in vec4 value ) {\n\tfloat Le = value.z * 255.0 + value.w;\n\tvec3 Xp_Y_XYZp;\n\tXp_Y_XYZp.y = exp2( ( Le - 127.0 ) / 2.0 );\n\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\n\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\n\tvec3 vRGB = cLogLuvInverseM * Xp_Y_XYZp.rgb;\n\treturn vec4( max( vRGB, 0.0 ), 1.0 );\n}", +envmap_fragment:"#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\t\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 envColor = textureCubeUV( envMap, reflectVec, 0.0 );\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\tvec2 sampleUV;\n\t\treflectVec = normalize( reflectVec );\n\t\tsampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\n\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\treflectVec = normalize( reflectVec );\n\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) );\n\t\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifndef ENVMAP_TYPE_CUBE_UV\n\t\tenvColor = envMapTexelToLinear( envColor );\n\t#endif\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif", +envmap_common_pars_fragment:"#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap;\n\tuniform int maxMipLevel;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\t\n#endif",envmap_pars_fragment:"#ifdef USE_ENVMAP\n\tuniform float reflectivity;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\tvarying vec3 vWorldPosition;\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif", +envmap_pars_vertex:"#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) ||defined( PHONG )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\t\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif",envmap_physical_pars_fragment:"#if defined( USE_ENVMAP )\n\t#ifdef ENVMAP_MODE_REFRACTION\n\t\tuniform float refractionRatio;\n\t#endif\n\tvec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\n\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t#else\n\t\t\tvec4 envMapColor = vec4( 0.0 );\n\t\t#endif\n\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t}\n\tfloat getSpecularMIPLevel( const in float roughness, const in int maxMIPLevel ) {\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\n\t\tfloat sigma = PI * roughness * roughness / ( 1.0 + roughness );\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar + log2( sigma );\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\n\t}\n\tvec3 getLightProbeIndirectRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in int maxMIPLevel ) {\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t vec3 reflectVec = reflect( -viewDir, normal );\n\t\t reflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t#else\n\t\t vec3 reflectVec = refract( -viewDir, normal, refractionRatio );\n\t\t#endif\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( roughness, maxMIPLevel );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\t\tvec2 sampleUV;\n\t\t\tsampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\t\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0,0.0,1.0 ) );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#endif\n\t\treturn envMapColor.rgb * envMapIntensity;\n\t}\n#endif", +envmap_vertex:"#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex;\n\t\tif ( isOrthographic ) { \n\t\t\tcameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif", +fog_vertex:"#ifdef USE_FOG\n\tfogDepth = -mvPosition.z;\n#endif",fog_pars_vertex:"#ifdef USE_FOG\n\tvarying float fogDepth;\n#endif",fog_fragment:"#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = 1.0 - exp( - fogDensity * fogDensity * fogDepth * fogDepth );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, fogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif",fog_pars_fragment:"#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float fogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif", +gradientmap_pars_fragment:"#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\tfloat dotNL = dot( normal, lightDirection );\n\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t#ifdef USE_GRADIENTMAP\n\t\treturn texture2D( gradientMap, coord ).rgb;\n\t#else\n\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t#endif\n}",lightmap_fragment:"#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\treflectedLight.indirectDiffuse += PI * lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n#endif", +lightmap_pars_fragment:"#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif",lights_lambert_vertex:"vec3 diffuse = vec3( 1.0 );\nGeometricContext geometry;\ngeometry.position = mvPosition.xyz;\ngeometry.normal = normalize( transformedNormal );\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\nvIndirectFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n\tvIndirectBack = vec3( 0.0 );\n#endif\nIncidentLight directLight;\nfloat dotNL;\nvec3 directLightColor_Diffuse;\n#if NUM_POINT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_DIR_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvIndirectFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvIndirectBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n#endif", +lights_pars_begin:"uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\nuniform vec3 lightProbe[ 9 ];\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in GeometricContext geometry ) {\n\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treturn irradiance;\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tdirectLight.color = directionalLight.color;\n\t\tdirectLight.direction = directionalLight.direction;\n\t\tdirectLight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t\tfloat shadowCameraNear;\n\t\tfloat shadowCameraFar;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tdirectLight.color = pointLight.color;\n\t\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\n\t\tdirectLight.visible = ( directLight.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tfloat angleCos = dot( directLight.direction, spotLight.direction );\n\t\tif ( angleCos > spotLight.coneCos ) {\n\t\t\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\t\tdirectLight.color = spotLight.color;\n\t\t\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tdirectLight.visible = true;\n\t\t} else {\n\t\t\tdirectLight.color = vec3( 0.0 );\n\t\t\tdirectLight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {\n\t\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tirradiance *= PI;\n\t\t#endif\n\t\treturn irradiance;\n\t}\n#endif", +lights_toon_fragment:"ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;",lights_toon_pars_fragment:"varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct ToonMaterial {\n\tvec3\tdiffuseColor;\n\tvec3\tspecularColor;\n\tfloat\tspecularShininess;\n\tfloat\tspecularStrength;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon\n#define Material_LightProbeLOD( material )\t(0)", +lights_phong_fragment:"BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;",lights_phong_pars_fragment:"varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct BlinnPhongMaterial {\n\tvec3\tdiffuseColor;\n\tvec3\tspecularColor;\n\tfloat\tspecularShininess;\n\tfloat\tspecularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)", +lights_physical_fragment:"PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.specularRoughness = max( roughnessFactor, 0.0525 );material.specularRoughness += geometryRoughness;\nmaterial.specularRoughness = min( material.specularRoughness, 1.0 );\n#ifdef REFLECTIVITY\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\n#endif\n#ifdef CLEARCOAT\n\tmaterial.clearcoat = saturate( clearcoat );\tmaterial.clearcoatRoughness = max( clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheen;\n#endif", +lights_physical_pars_fragment:"struct PhysicalMaterial {\n\tvec3\tdiffuseColor;\n\tfloat\tspecularRoughness;\n\tvec3\tspecularColor;\n#ifdef CLEARCOAT\n\tfloat clearcoat;\n\tfloat clearcoatRoughness;\n#endif\n#ifdef USE_SHEEN\n\tvec3 sheenColor;\n#endif\n};\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\nfloat clearcoatDHRApprox( const in float roughness, const in float dotNL ) {\n\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometry.normal;\n\t\tvec3 viewDir = geometry.viewDir;\n\t\tvec3 position = geometry.position;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.specularRoughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\t#ifdef CLEARCOAT\n\t\tfloat ccDotNL = saturate( dot( geometry.clearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = ccDotNL * directLight.color;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tccIrradiance *= PI;\n\t\t#endif\n\t\tfloat clearcoatDHR = material.clearcoat * clearcoatDHRApprox( material.clearcoatRoughness, ccDotNL );\n\t\treflectedLight.directSpecular += ccIrradiance * material.clearcoat * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearcoatRoughness );\n\t#else\n\t\tfloat clearcoatDHR = 0.0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\treflectedLight.directSpecular += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Specular_Sheen(\n\t\t\tmaterial.specularRoughness,\n\t\t\tdirectLight.direction,\n\t\t\tgeometry,\n\t\t\tmaterial.sheenColor\n\t\t);\n\t#else\n\t\treflectedLight.directSpecular += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness);\n\t#endif\n\treflectedLight.directDiffuse += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef CLEARCOAT\n\t\tfloat ccDotNV = saturate( dot( geometry.clearcoatNormal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular += clearcoatRadiance * material.clearcoat * BRDF_Specular_GGX_Environment( geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearcoatRoughness );\n\t\tfloat ccDotNL = ccDotNV;\n\t\tfloat clearcoatDHR = material.clearcoat * clearcoatDHRApprox( material.clearcoatRoughness, ccDotNL );\n\t#else\n\t\tfloat clearcoatDHR = 0.0;\n\t#endif\n\tfloat clearcoatInv = 1.0 - clearcoatDHR;\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\tBRDF_Specular_Multiscattering_Environment( geometry, material.specularColor, material.specularRoughness, singleScattering, multiScattering );\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - ( singleScattering + multiScattering ) );\n\treflectedLight.indirectSpecular += clearcoatInv * radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}", +lights_fragment_begin:"\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\n#ifdef CLEARCOAT\n\tgeometry.clearcoatNormal = clearcoatNormal;\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tdirectLight.color *= all( bvec3( pointLight.shadow, directLight.visible, receiveShadow ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tdirectLight.color *= all( bvec3( spotLight.shadow, directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectLight.color *= all( bvec3( directionalLight.shadow, directLight.visible, receiveShadow ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\tirradiance += getLightProbeIrradiance( lightProbe, geometry );\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif", +lights_fragment_maps:"#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\t\tvec3 lightMapIrradiance = lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tlightMapIrradiance *= PI;\n\t\t#endif\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getLightProbeIndirectIrradiance( geometry, maxMipLevel );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tradiance += getLightProbeIndirectRadiance( geometry.viewDir, geometry.normal, material.specularRoughness, maxMipLevel );\n\t#ifdef CLEARCOAT\n\t\tclearcoatRadiance += getLightProbeIndirectRadiance( geometry.viewDir, geometry.clearcoatNormal, material.clearcoatRoughness, maxMipLevel );\n\t#endif\n#endif", +lights_fragment_end:"#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometry, material, reflectedLight );\n#endif",logdepthbuf_fragment:"#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif",logdepthbuf_pars_fragment:"#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif", +logdepthbuf_pars_vertex:"#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t\tvarying float vIsPerspective;\n\t#else\n\t\tuniform float logDepthBufFC;\n\t#endif\n#endif",logdepthbuf_vertex:"#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n\t#else\n\t\tif ( isPerspectiveMatrix( projectionMatrix ) ) {\n\t\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\t\tgl_Position.z *= gl_Position.w;\n\t\t}\n\t#endif\n#endif", +map_fragment:"#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif",map_pars_fragment:"#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif",map_particle_fragment:"#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n#endif\n#ifdef USE_MAP\n\tvec4 mapTexel = texture2D( map, uv );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif", +map_particle_pars_fragment:"#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tuniform mat3 uvTransform;\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif",metalnessmap_fragment:"float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif",metalnessmap_pars_fragment:"#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif", +morphnormal_vertex:"#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\tobjectNormal += morphNormal0 * morphTargetInfluences[ 0 ];\n\tobjectNormal += morphNormal1 * morphTargetInfluences[ 1 ];\n\tobjectNormal += morphNormal2 * morphTargetInfluences[ 2 ];\n\tobjectNormal += morphNormal3 * morphTargetInfluences[ 3 ];\n#endif",morphtarget_pars_vertex:"#ifdef USE_MORPHTARGETS\n\tuniform float morphTargetBaseInfluence;\n\t#ifndef USE_MORPHNORMALS\n\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif", +morphtarget_vertex:"#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\ttransformed += morphTarget0 * morphTargetInfluences[ 0 ];\n\ttransformed += morphTarget1 * morphTargetInfluences[ 1 ];\n\ttransformed += morphTarget2 * morphTargetInfluences[ 2 ];\n\ttransformed += morphTarget3 * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\ttransformed += morphTarget4 * morphTargetInfluences[ 4 ];\n\ttransformed += morphTarget5 * morphTargetInfluences[ 5 ];\n\ttransformed += morphTarget6 * morphTargetInfluences[ 6 ];\n\ttransformed += morphTarget7 * morphTargetInfluences[ 7 ];\n\t#endif\n#endif", +normal_fragment_begin:"#ifdef FLAT_SHADED\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t#endif\n\t#ifdef USE_TANGENT\n\t\tvec3 tangent = normalize( vTangent );\n\t\tvec3 bitangent = normalize( vBitangent );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\ttangent = tangent * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t\tbitangent = bitangent * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t#endif\n\t\t#if defined( TANGENTSPACE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tmat3 vTBN = mat3( tangent, bitangent, normal );\n\t\t#endif\n\t#endif\n#endif\nvec3 geometryNormal = normal;", +normal_fragment_maps:"#ifdef OBJECTSPACE_NORMALMAP\n\tnormal = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( TANGENTSPACE_NORMALMAP )\n\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\t#ifdef USE_TANGENT\n\t\tnormal = normalize( vTBN * mapN );\n\t#else\n\t\tnormal = perturbNormal2Arb( -vViewPosition, normal, mapN );\n\t#endif\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif", +normalmap_pars_fragment:"#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef OBJECTSPACE_NORMALMAP\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( TANGENTSPACE_NORMALMAP ) || defined ( USE_CLEARCOAT_NORMALMAP ) )\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 mapN ) {\n\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\n\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tfloat scale = sign( st1.t * st0.s - st0.t * st1.s );\n\t\tvec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * scale );\n\t\tvec3 T = normalize( ( - q0 * st1.s + q1 * st0.s ) * scale );\n\t\tvec3 N = normalize( surf_norm );\n\t\tmat3 tsn = mat3( S, T, N );\n\t\tmapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif", +clearcoat_normal_fragment_begin:"#ifdef CLEARCOAT\n\tvec3 clearcoatNormal = geometryNormal;\n#endif",clearcoat_normal_fragment_maps:"#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\t#ifdef USE_TANGENT\n\t\tclearcoatNormal = normalize( vTBN * clearcoatMapN );\n\t#else\n\t\tclearcoatNormal = perturbNormal2Arb( - vViewPosition, clearcoatNormal, clearcoatMapN );\n\t#endif\n#endif",clearcoat_normalmap_pars_fragment:"#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif", +packing:"vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nvec4 pack2HalfToRGBA( vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ));\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w);\n}\nvec2 unpackRGBATo2Half( vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn (( near + viewZ ) * far ) / (( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}", +premultiplied_alpha_fragment:"#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif",project_vertex:"vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;",dithering_fragment:"#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif",dithering_pars_fragment:"#ifdef DITHERING\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif", +roughnessmap_fragment:"float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif",roughnessmap_pars_fragment:"#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif",shadowmap_pars_fragment:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ), \n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ), \n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif", +shadowmap_pars_vertex:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif", +shadowmap_vertex:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n#endif", +shadowmask_pars_fragment:"float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLight directionalLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tshadow *= all( bvec2( directionalLight.shadow, receiveShadow ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLight spotLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tshadow *= all( bvec2( spotLight.shadow, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLight pointLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tshadow *= all( bvec2( pointLight.shadow, receiveShadow ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#endif\n\t#endif\n\treturn shadow;\n}", +skinbase_vertex:"#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif",skinning_pars_vertex:"#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\t#ifdef BONE_TEXTURE\n\t\tuniform highp sampler2D boneTexture;\n\t\tuniform int boneTextureSize;\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureSize ) );\n\t\t\tfloat y = floor( j / float( boneTextureSize ) );\n\t\t\tfloat dx = 1.0 / float( boneTextureSize );\n\t\t\tfloat dy = 1.0 / float( boneTextureSize );\n\t\t\ty = dy * ( y + 0.5 );\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\t\treturn bone;\n\t\t}\n\t#else\n\t\tuniform mat4 boneMatrices[ MAX_BONES ];\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tmat4 bone = boneMatrices[ int(i) ];\n\t\t\treturn bone;\n\t\t}\n\t#endif\n#endif", +skinning_vertex:"#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif",skinnormal_vertex:"#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n\t#ifdef USE_TANGENT\n\t\tobjectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#endif\n#endif", +specularmap_fragment:"float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif",specularmap_pars_fragment:"#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif",tonemapping_fragment:"#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif",tonemapping_pars_fragment:"#ifndef saturate\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nuniform float toneMappingWhitePoint;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\n#define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )\nvec3 Uncharted2ToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( ( color * ( 2.51 * color + 0.03 ) ) / ( color * ( 2.43 * color + 0.59 ) + 0.14 ) );\n}", +uv_pars_fragment:"#if ( defined( USE_UV ) && ! defined( UVS_VERTEX_ONLY ) )\n\tvarying vec2 vUv;\n#endif",uv_pars_vertex:"#ifdef USE_UV\n\t#ifdef UVS_VERTEX_ONLY\n\t\tvec2 vUv;\n\t#else\n\t\tvarying vec2 vUv;\n\t#endif\n\tuniform mat3 uvTransform;\n#endif",uv_vertex:"#ifdef USE_UV\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n#endif",uv2_pars_fragment:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif",uv2_pars_vertex:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n\tuniform mat3 uv2Transform;\n#endif", +uv2_vertex:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = ( uv2Transform * vec3( uv2, 1 ) ).xy;\n#endif",worldpos_vertex:"#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif",background_frag:"uniform sampler2D t2D;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\t#include \n\t#include \n}", +background_vert:"varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}",cube_frag:"#include \nuniform float opacity;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 vReflect = vWorldDirection;\n\t#include \n\tgl_FragColor = envColor;\n\tgl_FragColor.a *= opacity;\n\t#include \n\t#include \n}", +cube_vert:"varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}",depth_frag:"#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - gl_FragCoord.z ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( gl_FragCoord.z );\n\t#endif\n}", +depth_vert:"#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}", +distanceRGBA_frag:"#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main () {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#include \n\t#include \n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}", +distanceRGBA_vert:"#define DISTANCE\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition.xyz;\n}", +equirect_frag:"uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV;\n\tsampleUV.y = asin( clamp( direction.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\n\tvec4 texColor = texture2D( tEquirect, sampleUV );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\t#include \n\t#include \n}", +equirect_vert:"varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}",linedashed_frag:"uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}", +linedashed_vert:"uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvLineDistance = scale * lineDistance;\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}", +meshbasic_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\n\t\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\t\treflectedLight.indirectDiffuse += lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}", +meshbasic_vert:"#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#ifdef USE_ENVMAP\n\t#include \n\t#include \n\t#include \n\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}", +meshlambert_frag:"uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\nvarying vec3 vIndirectFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n\tvarying vec3 vIndirectBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\treflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.indirectDiffuse += ( gl_FrontFacing ) ? vIndirectFront : vIndirectBack;\n\t#else\n\t\treflectedLight.indirectDiffuse += vIndirectFront;\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\n\t#else\n\t\treflectedLight.directDiffuse = vLightFront;\n\t#endif\n\treflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}", +meshlambert_vert:"#define LAMBERT\nvarying vec3 vLightFront;\nvarying vec3 vIndirectFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n\tvarying vec3 vIndirectBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}", +meshmatcap_frag:"#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t\tmatcapColor = matcapTexelToLinear( matcapColor );\n\t#else\n\t\tvec4 matcapColor = vec4( 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}", +meshmatcap_vert:"#define MATCAP\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#ifndef FLAT_SHADED\n\t\tvNormal = normalize( transformedNormal );\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n}", +meshtoon_frag:"#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}", +meshtoon_vert:"#define TOON\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}", +meshphong_frag:"#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}", +meshphong_vert:"#define PHONG\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}", +meshphysical_frag:"#define STANDARD\n#ifdef PHYSICAL\n\t#define REFLECTIVITY\n\t#define CLEARCOAT\n\t#define TRANSPARENCY\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef TRANSPARENCY\n\tuniform float transparency;\n#endif\n#ifdef REFLECTIVITY\n\tuniform float reflectivity;\n#endif\n#ifdef CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheen;\n#endif\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#ifdef TRANSPARENCY\n\t\tdiffuseColor.a *= saturate( 1. - transparency + linearToRelativeLuminance( reflectedLight.directSpecular + reflectedLight.indirectSpecular ) );\n\t#endif\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}", +meshphysical_vert:"#define STANDARD\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}", +normal_frag:"#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n}", +normal_vert:"#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}", +points_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}", +points_vert:"uniform float size;\nuniform float scale;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n}", +shadow_frag:"uniform vec3 color;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include \n\t#include \n\t#include \n}",shadow_vert:"#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}", +sprite_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n}", +sprite_vert:"uniform float rotation;\nuniform vec2 center;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}"}, +fb={basic:{uniforms:pa([F.common,F.specularmap,F.envmap,F.aomap,F.lightmap,F.fog]),vertexShader:N.meshbasic_vert,fragmentShader:N.meshbasic_frag},lambert:{uniforms:pa([F.common,F.specularmap,F.envmap,F.aomap,F.lightmap,F.emissivemap,F.fog,F.lights,{emissive:{value:new B(0)}}]),vertexShader:N.meshlambert_vert,fragmentShader:N.meshlambert_frag},phong:{uniforms:pa([F.common,F.specularmap,F.envmap,F.aomap,F.lightmap,F.emissivemap,F.bumpmap,F.normalmap,F.displacementmap,F.fog,F.lights,{emissive:{value:new B(0)}, +specular:{value:new B(1118481)},shininess:{value:30}}]),vertexShader:N.meshphong_vert,fragmentShader:N.meshphong_frag},standard:{uniforms:pa([F.common,F.envmap,F.aomap,F.lightmap,F.emissivemap,F.bumpmap,F.normalmap,F.displacementmap,F.roughnessmap,F.metalnessmap,F.fog,F.lights,{emissive:{value:new B(0)},roughness:{value:.5},metalness:{value:.5},envMapIntensity:{value:1}}]),vertexShader:N.meshphysical_vert,fragmentShader:N.meshphysical_frag},toon:{uniforms:pa([F.common,F.specularmap,F.aomap,F.lightmap, +F.emissivemap,F.bumpmap,F.normalmap,F.displacementmap,F.gradientmap,F.fog,F.lights,{emissive:{value:new B(0)},specular:{value:new B(1118481)},shininess:{value:30}}]),vertexShader:N.meshtoon_vert,fragmentShader:N.meshtoon_frag},matcap:{uniforms:pa([F.common,F.bumpmap,F.normalmap,F.displacementmap,F.fog,{matcap:{value:null}}]),vertexShader:N.meshmatcap_vert,fragmentShader:N.meshmatcap_frag},points:{uniforms:pa([F.points,F.fog]),vertexShader:N.points_vert,fragmentShader:N.points_frag},dashed:{uniforms:pa([F.common, +F.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:N.linedashed_vert,fragmentShader:N.linedashed_frag},depth:{uniforms:pa([F.common,F.displacementmap]),vertexShader:N.depth_vert,fragmentShader:N.depth_frag},normal:{uniforms:pa([F.common,F.bumpmap,F.normalmap,F.displacementmap,{opacity:{value:1}}]),vertexShader:N.normal_vert,fragmentShader:N.normal_frag},sprite:{uniforms:pa([F.sprite,F.fog]),vertexShader:N.sprite_vert,fragmentShader:N.sprite_frag},background:{uniforms:{uvTransform:{value:new za}, +t2D:{value:null}},vertexShader:N.background_vert,fragmentShader:N.background_frag},cube:{uniforms:pa([F.envmap,{opacity:{value:1}}]),vertexShader:N.cube_vert,fragmentShader:N.cube_frag},equirect:{uniforms:{tEquirect:{value:null}},vertexShader:N.equirect_vert,fragmentShader:N.equirect_frag},distanceRGBA:{uniforms:pa([F.common,F.displacementmap,{referencePosition:{value:new n},nearDistance:{value:1},farDistance:{value:1E3}}]),vertexShader:N.distanceRGBA_vert,fragmentShader:N.distanceRGBA_frag},shadow:{uniforms:pa([F.lights, +F.fog,{color:{value:new B(0)},opacity:{value:1}}]),vertexShader:N.shadow_vert,fragmentShader:N.shadow_frag}};fb.physical={uniforms:pa([fb.standard.uniforms,{transparency:{value:0},clearcoat:{value:0},clearcoatRoughness:{value:0},sheen:{value:new B(0)},clearcoatNormalScale:{value:new w(1,1)},clearcoatNormalMap:{value:null}}]),vertexShader:N.meshphysical_vert,fragmentShader:N.meshphysical_frag};rb.prototype=Object.create(Z.prototype);rb.prototype.constructor=rb;rb.prototype.isCubeTexture=!0;Object.defineProperty(rb.prototype, +"images",{get:function(){return this.image},set:function(a){this.image=a}});Ic.prototype=Object.create(Z.prototype);Ic.prototype.constructor=Ic;Ic.prototype.isDataTexture2DArray=!0;Jc.prototype=Object.create(Z.prototype);Jc.prototype.constructor=Jc;Jc.prototype.isDataTexture3D=!0;var Hh=new Z,Pj=new Ic,Rj=new Jc,Ih=new rb,Bh=[],Dh=[],Gh=new Float32Array(16),Fh=new Float32Array(9),Eh=new Float32Array(4);Jh.prototype.updateCache=function(a){var b=this.cache;a instanceof Float32Array&&b.length!==a.length&& +(this.cache=new Float32Array(a.length));Ka(b,a)};Kh.prototype.setValue=function(a,b,c){for(var d=this.seq,e=0,f=d.length;e!==f;++e){var g=d[e];g.setValue(a,b[g.id],c)}};var ig=/([\w\d_]+)(\])?(\[|\.)?/g;Fb.prototype.setValue=function(a,b,c,d){b=this.map[b];void 0!==b&&b.setValue(a,c,d)};Fb.prototype.setOptional=function(a,b,c){b=b[c];void 0!==b&&this.setValue(a,c,b)};Fb.upload=function(a,b,c,d){for(var e=0,f=b.length;e!==f;++e){var g=b[e],k=c[g.id];!1!==k.needsUpdate&&g.setValue(a,k.value,d)}};Fb.seqWithValue= +function(a,b){for(var c=[],d=0,e=a.length;d!==e;++d){var f=a[d];f.id in b&&c.push(f)}return c};var wk=0,kg=/^[ \t]*#include +<([\w\d./]+)>/gm,Sh=/#pragma unroll_loop[\s]+?for \( int i = (\d+); i < (\d+); i \+\+ \) \{([\s\S]+?)(?=\})\}/g,Fk=0;Gb.prototype=Object.create(K.prototype);Gb.prototype.constructor=Gb;Gb.prototype.isMeshDepthMaterial=!0;Gb.prototype.copy=function(a){K.prototype.copy.call(this,a);this.depthPacking=a.depthPacking;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.map= +a.map;this.alphaMap=a.alphaMap;this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;return this};Hb.prototype=Object.create(K.prototype);Hb.prototype.constructor=Hb;Hb.prototype.isMeshDistanceMaterial=!0;Hb.prototype.copy=function(a){K.prototype.copy.call(this,a);this.referencePosition.copy(a.referencePosition);this.nearDistance=a.nearDistance;this.farDistance= +a.farDistance;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.map=a.map;this.alphaMap=a.alphaMap;this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;return this};pg.prototype=Object.assign(Object.create(wa.prototype),{constructor:pg,isWebGLMultiviewRenderTarget:!0,copy:function(a){wa.prototype.copy.call(this,a);this.numViews=a.numViews;return this},setNumViews:function(a){this.numViews!==a&&(this.numViews=a,this.dispose()); +return this}});Qe.prototype=Object.assign(Object.create(da.prototype),{constructor:Qe,isArrayCamera:!0});Mc.prototype=Object.assign(Object.create(D.prototype),{constructor:Mc,isGroup:!0});Object.assign(Zh.prototype,Fa.prototype);Object.assign(Re.prototype,{isFogExp2:!0,clone:function(){return new Re(this.color,this.density)},toJSON:function(){return{type:"FogExp2",color:this.color.getHex(),density:this.density}}});Object.assign(Se.prototype,{isFog:!0,clone:function(){return new Se(this.color,this.near, +this.far)},toJSON:function(){return{type:"Fog",color:this.color.getHex(),near:this.near,far:this.far}}});Object.defineProperty(sb.prototype,"needsUpdate",{set:function(a){!0===a&&this.version++}});Object.assign(sb.prototype,{isInterleavedBuffer:!0,onUploadCallback:function(){},setUsage:function(a){this.usage=a;return this},copy:function(a){this.array=new a.array.constructor(a.array);this.count=a.count;this.stride=a.stride;this.usage=a.usage;return this},copyAt:function(a,b,c){a*=this.stride;c*=b.stride; +for(var d=0,e=this.stride;da.far||b.push({distance:e,point:Fe.clone(),uv:oa.getUV(Fe,Nf,Ge,Of,Ri,oh,Si,new w),face:null,object:this})},clone:function(){return(new this.constructor(this.material)).copy(this)},copy:function(a){D.prototype.copy.call(this,a);void 0!==a.center&&this.center.copy(a.center);return this}});var Pf=new n,Ti=new n;Td.prototype=Object.assign(Object.create(D.prototype),{constructor:Td,isLOD:!0,copy:function(a){D.prototype.copy.call(this,a,!1);for(var b=a.levels,c=0,d=b.length;c=b[c].distance)b[c-1].object.visible=!1,b[c].object.visible=!0;else break;for(;cc||(k.applyMatrix4(this.matrixWorld),q=a.ray.origin.distanceTo(k),qa.far||b.push({distance:q,point:e.clone().applyMatrix4(this.matrixWorld),index:d,face:null,faceIndex:null,object:this}))}}else for(d=0,p=x.length/3-1;dc||(k.applyMatrix4(this.matrixWorld),q=a.ray.origin.distanceTo(k),qa.far||b.push({distance:q,point:e.clone().applyMatrix4(this.matrixWorld),index:d,face:null,faceIndex:null,object:this}))}else if(d.isGeometry)for(f=d.vertices,g=f.length,d=0;dc||(k.applyMatrix4(this.matrixWorld),q=a.ray.origin.distanceTo(k),qa.far||b.push({distance:q,point:e.clone().applyMatrix4(this.matrixWorld), +index:d,face:null,faceIndex:null,object:this}))}},clone:function(){return(new this.constructor(this.geometry,this.material)).copy(this)}});var Rf=new n,Sf=new n;ma.prototype=Object.assign(Object.create(La.prototype),{constructor:ma,isLineSegments:!0,computeLineDistances:function(){var a=this.geometry;if(a.isBufferGeometry)if(null===a.index){for(var b=a.attributes.position,c=[],d=0,e=b.count;d=a.HAVE_CURRENT_DATA&&(this.needsUpdate=!0)}});Qc.prototype=Object.create(Z.prototype);Qc.prototype.constructor=Qc;Qc.prototype.isCompressedTexture=!0;Vd.prototype=Object.create(Z.prototype);Vd.prototype.constructor=Vd;Vd.prototype.isCanvasTexture=!0;Wd.prototype=Object.create(Z.prototype);Wd.prototype.constructor=Wd;Wd.prototype.isDepthTexture= +!0;Rc.prototype=Object.create(A.prototype);Rc.prototype.constructor=Rc;Xd.prototype=Object.create(L.prototype);Xd.prototype.constructor=Xd;Sc.prototype=Object.create(A.prototype);Sc.prototype.constructor=Sc;Yd.prototype=Object.create(L.prototype);Yd.prototype.constructor=Yd;Ja.prototype=Object.create(A.prototype);Ja.prototype.constructor=Ja;Zd.prototype=Object.create(L.prototype);Zd.prototype.constructor=Zd;Tc.prototype=Object.create(Ja.prototype);Tc.prototype.constructor=Tc;$d.prototype=Object.create(L.prototype); +$d.prototype.constructor=$d;dc.prototype=Object.create(Ja.prototype);dc.prototype.constructor=dc;ae.prototype=Object.create(L.prototype);ae.prototype.constructor=ae;Uc.prototype=Object.create(Ja.prototype);Uc.prototype.constructor=Uc;be.prototype=Object.create(L.prototype);be.prototype.constructor=be;Vc.prototype=Object.create(Ja.prototype);Vc.prototype.constructor=Vc;ce.prototype=Object.create(L.prototype);ce.prototype.constructor=ce;ec.prototype=Object.create(A.prototype);ec.prototype.constructor= +ec;ec.prototype.toJSON=function(){var a=A.prototype.toJSON.call(this);a.path=this.parameters.path.toJSON();return a};de.prototype=Object.create(L.prototype);de.prototype.constructor=de;Wc.prototype=Object.create(A.prototype);Wc.prototype.constructor=Wc;ee.prototype=Object.create(L.prototype);ee.prototype.constructor=ee;Xc.prototype=Object.create(A.prototype);Xc.prototype.constructor=Xc;var al={triangulate:function(a,b,c){c=c||2;var d=b&&b.length,e=d?b[0]*c:a.length,f=bi(a,0,e,c,!0),g=[];if(!f||f.next=== +f.prev)return g;var k;if(d){var h=c;d=[];var m;var n=0;for(m=b.length;n80*c){var t=k=a[0];var r=d=a[1];for(h=c;hk&&(k=n),b>d&&(d=b);k=Math.max(k-t,d-r);k=0!==k?1/k:0}he(f,g,c,t,r,k);return g}},tb={area:function(a){for(var b=a.length,c= +0,d=b-1,e=0;etb.area(a)},triangulateShape:function(a,b){var c=[],d=[],e=[];fi(a);gi(c,a);var f=a.length;b.forEach(fi);for(a=0;aMath.abs(g-h)?[new w(a,1-c),new w(k,1-d),new w(m,1-e),new w(p,1-b)]:[new w(g,1-c),new w(h,1-d),new w(n,1-e),new w(q,1-b)]}};je.prototype=Object.create(L.prototype);je.prototype.constructor=je;Zc.prototype=Object.create(gb.prototype);Zc.prototype.constructor=Zc;ke.prototype=Object.create(L.prototype);ke.prototype.constructor=ke;hc.prototype=Object.create(A.prototype);hc.prototype.constructor=hc;le.prototype=Object.create(L.prototype);le.prototype.constructor= +le;$c.prototype=Object.create(A.prototype);$c.prototype.constructor=$c;me.prototype=Object.create(L.prototype);me.prototype.constructor=me;ad.prototype=Object.create(A.prototype);ad.prototype.constructor=ad;ic.prototype=Object.create(L.prototype);ic.prototype.constructor=ic;ic.prototype.toJSON=function(){var a=L.prototype.toJSON.call(this);return ii(this.parameters.shapes,a)};jc.prototype=Object.create(A.prototype);jc.prototype.constructor=jc;jc.prototype.toJSON=function(){var a=A.prototype.toJSON.call(this); +return ii(this.parameters.shapes,a)};bd.prototype=Object.create(A.prototype);bd.prototype.constructor=bd;kc.prototype=Object.create(L.prototype);kc.prototype.constructor=kc;ub.prototype=Object.create(A.prototype);ub.prototype.constructor=ub;ne.prototype=Object.create(kc.prototype);ne.prototype.constructor=ne;oe.prototype=Object.create(ub.prototype);oe.prototype.constructor=oe;pe.prototype=Object.create(L.prototype);pe.prototype.constructor=pe;cd.prototype=Object.create(A.prototype);cd.prototype.constructor= +cd;var va=Object.freeze({__proto__:null,WireframeGeometry:Rc,ParametricGeometry:Xd,ParametricBufferGeometry:Sc,TetrahedronGeometry:Zd,TetrahedronBufferGeometry:Tc,OctahedronGeometry:$d,OctahedronBufferGeometry:dc,IcosahedronGeometry:ae,IcosahedronBufferGeometry:Uc,DodecahedronGeometry:be,DodecahedronBufferGeometry:Vc,PolyhedronGeometry:Yd,PolyhedronBufferGeometry:Ja,TubeGeometry:ce,TubeBufferGeometry:ec,TorusKnotGeometry:de,TorusKnotBufferGeometry:Wc,TorusGeometry:ee,TorusBufferGeometry:Xc,TextGeometry:je, +TextBufferGeometry:Zc,SphereGeometry:ke,SphereBufferGeometry:hc,RingGeometry:le,RingBufferGeometry:$c,PlaneGeometry:Jd,PlaneBufferGeometry:cc,LatheGeometry:me,LatheBufferGeometry:ad,ShapeGeometry:ic,ShapeBufferGeometry:jc,ExtrudeGeometry:gc,ExtrudeBufferGeometry:gb,EdgesGeometry:bd,ConeGeometry:ne,ConeBufferGeometry:oe,CylinderGeometry:kc,CylinderBufferGeometry:ub,CircleGeometry:pe,CircleBufferGeometry:cd,BoxGeometry:nh,BoxBufferGeometry:Kd});lc.prototype=Object.create(K.prototype);lc.prototype.constructor= +lc;lc.prototype.isShadowMaterial=!0;lc.prototype.copy=function(a){K.prototype.copy.call(this,a);this.color.copy(a.color);return this};vb.prototype=Object.create(qa.prototype);vb.prototype.constructor=vb;vb.prototype.isRawShaderMaterial=!0;hb.prototype=Object.create(K.prototype);hb.prototype.constructor=hb;hb.prototype.isMeshStandardMaterial=!0;hb.prototype.copy=function(a){K.prototype.copy.call(this,a);this.defines={STANDARD:""};this.color.copy(a.color);this.roughness=a.roughness;this.metalness=a.metalness; +this.map=a.map;this.lightMap=a.lightMap;this.lightMapIntensity=a.lightMapIntensity;this.aoMap=a.aoMap;this.aoMapIntensity=a.aoMapIntensity;this.emissive.copy(a.emissive);this.emissiveMap=a.emissiveMap;this.emissiveIntensity=a.emissiveIntensity;this.bumpMap=a.bumpMap;this.bumpScale=a.bumpScale;this.normalMap=a.normalMap;this.normalMapType=a.normalMapType;this.normalScale.copy(a.normalScale);this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias; +this.roughnessMap=a.roughnessMap;this.metalnessMap=a.metalnessMap;this.alphaMap=a.alphaMap;this.envMap=a.envMap;this.envMapIntensity=a.envMapIntensity;this.refractionRatio=a.refractionRatio;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.wireframeLinecap=a.wireframeLinecap;this.wireframeLinejoin=a.wireframeLinejoin;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};mc.prototype=Object.create(hb.prototype);mc.prototype.constructor= +mc;mc.prototype.isMeshPhysicalMaterial=!0;mc.prototype.copy=function(a){hb.prototype.copy.call(this,a);this.defines={STANDARD:"",PHYSICAL:""};this.reflectivity=a.reflectivity;this.clearcoat=a.clearcoat;this.clearcoatRoughness=a.clearcoatRoughness;this.sheen=a.sheen?(this.sheen||new B).copy(a.sheen):null;this.clearcoatNormalMap=a.clearcoatNormalMap;this.clearcoatNormalScale.copy(a.clearcoatNormalScale);this.transparency=a.transparency;return this};Kb.prototype=Object.create(K.prototype);Kb.prototype.constructor= +Kb;Kb.prototype.isMeshPhongMaterial=!0;Kb.prototype.copy=function(a){K.prototype.copy.call(this,a);this.color.copy(a.color);this.specular.copy(a.specular);this.shininess=a.shininess;this.map=a.map;this.lightMap=a.lightMap;this.lightMapIntensity=a.lightMapIntensity;this.aoMap=a.aoMap;this.aoMapIntensity=a.aoMapIntensity;this.emissive.copy(a.emissive);this.emissiveMap=a.emissiveMap;this.emissiveIntensity=a.emissiveIntensity;this.bumpMap=a.bumpMap;this.bumpScale=a.bumpScale;this.normalMap=a.normalMap; +this.normalMapType=a.normalMapType;this.normalScale.copy(a.normalScale);this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;this.specularMap=a.specularMap;this.alphaMap=a.alphaMap;this.envMap=a.envMap;this.combine=a.combine;this.reflectivity=a.reflectivity;this.refractionRatio=a.refractionRatio;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.wireframeLinecap=a.wireframeLinecap;this.wireframeLinejoin= +a.wireframeLinejoin;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};nc.prototype=Object.create(K.prototype);nc.prototype.constructor=nc;nc.prototype.isMeshToonMaterial=!0;nc.prototype.copy=function(a){K.prototype.copy.call(this,a);this.color.copy(a.color);this.specular.copy(a.specular);this.shininess=a.shininess;this.map=a.map;this.gradientMap=a.gradientMap;this.lightMap=a.lightMap;this.lightMapIntensity=a.lightMapIntensity;this.aoMap=a.aoMap; +this.aoMapIntensity=a.aoMapIntensity;this.emissive.copy(a.emissive);this.emissiveMap=a.emissiveMap;this.emissiveIntensity=a.emissiveIntensity;this.bumpMap=a.bumpMap;this.bumpScale=a.bumpScale;this.normalMap=a.normalMap;this.normalMapType=a.normalMapType;this.normalScale.copy(a.normalScale);this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;this.specularMap=a.specularMap;this.alphaMap=a.alphaMap;this.wireframe=a.wireframe;this.wireframeLinewidth= +a.wireframeLinewidth;this.wireframeLinecap=a.wireframeLinecap;this.wireframeLinejoin=a.wireframeLinejoin;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};oc.prototype=Object.create(K.prototype);oc.prototype.constructor=oc;oc.prototype.isMeshNormalMaterial=!0;oc.prototype.copy=function(a){K.prototype.copy.call(this,a);this.bumpMap=a.bumpMap;this.bumpScale=a.bumpScale;this.normalMap=a.normalMap;this.normalMapType=a.normalMapType;this.normalScale.copy(a.normalScale); +this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};pc.prototype=Object.create(K.prototype);pc.prototype.constructor=pc;pc.prototype.isMeshLambertMaterial=!0;pc.prototype.copy=function(a){K.prototype.copy.call(this,a);this.color.copy(a.color);this.map=a.map; +this.lightMap=a.lightMap;this.lightMapIntensity=a.lightMapIntensity;this.aoMap=a.aoMap;this.aoMapIntensity=a.aoMapIntensity;this.emissive.copy(a.emissive);this.emissiveMap=a.emissiveMap;this.emissiveIntensity=a.emissiveIntensity;this.specularMap=a.specularMap;this.alphaMap=a.alphaMap;this.envMap=a.envMap;this.combine=a.combine;this.reflectivity=a.reflectivity;this.refractionRatio=a.refractionRatio;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.wireframeLinecap=a.wireframeLinecap; +this.wireframeLinejoin=a.wireframeLinejoin;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};qc.prototype=Object.create(K.prototype);qc.prototype.constructor=qc;qc.prototype.isMeshMatcapMaterial=!0;qc.prototype.copy=function(a){K.prototype.copy.call(this,a);this.defines={MATCAP:""};this.color.copy(a.color);this.matcap=a.matcap;this.map=a.map;this.bumpMap=a.bumpMap;this.bumpScale=a.bumpScale;this.normalMap=a.normalMap;this.normalMapType=a.normalMapType; +this.normalScale.copy(a.normalScale);this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;this.alphaMap=a.alphaMap;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};rc.prototype=Object.create(ka.prototype);rc.prototype.constructor=rc;rc.prototype.isLineDashedMaterial=!0;rc.prototype.copy=function(a){ka.prototype.copy.call(this,a);this.scale=a.scale;this.dashSize=a.dashSize;this.gapSize= +a.gapSize;return this};var bl=Object.freeze({__proto__:null,ShadowMaterial:lc,SpriteMaterial:Jb,RawShaderMaterial:vb,ShaderMaterial:qa,PointsMaterial:Wa,MeshPhysicalMaterial:mc,MeshStandardMaterial:hb,MeshPhongMaterial:Kb,MeshToonMaterial:nc,MeshNormalMaterial:oc,MeshLambertMaterial:pc,MeshDepthMaterial:Gb,MeshDistanceMaterial:Hb,MeshBasicMaterial:Pa,MeshMatcapMaterial:qc,LineDashedMaterial:rc,LineBasicMaterial:ka,Material:K}),ea={arraySlice:function(a,b,c){return ea.isTypedArray(a)?new a.constructor(a.subarray(b, +void 0!==c?c:a.length)):a.slice(b,c)},convertArray:function(a,b,c){return!a||!c&&a.constructor===b?a:"number"===typeof b.BYTES_PER_ELEMENT?new b(a):Array.prototype.slice.call(a)},isTypedArray:function(a){return ArrayBuffer.isView(a)&&!(a instanceof DataView)},getKeyframeOrder:function(a){for(var b=a.length,c=Array(b),d=0;d!==b;++d)c[d]=d;c.sort(function(b,c){return a[b]-a[c]});return c},sortedArray:function(a,b,c){for(var d=a.length,e=new a.constructor(d),f=0,g=0;g!==d;++f)for(var k=c[f]*b,h=0;h!== +b;++h)e[g++]=a[k+h];return e},flattenJSON:function(a,b,c,d){for(var e=1,f=a[0];void 0!==f&&void 0===f[d];)f=a[e++];if(void 0!==f){var g=f[d];if(void 0!==g)if(Array.isArray(g)){do g=f[d],void 0!==g&&(b.push(f.time),c.push.apply(c,g)),f=a[e++];while(void 0!==f)}else if(void 0!==g.toArray){do g=f[d],void 0!==g&&(b.push(f.time),g.toArray(c,c.length)),f=a[e++];while(void 0!==f)}else{do g=f[d],void 0!==g&&(b.push(f.time),c.push(g)),f=a[e++];while(void 0!==f)}}},subclip:function(a,b,c,d,e){e=e||30;a=a.clone(); +a.name=b;var f=[];for(b=0;b=d))for(h.push(g.times[n]),p=0;pa.tracks[b].times[0]&&(c=a.tracks[b].times[0]);for(b=0;b=e)break a;else{f=b[1];a=e)break b}d=c;c=0}}for(;c< +d;)e=c+d>>>1,ab;)--f;++f;if(0!==e||f!==d)e>=f&&(f=Math.max(f,1),e=f-1),a=this.getValueSize(),this.times=ea.arraySlice(c,e,f),this.values=ea.arraySlice(this.values,e*a,f*a);return this},validate:function(){var a= +!0,b=this.getValueSize();0!==b-Math.floor(b)&&(console.error("THREE.KeyframeTrack: Invalid value size in track.",this),a=!1);var c=this.times;b=this.values;var d=c.length;0===d&&(console.error("THREE.KeyframeTrack: Track is empty.",this),a=!1);for(var e=null,f=0;f!==d;f++){var g=c[f];if("number"===typeof g&&isNaN(g)){console.error("THREE.KeyframeTrack: Time is not a valid number.",this,f,g);a=!1;break}if(null!==e&&e>g){console.error("THREE.KeyframeTrack: Out of order keys.",this,f,g,e);a=!1;break}e= +g}if(void 0!==b&&ea.isTypedArray(b))for(f=0,c=b.length;f!==c;++f)if(d=b[f],isNaN(d)){console.error("THREE.KeyframeTrack: Value is not a valid number.",this,f,d);a=!1;break}return a},optimize:function(){for(var a=ea.arraySlice(this.times),b=ea.arraySlice(this.values),c=this.getValueSize(),d=2302===this.getInterpolation(),e=1,f=a.length-1,g=1;gg)e=a+1;else if(0b&&(b=0);1Number.EPSILON&&(g.normalize(),c=Math.acos(P.clamp(d[h-1].dot(d[h]),-1,1)),e[h].applyMatrix4(k.makeRotationAxis(g,c))),f[h].crossVectors(d[h], +e[h]);if(!0===b)for(c=Math.acos(P.clamp(e[0].dot(e[a]),-1,1)),c/=a,0d;)d+=c;for(;d>c;)d-=c;de&&(e=1);1E-4>d&&(d=e);1E-4>l&&(l=e);ph.initNonuniformCatmullRom(f.x,g.x,h.x,c.x,d,e,l);qh.initNonuniformCatmullRom(f.y,g.y,h.y,c.y,d,e,l);rh.initNonuniformCatmullRom(f.z,g.z,h.z,c.z,d, +e,l)}else"catmullrom"===this.curveType&&(ph.initCatmullRom(f.x,g.x,h.x,c.x,this.tension),qh.initCatmullRom(f.y,g.y,h.y,c.y,this.tension),rh.initCatmullRom(f.z,g.z,h.z,c.z,this.tension));b.set(ph.calc(a),qh.calc(a),rh.calc(a));return b};Aa.prototype.copy=function(a){I.prototype.copy.call(this,a);this.points=[];for(var b=0,c=a.points.length;bc.length-2?c.length-1:a+1];c=c[a>c.length-3?c.length-1:a+2];b.set(ki(d,e.x,f.x,g.x, +c.x),ki(d,e.y,f.y,g.y,c.y));return b};$a.prototype.copy=function(a){I.prototype.copy.call(this,a);this.points=[];for(var b=0,c=a.points.length;b=b)return b=c[a]-b,a=this.curves[a],c=a.getLength(),a.getPointAt(0===c?0:1-b/c);a++}return null},getLength:function(){var a=this.getCurveLengths();return a[a.length-1]},updateArcLengths:function(){this.needsUpdate=!0;this.cacheLengths=null;this.getCurveLengths()},getCurveLengths:function(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths;for(var a=[], +b=0,c=0,d=this.curves.length;cNumber.EPSILON){if(0>l&&(g=b[f],k=-k,h=b[e],l=-l),!(a.yh.y))if(a.y===g.y){if(a.x===g.x)return!0}else{e=l*(a.x-g.x)-k*(a.y-g.y);if(0===e)return!0;0>e||(d=!d)}}else if(a.y===g.y&&(h.x<=a.x&&a.x<=g.x||g.x<=a.x&&a.x<=h.x))return!0}return d}var e=tb.isClockWise,f=this.subPaths;if(0===f.length)return[];if(!0===b)return c(f);b=[];if(1===f.length){var g=f[0];var h=new Lb;h.curves=g.curves;b.push(h);return b}var l=!e(f[0].getPoints());l=a? +!l:l;h=[];var m=[],n=[],p=0;m[p]=void 0;n[p]=[];for(var q=0,t=f.length;qb;b++)this.coefficients[b].copy(a[b]);return this},zero:function(){for(var a=0;9>a;a++)this.coefficients[a].set(0,0,0);return this},getAt:function(a,b){var c=a.x,d=a.y;a=a.z;var e=this.coefficients;b.copy(e[0]).multiplyScalar(.282095);b.addScale(e[1],.488603*d);b.addScale(e[2],.488603*a);b.addScale(e[3],.488603*c);b.addScale(e[4],1.092548*c*d);b.addScale(e[5],1.092548*d*a);b.addScale(e[6],.315392*(3*a*a-1));b.addScale(e[7],1.092548*c*a);b.addScale(e[8], +.546274*(c*c-d*d));return b},getIrradianceAt:function(a,b){var c=a.x,d=a.y;a=a.z;var e=this.coefficients;b.copy(e[0]).multiplyScalar(.886227);b.addScale(e[1],1.023328*d);b.addScale(e[2],1.023328*a);b.addScale(e[3],1.023328*c);b.addScale(e[4],.858086*c*d);b.addScale(e[5],.858086*d*a);b.addScale(e[6],.743125*a*a-.247708);b.addScale(e[7],.858086*c*a);b.addScale(e[8],.429043*(c*c-d*d));return b},add:function(a){for(var b=0;9>b;b++)this.coefficients[b].add(a.coefficients[b]);return this},scale:function(a){for(var b= +0;9>b;b++)this.coefficients[b].multiplyScalar(a);return this},lerp:function(a,b){for(var c=0;9>c;c++)this.coefficients[c].lerp(a.coefficients[c],b);return this},equals:function(a){for(var b=0;9>b;b++)if(!this.coefficients[b].equals(a.coefficients[b]))return!1;return!0},copy:function(a){return this.set(a.coefficients)},clone:function(){return(new this.constructor).copy(this)},fromArray:function(a,b){void 0===b&&(b=0);for(var c=this.coefficients,d=0;9>d;d++)c[d].fromArray(a,b+3*d);return this},toArray:function(a, +b){void 0===a&&(a=[]);void 0===b&&(b=0);for(var c=this.coefficients,d=0;9>d;d++)c[d].toArray(a,b+3*d);return a}});Object.assign(uf,{getBasisAt:function(a,b){var c=a.x,d=a.y;a=a.z;b[0]=.282095;b[1]=.488603*d;b[2]=.488603*a;b[3]=.488603*c;b[4]=1.092548*c*d;b[5]=1.092548*d*a;b[6]=.315392*(3*a*a-1);b[7]=1.092548*c*a;b[8]=.546274*(c*c-d*d)}});bb.prototype=Object.assign(Object.create(ba.prototype),{constructor:bb,isLightProbe:!0,copy:function(a){ba.prototype.copy.call(this,a);this.sh.copy(a.sh);this.intensity= +a.intensity;return this},toJSON:function(a){return ba.prototype.toJSON.call(this,a)}});Gg.prototype=Object.assign(Object.create(bb.prototype),{constructor:Gg,isHemisphereLightProbe:!0,copy:function(a){bb.prototype.copy.call(this,a);return this},toJSON:function(a){return bb.prototype.toJSON.call(this,a)}});Hg.prototype=Object.assign(Object.create(bb.prototype),{constructor:Hg,isAmbientLightProbe:!0,copy:function(a){bb.prototype.copy.call(this,a);return this},toJSON:function(a){return bb.prototype.toJSON.call(this, +a)}});var cj=new O,dj=new O;Object.assign(li.prototype,{update:function(a){var b=this._cache;if(b.focus!==a.focus||b.fov!==a.fov||b.aspect!==a.aspect*this.aspect||b.near!==a.near||b.far!==a.far||b.zoom!==a.zoom||b.eyeSep!==this.eyeSep){b.focus=a.focus;b.fov=a.fov;b.aspect=a.aspect*this.aspect;b.near=a.near;b.far=a.far;b.zoom=a.zoom;b.eyeSep=this.eyeSep;var c=a.projectionMatrix.clone(),d=b.eyeSep/2,e=d*b.near/b.focus,f=b.near*Math.tan(P.DEG2RAD*b.fov*.5)/b.zoom;dj.elements[12]=-d;cj.elements[12]=d; +d=-f*b.aspect+e;var g=f*b.aspect+e;c.elements[0]=2*b.near/(g-d);c.elements[8]=(g+d)/(g-d);this.cameraL.projectionMatrix.copy(c);d=-f*b.aspect-e;g=f*b.aspect-e;c.elements[0]=2*b.near/(g-d);c.elements[8]=(g+d)/(g-d);this.cameraR.projectionMatrix.copy(c)}this.cameraL.matrixWorld.copy(a.matrixWorld).multiply(dj);this.cameraR.matrixWorld.copy(a.matrixWorld).multiply(cj)}});Object.assign(Ig.prototype,{start:function(){this.oldTime=this.startTime=("undefined"===typeof performance?Date:performance).now(); +this.elapsedTime=0;this.running=!0},stop:function(){this.getElapsedTime();this.autoStart=this.running=!1},getElapsedTime:function(){this.getDelta();return this.elapsedTime},getDelta:function(){var a=0;if(this.autoStart&&!this.running)return this.start(),0;if(this.running){var b=("undefined"===typeof performance?Date:performance).now();a=(b-this.oldTime)/1E3;this.oldTime=b;this.elapsedTime+=a}return a}});var wc=new n,ej=new Da,dl=new n,xc=new n;Jg.prototype=Object.assign(Object.create(D.prototype), +{constructor:Jg,getInput:function(){return this.gain},removeFilter:function(){null!==this.filter&&(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination),this.gain.connect(this.context.destination),this.filter=null);return this},getFilter:function(){return this.filter},setFilter:function(a){null!==this.filter?(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination)):this.gain.disconnect(this.context.destination);this.filter=a;this.gain.connect(this.filter); +this.filter.connect(this.context.destination);return this},getMasterVolume:function(){return this.gain.gain.value},setMasterVolume:function(a){this.gain.gain.setTargetAtTime(a,this.context.currentTime,.01);return this},updateMatrixWorld:function(a){D.prototype.updateMatrixWorld.call(this,a);a=this.context.listener;var b=this.up;this.timeDelta=this._clock.getDelta();this.matrixWorld.decompose(wc,ej,dl);xc.set(0,0,-1).applyQuaternion(ej);if(a.positionX){var c=this.context.currentTime+this.timeDelta; +a.positionX.linearRampToValueAtTime(wc.x,c);a.positionY.linearRampToValueAtTime(wc.y,c);a.positionZ.linearRampToValueAtTime(wc.z,c);a.forwardX.linearRampToValueAtTime(xc.x,c);a.forwardY.linearRampToValueAtTime(xc.y,c);a.forwardZ.linearRampToValueAtTime(xc.z,c);a.upX.linearRampToValueAtTime(b.x,c);a.upY.linearRampToValueAtTime(b.y,c);a.upZ.linearRampToValueAtTime(b.z,c)}else a.setPosition(wc.x,wc.y,wc.z),a.setOrientation(xc.x,xc.y,xc.z,b.x,b.y,b.z)}});id.prototype=Object.assign(Object.create(D.prototype), +{constructor:id,getOutput:function(){return this.gain},setNodeSource:function(a){this.hasPlaybackControl=!1;this.sourceType="audioNode";this.source=a;this.connect();return this},setMediaElementSource:function(a){this.hasPlaybackControl=!1;this.sourceType="mediaNode";this.source=this.context.createMediaElementSource(a);this.connect();return this},setMediaStreamSource:function(a){this.hasPlaybackControl=!1;this.sourceType="mediaStreamNode";this.source=this.context.createMediaStreamSource(a);this.connect(); +return this},setBuffer:function(a){this.buffer=a;this.sourceType="buffer";this.autoplay&&this.play();return this},play:function(a){void 0===a&&(a=0);if(!0===this.isPlaying)console.warn("THREE.Audio: Audio is already playing.");else if(!1===this.hasPlaybackControl)console.warn("THREE.Audio: this Audio has no playback control.");else return this._startedAt=this.context.currentTime+a,a=this.context.createBufferSource(),a.buffer=this.buffer,a.loop=this.loop,a.loopStart=this.loopStart,a.loopEnd=this.loopEnd, +a.onended=this.onEnded.bind(this),a.start(this._startedAt,this._pausedAt+this.offset,this.duration),this.isPlaying=!0,this.source=a,this.setDetune(this.detune),this.setPlaybackRate(this.playbackRate),this.connect()},pause:function(){if(!1===this.hasPlaybackControl)console.warn("THREE.Audio: this Audio has no playback control.");else return!0===this.isPlaying&&(this._pausedAt=(this.context.currentTime-this._startedAt)*this.playbackRate,this.source.stop(),this.source.onended=null,this.isPlaying=!1), +this},stop:function(){if(!1===this.hasPlaybackControl)console.warn("THREE.Audio: this Audio has no playback control.");else return this._pausedAt=0,this.source.stop(),this.source.onended=null,this.isPlaying=!1,this},connect:function(){if(0d&&this._mixBufferRegion(c,a,3*b,1-d,b);d=b;for(var f=b+b;d!==f;++d)if(c[d]!==c[d+b]){e.setValue(c,a);break}},saveOriginalState:function(){var a=this.buffer,b=this.valueSize,c=3*b;this.binding.getValue(a,c);for(var d=b;d!==c;++d)a[d]=a[c+d%b];this.cumulativeWeight=0},restoreOriginalState:function(){this.binding.setValue(this.buffer,3*this.valueSize)},_select:function(a, +b,c,d,e){if(.5<=d)for(d=0;d!==e;++d)a[b+d]=a[c+d]},_slerp:function(a,b,c,d){Da.slerpFlat(a,b,a,b,a,c,d)},_lerp:function(a,b,c,d,e){for(var f=1-d,g=0;g!==e;++g){var h=b+g;a[h]=a[h]*f+a[c+g]*d}}});var fl=/[\[\]\.:\/]/g,gl="[^"+"\\[\\]\\.:\\/".replace("\\.","")+"]",hl=/((?:WC+[\/:])*)/.source.replace("WC","[^\\[\\]\\.:\\/]"),il=/(WCOD+)?/.source.replace("WCOD",gl),jl=/(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace("WC","[^\\[\\]\\.:\\/]"),kl=/\.(WC+)(?:\[(.+)\])?/.source.replace("WC","[^\\[\\]\\.:\\/]"), +ll=new RegExp("^"+hl+il+jl+kl+"$"),ml=["material","materials","bones"];Object.assign(mi.prototype,{getValue:function(a,b){this.bind();var c=this._bindings[this._targetGroup.nCachedObjects_];void 0!==c&&c.getValue(a,b)},setValue:function(a,b){for(var c=this._bindings,d=this._targetGroup.nCachedObjects_,e=c.length;d!==e;++d)c[d].setValue(a,b)},bind:function(){for(var a=this._bindings,b=this._targetGroup.nCachedObjects_,c=a.length;b!==c;++b)a[b].bind()},unbind:function(){for(var a=this._bindings,b=this._targetGroup.nCachedObjects_, +c=a.length;b!==c;++b)a[b].unbind()}});Object.assign(Ba,{Composite:mi,create:function(a,b,c){return a&&a.isAnimationObjectGroup?new Ba.Composite(a,b,c):new Ba(a,b,c)},sanitizeNodeName:function(a){return a.replace(/\s/g,"_").replace(fl,"")},parseTrackName:function(a){var b=ll.exec(a);if(!b)throw Error("PropertyBinding: Cannot parse trackName: "+a);b={nodeName:b[2],objectName:b[3],objectIndex:b[4],propertyName:b[5],propertyIndex:b[6]};var c=b.nodeName&&b.nodeName.lastIndexOf(".");if(void 0!==c&&-1!== +c){var d=b.nodeName.substring(c+1);-1!==ml.indexOf(d)&&(b.nodeName=b.nodeName.substring(0,c),b.objectName=d)}if(null===b.propertyName||0===b.propertyName.length)throw Error("PropertyBinding: can not parse propertyName from trackName: "+a);return b},findNode:function(a,b){if(!b||""===b||"root"===b||"."===b||-1===b||b===a.name||b===a.uuid)return a;if(a.skeleton){var c=a.skeleton.getBoneByName(b);if(void 0!==c)return c}if(a.children){var d=function(a){for(var c=0;c=b){var n=b++,p=a[n];c[p.uuid]=m;a[m]=p;c[l]=n;a[n]=h;h=0;for(l=e;h!==l;++h){p=d[h];var q=p[m];p[m]=p[n];p[n]=q}}}this.nCachedObjects_=b},uncache:function(){for(var a=this._objects,b=a.length,c=this.nCachedObjects_,d=this._indicesByUUID,e=this._bindings,f=e.length,g=0,h=arguments.length;g!==h;++g){var l=arguments[g].uuid,m=d[l];if(void 0!==m)if(delete d[l],mb||0===c)return;this._startTime=null;b*=c}b*=this._updateTimeScale(a);c=this._updateTime(b);a=this._updateWeight(a);if(0c.parameterPositions[1]&&(this.stopFading(),0===d&&(this.enabled=!1))}}return this._effectiveWeight=b},_updateTimeScale:function(a){var b=0;if(!this.paused){b=this.timeScale;var c=this._timeScaleInterpolant;if(null!==c){var d=c.evaluate(a)[0]; +b*=d;a>c.parameterPositions[1]&&(this.stopWarping(),0===b?this.paused=!0:this.timeScale=b)}}return this._effectiveTimeScale=b},_updateTime:function(a){var b=this.time+a,c=this._clip.duration,d=this.loop,e=this._loopCount,f=2202===d;if(0===a)return-1===e?b:f&&1===(e&1)?c-b:b;if(2200===d)a:{if(-1===e&&(this._loopCount=0,this._setEndings(!0,!0,!1)),b>=c)b=c;else if(0>b)b=0;else{this.time=b;break a}this.clampWhenFinished?this.paused=!0:this.enabled=!1;this.time=b;this._mixer.dispatchEvent({type:"finished", +action:this,direction:0>a?-1:1})}else{-1===e&&(0<=a?(e=0,this._setEndings(!0,0===this.repetitions,f)):this._setEndings(0===this.repetitions,!0,f));if(b>=c||0>b){d=Math.floor(b/c);b-=c*d;e+=Math.abs(d);var g=this.repetitions-e;0>=g?(this.clampWhenFinished?this.paused=!0:this.enabled=!1,this.time=b=0a,this._setEndings(a,!a,f)):this._setEndings(!1,!1,f),this._loopCount=e,this.time=b,this._mixer.dispatchEvent({type:"loop", +action:this,loopDelta:d}))}else this.time=b;if(f&&1===(e&1))return c-b}return b},_setEndings:function(a,b,c){var d=this._interpolantSettings;c?(d.endingStart=2401,d.endingEnd=2401):(d.endingStart=a?this.zeroSlopeAtStart?2401:2400:2402,d.endingEnd=b?this.zeroSlopeAtEnd?2401:2400:2402)},_scheduleFading:function(a,b,c){var d=this._mixer,e=d.time,f=this._weightInterpolant;null===f&&(this._weightInterpolant=f=d._lendControlInterpolant());d=f.parameterPositions;f=f.sampleValues;d[0]=e;f[0]=b;d[1]=e+a;f[1]= +c;return this}});Og.prototype=Object.assign(Object.create(Fa.prototype),{constructor:Og,_bindAction:function(a,b){var c=a._localRoot||this._root,d=a._clip.tracks,e=d.length,f=a._propertyBindings;a=a._interpolants;var g=c.uuid,h=this._bindingsByRootAndName,l=h[g];void 0===l&&(l={},h[g]=l);for(h=0;h!==e;++h){var m=d[h],n=m.name,p=l[n];if(void 0===p){p=f[h];if(void 0!==p){null===p._cacheIndex&&(++p.referenceCount,this._addInactiveBinding(p,g,n));continue}p=new Ng(Ba.create(c,n,b&&b._propertyBindings[h].binding.parsedPath), +m.ValueTypeName,m.getValueSize());++p.referenceCount;this._addInactiveBinding(p,g,n)}f[h]=p;a[h].resultBuffer=p.buffer}},_activateAction:function(a){if(!this._isActiveAction(a)){if(null===a._cacheIndex){var b=(a._localRoot||this._root).uuid,c=a._clip.uuid,d=this._actionsByClip[c];this._bindAction(a,d&&d.knownActions[0]);this._addInactiveAction(a,c,b)}b=a._propertyBindings;c=0;for(d=b.length;c!==d;++c){var e=b[c];0===e.useCount++&&(this._lendBinding(e),e.saveOriginalState())}this._lendAction(a)}}, +_deactivateAction:function(a){if(this._isActiveAction(a)){for(var b=a._propertyBindings,c=0,d=b.length;c!==d;++c){var e=b[c];0===--e.useCount&&(e.restoreOriginalState(),this._takeBackBinding(e))}this._takeBackAction(a)}},_initMemoryManager:function(){this._actions=[];this._nActiveActions=0;this._actionsByClip={};this._bindings=[];this._nActiveBindings=0;this._bindingsByRootAndName={};this._controlInterpolants=[];this._nActiveControlInterpolants=0;var a=this;this.stats={actions:{get total(){return a._actions.length}, +get inUse(){return a._nActiveActions}},bindings:{get total(){return a._bindings.length},get inUse(){return a._nActiveBindings}},controlInterpolants:{get total(){return a._controlInterpolants.length},get inUse(){return a._nActiveControlInterpolants}}}},_isActiveAction:function(a){a=a._cacheIndex;return null!==a&&athis.max.x||a.ythis.max.y?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y},getParameter:function(a, +b){void 0===b&&(console.warn("THREE.Box2: .getParameter() target is now required"),b=new w);return b.set((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y))},intersectsBox:function(a){return a.max.xthis.max.x||a.max.ythis.max.y?!1:!0},clampPoint:function(a,b){void 0===b&&(console.warn("THREE.Box2: .clampPoint() target is now required"),b=new w);return b.copy(a).clamp(this.min,this.max)},distanceToPoint:function(a){return gj.copy(a).clamp(this.min, +this.max).sub(a).length()},intersect:function(a){this.min.max(a.min);this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},translate:function(a){this.min.add(a);this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)}});var hj=new n,Wf=new n;Object.assign(Sg.prototype,{set:function(a,b){this.start.copy(a);this.end.copy(b);return this},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.start.copy(a.start); +this.end.copy(a.end);return this},getCenter:function(a){void 0===a&&(console.warn("THREE.Line3: .getCenter() target is now required"),a=new n);return a.addVectors(this.start,this.end).multiplyScalar(.5)},delta:function(a){void 0===a&&(console.warn("THREE.Line3: .delta() target is now required"),a=new n);return a.subVectors(this.end,this.start)},distanceSq:function(){return this.start.distanceToSquared(this.end)},distance:function(){return this.start.distanceTo(this.end)},at:function(a,b){void 0=== +b&&(console.warn("THREE.Line3: .at() target is now required"),b=new n);return this.delta(b).multiplyScalar(a).add(this.start)},closestPointToPointParameter:function(a,b){hj.subVectors(a,this.start);Wf.subVectors(this.end,this.start);a=Wf.dot(Wf);a=Wf.dot(hj)/a;b&&(a=P.clamp(a,0,1));return a},closestPointToPoint:function(a,b,c){a=this.closestPointToPointParameter(a,b);void 0===c&&(console.warn("THREE.Line3: .closestPointToPoint() target is now required"),c=new n);return this.delta(c).multiplyScalar(a).add(this.start)}, +applyMatrix4:function(a){this.start.applyMatrix4(a);this.end.applyMatrix4(a);return this},equals:function(a){return a.start.equals(this.start)&&a.end.equals(this.end)}});ue.prototype=Object.create(D.prototype);ue.prototype.constructor=ue;ue.prototype.isImmediateRenderObject=!0;var ij=new n;jd.prototype=Object.create(D.prototype);jd.prototype.constructor=jd;jd.prototype.dispose=function(){this.cone.geometry.dispose();this.cone.material.dispose()};jd.prototype.update=function(){this.light.updateMatrixWorld(); +var a=this.light.distance?this.light.distance:1E3,b=a*Math.tan(this.light.angle);this.cone.scale.set(b,b,a);ij.setFromMatrixPosition(this.light.target.matrixWorld);this.cone.lookAt(ij);void 0!==this.color?this.cone.material.color.set(this.color):this.cone.material.color.copy(this.light.color)};var Rb=new n,Xf=new O,vh=new O;kd.prototype=Object.create(ma.prototype);kd.prototype.constructor=kd;kd.prototype.updateMatrixWorld=function(a){var b=this.bones,c=this.geometry,d=c.getAttribute("position");vh.getInverse(this.root.matrixWorld); +for(var e=0,f=0;eMath.abs(b)&&(b=1E-8);this.scale.set(.5*this.size,.5*this.size,b);this.children[0].material.side=0>b?1:0;this.lookAt(this.plane.normal);D.prototype.updateMatrixWorld.call(this,a)};var nj=new n,zf,Tg;yb.prototype=Object.create(D.prototype);yb.prototype.constructor=yb;yb.prototype.setDirection=function(a){.99999< +a.y?this.quaternion.set(0,0,0,1):-.99999>a.y?this.quaternion.set(1,0,0,0):(nj.set(a.z,0,-a.x).normalize(),this.quaternion.setFromAxisAngle(nj,Math.acos(a.y)))};yb.prototype.setLength=function(a,b,c){void 0===b&&(b=.2*a);void 0===c&&(c=.2*b);this.line.scale.set(1,Math.max(1E-4,a-b),1);this.line.updateMatrix();this.cone.scale.set(c,b,c);this.cone.position.y=a;this.cone.updateMatrix()};yb.prototype.setColor=function(a){this.line.material.color.set(a);this.cone.material.color.set(a)};yb.prototype.copy= +function(a){D.prototype.copy.call(this,a,!1);this.line.copy(a.line);this.cone.copy(a.cone);return this};yb.prototype.clone=function(){return(new this.constructor).copy(this)};ye.prototype=Object.create(ma.prototype);ye.prototype.constructor=ye;var lb=Math.pow(2,8),oj=[.125,.215,.35,.446,.526,.582],yi=5+oj.length,mb={3E3:0,3001:1,3002:2,3004:3,3005:4,3006:5,3007:6},Xg=new hd,Af=function(a){var b=new Float32Array(a),c=new n(0,1,0);a=new vb({defines:{n:a},uniforms:{envMap:{value:null},samples:{value:1}, +weights:{value:b},latitudinal:{value:!1},dTheta:{value:0},mipInt:{value:0},poleAxis:{value:c},inputEncoding:{value:mb[3E3]},outputEncoding:{value:mb[3E3]}},vertexShader:Zg(),fragmentShader:"\nprecision mediump float;\nprecision mediump int;\nvarying vec3 vOutputDirection;\nuniform sampler2D envMap;\nuniform int samples;\nuniform float weights[n];\nuniform bool latitudinal;\nuniform float dTheta;\nuniform float mipInt;\nuniform vec3 poleAxis;\n\n"+$g()+"\n\n#define ENVMAP_TYPE_CUBE_UV\n#include \n\nvoid main() {\n\tgl_FragColor = vec4(0.0);\n\tfor (int i = 0; i < n; i++) {\n\t\tif (i >= samples)\n\t\t\tbreak;\n\t\tfor (int dir = -1; dir < 2; dir += 2) {\n\t\t\tif (i == 0 && dir == 1)\n\t\t\t\tcontinue;\n\t\t\tvec3 axis = latitudinal ? poleAxis : cross(poleAxis, vOutputDirection);\n\t\t\tif (all(equal(axis, vec3(0.0))))\n\t\t\t\taxis = cross(vec3(0.0, 1.0, 0.0), vOutputDirection);\n\t\t\taxis = normalize(axis);\n\t\t\tfloat theta = dTheta * float(dir * i);\n\t\t\tfloat cosTheta = cos(theta);\n\t\t\t// Rodrigues' axis-angle rotation\n\t\t\tvec3 sampleDirection = vOutputDirection * cosTheta\n\t\t\t\t\t+ cross(axis, vOutputDirection) * sin(theta)\n\t\t\t\t\t+ axis * dot(axis, vOutputDirection) * (1.0 - cosTheta);\n\t\t\tgl_FragColor.rgb +=\n\t\t\t\t\tweights[i] * bilinearCubeUV(envMap, sampleDirection, mipInt);\n\t\t}\n\t}\n\tgl_FragColor = linearToOutputTexel(gl_FragColor);\n}\n\t\t", +blending:0,depthTest:!1,depthWrite:!1});a.type="SphericalGaussianBlur";return a}(20),Sb=null,Tb=null,wh=function(){for(var a=[],b=[],c=[],d=8,e=0;em;m++){var n=m%3*2/3-1,p=2p;p++)q=p%3,0==q?(c.up.set(0,d[p],0),c.lookAt(f[p],0,0)):1==q?(c.up.set(0,0,d[p]),c.lookAt(0,f[p],0)):(c.up.set(0,d[p],0),c.lookAt(0,0,f[p])),Yg(e,q*lb,2Has Color: ${hasColorData}`; +} + + +function InitializeScene() { + + camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); + + scene = new THREE.Scene(); + renderer = new THREE.WebGLRenderer({ + "canvas" : document.getElementById("viewport") + }); + + pointsGeometry = new THREE.BufferGeometry(); + pointsMaterial = new THREE.PointsMaterial( { + color: 0x888888, + size: 0.25, + vertexColors: THREE.VertexColors + + } ); + + pointsMesh = new THREE.Points(pointsGeometry, pointsMaterial); + let s = 1; + pointsMesh.scale.set(s,s,s); + pointsMesh.position.y = -5; + + scene.add(pointsMesh); + + camera.position.set(0, 10, 50); + camera.lookAt(scene.position); + + resizeViewport(); + render(); + + sceneReady = true; +} + + +function resizeViewport() { + let height = window.innerHeight; + let width = window.innerWidth; + + let aspectRatio = width / height; + + renderer.setSize(width,height); + camera.aspect = aspectRatio; + camera.updateProjectionMatrix(); +} + + +function render() { + + requestAnimationFrame(render); + + let deltaTime = Date.now() - lastFrameTime; + + if(lastFrameTime == 0) { + deltaTime = 0; + } + + renderer.render(scene, camera); + + pointsMesh.rotation.y += deltaTime * 0.0001; + lastFrameTime = Date.now(); + +} + +window.addEventListener("resize", resizeViewport); +InitializeScene(); \ No newline at end of file diff --git a/streaming-pointcloud/examples/threejs/webgl-screenshot.jpg b/streaming-pointcloud/examples/threejs/webgl-screenshot.jpg new file mode 100644 index 00000000..7727e4fd Binary files /dev/null and b/streaming-pointcloud/examples/threejs/webgl-screenshot.jpg differ diff --git a/streaming-pointcloud/kinect capture/Eigen.MPL2 b/streaming-pointcloud/kinect capture/Eigen.MPL2 new file mode 100644 index 00000000..09f91efd --- /dev/null +++ b/streaming-pointcloud/kinect capture/Eigen.MPL2 @@ -0,0 +1,375 @@ +Eigen3 source obtained at: https://github.com/eigenteam/eigen-git-mirror + +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/streaming-pointcloud/kinect capture/README.md b/streaming-pointcloud/kinect capture/README.md new file mode 100644 index 00000000..ed9dc7ab --- /dev/null +++ b/streaming-pointcloud/kinect capture/README.md @@ -0,0 +1,97 @@ +# Azure Kinect Capture + +This application will capture depth frames from the Azure Kinect camera and transmit them as a set of 3D points via MQTT, with or without the matching RGB colors for each point. It can also perform translation and rotation of the depth points prior to transmission in order to align multiple cameras in the same phsyical space. + +**Note:** This application provides a depth data source and does not do much by itself. It's meant to be used in conjunction with other applications that make use of the depth data. + +# Prerequisites + +In order to use this application, you will need the following: + +1. An Azure Kinect camera +1. An MQTT broker such as [Mosquitto](https://mosquitto.org/download) +1. The executable `'kinect capture.exe'` which is available in this repository or can be compiled from source. + + +# Usage + +This is a command line application with two optional arguments. + +``` +'kinect capture.exe' [device index] [timeout] +``` + ++ `[device index]` The numeric index of the device (used when there are multiple cameras connected to a single computer). Default is zero. ++ `[timeout]` The timeout, in milliseconds, when waiting for frames (see _insert link to kinect documentation_ for more information). Default is 10 milliseconds. + + +# Configuration + +For configuration, the application will look for a file named `settings[device index].toml` where `[device index]` matches the optional device index command line argument. + +This means that the application will attempt to open `settings0.toml` if no device index is specified. + +## Settings TOML + +The settings TOML file contains the following values. + +| Property | Description | +| ---- | --- | +| `file`| The name of the TOML file containing camera transform and clipping values (see below). | + +### [MqttInfo] Section + +Connection settings for the MQTT client are stored in the `[MqttInfo]` section. + +| Property | Description | +| ---- | --- | +| `host` | the IP address of the MQTT broker | +| `port` | the port for the MQTT broker (typically this is 1883) | +| `id` | the MQTT client ID for this application (this must be unique among clients). | +| `topic` | the MQTT topic upon which the depth frames will be published. | +| `keepalive` | The MQTT keepalive interval, in seconds | +| `clean_session` | The `clean_session` value to use when connecting to the broker (see MQTT spec) | + + +## Camera Transform TOML + +Camera translation, rotation, and clipping values are specified in a separate TOML file. The name of this file is configurable via the `file` property in the settings TOML (see above). + +By specifying these values you can compensate for the position of the camera in physical space, and cull any points that fall outside a specific region of interest (such as distant objects, walls, floor, ceiling, etc). + +The transformation values are applied first, then the transformed points are tested + +The file must contain the following values: + +### [Camera] Section + +| Property | Description | +| ---- | --- | +| `translation` | The X, Y, and Z translation, in millimeters, to apply to all points. | +| `rotation` | The X, Y, and Z rotation, in degrees, to apply to all points. | +| `min` | The minimum X, Y, and Z boundary, in millimeters, for culling points. | +| `max` | The maximum X, Y, and Z boundary, in millimeters, for culling points. | + +# Compiling from Source + +To compile this application from source, you will need the following: + ++ Visual Studio 2019 with MSVC v142 or greater + ++ Install the following packages via [Vcpkg](https://github.com/microsoft/vcpkg) + + boost:x64-windows + + eigen3:x64-windows + + mosquitto:x64-windows + ++ If you experience problems compiling the projects related to the Kinect SDK or libraries, it may be that you need to manually add the Microsoft Azure Kinect Sensor package. You can do this from within Visual Studio via the Nuget Package Manager. + + In Visual Studio, open the `Tools` menu and select `NuGet Package Manager > Manage NuGet Packages for Solution...` + + Search for `Microsoft.Azure.Kinect.Sensor` and install it. + ++ [TomlParser](https://github.com/ToruNiina/TOMLParser) Library + + Download or clone the repository and copy the contents to ```packages/``` + + Insert ```#pragma warning(disable : 4996) //_CRT_SECURE_NO_WARNINGS``` to the top of ```src/toml_parser.hpp``` + +Once you have all of these prerequisites, open `kinect capture.sln` in Visual Studio to build the application. + +# License +The Eigen3 library is under the MPL2.0 License, information regarding the license can be found [here](./Eigen.MPL2). diff --git a/streaming-pointcloud/kinect capture/Release.zip b/streaming-pointcloud/kinect capture/Release.zip new file mode 100644 index 00000000..a8eda078 Binary files /dev/null and b/streaming-pointcloud/kinect capture/Release.zip differ diff --git a/streaming-pointcloud/kinect capture/kinect capture.sln b/streaming-pointcloud/kinect capture/kinect capture.sln new file mode 100644 index 00000000..45cefd98 --- /dev/null +++ b/streaming-pointcloud/kinect capture/kinect capture.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29728.190 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kinect capture", "kinect capture\kinect capture.vcxproj", "{1454E4C3-778C-4601-9B93-6F70719DB1B3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1454E4C3-778C-4601-9B93-6F70719DB1B3}.Debug|x64.ActiveCfg = Debug|x64 + {1454E4C3-778C-4601-9B93-6F70719DB1B3}.Debug|x64.Build.0 = Debug|x64 + {1454E4C3-778C-4601-9B93-6F70719DB1B3}.Debug|x86.ActiveCfg = Debug|Win32 + {1454E4C3-778C-4601-9B93-6F70719DB1B3}.Debug|x86.Build.0 = Debug|Win32 + {1454E4C3-778C-4601-9B93-6F70719DB1B3}.Release|x64.ActiveCfg = Release|x64 + {1454E4C3-778C-4601-9B93-6F70719DB1B3}.Release|x64.Build.0 = Release|x64 + {1454E4C3-778C-4601-9B93-6F70719DB1B3}.Release|x86.ActiveCfg = Release|Win32 + {1454E4C3-778C-4601-9B93-6F70719DB1B3}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1652DD3B-7B2C-4D8F-B00C-C55E401277F6} + EndGlobalSection +EndGlobal diff --git a/streaming-pointcloud/kinect capture/kinect capture/cameraposition.toml b/streaming-pointcloud/kinect capture/kinect capture/cameraposition.toml new file mode 100644 index 00000000..ae1269ab --- /dev/null +++ b/streaming-pointcloud/kinect capture/kinect capture/cameraposition.toml @@ -0,0 +1,5 @@ +[Camera] +translation = [0, 0, 0] +rotation = [0, 0, 0] +min = [-2000, 0, -1500] +max = [2000, 2000, 2000] \ No newline at end of file diff --git a/streaming-pointcloud/kinect capture/kinect capture/cameraposition0.toml b/streaming-pointcloud/kinect capture/kinect capture/cameraposition0.toml new file mode 100644 index 00000000..ae1269ab --- /dev/null +++ b/streaming-pointcloud/kinect capture/kinect capture/cameraposition0.toml @@ -0,0 +1,5 @@ +[Camera] +translation = [0, 0, 0] +rotation = [0, 0, 0] +min = [-2000, 0, -1500] +max = [2000, 2000, 2000] \ No newline at end of file diff --git a/streaming-pointcloud/kinect capture/kinect capture/cameraposition1.toml b/streaming-pointcloud/kinect capture/kinect capture/cameraposition1.toml new file mode 100644 index 00000000..f95be626 --- /dev/null +++ b/streaming-pointcloud/kinect capture/kinect capture/cameraposition1.toml @@ -0,0 +1,5 @@ +[Camera] +translation = [0, 0, 0] +rotation = [0, 0, 0] +min = [-2000, 0, -1500] +max = [2000, 2000, 2000] diff --git a/streaming-pointcloud/kinect capture/kinect capture/cameraposition2.toml b/streaming-pointcloud/kinect capture/kinect capture/cameraposition2.toml new file mode 100644 index 00000000..ae1269ab --- /dev/null +++ b/streaming-pointcloud/kinect capture/kinect capture/cameraposition2.toml @@ -0,0 +1,5 @@ +[Camera] +translation = [0, 0, 0] +rotation = [0, 0, 0] +min = [-2000, 0, -1500] +max = [2000, 2000, 2000] \ No newline at end of file diff --git a/streaming-pointcloud/kinect capture/kinect capture/kinect capture.cpp b/streaming-pointcloud/kinect capture/kinect capture/kinect capture.cpp new file mode 100644 index 00000000..c5bf45a9 --- /dev/null +++ b/streaming-pointcloud/kinect capture/kinect capture/kinect capture.cpp @@ -0,0 +1,90 @@ +#include "mqtt.h" +#include "kinectCamera.h" + +mqtt mosquittoWrapper; +kinectCamera camera; + +int main(int argc, char* argv[]) +{ + int deviceIndex = 0; + int timeoutMS = 10; + + //Set the device index if the commandline argument was supplied. Keep at 0 if not. + if (argc < 2) { + std::cout << "Did not supply deviceIndex argument, using 0 as the default" << std::endl; + } + else { + deviceIndex = std::atoi(argv[1]); + } + //Set the timeoutMS values (how long to wait for a capture from the Kinect for Azure camera to have an image ready) + if (argc < 3) { + std::cout << "Did not supply timeoutMS argument, using 10 as the default" << std::endl; + } + else { + timeoutMS = std::atoi(argv[2]); + } + + //Initialize the mqtt library + mosquittoWrapper.initMqttLib(); + + //Set the index of the camera and parse the toml, passes in mosquittoWrapper to have it parse its table as well + camera.setCameraIndex(deviceIndex); + camera.parseToml(mosquittoWrapper); + + //Setup callbacks, connect, and subscribe to the necessary topics for the app to run + mosquittoWrapper.callbacks(); + mosquittoWrapper.connect(); + + mosquittoWrapper.subscribe((char*)TOPIC_CAMERA_CONFIGURE); + mosquittoWrapper.subscribe((char*)TOPIC_CONTROL); + mosquittoWrapper.subscribe((char*)"calibrate", true); + + //Start the mosquitto loop + mosquitto_loop_start(mosquittoWrapper.giveMosquitto()); + std::string topic(mosquittoWrapper.giveTopic()); + + //While camera is not done capturing + //Main Loop + while (!camera.isDone()) { + //Connect to the camera + camera.connectCamera(); + camera.checkSyncCables(); + std::cout << "Camera is in "; + if (camera.isSubordinate()) { + std::cout << "SUBORDINATE mode." << std::endl; + } + else { + std::cout << "MASTER/STANDALONE mode." << std::endl; + } + std::cout << "Waiting for response from the merger" << std::endl; + do { + //Wait to get the configuration form the merger, send a message every second + mosquittoWrapper.sendMessage((int)topic.size(), topic.c_str(), (char*)TOPIC_CAMERA_AVAILBLE); + std::this_thread::sleep_for(std::chrono::seconds(1)); + } while (!camera.isReady() && !camera.isRestart()); + //Check to see if the while loop was exited because of restarting, or because camera received + //the configuration from the merger + std::cout << "Starting capture" << std::endl; + if (!camera.isRestart()) { + //If it didn't leave because of restart, reset ready variable and start camera up + camera.setReady(false); + camera.startCamera(); + camera.setCameraCalibrationandTransformation(); + } + //Main loop for capturing the image + while (!camera.isDone() && !camera.isRestart()) { + if (camera.takeCaptureCamera(timeoutMS)) { + camera.processCaptureCamera(mosquittoWrapper); + } + } + //Exit restart Loop + camera.setRestart(false); + camera.disconnectCamera(); + } + //Exit Main Loop + + //Exited main loop, close mosquitto and clean up the library + mosquittoWrapper.disconnect(); + mosquittoWrapper.finishMosquitto(); + return 0; +} diff --git a/streaming-pointcloud/kinect capture/kinect capture/kinect capture.vcxproj b/streaming-pointcloud/kinect capture/kinect capture/kinect capture.vcxproj new file mode 100644 index 00000000..52204056 --- /dev/null +++ b/streaming-pointcloud/kinect capture/kinect capture/kinect capture.vcxproj @@ -0,0 +1,201 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + {1454E4C3-778C-4601-9B93-6F70719DB1B3} + Win32Proj + kinectcapture + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + + + Level3 + true + + + true + MultiThreaded + + + Console + true + + + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + Level3 + true + true + true + + + true + MultiThreaded + + + Console + true + true + true + + + + + + + + + + + + + + + + Document + + + Document + + + Document + + + Document + + + + Document + + + Document + + + Document + + + Document + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/streaming-pointcloud/kinect capture/kinect capture/kinect capture.vcxproj.filters b/streaming-pointcloud/kinect capture/kinect capture/kinect capture.vcxproj.filters new file mode 100644 index 00000000..185e7e38 --- /dev/null +++ b/streaming-pointcloud/kinect capture/kinect capture/kinect capture.vcxproj.filters @@ -0,0 +1,71 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + \ No newline at end of file diff --git a/streaming-pointcloud/kinect capture/kinect capture/kinectCamera.cpp b/streaming-pointcloud/kinect capture/kinect capture/kinectCamera.cpp new file mode 100644 index 00000000..e91fcfff --- /dev/null +++ b/streaming-pointcloud/kinect capture/kinect capture/kinectCamera.cpp @@ -0,0 +1,807 @@ +#include "kinectCamera.h" +#include + +//-----------------------------------------public functions-----------------------------------------// + +//-----KinectCamera default contstructor------// +/* +Set all members to their respective 0 default +Have the message buffer be the max possible buffer required for an image +Add 180 degrees to the x-axis for rotation +*/ +kinectCamera::kinectCamera() { + this->deviceIndex = 0; + this->color = false; + this->kinectDeviceCaptureTimeStamp = 0; + this->kinectDevice = nullptr; + this->kinectDeviceCapture = nullptr; + this->kinectDeviceCaptureDepthImage = nullptr; + this->kinectDeviceCaptureXYZImage = nullptr; + this->kinectDeviceCaptureColorImage = nullptr; + this->kinectDeviceCaptureTransformedColorImage = nullptr; + this->kinectDeviceConfiguration = K4A_DEVICE_CONFIG_INIT_DISABLE_ALL; + this->kinectDeviceCalibration = k4a_calibration_t(); + this->kinectDeviceTransformation = nullptr; + this->kinectDeviceStarted = false; + this->kinectDeviceDone = false; + this->kinectDeviceRestart = false; + this->kinectDeviceReady = false; + this->messageBuffer = new char[8 + 4 + 1 + (1024 * 1024 * 9)]; + this->transformation = std::vector(4, Eigen::Vector3f(0.0,0.0,0.0)); + transformation[1][0] = 180.0; +} + +//-----KinectCamera config contstructor------// +/* +Call the default constructor +Apply the configuration supplied from cameraConfig to the camera's settings +*/ +kinectCamera::kinectCamera(cameraConfiguration cameraConfig) { + this->kinectCamera::kinectCamera(); + this->deviceIndex = cameraConfig.deviceIndex; + this->color = cameraConfig.color; + this->kinectDeviceConfiguration.depth_mode = cameraConfig.depthMode; + this->kinectDeviceConfiguration.color_resolution = cameraConfig.colorResolution; + //Make sure that the fps isn't greater than the max allowed for wfov_unbinned or 3072p for the cameras + if ((cameraConfig.depthMode == K4A_DEPTH_MODE_WFOV_UNBINNED || cameraConfig.colorResolution == K4A_COLOR_RESOLUTION_3072P) && cameraConfig.fpsMode == K4A_FRAMES_PER_SECOND_30) { + this->kinectDeviceConfiguration.camera_fps = K4A_FRAMES_PER_SECOND_15; + } + else { + this->kinectDeviceConfiguration.camera_fps = cameraConfig.fpsMode; + } +} + +//-----KinectCamera decontstructor------// +/* +Free up memory and set everything to their zero respective value + +Have to check every image if it is null to avoid the sdk outputting error messages. +*/ +kinectCamera::~kinectCamera(){ + this->deviceIndex = 0; + this->color = false; + this->kinectDeviceStarted = false; + this->kinectDeviceDone = false; + this->kinectDeviceRestart = false; + delete[]this->messageBuffer; + if (this->kinectDevice != nullptr) { + k4a_device_stop_cameras(this->kinectDevice); + k4a_device_close(this->kinectDevice); + this->kinectDevice = nullptr; + } + if (this->kinectDeviceCapture != nullptr) { + k4a_capture_release(this->kinectDeviceCapture); + this->kinectDeviceCapture = nullptr; + } + if (this->kinectDeviceCaptureDepthImage != nullptr) { + k4a_image_release(this->kinectDeviceCaptureDepthImage); + this->kinectDeviceCaptureDepthImage = nullptr; + } + if (this->kinectDeviceCaptureXYZImage != nullptr) { + k4a_image_release(this->kinectDeviceCaptureXYZImage); + this->kinectDeviceCaptureXYZImage = nullptr; + } + if (this->kinectDeviceCaptureColorImage != nullptr) { + k4a_image_release(this->kinectDeviceCaptureColorImage); + this->kinectDeviceCaptureDepthImage = nullptr; + } + if (this->kinectDeviceCaptureTransformedColorImage != nullptr) { + k4a_image_release(this->kinectDeviceCaptureTransformedColorImage); + this->kinectDeviceCaptureTransformedColorImage = nullptr; + } + this->kinectDeviceConfiguration = K4A_DEVICE_CONFIG_INIT_DISABLE_ALL; + if (this->kinectDeviceTransformation != nullptr) { + k4a_transformation_destroy(this->kinectDeviceTransformation); + this->kinectDeviceTransformation = nullptr; + } +} + +//-----KinectCamera setCameraIndex------// +/* +Set the device index to the value of the argument +*/ +bool kinectCamera::setCameraIndex(int index) { + this->deviceIndex = index; + + return true; +} + +//-----KinectCamera parseToml------// +/* +Grab all of the configurations from the toml files and set the available values + +Also passes mqtt's table over so it can grab the configurations +*/ +bool kinectCamera::parseToml(mqtt& mosquittoWrapper) { + std::string settingsFile("settings"); + settingsFile.append(std::to_string(this->deviceIndex)); + settingsFile.append(".toml"); + std::ifstream file(settingsFile.c_str()); + if (!file.good()) { + std::cout << "kinectCamera::parseToml() Error reading settings file!\n" << std::endl; + std::cout << "File Name: " << settingsFile << std::endl; + return false; + } + toml::Data data = toml::parse(file); + file.close(); + + //Getting the translations/rotation file to be used + std::string cameraConfigFile = toml::get(data.at("file")); + + //Passing over the [MqttInfo] section to the mosquittoWrapper + mosquittoWrapper.ParseArgs(toml::get(data.at("MqttInfo"))); + + //Opening the cameraConfig File + file.open(cameraConfigFile, std::ios::in | std::ios::out); + if (!file.good()) { + std::cout << "kinectCamera::parseToml() Error reading camera position file!\n" << std::endl; + std::cout << "File Name: " << cameraConfigFile << std::endl; + return false; + } + data = toml::parse(file); + file.close(); + + //Grab the translation, rotation, min, max values off of the toml file + //min and max have to be multiplied by 1000 in order to scale down to mm (camera's units) + //Converts to floats here to take advantage of Eigen's librarys for rotation with quaterionf + toml::Table table = toml::get(data.at("Camera")); + std::vector temp = toml::get>(table.at("translation")); + this->transformation[0] += Eigen::Vector3f((float)temp[0], (float)temp[1], (float)temp[2]); + temp = toml::get>(table.at("rotation")); + this->transformation[1] += Eigen::Vector3f((float)temp[0], (float)temp[1], (float)temp[2]); + temp = toml::get>(table.at("min")); + this->transformation[2] += Eigen::Vector3f((float)temp[0], (float)temp[1], (float)temp[2]); + temp = toml::get>(table.at("max")); + this->transformation[3] += Eigen::Vector3f((float)temp[0], (float)temp[1], (float)temp[2]); + + return true; +} + +//-----KinectCamera connectCamera------// +/* +Error out if there is already a device connected + +Calls k4a_device_open if this->kinectDevice was null +*/ +bool kinectCamera::connectCamera() { + if (this->kinectDevice != nullptr) { + fprintf(stderr, "kinectCamera::connectCamera() KinectDevice must be null, make sure to call closeCamera() prior to opening a new camera!\n"); + return false; + } + + //Try to connect to the device error out if it fails to open + if (K4A_FAILED(k4a_device_open(this->deviceIndex, &this->kinectDevice))) { + fprintf(stderr, "kinectCamera::connectCamera() Failed to open the device with index %d", this->deviceIndex); + this->kinectDevice = nullptr; + return false; + } + + return true; +} + +//-----KinectCamera setCameraConfiguration------// +/* +Makes sure the device is connected and not null + +Sets the device to the configuration, +it will error correct if a user put 30fps when it should've been 15fps due to either +color resolution or the depth mode +*/ +bool kinectCamera::setCameraConfiguration(cameraConfiguration config) { + if (this->kinectDevice == nullptr) { + return false; + } + + //Settings conflict with each other, lower the fps so it will still run + if (config.depthMode == K4A_DEPTH_MODE_WFOV_UNBINNED || config.colorResolution == K4A_COLOR_RESOLUTION_3072P) { + if (config.fpsMode == K4A_FRAMES_PER_SECOND_30) { + config.fpsMode = K4A_FRAMES_PER_SECOND_15; + } + } + //Determine if there is color capture and set the kinectDeviceConfiguration device + this->color = config.color; + this->kinectDeviceConfiguration.synchronized_images_only = true; + this->kinectDeviceConfiguration.depth_mode = config.depthMode; + this->kinectDeviceConfiguration.color_resolution = config.colorResolution; + this->kinectDeviceConfiguration.camera_fps = config.fpsMode; + + this->checkSyncCables(); + + //No need for extra cpu overhead if color isn't being captured, so use MJPG instead of bgra32 + if (this->color) { + this->kinectDeviceConfiguration.color_format = K4A_IMAGE_FORMAT_COLOR_BGRA32; + } + else { + this->kinectDeviceConfiguration.color_format = K4A_IMAGE_FORMAT_COLOR_MJPG; + } + + return true; +} + +//-----KinectCamera setCameraConfiguration------// +/* +Information was sent over from the merger, parse the modes that were sent. + +Pass it over to setCameraConfiguration with the newly built cameraConfiguration structure +*/ +void kinectCamera::setCameraConfiguration(uint8_t arr[]) { + cameraConfiguration config; + config.fpsMode = parseFpsMode(arr[0]); + config.depthMode = parseDepthMode(arr[1]); + config.colorResolution = parseColorResolution(arr[2]); + config.color = parseColorCapture(arr[3]); + + this->setCameraConfiguration(config); +} + +void kinectCamera::checkSyncCables() { + bool sync_in = false; + bool sync_out = false; + //Get the sync jacks on the back of the device to determine + //Master, Subordinate, or standalone status + k4a_device_get_sync_jack(this->kinectDevice, &sync_in, &sync_out); + if (sync_in == true) { + this->kinectDeviceConfiguration.wired_sync_mode = K4A_WIRED_SYNC_MODE_SUBORDINATE; + } + else if (sync_out == true) { + this->kinectDeviceConfiguration.wired_sync_mode = K4A_WIRED_SYNC_MODE_MASTER; + } + else { + this->kinectDeviceConfiguration.wired_sync_mode = K4A_WIRED_SYNC_MODE_STANDALONE; + } +} + +//-----KinectCamera setCameraCalibrationandTransforamtion------// +/* +First, make sure that the device has been connected and not started, +if it is not. Then get out of the function. + +If there is, go ahead and gather the calibration and transformation variables from the camera +in order to morph the bgra image into the depth space. +*/ +bool kinectCamera::setCameraCalibrationandTransformation() { + if (this->kinectDevice == nullptr || this->kinectDeviceStarted == false) { + fprintf(stderr, "kinectCamera::setCameraCalibration() Must be connected to a KinectDevice and started already\n"); + return false; + } + + this->kinectDeviceCalibration = k4a_calibration_t(); + k4a_device_get_calibration(this->kinectDevice, this->kinectDeviceConfiguration.depth_mode, this->kinectDeviceConfiguration.color_resolution, &this->kinectDeviceCalibration); + if (this->kinectDeviceTransformation) { + k4a_transformation_destroy(this->kinectDeviceTransformation); + } + this->kinectDeviceTransformation = k4a_transformation_create(&this->kinectDeviceCalibration); + + return true; +} + +//-----KinectCamera getCameraIndex------// +/* +Getter for the deviceIndex +*/ +int kinectCamera::getCameraIndex() { + return this->deviceIndex; +} + +//-----KinectCamera startCamera------// +/* +Get the camera in the standby state +*/ +bool kinectCamera::startCamera() { + //Get the cameras on standby, ready to capture + if (K4A_FAILED(k4a_device_start_cameras(this->kinectDevice, &this->kinectDeviceConfiguration))) { + fprintf(stderr, "kinectCamera::startCamera() failed to start device at index %d\n", this->deviceIndex); + this->kinectDevice = nullptr; + return false; + } + + this->kinectDeviceStarted = true; + return true; +} + +//-----KinectCamera setCameraIndex------// +/* +First checks if kinectDevice is not null, if it is null, error out of the function. + +If the capture is not null, free up memory first. + +Finally return the result if the capture succeeded within the timeout time +*/ +bool kinectCamera::takeCaptureCamera(int timeoutMS) { + if (this->kinectDevice == nullptr) { + fprintf(stderr, "kinectCamera::takeCaptureCamera() needs to have device connected and running to take a picture\n"); + return false; + } + if (this->kinectDeviceCapture != nullptr) { + k4a_capture_release(this->kinectDeviceCapture); + this->kinectDeviceCapture = nullptr; + } + return (K4A_WAIT_RESULT_SUCCEEDED == k4a_device_get_capture(this->kinectDevice, &this->kinectDeviceCapture, timeoutMS)); +} + +//-----KinectCamera processCaptureCamera------// +/* +First checks that kinectDeviceCapture has a valid image + +Then depending if color is active, process either depth and/or color images + +If there was an error processing the images, pointCount will be set to -1 +*/ +bool kinectCamera::processCaptureCamera(mqtt &mosquittoWrapper, char* topic) { + if (this->kinectDeviceCapture == nullptr) { + fprintf(stderr, "kinectCamera::processCaptureCamera() needs to have a capture present to process\n"); + return false; + } + bool result = true; + uint32_t pointCount = 0; + if (this->color) { + pointCount = this->processCaptureColorCamera(); + } + else { + pointCount = this->processCaptureDepthCamera(); + } + + if (pointCount != -1) { + size_t size = 0; + memcpy(&this->messageBuffer[size], &this->kinectDeviceCaptureTimeStamp, 8); // 8 is the sizeof(uint64_t) + size = 8; + memcpy(&this->messageBuffer[size], &pointCount, 4); // 4 is the sizeof(uint32_t) + size += 4; + memcpy(&this->messageBuffer[size], &this->color, 1); // 1 is the sizeof(bool) + size += 1; + memcpy(&this->messageBuffer[size], this->smallDepth.data(), this->smallDepth.size() * 2); // 2 is the sizeof(int16_t) + size += (this->smallDepth.size() * 2); + //If color was not captured, this will be a memcpy of 0 bytes + memcpy(&this->messageBuffer[size], this->smallColor.data(), this->smallColor.size()); // 1 is the sizeof(uint8_t) + size += this->smallColor.size(); + //Send off the message through mqtt + mosquittoWrapper.sendMessage((int)size, this->messageBuffer, topic); + + //Display the number of points sent. + + std::cout << "Points sent : " << pointCount << " \r"; + } + else { + result = false; + } + + //Free up all the memory that is always used (depth data) and the capture + if (this->kinectDeviceCaptureDepthImage != nullptr) { + k4a_image_release(this->kinectDeviceCaptureDepthImage); + this->kinectDeviceCaptureDepthImage = nullptr; + } + if (this->kinectDeviceCaptureXYZImage != nullptr) { + k4a_image_release(this->kinectDeviceCaptureXYZImage); + this->kinectDeviceCaptureXYZImage = nullptr; + } + if (this->kinectDeviceCapture != nullptr) { + k4a_capture_release(this->kinectDeviceCapture); + this->kinectDeviceCapture = nullptr; + } + //Clear out the vectors + this->smallDepth.clear(); + this->smallColor.clear(); + + return result; +} + +//-----KinectCamera updateCameraTransformation------// +/* +add the adjustmentVector (translation/rotation) vectors, this will normally only come from the message callback mqtt +*/ +bool kinectCamera::updateCameraTransformation(std::vector adjustmentVector) { + for (int i = 0; i < 2; ++i) { + this->transformation[i] += adjustmentVector[i]; + } + + return true; +} + +//-----KinectCamera isDone, setDone, isRestart, setRestart, isReady, setReady------// +/* +Simple getters and setters for the respective member variables +*/ +bool kinectCamera::isDone() { + return this->kinectDeviceDone; +} + +bool kinectCamera::setDone(bool setDone) { + return this->kinectDeviceDone = setDone; +} + +bool kinectCamera::isRestart() { + return this->kinectDeviceRestart; +} + +bool kinectCamera::setRestart(bool setRestart) { + return this->kinectDeviceRestart = setRestart; +} + +bool kinectCamera::isReady() { + return this->kinectDeviceReady; +} + +bool kinectCamera::setReady(bool setReady) { + return this->kinectDeviceReady = setReady; +} + +//-----KinectCamera disconnectCamera------// +/* +Checks to see if there is a valid device, error out if not. + +If there is, ensure all the images are freed before stoping and closing the cameras + +Clear out the vectors as well. +*/ +bool kinectCamera::disconnectCamera() { + if (this->kinectDevice == nullptr) { + fprintf(stderr, "kinectCamera::disconnectCamera() Needs to already be connected to a device\n"); + return false; + } + if (this->kinectDeviceCapture != nullptr) { + k4a_capture_reference(this->kinectDeviceCapture); + this->kinectDeviceCapture = nullptr; + } + if (this->kinectDeviceCaptureDepthImage != nullptr) { + k4a_image_release(this->kinectDeviceCaptureDepthImage); + this->kinectDeviceCaptureDepthImage = nullptr; + } + if (this->kinectDeviceCaptureXYZImage != nullptr) { + k4a_image_release(this->kinectDeviceCaptureXYZImage); + this->kinectDeviceCaptureXYZImage = nullptr; + } + if (this->kinectDeviceCaptureColorImage != nullptr) { + k4a_image_release(this->kinectDeviceCaptureColorImage); + this->kinectDeviceCaptureDepthImage = nullptr; + } + if (this->kinectDeviceCaptureTransformedColorImage != nullptr) { + k4a_image_release(this->kinectDeviceCaptureTransformedColorImage); + this->kinectDeviceCaptureTransformedColorImage = nullptr; + } + if (this->kinectDeviceTransformation != nullptr) { + k4a_transformation_destroy(this->kinectDeviceTransformation); + this->kinectDeviceTransformation = nullptr; + } + k4a_device_stop_cameras(this->kinectDevice); + k4a_device_close(this->kinectDevice); + this->kinectDevice = nullptr; + this->vec.clear(); + this->smallColor.clear(); + this->smallDepth.clear(); + return true; +} + +//-----KinectCamera writeToml------// +/* +The toml file has the device index attached to it as well +Build up the toml file and open it + +Ensure the file is still there and parse the toml file to get the configFileName +*/ +bool kinectCamera::writeToml() { + std::string settingsFile("settings"); + settingsFile.append(std::to_string(this->deviceIndex)); + settingsFile.append(".toml"); + std::ifstream file(settingsFile.c_str()); + if (!file.good()) { + std::cout << "kinectCamera::writeToml() Error reading settings file!" << std::endl; + std::cout << "File Name: " << settingsFile << std::endl; + return false; + } + toml::Data data = toml::parse(file); + file.close(); + + std::string cameraConfigFile = toml::get(data.at("file")); + + //Visual feedback of the cameraConfigFile + std::cout << cameraConfigFile << std::endl; + return this->writeSection(cameraConfigFile, "Camera"); +} + +//-----KinectCamera isSubordinate------// +/* +Simple 'getter' that will check to see if the wired_sync_mode was set to Subordinate +*/ +bool kinectCamera::isSubordinate() { + return this->kinectDeviceConfiguration.wired_sync_mode == K4A_WIRED_SYNC_MODE_SUBORDINATE; +} + +//-----------------------------------------private functions-----------------------------------------// + +//-----KinectCamera processCaptureColorCamera------// +/* +Process the depthCapture first, if that failed no point in continuing + +Then get the color image and transform it. + +return the amount of points +*/ +uint32_t kinectCamera::processCaptureColorCamera() { + if (!this->processDepth()) { + return -1; + } + + //get color image from the device capture + //if it failed to get the color image capture, return out of the function. + this->kinectDeviceCaptureColorImage = k4a_capture_get_color_image(this->kinectDeviceCapture); + if (this->kinectDeviceCaptureColorImage == nullptr) { + return -1; + } + int w, h = 0; + //Get the height and width rom the depthImage + w = k4a_image_get_width_pixels(this->kinectDeviceCaptureDepthImage); + h = k4a_image_get_height_pixels(this->kinectDeviceCaptureDepthImage); + //Create a new image that is 4 time the width and size of a uint8_t data type + //Then use the color and depth image to make the transformed_color_image be in the same coordinate space as the depth camera + k4a_image_create(K4A_IMAGE_FORMAT_COLOR_BGRA32, w, h, w * 4, &this->kinectDeviceCaptureTransformedColorImage); + //If the image failed to be allocated, free the color image and exit the function + if (this->kinectDeviceCaptureTransformedColorImage == nullptr) { + k4a_image_release(this->kinectDeviceCaptureColorImage); + this->kinectDeviceCaptureColorImage = nullptr; + return -1; + } + + k4a_transformation_color_image_to_depth_camera(this->kinectDeviceTransformation, this->kinectDeviceCaptureDepthImage, this->kinectDeviceCaptureColorImage, this->kinectDeviceCaptureTransformedColorImage); + //Get the raw buffer from the transformed color image + uint8_t* colorbuffer = (uint8_t*)k4a_image_get_buffer(this->kinectDeviceCaptureTransformedColorImage); + + //'free' the vec before reassigning it to this->currentPoints + this->vec.clear(); + this->vec.shrink_to_fit(); + this->vec = this->currentPoints.give_points(); + size_t size = this->vec.size(); + + for (int i = 0; i < size; ++i) { + //Vector.data() gives the raw xyz array that the points are stored in + float* xyz = vec[i].data(); + if (xyz[0] == 0.0 && xyz[1] == 0.0 && xyz[2] == 0.0) { + continue; + } + + //Change the Eigen::Vector3f into xyz points + this->smallDepth.emplace_back((int16_t)xyz[0]); + this->smallDepth.emplace_back((int16_t)xyz[1]); + this->smallDepth.emplace_back((int16_t)xyz[2]); + + //Change bgra into rgb + this->smallColor.emplace_back((uint8_t)colorbuffer[i * 4 + 2]); + this->smallColor.emplace_back((uint8_t)colorbuffer[i * 4 + 1]); + this->smallColor.emplace_back((uint8_t)colorbuffer[i * 4 + 0]); + } + + //Free up the memory and set color image related variables to null + k4a_image_release(this->kinectDeviceCaptureColorImage); + k4a_image_release(this->kinectDeviceCaptureTransformedColorImage); + this->kinectDeviceCaptureColorImage = nullptr; + this->kinectDeviceCaptureTransformedColorImage = nullptr; + return (uint32_t)((this->smallDepth.size() / 3)); +} + +//-----KinectCamera processCaptureDepthCamera------// +/* +Process the depth first, if that fails. No point in continuing + +Otherwise set the smallDepth vecotr to the culled points. + +//Return the amount of points +*/ +uint32_t kinectCamera::processCaptureDepthCamera() { + if (!this->processDepth()) { + return -1; + } + + this->vec.clear(); + this->vec.shrink_to_fit(); + this->vec = this->currentPoints.give_points(); + size_t size = this->vec.size(); + for (int i = 0; i < size; ++i) { + //Vector.data() gives the raw xyz array that the points are stored in + float* xyz = vec[i].data(); + if (xyz[0] == 0.0 && xyz[1] == 0.0 && xyz[2] == 0.0) { + continue; + } + + //Change the Eigen::Vector3f into xyz points + this->smallDepth.emplace_back((int16_t)xyz[0]); + this->smallDepth.emplace_back((int16_t)xyz[1]); + this->smallDepth.emplace_back((int16_t)xyz[2]); + + } + + return (uint32_t)(this->smallDepth.size() / 3); +} + +//-----KinectCamera processDepth------// +/* +Checks to see if depthImage was valid, if not error out. + +The main function that gets the depth image into an xyz buffer to be transformed into a vector of Eigen::Vector3f + +Once it is in a vector of Eigen::Vector3f, it can be imported into the points class to run +translateRotateThreshold and sparseFilter functions to the points + +return true +*/ +bool kinectCamera::processDepth() { + this->kinectDeviceCaptureDepthImage = k4a_capture_get_depth_image(this->kinectDeviceCapture); + if (this->kinectDeviceCaptureDepthImage == nullptr) { + return false; + } + + this->kinectDeviceCaptureTimeStamp = k4a_image_get_timestamp_usec(this->kinectDeviceCaptureDepthImage); + int w, h = 0; + w = k4a_image_get_width_pixels(this->kinectDeviceCaptureDepthImage); + h = k4a_image_get_height_pixels(this->kinectDeviceCaptureDepthImage); + //XYZ point image needs to be a custom image that is 3 times the width of a int16_t (size of each point) + //Transform the depth image into the xyz image + k4a_image_create(K4A_IMAGE_FORMAT_CUSTOM, w, h, w * 6, &this->kinectDeviceCaptureXYZImage); + k4a_transformation_depth_image_to_point_cloud(this->kinectDeviceTransformation, + this->kinectDeviceCaptureDepthImage, + K4A_CALIBRATION_TYPE_DEPTH, + this->kinectDeviceCaptureXYZImage); + + int16_t* xyzbuffer = (int16_t*)k4a_image_get_buffer(this->kinectDeviceCaptureXYZImage); + size_t size = w * h; + if (this->vec.size() == 0) { + this->vec = std::vector(size, Eigen::Vector3f(0, 0, 0)); + } + this->convertToEigen(this->vec, xyzbuffer, size); + + //Import the vector into the points class and do the translating, thresholding, and rotation to the points + //Note: This does not mess with the ordering of the points. + this->currentPoints.importPoints(vec); + this->currentPoints.translateRotateThreshold(transformation[0], transformation[1], transformation[2], transformation[3]); + this->currentPoints.sparseFilter(w, h); + + return true; +} + +//-----KinectCamera writeSection------// +/* +Writes a section into the toml file. It will overwrite anything that was in there before. + + +*/ +bool kinectCamera::writeSection(std::string fileName, std::string sectionName) { + std::ofstream file_out; + file_out.open(fileName, std::ios::out); + //Output the section name surrounded by '[' ']' + file_out << "[" << sectionName << "]\n"; + //Create the translation, rotation, min, max arrays of ints + //Min and max need to be divided by 1000 to be scaled up to meters for the user to change by hand + std::string string = createVariableString("translation", this->transformation[0]); + file_out << string.c_str(); + Eigen::Vector3f tempRotation(this->transformation[1][0] - 180, this->transformation[1][1], this->transformation[1][2]); + string = createVariableString("rotation", tempRotation); + file_out << string.c_str(); + string = createVariableString("min", this->transformation[2]); + file_out << string.c_str(); + string = createVariableString("max", this->transformation[3]); + file_out << string.c_str(); + file_out.close(); + + return true; +} + +//-----KinectCamera createVariableString------// +/* +Helper function to get the array variable, so the Eigen::Vector3f is in array format for TOML to understand. +*/ +std::string kinectCamera::createVariableString(std::string variableName, Eigen::Vector3f vector) { + std::string variable; + variable.append(variableName); + float* arr = vector.data(); + variable.append(" = [" + std::to_string((int)arr[0]) + ", " + std::to_string((int)arr[1]) + ", " + + std::to_string((int)arr[2]) + "]\n"); + return variable; +} + +//-----KinectCamera parseDepthMode------// +/* +Helper function to determine which depthMode was sent in from mqtt +*/ +k4a_depth_mode_t kinectCamera::parseDepthMode(uint8_t arg) { + k4a_depth_mode_t ret = K4A_DEPTH_MODE_OFF; + switch (arg) { + case 0: + ret = K4A_DEPTH_MODE_OFF; + break; + case 1: + ret = K4A_DEPTH_MODE_NFOV_2X2BINNED; + break; + case 2: + ret = K4A_DEPTH_MODE_NFOV_UNBINNED; + break; + case 3: + ret = K4A_DEPTH_MODE_WFOV_2X2BINNED; + break; + case 4: + ret = K4A_DEPTH_MODE_WFOV_UNBINNED; + break; + case 5: + ret = K4A_DEPTH_MODE_PASSIVE_IR; + break; + default: + fprintf(stderr, "Error parsing depthMode\n"); + } + + return ret; +} + +//-----KinectCamera parseColorResolution------// +/* +Helper function to determine which color resolution was sent in from mqtt +*/ +k4a_color_resolution_t kinectCamera::parseColorResolution(uint8_t arg) { + k4a_color_resolution_t ret = K4A_COLOR_RESOLUTION_OFF; + switch (arg) { + case 0: + ret = K4A_COLOR_RESOLUTION_OFF; + break; + case 1: + ret = K4A_COLOR_RESOLUTION_720P; + break; + case 2: + ret = K4A_COLOR_RESOLUTION_1080P; + break; + case 3: + ret = K4A_COLOR_RESOLUTION_1440P; + break; + case 4: + ret = K4A_COLOR_RESOLUTION_1536P; + break; + case 5: + ret = K4A_COLOR_RESOLUTION_2160P; + break; + case 6: + ret = K4A_COLOR_RESOLUTION_3072P; + break; + default: + fprintf(stderr, "Error parsing depthMode\n"); + } + + return ret; +} + +//-----KinectCamera parseFpsMode------// +/* +Helper function to determine which camera fps mode was sent in from mqtt +*/ +k4a_fps_t kinectCamera::parseFpsMode(uint8_t arg) { + k4a_fps_t ret = K4A_FRAMES_PER_SECOND_5; + switch (arg) { + case 0: + ret = K4A_FRAMES_PER_SECOND_5; + break; + case 1: + ret = K4A_FRAMES_PER_SECOND_15; + break; + case 2: + ret = K4A_FRAMES_PER_SECOND_30; + break; + default: + fprintf(stderr, "Error parsing fpsMode\n"); + } + + return ret; +} + +//-----KinectCamera parseColorCapture------// +/* +Helper function to determine whcich color capture setting was sent in from mqtt +*/ +bool kinectCamera::parseColorCapture(uint8_t arg) { + bool ret = false; + switch (arg) { + case 0: + ret = false; + break; + case 1: + ret = true; + break; + default: + fprintf(stderr, "Error parsing colorCapture setting\n"); + } + + return ret; +} \ No newline at end of file diff --git a/streaming-pointcloud/kinect capture/kinect capture/kinectCamera.h b/streaming-pointcloud/kinect capture/kinect capture/kinectCamera.h new file mode 100644 index 00000000..439c61ec --- /dev/null +++ b/streaming-pointcloud/kinect capture/kinect capture/kinectCamera.h @@ -0,0 +1,88 @@ +#pragma once +#pragma warning(disable : 26812) //Disable enum class warning from the sdk api + +#include "points.h" +#include "k4a/k4a.h" +#include "k4a/k4atypes.h" +#include "mqtt.h" + +struct cameraConfiguration { + int deviceIndex = 0; + bool color = false; + k4a_depth_mode_t depthMode = K4A_DEPTH_MODE_NFOV_2X2BINNED; + k4a_color_resolution_t colorResolution = K4A_COLOR_RESOLUTION_720P; + k4a_fps_t fpsMode = K4A_FRAMES_PER_SECOND_30; + +}; + +class kinectCamera { +public: //functions + kinectCamera(); + kinectCamera(cameraConfiguration cameraConfig); + ~kinectCamera(); + bool setCameraIndex(int index); + bool parseToml(mqtt& mosquittoWrapper); + bool connectCamera(); + bool setCameraConfiguration(cameraConfiguration config); + void setCameraConfiguration(uint8_t arr[]); + void checkSyncCables(); + bool setCameraCalibrationandTransformation(); + int getCameraIndex(); + bool startCamera(); + bool takeCaptureCamera(int timeoutMS); + bool processCaptureCamera(mqtt& mosquittoWrapper, char* topic = nullptr); + bool updateCameraTransformation(std::vector adjustmentVector); + bool isDone(); + bool setDone(bool setDone); + bool isRestart(); + bool setRestart(bool setRestart); + bool isReady(); + bool setReady(bool setReady); + bool disconnectCamera(); + bool writeToml(); + bool isSubordinate(); + +private: //functions + inline void convertToEigen(std::vector& depthVec, int16_t*& xyzbuffer, size_t size) { + for (int i = 0; i < size; ++i) { + depthVec[i] = Eigen::Vector3f(xyzbuffer[i * 3 + 0], xyzbuffer[i * 3 + 1], xyzbuffer[i * 3 + 2]); + } + } + + uint32_t processCaptureColorCamera(); + uint32_t processCaptureDepthCamera(); + bool processDepth(); + bool writeSection(std::string file_name, std::string section_name); + std::string createVariableString(std::string variableName, Eigen::Vector3f vector); + k4a_depth_mode_t parseDepthMode(uint8_t arg); + k4a_color_resolution_t parseColorResolution(uint8_t arg); + k4a_fps_t parseFpsMode(uint8_t arg); + bool parseColorCapture(uint8_t arg); + +private: //variables + k4a_device_t kinectDevice; + k4a_capture_t kinectDeviceCapture; + uint64_t kinectDeviceCaptureTimeStamp; + + k4a_image_t kinectDeviceCaptureDepthImage; + k4a_image_t kinectDeviceCaptureXYZImage; + k4a_image_t kinectDeviceCaptureColorImage; + k4a_image_t kinectDeviceCaptureTransformedColorImage; + k4a_device_configuration_t kinectDeviceConfiguration; + k4a_transformation_t kinectDeviceTransformation; + k4a_calibration_t kinectDeviceCalibration; + std::vector transformation; + + points currentPoints; + int deviceIndex; + bool color; + bool kinectDeviceStarted; + bool kinectDeviceDone; + bool kinectDeviceRestart; + bool kinectDeviceReady; + + std::vector smallDepth; + std::vector smallColor; + std::vector vec; + char* messageBuffer; +}; \ No newline at end of file diff --git a/streaming-pointcloud/kinect capture/kinect capture/mqtt.cpp b/streaming-pointcloud/kinect capture/kinect capture/mqtt.cpp new file mode 100644 index 00000000..ddae2cc4 --- /dev/null +++ b/streaming-pointcloud/kinect capture/kinect capture/mqtt.cpp @@ -0,0 +1,321 @@ +#include "mqtt.h" +#include "kinectCamera.h" + +extern mqtt mosquittoWrapper; +extern kinectCamera camera; + +//Converts an std::string into an array of chars, syntax is very similar to how strcpy works +//Used for getting std::/toml::string into a char* +void stringToChar(char*& dest, std::string source) { + if (strlen(source.c_str())) { + size_t len = strlen(source.c_str()) + 1; + dest = new char[len]; + strcpy_s(dest, len, source.c_str()); + dest[len - 1] = '\0'; + } +} + +/* +The constructor sets all pointers to null and sets the non pointer variables to the default by mosquitto's standards +port = 1883 +keepalive = 60 +clean_session = true +*/ +mqtt::mqtt() { + this->host = nullptr; + this->topic = nullptr; + this->port = 1883; + this->keepalive = 60; + this->clean_session = true; + this->mosq = nullptr; + this->id = nullptr; + this->userdata = nullptr; +} + +/* +The constructor frees up all of the pointer's memory and then set them to point at 0 +All other non-pointer data variables are set to 0. +*/ +mqtt::~mqtt() { + delete[] this->host; + this->host = 0; + delete[] this->topic; + this->topic = 0; + this->port = 0; + this->keepalive = 0; + this->clean_session = false; + delete this->userdata; + this->userdata = nullptr; + mosquitto_destroy(this->mosq); + this->mosq = 0; +} + +/* +Frees up all memory for the pointer fields before allocating the data onto host, topic, and id +Sets all the other non pointer variables to their respective fields. +It will then go through and call init_mosquitto() which will initialize the mosq variable, +allowing it to connect() right after create() +*/ +bool mqtt::create(char* host, char* topic, int port, char* id, void* userdata, int keep_alive, bool clean_session, int num_cameras) { + delete[]this->host; + delete[]this->topic; + delete[]this->id; + this->host = new char[strlen(host) + 1]; + strcpy_s(this->host, (strlen(host) + 1), host); + this->topic = new char[strlen(topic) + 1]; + strcpy_s(this->topic, (strlen(topic) + 1), topic); + this->port = port; + this->keepalive = keepalive; + this->clean_session = clean_session; + this->id = new char[strlen(id) + 1]; + strcpy_s(this->id, (strlen(id) + 1), id); + + return initMosquitto(); +} + +/* +connect() is a wrapper that will check to make sure that the connection succeeded, if it didn't it will return 1 +succeeding will return 0 +*/ +bool mqtt::connect(void) { + if (mosquitto_connect(this->mosq, this->host, this->port, this->keepalive)) { + fprintf(stderr, "mqtt::connect Unable to connect.\n"); + return false; + } + return true; +} + +/* +The my_function_callback are functions that will help in the debug process. They are the functions that are called as if there +were on_event() type syntax. These are added to the callback function when calling the mosquitto_log_function_set(). The +mosquitto_log_function_set() takes the mosquitto structure and these my_function_callback() as the arguments. +*/ +void mqtt::callbacks(void) { + //mosquitto_log_callback_set(this->mosq, my_log_callback); + //mosquitto_connect_callback_set(this->mosq, my_connect_callback); + mosquitto_message_callback_set(this->mosq, my_message_callback); + //mosquitto_subscribe_callback_set(this->mosq, my_subscribe_callback); +} + +/* +Send message is just a simple wrapper to publish/send a message over the mqtt stream with the +topic that the varible was initialized with. +The required arguments are: +payload_len: size of payload to be sent over +payload: the actual payload to be sent over +qos: 0, 1 or 2 indicating the quality of service to be used for the message +Optional arguments are: +retain: if message is desired to be kept +mid: number for the message id specifically sent over, can be NULL and the library will increment its own. +*/ +void mqtt::sendMessage(int payload_len, const void* payload, char* topic, int qos, bool retain, int* mid) { + if(topic != nullptr){ + mosquitto_publish(this->mosq, mid, topic, payload_len, payload, qos, retain); + } + else { + mosquitto_publish(this->mosq, mid, this->topic, payload_len, payload, qos, retain); + } +} + +/* +Finish mosquitto is a wrapper that calls the mosquitto_lib_cleanup() function +Only do this at the end of the program. +*/ +void mqtt::finishMosquitto(void) { + mosquitto_lib_cleanup(); +} + +/* +Wrapper that is used to initialize the mosquitto library. Only needs to be called once. +*/ +void mqtt::initMqttLib(void) { + mosquitto_lib_init(); +} + +/* +Wrapper to help create a new mosquitto instance. +There are no required parameters for this function as it already assumes that the values for the class +has been populated in some fashion prior to calling this. +*/ +bool mqtt::initMosquitto(void) { + this->mosq = mosquitto_new(this->id, this->clean_session, this->userdata); + if (!mosq) { + fprintf(stderr, "mqtt::initMosquitto Unable to connect.\n"); + return false; + } + return true; +} + +/* +ParseArgs takes in the section of toml that is relevant for mqtt info. +It will create the variables right from the file and then initialize the values to those provided from the +config.toml file. +Returns the success or failure of init_mosquitto() +*/ +bool mqtt::ParseArgs(toml::Table table) { + stringToChar(this->host, toml::get(table.at("host"))); + stringToChar(this->id, toml::get(table.at("id"))); + std::string topicString(toml::get(table.at("topic"))); + topicString.append("/"); + topicString.append(this->id); + stringToChar(this->topic, topicString); + std::cout << this->topic << std::endl; + this->port = (int)toml::get(table.at("port")); + + try { + this->keepalive = (int)toml::get(table.at("keepalive")); + } + catch (std::exception & e) { + e; //Removes unreferenced local veriable warning + this->keepalive = 60; + } + try { + this->clean_session = toml::get(table.at("clean_session")); + } + catch (std::exception & e) { + e; //Removes unreferenced local veriable warning + this->clean_session = true; + } + + return initMosquitto(); +} + +/* +Give the current mosquitto instance back, useful for: +mosquitto_loop_start(); +*/ +mosquitto* mqtt::giveMosquitto() { + return this->mosq; +} + +/* +Subscribe to the topic that is stored in the class +*/ +void mqtt::subscribe() { + mosquitto_subscribe(this->mosq, NULL, this->topic, 0); +} + +/* +Subscribe to a topic that is not stored in the class +Can do either to be '(this->topic)/newtopic' in terms of appending +or its own topic to something that is not tied to this->topic +*/ +void mqtt::subscribe(char* topic, bool append) { + std::string subTopic; + if (append) { + subTopic = std::string(this->topic); + subTopic.append("/"); + subTopic.append(topic); + } + else { + subTopic = std::string(topic); + } + mosquitto_subscribe(this->mosq, NULL, subTopic.c_str(), 0); +} + +/* +Disconnect the mosquitto client from the broker +*/ +void mqtt::disconnect() { + mosquitto_disconnect(this->mosq); +} + +/* +Return the stored topic in the class +*/ +std::string mqtt::giveTopic() { + return this->topic; +} + +void handle_camera_control(char* command) { + + if (strcmp(command, COMMAND_SHUTDOWN) == 0) { + printf("Shutting down the application..\n"); + camera.setDone(true); + } + else if (strcmp(command, COMMAND_SAVE) == 0) { + printf("Saving configuration - "); + camera.writeToml(); + } + else if (strcmp(command, COMMAND_RESTART) == 0) { + printf("Restarting camera\n"); + camera.setRestart(true); + } +} + + +/* +Function is provided by the mosquitto.org documentation +*/ +void my_message_callback(struct mosquitto* mosq, void* userdata, const struct mosquitto_message* message) +{ + if (message->payloadlen) { + + if (strcmp((char*)message->topic, TOPIC_CONTROL) == 0) + { + handle_camera_control((char*)message->payload); + } + else if(strcmp((char*)message->topic, TOPIC_CAMERA_CONFIGURE) == 0) + { + if (message->payloadlen == 4) { + uint8_t arr[4]; + uint8_t* messageArr = (uint8_t*)message->payload; + for (int i = 0; i < 4; ++i) { + arr[i] = messageArr[i]; + } + camera.setCameraConfiguration(arr); + camera.setReady(true); + } + } + else if (strcmp((char*)message->topic, mosquittoWrapper.giveTopic().append("/calibrate").c_str()) == 0) + { + float* payload = (float*)message->payload; + std::vector temp; + for (int i = 0; i < 2; ++i) { + temp.emplace_back(Eigen::Vector3f(payload[3 * i + 0], payload[3 * i + 1], payload[3 * i + 2])); + } + camera.updateCameraTransformation(temp); + } + else { + //For Debugging purposes + //printf("%s %d bytes\n", (char*)message->topic, message->payloadlen); + } + } +} + +/* +Function is provided by the mosquitto.org documentation +*/ +void my_connect_callback(struct mosquitto* mosq, void* userdata, int result) +{ + if (!result) { + /* Subscribe to broker information topics on successful connect. */ + mosquitto_subscribe(mosq, NULL, "$SYS/#", 2); + } + else { + fprintf(stderr, "mqtt::my_connect_callback Connect failed\n"); + } +} + +/* +Function is provided by the mosquitto.org documentation +*/ +void my_subscribe_callback(struct mosquitto* mosq, void* userdata, int mid, int qos_count, const int* granted_qos) +{ + int i; + + printf("Subscribed (mid: %d): %d", mid, granted_qos[0]); + for (i = 1; i < qos_count; i++) { + printf(", %d", granted_qos[i]); + } + printf("\n"); +} + +/* +Function is provided by the mosquitto.org documentation +*/ +void my_log_callback(struct mosquitto* mosq, void* userdata, int level, const char* str) +{ + /* Pring all log messages regardless of level. */ + printf("%s\n", str); +} \ No newline at end of file diff --git a/streaming-pointcloud/kinect capture/kinect capture/mqtt.h b/streaming-pointcloud/kinect capture/kinect capture/mqtt.h new file mode 100644 index 00000000..8d592e52 --- /dev/null +++ b/streaming-pointcloud/kinect capture/kinect capture/mqtt.h @@ -0,0 +1,62 @@ +#pragma once +#pragma once +#include +#include +#include "..//packages/TOMLParser-master/toml.hpp" + +#define TOPIC_CAMERA_AVAILBLE "cameras/available" +#define TOPIC_CAMERA_CONFIGURE "cameras/configure" +#define TOPIC_CONTROL "cameras/control" +#define TOPIC_VIEWER "viewer" +#define TOPIC_MERGER "merger" + +// Commands for the TOPIC_CAMERA_CONTROL messages +#define COMMAND_SHUTDOWN "done" +#define COMMAND_SAVE "save" +#define COMMAND_RESTART "restart" + + +/* +These callback functions are not included within the class as they are used to be passed as pointers to the functions +for mosquitto to use them properly +*/ +void my_message_callback(struct mosquitto* mosq, void* userdata, const struct mosquitto_message* message); +void my_connect_callback(struct mosquitto* mosq, void* userdata, int result); +void my_subscribe_callback(struct mosquitto* mosq, void* userdata, int mid, int qos_count, const int* granted_qos); +void my_log_callback(struct mosquitto* mosq, void* userdata, int level, const char* str); + +/* +mqtt class is a wrapper for the mosquitto library +It holds just about all the information to be able to send data with the exception of some sort of message +variable. +Once the class has been created, the next steps to send a message are connect(), then send_message() +With send_message(), be sure to include the payload length, the payload, and the quality of service that would be desired. +*/ +class mqtt { +public: //Functions + mqtt(); + ~mqtt(); + bool create(char* host, char* topic, int port, char* id, void* userdata, int keep_alive, bool clean_session, int num_cameras); + bool connect(void); + void disconnect(); + void callbacks(void); + void sendMessage(int payload_len, const void* payload, char* topic = nullptr, int qos = 0, bool retain = false, int* mid = NULL); + void finishMosquitto(void); + void initMqttLib(void); + bool initMosquitto(void); + bool ParseArgs(toml::Table table); + void subscribe(void); + void subscribe(char* topic, bool append = false); + std::string giveTopic(); + mosquitto* giveMosquitto(); + +private: //Variables + char* host; + char* topic; + int port; + int keepalive; + bool clean_session; + char* id; + void* userdata; + struct mosquitto* mosq; +}; \ No newline at end of file diff --git a/streaming-pointcloud/kinect capture/kinect capture/packages.config b/streaming-pointcloud/kinect capture/kinect capture/packages.config new file mode 100644 index 00000000..1fd62b78 --- /dev/null +++ b/streaming-pointcloud/kinect capture/kinect capture/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/streaming-pointcloud/kinect capture/kinect capture/points.cpp b/streaming-pointcloud/kinect capture/kinect capture/points.cpp new file mode 100644 index 00000000..7e5b8129 --- /dev/null +++ b/streaming-pointcloud/kinect capture/kinect capture/points.cpp @@ -0,0 +1,178 @@ +#include "points.h" +#include +//-----Points default contstructor------// +/* +This constructor will set flat to false (used to signify if flat points have been made) and +reserve the previous points to hold up to 10 frames for averaging the amount of points +*/ +points::points() { + this->current_points; +} + +//-----Points default deconstructor------// +/* +This deconstructor will free all memory and then set their points to +their 0 respective value +*/ +points::~points() { + this->current_points.clear(); + this->current_points.shrink_to_fit(); +} + +//-----importPoints------// +/* +This will go through and import the points from 3 different types which will be a vector of either: +Eigen::Vector3f + +It will first check to see that the new points is not an empty list, +then it will call add previous to get the current point added into the queue (this will have the first frame in there twice +until it is cleared past the frame average points), +Then it will set the current points to the newPoints value by converting to the +std::vector that is used for current points. + +Returns true if succeeded, which means it doesn't recieve a nonempty amount of points from newPoints +*/ +bool points::importPoints(std::vector& newPoints) { + if (newPoints.size() == 0) { + return false; + } + + this->current_points = newPoints; + + return true; +} + +//-----translation------// +/* +Translates all values in this->current) points +*/ +void points::translate(Eigen::Vector3f& t) { + for (auto&& i : this->current_points) { + i = i - t; + } +} + +//-----rotate------// +/* +This function Will rotate the points around the x,y,z axis separately or all at once depending on the use case. +*/ +void points::rotate(Eigen::Vector3f& rot) { + //Get the degrees to rotate by + float anglex = (float)0.0174533 * rot.x(); + float angley = (float)0.0174533 * rot.y(); + float anglez = (float)0.0174533 * rot.z(); + + //Get the rotations for each axis + Eigen::AngleAxisf xrot(anglex, Eigen::Vector3f::UnitX()); + Eigen::AngleAxisf yrot(angley, Eigen::Vector3f::UnitY()); + Eigen::AngleAxisf zrot(anglez, Eigen::Vector3f::UnitZ()); + + //Set all the rotations into a single quaterniond and pass to the cuda function + Eigen::Quaternionf quat = xrot * yrot * zrot; + + for (auto&& i : this->current_points) { + i = quat * i; + } + + +} + +//-----threshold------// +/* +This function will apply a boundrary onto the 3d points and set them to origin if they are out of bounds. +Points at origin are considered invalid and will be discarded when sent over mqtt, they are not removed to maintain ordering +*/ +void points::threshold(Eigen::Vector3f& min, Eigen::Vector3f& max) { + Eigen::Vector3f allZero(0, 0, 0); + float* minArr = min.data(); + float* maxArr = max.data(); + for (auto&& i : this->current_points) { + float* idata = i.data(); + if (i[0] < minArr[0] || i[0] > maxArr[0] || i[1] < minArr[1] || i[1] > maxArr[1] || i[2] < minArr[2] || i[2] > maxArr[2]) { + i = allZero; + } + } +} + +//-----threshold------// +/* +This function is the translate, rotate, and threshold functions all combined into one function call. +Sets points to origin if they are out of the thresholding cube, points at origin are considered invalid and +will not be sent over mqtt. They are not deleted from the vector to maintain ordering +*/ +void points::translateRotateThreshold(Eigen::Vector3f& t, Eigen::Vector3f& rot, Eigen::Vector3f& min, Eigen::Vector3f& max) { + //Get the degrees to rotate by + float anglex = (float)0.0174533 * rot.x(); + float angley = (float)0.0174533 * rot.y(); + float anglez = (float)0.0174533 * rot.z(); + + //Get the rotations for each axis + Eigen::AngleAxisf xrot(anglex, Eigen::Vector3f::UnitX()); + Eigen::AngleAxisf yrot(angley, Eigen::Vector3f::UnitY()); + Eigen::AngleAxisf zrot(anglez, Eigen::Vector3f::UnitZ()); + + //Set all the rotations into a single quaterniond and pass to the cuda function + Eigen::Quaternionf const quat = xrot * yrot * zrot; + + Eigen::Vector3f allZero(0, 0, 0); + + float* minArr = min.data(); + float* maxArr = max.data(); + for (auto&& i : this->current_points) { + i -= t; + i = quat * i; + float* idata = i.data(); + if (i[0] < minArr[0] || i[0] > maxArr[0] || i[1] < minArr[1] || i[1] > maxArr[1] || i[2] < minArr[2] || i[2] > maxArr[2]) { + i = allZero; + } + } +} + + +//-----give_points------// +/* +This will return the current points in a vector of Eigen::Vector3f points +*/ +std::vector& points::give_points() { + return this->current_points; +} + +//-----sparseFilter------// +/* +This function will go through and see if there at least [validNeightbor]s around a point. If there is not, the point is considered an error +in the camera and set to origin and is considered invalid. +*/ +void points::sparseFilter(int& width, int& height) { + static int validNeighbor = 4; + static int size = width * height; + Eigen::Vector3f allZero(0, 0, 0); + for (int i = 0; i < size; ++i) { + //Check that the point is not already invalid + //If it isn't get the x,y in relation to the image + if (this->current_points[i] != allZero) { + int idxwidth = i % width; + int idxheight = i / width; + + //Make sure its not around the border of the image + if (0 < idxwidth && idxwidth < width - 1 && 0 < idxheight && idxheight < height - 1) { + int neighborCount = 0; + //Get the neighbors + int neighbors[8] = { + ((width * (idxheight - 1)) + idxwidth - 1), (idxwidth + (width * (idxheight - 1))), (idxwidth + 1 + (width * (idxheight - 1))), + (idxwidth - 1 + (width * idxheight)), (idxwidth + 1 + (width * idxheight)), + (idxwidth - 1 + (width * (idxheight + 1))), (idxwidth + (width * (idxheight + 1))), (idxwidth + 1 + (width * (idxheight + 1))) + }; + //Count to see how many neighbors are valid + for (auto&& j : neighbors) { + if (this->current_points[j] != allZero) { + ++neighborCount; + } + } + //If the point doesn't have enough valid neighbors, that point is invalid + if (neighborCount < validNeighbor) { + this->current_points[i] = allZero; + } + } + } + } +} \ No newline at end of file diff --git a/streaming-pointcloud/kinect capture/kinect capture/points.h b/streaming-pointcloud/kinect capture/kinect capture/points.h new file mode 100644 index 00000000..e5560574 --- /dev/null +++ b/streaming-pointcloud/kinect capture/kinect capture/points.h @@ -0,0 +1,23 @@ +#pragma once + +#include +//Ensuring that only code licenced under MPL2.0 is used +//Will cause a compiler error if trying to access code that is not MPL2.0 +#define EIGEN_MPL2_ONLY +#include + +class points { +public: //Functions + points(); + ~points(); + bool importPoints(std::vector& newPoints); + void translate(Eigen::Vector3f& t); + void rotate(Eigen::Vector3f& rot); + void threshold(Eigen::Vector3f& min, Eigen::Vector3f& max); + void translateRotateThreshold(Eigen::Vector3f& t, Eigen::Vector3f& rot, Eigen::Vector3f& min, Eigen::Vector3f& max); + std::vector& give_points(); + void sparseFilter(int& width, int& height); + +private: //Variables + std::vector current_points; +}; \ No newline at end of file diff --git a/streaming-pointcloud/kinect capture/kinect capture/settings.toml b/streaming-pointcloud/kinect capture/kinect capture/settings.toml new file mode 100644 index 00000000..5f56acfa --- /dev/null +++ b/streaming-pointcloud/kinect capture/kinect capture/settings.toml @@ -0,0 +1,7 @@ +file = "camerapositionN.toml" + +[MqttInfo] +host = 'localhost' +id = 'cameraN' +topic = 'points' +port = 1883 \ No newline at end of file diff --git a/streaming-pointcloud/kinect capture/kinect capture/settings0.toml b/streaming-pointcloud/kinect capture/kinect capture/settings0.toml new file mode 100644 index 00000000..51245f09 --- /dev/null +++ b/streaming-pointcloud/kinect capture/kinect capture/settings0.toml @@ -0,0 +1,7 @@ +file = "cameraposition0.toml" + +[MqttInfo] +host = 'localhost' +id = 'LEFT' +topic = 'points' +port = 1883 \ No newline at end of file diff --git a/streaming-pointcloud/kinect capture/kinect capture/settings1.toml b/streaming-pointcloud/kinect capture/kinect capture/settings1.toml new file mode 100644 index 00000000..72c5599d --- /dev/null +++ b/streaming-pointcloud/kinect capture/kinect capture/settings1.toml @@ -0,0 +1,7 @@ +file = "cameraposition1.toml" + +[MqttInfo] +host = 'localhost' +id = 'RIGHT' +topic = 'points' +port = 1883 \ No newline at end of file diff --git a/streaming-pointcloud/kinect capture/kinect capture/settings2.toml b/streaming-pointcloud/kinect capture/kinect capture/settings2.toml new file mode 100644 index 00000000..41cb8c62 --- /dev/null +++ b/streaming-pointcloud/kinect capture/kinect capture/settings2.toml @@ -0,0 +1,7 @@ +file = "cameraposition2.toml" + +[MqttInfo] +host = 'localhost' +id = 'CENTER' +topic = 'points' +port = 1883 \ No newline at end of file diff --git a/streaming-pointcloud/merger/README.md b/streaming-pointcloud/merger/README.md new file mode 100644 index 00000000..6e11f9f1 --- /dev/null +++ b/streaming-pointcloud/merger/README.md @@ -0,0 +1,81 @@ +# Point Cloud Merger Application + +The Point Cloud Merger Application will consume MQTT data from one or more Kinect Capture instances and publish the merged data for use in interactive applications. + +# Prerequisites + +In order to use this application, you will need the following: + +1. One or more Azure Kinect cameras +1. An MQTT broker such as [Mosquitto](https://mosquitto.org) +1. One or more instances of the `kinect capture` application configured to publish data to your MQTT broker. +1. The executable `'merger.exe'`, which is available in this repository or can be compiled from source. + + +# Usage + +This is a console application which takes one optional argument: + +``` +merger.exe [settings_filename] +``` + +`[settings_filename]` - the name of the TOML file containing the application settings, default is `settings.toml` + + +# Configuration + +Configuration for the merger application is stored in a TOML file. By default the application will look for `settings.toml` or you may specify the file name via the optional command line parameter (see above). + +The contents of the TOML file are as follows: + +## [CameraInfo] Section + +The `merger` application communicates with the `kinect capture` instances to set the desired camera configuration (resolution, frame rate, etc). The capture settings are specified in the `[CameraInfo]` section of the settings.toml file. + + +| Property | Description | Values | +| ---- | --- | --- | +| `fps` | Camera frame rate | `'5'`, `'15'`, or `'30'` | +| `depth_mode` | The depth mode for the camera * | `'NFOV_BINNED'`, `'NFOV_UNBINNED'`, `'WFOV_BINNED'`, `'WFOV_UNBINNED'` | +| `color` | Capture the RGB color data for each 3D point | `True`, `False` | +| `color_resolution` | The resolution of the color camera input ** | `'2160P'`, `'1440P'`, `'1080P'`, `'720P'`, `'3072P'`, `'1536P'` | + +\* All depth modes can operate up to 30 FPS except `'NFOV_UNBINNED'` which has a maximum frame rate of `'15'` + +** All color modes can operate up to 30 FPS except `'3072P'` which has a maximum frame rate of `'15'` + + +## [MqttInfo] Section + +Connection settings for the MQTT client are stored in the `[MqttInfo]` section. + +| Property | Description | +| ---- | --- | +| `host` | the IP address of the MQTT broker | +| `port` | the port for the MQTT broker (typically this is 1883) | +| `id` | the MQTT client ID for this application (this must be unique among clients). | +| `topic` | the MQTT topic upon which the depth frames will be published. | +| `keepalive` | The MQTT keepalive interval, in seconds | +| `clean_session` | The `clean_session` value to use when connecting to the broker (see MQTT spec) + + +# Compiling from Source + +To compile this application from source, you will need the following: + ++ Visual Studio 2019 with MSVC v142 or greater + ++ Install the following packages via [Vcpkg](https://github.com/microsoft/vcpkg) + + mosquitto:x64-windows + + boost:x64-windows + ++ If you experience problems compiling the projects related to the Kinect SDK or libraries, it may be that you need to manually add the Microsoft Azure Kinect Sensor package. You can do this from within Visual Studio via the Nuget Package Manager. + + In Visual Studio, open the `Tools` menu and select `NuGet Package Manager > Manage NuGet Packages for Solution...` + + Search for `Microsoft.Azure.Kinect.Sensor` and install it. + ++ [TomlParser](https://github.com/ToruNiina/TOMLParser) Library + + Download or clone the repository and copy the contents to ```packages/``` + + Insert ```#pragma warning(disable : 4996) //_CRT_SECURE_NO_WARNINGS``` to the top of ```src/toml_parser.hpp``` + +Once you have all of these prerequisites, open `merger.sln` in Visual Studio to build the application. diff --git a/streaming-pointcloud/merger/Release.zip b/streaming-pointcloud/merger/Release.zip new file mode 100644 index 00000000..04eb9d69 Binary files /dev/null and b/streaming-pointcloud/merger/Release.zip differ diff --git a/streaming-pointcloud/merger/merger.sln b/streaming-pointcloud/merger/merger.sln new file mode 100644 index 00000000..5014c9c1 --- /dev/null +++ b/streaming-pointcloud/merger/merger.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29728.190 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "merger", "merger\merger.vcxproj", "{C2E45FB2-DEA7-4C2D-A07C-EA84F1C6FF8F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C2E45FB2-DEA7-4C2D-A07C-EA84F1C6FF8F}.Debug|x64.ActiveCfg = Debug|x64 + {C2E45FB2-DEA7-4C2D-A07C-EA84F1C6FF8F}.Debug|x64.Build.0 = Debug|x64 + {C2E45FB2-DEA7-4C2D-A07C-EA84F1C6FF8F}.Debug|x86.ActiveCfg = Debug|Win32 + {C2E45FB2-DEA7-4C2D-A07C-EA84F1C6FF8F}.Debug|x86.Build.0 = Debug|Win32 + {C2E45FB2-DEA7-4C2D-A07C-EA84F1C6FF8F}.Release|x64.ActiveCfg = Release|x64 + {C2E45FB2-DEA7-4C2D-A07C-EA84F1C6FF8F}.Release|x64.Build.0 = Release|x64 + {C2E45FB2-DEA7-4C2D-A07C-EA84F1C6FF8F}.Release|x86.ActiveCfg = Release|Win32 + {C2E45FB2-DEA7-4C2D-A07C-EA84F1C6FF8F}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2E3ACFB3-3EC0-4E11-AEE3-D9C7A698FF88} + EndGlobalSection +EndGlobal diff --git a/streaming-pointcloud/merger/merger/merger.cpp b/streaming-pointcloud/merger/merger/merger.cpp new file mode 100644 index 00000000..80053790 --- /dev/null +++ b/streaming-pointcloud/merger/merger/merger.cpp @@ -0,0 +1,66 @@ +// merger.cpp : This file contains the 'main' function. Program execution begins and ends there. +// + +#include +#include "pointcloudmerger.h" +#include "mqtt.h" +#include + +mqtt mosquittoWrapper; +pointCloudMerger merger; + +int main(int argc, char* argv[]) { + //Get the filename from command line argument + std::string fileName("settings.toml"); + if (argc < 2) { + std::cout << "Did not supply settings file argument, using 'settings.toml' as the default" << std::endl; + } + else { + fileName = argv[1]; + } + std::ifstream file(fileName.c_str()); + //Error out if file doesn't exist + if (!file.good()) { + fprintf(stderr, "error, %s does not exist\n", fileName.c_str()); + exit(-1); + } + //Output that the program is parsing the file + std::cout << "Parsing '" << fileName << "' file" << std::endl; + toml::Data data = toml::parse(file); + file.close(); + + //Initialize the mosquitto library and parse the arguments into the mqtt class + mosquittoWrapper.initMqttLib(); + mosquittoWrapper.ParseArgs(data); + std::cout << "Finished parsing" << std::endl; + mosquittoWrapper.connect(); + + //Set callbacks and subscribe to 'cameras' and 'viewer' + mosquittoWrapper.callbacks(); + mosquittoWrapper.subscribe((char*)TOPIC_CAMERA_AVAILABLE); + mosquittoWrapper.subscribe((char*)TOPIC_CONTROL); + mosquittoWrapper.subscribe((char*)TOPIC_VIEWER); + + //Start the loop for mosquitto to keep connection + mosquitto_loop_start(mosquittoWrapper.giveMosquitto()); + //Main loop + while (!merger.isDone()) { + std::cout << "Processing frames..." << std::endl; + while (!merger.isDone() && !merger.isRestart()) { + merger.merge(); + } + //Restarting or ending, clear out the unordered_map if restarting + merger.setRestart(false); + merger.eraseList(); + } //End main loop + + //Mosquitto is done, disconnect and clean up the library + mosquittoWrapper.disconnect(); + mosquittoWrapper.finishMosquitto(); + + std::cout << "Exiting program now" << std::endl; + + + + return 0; +} \ No newline at end of file diff --git a/streaming-pointcloud/merger/merger/merger.vcxproj b/streaming-pointcloud/merger/merger/merger.vcxproj new file mode 100644 index 00000000..b55bc483 --- /dev/null +++ b/streaming-pointcloud/merger/merger/merger.vcxproj @@ -0,0 +1,174 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + {C2E45FB2-DEA7-4C2D-A07C-EA84F1C6FF8F} + Win32Proj + merger + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + + + Level3 + true + + + true + MultiThreaded + Default + + + Console + true + + + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + Level3 + + + true + true + + + true + MultiThreaded + Default + + + Console + true + true + true + + + + + + + + + + Document + + + + + + + + + + + \ No newline at end of file diff --git a/streaming-pointcloud/merger/merger/merger.vcxproj.filters b/streaming-pointcloud/merger/merger/merger.vcxproj.filters new file mode 100644 index 00000000..fd8b66d8 --- /dev/null +++ b/streaming-pointcloud/merger/merger/merger.vcxproj.filters @@ -0,0 +1,44 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/streaming-pointcloud/merger/merger/messageBuffer.h b/streaming-pointcloud/merger/merger/messageBuffer.h new file mode 100644 index 00000000..2b26dfd9 --- /dev/null +++ b/streaming-pointcloud/merger/merger/messageBuffer.h @@ -0,0 +1,54 @@ +#pragma once +#include //string library imports memcpy and uint64_t + +//Message buffer is a struct that is used to hold the mqtt messages that are sent +//Has a constructor and deconstructor for the concurrent queue +struct messageBuffer { + uint64_t timestamp; + char * points; + size_t size; + uint32_t pointCount; + bool color; + + messageBuffer() { + this->timestamp = 0; + this->points = nullptr; + this->size = 0; + this->pointCount = 0; + this->color = false; + } + ~messageBuffer() { + this->timestamp = 0; + delete[]this->points; + this->points = nullptr; + this->size = 0; + this->pointCount = 0; + this->color = false; + } + + messageBuffer*& clone() { + messageBuffer* ret = new messageBuffer; + + ret->timestamp = this->timestamp; + ret->points = new char[this->size]; + memcpy(ret->points, this->points, this->size); + ret->size = this->size; + ret->pointCount = this->pointCount; + ret->color = this->color; + + return ret; + } + + messageBuffer operator&=(messageBuffer other) { + if (this != &other) { + this->timestamp = other.timestamp; + this->size = other.size; + delete[]this->points; + this->points = new char[this->size]; + memcpy(this->points, other.points, this->size); + this->pointCount = other.pointCount; + this->color = other.color; + } + return *this; + } +}; \ No newline at end of file diff --git a/streaming-pointcloud/merger/merger/mqtt.cpp b/streaming-pointcloud/merger/merger/mqtt.cpp new file mode 100644 index 00000000..0d21e076 --- /dev/null +++ b/streaming-pointcloud/merger/merger/mqtt.cpp @@ -0,0 +1,478 @@ +#include "mqtt.h" +#include "messageBuffer.h" +#include "pointcloudmerger.h" +#include + +extern mqtt mosquittoWrapper; +extern pointCloudMerger merger; + +//Converts an std::string into an array of chars, syntax is very similar to how strcpy works +//Used for getting std/toml string into a char* +void stringToChar(char*& dest, std::string source) { + if (strlen(source.c_str())) { + size_t len = strlen(source.c_str()) + 1; + dest = new char[len]; + strcpy_s(dest, len, source.c_str()); + dest[len - 1] = '\0'; + } +} + +//-------------------------------public functions-------------------------------// + + +/* +The constructor sets all pointers to null and sets the non pointer variables to the default by mosquitto's standards +port = 1883 +keepalive = 60 +clean_session = true +*/ +mqtt::mqtt() { + this->host = nullptr; + this->topic = nullptr; + this->port = 1883; + this->keepalive = 60; + this->clean_session = true; + this->mosq = nullptr; + this->id = nullptr; + this->userdata = nullptr; +} + +/* +The constructor frees up all of the pointer's memory and then set them to point at 0 +All other non-pointer data variables are set to 0. +*/ +mqtt::~mqtt() { + delete[] this->host; + this->host = 0; + delete[] this->topic; + this->topic = 0; + this->port = 0; + this->keepalive = 0; + this->clean_session = false; + delete this->userdata; + this->userdata = nullptr; + mosquitto_destroy(this->mosq); + this->mosq = nullptr; +} + +/* +Frees up all memory for the pointer fields before allocating the data onto host, topic, and id +Sets all the other non pointer variables to their respective fields. +It will then go through and call init_mosquitto() which will initialize the mosq variable, +allowing it to connect() right after create() +*/ +bool mqtt::create(char* host, char* topic, int port, char* id, void* userdata, int keep_alive, bool clean_session, int num_cameras) { + delete[]this->host; + delete[]this->topic; + delete[]this->id; + this->host = new char[strlen(host) + 1]; + strcpy_s(this->host, (strlen(host) + 1), host); + this->topic = new char[strlen(topic) + 1]; + strcpy_s(this->topic, (strlen(topic) + 1), topic); + this->port = port; + this->keepalive = keepalive; + this->clean_session = clean_session; + this->id = new char[strlen(id) + 1]; + strcpy_s(this->id, (strlen(id) + 1), id); + + return initMosquitto(); +} + +/* +connect() is a wrapper that will check to make sure that the connection succeeded, if it didn't it will return 1 +succeeding will return 0 +*/ +bool mqtt::connect(void) { + if (mosquitto_connect(this->mosq, this->host, this->port, this->keepalive)) { + fprintf(stderr, "mqtt::connect() Unable to connect.\n"); + return false; + } + return true; +} + +/* +The my_function_callback are functions that will help in the debug process. They are the functions that are called as if there +were on_event() type syntax. These are added to the callback function when calling the mosquitto_log_function_set(). The +mosquitto_log_function_set() takes the mosquitto structure and these my_function_callback() as the arguments. +*/ +void mqtt::callbacks(void) { + //log_callback, connect_callback, and subscribe_callback are used for debugging + //mosquitto_log_callback_set(this->mosq, my_log_callback); + //mosquitto_connect_callback_set(this->mosq, my_connect_callback); + mosquitto_message_callback_set(this->mosq, my_message_callback); + //mosquitto_subscribe_callback_set(this->mosq, my_subscribe_callback); +} + +/* +Send message is just a simple wrapper to publish/send a message over the mqtt stream with the +topic that the varible was initialized with. +The required arguments are: +payload_len: size of payload to be sent over +payload: the actual payload to be sent over +qos: 0, 1 or 2 indicating the quality of service to be used for the message +Optional arguments are: +retain: if message is desired to be kept +mid: number for the message id specifically sent over, can be NULL and the library will increment its own. +*/ +void mqtt::sendMessage(int payload_len, const void* payload, char* topic, int qos, bool retain, int* mid) { + if(topic != nullptr){ + mosquitto_publish(this->mosq, mid, topic, payload_len, payload, qos, retain); + } + else { + mosquitto_publish(this->mosq, mid, this->topic, payload_len, payload, qos, retain); + } +} + +/* +Finish mosquitto is a wrapper that calls the mosquitto_lib_cleanup() function +Only do this at the end of the program. +*/ +void mqtt::finishMosquitto(void) { + mosquitto_lib_cleanup(); +} + +/* +Wrapper that is used to initialize the mosquitto library. Only needs to be called once. +*/ +void mqtt::initMqttLib(void) { + mosquitto_lib_init(); +} + +/* +Wrapper to help create a new mosquitto instance. +There are no required parameters for this function as it already assumes that the values for the class +has been populated in some fashion prior to calling this. +*/ +int mqtt::initMosquitto(void) { + this->mosq = mosquitto_new(this->id, this->clean_session, this->userdata); + if (!mosq) { + fprintf(stderr, "mqtt::initMosquitto() Unable to connect.\n"); + return 0; + } + return 1; +} + +/* +ParseArgs takes in the section of toml that is relevant for mqtt info. +It will create the variables right from the file and then initialize the values to those provided from the +config.toml file. +Returns the success or failure of init_mosquitto() +*/ +bool mqtt::ParseArgs(toml::Table data) { + toml::Table table = toml::get(data.at("MqttInfo")); + stringToChar(this->host, toml::get(table.at("host"))); + stringToChar(this->id, toml::get(table.at("id"))); + std::string topicString(toml::get(table.at("topic"))); + topicString.append("/"); + topicString.append(id); + stringToChar(this->topic, topicString); + this->port = (int)toml::get(table.at("port")); + try { + this->keepalive = (int)toml::get(table.at("keepalive")); + } + catch (std::exception& e) { + e; //Removes unreferenced local veriable warning + this->keepalive = 60; + } + try { + this->clean_session = toml::get(table.at("clean_session")); + } + catch (std::exception & e) { + e; //Removes unreferenced local veriable warning + this->clean_session = true; + } + + table = toml::get(data.at("CameraInfo")); + this->parseFPS(toml::get(table.at("fps"))); + this->parseDepthMode(toml::get(table.at("depth_mode"))); + this->parseColorResolution(toml::get(table.at("color_resolution"))); + this->cameraConfig.color = toml::get(table.at("color")); + + return initMosquitto(); +} + +/* +Give the current mosquitto instance back, useful for: +mosquitto_loop_start(); +*/ +mosquitto* mqtt::giveMosquitto() { + return this->mosq; +} + +/* +Subscribe to the topic that is stored in the class +*/ +void mqtt::subscribe() { + mosquitto_subscribe(this->mosq, NULL, this->topic, 0); +} + +/* +Subscribe to a topic that is not stored in the class +Can do either to be '(this->topic)/newtopic' in terms of appending +or its own topic to something that is not tied to this->topic +*/ +void mqtt::subscribe(char* topic, bool append) { + std::string subTopic; + if (append) { + subTopic = std::string(this->topic); + subTopic.append("/"); + subTopic.append(topic); + } + else { + subTopic = std::string(topic); + } + mosquitto_subscribe(this->mosq, NULL, subTopic.c_str(), 0); +} + +/* +Unsubscribe from a specific topic. +*/ +void mqtt::unsubscribe(char* topic, bool append) { + std::string subTopic; + if (append) { + subTopic = std::string(this->topic); + subTopic.append("/"); + subTopic.append(topic); + } + else { + subTopic = std::string(topic); + } + mosquitto_unsubscribe(this->mosq, NULL, subTopic.c_str()); +} + +/* +Disconnect the mosquitto client from the broker +*/ +void mqtt::disconnect() { + mosquitto_disconnect(this->mosq); +} + +/* +Return the stored topic in the class +*/ +std::string mqtt::giveTopic() { + return this->topic; +} + +/* +* Handle incoming MQTT messages. +*/ +void my_message_callback(struct mosquitto* mosq, void* userdata, const struct mosquitto_message* message) +{ + if (message->payloadlen) { + + //Camera's topic + if (strcmp((char*)message->topic, TOPIC_CONTROL) == 0) { + + // Program is over with, set done + if (strcmp((char*)message->payload, COMMAND_SHUTDOWN) == 0) { + printf("Closing down the application..\n"); + merger.setDone(true); + } + + // Program needs to restart + else if (strcmp((char*)message->payload, COMMAND_RESTART) == 0) { + merger.setRestart(true); + printf("Restarting the application..\n"); + std::fflush(stdout); + } + } + else if (strcmp((char*)message->topic, TOPIC_CAMERA_AVAILABLE) == 0) { + // Cameras announce the MQTT topic upon which they will broadcast frames. + // Subscribe to the topic and send back the configuration so the camera + // can initialize and start sending data. + + std::string messagePayload((char*)message->payload); + merger.createNewIndex(messagePayload); + mosquittoWrapper.subscribe((char*)message->payload); + + uint8_t configArr[4] = { + (uint8_t)mosquittoWrapper.cameraConfig.fps, + (uint8_t)mosquittoWrapper.cameraConfig.depthMode, + (uint8_t)mosquittoWrapper.cameraConfig.colorMode, + (uint8_t)mosquittoWrapper.cameraConfig.color + }; + mosquittoWrapper.sendMessage(4, configArr, (char*)TOPIC_CAMERA_CONFIGURE); + }//End topic + else { + //Viewer Topic + if (strcmp((char*)message->topic, TOPIC_VIEWER) == 0) { + + // Viewer is asking for the list of camera topics + if (strcmp((char*)message->payload, COMMAND_GET_CAMERA_TOPICS) == 0) { + std::string cameraTopics; + if (merger.giveIndexNames(cameraTopics)) { + mosquittoWrapper.sendMessage((int)cameraTopics.size(), cameraTopics.c_str(), (char*)TOPIC_MERGER); + } + } + //Viewer is asking for the merger's topic + else if (strcmp((char*)message->payload, COMMAND_GET_MERGED_TOPIC) == 0) { + std::string mergerTopic(mosquittoWrapper.giveTopic()); + mosquittoWrapper.sendMessage((int)mergerTopic.size(), mergerTopic.c_str(), (char*)TOPIC_MERGER); + } + + }//End viewer topic + else if (message->payloadlen >= 13) { + //Else the message must be a camera sending a frame over + char* payload = (char*)message->payload; + + int bytesPerPoint = 6; + //Get and create the msg structure + messageBuffer* msg = new messageBuffer; + memcpy(&msg->timestamp, &payload[0], 8); + memcpy(&msg->pointCount, &payload[8], 4); + memcpy(&msg->color, &payload[12], 1); + if (msg->color) { + bytesPerPoint = 9; + } + msg->size = msg->pointCount * bytesPerPoint; + msg->points = new char[msg->size]; + memcpy(&msg->points[0], &payload[13], msg->size); + if (!merger.addMessage(message->topic, msg)) { + delete msg; + } + + } + else { + //For Debugging + //printf("\n%s %d\t\t%u\n", (char*)message->topic, message->payloadlen, timestamp); + } + } + } +} + +/* +Function is provided by the mosquitto.org documentation +*/ +void my_connect_callback(struct mosquitto* mosq, void* userdata, int result) +{ + if (!result) { + /* Subscribe to broker information topics on successful connect. */ + mosquitto_subscribe(mosq, NULL, "$SYS/#", 2); + } + else { + fprintf(stderr, "mqtt::my_connect_callback() Connect failed\n"); + } +} + +/* +Function is provided by the mosquitto.org documentation +*/ +void my_subscribe_callback(struct mosquitto* mosq, void* userdata, int mid, int qos_count, const int* granted_qos) +{ + int i; + + printf("Subscribed (mid: %d): %d", mid, granted_qos[0]); + for (i = 1; i < qos_count; i++) { + printf(", %d", granted_qos[i]); + } + printf("\n"); +} + +/* +Function is provided by the mosquitto.org documentation +*/ +void my_log_callback(struct mosquitto* mosq, void* userdata, int level, const char* str) +{ + /* Pring all log messages regardless of level. */ + printf("%s\n", str); +} + +//-------------------------------private functions-------------------------------// + +/* +Parse the fps from the toml file and set it into a pseudo enum state. +*/ +bool mqtt::parseFPS(std::string fpsSetting) { + int mode = 0; + if (fpsSetting.compare("5") == 0) { + mode = 0; + } + else if (fpsSetting.compare("15") == 0) { + mode = 1; + } + else if (fpsSetting.compare("30") == 0) { + mode = 2; + } + else { + this->parseErrorOutput("fps"); + return false; + } + + this->cameraConfig.fps = mode; + return true; +} + +/* +Parse the depth mode from the toml file and set it into a pseudo enum state. +*/ +bool mqtt::parseDepthMode(std::string depthSetting) { + int mode = 0; + if (depthSetting.compare("OFF") == 0) { + mode = 0; + } + else if (depthSetting.compare("NFOV_BINNED") == 0) { + mode = 1; + } + else if (depthSetting.compare("NFOV_UNBINNED") == 0) { + mode = 2; + } + else if (depthSetting.compare("WFOV_BINNED") == 0) { + mode = 3; + } + else if (depthSetting.compare("WFOV_UNBINNED") == 0) { + mode = 4; + } + else if (depthSetting.compare("PASSIVE_IR") == 0) { + mode = 5; + } + else { + this->parseErrorOutput("depth_setting"); + return false; + } + + this->cameraConfig.depthMode = mode; + return true; +} + +/* +Parse the color resolution from the toml file and set it into a pseudo enum state. +*/ +bool mqtt::parseColorResolution(std::string colorResolutionSetting) { + int mode = 0; + if (colorResolutionSetting.compare("OFF") == 0) { + mode = 0; + } + else if (colorResolutionSetting.compare("720P") == 0) { + mode = 1; + } + else if (colorResolutionSetting.compare("1080P") == 0) { + mode = 2; + } + else if (colorResolutionSetting.compare("1440P") == 0) { + mode = 3; + } + else if (colorResolutionSetting.compare("1536P") == 0) { + mode = 4; + } + else if (colorResolutionSetting.compare("2160P") == 0) { + mode = 5; + } + else if (colorResolutionSetting.compare("3072P") == 0) { + mode = 6; + } + else { + this->parseErrorOutput("color_resolution"); + return false; + } + + this->cameraConfig.colorMode = mode; + return true; +} + +/* +Parse the error explaining the wrong user input from the toml file and set it into a pseudo enum state. +*/ +void mqtt::parseErrorOutput(std::string errorString) { + fprintf(stderr, "error, cannot parse the %s correctly, please ensure there are no typos\n", errorString.c_str()); +} \ No newline at end of file diff --git a/streaming-pointcloud/merger/merger/mqtt.h b/streaming-pointcloud/merger/merger/mqtt.h new file mode 100644 index 00000000..c375de93 --- /dev/null +++ b/streaming-pointcloud/merger/merger/mqtt.h @@ -0,0 +1,87 @@ +#pragma once +#pragma once +#include +#include +#include "..//packages/TOMLParser-master/toml.hpp" + +#define TOPIC_CAMERA_AVAILABLE "cameras/available" +#define TOPIC_CAMERA_CONFIGURE "cameras/configure" +#define TOPIC_CONTROL "cameras/control" +#define TOPIC_VIEWER "viewer" +#define TOPIC_MERGER "merger" + +#define COMMAND_SHUTDOWN "done" +#define COMMAND_RESTART "restart" + +#define COMMAND_GET_CAMERA_TOPICS "get_camera_topics" +#define COMMAND_GET_MERGED_TOPIC "get_merged_topic" + + +//Wrapper to hold the configuration to send off to cameras when they come online +struct cameraConfiguration { + int fps = 0; + int depthMode = 0; + int colorMode = 0; + bool color = false; + + ~cameraConfiguration() { + this->fps = 0; + this->depthMode = 0; + this->colorMode = 0; + this->color = false; + } +}; + +/* +These callback functions are not included within the class as they are used to be passed as pointers to the functions +for mosquitto to use them properly +*/ +void my_message_callback(struct mosquitto* mosq, void* userdata, const struct mosquitto_message* message); +void my_connect_callback(struct mosquitto* mosq, void* userdata, int result); +void my_subscribe_callback(struct mosquitto* mosq, void* userdata, int mid, int qos_count, const int* granted_qos); +void my_log_callback(struct mosquitto* mosq, void* userdata, int level, const char* str); + +/* +mqtt class is a wrapper for the mosquitto library +It holds just about all the information to be able to send data with the exception of some sort of message +variable. +Once the class has been created, the next steps to send a message are connect(), then send_message() +With send_message(), be sure to include the payload length, the payload, and the quality of service that would be desired. +*/ +class mqtt { +public: //Functions + mqtt(); + ~mqtt(); + bool create(char* host, char* topic, int port, char* id, void* userdata, int keep_alive, bool clean_session, int num_cameras); + bool connect(void); + void disconnect(); + void callbacks(void); + void sendMessage(int payload_len, const void* payload, char* topic = nullptr, int qos = 0, bool retain = false, int* mid = NULL); + void finishMosquitto(void); + void initMqttLib(void); + int initMosquitto(void); + bool ParseArgs(toml::Table table); + void subscribe(void); + void subscribe(char* topic, bool append = false); + void unsubscribe(char* topic, bool append = false); + std::string giveTopic(); + mosquitto* giveMosquitto(); + struct cameraConfiguration cameraConfig; + + +private: //Functions + bool parseFPS(std::string fpsSetting); + bool parseDepthMode(std::string depthSetting); + bool parseColorResolution(std::string colorResolutionSetting); + void parseErrorOutput(std::string errorString); + +private: //Variables + char* host; + char* topic; + int port; + int keepalive; + bool clean_session; + char* id; + void* userdata; + struct mosquitto* mosq; +}; \ No newline at end of file diff --git a/streaming-pointcloud/merger/merger/pointcloudmerger.cpp b/streaming-pointcloud/merger/merger/pointcloudmerger.cpp new file mode 100644 index 00000000..9daa3984 --- /dev/null +++ b/streaming-pointcloud/merger/merger/pointcloudmerger.cpp @@ -0,0 +1,394 @@ +#include "pointcloudmerger.h" +#include "mqtt.h" +#include + +extern mqtt mosquittoWrapper; + +//-------------------------------public functions-------------------------------// + +//-----pointCloudMerger default contstructor------// +/* +Set all members to their respective 0 default except for the bufferSize +5 is the sweetspot to have some extra frames just in case one camera is taking +too long to send over +*/ +pointCloudMerger::pointCloudMerger() { + this->framePointCount = 0; + this->frameBufferSize = 0; + this->frameTimestamp = 0; + this->frameColor = false; + this->bufferSize = 5; //Minimum size for the buffer before just deleting them all + this->done = false; + this->restart = false; + this->syncMode = false; +} + +//-----pointCloudMerger buffSize contstructor------// +/* +Calls the default constructor and sets the buffer size to a specific value instead +*/ +pointCloudMerger::pointCloudMerger(uint32_t buffSize) { + this->pointCloudMerger::pointCloudMerger(); + this->setBufferSize(buffSize); +} + +//-----pointCloudMerger decontstructor------// +/* +Frees up all memory and sets members to their zero equivalent values +*/ +pointCloudMerger::~pointCloudMerger() { + this->framePointCount = 0; + this->frameBufferSize = 0; + this->frameTimestamp = 0; + this->frameColor = 0; + this->bufferSize = 0; + this->done = false; + this->restart = false; + this->syncMode = false; + + if (this->buffer.size() > 0) { + this->eraseList(); + } +} + +//-----pointCloudMerger setBufferSize------// +/* +Sets the bufferSize to anything that is greater than or equal to 5 frames. +If not, error out and don't change the size. +*/ +bool pointCloudMerger::setBufferSize(uint32_t buffSize) { + if (buffSize < 5) { + fprintf(stderr, "pointCloudMerger::setBufferSize() error, buffer size needs to be at least 5\n"); + fprintf(stderr, "Size entered was: %d\n", buffSize); + return false; + } + + this->bufferSize = buffSize; + + return true; +} + +//-----pointCloudMerger createNewIndex------// +/* +Create a new entry in the unordered_map +This must be called first before attempting to insert into an index. +Outputs an error if the index is already found +*/ +bool pointCloudMerger::createNewIndex(std::string indexName) { + if (this->buffer.find(indexName) != this->buffer.end()) { + fprintf(stderr, "pointCloudMerger::createNewEntry() error, entry with the index already exists\n"); + return false; + } + + this->buffer[indexName] = new concurrency::concurrent_queue; + + std::cout <<"Subscribed to '" << indexName <<"'" <errorCantFindEntry(indexName)) { + fprintf(stderr, " 'pointCloudMerger::addMessage()'\n"); + return false; + } + + this->buffer[indexName]->push(msg); + + return true; +} + +//-----pointCloudMerger readMessage------// +/* +Checks to make sure that the entry is already found, if not. Output an error message and return false + +Otherwise pops off the most recent frame from that index +*/ +bool pointCloudMerger::readMessage(std::string indexName, messageBuffer*& msg) { + if (this->errorCantFindEntry(indexName)) { + fprintf(stderr, " 'pointCloudMerger::readMessage()'\n"); + return false; + } + + if (!this->buffer[indexName]->try_pop(msg)) { + return false; + } + + return true; +} + +//-----pointCloudMerger eraseList------// +/* +Checks to make sure that the buffer has at least 1 entry, errors out if it is an empty list + +Otherwise it grabs all of the index names and then erases each Index item +*/ +bool pointCloudMerger::eraseList() { + if (this->buffer.size() == 0) { + fprintf(stderr, "error, list is empty, 'pointCloudMerger::emptyList()'\n"); + return false; + } + + std::vector indexNames; + + for (auto iter : this->buffer) { + indexNames.emplace_back(iter.first); + } + + + for (int i = 0; i < indexNames.size(); ++i) { + this->eraseIndex(indexNames[i]); + } + + return true; +} + +//-----pointCloudMerger eraseIndex------// +/* +Checks to make sure that the entry is already found, if not. Output an error message and return false + +unsubscribe from that topic +empty the concurrentqueue +delete the concurrentqueue +erase the entry from the unordered_map +*/ +bool pointCloudMerger::eraseIndex(std::string& indexName) { + if (this->errorCantFindEntry(indexName)) { + fprintf(stderr, " 'pointCloudMerger::eraseItem()'\n"); + return false; + } + + mosquittoWrapper.unsubscribe((char*)indexName.c_str()); + messageBuffer* temp = nullptr; + concurrency::concurrent_queue* queuBuffer = this->buffer[indexName]; + while (queuBuffer->try_pop(temp)) { + delete temp; + } + delete this->buffer[indexName]; + this->buffer.erase(indexName); + + return true; +} + +//-----pointCloudMerger merge------// +/* +Checks to make sure that the buffer is nonzero, if is zero error out + +Checks to make sure that each buffer has at least 1 frame, doesn't merge if one is missing + +Otherwise, make a vector to hold the most recent frame from each camera and combine them all to one buffer +*/ +bool pointCloudMerger::merge() { + bool result = true; + if (this->buffer.size() == 0) { + result = false; + } + for (auto iter : this->buffer) { + if (result == true && iter.second->unsafe_size() == 0) { + result = false; + } + } + + //Each buffer had at least one frame + if (result == true) { + std::vector frames(this->buffer.size()); + //Set counters back to zero + this->framePointCount = 0; + this->frameBufferSize = 0; + this->frameTimestamp = 0; + + { + //Scope will drop count + int count = 0; + //Go through each buffer entry and add to the total of the points and size + //Insert the message into the vector + for (auto iter : this->buffer) { + messageBuffer* msgPtr = nullptr; + if (iter.second->try_pop(msgPtr)) { + this->framePointCount += msgPtr->pointCount; + this->frameBufferSize += msgPtr->size; + this->frameColor = msgPtr->color; + frames[count] = msgPtr; + ++count; + } + } + } + + //If result is still good and the first frame is a valid point + if (result == true && frames[0]) { + //Copy the timestamp only once + this->frameTimestamp = frames[0]->timestamp; + + //Preform the actual merge + if (!merge(frames)) { + result = false; + } + + } + //Clear the memory out of the vector + frames.clear(); + + //Empty the queues, so older frames are not displayed next time + for (auto iter : this->buffer) { + messageBuffer* temp = nullptr; + while (iter.second->try_pop(temp)) { + delete temp; + } + } + } //Not all cameras have sent a frame since last time + else { + //Make sure all the queues are less than the max allowed bufferSize + //If its too big, empty the whole queue. + for (auto iter : this->buffer) { + if (iter.second->unsafe_size() > this->bufferSize) { + messageBuffer* temp = nullptr; + while (iter.second->try_pop(temp)) { + delete temp; + } + } + + } + } + + //Return the result of merge + return result; +} + +//-----pointCloudMerger setRestart, isRestart, setDone, isDone------// +/* +These are all simple setters and getters that keep track of program state +*/ +bool pointCloudMerger::setRestart(bool toSet) { + this->restart = toSet; + + return true; +} + +bool pointCloudMerger::isRestart() { + return this->restart; +} + +bool pointCloudMerger::setDone(bool toSet) { + this->done = toSet; + + return true; +} + +bool pointCloudMerger::isDone() { + return this->done; +} + +//-----pointCloudMerger giveIndexNames------// +/* +Checks to make sure that the buffer is nonzero, if it is zero error out + +Otherwise, return all the names of the different topics in a space separated format. +*/ +bool pointCloudMerger::giveIndexNames(std::string &indexNames) { + + int activeTopics = this->buffer.size(); + + if (activeTopics == 0) { + fprintf(stderr, "error, buffer is empty, 'pointCloudMerger::giveIndexNames()'\n"); + return false; + } + + for (auto iter : this->buffer) { + indexNames.append(iter.first); + + if (--activeTopics != 0) { + indexNames.append(" "); + } + } + + return true; +} + +//-------------------------------private functions-------------------------------// + +//-----pointCloudMerger errorCantFindEntry------// +/* +Helper function to make sure that an index is present in the unordered_map, otherwise output the trouble index and return true to +be picked by the other funtions. +*/ +bool pointCloudMerger::errorCantFindEntry(std::string indexName) { + if (this->buffer.find(indexName) == this->buffer.end()) { + fprintf(stderr, "error, cannot find entry for buffer[%s]", indexName.c_str()); + return true; + } + return false; +} + +//-----pointCloudMerger merge------// +/* +Merges all the points together + +If the frame bool was present, sets the color size from 0 to 3, otherwise it stays 0 bytes. +*/ +bool pointCloudMerger::merge(std::vector& frames) { + char* messageBuffer = new char[this->frameBufferSize + 13]; //To be sent out + char* mergedDepthBuffer = new char[this->frameBufferSize]; + char* mergedColorBuffer = new char[this->frameBufferSize]; + int mergedDepthBufferOffset = 0; + int mergedColorBufferOffset = 0; + + int colorSize = 0; + if (this->frameColor) { + colorSize = 3; + } + //Go through and make a combined buffer of depth and color info, keeping track of their offsets. + for (auto iter : frames) { + memcpy(&mergedDepthBuffer[mergedDepthBufferOffset], &iter->points[0], iter->pointCount*6); + mergedDepthBufferOffset += iter->pointCount * 6; + memcpy(&mergedColorBuffer[mergedColorBufferOffset], &iter->points[iter->pointCount * 6], iter->pointCount * colorSize); + mergedColorBufferOffset += iter->pointCount * colorSize; + } + + //Put the header together on the mergedMessageBuffer + int mergedMessageBufferOffset = 0; + memcpy(&messageBuffer[mergedMessageBufferOffset], &this->frameTimestamp, 8); + mergedMessageBufferOffset += 8; + memcpy(&messageBuffer[mergedMessageBufferOffset], &this->framePointCount, 4); + mergedMessageBufferOffset += 4; + memcpy(&messageBuffer[mergedMessageBufferOffset], &this->frameColor, 1); + mergedMessageBufferOffset += 1; + //Insert the depth data after the header + memcpy(&messageBuffer[mergedMessageBufferOffset], &mergedDepthBuffer[0], mergedDepthBufferOffset); + mergedMessageBufferOffset += mergedDepthBufferOffset; + //Insert the color data after the depth data + memcpy(&messageBuffer[mergedMessageBufferOffset], &mergedColorBuffer[0], mergedColorBufferOffset); + mergedMessageBufferOffset += mergedColorBufferOffset; + + //For debugging purposes + //std::cout << "\nTimeStamp:\t" << this->frameTimestamp << "\n" + // << "Points:\t\t" << this->framePointCount << "\n" + // << "Color:\t\t" << this->frameColor << "\n" + // << "SIZE:\t\t" << mergedMessageBufferOffset << std::endl; + + //Output how many points are going to be sent + std::cout << "Points sent : " << this->framePointCount << " \r"; + + //MosquittoWrapper send here + mosquittoWrapper.sendMessage(mergedMessageBufferOffset, messageBuffer, (char*)mosquittoWrapper.giveTopic().c_str()); + + //Clear out the frames + for (auto iter : frames) { + delete[]iter->points; + iter->points = nullptr; + delete iter; + } + + //Free up the memory + delete[]messageBuffer; + delete[]mergedDepthBuffer; + delete[]mergedColorBuffer; + + //Return true, merge was a success + return true; +} \ No newline at end of file diff --git a/streaming-pointcloud/merger/merger/pointcloudmerger.h b/streaming-pointcloud/merger/merger/pointcloudmerger.h new file mode 100644 index 00000000..fdebaf82 --- /dev/null +++ b/streaming-pointcloud/merger/merger/pointcloudmerger.h @@ -0,0 +1,38 @@ +#pragma once +#include +#include "concurrent_queue.h" +#include "messageBuffer.h" + +class pointCloudMerger { +public: //Functions + pointCloudMerger(); + pointCloudMerger(uint32_t buffSize); + ~pointCloudMerger(); + bool setBufferSize(uint32_t buffSize); + bool createNewIndex(std::string indexName); + bool addMessage(std::string indexName, messageBuffer* &msg); + bool readMessage(std::string indexName, messageBuffer*& msg); + bool eraseList(); + bool eraseIndex(std::string& indexName); + bool merge(); + bool setRestart(bool toSet); + bool isRestart(); + bool setDone(bool toSet); + bool isDone(); + bool giveIndexNames(std::string &indexNames); + +private: //Functions + bool errorCantFindEntry(std::string indexName); + bool merge(std::vector& frames); + +private: //Variables + std::unordered_map*> buffer; + uint32_t framePointCount; + uint64_t frameBufferSize; + uint64_t frameTimestamp; + bool frameColor; + uint32_t bufferSize; + bool done; + bool restart; + bool syncMode; +}; \ No newline at end of file diff --git a/streaming-pointcloud/merger/merger/settings.toml b/streaming-pointcloud/merger/merger/settings.toml new file mode 100644 index 00000000..ae7a4794 --- /dev/null +++ b/streaming-pointcloud/merger/merger/settings.toml @@ -0,0 +1,11 @@ +[CameraInfo] +fps = '30' +depth_mode = 'NFOV_UNBINNED' +color_resolution = '720P' +color = true + +[MqttInfo] +host = 'localhost' +id = 'pointmerger' +topic = 'points' +port = 1883 \ No newline at end of file